Feature/vba 77 (#178)
* Add say command (#174) Co-authored-by: Ethan Lane <ethan@vylpes.com> Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/174 * Add repo and funding link to about message (#176) Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/176 * Add other subreddits to bunny command (#177) Reviewed-on: https://gitea.vylpes.xyz/RabbitLabs/vylbot-app/pulls/177 * Add database table * Save moderation actions to database * Add audit command to see a user's audits * Add audit view subcommand * Add audit clear subcommand * Create add audit subcommand * Fix bot crashing when viewing an audit with no reason * Fix changes requested
This commit is contained in:
parent
2da5e1aa75
commit
cd666d24fd
12 changed files with 293 additions and 1 deletions
|
@ -22,6 +22,7 @@
|
|||
"email": "helpdesk@vylpes.com"
|
||||
},
|
||||
"homepage": "https://github.com/Vylpes/vylbot-app",
|
||||
"funding": "https://ko-fi.com/vylpes",
|
||||
"dependencies": {
|
||||
"@types/jest": "^27.0.3",
|
||||
"@types/uuid": "^8.3.4",
|
||||
|
|
|
@ -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";
|
||||
|
|
144
src/commands/audits.ts
Normal file
144
src/commands/audits.ts
Normal file
|
@ -0,0 +1,144 @@
|
|||
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";
|
||||
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
|
||||
|
||||
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;
|
||||
case "view":
|
||||
await this.SendAudit(context);
|
||||
break;
|
||||
case "clear":
|
||||
await this.ClearAudit(context);
|
||||
break;
|
||||
case "add":
|
||||
await this.AddAudit(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 <id>\` - Send the audits for this user`,
|
||||
`\`${prefix}audits view <id>\` - Send information about an audit`,
|
||||
`\`${prefix}audits clear <id>\` - Clears an audit for a user by audit id`,
|
||||
`\`${prefix}audits add <userid> <type> [reason]\` - Manually add an audit for a 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();
|
||||
}
|
||||
|
||||
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 || "*none*", true);
|
||||
publicEmbed.addField("Type", AuditTools.TypeToFriendlyText(audit.AuditType), true);
|
||||
publicEmbed.addField("Moderator", `<@${audit.ModeratorId}>`, true);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
|
@ -5,6 +5,8 @@ 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";
|
||||
|
||||
export default class Ban extends Command {
|
||||
constructor() {
|
||||
|
@ -75,6 +77,12 @@ export default class Ban extends Command {
|
|||
await logEmbed.SendToModLogsChannel();
|
||||
await publicEmbed.SendToCurrentChannel();
|
||||
|
||||
if (context.message.guild) {
|
||||
const audit = new Audit(targetUser.id, AuditType.Ban, reason, context.message.author.id, context.message.guild.id);
|
||||
|
||||
await audit.Save(Audit, audit);
|
||||
}
|
||||
|
||||
return {
|
||||
commandContext: context,
|
||||
embeds: [logEmbed, publicEmbed],
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
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 ErrorEmbed from "../helpers/embeds/ErrorEmbed";
|
||||
import LogEmbed from "../helpers/embeds/LogEmbed";
|
||||
import PublicEmbed from "../helpers/embeds/PublicEmbed";
|
||||
|
@ -74,6 +76,12 @@ export default class Kick extends Command {
|
|||
|
||||
await logEmbed.SendToModLogsChannel();
|
||||
await publicEmbed.SendToCurrentChannel();
|
||||
|
||||
if (context.message.guild) {
|
||||
const audit = new Audit(targetUser.id, AuditType.Kick, reason, context.message.author.id, context.message.guild.id);
|
||||
|
||||
await audit.Save(Audit, audit);
|
||||
}
|
||||
|
||||
return {
|
||||
commandContext: context,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
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 ErrorEmbed from "../helpers/embeds/ErrorEmbed";
|
||||
import LogEmbed from "../helpers/embeds/LogEmbed";
|
||||
import PublicEmbed from "../helpers/embeds/PublicEmbed";
|
||||
|
@ -87,6 +89,12 @@ export default class Mute extends Command {
|
|||
|
||||
await logEmbed.SendToModLogsChannel();
|
||||
await publicEmbed.SendToCurrentChannel();
|
||||
|
||||
if (context.message.guild) {
|
||||
const audit = new Audit(targetUser.id, AuditType.Mute, reason, context.message.author.id, context.message.guild.id);
|
||||
|
||||
await audit.Save(Audit, audit);
|
||||
}
|
||||
|
||||
return {
|
||||
commandContext: context,
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { AuditType } from "../constants/AuditType";
|
||||
import { ICommandContext } from "../contracts/ICommandContext";
|
||||
import ICommandReturnContext from "../contracts/ICommandReturnContext";
|
||||
import Audit from "../entity/Audit";
|
||||
import ErrorEmbed from "../helpers/embeds/ErrorEmbed";
|
||||
import LogEmbed from "../helpers/embeds/LogEmbed";
|
||||
import PublicEmbed from "../helpers/embeds/PublicEmbed";
|
||||
|
@ -62,6 +64,12 @@ export default class Warn extends Command {
|
|||
|
||||
await logEmbed.SendToModLogsChannel();
|
||||
await publicEmbed.SendToCurrentChannel();
|
||||
|
||||
if (context.message.guild) {
|
||||
const audit = new Audit(user.id, AuditType.Warn, reason, context.message.author.id, context.message.guild.id);
|
||||
|
||||
await audit.Save(Audit, audit);
|
||||
}
|
||||
|
||||
return {
|
||||
commandContext: context,
|
||||
|
|
7
src/constants/AuditType.ts
Normal file
7
src/constants/AuditType.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
export enum AuditType {
|
||||
General,
|
||||
Warn,
|
||||
Mute,
|
||||
Kick,
|
||||
Ban,
|
||||
}
|
56
src/entity/Audit.ts
Normal file
56
src/entity/Audit.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { Column, Entity, getConnection, ManyToOne } from "typeorm";
|
||||
import { AuditType } from "../constants/AuditType";
|
||||
import BaseEntity from "../contracts/BaseEntity";
|
||||
import StringTools from "../helpers/StringTools";
|
||||
|
||||
@Entity()
|
||||
export default class Audit extends BaseEntity {
|
||||
constructor(userId: string, auditType: AuditType, reason: string, moderatorId: string, serverId: string) {
|
||||
super();
|
||||
|
||||
this.AuditId = StringTools.RandomString(5).toUpperCase();
|
||||
this.UserId = userId;
|
||||
this.AuditType = auditType;
|
||||
this.Reason = reason;
|
||||
this.ModeratorId = moderatorId;
|
||||
this.ServerId = serverId;
|
||||
}
|
||||
|
||||
@Column()
|
||||
AuditId: string;
|
||||
|
||||
@Column()
|
||||
UserId: string;
|
||||
|
||||
@Column()
|
||||
AuditType: AuditType;
|
||||
|
||||
@Column()
|
||||
Reason: string;
|
||||
|
||||
@Column()
|
||||
ModeratorId: string;
|
||||
|
||||
@Column()
|
||||
ServerId: string;
|
||||
|
||||
public static async FetchAuditsByUserId(userId: string, serverId: string): Promise<Audit[] | undefined> {
|
||||
const connection = getConnection();
|
||||
|
||||
const repository = connection.getRepository(Audit);
|
||||
|
||||
const all = await repository.find({ UserId: userId, ServerId: serverId });
|
||||
|
||||
return all;
|
||||
}
|
||||
|
||||
public static async FetchAuditByAuditId(auditId: string, serverId: string): Promise<Audit | undefined> {
|
||||
const connection = getConnection();
|
||||
|
||||
const repository = connection.getRepository(Audit);
|
||||
|
||||
const single = await repository.findOne({ AuditId: auditId, ServerId: serverId });
|
||||
|
||||
return single;
|
||||
}
|
||||
}
|
37
src/helpers/AuditTools.ts
Normal file
37
src/helpers/AuditTools.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
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";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
13
src/migration/1660754832945-CreateAudit.ts
Normal file
13
src/migration/1660754832945-CreateAudit.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
|
||||
export class CreateAudit1660754832945 implements MigrationInterface {
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
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<void> {
|
||||
queryRunner.query(`DROP TABLE audit`);
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue