From f5bda6ba55b74b677b6bb12049869f672a8db19e Mon Sep 17 00:00:00 2001 From: niklhut <49069026+niklhut@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:27:19 +0100 Subject: [PATCH 01/15] Check all guilds the bot is in on start (#17) * Await all events to be registered * Log in at the end to ensure ready event is executed * Run eslint --- src/bot.ts | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/bot.ts b/src/bot.ts index c399fcd..f62433a 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,13 +1,12 @@ import { ConfigHandler } from "./handlers/configHandler"; import { Client, Collection, Partials, TextChannel, VoiceChannel } from "discord.js"; import consola, { ConsolaInstance } from "consola"; -import cron, { CronJob } from "cron"; -import { BotConfig, BotEvent, ButtonInteraction, Command } from "../typings"; +import { CronJob } from "cron"; +import { BotEvent, ButtonInteraction, Command } from "../typings"; import glob from "glob-promise"; -import { promisify } from "util"; import * as fs from "fs"; import * as utils from "./utils/utils"; -import {GuildModel} from "./models/guilds"; +import { GuildModel } from "./models/guilds"; import parser from "yargs-parser"; import mongoose from "mongoose"; import path from "path/posix"; @@ -31,7 +30,7 @@ export class Bot extends Client { public parser = parser; public database = mongoose; public readonly initTimestamp = Date.now(); - public jobs: CronJob[] = []; + public jobs: CronJob[] = []; public constructor() { super({ intents: [ @@ -61,14 +60,6 @@ export class Bot extends Client { * @param config The bot Configuration */ public async start(): Promise { - this.logger.info("starting Bot..."); - try { - await this.login(this.config.get("token")); - } catch (error) { - this.logger.error("Invalid token", error); - process.exit(1); - } - // Commands this.logger.info("Loading Commands..."); const commandFiles = fs.readdirSync(`${__dirname}/commands`).filter(file => file.endsWith(".js") || file.endsWith("ts")); @@ -135,12 +126,12 @@ export class Bot extends Client { // Event Files this.logger.info("Loading Events..."); const eventFiles = fs.readdirSync(`${__dirname}/events`).filter(file => file.endsWith(".js") || file.endsWith("ts")); - await eventFiles.map(async (eventFile: string) => { + await Promise.all(eventFiles.map(async (eventFile: string) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const event = (await import(`${__dirname}/events/${eventFile}`)) as BotEvent; console.log(`${JSON.stringify(event.name)} (./events/${eventFile})`); this.on(event.name, event.execute.bind(null, this)); - }); + })); const queueGuardJob = new CronJob("*/30 * * * * *", async () => { for (const g of this.guilds.cache.values()) { @@ -194,6 +185,14 @@ export class Bot extends Client { }, null, true, "America/Los_Angeles"); queueGuardJob.start(); + this.logger.info("starting Bot..."); + try { + await this.login(this.config.get("token")); + } catch (error) { + this.logger.error("Invalid token", error); + process.exit(1); + } + this.logger.ready(`Bot ${this.user?.displayName} is Ready!`); // public async createGuildCommand(data:any, guildId:string) { From 018fb804b3e7dcfdd778f5c68a3d6550e514bafc Mon Sep 17 00:00:00 2001 From: niklhut <49069026+niklhut@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:29:59 +0100 Subject: [PATCH 02/15] Add rules to eslint and autofix (#19) * Add options to eslint * Add option to remove unused imports * Run eslint fix --- .eslintrc.json | 23 +++++++++++--- package-lock.json | 31 +++++++++++++++++++ package.json | 1 + src/commands/admin/decrypttoken.ts | 8 ++--- src/commands/admin/fixverify.ts | 4 +-- src/commands/admin/generatetoken.ts | 2 +- src/commands/admin/genverifyroles.ts | 5 ++- src/commands/admin/member/lookup-by.ts | 6 +--- src/commands/admin/member/lookup.ts | 8 ++--- src/commands/admin/member/unverify.ts | 6 +--- src/commands/admin/queue/fixup.ts | 7 ++--- src/commands/admin/queue/info.ts | 3 +- src/commands/admin/queue/kick.ts | 4 +-- src/commands/admin/queue/list.ts | 4 +-- src/commands/admin/queue/lock.ts | 6 ++-- src/commands/admin/queue/unlock.ts | 6 ++-- src/commands/admin/queue/userrank.ts | 9 +++--- src/commands/admin/queue/userstats.ts | 6 ++-- src/commands/admin/serverstats.ts | 7 ++--- src/commands/admin/session/list.ts | 7 ++--- src/commands/admin/session/terminate.ts | 8 ++--- src/commands/admin/session/terminateall.ts | 8 ++--- src/commands/coach/info.ts | 4 +-- src/commands/coach/queue/info.ts | 4 +-- src/commands/coach/queue/list.ts | 5 ++- src/commands/coach/queue/next.ts | 8 ++--- src/commands/coach/queue/pick.ts | 8 ++--- src/commands/coach/session/info.ts | 4 +-- src/commands/coach/session/quit.ts | 4 +-- src/commands/coach/session/start.ts | 6 ++-- src/commands/config/commands/permission.ts | 2 +- src/commands/config/commands/rename.ts | 4 +-- src/commands/config/commands/visibility.ts | 4 +-- src/commands/config/queue/add_unlock_time.ts | 6 ++-- src/commands/config/queue/autolock.ts | 4 +-- src/commands/config/queue/get_schedules.ts | 6 ++-- .../config/queue/remove_unlock_time.ts | 6 ++-- src/commands/config/queue/set_category.ts | 5 ++- .../config/queue/set_closing_shift.ts | 7 ++--- .../config/queue/set_opening_shift.ts | 7 ++--- src/commands/config/queue/set_text_channel.ts | 8 ++--- src/commands/create-queue.ts | 2 +- src/commands/help.ts | 4 +-- src/commands/ping.ts | 9 +++--- src/commands/queue/info.ts | 2 +- src/commands/queue/join.ts | 5 ++- src/commands/queue/leave.ts | 4 +-- src/commands/queue/list.ts | 3 +- src/commands/rate.ts | 4 +-- src/commands/setjointocreate.ts | 2 +- src/commands/setqueue.ts | 2 +- src/commands/urban.ts | 4 +-- src/commands/verify.ts | 6 ++-- src/commands/voice/close.ts | 3 +- src/commands/voice/kick.ts | 3 +- src/commands/voice/lock.ts | 3 +- src/commands/voice/permit.ts | 3 +- src/commands/voice/togglelock.ts | 3 +- src/commands/voice/togglevisibility.ts | 3 +- src/commands/voice/transfer.ts | 3 +- src/commands/voice/unlock.ts | 3 +- .../buttons/queue/leave.ts | 2 +- .../buttons/queue/stay.ts | 2 +- src/events/GuildCreateEvent.ts | 6 ++-- src/events/InteractionCreateEvent.ts | 8 ++--- src/events/MessageCreateEvent.ts | 4 +-- src/events/ReadyEvent.ts | 4 +-- src/events/VoiceStateUpdateEvent.ts | 11 +++---- src/events/guildMemberAddEvent.ts | 8 ++--- src/events/guildMemberRemoveEvent.ts | 2 +- src/handlers/configHandler.ts | 1 - src/models/database_mockup.ts | 4 +-- src/models/events.ts | 10 +++--- src/models/queues.ts | 3 +- src/models/sessions.ts | 14 ++++----- src/models/slash_command_settings.ts | 4 +-- src/models/text_channels.ts | 8 ++--- src/models/voice_channel_spawner.ts | 12 +++---- src/models/week_timestamp.ts | 2 +- src/utils/embeds.ts | 4 +-- src/utils/errors.ts | 3 +- src/utils/general.ts | 6 ++-- src/utils/utils.ts | 2 +- src/utils/voice.ts | 2 +- 84 files changed, 207 insertions(+), 257 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index c940a14..9b95074 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -13,9 +13,21 @@ "sourceType": "module" }, "plugins": [ - "@typescript-eslint" + "@typescript-eslint", + "unused-imports" ], "rules": { + "object-curly-spacing": [ + "warn", + "always" + ], + "comma-spacing": [ + "warn", + { + "before": false, + "after": true + } + ], "indent": [ "error", 4 @@ -34,9 +46,12 @@ ], "@typescript-eslint/no-non-null-assertion": "off", "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": [ - "warn" - ], + "@typescript-eslint/no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": [ + "warn", + { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } + ], "prefer-const": "warn", "@typescript-eslint/no-empty-interface": [ "warn", diff --git a/package-lock.json b/package-lock.json index 7dcfab4..aebf9ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "@typescript-eslint/parser": "^6.7.5", "chai": "^4.3.10", "eslint": "^8.51.0", + "eslint-plugin-unused-imports": "^3.0.0", "jest": "^29.7.0", "mocha": "^10.2.0", "nodemon": "^3.0.1", @@ -3365,6 +3366,36 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-plugin-unused-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", + "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.0.0", + "eslint": "^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", diff --git a/package.json b/package.json index fc7cc4b..8759e8e 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@typescript-eslint/parser": "^6.7.5", "chai": "^4.3.10", "eslint": "^8.51.0", + "eslint-plugin-unused-imports": "^3.0.0", "jest": "^29.7.0", "mocha": "^10.2.0", "nodemon": "^3.0.1", diff --git a/src/commands/admin/decrypttoken.ts b/src/commands/admin/decrypttoken.ts index 035b949..b5d77ea 100644 --- a/src/commands/admin/decrypttoken.ts +++ b/src/commands/admin/decrypttoken.ts @@ -1,10 +1,6 @@ -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../typings"; import "moment-duration-format"; -import {UserModel, User } from "../../models/users"; -import {GuildModel} from "../../models/guilds"; -import { DBRole, InternalRoles, RoleScopes } from "../../models/bot_roles"; -import { Types } from "mongoose"; @@ -37,7 +33,7 @@ const command: Command = { } catch (error) { return await client.utils.embeds.SimpleEmbed(interaction, { title: "Verification System Error", text: "Token is not valid.", empheral: true }); } - return client.utils.embeds.SimpleEmbed(interaction, { title: "Decrypted Text", text: `decrypted: ${decrypted}`, empheral:true}); + return client.utils.embeds.SimpleEmbed(interaction, { title: "Decrypted Text", text: `decrypted: ${decrypted}`, empheral:true }); }, }; diff --git a/src/commands/admin/fixverify.ts b/src/commands/admin/fixverify.ts index 81269c5..aa036d9 100644 --- a/src/commands/admin/fixverify.ts +++ b/src/commands/admin/fixverify.ts @@ -1,8 +1,8 @@ import { Message, Role } from "discord.js"; import { Command } from "../../../typings"; import "moment-duration-format"; -import {UserModel, User } from "../../models/users"; -import {GuildModel} from "../../models/guilds"; +import { UserModel } from "../../models/users"; +import { GuildModel } from "../../models/guilds"; import { DBRole, InternalRoles, RoleScopes } from "../../models/bot_roles"; import { Types } from "mongoose"; import { DocumentType } from "@typegoose/typegoose"; diff --git a/src/commands/admin/generatetoken.ts b/src/commands/admin/generatetoken.ts index e2c202b..4e34420 100644 --- a/src/commands/admin/generatetoken.ts +++ b/src/commands/admin/generatetoken.ts @@ -28,7 +28,7 @@ const command: Command = { } const encrypted = client.utils.general.encryptText(interaction.options.getString("encryptionstring", true)); const decrypted = client.utils.general.decryptText(encrypted); - return client.utils.embeds.SimpleEmbed(interaction, { title: "Encrypted+Decrypted Text", text: `encrypted: ${encrypted}\ndecrypted: ${decrypted}`, empheral:true}); + return client.utils.embeds.SimpleEmbed(interaction, { title: "Encrypted+Decrypted Text", text: `encrypted: ${encrypted}\ndecrypted: ${decrypted}`, empheral:true }); }, }; diff --git a/src/commands/admin/genverifyroles.ts b/src/commands/admin/genverifyroles.ts index 9aa8e7a..88be986 100644 --- a/src/commands/admin/genverifyroles.ts +++ b/src/commands/admin/genverifyroles.ts @@ -1,10 +1,9 @@ import { Message, Role } from "discord.js"; import { Command } from "../../../typings"; import "moment-duration-format"; -import {UserModel, User } from "../../models/users"; -import {GuildModel} from "../../models/guilds"; +import { GuildModel } from "../../models/guilds"; import { DBRole, InternalRoles, RoleScopes } from "../../models/bot_roles"; -import { ArraySubDocumentType, DocumentType, mongoose } from "@typegoose/typegoose"; +import { ArraySubDocumentType, mongoose } from "@typegoose/typegoose"; diff --git a/src/commands/admin/member/lookup-by.ts b/src/commands/admin/member/lookup-by.ts index 041bad5..270d860 100644 --- a/src/commands/admin/member/lookup-by.ts +++ b/src/commands/admin/member/lookup-by.ts @@ -1,10 +1,6 @@ import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; -import moment from "moment"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel, User } from "../../../models/users"; -import {SessionModel} from "../../../models/sessions"; -import {QueueModel} from "../../../models/queues"; +import { UserModel, User } from "../../../models/users"; import { FilterQuery } from "mongoose"; import { DocumentType, mongoose } from "@typegoose/typegoose"; import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; diff --git a/src/commands/admin/member/lookup.ts b/src/commands/admin/member/lookup.ts index a628bb8..a72f8cd 100644 --- a/src/commands/admin/member/lookup.ts +++ b/src/commands/admin/member/lookup.ts @@ -1,10 +1,6 @@ -import { ApplicationCommandOptionType, EmbedData, EmbedField, Message } from "discord.js"; -import moment from "moment"; +import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {SessionModel} from "../../../models/sessions"; -import {QueueModel} from "../../../models/queues"; +import { UserModel } from "../../../models/users"; const command: Command = { name: "lookup", diff --git a/src/commands/admin/member/unverify.ts b/src/commands/admin/member/unverify.ts index 8c7e788..96a433e 100644 --- a/src/commands/admin/member/unverify.ts +++ b/src/commands/admin/member/unverify.ts @@ -1,10 +1,6 @@ import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; -import moment from "moment"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {SessionModel} from "../../../models/sessions"; -import {QueueModel} from "../../../models/queues"; +import { UserModel } from "../../../models/users"; const command: Command = { name: "unverify", diff --git a/src/commands/admin/queue/fixup.ts b/src/commands/admin/queue/fixup.ts index 730f44e..9fcb03a 100644 --- a/src/commands/admin/queue/fixup.ts +++ b/src/commands/admin/queue/fixup.ts @@ -1,8 +1,7 @@ -import { ApplicationCommandOptionType, EmbedField, Message, Role } from "discord.js"; -import path from "path"; +import { ApplicationCommandOptionType, Message, Role } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; const command: Command = { name: "fixup", diff --git a/src/commands/admin/queue/info.ts b/src/commands/admin/queue/info.ts index 6157e20..f51a684 100644 --- a/src/commands/admin/queue/info.ts +++ b/src/commands/admin/queue/info.ts @@ -1,7 +1,6 @@ import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "info", diff --git a/src/commands/admin/queue/kick.ts b/src/commands/admin/queue/kick.ts index 0fa54c4..a038d8d 100644 --- a/src/commands/admin/queue/kick.ts +++ b/src/commands/admin/queue/kick.ts @@ -1,8 +1,6 @@ import { ApplicationCommandOptionType, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "kick", diff --git a/src/commands/admin/queue/list.ts b/src/commands/admin/queue/list.ts index 52ceae1..59e1fa5 100644 --- a/src/commands/admin/queue/list.ts +++ b/src/commands/admin/queue/list.ts @@ -1,8 +1,6 @@ import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "list", diff --git a/src/commands/admin/queue/lock.ts b/src/commands/admin/queue/lock.ts index 6109b72..5cc42b3 100644 --- a/src/commands/admin/queue/lock.ts +++ b/src/commands/admin/queue/lock.ts @@ -1,8 +1,6 @@ -import { ApplicationCommandOptionType, EmbedField, Message, VoiceChannel } from "discord.js"; -import path from "path"; +import { ApplicationCommandOptionType, Message, VoiceChannel } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "lock", diff --git a/src/commands/admin/queue/unlock.ts b/src/commands/admin/queue/unlock.ts index 04b6f24..b7eb6af 100644 --- a/src/commands/admin/queue/unlock.ts +++ b/src/commands/admin/queue/unlock.ts @@ -1,8 +1,6 @@ -import { ApplicationCommandOptionType, EmbedField, Message, VoiceChannel } from "discord.js"; -import path from "path"; +import { ApplicationCommandOptionType, Message, VoiceChannel } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "unlock", diff --git a/src/commands/admin/queue/userrank.ts b/src/commands/admin/queue/userrank.ts index fabb580..7e4ea7c 100644 --- a/src/commands/admin/queue/userrank.ts +++ b/src/commands/admin/queue/userrank.ts @@ -1,9 +1,8 @@ import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {RoomModel} from "../../../models/rooms"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; +import { RoomModel } from "../../../models/rooms"; const command: Command = { name: "userrank", @@ -75,7 +74,7 @@ const command: Command = { inline: false, }); } catch (error) { - client.logger.error(`could not get user details for ${u._id}`,error); + client.logger.error(`could not get user details for ${u._id}`, error); fields.push({ name: u._id, value: `-Sprechstunden Beigetreten: ${u.roomCount}`, diff --git a/src/commands/admin/queue/userstats.ts b/src/commands/admin/queue/userstats.ts index 47f3ea0..f76aa94 100644 --- a/src/commands/admin/queue/userstats.ts +++ b/src/commands/admin/queue/userstats.ts @@ -1,9 +1,7 @@ import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {RoomModel} from "../../../models/rooms"; +import { GuildModel } from "../../../models/guilds"; +import { RoomModel } from "../../../models/rooms"; const command: Command = { name: "userstats", diff --git a/src/commands/admin/serverstats.ts b/src/commands/admin/serverstats.ts index a37dbe8..1b2427c 100644 --- a/src/commands/admin/serverstats.ts +++ b/src/commands/admin/serverstats.ts @@ -1,10 +1,7 @@ -import { ApplicationCommandOptionType, AttachmentBuilder, AuditLogEvent, Collection, GuildAuditLogs, GuildAuditLogsEntry, Message } from "discord.js"; +import { ApplicationCommandOptionType, AttachmentBuilder, AuditLogEvent, Collection, GuildAuditLogsEntry, Message } from "discord.js"; import { Command } from "../../../typings"; -import { version as djsversion } from "discord.js"; -import * as moment from "moment"; import "moment-duration-format"; import { ChartJSNodeCanvas } from "chartjs-node-canvas"; -import { string } from "yargs"; import { APIRole } from "discord-api-types/v9"; @@ -172,7 +169,7 @@ const command: Command = { }, }, ); - const attachment = new AttachmentBuilder(image, {name: "graph.png"}); + const attachment = new AttachmentBuilder(image, { name: "graph.png" }); await client.utils.embeds.SimpleEmbed(interaction, { title: "Server Stats", text: "Server Information", diff --git a/src/commands/admin/session/list.ts b/src/commands/admin/session/list.ts index 2474491..56e1492 100644 --- a/src/commands/admin/session/list.ts +++ b/src/commands/admin/session/list.ts @@ -1,10 +1,7 @@ import { EmbedField, Message } from "discord.js"; -import moment from "moment"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {SessionModel} from "../../../models/sessions"; -import {QueueModel} from "../../../models/queues"; +import { GuildModel } from "../../../models/guilds"; +import { SessionModel } from "../../../models/sessions"; const command: Command = { name: "list", diff --git a/src/commands/admin/session/terminate.ts b/src/commands/admin/session/terminate.ts index 344c3f8..82a8e79 100644 --- a/src/commands/admin/session/terminate.ts +++ b/src/commands/admin/session/terminate.ts @@ -1,10 +1,8 @@ -import { ApplicationCommandOptionType, EmbedField, GuildMember, Message, User } from "discord.js"; +import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; import moment from "moment"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {SessionModel} from "../../../models/sessions"; -import {QueueModel} from "../../../models/queues"; +import { GuildModel } from "../../../models/guilds"; +import { SessionModel } from "../../../models/sessions"; const command: Command = { name: "terminate", diff --git a/src/commands/admin/session/terminateall.ts b/src/commands/admin/session/terminateall.ts index b289495..58433d3 100644 --- a/src/commands/admin/session/terminateall.ts +++ b/src/commands/admin/session/terminateall.ts @@ -1,10 +1,8 @@ -import { EmbedField, GuildMember, Message, User } from "discord.js"; +import { EmbedField, Message } from "discord.js"; import moment from "moment"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {SessionModel} from "../../../models/sessions"; -import {QueueModel} from "../../../models/queues"; +import { GuildModel } from "../../../models/guilds"; +import { SessionModel } from "../../../models/sessions"; const command: Command = { name: "terminateall", diff --git a/src/commands/coach/info.ts b/src/commands/coach/info.ts index d0aefba..819129e 100644 --- a/src/commands/coach/info.ts +++ b/src/commands/coach/info.ts @@ -1,8 +1,8 @@ import { Message } from "discord.js"; import moment from "moment"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import {UserModel} from "../../models/users"; +import { GuildModel } from "../../models/guilds"; +import { UserModel } from "../../models/users"; const command: Command = { name: "info", diff --git a/src/commands/coach/queue/info.ts b/src/commands/coach/queue/info.ts index 079ecb6..78b9e0a 100644 --- a/src/commands/coach/queue/info.ts +++ b/src/commands/coach/queue/info.ts @@ -1,7 +1,7 @@ import { Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; const command: Command = { name: "info", diff --git a/src/commands/coach/queue/list.ts b/src/commands/coach/queue/list.ts index a5828b0..49b4403 100644 --- a/src/commands/coach/queue/list.ts +++ b/src/commands/coach/queue/list.ts @@ -1,8 +1,7 @@ import { ApplicationCommandOptionType, EmbedField, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; const command: Command = { name: "list", diff --git a/src/commands/coach/queue/next.ts b/src/commands/coach/queue/next.ts index 080ac12..80459be 100644 --- a/src/commands/coach/queue/next.ts +++ b/src/commands/coach/queue/next.ts @@ -1,10 +1,10 @@ -import {EventModel, Event as EVT, eventType } from "./../../../models/events"; +import { Event as EVT, eventType } from "./../../../models/events"; import { PermissionOverwriteData } from "./../../../models/permission_overwrite_data"; import ChannelType, { ApplicationCommandOptionType, Message, TextChannel } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {RoomModel} from "../../../models/rooms"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; +import { RoomModel } from "../../../models/rooms"; import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; import { mongoose } from "@typegoose/typegoose"; diff --git a/src/commands/coach/queue/pick.ts b/src/commands/coach/queue/pick.ts index 852eccf..cc51955 100644 --- a/src/commands/coach/queue/pick.ts +++ b/src/commands/coach/queue/pick.ts @@ -1,11 +1,11 @@ import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; -import {EventModel, Event as EVT, eventType } from "../../../models/events"; +import { Event as EVT, eventType } from "../../../models/events"; import { PermissionOverwriteData } from "../../../models/permission_overwrite_data"; import ChannelType, { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {RoomModel} from "../../../models/rooms"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; +import { RoomModel } from "../../../models/rooms"; import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; import { mongoose } from "@typegoose/typegoose"; diff --git a/src/commands/coach/session/info.ts b/src/commands/coach/session/info.ts index ad70fdd..7ec1111 100644 --- a/src/commands/coach/session/info.ts +++ b/src/commands/coach/session/info.ts @@ -1,8 +1,8 @@ import { Message } from "discord.js"; import moment from "moment"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; const command: Command = { name: "info", diff --git a/src/commands/coach/session/quit.ts b/src/commands/coach/session/quit.ts index 7d7f29a..3d1387f 100644 --- a/src/commands/coach/session/quit.ts +++ b/src/commands/coach/session/quit.ts @@ -1,7 +1,7 @@ import { Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; import moment from "moment"; const command: Command = { diff --git a/src/commands/coach/session/start.ts b/src/commands/coach/session/start.ts index 79e34d0..cf44d12 100644 --- a/src/commands/coach/session/start.ts +++ b/src/commands/coach/session/start.ts @@ -1,8 +1,8 @@ import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import {UserModel} from "../../../models/users"; -import {SessionModel, sessionRole } from "../../../models/sessions"; +import { GuildModel } from "../../../models/guilds"; +import { UserModel } from "../../../models/users"; +import { SessionModel, sessionRole } from "../../../models/sessions"; import { Queue } from "../../../models/queues"; import { DocumentType } from "@typegoose/typegoose"; diff --git a/src/commands/config/commands/permission.ts b/src/commands/config/commands/permission.ts index ea3f4ac..4af6df2 100644 --- a/src/commands/config/commands/permission.ts +++ b/src/commands/config/commands/permission.ts @@ -1,7 +1,7 @@ import { SlashCommandPermission } from "./../../../models/slash_command_permission"; import { ApplicationCommandOptionType, Message, Role } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "permission", diff --git a/src/commands/config/commands/rename.ts b/src/commands/config/commands/rename.ts index 0a834a2..c02e6c0 100644 --- a/src/commands/config/commands/rename.ts +++ b/src/commands/config/commands/rename.ts @@ -1,8 +1,6 @@ -import { SlashCommandSettings } from "./../../../models/slash_command_settings"; import { ApplicationCommandOptionType, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "rename", diff --git a/src/commands/config/commands/visibility.ts b/src/commands/config/commands/visibility.ts index 6261971..f27cb6c 100644 --- a/src/commands/config/commands/visibility.ts +++ b/src/commands/config/commands/visibility.ts @@ -1,8 +1,6 @@ -import { SlashCommandSettings } from "./../../../models/slash_command_settings"; import { ApplicationCommandOptionType, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "visibility", diff --git a/src/commands/config/queue/add_unlock_time.ts b/src/commands/config/queue/add_unlock_time.ts index f54f155..2a595d2 100644 --- a/src/commands/config/queue/add_unlock_time.ts +++ b/src/commands/config/queue/add_unlock_time.ts @@ -1,8 +1,6 @@ -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; import { QueueSpan } from "../../../models/queue_span"; const command: Command = { diff --git a/src/commands/config/queue/autolock.ts b/src/commands/config/queue/autolock.ts index d73291d..216159c 100644 --- a/src/commands/config/queue/autolock.ts +++ b/src/commands/config/queue/autolock.ts @@ -1,6 +1,4 @@ -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; import { GuildModel } from "../../../models/guilds"; diff --git a/src/commands/config/queue/get_schedules.ts b/src/commands/config/queue/get_schedules.ts index cb65032..c11754e 100644 --- a/src/commands/config/queue/get_schedules.ts +++ b/src/commands/config/queue/get_schedules.ts @@ -1,8 +1,6 @@ -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; import { QueueSpan } from "../../../models/queue_span"; import { WeekTimestamp } from "../../../models/week_timestamp"; diff --git a/src/commands/config/queue/remove_unlock_time.ts b/src/commands/config/queue/remove_unlock_time.ts index 2d151fb..81bb0c7 100644 --- a/src/commands/config/queue/remove_unlock_time.ts +++ b/src/commands/config/queue/remove_unlock_time.ts @@ -1,8 +1,6 @@ -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; import { QueueSpan } from "../../../models/queue_span"; import { WeekTimestamp } from "../../../models/week_timestamp"; diff --git a/src/commands/config/queue/set_category.ts b/src/commands/config/queue/set_category.ts index 5ffebe5..43614d6 100644 --- a/src/commands/config/queue/set_category.ts +++ b/src/commands/config/queue/set_category.ts @@ -1,9 +1,8 @@ import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; import { VoiceChannelSpawner } from "./../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "./../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; +import { GuildModel } from "../../../models/guilds"; import { mongoose } from "@typegoose/typegoose"; const command: Command = { diff --git a/src/commands/config/queue/set_closing_shift.ts b/src/commands/config/queue/set_closing_shift.ts index a16968d..6284f18 100644 --- a/src/commands/config/queue/set_closing_shift.ts +++ b/src/commands/config/queue/set_closing_shift.ts @@ -1,9 +1,6 @@ -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import { QueueSpan } from "../../../models/queue_span"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "set_closing_shift", diff --git a/src/commands/config/queue/set_opening_shift.ts b/src/commands/config/queue/set_opening_shift.ts index ea18367..07f3dc6 100644 --- a/src/commands/config/queue/set_opening_shift.ts +++ b/src/commands/config/queue/set_opening_shift.ts @@ -1,9 +1,6 @@ -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import { QueueSpan } from "../../../models/queue_span"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "set_opening_shift", diff --git a/src/commands/config/queue/set_text_channel.ts b/src/commands/config/queue/set_text_channel.ts index 24a7548..17fb6ab 100644 --- a/src/commands/config/queue/set_text_channel.ts +++ b/src/commands/config/queue/set_text_channel.ts @@ -1,10 +1,6 @@ -import { Channel } from "./../../../models/text_channels"; -import { VoiceChannelSpawner } from "../../../models/voice_channel_spawner"; -import { SlashCommandPermission } from "../../../models/slash_command_permission"; -import { ApplicationCommandOptionType, Message, Role } from "discord.js"; +import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../../../typings"; -import {GuildModel} from "../../../models/guilds"; -import { QueueSpan } from "../../../models/queue_span"; +import { GuildModel } from "../../../models/guilds"; const command: Command = { name: "set_text_channel", diff --git a/src/commands/create-queue.ts b/src/commands/create-queue.ts index dd00d38..306d763 100644 --- a/src/commands/create-queue.ts +++ b/src/commands/create-queue.ts @@ -1,6 +1,6 @@ import { ApplicationCommandOptionType, Message } from "discord.js"; import { Command } from "../../typings"; -import {GuildModel} from "../models/guilds"; +import { GuildModel } from "../models/guilds"; import { Queue } from "../models/queues"; import { mongoose } from "@typegoose/typegoose"; import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; diff --git a/src/commands/help.ts b/src/commands/help.ts index 5cf9ae1..e725b20 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -1,7 +1,7 @@ import { ApplicationCommandOptionType, EmojiIdentifierResolvable, Message, EmbedBuilder } from "discord.js"; import yargsParser from "yargs-parser"; -import { Command, RunCommand } from "../../typings"; -import {GuildModel} from "../models/guilds"; +import { Command } from "../../typings"; +import { GuildModel } from "../models/guilds"; const command: Command = { diff --git a/src/commands/ping.ts b/src/commands/ping.ts index 310b6a5..dd397fd 100644 --- a/src/commands/ping.ts +++ b/src/commands/ping.ts @@ -1,6 +1,5 @@ -import { ChatInputCommandInteraction, Interaction, Message, EmbedBuilder } from "discord.js"; -import { Command, RunCommand } from "../../typings"; -import { APIMessage } from "discord-api-types/v9"; +import { ChatInputCommandInteraction, Message, EmbedBuilder } from "discord.js"; +import { Command } from "../../typings"; /** * The Command Definition @@ -30,8 +29,8 @@ const command: Command = { const embed = new EmbedBuilder() .setTitle("__Response Times__") .setColor(interaction!.guild?.members.me?.roles.highest.color || 0x7289da) - .addFields({name:"Bot Latency:", value:":hourglass_flowing_sand:" + ping + "ms", inline:true}) - .addFields({name:"API Latency:", value:":hourglass_flowing_sand:" + Math.round(client.ws.ping) + "ms", inline:true}); + .addFields({ name:"Bot Latency:", value:":hourglass_flowing_sand:" + ping + "ms", inline:true }) + .addFields({ name:"API Latency:", value:":hourglass_flowing_sand:" + Math.round(client.ws.ping) + "ms", inline:true }); if (interaction instanceof ChatInputCommandInteraction) { await interaction.editReply({ content: "Pong.", embeds: [embed] }); } else { diff --git a/src/commands/queue/info.ts b/src/commands/queue/info.ts index 68168a2..6d7cda2 100644 --- a/src/commands/queue/info.ts +++ b/src/commands/queue/info.ts @@ -1,6 +1,6 @@ import { Message, EmbedField } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "info", diff --git a/src/commands/queue/join.ts b/src/commands/queue/join.ts index 27c7aab..c6376ae 100644 --- a/src/commands/queue/join.ts +++ b/src/commands/queue/join.ts @@ -1,8 +1,7 @@ import { ApplicationCommandOptionType, Message } from "discord.js"; -import path from "path"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import {UserModel} from "../../models/users"; +import { GuildModel } from "../../models/guilds"; +import { UserModel } from "../../models/users"; const command: Command = { name: "join", diff --git a/src/commands/queue/leave.ts b/src/commands/queue/leave.ts index ed78359..eb51148 100644 --- a/src/commands/queue/leave.ts +++ b/src/commands/queue/leave.ts @@ -1,8 +1,6 @@ import { Message } from "discord.js"; -import moment from "moment"; -import path from "path"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "leave", diff --git a/src/commands/queue/list.ts b/src/commands/queue/list.ts index e374893..f6ceee1 100644 --- a/src/commands/queue/list.ts +++ b/src/commands/queue/list.ts @@ -1,7 +1,6 @@ -import { Queue } from "./../../models/queues"; import { Message } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "list", diff --git a/src/commands/rate.ts b/src/commands/rate.ts index 27be955..6161017 100644 --- a/src/commands/rate.ts +++ b/src/commands/rate.ts @@ -1,5 +1,5 @@ -import { ApplicationCommandOptionType, ChatInputCommandInteraction, EmbedBuilder } from "discord.js"; -import { Command, RunCommand } from "../../typings"; +import { ApplicationCommandOptionType, ChatInputCommandInteraction } from "discord.js"; +import { Command } from "../../typings"; /** * The Command Definition diff --git a/src/commands/setjointocreate.ts b/src/commands/setjointocreate.ts index b5b7885..83f06b2 100644 --- a/src/commands/setjointocreate.ts +++ b/src/commands/setjointocreate.ts @@ -1,6 +1,6 @@ import { ApplicationCommandOptionType, CategoryChannel, GuildChannel, Message, VoiceChannel as dvc } from "discord.js"; import { Command } from "../../typings"; -import {GuildModel} from "../models/guilds"; +import { GuildModel } from "../models/guilds"; import { VoiceChannel } from "../models/voice_channels"; import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; import { mongoose } from "@typegoose/typegoose"; diff --git a/src/commands/setqueue.ts b/src/commands/setqueue.ts index 2226e05..43e8b24 100644 --- a/src/commands/setqueue.ts +++ b/src/commands/setqueue.ts @@ -1,7 +1,7 @@ import { VoiceChannelModel } from "./../models/voice_channels"; import { ApplicationCommandOptionType, GuildChannel, Message } from "discord.js"; import { Command } from "../../typings"; -import {GuildModel} from "../models/guilds"; +import { GuildModel } from "../models/guilds"; import { VoiceChannel } from "../models/voice_channels"; import { mongoose } from "@typegoose/typegoose"; import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; diff --git a/src/commands/urban.ts b/src/commands/urban.ts index 8312db1..df34970 100644 --- a/src/commands/urban.ts +++ b/src/commands/urban.ts @@ -1,7 +1,7 @@ import { stripIndents } from "common-tags"; import * as urban from "urban-dictionary"; -import { ApplicationCommandOptionType, ChatInputCommandInteraction, Interaction, Message, EmbedBuilder } from "discord.js"; -import { Command, RunCommand } from "../../typings"; +import { ApplicationCommandOptionType, ChatInputCommandInteraction, EmbedBuilder } from "discord.js"; +import { Command } from "../../typings"; /** * The Command Definition diff --git a/src/commands/verify.ts b/src/commands/verify.ts index 34146be..ae8bc0f 100644 --- a/src/commands/verify.ts +++ b/src/commands/verify.ts @@ -1,7 +1,5 @@ -import { UserModel, User } from "./../models/users"; -import { ApplicationCommandOptionType, GuildMember, Interaction, Message } from "discord.js"; -import { Command, RunCommand } from "../../typings"; -import * as crypto from "crypto"; +import { ApplicationCommandOptionType, Message } from "discord.js"; +import { Command } from "../../typings"; /** * The Command Definition diff --git a/src/commands/voice/close.ts b/src/commands/voice/close.ts index 85e5670..3188629 100644 --- a/src/commands/voice/close.ts +++ b/src/commands/voice/close.ts @@ -1,7 +1,6 @@ import { Message } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "close", diff --git a/src/commands/voice/kick.ts b/src/commands/voice/kick.ts index a02e91a..d0ab5ae 100644 --- a/src/commands/voice/kick.ts +++ b/src/commands/voice/kick.ts @@ -1,7 +1,6 @@ import { ApplicationCommandOptionType, GuildMember, Message } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "kick", diff --git a/src/commands/voice/lock.ts b/src/commands/voice/lock.ts index d980653..968b4e8 100644 --- a/src/commands/voice/lock.ts +++ b/src/commands/voice/lock.ts @@ -1,6 +1,5 @@ import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "lock", diff --git a/src/commands/voice/permit.ts b/src/commands/voice/permit.ts index c139d8f..07c8b13 100644 --- a/src/commands/voice/permit.ts +++ b/src/commands/voice/permit.ts @@ -1,7 +1,6 @@ import { ApplicationCommandOptionType, GuildMember, Message } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "permit", diff --git a/src/commands/voice/togglelock.ts b/src/commands/voice/togglelock.ts index dc6ff1e..bf4ec49 100644 --- a/src/commands/voice/togglelock.ts +++ b/src/commands/voice/togglelock.ts @@ -1,7 +1,6 @@ import { OverwriteData } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "togglelock", diff --git a/src/commands/voice/togglevisibility.ts b/src/commands/voice/togglevisibility.ts index 56de897..0a60c06 100644 --- a/src/commands/voice/togglevisibility.ts +++ b/src/commands/voice/togglevisibility.ts @@ -1,6 +1,5 @@ import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "togglevisibility", diff --git a/src/commands/voice/transfer.ts b/src/commands/voice/transfer.ts index f58433c..f6f1153 100644 --- a/src/commands/voice/transfer.ts +++ b/src/commands/voice/transfer.ts @@ -1,7 +1,6 @@ import { ApplicationCommandOptionType, GuildMember, Message } from "discord.js"; import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "transfer", diff --git a/src/commands/voice/unlock.ts b/src/commands/voice/unlock.ts index 5df5ec1..00ce396 100644 --- a/src/commands/voice/unlock.ts +++ b/src/commands/voice/unlock.ts @@ -1,6 +1,5 @@ import { Command } from "../../../typings"; -import {GuildModel} from "../../models/guilds"; -import { VoiceChannel } from "../../models/voice_channels"; +import { GuildModel } from "../../models/guilds"; const command: Command = { name: "unlock", diff --git a/src/componentInteractions/buttons/queue/leave.ts b/src/componentInteractions/buttons/queue/leave.ts index cda1bbc..0a6eccf 100644 --- a/src/componentInteractions/buttons/queue/leave.ts +++ b/src/componentInteractions/buttons/queue/leave.ts @@ -1,4 +1,4 @@ -import { Collection, EmbedBuilder } from "discord.js"; +import { EmbedBuilder } from "discord.js"; import { ButtonInteraction } from "../../../../typings"; import { GuildModel, Guild } from "../../../models/guilds"; import { Queue } from "../../../models/queues"; diff --git a/src/componentInteractions/buttons/queue/stay.ts b/src/componentInteractions/buttons/queue/stay.ts index 12e1cb5..239b4ac 100644 --- a/src/componentInteractions/buttons/queue/stay.ts +++ b/src/componentInteractions/buttons/queue/stay.ts @@ -1,6 +1,6 @@ import { ActionRowBuilder, ButtonBuilder, ButtonStyle, Collection, EmbedBuilder } from "discord.js"; import { ButtonInteraction } from "../../../../typings"; -import {GuildModel, Guild } from "../../../models/guilds"; +import { GuildModel, Guild } from "../../../models/guilds"; import { Queue } from "../../../models/queues"; import { DocumentType } from "@typegoose/typegoose"; diff --git a/src/events/GuildCreateEvent.ts b/src/events/GuildCreateEvent.ts index 759c989..e9cd653 100644 --- a/src/events/GuildCreateEvent.ts +++ b/src/events/GuildCreateEvent.ts @@ -1,7 +1,5 @@ -import { ClientEventListener, ExecuteEvent } from "../../typings"; -import { ApplicationCommandData, ApplicationCommandOptionChoiceData, Client, ClientEvents, Guild } from "discord.js"; -import {GuildModel} from "../models/guilds"; -import { inspect } from "util"; +import { ExecuteEvent } from "../../typings"; +import { GuildModel } from "../models/guilds"; export const name = "guildCreate"; diff --git a/src/events/InteractionCreateEvent.ts b/src/events/InteractionCreateEvent.ts index 05f019b..ab6e9dc 100644 --- a/src/events/InteractionCreateEvent.ts +++ b/src/events/InteractionCreateEvent.ts @@ -1,9 +1,7 @@ -import { Command, ExecuteEvent } from "../../typings"; -import { ChatInputCommandInteraction, Collection, CommandInteractionOption } from "discord.js"; +import { ExecuteEvent } from "../../typings"; +import { ChatInputCommandInteraction, Collection } from "discord.js"; export const name = "interactionCreate"; -import {GuildModel} from "../models/guilds"; -import { DocumentType, isDocument } from "@typegoose/typegoose"; -import { GuildSettings } from "../models/guild_settings"; +import { GuildModel } from "../models/guilds"; export const execute: ExecuteEvent<"interactionCreate"> = async (client, interaction) => { diff --git a/src/events/MessageCreateEvent.ts b/src/events/MessageCreateEvent.ts index d17e746..f34c990 100644 --- a/src/events/MessageCreateEvent.ts +++ b/src/events/MessageCreateEvent.ts @@ -1,8 +1,6 @@ import { ExecuteEvent } from "../../typings"; -import { Collection, Guild, GuildMember, Message } from "discord.js"; +import { Collection } from "discord.js"; export const name = "messageCreate"; -import * as crypto from "crypto"; -import {UserModel} from "../models/users"; export const execute: ExecuteEvent<"messageCreate"> = async (client, message) => { if (message.partial) { diff --git a/src/events/ReadyEvent.ts b/src/events/ReadyEvent.ts index cc343ee..7918861 100644 --- a/src/events/ReadyEvent.ts +++ b/src/events/ReadyEvent.ts @@ -1,6 +1,6 @@ import { ExecuteEvent } from "../../typings"; import { ActivityType, ApplicationCommandData } from "discord.js"; -import {GuildModel} from "../models/guilds"; +import { GuildModel } from "../models/guilds"; export const execute: ExecuteEvent<"ready"> = async (client) => { // -- Setup Databases -- // @@ -27,7 +27,7 @@ export const execute: ExecuteEvent<"ready"> = async (client) => { // Guilds client.logger.info("Processing Guilds"); for (const g of [...client.guilds.cache.values()]) { - await GuildModel.prepareGuild(client,g); + await GuildModel.prepareGuild(client, g); } await client.user?.setPresence({ status: "online", activities: [{ name: "Sprechstunden.", type: ActivityType.Watching }], afk: false }); diff --git a/src/events/VoiceStateUpdateEvent.ts b/src/events/VoiceStateUpdateEvent.ts index a4cf509..8621e9b 100644 --- a/src/events/VoiceStateUpdateEvent.ts +++ b/src/events/VoiceStateUpdateEvent.ts @@ -1,13 +1,10 @@ import { ExecuteEvent } from "../../typings"; -import { Collection, ActionRow, Embed, ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder, APIMessageActionRowComponent } from "discord.js"; -import {GuildModel} from "../models/guilds"; -import { VoiceChannel } from "../models/voice_channels"; -import { Queue } from "../models/queues"; +import { Collection, ActionRowBuilder, ButtonBuilder, ButtonStyle, EmbedBuilder } from "discord.js"; +import { GuildModel } from "../models/guilds"; import { QueueEntry } from "../models/queue_entry"; export const name = "voiceStateUpdate"; -import {RoomModel} from "../models/rooms"; -import {UserModel} from "../models/users"; -import {EventModel, Event as EVT, eventType } from "../models/events"; +import { RoomModel } from "../models/rooms"; +import { Event as EVT, eventType } from "../models/events"; export const execute: ExecuteEvent<"voiceStateUpdate"> = async (client, oldState, newState) => { const oldUserChannel = oldState.channel; diff --git a/src/events/guildMemberAddEvent.ts b/src/events/guildMemberAddEvent.ts index 5894b2d..879a349 100644 --- a/src/events/guildMemberAddEvent.ts +++ b/src/events/guildMemberAddEvent.ts @@ -1,8 +1,6 @@ -import { ClientEventListener, ExecuteEvent, StringReplacements } from "../../typings"; -import { ApplicationCommandData, ApplicationCommandOptionChoiceData, Client, ClientEvents, Guild } from "discord.js"; -import {GuildModel} from "../models/guilds"; -import {UserModel} from "../models/users"; -import { inspect } from "util"; +import { ExecuteEvent, StringReplacements } from "../../typings"; +import { GuildModel } from "../models/guilds"; +import { UserModel } from "../models/users"; export const name = "guildMemberAdd"; diff --git a/src/events/guildMemberRemoveEvent.ts b/src/events/guildMemberRemoveEvent.ts index 24a1cb7..8cfdce0 100644 --- a/src/events/guildMemberRemoveEvent.ts +++ b/src/events/guildMemberRemoveEvent.ts @@ -1,5 +1,5 @@ import { ExecuteEvent } from "../../typings"; -import {UserModel} from "../models/users"; +import { UserModel } from "../models/users"; export const name = "guildMemberRemove"; diff --git a/src/handlers/configHandler.ts b/src/handlers/configHandler.ts index 4dd5f51..f8ef3b9 100644 --- a/src/handlers/configHandler.ts +++ b/src/handlers/configHandler.ts @@ -1,5 +1,4 @@ import { BotConfig } from "../../typings"; -import dotenv from "dotenv"; /** * This is a readonly data class that holds the config of the bot. diff --git a/src/models/database_mockup.ts b/src/models/database_mockup.ts index a69a2eb..83bc06b 100644 --- a/src/models/database_mockup.ts +++ b/src/models/database_mockup.ts @@ -18,10 +18,10 @@ const sessions = active: true, user: "313753317484527616", guild: "604601483920408576", - queue: "queue_id",//optional + queue: "queue_id", //optional role: "coach", // participant|coach|supervisor started_at: "1629567410185", - ended_at: undefined,//Set when active=false + ended_at: undefined, //Set when active=false end_certain: false, // Only set to true if session had a clean exit rooms: ["626065226986553343", "626065222936553347"], }, diff --git a/src/models/events.ts b/src/models/events.ts index 600d211..135d46a 100644 --- a/src/models/events.ts +++ b/src/models/events.ts @@ -23,27 +23,27 @@ export class Event { /** * The Unix Time Stamp of the Event */ - @prop({required: true}) + @prop({ required: true }) timestamp!: string; /** * The Event Type */ - @prop({required: true, enum: eventType, default: eventType.other}) + @prop({ required: true, enum: eventType, default: eventType.other }) type!: eventType; /** * Client ID or "me" */ - @prop({required: true}) + @prop({ required: true }) emitted_by!: string; /** * A Target that was affected */ - @prop({required: false}) + @prop({ required: false }) target?: string; /** * The Reason why the Event was Emitted */ - @prop({required: false}) + @prop({ required: false }) reason?: string; } diff --git a/src/models/queues.ts b/src/models/queues.ts index beae820..8c3fdfe 100644 --- a/src/models/queues.ts +++ b/src/models/queues.ts @@ -4,7 +4,6 @@ import { QueueEntry } from "./queue_entry"; import * as utils from "../utils/utils"; import { StringReplacements } from "../../typings"; import * as moment from "moment"; -import momentDurationFormatSetup from "moment-duration-format"; import { QueueSpan } from "./queue_span"; import { Guild } from "./guilds"; import { VoiceChannelSpawner } from "./voice_channel_spawner"; @@ -146,7 +145,7 @@ export class Queue { * Returns true if the ID is contained in the queue * @param discord_id the Discord ID to check if it's contained */ - public contains(this:DocumentType,discord_id: string): boolean { + public contains(this:DocumentType, discord_id: string): boolean { return this.entries.some(x => x.discord_id === discord_id); } /** diff --git a/src/models/sessions.ts b/src/models/sessions.ts index 60ac1ac..2ab769d 100644 --- a/src/models/sessions.ts +++ b/src/models/sessions.ts @@ -1,5 +1,5 @@ -import {RoomModel} from "./rooms"; -import {DocumentType, getModelForClass, prop, mongoose} from "@typegoose/typegoose"; +import { RoomModel } from "./rooms"; +import { DocumentType, getModelForClass, prop, mongoose } from "@typegoose/typegoose"; export enum sessionRole { "participant" = "participant", "coach" = "coach", @@ -10,12 +10,12 @@ export class Session { /** * Whether the Session is currently active */ - @prop({required: true}) + @prop({ required: true }) active!: boolean; /** * The User that the Session belongs to */ - @prop({required: true}) + @prop({ required: true }) user!: string; /** * A Guild that the Session belongs to @@ -30,7 +30,7 @@ export class Session { /** * The Role that the user plays */ - @prop({required: true, enum: sessionRole}) + @prop({ required: true, enum: sessionRole }) role!: sessionRole; /** * The Start Timestamp @@ -45,12 +45,12 @@ export class Session { /** * Only set to true if session had a clean exit */ - @prop({required: true}) + @prop({ required: true }) end_certain!: boolean; /** * The Room IDs That Were Visited in the Session */ - @prop({required: true, type: () => [String], default: []}) + @prop({ required: true, type: () => [String], default: [] }) rooms!: mongoose.Types.Array; /** diff --git a/src/models/slash_command_settings.ts b/src/models/slash_command_settings.ts index 1cb0de0..f9656fc 100644 --- a/src/models/slash_command_settings.ts +++ b/src/models/slash_command_settings.ts @@ -1,11 +1,11 @@ import { SlashCommandPermission } from "./slash_command_permission"; import { PermissionResolvable } from "discord.js"; -import { ArraySubDocumentType, SubDocumentType, getModelForClass, prop, mongoose } from "@typegoose/typegoose"; +import { ArraySubDocumentType, getModelForClass, prop, mongoose } from "@typegoose/typegoose"; export class SlashCommandSettings { /** * The original Command name used to retrieve it from the event handler */ - @prop({ required: true,sparse: true }) + @prop({ required: true, sparse: true }) internal_name!: string; /** * The Command Name overwrite diff --git a/src/models/text_channels.ts b/src/models/text_channels.ts index b40ae97..dc4220a 100644 --- a/src/models/text_channels.ts +++ b/src/models/text_channels.ts @@ -1,5 +1,5 @@ import { ChannelType, TextChannelType } from "discord.js"; -import {getModelForClass, prop} from "@typegoose/typegoose"; +import { getModelForClass, prop } from "@typegoose/typegoose"; /** * Database Representation of a Discord Channel @@ -28,9 +28,9 @@ export interface Channel { } export class TextChannel implements Channel { - @prop({required: true}) + @prop({ required: true }) _id!: string; - @prop({ required: true, type: Number, enum: [ChannelType.DM, ChannelType.GroupDM, ChannelType.GuildAnnouncement, ChannelType.PublicThread, ChannelType.PrivateThread, ChannelType.AnnouncementThread, ChannelType.GuildText, ChannelType.GuildForum, ChannelType.GuildVoice, ChannelType.GuildStageVoice]}) + @prop({ required: true, type: Number, enum: [ChannelType.DM, ChannelType.GroupDM, ChannelType.GuildAnnouncement, ChannelType.PublicThread, ChannelType.PrivateThread, ChannelType.AnnouncementThread, ChannelType.GuildText, ChannelType.GuildForum, ChannelType.GuildVoice, ChannelType.GuildStageVoice] }) channel_type!: TextChannelType; @prop({ required: true }) managed!: boolean; @@ -51,7 +51,7 @@ export class TextChannel implements Channel { /** * WHETHER THE CHANNEL IS CAPS-ONLY */ - @prop({default: false}) + @prop({ default: false }) rage_channel?: boolean; } diff --git a/src/models/voice_channel_spawner.ts b/src/models/voice_channel_spawner.ts index aa7e766..ec43e94 100644 --- a/src/models/voice_channel_spawner.ts +++ b/src/models/voice_channel_spawner.ts @@ -1,5 +1,5 @@ import { PermissionOverwriteData } from "./permission_overwrite_data"; -import {prop,mongoose, getModelForClass, ArraySubDocumentType} from "@typegoose/typegoose"; +import { prop, mongoose, getModelForClass, ArraySubDocumentType } from "@typegoose/typegoose"; export class VoiceChannelSpawner { /** @@ -10,12 +10,12 @@ export class VoiceChannelSpawner { /** * The Roles that can moderate this channel */ - @prop({required: true, type: () => [String], default: []}) + @prop({ required: true, type: () => [String], default: [] }) supervisor_roles!: mongoose.Types.Array; /** * The Channel Permissions */ - @prop({required: true, type: () => [PermissionOverwriteData], default: []}) + @prop({ required: true, type: () => [PermissionOverwriteData], default: [] }) permission_overwrites!: mongoose.Types.DocumentArray>; /** * Limit the amount of Users that can join the channel @@ -25,17 +25,17 @@ export class VoiceChannelSpawner { /** * The Name of the Channel; use ${owner} and so on to create dynamic channel names */ - @prop({required: true, default: "${owner_name}'s VC"}) + @prop({ required: true, default: "${owner_name}'s VC" }) name!: string; /** * Whether the Channel should initially be locked or not */ - @prop({default: false}) + @prop({ default: false }) lock_initially?: boolean; /** * Whether the Channel should initially be hidden or not */ - @prop({default: false}) + @prop({ default: false }) hide_initially?: boolean; /** * The Category Channel ID diff --git a/src/models/week_timestamp.ts b/src/models/week_timestamp.ts index f591b65..4615973 100644 --- a/src/models/week_timestamp.ts +++ b/src/models/week_timestamp.ts @@ -39,7 +39,7 @@ export class WeekTimestamp { /** * The Day of the Week */ - @prop({ required: true,enum: Weekday }) + @prop({ required: true, enum: Weekday }) weekday!: Weekday; /** diff --git a/src/utils/embeds.ts b/src/utils/embeds.ts index 7e095bf..31a7745 100644 --- a/src/utils/embeds.ts +++ b/src/utils/embeds.ts @@ -1,6 +1,4 @@ -import { ColorResolvable, CommandInteraction, DMChannel, Guild, GuildResolvable, Interaction, InteractionReplyOptions, Message, Embed, NewsChannel, PartialDMChannel, TextBasedChannel, TextChannel, ThreadChannel, UserResolvable, EmbedBuilder, InteractionResponse } from "discord.js"; -import { APIMessage } from "discord-api-types/v9"; -import * as utils from "./utils"; +import { CommandInteraction, DMChannel, Message, NewsChannel, TextChannel, ThreadChannel, EmbedBuilder, InteractionResponse } from "discord.js"; import { SimpleEmbedOptions } from "../../typings"; export async function SimpleEmbed(interaction: Message | CommandInteraction | DMChannel | TextChannel | NewsChannel | ThreadChannel, title: string, description: string): Promise; diff --git a/src/utils/errors.ts b/src/utils/errors.ts index edde234..8dac797 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,6 +1,5 @@ -import { DiscordAPIError, Message, EmbedBuilder } from "discord.js"; +import { Message, EmbedBuilder } from "discord.js"; import * as discord from "discord.js"; -import { APIMessage } from "discord-api-types/v9"; // : (message: Message, error: string, deleteinterval: number => Promise) export const errorMessage = async (interaction: Message | discord.CommandInteraction, error: string | Error, deleteinterval?: number) => { if (!interaction.channel) { diff --git a/src/utils/general.ts b/src/utils/general.ts index 13b4cd5..50c761e 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -3,11 +3,9 @@ import { DBRole, InternalRoles, RoleScopes } from "./../models/bot_roles"; import ChannelType, { CommandInteraction, Guild, GuildMember, GuildMemberResolvable, GuildResolvable, Interaction, Message, RoleResolvable, UserResolvable } from "discord.js"; import moment from "moment"; import { Command, StringReplacements } from "../../typings"; -import { promisify } from "util"; -import {GuildModel} from "../models/guilds"; -import glob from "glob"; +import { GuildModel } from "../models/guilds"; import { Bot } from "../bot"; -import {UserModel} from "../models/users"; +import { UserModel } from "../models/users"; import * as cryptojs from "crypto-js"; import { DocumentType } from "@typegoose/typegoose"; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 21d67ce..3da88d2 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -9,7 +9,7 @@ import * as errors from "./errors"; import * as general from "./general"; import * as embeds from "./embeds"; import * as voice from "./voice"; -export {errors, general, embeds, voice}; +export { errors, general, embeds, voice }; // module.exports = { //TODO dynamically read new Util classes // errors: require('./errors'), // // functions: require('./functions'), diff --git a/src/utils/voice.ts b/src/utils/voice.ts index ce8d066..dec2481 100644 --- a/src/utils/voice.ts +++ b/src/utils/voice.ts @@ -1,7 +1,7 @@ import { FilterOutFunctionKeys } from "@typegoose/typegoose/lib/types"; import { ChannelType, Guild, GuildMember, GuildPremiumTier, OverwriteData } from "discord.js"; import { Bot } from "../bot"; -import {GuildModel} from "../models/guilds"; +import { GuildModel } from "../models/guilds"; import { VoiceChannel } from "../models/voice_channels"; import { VoiceChannelSpawner } from "../models/voice_channel_spawner"; import { mongoose } from "@typegoose/typegoose"; From 6d1028af773bb0d1edcf3927581fde0f0d39fb8c Mon Sep 17 00:00:00 2001 From: niklhut <49069026+niklhut@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:18:05 +0100 Subject: [PATCH 03/15] Improve build and push GitHub Action (#18) * Update and improve GitHub actions * Add name for job and remove source of old workflow * Add support for latest tag * Add support for tagging pull requests * Remove dedicated build action --- .github/workflows/build.yml | 29 ------------ .github/workflows/docker-img.yml | 78 ++++++++++++++++++++------------ 2 files changed, 49 insertions(+), 58 deletions(-) delete mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index a58d041..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Build - -# Controls when the workflow will run -on: - # Triggers the workflow on push events for all branches - push: - pull_request: - branches: - - main - - master - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - build: - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # 1. Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - name: Set up Git repository - uses: actions/checkout@v3 - - # 2. Test build using docker-compose - - name: Test build - run: docker compose build --no-cache diff --git a/.github/workflows/docker-img.yml b/.github/workflows/docker-img.yml index 72329bd..a6e9bda 100644 --- a/.github/workflows/docker-img.yml +++ b/.github/workflows/docker-img.yml @@ -1,49 +1,69 @@ -# shamelessly stolen from: https://github.com/CloudGoBrrr/server/blob/main/.github/workflows/main.yml name: Build and publish container on: release: - types: [published] + types: + - published push: branches: - main - master + pull_request: + branches: + - main + - master + +env: + REGISTRY: ghcr.io jobs: ghr_push: + name: Build and publish container runs-on: ubuntu-latest steps: - name: checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx - uses: docker/setup-buildx-action@v1 - - - name: Log-in to ghcr.io - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Build and push container image - run: | - IMAGE_ID=$(echo ghcr.io/${{ github.repository }} | tr '[A-Z]' '[a-z]') - - # Strip git ref prefix from version - VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - # Strip "v" prefix from tag name - [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') - # when the branch is master, replace master with latest - [ "$VERSION" == "master" ] && VERSION=latest - - echo IMAGE_ID=$IMAGE_ID - echo VERSION=$VERSION - - # Build and Publish container image - docker buildx build --push \ - --tag $IMAGE_ID:$VERSION \ - --build-arg CHECKOUT=${{ github.ref }} \ - --build-arg VERSION=$VERSION \ - --platform linux/amd64 . + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ github.repository }} + flavor: | + # don't set latest flavor since it is handled by the raw latest tag + latest=false + tags: | + # set tags for pushes to branches + type=ref,event=branch + # set tags for pull requests + type=ref,event=pr + # set tags for releases + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + # set latest tag for default branch + type=raw,value=latest,enable={{is_default_branch}} + - name: Build and push Docker image + uses: docker/build-push-action@v4 + with: + context: . + push: true + cache-from: type=gha + cache-to: type=gha,mode=max + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file From 62f5341903200828c503a37785df1c4f08250a25 Mon Sep 17 00:00:00 2001 From: niklhut <49069026+niklhut@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:09:31 +0100 Subject: [PATCH 04/15] Add permissions to job (#24) --- .github/workflows/docker-img.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/docker-img.yml b/.github/workflows/docker-img.yml index a6e9bda..c5dd8b9 100644 --- a/.github/workflows/docker-img.yml +++ b/.github/workflows/docker-img.yml @@ -20,6 +20,9 @@ jobs: ghr_push: name: Build and publish container runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - name: checkout From f1919c63c08eeabb722f049009962b960219ef2a Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Sun, 12 Nov 2023 19:43:01 +0100 Subject: [PATCH 05/15] improve discord token generation --- .gitignore | 3 ++- src/crypto_test.ts | 44 +++++++++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index e1ce007..33b022c 100644 --- a/.gitignore +++ b/.gitignore @@ -122,4 +122,5 @@ dist .pnp.* report*.csv -result.json \ No newline at end of file +result.json +result.json.bak diff --git a/src/crypto_test.ts b/src/crypto_test.ts index e8f9275..92cdcdf 100644 --- a/src/crypto_test.ts +++ b/src/crypto_test.ts @@ -14,7 +14,7 @@ dotenv.config(); * @returns the encrypted Text */ export function encryptText(text: string) { - return cryptojs.AES.encrypt(text, "mbvWKnjLFh4nHbj7Vx79rvp9kcJF9g4C").toString(); + return cryptojs.AES.encrypt(text, ConfigHandler.getInstance().get("verify_secret")).toString(); } /** @@ -55,6 +55,16 @@ type Student = { const fileContent = fs.readFileSync(csvFilePath, { encoding: "utf-8" }); + // if result.json.bak exists, read it and save a list of all moodleIds + const oldResultFilePath = path.resolve(__dirname, "result.json.bak"); + let oldMoodleIds: string[] = []; + if (fs.existsSync(oldResultFilePath)) { + const oldResultFileContent = fs.readFileSync(oldResultFilePath, { encoding: "utf-8" }); + const oldResult: { moodleId: string; token: string; }[] = JSON.parse(oldResultFileContent); + oldMoodleIds = oldResult.map(x => x.moodleId); + console.log(`Skipping ${oldMoodleIds.length} moodleIds`); + } + parse(fileContent, { delimiter: ",", columns: headers, @@ -63,21 +73,25 @@ type Student = { console.error(error); } // {"moodleId":"1","token":"FOP-DiscordV1|guest|1#5630c38fb1ae39b1048e0cf802f4170dba8943f5e13510055357b3cb67a3bac1"} - const newResult = result.map((student) => { - const token = encryptTokenString( - "1078710248086446120", - "01", - student.id_tu, - student.id_moodle, - [InternalRoles.VERIFIED], - ); - return { - moodleId: student.id_moodle, - token, - }; - }); + const newResult = result + .filter((student) => !isNaN(parseInt(student.id_moodle))) + .filter((student) => !oldMoodleIds.includes(student.id_moodle)) + .map((student) => { + const token = encryptTokenString( + "1078710248086446120", + "01", + student.id_tu, + student.id_moodle, + [InternalRoles.VERIFIED], + ); + return { + moodleId: student.id_moodle, + token, + }; + }); console.log("Result", newResult); - + console.log(`Found ${newResult.length} new moodleIds`); + // write result to result.json file fs.writeFileSync(path.resolve(__dirname, "result.json"), JSON.stringify(newResult, null, 4)); }); From 41f3a49c31ea7bbc689199ca3031d02b1b83546f Mon Sep 17 00:00:00 2001 From: AlphaKevin01 <56456245+AlphaKevin01@users.noreply.github.com> Date: Mon, 13 Nov 2023 17:41:06 +0100 Subject: [PATCH 06/15] added active_session role (#25) (#28) Co-authored-by: Kevin Siniecki --- src/commands/admin/fixverify.ts | 8 +++-- src/commands/admin/genverifyroles.ts | 8 ++++- src/commands/coach/session/quit.ts | 3 ++ src/commands/coach/session/start.ts | 4 +++ src/models/bot_roles.ts | 1 + src/utils/general.ts | 49 +++++++++++++++++++++++++++- 6 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/commands/admin/fixverify.ts b/src/commands/admin/fixverify.ts index aa036d9..eea9706 100644 --- a/src/commands/admin/fixverify.ts +++ b/src/commands/admin/fixverify.ts @@ -35,9 +35,11 @@ const command: Command = { let dbOrgaRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.SERVER_ADMIN); const tutorRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "tutor"); let dbTutorRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.TUTOR); + const activeSessionRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "active_session"); + let dbActiveSessionRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.ACTIVE_SESSION); // Create the roles if they don't exist - for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR]] as [Role, DocumentType, InternalRoles][])) { + for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR], [activeSessionRole, dbActiveSessionRole, InternalRoles.ACTIVE_SESSION]] as [Role, DocumentType, InternalRoles][])) { if (!r) continue; if (!dbr) { console.log(`creating role ${irn}`); @@ -56,6 +58,8 @@ const command: Command = { dbOrgaRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; } else if(irn === InternalRoles.TUTOR) { dbTutorRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; + } else if(irn === InternalRoles.ACTIVE_SESSION) { + dbActiveSessionRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; } } } @@ -64,7 +68,7 @@ const command: Command = { let count = 0; for (const u of users) { console.log(`(${++count}/${users.length}) updating roles for user ${u.tu_id}`); - for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR]] as [Role, DocumentType, InternalRoles][])) { + for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR], [activeSessionRole, dbActiveSessionRole, InternalRoles.ACTIVE_SESSION]] as [Role, DocumentType, InternalRoles][])) { if (!r || !dbr) continue; if (members.get(u._id)?.roles.cache.has(r.id)) { console.log(`${u.tu_id} has role ${irn}`); diff --git a/src/commands/admin/genverifyroles.ts b/src/commands/admin/genverifyroles.ts index 88be986..ff9eaf8 100644 --- a/src/commands/admin/genverifyroles.ts +++ b/src/commands/admin/genverifyroles.ts @@ -33,9 +33,13 @@ const command: Command = { let dbOrgaRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.SERVER_ADMIN); const tutorRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "tutor"); let dbTutorRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.TUTOR); + const activeSessionRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "active_session"); + let dbActiveSessionRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.ACTIVE_SESSION); + + // Create the roles if they don't exist - for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR]] as [Role, ArraySubDocumentType, InternalRoles][])) { + for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR], [activeSessionRole, dbActiveSessionRole, InternalRoles.ACTIVE_SESSION]] as [Role, ArraySubDocumentType, InternalRoles][])) { if (!r) continue; if (!dbr) { console.log(`creating role ${irn}`); @@ -56,6 +60,8 @@ const command: Command = { dbOrgaRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; } else if(irn === InternalRoles.TUTOR) { dbTutorRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; + } else if(irn === InternalRoles.ACTIVE_SESSION) { + dbActiveSessionRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; } } } diff --git a/src/commands/coach/session/quit.ts b/src/commands/coach/session/quit.ts index 3d1387f..941db49 100644 --- a/src/commands/coach/session/quit.ts +++ b/src/commands/coach/session/quit.ts @@ -3,6 +3,7 @@ import { Command } from "../../../../typings"; import { GuildModel } from "../../../models/guilds"; import { UserModel } from "../../../models/users"; import moment from "moment"; +import {removeRoleFromUser} from "../../../utils/general"; const command: Command = { name: "quit", @@ -33,6 +34,8 @@ const command: Command = { return await client.utils.embeds.SimpleEmbed(interaction, { title: "Coaching System", text: "You Have no Active Coaching Session.", empheral: true }); } + await removeRoleFromUser(g, user, 'active_session') + //TODO: Terminate Rooms // Set inactive diff --git a/src/commands/coach/session/start.ts b/src/commands/coach/session/start.ts index cf44d12..49aa152 100644 --- a/src/commands/coach/session/start.ts +++ b/src/commands/coach/session/start.ts @@ -5,6 +5,7 @@ import { UserModel } from "../../../models/users"; import { SessionModel, sessionRole } from "../../../models/sessions"; import { Queue } from "../../../models/queues"; import { DocumentType } from "@typegoose/typegoose"; +import {assignRoleToUser} from "../../../utils/general"; const command: Command = { name: "start", @@ -58,6 +59,9 @@ const command: Command = { const session = await SessionModel.create({ active: true, user: user.id, guild: g.id, queue: queueData._id, role: sessionRole.coach, started_at: Date.now(), end_certain: false, rooms: [] }); userEntry.sessions.push(session._id); await userEntry.save(); + + await assignRoleToUser(g, user, 'active_session') + client.utils.embeds.SimpleEmbed(interaction, { title: "Coaching System", text: "The Session was started.", empheral: true }); }, }; diff --git a/src/models/bot_roles.ts b/src/models/bot_roles.ts index d611639..6f20eb9 100644 --- a/src/models/bot_roles.ts +++ b/src/models/bot_roles.ts @@ -5,6 +5,7 @@ export enum InternalRoles { SERVER_ADMIN = "server_admin", TUTOR = "tutor", VERIFIED = "verified", + ACTIVE_SESSION = "active_session", BOT_OWNER = "bot_owner", BOT_ADMIN = "bot_admin", } diff --git a/src/utils/general.ts b/src/utils/general.ts index 50c761e..7b19ff6 100644 --- a/src/utils/general.ts +++ b/src/utils/general.ts @@ -1,6 +1,17 @@ import { ConfigHandler } from "./../handlers/configHandler"; import { DBRole, InternalRoles, RoleScopes } from "./../models/bot_roles"; -import ChannelType, { CommandInteraction, Guild, GuildMember, GuildMemberResolvable, GuildResolvable, Interaction, Message, RoleResolvable, UserResolvable } from "discord.js"; +import ChannelType, { + CommandInteraction, + Guild, + GuildMember, + GuildMemberResolvable, + GuildResolvable, + Interaction, + Message, + RoleResolvable, + User, + UserResolvable +} from "discord.js"; import moment from "moment"; import { Command, StringReplacements } from "../../typings"; import { GuildModel } from "../models/guilds"; @@ -364,6 +375,8 @@ function checkArgument(value: unknown, name: string) { } + + /** * The Possible Annotations for queue Stayings */ @@ -380,4 +393,38 @@ export enum QueueStayOptions { * Annotates user already left */ LEFT, +} + +/** + * Assigns an existing role to a member of a guild. + * @param g Guild + * @param user User to assign the role to + * @param roleName name of the role + */ +export async function assignRoleToUser(g: Guild, user: User, roleName: string) { + const roles = await g.roles.fetch(); + const role = roles.find(role => role.name.toLowerCase() === roleName.toLowerCase()); + const member = g.members.resolve(user); + if (role && member && !member.roles.cache.has(role.id)) { + await member.roles.add(role); + } else { + console.error(`Could not assign role: ${roleName} to ${user.username} on guild: ${g.name}`) + } +} + +/** + * Removes the given role from a user + * @param g Guild + * @param user User to remove the role from + * @param roleName name of the role + */ +export async function removeRoleFromUser(g: Guild, user: User, roleName: string) { + const roles = await g.roles.fetch(); + const role = roles.find(role => role.name.toLowerCase() === roleName.toLowerCase()); + const member = g.members.resolve(user); + if (role && member && member.roles.cache.has(role.id)) { + await member.roles.remove(role); + } else { + console.error(`Could not remove role: ${roleName} from ${user.username} on guild: ${g.name}`) + } } \ No newline at end of file From 501531ac15e72c5d1664ee0a0216bd13ce982739 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 11:36:22 +0100 Subject: [PATCH 07/15] Bump crypto-js from 4.1.1 to 4.2.0 (#23) Bumps [crypto-js](https://github.com/brix/crypto-js) from 4.1.1 to 4.2.0. - [Commits](https://github.com/brix/crypto-js/compare/4.1.1...4.2.0) --- updated-dependencies: - dependency-name: crypto-js dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index aebf9ed..1e9ffc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "commonjs": "^0.0.1", "consola": "^3.2.3", "cron": "^3.1.0", - "crypto-js": "^4.1.1", + "crypto-js": "^4.2.0", "csv-parse": "^5.5.2", "discord.js": "^14.13.0", "dotenv": "^16.3.1", @@ -2880,9 +2880,9 @@ } }, "node_modules/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "node_modules/css-select": { "version": "5.1.0", diff --git a/package.json b/package.json index 8759e8e..e1cae2f 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "commonjs": "^0.0.1", "consola": "^3.2.3", "cron": "^3.1.0", - "crypto-js": "^4.1.1", + "crypto-js": "^4.2.0", "csv-parse": "^5.5.2", "discord.js": "^14.13.0", "dotenv": "^16.3.1", From a2963845c4ce7360cf9c56bb51c62b6479dc7991 Mon Sep 17 00:00:00 2001 From: niklhut <49069026+niklhut@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:27:14 +0100 Subject: [PATCH 08/15] Fix supervisor roles for voice channels (#34) --- src/commands/coach/queue/next.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/coach/queue/next.ts b/src/commands/coach/queue/next.ts index 80459be..76b96cf 100644 --- a/src/commands/coach/queue/next.ts +++ b/src/commands/coach/queue/next.ts @@ -94,7 +94,7 @@ const command: Command = { // queueData.set("room_spawner", spawner); // await guildData.save(); } else { - spawner.supervisor_roles = new mongoose.Types.Array(...spawner.supervisor_roles.concat(queue_channel_data?.supervisors ?? [])); + spawner.supervisor_roles.push(...(queue_channel_data?.supervisors ?? [])); spawner.owner = user.id; if (spawner.name) { spawner.name = client.utils.general.interpolateString( From 75bfc4d7b8954b07dc02dd37ec11698747dd6c23 Mon Sep 17 00:00:00 2001 From: niklhut <49069026+niklhut@users.noreply.github.com> Date: Tue, 28 Nov 2023 20:28:47 +0100 Subject: [PATCH 09/15] Improve setup documentation (#33) * Add development docker compose with db port exposed * Add Setup page detailing how to setup a test server * Improve and update Readme --- README.md | 28 ++++++++++++++++++++-------- Setup.md | 28 ++++++++++++++++++++++++++++ docker-compose.development.yml | 12 ++++++++++++ 3 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 Setup.md create mode 100644 docker-compose.development.yml diff --git a/README.md b/README.md index c072fbc..d1c4c7f 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,28 @@ # Rubot2 -[![Build](https://github.com/Rdeisenroth/Rubot2/actions/workflows/build.yml/badge.svg)](https://github.com/Rdeisenroth/Rubot2/actions/workflows/build.yml) +[![Build](https://github.com/Rdeisenroth/Rubot2/actions/workflows/docker-img.yml/badge.svg)](https://github.com/Rdeisenroth/Rubot2/actions/workflows/docker-img.yml) ![GitHub top language](https://img.shields.io/github/languages/top/Rdeisenroth/Rubot2?logo=Github) ![GitHub repo size](https://img.shields.io/github/repo-size/Rdeisenroth/Rubot2?color=success&logo=Github) ![Commands](https://img.shields.io/badge/Commands-77-orange?logo=Discord&logoColor=ffffff) -a general Purpose Discord Bot -# Setup -- Install Mongodb and add a new user and give it acess to the schema you want to use - - Hint: A strong password can be generated with `openssl rand -base64 ` and converted for the coonnection string with `php -r "echo urlencode(\"\");"` -- install the Dependencies with `npm install` -- Create a config.json File and Fill it according to the Json Schema -- run `npm start` to compile and run the Bot +A general Purpose Discord Bot. + +# Development Setup +- Clone the Repository +- Either use the docker compose file to start a mongodb instance or install mongodb locally + - To use the docker compose file run `docker-compose -f docker-compose.development.yml up -d` +- Setup a `.env` File + - `TOKEN` is the Discord Bot Token. To see how to create a Discord Bot see [Setup.md](Setup.md) + - `OWNER_ID` is the Discord ID of the Bot Owner. To get your Discord ID enable Developer Mode in the Discord Settings and right click on your name in the User List. + - `CLIENT_ID` is the Discord ID of the Bot. To get the ID go to the [Discord Developer Portal](https://discord.com/developers/applications) and select your application. The ID is displayed under the name of the application. Alternatively enable Developer Mode in the Discord Settings and right click on the Bot in the User List to copy the ID. + - `MONGODB_USER` is the Username for the Mongodb Database. If you use the docker compose development file you can freely choose the value. If you use a local instance of mongodb you have to create a new user and give it access to the database you want to use. + - `MONGODB_PASSWORD` is the Password for the Mongodb Database. If you use the docker compose development file you can freely choose the value. If you use a local instance of mongodb you have to create a new user and give it access to the database you want to use. + - `MONGODB_DBNAME` is the Name of the Mongodb Database. If you use the docker compose development file you can freely choose the value. If you use a local instance of mongodb you have to create a new user and give it access to the database you want to use. + - `MONGODB_CONNECTION_URL` is the Connection String for the Mongodb Database. The connection string should look like this: `mongodb://:@:/?authSource=admin` make sure to replace the values with the ones you chose above, host and port should be `localhost` or `127.0.0.1` and `27017` respectively. +- Install the Dependencies with `npm install` +- Run `npm start` to compile and run the Bot in development mode + +## Setup for manual Testing +See [Setup.md](Setup.md). # Deployment - Run `npm build` once to compile to the dist directory on the target device diff --git a/Setup.md b/Setup.md new file mode 100644 index 0000000..8d02ec4 --- /dev/null +++ b/Setup.md @@ -0,0 +1,28 @@ +# Setup to test the bot + +## Create a Discord Bot + +1. Go to the [Discord Developer Portal](https://discord.com/developers/applications) and create a new application. +2. Under the `Bot` tab, of the application, enable all the `Privileged Gateway Intents`. +3. Under OAuth2 go the URL Generator and select the `applications.commands` and `bot` scopes. For bot permissions, select `Administrator`. +4. Copy the generated URL and paste it into your browser. Select the server you want to add the bot to and click `Authorize`. + +## Creating a Test Server + +1. Create a new server and add the bot to it (see above). +2. Go to the `Server Settings` and under `Roles` create a new role called `Admin` and give it the `Administrator` permission. +3. Assign the `Admin` role to the bot. +4. Also under `Roles` create three new roles called `Orga`, `Tutor`, and `Verified`, they don't need any permissions. +5. Call the command `/admin genverifyroles` to generate the roles in the database. +6. Create a new category, call it for example `Tutoring` and make it private but allow the `Tutor` role to see it. +7. Create one voice channel in the category, for example `tutoring-waiting` and allow the `Verified` role to see it. The `Tutor` role should be able to see it already because it is in the same category. +8. Call the command `/create-queue` and pass it the name for the queue and a description, for example `tutoring`. This will create a new queue in the database. +9. Call the command `/setqueue` and pass it the name of the waiting channel, for example `tutoring-waiting` and the name of the queue, for example `tutoring` as well as the supervisor role, for example `Tutor`. This will set the waiting channel for the queue and the supervisor role. +10. Optionally rename the `coach` commands on the server to `tutor` by calling the command `/config commands rename` and passing it the old and new name of the command. + +## Testing the Bot + +1. Create a second discord account and join the test server. +2. Assign the `Verified` role to the test account. +3. Assign the `Tutor` role to the primary account. +4. You now have a working test setup. The test account acts as a student and the primary account acts as a tutor. \ No newline at end of file diff --git a/docker-compose.development.yml b/docker-compose.development.yml new file mode 100644 index 0000000..e8f86bb --- /dev/null +++ b/docker-compose.development.yml @@ -0,0 +1,12 @@ +version: '3.8' +services: + db: + image: mongo + container_name: sprechi-mongodb + environment: + - MONGO_INITDB_ROOT_USERNAME=$MONGODB_USER + - MONGO_INITDB_ROOT_PASSWORD=$MONGODB_PASSWORD + - MONGO_INITDB_DATABASE=$MONGODB_DBNAME + restart: unless-stopped + ports: + - 27017:27017 \ No newline at end of file From 46506844a92e18a2161c1529c5c048d19b2ca80b Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Thu, 30 Nov 2023 18:47:10 +0100 Subject: [PATCH 10/15] Add constant for internal guild roles --- src/models/bot_roles.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/models/bot_roles.ts b/src/models/bot_roles.ts index 6f20eb9..4243bf4 100644 --- a/src/models/bot_roles.ts +++ b/src/models/bot_roles.ts @@ -10,6 +10,8 @@ export enum InternalRoles { BOT_ADMIN = "bot_admin", } +export const InternalGuildRoles = [InternalRoles.SERVER_OWNER, InternalRoles.SERVER_ADMIN, InternalRoles.TUTOR, InternalRoles.VERIFIED, InternalRoles.ACTIVE_SESSION]; + export enum RoleScopes { GLOBAL = "global", SERVER = "server", From d2618f1df47e984ec48e17f4a46bc11e6aa8ae35 Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Thu, 30 Nov 2023 18:52:58 +0100 Subject: [PATCH 11/15] improve fixverify --- src/commands/admin/fixverify.ts | 81 ++++++++------------------------- 1 file changed, 20 insertions(+), 61 deletions(-) diff --git a/src/commands/admin/fixverify.ts b/src/commands/admin/fixverify.ts index eea9706..5e79066 100644 --- a/src/commands/admin/fixverify.ts +++ b/src/commands/admin/fixverify.ts @@ -3,9 +3,9 @@ import { Command } from "../../../typings"; import "moment-duration-format"; import { UserModel } from "../../models/users"; import { GuildModel } from "../../models/guilds"; -import { DBRole, InternalRoles, RoleScopes } from "../../models/bot_roles"; +import { DBRole } from "../../models/bot_roles"; import { Types } from "mongoose"; -import { DocumentType } from "@typegoose/typegoose"; +import { ArraySubDocumentType } from "@typegoose/typegoose"; @@ -15,7 +15,7 @@ import { DocumentType } from "@typegoose/typegoose"; const command: Command = { name: "fixverify", guildOnly: false, - description: "Temp Command that fixes the Verify DB.", + description: "This command updates the db roles for all users based on their guild roles.", async execute(client, interaction, args) { if (!interaction || !interaction.guild) { return; @@ -26,78 +26,37 @@ const command: Command = { } await interaction.deferReply(); const guild = interaction.guild; - const roles = await interaction.guild.roles.fetch(); const members = await interaction.guild.members.fetch(); - const dbGuild = (await GuildModel.findOne({ _id: guild.id }))!; - const verifiedRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "verified"); - let dbVerifyRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.VERIFIED); - const orgaRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "orga"); - let dbOrgaRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.SERVER_ADMIN); - const tutorRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "tutor"); - let dbTutorRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.TUTOR); - const activeSessionRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "active_session"); - let dbActiveSessionRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.ACTIVE_SESSION); - - // Create the roles if they don't exist - for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR], [activeSessionRole, dbActiveSessionRole, InternalRoles.ACTIVE_SESSION]] as [Role, DocumentType, InternalRoles][])) { - if (!r) continue; - if (!dbr) { - console.log(`creating role ${irn}`); - if (!dbGuild.guild_settings.roles) dbGuild.guild_settings.roles = new Types.DocumentArray([]); - dbGuild.guild_settings.roles.push({ - internal_name: irn, - role_id: r.id, - scope: RoleScopes.SERVER, - server_id: guild.id, - server_role_name: r.name, - }); - await dbGuild.save(); - if(irn === InternalRoles.VERIFIED) { - dbVerifyRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } else if(irn === InternalRoles.SERVER_ADMIN) { - dbOrgaRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } else if(irn === InternalRoles.TUTOR) { - dbTutorRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } else if(irn === InternalRoles.ACTIVE_SESSION) { - dbActiveSessionRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } - } + const dbGuild = await GuildModel.findById(guild.id); + if(!dbGuild) { + return await client.utils.embeds.SimpleEmbed(interaction, "Adminstration", "Guild not found in Database."); } - + const dbRoles = dbGuild.guild_settings.roles; + if (!dbRoles) { + return await client.utils.embeds.SimpleEmbed(interaction, "Adminstration", "No Roles found in Database."); + } + const roles = new Map(await Promise.all(dbRoles.map(async (x) => [x, await interaction.guild?.roles.resolve(x.role_id!) ?? null] as [ArraySubDocumentType, Role | null]))); const users = await UserModel.find({}); + let count = 0; + let updatedCount = 0; for (const u of users) { console.log(`(${++count}/${users.length}) updating roles for user ${u.tu_id}`); - for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR], [activeSessionRole, dbActiveSessionRole, InternalRoles.ACTIVE_SESSION]] as [Role, DocumentType, InternalRoles][])) { + for (const [dbr, r] of roles) { if (!r || !dbr) continue; if (members.get(u._id)?.roles.cache.has(r.id)) { - console.log(`${u.tu_id} has role ${irn}`); if (!u.token_roles) u.token_roles = new Types.Array(); - u.token_roles.push(dbr); + if(!u.token_roles.find(x => dbr._id.equals(x._id))) { + console.log(`${u.tu_id} has new role ${dbr.internal_name}`); + u.token_roles.push(dbr); + updatedCount++; + } await u.save(); } } } - await client.utils.embeds.SimpleEmbed(interaction, "Fix Verify", "Done"); - - // await client.utils.embeds.SimpleEmbed(interaction, { - // title: "Server Stats", - // text: "Server Information", - // empheral: false, - // fields: [ - // { name: "❯ Members: ", value: `${interaction.guild.memberCount}`, inline: true }, - // { name: "❯ Verified Members: ", value: `${verifiedRole?.members.size ?? 0}`, inline: true }, - // { name: "❯ Unverified Members: ", value: `${interaction.guild.memberCount - (verifiedRole?.members.size ?? 0)}`, inline: true }, - // { name: "❯ Channels: ", value: `${interaction.guild.channels.cache.size}`, inline: true }, - // { name: "❯ Owner: ", value: `<@${interaction.guild.ownerId}>`, inline: true }, - // { name: "❯ Created at: ", value: ``, inline: true }, - // ], - // image: "attachment://graph.png", - // files: [ - // attachment, - // ], - // }); + await client.utils.embeds.SimpleEmbed(interaction, "Fix Verify", `Done. Updated ${updatedCount} DB-Roles.`); }, }; From af7df96ce0b9df34ed213b864f4ad662aea6d1b2 Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Thu, 30 Nov 2023 18:53:44 +0100 Subject: [PATCH 12/15] rename fixverify -> updateuserroles --- src/commands/admin/{fixverify.ts => updateuserroles.ts} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/commands/admin/{fixverify.ts => updateuserroles.ts} (94%) diff --git a/src/commands/admin/fixverify.ts b/src/commands/admin/updateuserroles.ts similarity index 94% rename from src/commands/admin/fixverify.ts rename to src/commands/admin/updateuserroles.ts index 5e79066..33b75a5 100644 --- a/src/commands/admin/fixverify.ts +++ b/src/commands/admin/updateuserroles.ts @@ -13,7 +13,7 @@ import { ArraySubDocumentType } from "@typegoose/typegoose"; * The Command Definition */ const command: Command = { - name: "fixverify", + name: "updateuserroles", guildOnly: false, description: "This command updates the db roles for all users based on their guild roles.", async execute(client, interaction, args) { @@ -56,7 +56,7 @@ const command: Command = { } } - await client.utils.embeds.SimpleEmbed(interaction, "Fix Verify", `Done. Updated ${updatedCount} DB-Roles.`); + await client.utils.embeds.SimpleEmbed(interaction, "Administration", `Done. Updated ${updatedCount} User-Roles in the DB.`); }, }; From b0621baa3236d6902e1b510e2c211a7540781dac Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Thu, 30 Nov 2023 18:54:47 +0100 Subject: [PATCH 13/15] improve genverifyroles --- src/commands/admin/genverifyroles.ts | 90 +++++++++++++++++++--------- 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/src/commands/admin/genverifyroles.ts b/src/commands/admin/genverifyroles.ts index ff9eaf8..308f542 100644 --- a/src/commands/admin/genverifyroles.ts +++ b/src/commands/admin/genverifyroles.ts @@ -1,9 +1,10 @@ -import { Message, Role } from "discord.js"; +import { InternalGuildRoles } from "../../models/bot_roles"; +import { Message, ApplicationCommandOptionType } from "discord.js"; import { Command } from "../../../typings"; import "moment-duration-format"; import { GuildModel } from "../../models/guilds"; -import { DBRole, InternalRoles, RoleScopes } from "../../models/bot_roles"; -import { ArraySubDocumentType, mongoose } from "@typegoose/typegoose"; +import { RoleScopes } from "../../models/bot_roles"; +import { mongoose } from "@typegoose/typegoose"; @@ -11,9 +12,17 @@ import { ArraySubDocumentType, mongoose } from "@typegoose/typegoose"; * The Command Definition */ const command: Command = { - name: "genverifyroles", + name: "updatebotroles", guildOnly: false, - description: "Temp Command that fixes the Verify DB.", + description: "This command updates or generates the database entries for the internal roles", + options: [ + { + name: "create-if-not-exists", + description: "Create the Roles on the guild with the default name if they don't exist, defaults to true", + type: ApplicationCommandOptionType.Boolean, + required: false, + }, + ], async execute(client, interaction, args) { if (!interaction || !interaction.guild) { return; @@ -22,25 +31,53 @@ const command: Command = { client.utils.embeds.SimpleEmbed(interaction, "Slash Only Command", "This Command is Slash only but you Called it with The Prefix. use the slash Command instead."); return; } + await interaction.deferReply(); const guild = interaction.guild; - const roles = await interaction.guild.roles.fetch(); - const members = await interaction.guild.members.fetch(); - const dbGuild = (await GuildModel.findOne({ _id: guild.id }))!; - const verifiedRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "verified"); - let dbVerifyRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.VERIFIED); - const orgaRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "orga"); - let dbOrgaRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.SERVER_ADMIN); - const tutorRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "tutor"); - let dbTutorRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.TUTOR); - const activeSessionRole = interaction.guild.roles.cache.find(x => x.name.toLowerCase() === "active_session"); - let dbActiveSessionRole = dbGuild.guild_settings.roles?.find(x => x.internal_name === InternalRoles.ACTIVE_SESSION); + const dbGuild = await GuildModel.findById(guild.id); + if (!dbGuild) { + return await client.utils.embeds.SimpleEmbed(interaction, "Adminstration", "Guild not found in Database."); + } + const createIfNotExists = interaction.options.getBoolean("create-if-not-exists", false) ?? true; // Create the roles if they don't exist - for (const [r, dbr, irn] of ([[verifiedRole, dbVerifyRole, InternalRoles.VERIFIED], [orgaRole, dbOrgaRole, InternalRoles.SERVER_ADMIN], [tutorRole, dbTutorRole, InternalRoles.TUTOR], [activeSessionRole, dbActiveSessionRole, InternalRoles.ACTIVE_SESSION]] as [Role, ArraySubDocumentType, InternalRoles][])) { - if (!r) continue; + // iterate over type InternalGuildRoles + for (const irn of InternalGuildRoles) { + let r = guild.roles.cache.find(x => x.name === irn); + const dbr = dbGuild.guild_settings.roles?.find(x => x.internal_name === irn); + if (!r) { + // try to find role by id from db + if (dbr) { + const newR = interaction.guild.roles.resolve(dbr.role_id!); + if (newR) { + r = newR; + if (dbr.server_role_name !== r.name) { + console.log(`Role "${irn}" was renamed from "${dbr.server_role_name}" to "${r.name}". Updating DB`); + // update db + dbr.server_role_name = r.name; + await dbGuild.save(); + } + continue; + } + } + if (!createIfNotExists) { + console.log(`role ${irn} not found in guild ${guild.name}. Skipping`); + continue; + } + console.log(`role ${irn} not found in guild ${guild.name}. Creating`); + const newRole = await guild.roles.create({ + name: irn, + mentionable: false, + }); + if (!newRole) { + console.log(`Could not create role ${irn}`); + continue; + } + console.log(`created role ${irn}`); + r = newRole; + } if (!dbr) { console.log(`creating role ${irn}`); if (!dbGuild.guild_settings.roles) { @@ -54,17 +91,16 @@ const command: Command = { server_role_name: r.name, }); await dbGuild.save(); - if(irn === InternalRoles.VERIFIED) { - dbVerifyRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } else if(irn === InternalRoles.SERVER_ADMIN) { - dbOrgaRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } else if(irn === InternalRoles.TUTOR) { - dbTutorRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } else if(irn === InternalRoles.ACTIVE_SESSION) { - dbActiveSessionRole = dbGuild.guild_settings.roles.find(x => x.role_id === r.id)!; - } } } + await client.utils.embeds.SimpleEmbed( + interaction, + "Adminstration", + `Done generating internal Roles. Internal Roles: \n + ${(dbGuild.guild_settings.roles?.map(x => `❯ ${x.internal_name}: <@&${x.role_id}>`).join("\n") ?? "None")} + \nUnassigned Roles: \n + ${InternalGuildRoles.filter(x => !dbGuild.guild_settings.roles?.find(y => y.internal_name === x)).map(x => `❯ ${x}`).join("\n") ?? "None"}`, + ); }, }; From bc95b4815765bc4a6a4fb4e09595491ea8709502 Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Thu, 30 Nov 2023 18:55:15 +0100 Subject: [PATCH 14/15] rename fixverifyroles -> updatebotroles --- src/commands/admin/{genverifyroles.ts => updatebotroles.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/commands/admin/{genverifyroles.ts => updatebotroles.ts} (100%) diff --git a/src/commands/admin/genverifyroles.ts b/src/commands/admin/updatebotroles.ts similarity index 100% rename from src/commands/admin/genverifyroles.ts rename to src/commands/admin/updatebotroles.ts From c987d2e54134ba879bfcb6c3cda9ed724630656d Mon Sep 17 00:00:00 2001 From: Rdeisenroth Date: Thu, 30 Nov 2023 18:55:29 +0100 Subject: [PATCH 15/15] add setinternalrole command --- src/commands/admin/setinternalrole.ts | 81 +++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/commands/admin/setinternalrole.ts diff --git a/src/commands/admin/setinternalrole.ts b/src/commands/admin/setinternalrole.ts new file mode 100644 index 0000000..b1a5ef8 --- /dev/null +++ b/src/commands/admin/setinternalrole.ts @@ -0,0 +1,81 @@ +import { Message, ApplicationCommandOptionType } from "discord.js"; +import { Command } from "../../../typings"; +import "moment-duration-format"; +import { GuildModel } from "../../models/guilds"; +import { InternalGuildRoles, InternalRoles, RoleScopes } from "../../models/bot_roles"; +import { mongoose } from "@typegoose/typegoose"; + + + +/** + * The Command Definition + */ +const command: Command = { + name: "setinternalrole", + guildOnly: false, + description: "This command generates the database entries for the internal roles", + options: [ + { + name: "internal-role-name", + description: "The Internal Role Name used for tracking", + type: ApplicationCommandOptionType.String, + choices: InternalGuildRoles.map(x => ({ name: Object.keys(InternalRoles).find(y => InternalRoles[y as keyof typeof InternalRoles] === x)!, value: x })), + required: true, + }, + { + name: "guild-role", + description: "The Guild Role to use for the Internal Role", + type: ApplicationCommandOptionType.Role, + required: true, + }, + ], + async execute(client, interaction, args) { + if (!interaction || !interaction.guild) { + return; + } + if (interaction instanceof Message) { + client.utils.embeds.SimpleEmbed(interaction, "Slash Only Command", "This Command is Slash only but you Called it with The Prefix. use the slash Command instead."); + return; + } + await interaction.deferReply(); + const guild = interaction.guild; + const internalRoleName = interaction.options.getString("internal-role-name", true) as typeof InternalGuildRoles[number]; + const guildRole = interaction.options.getRole("guild-role", true); + const dbGuild = await GuildModel.findById(guild.id); + if(!dbGuild) { + return await client.utils.embeds.SimpleEmbed(interaction, "Adminstration", "Guild not found in Database."); + } + let roles = dbGuild.guild_settings.roles; + if (!roles) { + dbGuild.guild_settings.roles = new mongoose.Types.DocumentArray([]); + roles = dbGuild.guild_settings.roles; + } + const role = roles.find(x => x.internal_name === internalRoleName); + if (role) { + // Update + role.role_id = guildRole.id; + role.server_role_name = guildRole.name; + } else { + roles.push({ + internal_name: internalRoleName, + role_id: guildRole.id, + scope: RoleScopes.SERVER, + server_id: guild.id, + server_role_name: guildRole.name, + }); + } + + await dbGuild.save(); + + await client.utils.embeds.SimpleEmbed( + interaction, + "Adminstration", + `Internal Role ${internalRoleName} set to <@&${guildRole.id}>. Note that orphans are not automatically removed.`, + ); + }, +}; + +/** + * Exporting the Command using CommonJS + */ +module.exports = command; \ No newline at end of file