import { CommandInteraction, TextChannel, SlashCommandBuilder, SlashCommandBooleanOption, CommandInteractionOptionResolver, } from 'discord.js'; import {writeFileSync} from 'fs'; import {Command} from '../../classes/command'; import {logger} from '../../logger'; import {config} from '../../config'; import {getContest, getProblem, getSession} from '../../functions/database'; function isTextChannel(data: unknown): data is TextChannel{ return (data as TextChannel).name !== undefined; } type CIOR = CommandInteractionOptionResolver; class Result extends Command{ get name(){return "result";} get description(){return "See the result of a contest.";} async execute(interaction: CommandInteraction): Promise{ if(!isTextChannel(interaction.channel)){ await interaction.reply({ content: `Channel name doesn't exist!` }); logger.error(`Channel name doesn't exist`); return; } const contestName = interaction.channel.name; const channelId = interaction.channel.id; const markdown = (interaction.options as CIOR).getBoolean('markdown') ?? false; const contest = await getContest(channelId); if(contest === null){ await interaction.reply({ content: `The contest in this channel didn't start!` }); logger.error(`Contest ${contestName} didn't start`); return; } let content: string = ''; content += `# ${contestName}\n\n` contest.problems.sort( (a, b) => { if(a.problemId > b.problemId) return 1; if(a.problemId < b.problemId) return -1; return 0; } ); const getTime = (time: number) => { if(time === -1) return -1; return Math.floor((time-contest.startTime)/(1000*60)); }; for(const problem of contest.problems){ const p = await getProblem(problem._id); if(p === null) continue; content += `## p${p.problemId}\n`; if(getTime(p.ac) === -1) content += "*Problem unsolved!*\n"; else content += `**AC** at ${getTime(p.ac)} min\n`; if(p.wa.length !== 0){ content += `**WA** at`; let isFirst: boolean = true; for(const wa of p.wa.sort()){ if(isFirst) isFirst = false; else content += ','; content += ` ${getTime(wa)}`; } content += ' min\n'; } if(p.read.length === 0) content += "*Problem unread!*\n"; else{ content += `**Read**:\n`; for(const session of p.read){ const s = await getSession(session._id); if(s === null) continue; content += `- \`${s.name}\` at ${getTime(s.start)} min`; if(getTime(s.end) !== -1) content += ` (estimate: ${getTime(s.end)} min)`; content += '\n'; } } if(p.code.length === 0) content += "*No one have attempted*\n"; else{ content += `**Code**:\n`; for(const session of p.code){ const s = await getSession(session._id); if(s === null) continue; content += `- \`${s.name}\` at ${getTime(s.start)} min` content += ` (estimate: ${getTime(s.end)} min)\n`; } } content += '\n'; } if(markdown){ const file = `${config.mdBaseDir}/${channelId}.md`; logger.log(`Output to ${file}`); await writeFileSync(file, content, {encoding: 'utf8'}); await interaction.reply({files:[file]}); }else await interaction.reply({content: content}); logger.log(`Command: result of ${contestName}/${channelId}`); } override build(): SlashCommandBuilder | Omit{ return new SlashCommandBuilder() .setName(this.name) .setDescription(this.description) .addBooleanOption((option: SlashCommandBooleanOption) => option .setName('markdown') .setDescription('If true then upload markdown file instead.') ) } }; export const command = new Result();