From 7e7167796f6618ab14c78ef2d3a348fcab3ecfd7 Mon Sep 17 00:00:00 2001 From: Vylpes Date: Tue, 9 Aug 2022 12:32:03 +0100 Subject: [PATCH 01/11] Add say command (#174) Co-authored-by: Ethan Lane Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/174 --- .env.template | 4 ++-- src/commands/say.ts | 26 ++++++++++++++++++++++++++ src/registry.ts | 2 ++ 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/commands/say.ts diff --git a/.env.template b/.env.template index ab57e01..88ad8df 100644 --- a/.env.template +++ b/.env.template @@ -7,7 +7,7 @@ # any secret values. BOT_TOKEN= -BOT_VER=3.0.4 +BOT_VER=3.1 BOT_AUTHOR=Vylpes -BOT_DATE=06 Jul 2022 +BOT_DATE=08 Aug 2022 BOT_OWNERID=147392775707426816 diff --git a/src/commands/say.ts b/src/commands/say.ts new file mode 100644 index 0000000..433b2b8 --- /dev/null +++ b/src/commands/say.ts @@ -0,0 +1,26 @@ +import { ICommandContext } from "../contracts/ICommandContext"; +import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; +import { Command } from "../type/command"; + +export default class Say extends Command { + constructor() { + super(); + super.Category = "Misc"; + super.Roles = [ + "moderator" + ]; + } + + public override async execute(context: ICommandContext) { + const input = context.args.join(" "); + + if (input.length == 0) { + const errorEmbed = new ErrorEmbed(context, "You must supply a message."); + + await errorEmbed.SendToCurrentChannel(); + return; + } + + context.message.channel.send(input); + } +} \ No newline at end of file diff --git a/src/registry.ts b/src/registry.ts index 183bac2..4fa68f7 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -14,6 +14,7 @@ import Mute from "./commands/mute"; import Poll from "./commands/poll"; import Role from "./commands/role"; import Rules from "./commands/rules"; +import Say from "./commands/say"; import Setup from "./commands/setup"; import Unmute from "./commands/unmute"; import Warn from "./commands/warn"; @@ -46,6 +47,7 @@ export default class Registry { CoreClient.RegisterCommand("unmute", new Unmute()); CoreClient.RegisterCommand("warn", new Warn()); CoreClient.RegisterCommand("setup", new Setup()); + CoreClient.RegisterCommand("say", new Say()); // Exclusive Commands: MankBot CoreClient.RegisterCommand("lobby", new Lobby(), "501231711271780357"); -- 2.43.4 From 7c90b2ff88548f03b4199ef85de20271cf7ea03a Mon Sep 17 00:00:00 2001 From: Vylpes Date: Sat, 13 Aug 2022 14:51:40 +0100 Subject: [PATCH 02/11] Add repo and funding link to about message (#176) Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/176 --- .env.template | 3 +++ package.json | 8 ++++---- src/commands/about.ts | 23 +++++++++++++++++++---- src/helpers/embeds/PublicEmbed.ts | 6 +++--- 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/.env.template b/.env.template index 88ad8df..5862d9c 100644 --- a/.env.template +++ b/.env.template @@ -11,3 +11,6 @@ BOT_VER=3.1 BOT_AUTHOR=Vylpes BOT_DATE=08 Aug 2022 BOT_OWNERID=147392775707426816 + +ABOUT_FUNDING= +ABOUT_REPO= diff --git a/package.json b/package.json index b45562f..aa06b2d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vylbot-app", - "version": "3.0.4", + "version": "3.1.0", "description": "A discord bot made for Vylpes' Den", "main": "./dist/vylbot", "typings": "./dist", @@ -13,12 +13,12 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/Vylpes/vylbot-app.git" + "url": "https://gitea.vylpes.xyz/rabbitlabs/vylbot-app" }, "author": "Vylpes", "license": "MIT", - "bugs": "https://github.com/Vylpes/vylbot-app/issues", - "homepage": "https://github.com/Vylpes/vylbot-app", + "bugs": "https://gitea.vylpes.xyz/rabbitlabs/vylbot-app/issues", + "homepage": "https://gitea.vylpes.xyz/rabbitlabs/vylbot-app", "dependencies": { "@types/jest": "^27.0.3", "@types/uuid": "^8.3.4", diff --git a/src/commands/about.ts b/src/commands/about.ts index 4246113..a5f62f4 100644 --- a/src/commands/about.ts +++ b/src/commands/about.ts @@ -1,3 +1,5 @@ +import { Emoji, MessageActionRow, MessageButton } from "discord.js"; +import { MessageButtonStyles } from "discord.js/typings/enums"; import { ICommandContext } from "../contracts/ICommandContext"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; import { Command } from "../type/command"; @@ -9,11 +11,24 @@ export default class About extends Command { } public override async execute(context: ICommandContext) { + const fundingLink = process.env.ABOUT_FUNDING; + const repoLink = process.env.ABOUT_REPO; + const embed = new PublicEmbed(context, "About", "") - .addField("Version", process.env.BOT_VER!) - .addField("Author", process.env.BOT_AUTHOR!) - .addField("Date", process.env.BOT_DATE!); + .addField("Version", process.env.BOT_VER!, true) + .addField("Author", process.env.BOT_AUTHOR!, true) + .addField("Date", process.env.BOT_DATE!, true); + + const row = new MessageActionRow(); + + if (repoLink) { + row.addComponents(new MessageButton().setURL(repoLink).setLabel("Repo").setStyle(MessageButtonStyles.LINK)); + } + + if (fundingLink) { + row.addComponents(new MessageButton().setURL(fundingLink).setLabel("Funding").setStyle(MessageButtonStyles.LINK)); + } - await embed.SendToCurrentChannel(); + await embed.SendToCurrentChannel({ components: [row] }); } } \ No newline at end of file diff --git a/src/helpers/embeds/PublicEmbed.ts b/src/helpers/embeds/PublicEmbed.ts index 84be5c9..059826b 100644 --- a/src/helpers/embeds/PublicEmbed.ts +++ b/src/helpers/embeds/PublicEmbed.ts @@ -1,4 +1,4 @@ -import { MessageEmbed, Permissions, TextChannel } from "discord.js"; +import { MessageEmbed, MessageOptions, Permissions, TextChannel } from "discord.js"; import { ICommandContext } from "../../contracts/ICommandContext"; export default class PublicEmbed extends MessageEmbed { @@ -20,7 +20,7 @@ export default class PublicEmbed extends MessageEmbed { } // Send methods - public async SendToCurrentChannel() { + public async SendToCurrentChannel(options?: MessageOptions) { const channel = this.context.message.channel as TextChannel; const botMember = await this.context.message.guild?.members.fetch({ user: this.context.message.client.user! }); @@ -30,6 +30,6 @@ export default class PublicEmbed extends MessageEmbed { if (!permissions.has(Permissions.FLAGS.SEND_MESSAGES)) return; - this.context.message.channel.send({ embeds: [ this ]}); + this.context.message.channel.send({ embeds: [ this ], ...options}); } } \ No newline at end of file -- 2.43.4 From bc24a4ecfe434cef6f49e82aa2f93b971cd7f0e8 Mon Sep 17 00:00:00 2001 From: Vylpes Date: Tue, 16 Aug 2022 18:12:32 +0100 Subject: [PATCH 03/11] Add other subreddits to bunny command (#177) Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/177 --- src/commands/bunny.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/commands/bunny.ts b/src/commands/bunny.ts index 47bafa6..a41e179 100644 --- a/src/commands/bunny.ts +++ b/src/commands/bunny.ts @@ -12,13 +12,24 @@ export default class Bunny extends Command { } public override async execute(context: ICommandContext) { - const result = await randomBunny('rabbits', 'hot'); + const subreddits = [ + 'rabbits', + 'bunnieswithhats', + 'buncomfortable', + 'bunnytongues', + 'dutchbunnymafia', + ]; + + const random = Math.floor(Math.random() * subreddits.length); + const selectedSubreddit = subreddits[random]; + + const result = await randomBunny(selectedSubreddit, 'hot'); if (result.IsSuccess) { const embed = new PublicEmbed(context, result.Result!.Title, "") .setImage(result.Result!.Url) .setURL(`https://reddit.com${result.Result!.Permalink}`) - .setFooter({ text: `r/Rabbits · ${result.Result!.Ups} upvotes` }); + .setFooter({ text: `r/${selectedSubreddit} · ${result.Result!.Ups} upvotes` }); await embed.SendToCurrentChannel(); } else { -- 2.43.4 From eef01b1c3df0fd4bc778bf855acc2b8db63e633f Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 17 Aug 2022 17:58:56 +0100 Subject: [PATCH 04/11] Add database table --- src/constants/AuditType.ts | 7 +++ src/entity/Audit.ts | 60 ++++++++++++++++++++++ src/entity/Server.ts | 4 ++ src/migration/1660754832945-CreateAudit.ts | 13 +++++ 4 files changed, 84 insertions(+) create mode 100644 src/constants/AuditType.ts create mode 100644 src/entity/Audit.ts create mode 100644 src/migration/1660754832945-CreateAudit.ts diff --git a/src/constants/AuditType.ts b/src/constants/AuditType.ts new file mode 100644 index 0000000..4ad8df6 --- /dev/null +++ b/src/constants/AuditType.ts @@ -0,0 +1,7 @@ +export enum AuditType { + General, + Warn, + Mute, + Kick, + Ban, +} \ No newline at end of file diff --git a/src/entity/Audit.ts b/src/entity/Audit.ts new file mode 100644 index 0000000..b2dfcd5 --- /dev/null +++ b/src/entity/Audit.ts @@ -0,0 +1,60 @@ +import { Column, Entity, getConnection, ManyToOne } from "typeorm"; +import { AuditType } from "../constants/AuditType"; +import BaseEntity from "../contracts/BaseEntity"; +import StringTools from "../helpers/StringTools"; +import Server from "./Server"; + +@Entity() +export default class Audit extends BaseEntity { + constructor(userId: string, auditType: AuditType, reason: string, moderatorId: string) { + super(); + + this.AuditId = StringTools.RandomString(5).toUpperCase(); + this.UserId = userId; + this.AuditType = auditType; + this.Reason = reason; + this.ModeratorId = moderatorId; + } + + @Column() + AuditId: string; + + @Column() + UserId: string; + + @Column() + AuditType: AuditType; + + @Column() + Reason: string; + + @Column() + ModeratorId: string; + + @ManyToOne(() => Server, x => x.Audits) + Server: Server; + + public AssignToServer(server: Server) { + this.Server = server; + } + + public static async FetchAuditsByUserId(userId: string): Promise { + const connection = getConnection(); + + const repository = connection.getRepository(Audit); + + const all = await repository.find({ UserId: userId }); + + return all; + } + + public static async FetchAuditByAuditId(auditId: string): Promise { + const connection = getConnection(); + + const repository = connection.getRepository(Audit); + + const single = await repository.findOne({ AuditId: auditId }); + + return single; + } +} \ No newline at end of file diff --git a/src/entity/Server.ts b/src/entity/Server.ts index f669e58..eadb249 100644 --- a/src/entity/Server.ts +++ b/src/entity/Server.ts @@ -1,5 +1,6 @@ import { Entity, OneToMany } from "typeorm"; import BaseEntity from "../contracts/BaseEntity"; +import Audit from "./Audit"; import Role from "./Role"; import Setting from "./Setting"; @@ -17,6 +18,9 @@ export default class Server extends BaseEntity { @OneToMany(() => Role, x => x.Server) Roles: Role[]; + @OneToMany(() => Audit, x => x.Server) + Audits: Audit[]; + public AddSettingToServer(setting: Setting) { this.Settings.push(setting); } diff --git a/src/migration/1660754832945-CreateAudit.ts b/src/migration/1660754832945-CreateAudit.ts new file mode 100644 index 0000000..9a44ed7 --- /dev/null +++ b/src/migration/1660754832945-CreateAudit.ts @@ -0,0 +1,13 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class CreateAudit1660754832945 implements MigrationInterface { + + public async up(queryRunner: QueryRunner): Promise { + queryRunner.query(`CREATE TABLE audit (Id varchar(255), WhenCreated datetime, WhenUpdated datetime, auditId varchar(255), userId varchar(255), auditType int, reason varchar(255), moderatorId varchar(255), serverId varchar(255), PRIMARY KEY (Id), FOREIGN KEY (serverId) REFERENCES server(id))`); + } + + public async down(queryRunner: QueryRunner): Promise { + queryRunner.query(`DROP TABLE audit`); + } + +} -- 2.43.4 From 4812f5b6917fcaf80ce8051abdd278c521ed4ccc Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Wed, 17 Aug 2022 18:09:55 +0100 Subject: [PATCH 05/11] Save moderation actions to database --- src/commands/ban.ts | 14 ++++++++++++++ src/commands/kick.ts | 14 ++++++++++++++ src/commands/mute.ts | 14 ++++++++++++++ src/commands/warn.ts | 14 ++++++++++++++ 4 files changed, 56 insertions(+) diff --git a/src/commands/ban.ts b/src/commands/ban.ts index ad39f03..8d7973b 100644 --- a/src/commands/ban.ts +++ b/src/commands/ban.ts @@ -5,6 +5,9 @@ import PublicEmbed from "../helpers/embeds/PublicEmbed"; import { Command } from "../type/command"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; +import Audit from "../entity/Audit"; +import { AuditType } from "../constants/AuditType"; +import Server from "../entity/Server"; export default class Ban extends Command { constructor() { @@ -75,6 +78,17 @@ export default class Ban extends Command { await logEmbed.SendToModLogsChannel(); await publicEmbed.SendToCurrentChannel(); + if (context.message.guild) { + const server = await Server.FetchOneById(Server, context.message.guild.id); + + if (server) { + const audit = new Audit(targetUser.id, AuditType.Ban, reason, context.message.author.id); + audit.AssignToServer(server); + + await audit.Save(Audit, audit); + } + } + return { commandContext: context, embeds: [logEmbed, publicEmbed], diff --git a/src/commands/kick.ts b/src/commands/kick.ts index 81b1af9..53b8b90 100644 --- a/src/commands/kick.ts +++ b/src/commands/kick.ts @@ -1,6 +1,9 @@ +import { AuditType } from "../constants/AuditType"; import ErrorMessages from "../constants/ErrorMessages"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; +import Audit from "../entity/Audit"; +import Server from "../entity/Server"; import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; import LogEmbed from "../helpers/embeds/LogEmbed"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -74,6 +77,17 @@ export default class Kick extends Command { await logEmbed.SendToModLogsChannel(); await publicEmbed.SendToCurrentChannel(); + + if (context.message.guild) { + const server = await Server.FetchOneById(Server, context.message.guild.id); + + if (server) { + const audit = new Audit(targetUser.id, AuditType.Kick, reason, context.message.author.id); + audit.AssignToServer(server); + + await audit.Save(Audit, audit); + } + } return { commandContext: context, diff --git a/src/commands/mute.ts b/src/commands/mute.ts index e5d43df..e426e4f 100644 --- a/src/commands/mute.ts +++ b/src/commands/mute.ts @@ -1,6 +1,9 @@ +import { AuditType } from "../constants/AuditType"; import ErrorMessages from "../constants/ErrorMessages"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; +import Audit from "../entity/Audit"; +import Server from "../entity/Server"; import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; import LogEmbed from "../helpers/embeds/LogEmbed"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -87,6 +90,17 @@ export default class Mute extends Command { await logEmbed.SendToModLogsChannel(); await publicEmbed.SendToCurrentChannel(); + + if (context.message.guild) { + const server = await Server.FetchOneById(Server, context.message.guild.id); + + if (server) { + const audit = new Audit(targetUser.id, AuditType.Mute, reason, context.message.author.id); + audit.AssignToServer(server); + + await audit.Save(Audit, audit); + } + } return { commandContext: context, diff --git a/src/commands/warn.ts b/src/commands/warn.ts index a36e28e..69f1f9f 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -1,5 +1,8 @@ +import { AuditType } from "../constants/AuditType"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; +import Audit from "../entity/Audit"; +import Server from "../entity/Server"; import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; import LogEmbed from "../helpers/embeds/LogEmbed"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -62,6 +65,17 @@ export default class Warn extends Command { await logEmbed.SendToModLogsChannel(); await publicEmbed.SendToCurrentChannel(); + + if (context.message.guild) { + const server = await Server.FetchOneById(Server, context.message.guild.id); + + if (server) { + const audit = new Audit(user.id, AuditType.Warn, reason, context.message.author.id); + audit.AssignToServer(server); + + await audit.Save(Audit, audit); + } + } return { commandContext: context, -- 2.43.4 From 595c15acb115c385de75cc493c1d10ca94b53711 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Thu, 18 Aug 2022 18:51:12 +0100 Subject: [PATCH 06/11] Add audit command to see a user's audits --- src/commands/audits.ts | 61 ++++++++++++++++++++++ src/commands/ban.ts | 3 +- src/commands/kick.ts | 3 +- src/commands/mute.ts | 3 +- src/commands/warn.ts | 3 +- src/entity/Audit.ts | 16 +++--- src/entity/Server.ts | 3 -- src/helpers/AuditTools.ts | 20 +++++++ src/migration/1660754832945-CreateAudit.ts | 2 +- src/registry.ts | 2 + 10 files changed, 94 insertions(+), 22 deletions(-) create mode 100644 src/commands/audits.ts create mode 100644 src/helpers/AuditTools.ts diff --git a/src/commands/audits.ts b/src/commands/audits.ts new file mode 100644 index 0000000..b6045a0 --- /dev/null +++ b/src/commands/audits.ts @@ -0,0 +1,61 @@ +import { ICommandContext } from "../contracts/ICommandContext"; +import Audit from "../entity/Audit"; +import AuditTools from "../helpers/AuditTools"; +import PublicEmbed from "../helpers/embeds/PublicEmbed"; +import { Command } from "../type/command"; +import SettingsHelper from "../helpers/SettingsHelper"; + +export default class Audits extends Command { + constructor() { + super(); + + super.Category = "Moderation"; + super.Roles = [ + "moderator" + ]; + } + + public override async execute(context: ICommandContext) { + if (!context.message.guild) return; + + switch (context.args[0]) { + case "user": + await this.SendAuditForUser(context); + break; + default: + await this.SendUsage(context); + } + } + + private async SendUsage(context: ICommandContext) { + const prefix = await SettingsHelper.GetServerPrefix(context.message.guild!.id); + + const description = [ + `\`${prefix}audits user \` - Send the audits for this user`, + ] + + const publicEmbed = new PublicEmbed(context, "Usage", description.join("\n")); + await publicEmbed.SendToCurrentChannel(); + } + + private async SendAuditForUser(context: ICommandContext) { + const userId = context.args[1]; + + const audits = await Audit.FetchAuditsByUserId(userId, context.message.guild!.id); + + if (!audits || audits.length == 0) { + const publicEmbed = new PublicEmbed(context, "", "There are no audits logged for this user."); + await publicEmbed.SendToCurrentChannel(); + + return; + } + + const publicEmbed = new PublicEmbed(context, "Audit Log", ""); + + for (let audit of audits) { + publicEmbed.addField(`${audit.AuditId} // ${AuditTools.TypeToFriendlyText(audit.AuditType)}`, audit.WhenCreated.toString()); + } + + await publicEmbed.SendToCurrentChannel(); + } +} \ No newline at end of file diff --git a/src/commands/ban.ts b/src/commands/ban.ts index 8d7973b..518b0d2 100644 --- a/src/commands/ban.ts +++ b/src/commands/ban.ts @@ -82,8 +82,7 @@ export default class Ban extends Command { const server = await Server.FetchOneById(Server, context.message.guild.id); if (server) { - const audit = new Audit(targetUser.id, AuditType.Ban, reason, context.message.author.id); - audit.AssignToServer(server); + const audit = new Audit(targetUser.id, AuditType.Ban, reason, context.message.author.id, context.message.guild.id); await audit.Save(Audit, audit); } diff --git a/src/commands/kick.ts b/src/commands/kick.ts index 53b8b90..5be4321 100644 --- a/src/commands/kick.ts +++ b/src/commands/kick.ts @@ -82,8 +82,7 @@ export default class Kick extends Command { const server = await Server.FetchOneById(Server, context.message.guild.id); if (server) { - const audit = new Audit(targetUser.id, AuditType.Kick, reason, context.message.author.id); - audit.AssignToServer(server); + const audit = new Audit(targetUser.id, AuditType.Kick, reason, context.message.author.id, context.message.guild.id); await audit.Save(Audit, audit); } diff --git a/src/commands/mute.ts b/src/commands/mute.ts index e426e4f..8e01eea 100644 --- a/src/commands/mute.ts +++ b/src/commands/mute.ts @@ -95,8 +95,7 @@ export default class Mute extends Command { const server = await Server.FetchOneById(Server, context.message.guild.id); if (server) { - const audit = new Audit(targetUser.id, AuditType.Mute, reason, context.message.author.id); - audit.AssignToServer(server); + const audit = new Audit(targetUser.id, AuditType.Mute, reason, context.message.author.id, context.message.guild.id); await audit.Save(Audit, audit); } diff --git a/src/commands/warn.ts b/src/commands/warn.ts index 69f1f9f..dbc70c0 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -70,8 +70,7 @@ export default class Warn extends Command { const server = await Server.FetchOneById(Server, context.message.guild.id); if (server) { - const audit = new Audit(user.id, AuditType.Warn, reason, context.message.author.id); - audit.AssignToServer(server); + const audit = new Audit(user.id, AuditType.Warn, reason, context.message.author.id, context.message.guild.id); await audit.Save(Audit, audit); } diff --git a/src/entity/Audit.ts b/src/entity/Audit.ts index b2dfcd5..58d2356 100644 --- a/src/entity/Audit.ts +++ b/src/entity/Audit.ts @@ -2,11 +2,10 @@ import { Column, Entity, getConnection, ManyToOne } from "typeorm"; import { AuditType } from "../constants/AuditType"; import BaseEntity from "../contracts/BaseEntity"; import StringTools from "../helpers/StringTools"; -import Server from "./Server"; @Entity() export default class Audit extends BaseEntity { - constructor(userId: string, auditType: AuditType, reason: string, moderatorId: string) { + constructor(userId: string, auditType: AuditType, reason: string, moderatorId: string, serverId: string) { super(); this.AuditId = StringTools.RandomString(5).toUpperCase(); @@ -14,6 +13,7 @@ export default class Audit extends BaseEntity { this.AuditType = auditType; this.Reason = reason; this.ModeratorId = moderatorId; + this.ServerId = serverId; } @Column() @@ -31,19 +31,15 @@ export default class Audit extends BaseEntity { @Column() ModeratorId: string; - @ManyToOne(() => Server, x => x.Audits) - Server: Server; + @Column() + ServerId: string; - public AssignToServer(server: Server) { - this.Server = server; - } - - public static async FetchAuditsByUserId(userId: string): Promise { + public static async FetchAuditsByUserId(userId: string, serverId: string): Promise { const connection = getConnection(); const repository = connection.getRepository(Audit); - const all = await repository.find({ UserId: userId }); + const all = await repository.find({ UserId: userId, ServerId: serverId }); return all; } diff --git a/src/entity/Server.ts b/src/entity/Server.ts index eadb249..bd0b1e9 100644 --- a/src/entity/Server.ts +++ b/src/entity/Server.ts @@ -18,9 +18,6 @@ export default class Server extends BaseEntity { @OneToMany(() => Role, x => x.Server) Roles: Role[]; - @OneToMany(() => Audit, x => x.Server) - Audits: Audit[]; - public AddSettingToServer(setting: Setting) { this.Settings.push(setting); } diff --git a/src/helpers/AuditTools.ts b/src/helpers/AuditTools.ts new file mode 100644 index 0000000..1464fa1 --- /dev/null +++ b/src/helpers/AuditTools.ts @@ -0,0 +1,20 @@ +import { AuditType } from "../constants/AuditType"; + +export default class AuditTools { + public static TypeToFriendlyText(auditType: AuditType): string { + switch (auditType) { + case AuditType.General: + return "General"; + case AuditType.Warn: + return "Warn"; + case AuditType.Mute: + return "Mute"; + case AuditType.Kick: + return "Kick"; + case AuditType.Ban: + return "Ban"; + default: + return "Other"; + } + } +} \ No newline at end of file diff --git a/src/migration/1660754832945-CreateAudit.ts b/src/migration/1660754832945-CreateAudit.ts index 9a44ed7..9dab091 100644 --- a/src/migration/1660754832945-CreateAudit.ts +++ b/src/migration/1660754832945-CreateAudit.ts @@ -3,7 +3,7 @@ import { MigrationInterface, QueryRunner } from "typeorm" export class CreateAudit1660754832945 implements MigrationInterface { public async up(queryRunner: QueryRunner): Promise { - queryRunner.query(`CREATE TABLE audit (Id varchar(255), WhenCreated datetime, WhenUpdated datetime, auditId varchar(255), userId varchar(255), auditType int, reason varchar(255), moderatorId varchar(255), serverId varchar(255), PRIMARY KEY (Id), FOREIGN KEY (serverId) REFERENCES server(id))`); + queryRunner.query(`CREATE TABLE audit (Id varchar(255), WhenCreated datetime, WhenUpdated datetime, auditId varchar(255), userId varchar(255), auditType int, reason varchar(255), moderatorId varchar(255), serverId varchar(255), PRIMARY KEY (Id))`); } public async down(queryRunner: QueryRunner): Promise { diff --git a/src/registry.ts b/src/registry.ts index 4fa68f7..c34c098 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -2,6 +2,7 @@ import { CoreClient } from "./client/client"; // Command Imports import About from "./commands/about"; +import Audits from "./commands/audits"; import Ban from "./commands/ban"; import Clear from "./commands/clear"; import Code from "./commands/code"; @@ -48,6 +49,7 @@ export default class Registry { CoreClient.RegisterCommand("warn", new Warn()); CoreClient.RegisterCommand("setup", new Setup()); CoreClient.RegisterCommand("say", new Say()); + CoreClient.RegisterCommand("audits", new Audits()); // Exclusive Commands: MankBot CoreClient.RegisterCommand("lobby", new Lobby(), "501231711271780357"); -- 2.43.4 From b85af78e5cd0f56883d5bde431035de966748423 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Fri, 19 Aug 2022 19:35:05 +0100 Subject: [PATCH 07/11] Add audit view subcommand --- src/commands/audits.ts | 31 +++++++++++++++++++++++++++++++ src/entity/Audit.ts | 4 ++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/commands/audits.ts b/src/commands/audits.ts index b6045a0..fb28026 100644 --- a/src/commands/audits.ts +++ b/src/commands/audits.ts @@ -4,6 +4,7 @@ import AuditTools from "../helpers/AuditTools"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; import { Command } from "../type/command"; import SettingsHelper from "../helpers/SettingsHelper"; +import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; export default class Audits extends Command { constructor() { @@ -22,6 +23,9 @@ export default class Audits extends Command { case "user": await this.SendAuditForUser(context); break; + case "view": + await this.SendAudit(context); + break; default: await this.SendUsage(context); } @@ -32,6 +36,7 @@ export default class Audits extends Command { const description = [ `\`${prefix}audits user \` - Send the audits for this user`, + `\`${prefix}audits view \` - Send information about an audit`, ] const publicEmbed = new PublicEmbed(context, "Usage", description.join("\n")); @@ -58,4 +63,30 @@ export default class Audits extends Command { await publicEmbed.SendToCurrentChannel(); } + + private async SendAudit(context: ICommandContext) { + const auditId = context.args[1]; + + if (!auditId) { + await this.SendUsage(context); + return; + } + + const audit = await Audit.FetchAuditByAuditId(auditId.toUpperCase(), context.message.guild!.id); + + if (!audit) { + const errorEmbed = new ErrorEmbed(context, "This audit can not be found."); + await errorEmbed.SendToCurrentChannel(); + + return; + } + + const publicEmbed = new PublicEmbed(context, `Audit ${audit.AuditId.toUpperCase()}`, ""); + + publicEmbed.addField("Reason", audit.Reason, true); + publicEmbed.addField("Type", AuditTools.TypeToFriendlyText(audit.AuditType), true); + publicEmbed.addField("Moderator", `<@${audit.ModeratorId}>`, true); + + await publicEmbed.SendToCurrentChannel(); + } } \ No newline at end of file diff --git a/src/entity/Audit.ts b/src/entity/Audit.ts index 58d2356..0ec1ea7 100644 --- a/src/entity/Audit.ts +++ b/src/entity/Audit.ts @@ -44,12 +44,12 @@ export default class Audit extends BaseEntity { return all; } - public static async FetchAuditByAuditId(auditId: string): Promise { + public static async FetchAuditByAuditId(auditId: string, serverId: string): Promise { const connection = getConnection(); const repository = connection.getRepository(Audit); - const single = await repository.findOne({ AuditId: auditId }); + const single = await repository.findOne({ AuditId: auditId, ServerId: serverId }); return single; } -- 2.43.4 From 10f23fedd9d500257a04525072391b3b016e5e83 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Fri, 19 Aug 2022 19:44:12 +0100 Subject: [PATCH 08/11] Add audit clear subcommand --- src/commands/audits.ts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/commands/audits.ts b/src/commands/audits.ts index fb28026..f0138b5 100644 --- a/src/commands/audits.ts +++ b/src/commands/audits.ts @@ -26,6 +26,9 @@ export default class Audits extends Command { case "view": await this.SendAudit(context); break; + case "clear": + await this.ClearAudit(context); + break; default: await this.SendUsage(context); } @@ -37,6 +40,7 @@ export default class Audits extends Command { const description = [ `\`${prefix}audits user \` - Send the audits for this user`, `\`${prefix}audits view \` - Send information about an audit`, + `\`${prefix}audits clear \` - Clears an audit for a user by audit id`, ] const publicEmbed = new PublicEmbed(context, "Usage", description.join("\n")); @@ -89,4 +93,27 @@ export default class Audits extends Command { await publicEmbed.SendToCurrentChannel(); } + + private async ClearAudit(context: ICommandContext) { + const auditId = context.args[1]; + + if (!auditId) { + await this.SendUsage(context); + return; + } + + const audit = await Audit.FetchAuditByAuditId(auditId.toUpperCase(), context.message.guild!.id); + + if (!audit) { + const errorEmbed = new ErrorEmbed(context, "This audit can not be found."); + await errorEmbed.SendToCurrentChannel(); + + return; + } + + await Audit.Remove(Audit, audit); + + const publicEmbed = new PublicEmbed(context, "", "Audit cleared"); + await publicEmbed.SendToCurrentChannel(); + } } \ No newline at end of file -- 2.43.4 From 061b375b346197c5703994f48935a482d44608fe Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Fri, 19 Aug 2022 19:54:26 +0100 Subject: [PATCH 09/11] Create add audit subcommand --- src/commands/audits.ts | 25 +++++++++++++++++++++++++ src/helpers/AuditTools.ts | 17 +++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/commands/audits.ts b/src/commands/audits.ts index f0138b5..e3dfd80 100644 --- a/src/commands/audits.ts +++ b/src/commands/audits.ts @@ -29,6 +29,9 @@ export default class Audits extends Command { case "clear": await this.ClearAudit(context); break; + case "add": + await this.AddAudit(context); + break; default: await this.SendUsage(context); } @@ -41,6 +44,7 @@ export default class Audits extends Command { `\`${prefix}audits user \` - Send the audits for this user`, `\`${prefix}audits view \` - Send information about an audit`, `\`${prefix}audits clear \` - Clears an audit for a user by audit id`, + `\`${prefix}audits add [reason]\` - Manually add an audit for a user`, ] const publicEmbed = new PublicEmbed(context, "Usage", description.join("\n")); @@ -116,4 +120,25 @@ export default class Audits extends Command { const publicEmbed = new PublicEmbed(context, "", "Audit cleared"); await publicEmbed.SendToCurrentChannel(); } + + private async AddAudit(context: ICommandContext) { + const userId = context.args[1]; + const typeString = context.args[2]; + const reason = context.args.splice(3) + .join(" "); + + if (!userId || !typeString) { + await this.SendUsage(context); + return; + } + + const type = AuditTools.StringToType(typeString); + + const audit = new Audit(userId, type, reason, context.message.author.id, context.message.guild!.id); + + await audit.Save(Audit, audit); + + const publicEmbed = new PublicEmbed(context, "", `Created new audit with ID \`${audit.AuditId}\``); + await publicEmbed.SendToCurrentChannel(); + } } \ No newline at end of file diff --git a/src/helpers/AuditTools.ts b/src/helpers/AuditTools.ts index 1464fa1..fa06c43 100644 --- a/src/helpers/AuditTools.ts +++ b/src/helpers/AuditTools.ts @@ -17,4 +17,21 @@ export default class AuditTools { return "Other"; } } + + public static StringToType(str: string): AuditType { + switch (str.toLowerCase()) { + case "general": + return AuditType.General; + case "warn": + return AuditType.Warn; + case "mute": + return AuditType.Mute; + case "kick": + return AuditType.Kick; + case "ban": + return AuditType.Ban; + default: + return AuditType.General; + } + } } \ No newline at end of file -- 2.43.4 From 508f8228b1c6579bd1b6912cdfca7d10d2dae655 Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Fri, 19 Aug 2022 19:56:00 +0100 Subject: [PATCH 10/11] Fix bot crashing when viewing an audit with no reason --- src/commands/audits.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/audits.ts b/src/commands/audits.ts index e3dfd80..c53fe37 100644 --- a/src/commands/audits.ts +++ b/src/commands/audits.ts @@ -91,7 +91,7 @@ export default class Audits extends Command { const publicEmbed = new PublicEmbed(context, `Audit ${audit.AuditId.toUpperCase()}`, ""); - publicEmbed.addField("Reason", audit.Reason, true); + publicEmbed.addField("Reason", audit.Reason || "*none*", true); publicEmbed.addField("Type", AuditTools.TypeToFriendlyText(audit.AuditType), true); publicEmbed.addField("Moderator", `<@${audit.ModeratorId}>`, true); -- 2.43.4 From ae85233ae06dbf1e6420636d9ec4c976d841a21c Mon Sep 17 00:00:00 2001 From: Ethan Lane Date: Sun, 4 Sep 2022 16:38:15 +0100 Subject: [PATCH 11/11] Fix changes requested --- package.json | 7 ++++--- src/commands/about.ts | 14 +++++++++++--- src/commands/ban.ts | 9 ++------- src/commands/kick.ts | 9 ++------- src/commands/mute.ts | 9 ++------- src/commands/warn.ts | 9 ++------- src/entity/Server.ts | 1 - 7 files changed, 23 insertions(+), 35 deletions(-) diff --git a/package.json b/package.json index aa06b2d..6ca06c5 100644 --- a/package.json +++ b/package.json @@ -13,12 +13,13 @@ }, "repository": { "type": "git", - "url": "https://gitea.vylpes.xyz/rabbitlabs/vylbot-app" + "url": "https://github.com/Vylpes/vylbot-app" }, "author": "Vylpes", "license": "MIT", - "bugs": "https://gitea.vylpes.xyz/rabbitlabs/vylbot-app/issues", - "homepage": "https://gitea.vylpes.xyz/rabbitlabs/vylbot-app", + "bugs": "https://github.com/Vylpes/vylbot-app/issues", + "homepage": "https://github.com/Vylpes/vylbot-app", + "funding": "https://ko-fi.com/vylpes", "dependencies": { "@types/jest": "^27.0.3", "@types/uuid": "^8.3.4", diff --git a/src/commands/about.ts b/src/commands/about.ts index a5f62f4..b688df6 100644 --- a/src/commands/about.ts +++ b/src/commands/about.ts @@ -1,4 +1,4 @@ -import { Emoji, MessageActionRow, MessageButton } from "discord.js"; +import { MessageActionRow, MessageButton } from "discord.js"; import { MessageButtonStyles } from "discord.js/typings/enums"; import { ICommandContext } from "../contracts/ICommandContext"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -22,11 +22,19 @@ export default class About extends Command { const row = new MessageActionRow(); if (repoLink) { - row.addComponents(new MessageButton().setURL(repoLink).setLabel("Repo").setStyle(MessageButtonStyles.LINK)); + row.addComponents( + new MessageButton() + .setURL(repoLink) + .setLabel("Repo") + .setStyle(MessageButtonStyles.LINK)); } if (fundingLink) { - row.addComponents(new MessageButton().setURL(fundingLink).setLabel("Funding").setStyle(MessageButtonStyles.LINK)); + row.addComponents( + new MessageButton() + .setURL(fundingLink) + .setLabel("Funding") + .setStyle(MessageButtonStyles.LINK)); } await embed.SendToCurrentChannel({ components: [row] }); diff --git a/src/commands/ban.ts b/src/commands/ban.ts index 518b0d2..8d50132 100644 --- a/src/commands/ban.ts +++ b/src/commands/ban.ts @@ -7,7 +7,6 @@ import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; import Audit from "../entity/Audit"; import { AuditType } from "../constants/AuditType"; -import Server from "../entity/Server"; export default class Ban extends Command { constructor() { @@ -79,13 +78,9 @@ export default class Ban extends Command { await publicEmbed.SendToCurrentChannel(); if (context.message.guild) { - const server = await Server.FetchOneById(Server, context.message.guild.id); + const audit = new Audit(targetUser.id, AuditType.Ban, reason, context.message.author.id, context.message.guild.id); - if (server) { - const audit = new Audit(targetUser.id, AuditType.Ban, reason, context.message.author.id, context.message.guild.id); - - await audit.Save(Audit, audit); - } + await audit.Save(Audit, audit); } return { diff --git a/src/commands/kick.ts b/src/commands/kick.ts index 5be4321..c1b2572 100644 --- a/src/commands/kick.ts +++ b/src/commands/kick.ts @@ -3,7 +3,6 @@ import ErrorMessages from "../constants/ErrorMessages"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; import Audit from "../entity/Audit"; -import Server from "../entity/Server"; import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; import LogEmbed from "../helpers/embeds/LogEmbed"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -79,13 +78,9 @@ export default class Kick extends Command { await publicEmbed.SendToCurrentChannel(); if (context.message.guild) { - const server = await Server.FetchOneById(Server, context.message.guild.id); + const audit = new Audit(targetUser.id, AuditType.Kick, reason, context.message.author.id, context.message.guild.id); - if (server) { - const audit = new Audit(targetUser.id, AuditType.Kick, reason, context.message.author.id, context.message.guild.id); - - await audit.Save(Audit, audit); - } + await audit.Save(Audit, audit); } return { diff --git a/src/commands/mute.ts b/src/commands/mute.ts index 8e01eea..7a45b87 100644 --- a/src/commands/mute.ts +++ b/src/commands/mute.ts @@ -3,7 +3,6 @@ import ErrorMessages from "../constants/ErrorMessages"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; import Audit from "../entity/Audit"; -import Server from "../entity/Server"; import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; import LogEmbed from "../helpers/embeds/LogEmbed"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -92,13 +91,9 @@ export default class Mute extends Command { await publicEmbed.SendToCurrentChannel(); if (context.message.guild) { - const server = await Server.FetchOneById(Server, context.message.guild.id); + const audit = new Audit(targetUser.id, AuditType.Mute, reason, context.message.author.id, context.message.guild.id); - if (server) { - const audit = new Audit(targetUser.id, AuditType.Mute, reason, context.message.author.id, context.message.guild.id); - - await audit.Save(Audit, audit); - } + await audit.Save(Audit, audit); } return { diff --git a/src/commands/warn.ts b/src/commands/warn.ts index dbc70c0..00f9efe 100644 --- a/src/commands/warn.ts +++ b/src/commands/warn.ts @@ -2,7 +2,6 @@ import { AuditType } from "../constants/AuditType"; import { ICommandContext } from "../contracts/ICommandContext"; import ICommandReturnContext from "../contracts/ICommandReturnContext"; import Audit from "../entity/Audit"; -import Server from "../entity/Server"; import ErrorEmbed from "../helpers/embeds/ErrorEmbed"; import LogEmbed from "../helpers/embeds/LogEmbed"; import PublicEmbed from "../helpers/embeds/PublicEmbed"; @@ -67,13 +66,9 @@ export default class Warn extends Command { await publicEmbed.SendToCurrentChannel(); if (context.message.guild) { - const server = await Server.FetchOneById(Server, context.message.guild.id); + const audit = new Audit(user.id, AuditType.Warn, reason, context.message.author.id, context.message.guild.id); - if (server) { - const audit = new Audit(user.id, AuditType.Warn, reason, context.message.author.id, context.message.guild.id); - - await audit.Save(Audit, audit); - } + await audit.Save(Audit, audit); } return { diff --git a/src/entity/Server.ts b/src/entity/Server.ts index bd0b1e9..f669e58 100644 --- a/src/entity/Server.ts +++ b/src/entity/Server.ts @@ -1,6 +1,5 @@ import { Entity, OneToMany } from "typeorm"; import BaseEntity from "../contracts/BaseEntity"; -import Audit from "./Audit"; import Role from "./Role"; import Setting from "./Setting"; -- 2.43.4