diff --git a/src/index.ts b/src/index.ts index 47f71f7..39611d9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,7 +11,7 @@ const roleService = new RoleService(client); client.once(Events.ClientReady, async (readyClient) => { // Initialize & validate await commandService.init(); - roleService.validate(); + roleService.validate(client.guilds.cache); // Ready! console.log(`Ready! Logged in as ${readyClient.user.tag}`); @@ -30,7 +30,7 @@ client.on("messageCreate", async (message) => { Bun.cron("0 */6 * * *", async () => { for (const guild of client.guilds.cache.values()) { - const lurkerRole = roleService.getRoleByName(guild, roleService.ROLES["LURKER"]); + const lurkerRole = roleService.getRoleByName(guild, RoleService.ROLES["LURKER"]?.name); if (!lurkerRole) continue; await guild.members.prune({ days: 5, roles: [lurkerRole] }); diff --git a/src/services/cmd/registry/chan.ts b/src/services/cmd/registry/chan.ts index 1b90c9c..a22379c 100644 --- a/src/services/cmd/registry/chan.ts +++ b/src/services/cmd/registry/chan.ts @@ -4,11 +4,21 @@ import Chan from "../../../util/chan"; export default { name: "chan", - description: "Get random media from a 4chan board. Usage: .chan [search]", + description: "Get random media from a 4chan board.", + usage: ".chan [search]", execute: async (message: Message) => { const [, board, search] = message.content.split(/\s+/); - if (!board) return message.reply("Usage: .chan [search]"); - if (Chan.isNsfwBoard(board)) return message.reply("Fuck off nigger"); + + if (!board) { + await message.reply("Usage: .chan [search]") + return; + }; + + if (Chan.isNsfwBoard(board)) { + await message.reply("Fuck off nigger") + return; + }; + await message.reply(await Chan.getMediaLink(board, search)); } -} as Command; +} satisfies Command; diff --git a/src/services/cmd/registry/comfy.ts b/src/services/cmd/registry/comfy.ts index 2fcf2fe..de42525 100644 --- a/src/services/cmd/registry/comfy.ts +++ b/src/services/cmd/registry/comfy.ts @@ -4,10 +4,11 @@ import Chan from "../../../util/chan"; export default { name: "comfy", - description: "Get comfy content from 4chan", + description: "Get comfy content from 4chan.", + usage: ".comfy", execute: async (message: Message) => { const boards = ["wsg", "wg"]; const board = boards[Math.floor(Math.random() * boards.length)] ?? "wsg"; await message.reply(await Chan.getMediaLink(board, "comfy")); } -} as Command; +} satisfies Command; diff --git a/src/services/cmd/registry/mode.ts b/src/services/cmd/registry/mode.ts new file mode 100644 index 0000000..54bb254 --- /dev/null +++ b/src/services/cmd/registry/mode.ts @@ -0,0 +1,10 @@ +import type { Message } from "discord.js"; +import type { Command } from "../service"; + +export default { + name: "limbo", + description: "Toggles on/off limbo mode. When limbo mode is on, new members will be placed in #limbo. When off, new members will be placed in #chat-and-shitpost.", + usage: ".limbo [on|off]", + execute: async (message: Message) => { + } +} satisfies Command; diff --git a/src/services/cmd/registry/redpillme.ts b/src/services/cmd/registry/redpillme.ts index 41194aa..b6c585f 100644 --- a/src/services/cmd/registry/redpillme.ts +++ b/src/services/cmd/registry/redpillme.ts @@ -3,12 +3,13 @@ import type { Command } from "../service"; export default { name: "redpillme", - description: "Receive wisdom from the Unabomber", + description: "Receive wisdom from the Unabomber.", + usage: ".redpillme", execute: async (message: Message) => { const quote = quotes[Math.floor(Math.random() * quotes.length)]; await message.reply(quote!); } -} as Command; +} satisfies Command; const quotes = [ "Our society tends to regard as a sickness any mode of thought or behavior that is inconvenient for the system and this is plausible because when an individual doesn't fit into the system it causes pain to the individual as well as problems for the system. Thus the manipulation of an individual to adjust him to the system is seen as a cure for a sickness and therefore as good.", diff --git a/src/services/cmd/service.ts b/src/services/cmd/service.ts index 25203e1..31a4dd1 100644 --- a/src/services/cmd/service.ts +++ b/src/services/cmd/service.ts @@ -6,6 +6,7 @@ const CMD_PREFIX = "."; export interface Command { name: string, description: string, + usage: string, execute: (message: Message) => void | Promise } diff --git a/src/services/role/service.ts b/src/services/role/service.ts index d69e4b0..3ecb97a 100644 --- a/src/services/role/service.ts +++ b/src/services/role/service.ts @@ -1,42 +1,103 @@ -import type { Client, Guild, GuildMember } from "discord.js"; +import type { Client, Guild, GuildMember, Collection, RoleCreateOptions } from "discord.js"; export default class RoleService { - ROLES = { - "ROBOT": "robot", - "NORMALFAG": "normalfag", - "FEMOID": "femoid", - "GAY": "gay", - "TROID": "troid", - "LURKER": "lurker", - "NEWFAG": "newfag", - "LIMBO": "limbo" + static readonly ROLES: Record = { + // Main + "ROBOT": { + name: "robot", + colors: { primaryColor: "#58a9df" }, + hoist: true, + mentionable: true, + position: 1, + }, + "FEMOID": { + name: "femoid", + colors: { primaryColor: "#ffb2f4" }, + hoist: true, + mentionable: true, + position: 2, + }, + "NORMALFAG": { + name: "normalfag", + colors: { primaryColor: "#e26254" }, + hoist: true, + mentionable: true, + position: 3, + }, + "GAY": { + name: "gay", + colors: { primaryColor: "#71368a" }, + hoist: true, + mentionable: true, + position: 4, + }, + "TROID": { + name: "troid", + colors: { primaryColor: "#992d22" }, + hoist: true, + mentionable: true, + position: 5, + }, + "LURKER": { + name: "lurker", + colors: { primaryColor: "#546e7a" }, + hoist: true, + mentionable: true, + position: 6, + }, + // Utility + "NEWFAG": { + name: "newfag", + mentionable: true, + position: 7, + }, + "LIMBO": { + name: "limbo", + position: 8, + } }; - private client: Client + static readonly STARTER_ROLES = [RoleService.ROLES["LURKER"], RoleService.ROLES["NEWFAG"]]; - private starterRoles = [this.ROLES["LURKER"], this.ROLES["NEWFAG"]]; + private client: Client constructor(client: Client) { this.client = client; } - validate(): void { - this.client.guilds.cache.forEach(guild => { - const missing = Object.values(this.ROLES).filter(name => !guild.roles.cache.find(r => r.name === name)); + validate(guilds: Collection): void { + guilds.forEach(guild => { + const missing = Object.values(RoleService.ROLES).filter(role => !this.getRoleByName(guild, role.name)); if (missing.length) console.error(`${guild.name} is missing roles: ${missing.join(",")}`); }); } - async giveStarterRoles(guildMember: GuildMember) { - for (const starterRole of this.starterRoles) { - const role = this.getRoleByName(guildMember.guild, starterRole); - if (!role) continue; - - await guildMember.roles.add(role); + async createRoles(guild: Guild, roles: RoleCreateOptions[]) { + for (const role of roles) { + try { + await guild.roles.create(role); + } + catch (err) { + console.error(`Failed to create role: ${role.name}`, err); + } } } - getRoleByName(guild: Guild, roleName: string) { + async giveStarterRoles(guildMember: GuildMember) { + for (const starterRole of RoleService.STARTER_ROLES) { + const role = this.getRoleByName(guildMember.guild, starterRole?.name); + if (!role) continue; + + try { + await guildMember.roles.add(role); + } + catch (err) { + console.error(`Failed to add starter role: ${role.name}`, err); + } + } + } + + getRoleByName(guild: Guild, roleName?: string) { return guild.roles.cache.find(role => role.name === roleName); } }