From 55bcff80306bfd830472aef9c30ec2ee11b98736 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:13:13 +0200 Subject: [PATCH] fix ticket cmd perms, updated djs & added dump cmd --- package.json | 2 +- src/commands/panel.ts | 2 +- src/core/api/defaults/client.ts | 4 +- src/core/api/modules/client.ts | 2 +- src/core/api/modules/defaults.ts | 3 + src/core/api/modules/permission.ts | 127 ++++++++++++++++------------- src/core/api/modules/responder.ts | 2 +- src/core/startup/dump.ts | 30 +++++++ src/data/framework/codeLoader.ts | 1 + src/index.ts | 3 + 10 files changed, 113 insertions(+), 63 deletions(-) create mode 100644 src/core/startup/dump.ts diff --git a/package.json b/package.json index d2c9e4d..8e2a1dd 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "dependencies": { "@types/node": "^22.5.0", "ansis": "^2.3.0", - "discord.js": "^14.15.3", + "discord.js": "^14.16.1", "formatted-json-stringify": "^1.1.0", "typescript": "^5.5.4" }, diff --git a/src/commands/panel.ts b/src/commands/panel.ts index 72cf050..0a7a184 100644 --- a/src/commands/panel.ts +++ b/src/commands/panel.ts @@ -46,7 +46,7 @@ export const registerCommandResponders = async () => { }), new api.ODWorker("openticket:panel",0,async (instance,params,source,cancel) => { const {guild,channel,user} = instance - if (!guild){ + if (!guild || instance.channel.type == discord.ChannelType.GroupDM){ //error instance.reply(await openticket.builders.messages.getSafe("openticket:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() diff --git a/src/core/api/defaults/client.ts b/src/core/api/defaults/client.ts index d03d26f..95e2cfe 100644 --- a/src/core/api/defaults/client.ts +++ b/src/core/api/defaults/client.ts @@ -82,6 +82,7 @@ export class ODSlashCommandManager_Default extends ODSlashCommandManager { * It's used to generate typescript declarations for this class. */ export interface ODTextCommandManagerIds_Default { + "openticket:dump":ODTextCommand, "openticket:help":ODTextCommand, "openticket:panel":ODTextCommand, "openticket:close":ODTextCommand, @@ -138,9 +139,6 @@ export class ODTextCommandManager_Default extends ODTextCommandManager { return super.exists(id) } - onInteraction(prefix:string, id:keyof ODTextCommandManagerIds_Default, callback:ODTextCommandInteractionCallback): void - onInteraction(commandPrefix:string, commandName:string|RegExp, callback:ODTextCommandInteractionCallback): void - onInteraction(commandPrefix:string, commandName:string|RegExp, callback:ODTextCommandInteractionCallback): void { return super.onInteraction(commandPrefix,commandName,callback) } diff --git a/src/core/api/modules/client.ts b/src/core/api/modules/client.ts index c7ca8dc..ccd6804 100644 --- a/src/core/api/modules/client.ts +++ b/src/core/api/modules/client.ts @@ -996,7 +996,7 @@ export class ODTextCommandManager extends ODManager { //filter commands for correct name const validNameCommands: {cmd:ODTextCommand,newContent:string}[] = [] validPrefixCommands.forEach((cmd) => { - if (cmd.newContent.startsWith(cmd.cmd.builder.name)) validNameCommands.push({ + if (cmd.newContent.startsWith(cmd.cmd.builder.name+" ") || cmd.newContent == cmd.cmd.builder.name) validNameCommands.push({ cmd:cmd.cmd, newContent:cmd.newContent.substring(cmd.cmd.builder.name.length+1) //+1 because of space after command name }) diff --git a/src/core/api/modules/defaults.ts b/src/core/api/modules/defaults.ts index 352c4ac..d67625e 100644 --- a/src/core/api/modules/defaults.ts +++ b/src/core/api/modules/defaults.ts @@ -13,6 +13,8 @@ export interface ODDefaults { crashOnError:boolean, /**Enable the system responsible for the `--debug` flag. */ debugLoading:boolean, + /**When enabled, you're able to use the "!OPENTICKET:dump" command to send the OT debug file. This is only possible when you're the owner of the bot. */ + allowDumpCommand:boolean, /**Enable loading all Open Ticket plugins, sadly enough is only useful for the system :) */ pluginLoading:boolean, /**Don't crash the bot when a plugin crashes! */ @@ -219,6 +221,7 @@ export class ODDefaultsManager { errorHandling:true, crashOnError:false, debugLoading:true, + allowDumpCommand:true, pluginLoading:true, softPluginLoading:false, diff --git a/src/core/api/modules/permission.ts b/src/core/api/modules/permission.ts index d46921b..5602d29 100644 --- a/src/core/api/modules/permission.ts +++ b/src/core/api/modules/permission.ts @@ -91,66 +91,18 @@ export class ODPermissionManager extends ODManager { else throw new ODSystemError("Invalid minimum permission type at ODPermissionManager.hasPermissions()") } async #defaultCalculation(user:discord.User,channel?:discord.Channel|null,guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { + const globalCalc = await this.#defaultGlobalCalculation(user,channel,guild,settings) + const channelCalc = await this.#defaultChannelCalculation(user,channel,guild,settings) + + if (globalCalc.level > channelCalc.level) return globalCalc + else return channelCalc + } + /**Check for global permissions. Then this result can be compared with the channel one. */ + async #defaultGlobalCalculation(user:discord.User,channel?:discord.Channel|null,guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { const idRegex = (settings && typeof settings.idRegex != "undefined") ? settings.idRegex : null - const allowChannelUserScope = (settings && typeof settings.allowChannelUserScope != "undefined") ? settings.allowChannelUserScope : true - const allowChannelRoleScope = (settings && typeof settings.allowChannelRoleScope != "undefined") ? settings.allowChannelRoleScope : true const allowGlobalUserScope = (settings && typeof settings.allowGlobalUserScope != "undefined") ? settings.allowGlobalUserScope : true const allowGlobalRoleScope = (settings && typeof settings.allowGlobalRoleScope != "undefined") ? settings.allowGlobalRoleScope : true - if (guild && channel && !channel.isDMBased()){ - //check for channel user permissions - if (allowChannelUserScope){ - const users = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-user" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.User) && permission.value.id == user.id) - - if (users.length > 0){ - //sort all permisions from highest to lowest - users.sort((a,b) => { - const levelA = ODPermissionLevel[a.permission] - const levelB = ODPermissionLevel[b.permission] - - if (levelB > levelA) return 1 - else if (levelA > levelB) return -1 - else return 0 - }) - - return { - type:users[0].permission, - scope:"channel-user", - level:ODPermissionLevel[users[0].permission], - source:users[0] ?? null - } - } - } - - //check for channel role permissions - if (allowChannelRoleScope){ - const member = await guild.members.fetch(user.id) - if (member){ - const memberRoles = member.roles.cache.map((role) => role.id) - const roles = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-role" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.Role) && memberRoles.includes(permission.value.id) && permission.value.guild.id == guild.id) - - if (roles.length > 0){ - //sort all permisions from highest to lowest - roles.sort((a,b) => { - const levelA = ODPermissionLevel[a.permission] - const levelB = ODPermissionLevel[b.permission] - - if (levelB > levelA) return 1 - else if (levelA > levelB) return -1 - else return 0 - }) - - return { - type:roles[0].permission, - scope:"channel-role", - level:ODPermissionLevel[roles[0].permission], - source:roles[0] ?? null - } - } - } - } - } - //check for global user permissions if (allowGlobalUserScope){ const users = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "global-user" && (permission.value instanceof discord.User) && permission.value.id == user.id) @@ -205,6 +157,69 @@ export class ODPermissionManager extends ODManager { } } + //spread result to prevent accidental referencing + return {...this.defaultResult} + } + /**Check for channel permissions. Then this result can be compared with the global one. */ + async #defaultChannelCalculation(user:discord.User,channel?:discord.Channel|null,guild?:discord.Guild|null, settings?:ODPermissionSettings|null): Promise { + const idRegex = (settings && typeof settings.idRegex != "undefined") ? settings.idRegex : null + const allowChannelUserScope = (settings && typeof settings.allowChannelUserScope != "undefined") ? settings.allowChannelUserScope : true + const allowChannelRoleScope = (settings && typeof settings.allowChannelRoleScope != "undefined") ? settings.allowChannelRoleScope : true + + if (guild && channel && !channel.isDMBased()){ + //check for channel user permissions + if (allowChannelUserScope){ + const users = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-user" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.User) && permission.value.id == user.id) + + if (users.length > 0){ + //sort all permisions from highest to lowest + users.sort((a,b) => { + const levelA = ODPermissionLevel[a.permission] + const levelB = ODPermissionLevel[b.permission] + + if (levelB > levelA) return 1 + else if (levelA > levelB) return -1 + else return 0 + }) + + return { + type:users[0].permission, + scope:"channel-user", + level:ODPermissionLevel[users[0].permission], + source:users[0] ?? null + } + } + } + + //check for channel role permissions + if (allowChannelRoleScope){ + const member = await guild.members.fetch(user.id) + if (member){ + const memberRoles = member.roles.cache.map((role) => role.id) + const roles = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-role" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.Role) && memberRoles.includes(permission.value.id) && permission.value.guild.id == guild.id) + + if (roles.length > 0){ + //sort all permisions from highest to lowest + roles.sort((a,b) => { + const levelA = ODPermissionLevel[a.permission] + const levelB = ODPermissionLevel[b.permission] + + if (levelB > levelA) return 1 + else if (levelA > levelB) return -1 + else return 0 + }) + + return { + type:roles[0].permission, + scope:"channel-role", + level:ODPermissionLevel[roles[0].permission], + source:roles[0] ?? null + } + } + } + } + } + //spread result to prevent accidental referencing return {...this.defaultResult} } diff --git a/src/core/api/modules/responder.ts b/src/core/api/modules/responder.ts index 9749471..2b7338f 100644 --- a/src/core/api/modules/responder.ts +++ b/src/core/api/modules/responder.ts @@ -325,7 +325,7 @@ export class ODCommandResponderInstance { this.didReply = true return {success:true,message:await sent.fetch()} } - }else if (this.type == "message" && this.interaction instanceof discord.Message){ + }else if (this.type == "message" && this.interaction instanceof discord.Message && this.interaction.channel.type != discord.ChannelType.GroupDM){ const sent = await this.interaction.channel.send(msg.message) this.didReply = true return {success:true,message:sent} diff --git a/src/core/startup/dump.ts b/src/core/startup/dump.ts new file mode 100644 index 0000000..1929e9f --- /dev/null +++ b/src/core/startup/dump.ts @@ -0,0 +1,30 @@ +import {openticket, api, utilities} from "../../index" +import * as discord from "discord.js" +import * as fs from "fs" + +export const loadDumpCommand = () => { + openticket.client.textCommands.add(new api.ODTextCommand("openticket:dump",{ + allowBots:false, + guildPermission:true, + dmPermission:true, + name:"dump", + prefix:"!OPENTICKET:" + })) + + openticket.client.textCommands.onInteraction("!OPENTICKET:","dump",async (msg) => { + if (msg.author.id == "779742674932072469" || openticket.permissions.hasPermissions("developer",await openticket.permissions.getPermissions(msg.author,msg.channel,null))){ + //user is bot owner OR creator of Open Ticket :) + openticket.log("Dumped otdebug.txt!","system",[ + {key:"user",value:msg.author.username}, + {key:"id",value:msg.author.id} + ]) + const debug = fs.readFileSync("./otdebug.txt") + + if (msg.channel.type != discord.ChannelType.GroupDM) msg.channel.send({content:"## The `otdebug.txt` dump is available!",files:[ + new discord.AttachmentBuilder(debug) + .setName("otdebug.txt") + .setDescription("The Open Ticket debug dump!") + ]}) + } + }) +} \ No newline at end of file diff --git a/src/data/framework/codeLoader.ts b/src/data/framework/codeLoader.ts index dd65bb7..2a52973 100644 --- a/src/data/framework/codeLoader.ts +++ b/src/data/framework/codeLoader.ts @@ -25,6 +25,7 @@ export const loadCommandErrorHandlingCode = async () => { openticket.code.add(new api.ODCode("openticket:command-error-handling",14,() => { //invalid/missing options openticket.client.textCommands.onError(async (error) => { + if (error.msg.channel.type == discord.ChannelType.GroupDM) return if (error.type == "invalid_option"){ error.msg.channel.send((await openticket.builders.messages.getSafe("openticket:error-option-invalid").build("text",{guild:error.msg.guild,channel:error.msg.channel,user:error.msg.author,error})).message) }else if (error.type == "missing_option"){ diff --git a/src/index.ts b/src/index.ts index 3226910..6d5281b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -373,6 +373,9 @@ const main = async () => { //load text commands openticket.log("Loading text commands...","system") + if (openticket.defaults.getDefault("allowDumpCommand")){ + (await import("./core/startup/dump.js")).loadDumpCommand() + } if (openticket.defaults.getDefault("textCommandLoading")){ await (await import("./data/framework/commandLoader.js")).loadAllTextCommands() }