Initial Code
This commit is contained in:
121
src/commands/users/weekly.ts
Normal file
121
src/commands/users/weekly.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import BotCommand from "../../libs/BotCommand";
|
||||
import BotClient from "../../libs/BotClient";
|
||||
import { ChatInputCommandInteraction, MessageFlags, EmbedBuilder, AttachmentBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, TextChannel } from "discord.js";
|
||||
import QuestionScheduler from "../../libs/QuestionScheduler";
|
||||
import AnswerGrader from "../../libs/AnswerGrader";
|
||||
|
||||
const SUBJECTS = ["Mathematics", "Physics", "Chemistry", "Biology", "Computer Science", "Engineering"];
|
||||
|
||||
export default class WeeklyCommand extends BotCommand {
|
||||
constructor() {
|
||||
super("weekly", "Answer this week's weekly STEM question", "/weekly");
|
||||
this.data.addStringOption(option =>
|
||||
option.setName("subject")
|
||||
.setDescription("Choose a subject")
|
||||
.addChoices(
|
||||
{ name: "Mathematics", value: "mathematics" },
|
||||
{ name: "Physics", value: "physics" },
|
||||
{ name: "Chemistry", value: "chemistry" },
|
||||
{ name: "Organic Chemistry", value: "organic chemistry" },
|
||||
{ name: "Biology", value: "biology" },
|
||||
{ name: "Computer Science", value: "computer science" },
|
||||
{ name: "Engineering", value: "engineering" }
|
||||
)
|
||||
.setRequired(true)
|
||||
);
|
||||
}
|
||||
|
||||
override async execute(Discord: any, client: BotClient, interaction: ChatInputCommandInteraction): Promise<any> {
|
||||
try {
|
||||
await interaction.deferReply({ flags: MessageFlags.Ephemeral });
|
||||
|
||||
const subject = interaction.options.getString("subject", true);
|
||||
|
||||
const scheduler = new QuestionScheduler();
|
||||
await scheduler.initialize();
|
||||
|
||||
const question = await scheduler.getQuestionForPeriod(subject, "weekly");
|
||||
|
||||
if (!question) {
|
||||
return interaction.editReply({ content: `Failed to load this week's ${subject} question. Please try again later.` });
|
||||
}
|
||||
|
||||
const hasAnswered = await scheduler.hasUserAnswered(interaction.user.id, question.id);
|
||||
if (hasAnswered) {
|
||||
return interaction.editReply({ content: "You've already submitted an answer for this week's question! Check back next Sunday." });
|
||||
}
|
||||
|
||||
const imagePath = await client.typst.renderToImage(question.typst_source);
|
||||
|
||||
if (!imagePath) {
|
||||
// Log error to logs channel
|
||||
const logsChannelId = process.env.LOGS_CHANNEL_ID;
|
||||
if (logsChannelId) {
|
||||
try {
|
||||
const logsChannel = await client.channels.fetch(logsChannelId) as TextChannel;
|
||||
if (logsChannel?.isTextBased()) {
|
||||
const errorEmbed = new EmbedBuilder()
|
||||
.setTitle("❌ Typst Render Error - Weekly Question")
|
||||
.setColor(0xef4444)
|
||||
.addFields(
|
||||
{ name: "Subject", value: subject, inline: true },
|
||||
{ name: "Question ID", value: question.id, inline: true },
|
||||
{ name: "Topic", value: question.topic, inline: false },
|
||||
{ name: "User", value: `<@${interaction.user.id}>`, inline: true },
|
||||
{ name: "Error", value: "Failed to render Typst image", inline: false }
|
||||
)
|
||||
.setTimestamp();
|
||||
await logsChannel.send({ embeds: [errorEmbed] });
|
||||
}
|
||||
} catch (logErr) {
|
||||
console.error("Failed to send error to logs channel:", logErr);
|
||||
}
|
||||
}
|
||||
return interaction.editReply({
|
||||
content: `❌ An error occurred while generating the question image. This has been reported to administrators.`
|
||||
});
|
||||
}
|
||||
|
||||
const embed = new EmbedBuilder()
|
||||
.setTitle(`🎓 Weekly ${subject} Question (PhD Level)`)
|
||||
.setDescription(`**Topic:** ${question.topic}\n**Difficulty:** ${question.difficulty_rating}`)
|
||||
.setColor(0xfacc15)
|
||||
.setImage(`attachment://weekly_${subject}.png`)
|
||||
.setFooter({ text: `Resets at 12 AM Sunday` })
|
||||
.setTimestamp();
|
||||
|
||||
const attachment = new AttachmentBuilder(imagePath, { name: `weekly_${subject}.png` });
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`weekly_answer_${question.id}`)
|
||||
.setLabel("Submit Answer")
|
||||
.setStyle(ButtonStyle.Primary)
|
||||
.setEmoji("✍️"),
|
||||
new ButtonBuilder()
|
||||
.setCustomId(`weekly_report_${question.id}`)
|
||||
.setLabel("Report Issue")
|
||||
.setStyle(ButtonStyle.Danger)
|
||||
.setEmoji("⚠️")
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
embeds: [embed],
|
||||
files: [attachment],
|
||||
components: [row],
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error executing weekly command:", err);
|
||||
try {
|
||||
if (interaction.deferred || interaction.replied) {
|
||||
await interaction.editReply({ content: "An error occurred. Please try again later." });
|
||||
} else {
|
||||
await interaction.reply({ content: "An error occurred. Please try again later.", flags: MessageFlags.Ephemeral });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error sending error reply:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user