This commit is contained in:
124
commands/contests/result.ts
Normal file
124
commands/contests/result.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
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<void>{
|
||||
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<SlashCommandBuilder, "addSubcommand" | "addSubcommandGroup">{
|
||||
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();
|
||||
Reference in New Issue
Block a user