Skip to content

Commit

Permalink
Merge pull request #35 from boaz-baekjoon/Feat/34-slash-command
Browse files Browse the repository at this point in the history
Feat: Slash Command
  • Loading branch information
synoti21 authored Feb 4, 2024
2 parents c1caf0a + e573b3f commit 451981e
Show file tree
Hide file tree
Showing 19 changed files with 287 additions and 374 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion src/bot/initialize-bot.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Client, Collection, GatewayIntentBits} from "discord.js";
import {ApplicationCommandDataResolvable, Client, Collection, GatewayIntentBits, REST, Routes} from "discord.js";
import { mongoConnect } from "../config/mongoDb.js";
import * as dotenv from "dotenv";
import * as fs from "fs";
Expand All @@ -18,13 +18,17 @@ export async function initializeBot(client: Client){

//Loading Commands
const commands = fs.readdirSync("./dist/commands").filter(file => file.endsWith(".js"));
const slashCommands = new Array<ApplicationCommandDataResolvable>();
for (const file of commands) {
const commandName = file.split(".")[0];
const command = await import(`../commands/${file}`);

console.log(`Attempting to load command ${commandName}`);
slashCommands.push(command.default.data);
client.commands.set(commandName, command);
}
const rest = new REST({ version: "9" }).setToken(String(process.env.DISCORD_TOKEN));
const response = await rest.put(Routes.applicationCommands(client.user!.id), { body: slashCommands });

//Initialize Success
client.once('ready', async () => {
Expand Down
59 changes: 24 additions & 35 deletions src/commands/category.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import {Message} from "discord.js";
import {ChatInputCommandInteraction, Message, SlashCommandBuilder, TextChannel} from "discord.js";
import {categoryList} from "../embedMessage/categoryMessage.js";
import {ModelUtil} from "../util/modelUtil.js";
import {MongoUtil} from "../util/mongoUtil.js";
import {logger} from "../logger.js";
import {getRandomProblem} from "./prob.js";

async function getProblemWithCategory(user_id: string, category: number) {
async function getProblemWithCategory(interaction: ChatInputCommandInteraction, category: number) {
try{
const problem_arr = await ModelUtil.getProblemWithCategory(user_id, category);
const problem_arr = await ModelUtil.getProblemWithCategory(interaction.user.id, category);
if (problem_arr.length === 0){
logger.warn(`${user_id}/ 모델 서버 오류로 인한 랜덤 문제 반환`)
await interaction.reply("모델 서버의 오류로 인해 랜덤 문제를 반환합니다.")
logger.warn(`${interaction.user.id}/ 모델 서버 오류로 인한 랜덤 문제 반환`)
return await getRandomProblem()
}
return await MongoUtil.findProblemWithProblemId(problem_arr[0]);
Expand All @@ -19,37 +20,25 @@ async function getProblemWithCategory(user_id: string, category: number) {
}
}

export async function execute(message: Message){
try{
await message.channel.send({embeds: [categoryList]});

const botFilter = (m: { author: { bot: any; id: string; }; content: string; }) => !m.author.bot && m.author.id === message.author.id
&& !m.content.startsWith('!');
const responseCollector = message.channel.createMessageCollector({filter: botFilter,max:1, time: 20000});

responseCollector.on('collect', async msg => {
const selectedNumber = parseInt(msg.content);
//만일 숫자가 아니거나 0~10 사이의 숫자가 아니라면
if (isNaN(selectedNumber) || selectedNumber < 0 || selectedNumber > 10){
await message.reply("숫자를 잘못 입력하셨습니다. 명령을 취소합니다.");
export default{
data: new SlashCommandBuilder()
.setName('category')
.setDescription('카테고리별 문제를 받습니다.')
.addStringOption(option => option.setName('category').setDescription('카테고리 번호를 입력해주세요. 번호 목록은 /categorylist를 통해 확인해주세요.').setRequired(true)),
async execute(interaction: ChatInputCommandInteraction){
try{
const number = interaction.options.getString('category');
if (number === null || parseInt(number) === null || parseInt(number) > 9 || parseInt(number) < 0){
await interaction.reply({embeds: [categoryList]});
await interaction.followUp("정확한 카테고리 번호를 입력해주세요.")
return;
}
if(selectedNumber === 10){
await message.reply("명령을 취소하셨습니다.");
return;
}

const problem = await getProblemWithCategory(message.author.id, selectedNumber);
await message.channel.send({embeds: [problem.getEmbedMsg("개인 맞춤형 문제입니다.")]})
});

responseCollector.on('end', collected => {
if (collected.size === 0){
message.reply("입력 시간이 만료되었습니다.")
}
});
}catch (error){
logger.error(error);
await message.reply("알 수 없는 오류가 발생했습니다.")
const problem = await getProblemWithCategory(interaction, parseInt(number));
await (interaction.channel as TextChannel).send({embeds: [problem.getEmbedMsg("개인 맞춤형 문제입니다.")]})
await interaction.reply("카테고리별 문제를 전송했습니다.")
}catch (error){
logger.error(error);
await interaction.reply("알 수 없는 오류가 발생했습니다.")
}
}
}
}
19 changes: 19 additions & 0 deletions src/commands/categorylist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {logger} from "../logger.js";
import {ChatInputCommandInteraction, SlashCommandBuilder} from "discord.js";
import {ModelUtil} from "../util/modelUtil.js";
import {categoryList} from "../embedMessage/categoryMessage.js";

export default {
data: new SlashCommandBuilder()
.setName('categorylist')
.setDescription('카테고리 목록을 받습니다.'),

async execute(interaction: ChatInputCommandInteraction) {
try {
await interaction.reply({embeds: [categoryList]});
} catch (error) {
logger.error(error)
await interaction.reply("알 수 없는 오류가 발생했습니다.")
}
}
}
170 changes: 39 additions & 131 deletions src/commands/daily.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,138 +8,46 @@

import { logger } from '../logger.js'
import {MongoUtil} from '../util/mongoUtil.js';
import {Message} from "discord.js";

async function getUserDailyTime(message: Message){
try {
const user = await MongoUtil.findUserWithDiscordId(message.author.id)

if (!user) { //If no user is found
await message.reply("백준 아이디를 등록하지 않았습니다. !register을 통해 아이디를 등록해주세요");
return;
import {ChatInputCommandInteraction, Message, SlashCommandBuilder} from "discord.js";

export default{
data: new SlashCommandBuilder()
.setName('daily')
.setDescription('일일 문제를 받을 시간을 정합니다.')
.addStringOption(option => option.setName('time').setDescription('일일 문제를 받을 시간을 입력해주세요. (HH MM, 예시: 13시 5분 => 13 05').setRequired(true)),

async execute(interaction: ChatInputCommandInteraction){
try{
const time = interaction.options.getString('time');
if (time === null){
await interaction.reply("시간을 입력해주세요.")
return;
}
const [hour, min] = time.split(' ');
if (hour.length !== 2 || min.length !== 2 || isNaN(Number(hour)) || isNaN(Number(min)) ||
parseInt(hour, 10) < 0 || parseInt(hour, 10) >= 24 || parseInt(min, 10) < 0 ||
parseInt(min, 10) >= 60) {
await interaction.reply("시간 형식이 올바르지 않습니다. 올바른 형식으로 입력해주세요. (ex. 오전 1시 1분: 01 01)")
return;
}

const userDailyTime = `${parseInt(hour, 10)} ${parseInt(min, 10)}`

const user = await MongoUtil.findUserWithDiscordId(interaction.user.id);
if (!user) {
await interaction.reply("백준 아이디를 등록하지 않았습니다. /register을 통해 아이디를 등록해주세요");
return;
}
const response = await MongoUtil.addTime(interaction.user.id, userDailyTime);
if (!response){
await interaction.reply("알 수 없는 오류가 발생했습니다.")
return;
}
await interaction.reply(`성공적으로 등록되었습니다. 설정한 시간: ${hour}${min}분`)
}catch (error){
logger.error(error);
await interaction.reply("알 수 없는 오류가 발생했습니다.")
}

if (user['daily_time']) { //If user already set daily time
const [hour, min] = user['daily_time'].split(' ');
await message.reply(`${hour}${min}분으로 알림이 설정된 상태입니다. 알림을 비활성화하려면 '비활성화', 변경하시려면 '변경', 명령을 취소하려면 '취소'를 입력해주세요`);

// Filter for user response
const responseFilter = (m: { author: { bot: any; id: string; }; content: string; }) => !m.author.bot && m.author.id === message.author.id && !m.content.startsWith('!') &&
(m.content === '비활성화' || m.content === '변경' || m.content === '취소');
const responseCollector = message.channel.createMessageCollector({
filter: responseFilter,
max: 1,
time: 20000
});

// Execute functions based on user response
responseCollector.on('collect', async msg => {
switch (msg.content) {
case '변경':
getInputOfDailyTime(message, true);
break;
case '취소':
await message.reply("명령을 취소하셨습니다.")
break;
case '비활성화':
const result = await MongoUtil.deleteTime(message.author.id);
if (result) {
await message.reply("알림을 비활성화했습니다")
} else {
await message.reply("알 수 없는 오류가 발생했습니다.")
}
break;
default:
break;
}
responseCollector.stop();
});

responseCollector.on('end', collected => {
//Terminate if time limit is exceeded
if (collected.size === 0) {
message.channel.send("입력 시간이 만료되었습니다.");
}
});

} else { //If user did not set daily time
getInputOfDailyTime(message, false);
}
}catch (error){
logger.error(error)
}
}


function getInputOfDailyTime(message: Message, isUserDailyTimeAlreadySet: boolean) {
message.channel.send("원하시는 시간을 24시간제로 다음과 같이 입력해주세요. (HH MM), 취소를 원하실 경우 '취소'를 입력해주세요.");

const botFilter = (m: { author: { bot: any; id: string; }; content: string; }) => !m.author.bot && m.author.id === message.author.id && !m.content.startsWith('!');
const idCollector = message.channel.createMessageCollector({filter: botFilter,max:1, time: 20000});

idCollector.on('collect', async msg => {
if (msg.content === '취소'){
await message.reply("명령을 취소하셨습니다.")
return;
}

const isDailyTimeInserted = await addDailyTimeOfUser(message.author.id, msg.content, isUserDailyTimeAlreadySet)

switch (isDailyTimeInserted) {
case 0: //If time is successfully inserted
const [hour, min] = msg.content.split(' ')
message.channel.send(`성공적으로 등록되었습니다. 설정한 시간: ${hour}${min}분`)
break;
case -1: //If error occurred
message.channel.send("알 수 없는 오류가 발생했습니다.")
break;
case -2: //If time format is invalid
await message.reply("시간 형식이 올바르지 않습니다. 올바른 형식으로 입력해주세요. (ex. 오전 1시 1분: 01 01)")
break;
}

//Terminate the collector after the user inputs the time
idCollector.stop();
});

idCollector.on('end', collected => {
//Terminate if time limit is exceeded
if (collected.size === 0) {
message.channel.send("입력 시간이 만료되었습니다.");
}
});

}

async function addDailyTimeOfUser(discordId: string, userInput: string, isDailyTimeAlreadySet: boolean) {
const [hour, minute] = userInput.split(' ');

// If the time format is not properly entered
if (hour.length !== 2 || minute.length !== 2 || isNaN(Number(hour)) || isNaN(Number(minute)) ||
parseInt(hour, 10) < 0 || parseInt(hour, 10) >= 24 || parseInt(minute, 10) < 0 ||
parseInt(minute, 10) >= 60) {
return -2;
}

const userDailyTime = `${parseInt(hour, 10)} ${parseInt(minute, 10)}`

// Modify time if user already set daily time, add time if not
if (!isDailyTimeAlreadySet){
const response = await MongoUtil.addTime(discordId, userDailyTime);
if (!response){
return -1;
}
}else{
const response = await MongoUtil.modifyTime(discordId, userDailyTime);
if (!response){
return -1;
}
}
return 0;

}

export async function execute(message: Message) {
await getUserDailyTime(message);
}

27 changes: 27 additions & 0 deletions src/commands/deactivate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {ChatInputCommandInteraction, SlashCommandBuilder} from "discord.js";
import {MongoUtil} from "../util/mongoUtil.js";
import {logger} from "../logger.js";

export default {
data: new SlashCommandBuilder()
.setName('deactivate')
.setDescription('일일 문제 알림 수신을 비활성화 합니다.'),
async execute(interaction: ChatInputCommandInteraction) {
try {
const user = await MongoUtil.findUserWithDiscordId(interaction.user.id);
if (!user) {
await interaction.reply("등록되지 않은 유저입니다. /register를 통해 등록해주세요.")
return;
}

const response = await MongoUtil.deleteTime(interaction.user.id);
if (response) {
await interaction.reply("정상적으로 중단되었습니다.")
}
return;
} catch (error: any) {
await interaction.reply("알 수 없는 오류가 발생했습니다.")
logger.error(error.message)
}
}
}
13 changes: 9 additions & 4 deletions src/commands/help.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import {embedWelcome} from '../embedMessage/guideMessage.js';
import {Message} from "discord.js";
import {ChatInputCommandInteraction, Message, SlashCommandBuilder} from "discord.js";

export async function execute(message: Message){
message.channel.send({embeds: [embedWelcome]})
}
export default {
data: new SlashCommandBuilder()
.setName('help')
.setDescription('도움말을 보여줍니다.'),
async execute(interaction: ChatInputCommandInteraction){
await interaction.reply({embeds: [embedWelcome]})
}
}
10 changes: 10 additions & 0 deletions src/commands/ping.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {ChatInputCommandInteraction, CommandInteraction, SlashCommandBuilder} from "discord.js";

export default {
data: new SlashCommandBuilder().setName('ping').setDescription('Replies with Pong!'),
async execute(interaction: ChatInputCommandInteraction) {
console.log('input')

await interaction.reply('Pong!');
}
}
Loading

0 comments on commit 451981e

Please sign in to comment.