generated from nhcarrigan/template
feat: add birthday system
This commit is contained in:
143
src/commands/birthday.ts
Normal file
143
src/commands/birthday.ts
Normal file
@ -0,0 +1,143 @@
|
||||
import { SlashCommandBuilder } from "discord.js";
|
||||
|
||||
import { Command } from "../interfaces/Command";
|
||||
import { errorHandler } from "../utils/errorHandler";
|
||||
|
||||
/**
|
||||
* Validates that the day provided is a valid day of the month.
|
||||
*
|
||||
* @param {string} month The month to validate.
|
||||
* @param {number} day The day to validate.
|
||||
* @returns {boolean} True if the day is within the month's range.
|
||||
*/
|
||||
const validateDate = (month: string, day: number): boolean => {
|
||||
switch (month) {
|
||||
case "Jan":
|
||||
case "Mar":
|
||||
case "May":
|
||||
case "Jul":
|
||||
case "Aug":
|
||||
case "Oct":
|
||||
case "Dec":
|
||||
return day >= 1 && day <= 31;
|
||||
case "Feb":
|
||||
return day >= 1 && day <= 29;
|
||||
case "Apr":
|
||||
case "Jun":
|
||||
case "Sep":
|
||||
case "Nov":
|
||||
return day >= 1 && day <= 30;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const bbset: Command = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName("bbset")
|
||||
.setDescription("Set your birthday!")
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName("month")
|
||||
.setDescription("Your Birth Month")
|
||||
.setRequired(true)
|
||||
.setChoices(
|
||||
{
|
||||
name: "January",
|
||||
value: "Jan"
|
||||
},
|
||||
{
|
||||
name: "February",
|
||||
value: "Feb"
|
||||
},
|
||||
{
|
||||
name: "March",
|
||||
value: "Mar"
|
||||
},
|
||||
{
|
||||
name: "April",
|
||||
value: "Apr"
|
||||
},
|
||||
{
|
||||
name: "May",
|
||||
value: "May"
|
||||
},
|
||||
{
|
||||
name: "June",
|
||||
value: "Jun"
|
||||
},
|
||||
{
|
||||
name: "July",
|
||||
value: "Jul"
|
||||
},
|
||||
{
|
||||
name: "August",
|
||||
value: "Aug"
|
||||
},
|
||||
{
|
||||
name: "September",
|
||||
value: "Sep"
|
||||
},
|
||||
{
|
||||
name: "October",
|
||||
value: "Oct"
|
||||
},
|
||||
{
|
||||
name: "November",
|
||||
value: "Nov"
|
||||
},
|
||||
{
|
||||
name: "December",
|
||||
value: "Dec"
|
||||
}
|
||||
)
|
||||
)
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName("day")
|
||||
.setDescription("Your Birth Day (1-31)")
|
||||
.setRequired(true)
|
||||
.setMinValue(1)
|
||||
.setMaxValue(31)
|
||||
),
|
||||
run: async (bot, interaction) => {
|
||||
try {
|
||||
await interaction.deferReply();
|
||||
const month = interaction.options.getString("month", true);
|
||||
const day = interaction.options.getInteger("day", true);
|
||||
|
||||
if (!validateDate(month, day)) {
|
||||
await interaction.editReply({
|
||||
content: `${month} ${day} is not a valid date!`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await bot.db.birthdays.upsert({
|
||||
where: {
|
||||
serverId_userId: {
|
||||
serverId: interaction.guild.id,
|
||||
userId: interaction.user.id
|
||||
}
|
||||
},
|
||||
update: {
|
||||
birthday: new Date(`${month}-${day}-2000`)
|
||||
},
|
||||
create: {
|
||||
serverId: interaction.guild.id,
|
||||
userId: interaction.user.id,
|
||||
birthday: new Date(`${month}-${day}-2000`)
|
||||
}
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
`Your birthday has been set to ${month}-${day}!`
|
||||
);
|
||||
} catch (err) {
|
||||
const id = await errorHandler(bot, "birthday command", err);
|
||||
await interaction.editReply({
|
||||
content: `Something went wrong. Please [join our support server](https://chat.naomi.lgbt) and provide this ID: \`${id}\``
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
@ -11,6 +11,7 @@ import { Command } from "../interfaces/Command";
|
||||
import { CommandHandler } from "../interfaces/CommandHandler";
|
||||
import { getConfig } from "../modules/data/getConfig";
|
||||
import { handleAppealLink } from "../modules/subcommands/config/handleAppealLink";
|
||||
import { handleBirthdayChannel } from "../modules/subcommands/config/handleBirthdayChannel";
|
||||
import { handleInviteLink } from "../modules/subcommands/config/handleInviteLink";
|
||||
import { handleJoinRole } from "../modules/subcommands/config/handleJoinRole";
|
||||
import { handleList } from "../modules/subcommands/config/handleList";
|
||||
@ -24,7 +25,8 @@ const handlers: { [key: string]: CommandHandler } = {
|
||||
"appeal-link": handleAppealLink,
|
||||
logging: handleLogging,
|
||||
role: handleRole,
|
||||
"join-role": handleJoinRole
|
||||
"join-role": handleJoinRole,
|
||||
"birthday-channel": handleBirthdayChannel
|
||||
};
|
||||
|
||||
export const config: Command = {
|
||||
@ -101,6 +103,19 @@ export const config: Command = {
|
||||
.setDescription("The role to assign.")
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
.addSubcommand(
|
||||
new SlashCommandSubcommandBuilder()
|
||||
.setName("birthday-channel")
|
||||
.setDescription(
|
||||
"Configure a channel where members can be wished a happy birthday."
|
||||
)
|
||||
.addChannelOption((o) =>
|
||||
o
|
||||
.setName("channel")
|
||||
.setDescription("The channel to send birthday messages in.")
|
||||
.setRequired(true)
|
||||
)
|
||||
),
|
||||
run: async (bot, interaction) => {
|
||||
try {
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { scheduleJob } from "node-schedule";
|
||||
|
||||
import { ExtendedClient } from "../../interfaces/ExtendedClient";
|
||||
import { postBirthdays } from "../../modules/postBirthdays";
|
||||
import { registerCommands } from "../../utils/registerCommands";
|
||||
import { sendDebugMessage } from "../../utils/sendDebugMessage";
|
||||
|
||||
@ -10,4 +13,7 @@ import { sendDebugMessage } from "../../utils/sendDebugMessage";
|
||||
export const onReady = async (bot: ExtendedClient) => {
|
||||
await sendDebugMessage(bot, `Logged in as ${bot.user?.tag}`);
|
||||
await registerCommands(bot);
|
||||
|
||||
// Daily at 9am PST
|
||||
scheduleJob("birthdays", "0 9 * * *", async () => await postBirthdays(bot));
|
||||
};
|
||||
|
@ -20,6 +20,12 @@ export const onMemberRemove = async (
|
||||
|
||||
const config = await getConfig(bot, guild.id);
|
||||
|
||||
await bot.db.birthdays.delete({
|
||||
where: {
|
||||
serverId_userId: { serverId: guild.id, userId: user.id }
|
||||
}
|
||||
});
|
||||
|
||||
if (!config.eventLogChannel) {
|
||||
return;
|
||||
}
|
||||
|
41
src/modules/postBirthdays.ts
Normal file
41
src/modules/postBirthdays.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import { ExtendedClient } from "../interfaces/ExtendedClient";
|
||||
import { errorHandler } from "../utils/errorHandler";
|
||||
|
||||
/**
|
||||
* Fetches the configs from the database, then for each config that
|
||||
* has a birthday channel set, fetch birthdays. If any are from today,
|
||||
* post!
|
||||
*
|
||||
* @param {ExtendedClient} bot The bot's Discord instance.
|
||||
*/
|
||||
export const postBirthdays = async (bot: ExtendedClient) => {
|
||||
try {
|
||||
const configs = await bot.db.configs.findMany();
|
||||
const withChannel = configs.filter((c) => c.birthdayChannel);
|
||||
for (const record of withChannel) {
|
||||
const guild = bot.guilds.cache.get(record.serverId);
|
||||
if (!guild) {
|
||||
continue;
|
||||
}
|
||||
const channel = guild.channels.cache.get(record.birthdayChannel);
|
||||
if (!channel || !("send" in channel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const hasBirthdaySet = await bot.db.birthdays.findMany({
|
||||
where: { serverId: guild.id }
|
||||
});
|
||||
const today = new Date();
|
||||
const todayIn2000 = new Date(
|
||||
`2000-${today.getMonth() + 1}-${today.getDate()}`
|
||||
);
|
||||
const isBirthdayToday = hasBirthdaySet.filter(
|
||||
(r) => r.birthday === todayIn2000
|
||||
);
|
||||
const names = isBirthdayToday.map((r) => `<@${r.userId}>`).join(", ");
|
||||
await channel.send(`Happy birthday to these lovely people~!\n${names}`);
|
||||
}
|
||||
} catch (err) {
|
||||
await errorHandler(bot, "post birthdays", err);
|
||||
}
|
||||
};
|
52
src/modules/subcommands/config/handleBirthdayChannel.ts
Normal file
52
src/modules/subcommands/config/handleBirthdayChannel.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { PermissionFlagsBits } from "discord.js";
|
||||
|
||||
import { CommandHandler } from "../../../interfaces/CommandHandler";
|
||||
import { errorHandler } from "../../../utils/errorHandler";
|
||||
import { setConfig } from "../../data/setConfig";
|
||||
|
||||
/**
|
||||
* Sets the birthday channel for the server.
|
||||
*/
|
||||
export const handleBirthdayChannel: CommandHandler = async (
|
||||
bot,
|
||||
interaction
|
||||
) => {
|
||||
try {
|
||||
const channel = interaction.options.getChannel("channel", true);
|
||||
if (!("send" in channel)) {
|
||||
await interaction.editReply({
|
||||
content: "You must specify a text channel!"
|
||||
});
|
||||
return;
|
||||
}
|
||||
const me = await interaction.guild.members.fetchMe();
|
||||
if (!me.permissionsIn(channel).has(PermissionFlagsBits.SendMessages)) {
|
||||
await interaction.editReply({
|
||||
content: "I can't send messages there. :c"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const success = await setConfig(
|
||||
bot,
|
||||
interaction.guild.id,
|
||||
"birthdayChannel",
|
||||
channel.id
|
||||
);
|
||||
|
||||
if (success) {
|
||||
await interaction.editReply({
|
||||
content: `Birthdays will be posted in ${channel.toString()}. Members can set their birthdays with the \`/birthday\` command.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
await interaction.editReply({
|
||||
content: "Failed to set the settings."
|
||||
});
|
||||
} catch (err) {
|
||||
const id = await errorHandler(bot, "automod logging subcommand", err);
|
||||
await interaction.editReply({
|
||||
content: `Something went wrong. Please [join our support server](https://chat.naomi.lgbt) and provide this ID: \`${id}\``
|
||||
});
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user