feat/40-reroll-on-disinterest #54

Merged
kenobi merged 73 commits from feat/40-reroll-on-disinterest into master 2023-11-19 20:24:36 +01:00
4 changed files with 67 additions and 60 deletions
Showing only changes of commit 7d794a8001 - Show all commits

View File

@ -1,10 +1,10 @@
import { format, isToday } from "date-fns";
import { utcToZonedTime } from "date-fns-tz"
import { GuildScheduledEvent } from "discord.js";
import { logger } from "../logger";
import de from "date-fns/locale/de";
import { Maybe } from "../interfaces";
export function createDateStringFromEvent(eventStartDate:Date, requestId: string, guildId?: string): string {
export function createDateStringFromEvent(eventStartDate: Maybe<Date>, requestId: string, guildId?: string): string {
if (!eventStartDate) {
logger.error("Event has no start. Cannot create dateString.", { guildId, requestId })
return `"habe keinen Startzeitpunkt ermitteln können"`

View File

@ -21,8 +21,7 @@ export type Vote = {
}
export type VoteMessageInfo = {
votes: Vote[],
eventId: string,
eventDate: Date
event: GuildScheduledEvent,
}
export default class VoteController {
private client: ExtendedClient
@ -74,11 +73,8 @@ export default class VoteController {
logger.debug(`${vote.movie} : ${vote.count} -> above: ${overOneVote}`)
return overOneVote
}
public async handleReroll(voteMessage: VoteMessage, guildId: string, requestId: string) {
// get the movies currently being voted on, their votes, the eventId and its date
const voteInfo: VoteMessageInfo = await this.parseVoteInfoFromVoteMessage(voteMessage, requestId)
magnetotail marked this conversation as resolved Outdated

maybe extract this if-else to a method to keep code more compact

maybe extract this if-else to a method to keep code more compact

7d794a8001
done

7d794a8001a66d068f949c893d689a068c3caeed done
let movies: string[] = Array()
public async generateRerollMovieList(voteInfo: VoteMessageInfo, guildId: string, requestId: string) {
if (config.bot.reroll_retains_top_picks) {
const votedOnMovies = voteInfo.votes.filter(this.hasAtLeastOneVote).filter(x => x.emote !== NONE_OF_THAT)
logger.info(`Found ${votedOnMovies.length} with votes`, { requestId, guildId })
@ -86,40 +82,53 @@ export default class VoteController {
logger.info(`Fetching ${newMovieCount} from jellyfin`)
const newMovies: string[] = await this.yavinJellyfinHandler.getRandomMovieNames(newMovieCount, guildId, requestId)
// merge
movies = newMovies.concat(votedOnMovies.map(x => x.movie))
return newMovies.concat(votedOnMovies.map(x => x.movie))
} else {
// get movies from jellyfin to fill the remaining slots
const newMovieCount: number = config.bot.random_movie_count
logger.info(`Fetching ${newMovieCount} from jellyfin`)
movies = await this.yavinJellyfinHandler.getRandomMovieNames(newMovieCount, guildId, requestId)
return await this.yavinJellyfinHandler.getRandomMovieNames(newMovieCount, guildId, requestId)
}
// create new message
}
magnetotail marked this conversation as resolved Outdated

is not a message, only messagetext

is not a message, only messagetext
a455fd8ff7e6b8ffb032fb4aed9389da68ee513b

done

done
public async handleReroll(voteMessage: VoteMessage, guildId: string, requestId: string) {
// get the movies currently being voted on, their votes, the eventId and its date
const voteInfo: VoteMessageInfo = await this.parseVoteInfoFromVoteMessage(voteMessage, requestId)
if (!voteInfo.event.scheduledStartAt) {
logger.info("Event does not have a start date, cancelling", { guildId: voteInfo.event.guildId, requestId })
return
}
let movies: string[] = await this.generateRerollMovieList(voteInfo, guildId, requestId)
logger.info(`Creating new poll message with new movies: ${movies}`, { requestId, guildId })
const messageText = this.createVoteMessageText(voteInfo.eventId, voteInfo.eventDate, movies, guildId, requestId)
const announcementChannel = this.client.getAnnouncementChannelForGuild(guildId)
if (!announcementChannel) {
logger.error(`No announcementChannel found for ${guildId}, can't post poll`)
return
}
magnetotail marked this conversation as resolved Outdated

why not pin message in method above?

why not pin message in method above?

7d794a8001
should have been moved to prepareAndSendVoteMessage()

7d794a8001a66d068f949c893d689a068c3caeed should have been moved to prepareAndSendVoteMessage()
try {
logger.info(`Trying to remove old vote Message`, { requestId, guildId })
this.removeMessage(voteMessage)
} catch (err) {
// TODO: integrate failure DM to media Admin to inform about inability to delete old message
logger.error(`Error during removeMessage: ${err}`)
}
const sentMessage = await this.sendVoteMessage(messageText, movies.length, announcementChannel)
sentMessage.pin()
logger.info(`Sent and pinned new poll message`, { requestId, guildId })
const sentMessage = this.prepareAndSendVoteMessage({
event: voteInfo.event,
movies,
announcementChannel,
startDate: voteInfo.event.scheduledStartAt,
pinAfterSending: true
},
guildId,
requestId)
logger.debug(`Sent reroll message: ${JSON.stringify(sentMessage)}`, { requestId, guildId })
}
private async fetchEventStartDateByEventId(guild: Guild, eventId: string, requestId: string): Promise<Maybe<Date>> {
private async fetchEventByEventId(guild: Guild, eventId: string, requestId: string): Promise<Maybe<GuildScheduledEvent>> {
const guildEvent: GuildScheduledEvent = await guild.scheduledEvents.fetch(eventId)
if (!guildEvent) logger.error(`GuildScheduledEvent with id${eventId} could not be found`, { requestId, guildId: guild.id })
if (guildEvent.scheduledStartAt)
return guildEvent.scheduledStartAt
return guildEvent
}
public async parseVoteInfoFromVoteMessage(message: VoteMessage, requestId: string): Promise<VoteMessageInfo> {
@ -129,8 +138,7 @@ export default class VoteController {
if (!message.guild)
throw new Error(`Message ${message.id} not a guild message`)
let eventStartDate: Maybe<Date> = await this.fetchEventStartDateByEventId(message.guild, parsedIds.eventId, requestId)
if (!eventStartDate) eventStartDate = this.parseEventDateFromMessage(message.cleanContent, message.guild.id, requestId)
const event: Maybe<GuildScheduledEvent> = await this.fetchEventByEventId(message.guild, parsedIds.eventId, requestId)
let votes: Vote[] = []
for (const line of lines) {
@ -149,7 +157,7 @@ export default class VoteController {
}
}
}
return <VoteMessageInfo>{ eventId: parsedIds.eventId, eventDate: eventStartDate, votes }
return <VoteMessageInfo>{ event, votes }
}
public parseEventDateFromMessage(message: string, guildId: string, requestId: string): Date {
logger.warn(`Falling back to RegEx parsing to get Event Date`, { guildId, requestId })
@ -168,15 +176,15 @@ export default class VoteController {
}
public async prepareAndSendVoteMessage(inputInfo: prepareVoteMessageInput, guildId: string, requestId: string) {
const messageText = this.createVoteMessageText(inputInfo.event.id, inputInfo.startDate, inputInfo.movies, guildId, requestId)
const messageText = this.createVoteMessageText(inputInfo.event, inputInfo.movies, guildId, requestId)
const sentMessage = await this.sendVoteMessage(messageText, inputInfo.movies.length, inputInfo.announcementChannel)
if (inputInfo.pinAfterSending)
sentMessage.pin()
return sentMessage
}
public createVoteMessageText(eventId: string, eventStartDate: Date, movies: string[], guildId: string, requestId: string): string {
let message = `[Abstimmung] für https://discord.com/events/${guildId}/${eventId} \n<@&${config.bot.announcement_role}> Es gibt eine neue Abstimmung für die nächste Watchparty ${createDateStringFromEvent(eventStartDate, guildId, requestId)}! Stimme hierunter für den nächsten Film ab!\n`
public createVoteMessageText(event: GuildScheduledEvent, movies: string[], guildId: string, requestId: string): string {
let message = `[Abstimmung] für https://discord.com/events/${guildId}/${event.id} \n<@&${config.bot.announcement_role}> Es gibt eine neue Abstimmung für die nächste Watchparty ${createDateStringFromEvent(event.scheduledStartAt, guildId, requestId)}! Stimme hierunter für den nächsten Film ab!\n`
for (let i = 0; i < movies.length; i++) {
message = message.concat(Emotes[i]).concat(": ").concat(movies[i]).concat("\n")
@ -186,6 +194,7 @@ export default class VoteController {
return message
}
// TODO: Refactor into separate message controller
public async sendVoteMessage(messageText: string, movieCount: number, announcementChannel: TextChannel) {
const options: MessageCreateOptions = {

View File

@ -29,11 +29,16 @@ describe('vote controller - none_of_that functions', () => {
id: 'mockId'
}
}
const mockEvent: GuildScheduledEvent = <GuildScheduledEvent><unknown>{
scheduledStartAt: testEventDate,
id: testEventId,
guild: testGuildId
}
const mockJellyfinHandler: JellyfinHandler = <JellyfinHandler><unknown>{
getRandomMovieNames: jest.fn().mockReturnValue(["movie1"])
}
const votes = new VoteController(mockClient, mockJellyfinHandler)
const mockMessageContent = votes.createVoteMessageText(testEventId, testEventDate, testMovies, testGuildId, "requestId")
const mockMessageContent = votes.createVoteMessageText(mockEvent, testMovies, testGuildId, "requestId")
test('sendVoteClosedMessage', async () => {
mockClient.getAnnouncementChannelForGuild = jest.fn().mockReturnValue({
@ -57,29 +62,6 @@ describe('vote controller - none_of_that functions', () => {
content: `[Abstimmung beendet] für https://discord.com/events/${testGuildId}/${testEventId}\n<@&WATCHPARTY_ANNOUNCEMENT_ROLE> Wir gucken MovieNew am 01.01. um 01:00`
})
})
// test('checkForPollsToClose', async () => {
//
// const testGuild: Guild = <Guild><unknown>{
// scheduledEvents: {
// fetch: jest.fn().mockImplementation(() => {
// return new Promise(resolve => {
// resolve([
// { name: "Event Name" },
// { name: "Event: VOTING OFFEN", scheduledStartTimestamp: "" },
// { name: "another voting" },
// ]
// )
// })
// })
// }
// }
//
// const result = await votes.checkForPollsToClose(testGuild)
//
//
//
//
// })
test('getVotesByEmote', async () => {
const mockMessage: Message = <Message><unknown>{

View File

@ -1,9 +1,9 @@
import { Emoji, NONE_OF_THAT } from "../../server/constants"
import VoteController, { Vote, VoteMessageInfo } from "../../server/helper/vote.controller"
import VoteController, { VoteMessageInfo } from "../../server/helper/vote.controller"
import { JellyfinHandler } from "../../server/jellyfin/handler"
import { ExtendedClient } from "../../server/structures/client"
import { VoteMessage } from "../../server/helper/messageIdentifiers"
import { Message, MessageReaction } from "discord.js"
import { GuildScheduledEvent, MessageReaction } from "discord.js"
test('parse votes from vote message', async () => {
const testMovies = [
'Movie1',
@ -16,12 +16,16 @@ test('parse votes from vote message', async () => {
const testEventDate = new Date('2023-01-01')
const testGuildId = "888999888"
const voteController: VoteController = new VoteController(<ExtendedClient>{}, <JellyfinHandler>{})
const testMessage = voteController.createVoteMessageText(testEventId, testEventDate, testMovies, testGuildId, "requestId")
const mockEvent: GuildScheduledEvent = <GuildScheduledEvent><unknown>{
scheduledStartAt: testEventDate,
id: testEventId,
guild: testGuildId
}
const testMessage = voteController.createVoteMessageText(mockEvent, testMovies, testGuildId, "requestId")
const expectedResult: VoteMessageInfo = {
eventId: testEventId,
eventDate: testEventDate,
event: mockEvent,
votes: [
{ emote: Emoji.one, count: 1, movie: testMovies[0] },
{ emote: Emoji.two, count: 2, movie: testMovies[1] },
@ -40,6 +44,8 @@ test('parse votes from vote message', async () => {
fetch: jest.fn().mockImplementation((input: any) => {
if (input === testEventId)
return {
id: testEventId,
guild: testGuildId,
scheduledStartAt: testEventDate
}
})
@ -61,8 +67,8 @@ test('parse votes from vote message', async () => {
const result = await voteController.parseVoteInfoFromVoteMessage(message, 'requestId')
console.log(JSON.stringify(result))
expect(Array.isArray(result)).toBe(false)
expect(result.eventId).toEqual(testEventId)
expect(result.eventDate).toEqual(testEventDate)
expect(result.event.id).toEqual(testEventId)
expect(result.event.scheduledStartAt).toEqual(testEventDate)
expect(result.votes.length).toEqual(expectedResult.votes.length)
expect(result).toEqual(expectedResult)
})
@ -79,7 +85,12 @@ test('parse votes from vote message', () => {
const testEventDate = new Date('2023-01-01')
const testGuildId = "888999888"
const voteController: VoteController = new VoteController(<ExtendedClient>{}, <JellyfinHandler>{})
const testMessage = voteController.createVoteMessageText(testEventId, testEventDate, testMovies, testGuildId, "requestId")
const mockEvent: GuildScheduledEvent = <GuildScheduledEvent><unknown>{
scheduledStartAt: testEventDate,
id: testEventId,
guild: testGuildId
}
const testMessage = voteController.createVoteMessageText(mockEvent, testMovies, testGuildId, "requestId")
const result = voteController.parseGuildIdAndEventIdFromWholeMessage(testMessage)
expect(result).toEqual({ guildId: testGuildId, eventId: testEventId })
@ -108,7 +119,12 @@ test.skip('handles complete none_of_that vote', () => {
}
}
const voteController = new VoteController(mockClient, mockJellyfinHandler)
const mockMessageContent = voteController.createVoteMessageText(testEventId, testEventDate, testMovies, testGuildId, "requestId")
const mockEvent: GuildScheduledEvent = <GuildScheduledEvent><unknown>{
scheduledStartAt: testEventDate,
id: testEventId,
guild: testGuildId
}
const mockMessageContent = voteController.createVoteMessageText(mockEvent, testMovies, testGuildId, "requestId")
const reactedUponMessage: VoteMessage = <VoteMessage><unknown>{
cleanContent: mockMessageContent,
guild: {