diff --git a/src/Bot.ts b/src/Bot.ts index 99df855..a931885 100644 --- a/src/Bot.ts +++ b/src/Bot.ts @@ -99,6 +99,19 @@ async function init(): Promise { await db.runAsync(`ALTER TABLE giveaways add author_display_name TEXT NULL`) await db.runAsync(`ALTER TABLE giveaways add author_avatar_url TEXT NULL`) } + await db.runAsync(`CREATE TABLE IF NOT EXISTS elite_game ( + identifier INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, + player TEXT NOT NULL, + register_date TEXT NOT NULL, + play_timestamp INTEGER NOT NULL + )`) + await db.runAsync(`CREATE TABLE IF NOT EXISTS elite_game_winner ( + identifier INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE, + player TEXT NOT NULL, + register_date TEXT NOT NULL, + play_timestamp INTEGER NOT NULL, + target_timestamp INTEGER NOT NULL + )`) await (await PersistentDataStorage.instance()).initBlackJack(db) }) @@ -129,6 +142,9 @@ async function init(): Promise { } commands.push(command) console.log(`Command ${command.data.name} loaded`) + if (command.init) { + command.init(client, logManager.logger(command.data.name)) + } } const buttons: Button[] = [] diff --git a/src/commandTypes.ts b/src/commandTypes.ts index 4ac62c7..eb39571 100644 --- a/src/commandTypes.ts +++ b/src/commandTypes.ts @@ -10,6 +10,7 @@ import { } from 'discord.js' export interface Command { + init?: (client: any, logger: any) => void data: SlashCommandBuilder execute: (interaction: CommandInteraction) => Promise } diff --git a/src/commands/elite.ts b/src/commands/elite.ts new file mode 100644 index 0000000..9ada7e1 --- /dev/null +++ b/src/commands/elite.ts @@ -0,0 +1,117 @@ +import { CommandInteraction, EmbedBuilder, SlashCommandBuilder, ChannelType, Client } from 'discord.js' +import LogManager, { ILogger } from '../logger/logger' +import schedule from 'node-schedule' +import { AsyncDatabase } from '../sqlite/sqlite' + +function getTodayAsDate(): string { + const berlinDate = new Date().toLocaleDateString('de-DE', { + timeZone: 'Europe/Berlin', + year: 'numeric', + month: '2-digit', + day: '2-digit' + }) + return berlinDate +} + +let db: AsyncDatabase | undefined +export default { + init: (client: Client, logger: ILogger): void => { + client.on('ready', async () => { + if (client.user == null || client.application == null) { + return + } + logger.logSync('INFO', `Init EliteCommand`) + + db = await AsyncDatabase.open() + if (!db) { + logger.logSync('ERROR', 'Datenbank konnte nicht geƶffnet werden.') + return + } + // Everyday at 13:37 (24 hour clock) Europe/ + schedule.scheduleJob({ rule: '37 13 * * *', tz: 'Europe/Berlin' }, async () => { + const targetChannel = await client.channels.fetch(process.env.SEND_1337_CHANNEL_ID ?? '') + if (!targetChannel || targetChannel.type !== ChannelType.GuildText) { + logger.logSync('WARN', 'MessageLogger could not find log channel or LogChannel is not TextBased') + return + } + + setTimeout(() => { + void (async () => { + const berlinDate = getTodayAsDate() + // write '\uFFFF' to player column to indicate that the game has been played for this day + await db?.runAsync(`INSERT INTO elite_game (register_date, player, play_timestamp) VALUES(?,?,?)`, [berlinDate, '\uFFFF', 0]) + // find all participants and sort them by play_timestamp (first one is the winner) + let rows = await db?.getAsync(`select * from elite_game where register_date = ? and player != "\uFFFF" order by play_timestamp desc`, [berlinDate]) + await targetChannel.send('13:37') + if (rows) { + if (!Array.isArray(rows)) { + rows = [rows] + } + console.log(rows) + await targetChannel.send(`Todays winner is <@${rows[0].player}>`) + await db?.runAsync(`INSERT INTO elite_game_winner (player, register_date, play_timestamp, target_timestamp) VALUES(?,?,?,?)`, [rows[0].player, berlinDate, rows[0].play_timestamp, Date.now()]) + } + })() + }, Math.random() * 60000) // delay by 0-60 seconds + }) + }) + }, + data: new SlashCommandBuilder().setName('1337').setDescription('Plays the 1337 game.'), + async execute(interaction: CommandInteraction) { + const logger = LogManager.getInstance().logger('EliteCommand') + if (!interaction.isRepliable()) { + logger.logSync('ERROR', 'Gegebene interaction kann nicht beantwortet werden.') + return + } + const berlinDate = getTodayAsDate() + + const userId = interaction.member?.user.id ?? '' + + let rows = await db?.getAsync(`select * from elite_game where register_date = ? and (player = ? or player = "\uFFFF") order by player desc`, [berlinDate, userId]) + try { + if (rows) { + if (!Array.isArray(rows)) { + rows = [rows] + } + if (rows[0].player === '\uFFFF') { + // the player '\uFFFF' indicates that the game has been played for this day + await interaction.reply({ + embeds: [new EmbedBuilder() + .setColor(0x0099ff) + .setTitle('Too late!') + .setDescription( + 'Es ist nach 13:37. Morgen kannst du wieder mitmachen.' + ) + .setTimestamp()], + ephemeral: true + }) + } else { + await interaction.reply({ + embeds: [new EmbedBuilder() + .setColor(0x0099ff) + .setTitle('That`s not going to happen!') + .setDescription( + 'Du hast heute bereits deinen Tipp abgegeben. Warte auf das Ergebnis.' + ) + .setTimestamp()], + ephemeral: true + }) + } + } else { + await db?.runAsync(`INSERT INTO elite_game(register_date, player, play_timestamp) VALUES(?,?,?)`, [berlinDate, userId, Date.now()]) + await interaction.reply({ + embeds: [new EmbedBuilder() + .setColor(0x0099ff) + .setTitle('Got it!') + .setDescription( + 'Dein Tipp wurde registriert. Warte auf das Ergebnis.' + ) + .setTimestamp()], + ephemeral: true + }) + } + } catch (err) { + logger.logSync('ERROR', `Reply to elite command konnte nicht gesendet werden. ${JSON.stringify(err)}`) + } + } +} diff --git a/src/listeners/ready.ts b/src/listeners/ready.ts index 7e7fe25..1fb53fd 100644 --- a/src/listeners/ready.ts +++ b/src/listeners/ready.ts @@ -1,6 +1,5 @@ -import { ChannelType, Client } from 'discord.js' +import { Client } from 'discord.js' import { ILogger } from '../logger/logger' -import schedule from 'node-schedule' export default (client: Client, logger: ILogger): void => { client.on('ready', async () => { @@ -9,19 +8,5 @@ export default (client: Client, logger: ILogger): void => { } logger.logSync('INFO', `${client.user.username}#${client.user.discriminator} ist online!`) - - // Everyday at 13:37 (24 hour clock) Europe/ - schedule.scheduleJob({ rule: '37 13 * * *', tz: 'Europe/Berlin' }, async () => { - logger.logSync('INFO', `Entered scheduleJob : channel_id=${process.env.SEND_1337_CHANNEL_ID}`) - const targetChannel = await client.channels.fetch(process.env.SEND_1337_CHANNEL_ID ?? '') - - logger.logSync('INFO', `Before if`) - if (!targetChannel || targetChannel.type !== ChannelType.GuildText) { - logger.logSync('WARN', 'MessageLogger could not find log channel or LogChannel is not TextBased') - return - } - logger.logSync('INFO', `Before send`) - await targetChannel.send('13:37') - }) }) }