diff --git a/.docs/createDocs.js b/.docs/createDocs.js
deleted file mode 100644
index efb5a05..0000000
--- a/.docs/createDocs.js
+++ /dev/null
@@ -1,328 +0,0 @@
-//@ts-check
-const fs = require("fs")
-
-/*////// OT DOCS GENERATOR ////////
-What does this file do?:
-Well, this file will parse the result returned from typedoc (the documentation generator).
-The resulting file will then be used in the OT Docs markdown generator to generate the Open Ticket API Reference.
-
-In short:
-This file generates the documentation for Open Ticket :)
-
-Contributing:
-If you want to contribute to the Open Ticket Docs, please run the following command:
-
-> npm run docs
-
-This will give you a "result.json" file which can then be used in the OT Docs.
-Further instructions can be found there.
-/////////////////////////////////*/
-
-if (!fs.existsSync(".docs/typedoc-result.json")){
- console.log("Unable to generate documentation! Run typedoc first!")
- process.exit(1)
-}
-const result = JSON.parse(fs.readFileSync(".docs/typedoc-result.json").toString())
-const availableElements = []
-const skipElementNames = [
- "#opendiscord-types"
-]
-
-const handleFunction = (memberType) => {
- if (!memberType || !memberType.signatures || !Array.isArray(memberType.signatures)) return {type:"unknown"}
-
- //try to get signature
- let signature = memberType.signatures.find((s) => !s.typeParameters)
- if (!signature) signature = memberType.signatures[0]
- if (!signature) return {type:"unknown"}
-
- //try to get comment
- let comment = signature.comment
- if (!comment) comment = memberType.signatures.find((s) => s.comment)?.comment
- if (!comment) comment = null
-
- const signatureInherited = signature.flags.isInherited ? true : false
- const signatureComment = comment ? comment.summary?.map((c) => c.text).join("") : null
- const signatureParameters = signature.parameters?.map((p) => {
- return {name:p.name,details:handleType(p.type)}
- }) ?? []
- const signatureReturns = handleType(signature.type)
-
- return {type:"function",inherited:signatureInherited,comment:signatureComment,parameters:signatureParameters,returns:signatureReturns}
-}
-
-const handleObject = (memberType) => {
- if (!memberType || !memberType.children || !Array.isArray(memberType.children)) return {type:"unknown"}
- const propertyIds = memberType.groups?.find((g) => g.title == "Properties")?.children ?? []
- const methodIds = memberType.groups?.find((g) => g.title == "Methods")?.children ?? []
-
- const objectChildren = []
- for (const member of (memberType.children ?? [])){
- const memberName = member.name
- const memberType = propertyIds.includes(member.id) ? "property" : methodIds.includes(member.id) ? "method" : "other"
- let memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null
-
- const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null
- let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null
-
- let memberDetails = null
- if (memberType == "property"){
- //INTERFACE => PROPERTY
- memberDetails = handleType(member.type)
- }else if (memberType == "method"){
- //INTERFACE => METHOD
- memberDetails = handleFunction(member)
- memberComment = memberDetails.comment
- }
-
- objectChildren.push({
- type:memberType,
- name:memberName,
- comment:memberComment,
- source:memberSource,
- details:memberDetails
- })
- }
- return {type:"object",children:objectChildren}
-}
-
-const handleType = (memberType) => {
- if (!memberType || !memberType.type) return {type:"unknown"}
- else if (memberType.type == "intrinsic") return {type:"primitive",name:memberType.name}
- else if (memberType.type == "array") return {type:"array",child:handleType(memberType.elementType)}
- else if (memberType.type == "union") return {type:"union",children:memberType.types.map((t) => handleType(t))}
- else if (memberType.type == "intersection") return {type:"intersection",children:memberType.types.map((t) => handleType(t))}
- else if (memberType.type == "reference"){
- const referenceTypeArguments = (memberType.typeArguments) ? memberType.typeArguments.map((ta) => handleType(ta)) : null
- let referenceType = availableElements.find((el) => el.name == memberType.name)?.type ?? null
-
- if (referenceType){
- //member is known type (from Open Ticket)
- return {type:"reference",name:memberType.name,target:referenceType,typeArguments:referenceTypeArguments}
- }else if (memberType.package){
- //member is type from node.js or another package
- if (memberType.package == "typescript") return {type:"internal",name:memberType.name,typeArguments:referenceTypeArguments}
- if (memberType.package == "open-ticket" && memberType.refersToTypeParameter) return {type:"typeParam",name:memberType.name,typeArguments:referenceTypeArguments}
- else return {type:"external",package:memberType.package,name:memberType.name,typeArguments:referenceTypeArguments}
- }else return {type:"unknown"}
- }
- else if (memberType.type == "literal") return {type:"literal",name:(typeof memberType.value == "string") ? JSON.stringify(memberType.value) : String(memberType.value)}
- else if (memberType.type == "typeOperator"){
- if (memberType.operator == "keyof") return {type:"keyof",child:handleType(memberType.target)}
- else if (memberType.operator == "readonly") return {type:"readonly",child:handleType(memberType.target)}
- else if (memberType.operator == "unique") return {type:"unique",child:handleType(memberType.target)}
- }
- else if (memberType.type == "conditional") return {type:"conditional",checker:handleType(memberType.checkType),extends:handleType(memberType.extendsType),trueValue:handleType(memberType.trueType),falseValue:handleType(memberType.falseType)}
- else if (memberType.type == "indexedAccess") return {type:"index",index:handleType(memberType.indexType),object:handleType(memberType.objectType)}
- else if (memberType.type == "mapped") return {type:"mapped",parameterName:memberType.parameter,parameter:handleType(memberType.parameterType),template:handleType(memberType.templateType)}
- else if (memberType.type == "optional") return {type:"optional",child:handleType(memberType.elementType)}
- else if (memberType.type == "predicate") return {type:"predicate",name:memberType.name,target:handleType(memberType.targetType)}
- else if (memberType.type == "query") return {type:"query",target:handleType(memberType.queryType)}
- else if (memberType.type == "rest") return {type:"rest",child:handleType(memberType.elementType)}
- else if (memberType.type == "tuple") return {type:"tuple",children:memberType.elements.map((t) => handleType(t))}
- else if (memberType.type == "templateLiteral") return {type:"template",head:memberType.head,tails:memberType.tail.map((t) => {
- return {element:handleType(t[0]),text:t[1]}
- })}
- else if (memberType.type == "reflection" && memberType.declaration && memberType.declaration.signatures && memberType.declaration.signatures[0]){
- return handleFunction(memberType.declaration)
- }
- else if (memberType.type == "reflection"){
- return handleObject(memberType.declaration)
- }
- else return {type:"unknown"}
-}
-
-for (const file of result.children){
- const classIds = file.groups?.find((g) => g.title == "Classes")?.children ?? []
- const interfaceIds = file.groups?.find((g) => g.title == "Interfaces")?.children ?? []
- const typeIds = file.groups?.find((g) => g.title == "Type Aliases")?.children ?? []
- const enumIds = file.groups?.find((g) => g.title == "Enumerations")?.children ?? []
- const varIds = file.groups?.find((g) => g.title == "Variables")?.children ?? []
- const funcIds = file.groups?.find((g) => g.title == "Functions")?.children ?? []
-
- for (const declaration of file.children){
- const declarationName = declaration.name
- const declarationType = classIds.includes(declaration.id) ? "class" : interfaceIds.includes(declaration.id) ? "interface" : typeIds.includes(declaration.id) ? "type" : enumIds.includes(declaration.id) ? "enum" : varIds.includes(declaration.id) ? "variable" : funcIds.includes(declaration.id) ? "function" : "other"
- availableElements.push({name:declarationName,type:declarationType})
- }
-}
-
-const exported = []
-for (const file of result.children){
- const classIds = file.groups?.find((g) => g.title == "Classes")?.children ?? []
- const interfaceIds = file.groups?.find((g) => g.title == "Interfaces")?.children ?? []
- const typeIds = file.groups?.find((g) => g.title == "Type Aliases")?.children ?? []
- const enumIds = file.groups?.find((g) => g.title == "Enumerations")?.children ?? []
- const varIds = file.groups?.find((g) => g.title == "Variables")?.children ?? []
- const funcIds = file.groups?.find((g) => g.title == "Functions")?.children ?? []
-
- for (const declaration of (file.children ?? [])){
- const declarationName = declaration.name
- if (skipElementNames.includes(declarationName)) continue
-
- const declarationType = classIds.includes(declaration.id) ? "class" : interfaceIds.includes(declaration.id) ? "interface" : typeIds.includes(declaration.id) ? "type" : enumIds.includes(declaration.id) ? "enum" : varIds.includes(declaration.id) ? "variable" : funcIds.includes(declaration.id) ? "function" : "other"
- const declarationTypeParams = (declaration.typeParameters) ? declaration.typeParameters.map((tp) => {
- return {name:tp.name,type:handleType(tp.type)}
- }) : null
- const declarationComment = declaration.comment?.summary?.map((c) => c.text).join("") ?? null
- const declarationConstant = declaration.flags.isConst ? true : false
-
- const rawDeclarationSource = declaration.sources ? (declaration.sources[0] ?? null) : null
- const declarationSource = rawDeclarationSource ? rawDeclarationSource.fileName+":"+rawDeclarationSource.line+":"+rawDeclarationSource.character : null
-
- const declarationChildren = []
- if (declarationType == "class"){
- //CLASS
- const constructorIds = declaration.groups?.find((g) => g.title == "Constructors")?.children ?? []
- const propertyIds = declaration.groups?.find((g) => g.title == "Properties")?.children ?? []
- const methodIds = declaration.groups?.find((g) => g.title == "Methods")?.children ?? []
-
- for (const member of (declaration.children ?? [])){
- const memberName = member.name
- const memberType = constructorIds.includes(member.id) ? "constructor" : propertyIds.includes(member.id) ? "property" : methodIds.includes(member.id) ? "method" : "other"
- let memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null
-
- const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null
- let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null
-
- const memberInherited = member.flags.isInherited ? true : false
- const memberStatic = member.flags.isStatic ? true : false
- const memberProtected = member.flags.isProtected ? true : false
- const memberOptional = member.flags.isOptional ? true : false
- const memberReadonly = member.flags.isReadonly ? true : false
-
- let memberDetails = null
- if (memberType == "property"){
- //CLASS => PROPERTY
- memberDetails = handleType(member.type)
-
- }else if (memberType == "method"){
- //CLASS => METHOD
- memberDetails = handleFunction(member)
- memberComment = memberDetails.comment
-
- }else if (memberType == "constructor"){
- //CLASS => CONSTRUCTOR
- memberDetails = handleFunction(member)
- memberComment = memberDetails.comment
- }
-
- declarationChildren.push({
- type:memberType,
- name:memberName,
- comment:memberComment,
- source:memberSource,
- details:memberDetails,
- inherited:memberInherited,
- static:memberStatic,
- protected:memberProtected,
- optional:memberOptional,
- readonly:memberReadonly
- })
- }
- }else if (declarationType == "interface"){
- //INTERFACE
- const propertyIds = declaration.groups?.find((g) => g.title == "Properties")?.children ?? []
- const methodIds = declaration.groups?.find((g) => g.title == "Methods")?.children ?? []
-
- for (const member of (declaration.children ?? [])){
- const memberName = member.name
- const memberType = propertyIds.includes(member.id) ? "property" : methodIds.includes(member.id) ? "method" : "other"
- let memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null
-
- const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null
- let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null
-
- const memberInherited = member.flags.isInherited ? true : false
- const memberStatic = member.flags.isStatic ? true : false
- const memberProtected = member.flags.isProtected ? true : false
- const memberOptional = member.flags.isOptional ? true : false
- const memberReadonly = member.flags.isReadonly ? true : false
-
- let memberDetails = null
- if (memberType == "property"){
- //INTERFACE => PROPERTY
- memberDetails = handleType(member.type)
- }else if (memberType == "method"){
- //INTERFACE => METHOD
- memberDetails = handleFunction(member)
- memberComment = memberDetails.comment
- }
-
- declarationChildren.push({
- type:memberType,
- name:memberName,
- comment:memberComment,
- source:memberSource,
- details:memberDetails,
- inherited:memberInherited,
- static:memberStatic,
- protected:memberProtected,
- optional:memberOptional,
- readonly:memberReadonly
- })
- }
- }else if (declarationType == "type"){
- //TYPE
- declarationChildren.push(handleType(declaration.type))
- }else if (declarationType == "enum"){
- //ENUM
- const enumerableIds = declaration.groups?.find((g) => g.title == "Enumeration Members")?.children ?? []
-
- for (const member of (declaration.children ?? [])){
- const memberName = member.name
- const memberType = enumerableIds.includes(member.id) ? "enumerable" : "other"
- const memberComment = member.comment?.summary?.map((c) => c.text).join("") ?? null
-
- const rawMemberSource = member.sources ? (member.sources[0] ?? null) : null
- let memberSource = rawMemberSource ? rawMemberSource.fileName+":"+rawMemberSource.line+":"+rawMemberSource.character : null
-
- let memberDetails = null
- if (memberType == "enumerable"){
- //ENUM => ENUMERABLE
- memberDetails = handleType(member.type)
- }
-
- const memberInherited = member.flags.isInherited ? true : false
- const memberStatic = member.flags.isStatic ? true : false
- const memberProtected = member.flags.isProtected ? true : false
- const memberOptional = member.flags.isOptional ? true : false
- const memberReadonly = member.flags.isReadonly ? true : false
-
- declarationChildren.push({
- type:memberType,
- name:memberName,
- comment:memberComment,
- source:memberSource,
- details:memberDetails,
- inherited:memberInherited,
- static:memberStatic,
- protected:memberProtected,
- optional:memberOptional,
- readonly:memberReadonly
- })
- }
- }else if (declarationType == "variable"){
- //VARIABLE
- declarationChildren.push(handleType(declaration.type))
-
- }else if (declarationType == "function"){
- //FUNCTION
- declarationChildren.push(handleFunction(declaration))
-
- }
-
- exported.push({
- type:declarationType,
- name:declarationName,
- comment:declarationComment,
- constant:declarationConstant,
- source:declarationSource,
- children:declarationChildren,
- typeParams:declarationTypeParams
- })
- }
-}
-
-fs.writeFileSync(".docs/result.json",JSON.stringify(exported,null,"\t"))
-fs.rmSync(".docs/typedoc-result.json")
\ No newline at end of file
diff --git a/.docs/typedoc-config.json b/.docs/typedoc-config.json
deleted file mode 100644
index 61e64f7..0000000
--- a/.docs/typedoc-config.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "$schema": "https://typedoc.org/schema.json",
- "entryPoints": [
- "../src/core/api/modules/",
- "../src/core/api/defaults/",
- "../src/core/api/openticket/",
- "../src/core/api/main.ts",
- "../src/core/startup/init.ts",
- ],
- "entryPointStrategy": "expand",
- "json": "./typedoc-result.json",
- "basePath": "../"
-}
\ No newline at end of file
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 59c6ac0..c7cc36e 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -1,7 +1,7 @@
# Contributing Guidelines
-[](https://discord.com/invite/26vT9wt3n3) [](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.3) [](https://github.com/sponsors/DJj123dj)
+[](https://discord.com/invite/26vT9wt3n3) [](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.2.0) [](https://github.com/sponsors/DJj123dj)
These are the Contributing Guidelines of Open Ticket!
Here you can find everything you need to know about contributing to Open Ticket.
diff --git a/.github/CONTRIBUTORS.json b/.github/CONTRIBUTORS.json
new file mode 100644
index 0000000..f703118
--- /dev/null
+++ b/.github/CONTRIBUTORS.json
@@ -0,0 +1,93 @@
+{
+ "_INFO":"This document contains all Open Ticket contributors.",
+ "SPONSOR_TEMPLATE":{
+ "name":"INSERT_NAME",
+ "pictureUrl":"INSERT_PICTURE_URL",
+ "profileUrl":"INSERT_PROFILE_URL",
+ "sectionId":"INSERT_ID"
+ },
+ "SECTION_TEMPLATE":{
+ "name":"INSERT_NAME",
+ "id":"INSERT_ID",
+ "pfpSize":50,
+ "pfpColumns":5,
+ "withNames":true
+ },
+ "sections":[
+ {
+ "name":"🛠️ Contributors",
+ "id":"contributor",
+ "pfpSize":100,
+ "pfpColumns":8,
+ "withNames":true
+ },
+ {
+ "name":"📞 Discord Support",
+ "id":"support",
+ "pfpSize":100,
+ "pfpColumns":8,
+ "withNames":true
+ },
+ {
+ "name":"🧩 Plugin Developers",
+ "id":"plugin-dev",
+ "pfpSize":100,
+ "pfpColumns":8,
+ "withNames":true
+ },
+ {
+ "name":"💬 Translators",
+ "id":"translator",
+ "pfpSize":100,
+ "pfpColumns":8,
+ "withNames":true
+ }
+ ],
+ "contributors":[
+ {"sectionId":"contributor","name":"DJj123dj","pictureUrl":"https://github.com/DJj123dj.png","profileUrl":"https://github.com/DJj123dj"},
+ {"sectionId":"contributor","name":"guillee3","pictureUrl":"https://github.com/guillee3.png","profileUrl":"https://github.com/guillee3"},
+ {"sectionId":"contributor","name":"SKaranjaN","pictureUrl":"https://github.com/SKaranjaN.png","profileUrl":"https://github.com/SKaranjaN"},
+ {"sectionId":"contributor","name":"Ashish5180","pictureUrl":"https://github.com/Ashish5180.png","profileUrl":"https://github.com/Ashish5180"},
+ {"sectionId":"contributor","name":"duboiss","pictureUrl":"https://github.com/duboiss.png","profileUrl":"https://github.com/duboiss"},
+ {"sectionId":"contributor","name":"sdehaarte","pictureUrl":"https://github.com/sdehaarte.png","profileUrl":"https://github.com/sdehaarte"},
+ {"sectionId":"contributor","name":"MauroDruwel","pictureUrl":"https://github.com/MauroDruwel.png","profileUrl":"https://github.com/MauroDruwel"},
+ {"sectionId":"support","name":"smetsliam","pictureUrl":"https://github.com/smetsliam.png","profileUrl":"https://github.com/smetsliam"},
+ {"sectionId":"support","name":"Sank34","pictureUrl":"https://github.com/Sank34.png","profileUrl":"https://github.com/Sank34"},
+ {"sectionId":"support","name":"FrankVissers","pictureUrl":"https://github.com/FrankVissers.png","profileUrl":"https://github.com/FrankVissers"},
+ {"sectionId":"plugin-dev","name":"Rapid-Fast","pictureUrl":"https://github.com/Rapid-Fast.png","profileUrl":"https://github.com/Rapid-Fast"},
+ {"sectionId":"plugin-dev","name":"NotMukundOP","pictureUrl":"https://github.com/NotMukundOP.png","profileUrl":"https://github.com/NotMukundOP"},
+ {"sectionId":"plugin-dev","name":"Imperatorix17","pictureUrl":"https://github.com/imperatorix17.png","profileUrl":"https://github.com/imperatorix17"},
+ {"sectionId":"plugin-dev","name":"DanoGlez","pictureUrl":"https://github.com/DanoGlez.png","profileUrl":"https://github.com/DanoGlez"},
+ {"sectionId":"plugin-dev","name":"yowsef","pictureUrl":"https://github.com/Yow-sef.png","profileUrl":"https://github.com/Yow-sef"},
+ {"sectionId":"plugin-dev","name":"MeneerSouf","pictureUrl":"https://github.com/MeneerSouf.png","profileUrl":"https://github.com/MeneerSouf"},
+ {"sectionId":"plugin-dev","name":"challenger_nova","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"HanumeshGupta","pictureUrl":"https://github.com/HanumeshGupta.png","profileUrl":"https://github.com/HanumeshGupta"},
+ {"sectionId":"translator","name":"benzorich","pictureUrl":"https://github.com/benzorich.png","profileUrl":"https://github.com/benzorich"},
+ {"sectionId":"translator","name":"Reddishye","pictureUrl":"https://github.com/Reddishye.png","profileUrl":"https://github.com/Reddishye"},
+ {"sectionId":"translator","name":"josuens","pictureUrl":"https://github.com/josuens.png","profileUrl":"https://github.com/josuens"},
+ {"sectionId":"translator","name":"quiradon","pictureUrl":"https://github.com/quiradon.png","profileUrl":"https://github.com/quiradon"},
+ {"sectionId":"translator","name":"Imperatorix17","pictureUrl":"https://github.com/imperatorix17.png","profileUrl":"https://github.com/imperatorix17"},
+ {"sectionId":"translator","name":"NoOneNook","pictureUrl":"https://github.com/NoOneNook.png","profileUrl":"https://github.com/NoOneNook"},
+ {"sectionId":"translator","name":"guillee3","pictureUrl":"https://github.com/guillee3.png","profileUrl":"https://github.com/guillee3"},
+ {"sectionId":"translator","name":"Mods HD","pictureUrl":"https://github.com/mods-hd.png","profileUrl":"https://github.com/mods-hd"},
+ {"sectionId":"translator","name":"anderskiy","pictureUrl":"https://github.com/anderskiy.png","profileUrl":"https://github.com/anderskiy"},
+ {"sectionId":"translator","name":"SpyEye2","pictureUrl":"https://github.com/SpyEye2.png","profileUrl":"https://github.com/SpyEye2"},
+ {"sectionId":"translator","name":"Sank34","pictureUrl":"https://github.com/Sank34.png","profileUrl":"https://github.com/Sank34"},
+ {"sectionId":"translator","name":"thegamer5095","pictureUrl":"https://github.com/thegamer5095.png","profileUrl":"https://github.com/thegamer5095"},
+ {"sectionId":"translator","name":"danoglez","pictureUrl":"https://github.com/danoglez.png","profileUrl":"https://github.com/danoglez"},
+ {"sectionId":"translator","name":"zhavis","pictureUrl":"https://github.com/zhavis.png","profileUrl":"https://github.com/zhavis"},
+ {"sectionId":"translator","name":"yuuslokrobjakkroval","pictureUrl":"https://github.com/yuuslokrobjakkroval.png","profileUrl":"https://github.com/yuuslokrobjakkroval"},
+ {"sectionId":"translator","name":"imLudwig","pictureUrl":"https://github.com/imLudwig.png","profileUrl":"https://github.com/imLudwig"},
+ {"sectionId":"translator","name":"iamnotmega","pictureUrl":"https://github.com/iamnotmega.png","profileUrl":"https://github.com/iamnotmega"},
+ {"sectionId":"translator","name":"Ronalds13424","pictureUrl":"https://github.com/Ronalds13424.png","profileUrl":"https://github.com/Ronalds13424"},
+ {"sectionId":"translator","name":"dysashop","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"fraden1mvp.","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"palestinian","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"challenger_nova","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"erxg","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"tsgindrius","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"kornel0706","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"me.october","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""},
+ {"sectionId":"translator","name":"ngocdiep2006","pictureUrl":"https://apis.dj-dj.be/cdn/openticket/default-avatar.png","profileUrl":""}
+ ]
+}
\ No newline at end of file
diff --git a/.github/CONTRIBUTORS.svg b/.github/CONTRIBUTORS.svg
new file mode 100644
index 0000000..97cec2f
--- /dev/null
+++ b/.github/CONTRIBUTORS.svg
@@ -0,0 +1,288 @@
+
+
+ 🛠️ Contributors
+
+
+
+
+ DJj123dj
+
+
+
+
+
+ guillee3
+
+
+
+
+
+ SKaranjaN
+
+
+
+
+
+ Ashish5180
+
+
+
+
+
+ duboiss
+
+
+
+
+
+ sdehaarte
+
+
+
+
+
+ MauroDruwel
+ 📞 Discord Support
+
+
+
+
+ smetsliam
+
+
+
+
+
+ Sank34
+
+
+
+
+
+ FrankVissers
+ 🧩 Plugin Developers
+
+
+
+
+ Rapid-Fast
+
+
+
+
+
+ NotMukundOP
+
+
+
+
+
+ Imperatorix17
+
+
+
+
+
+ DanoGlez
+
+
+
+
+
+ yowsef
+
+
+
+
+
+ MeneerSouf
+
+
+
+
+
+ challenger_nova
+ 💬 Translators
+
+
+
+
+ HanumeshGupta
+
+
+
+
+
+ benzorich
+
+
+
+
+
+ Reddishye
+
+
+
+
+
+ josuens
+
+
+
+
+
+ quiradon
+
+
+
+
+
+ Imperatorix17
+
+
+
+
+
+ NoOneNook
+
+
+
+
+
+ guillee3
+
+
+
+
+
+ Mods HD
+
+
+
+
+
+ anderskiy
+
+
+
+
+
+ SpyEye2
+
+
+
+
+
+ Sank34
+
+
+
+
+
+ thegamer5095
+
+
+
+
+
+ danoglez
+
+
+
+
+
+ zhavis
+
+
+
+
+
+ yuuslokrobjakkroval
+
+
+
+
+
+ imLudwig
+
+
+
+
+
+ iamnotmega
+
+
+
+
+
+ Ronalds13424
+
+
+
+
+
+ dysashop
+
+
+
+
+
+ fraden1mvp.
+
+
+
+
+
+ palestinian
+
+
+
+
+
+ challenger_nova
+
+
+
+
+
+ erxg
+
+
+
+
+
+ tsgindrius
+
+
+
+
+
+ kornel0706
+
+
+
+
+
+ me.october
+
+
+
+
+
+ ngocdiep2006
+
+
\ No newline at end of file
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
index 3f704b6..a381a61 100644
--- a/.github/SECURITY.md
+++ b/.github/SECURITY.md
@@ -19,18 +19,15 @@ This list will be updated on every release.
| Version | Supported | Notes |
|------------|-----------|---------------------------------------------------------------|
-| 4.2.0 | 🟦 | In Development |
-| 4.1.x | 🟦 | In Development |
-| 4.1.3 | ✅ | |
-| 4.1.2 | ✅ | |
-| 4.1.1 | ✅ | Supported Until April 2026 (LTS) |
+| 4.2.x | 🟦 | In Development |
+| 4.2.1 | 🟦 | In Development |
+| 4.2.0 | ✅ | |
+| 4.1.3 | ✅ | (LTS) Long-Term-Support, Until September 2026 |
+| 4.1.2 | 🚧 | |
+| 4.1.1 | 🚧 | |
| 4.1.0 | 🚧 | |
-| 4.0.7 | 🚧 | |
-| 4.0.6 | 🚧 | |
-| 4.0.5 | 🟧 | Deprecated |
-| 4.0.4 | 🟧 | Deprecated |
-| < 4.0.4 | 🟧 | Deprecated, Transcripts v2.0, Documentation Only |
-| < 4.0.0 | ❌ | |
+| 4.0.7 | 🟧 | Deprecated |
+| < 4.0.7 | ❌ | |
### 🕷️ Reporting Vulnerabilities
You can report vulnerabilities, errors & bugs using one of the following methods:
diff --git a/.github/SPONSORS.json b/.github/SPONSORS.json
new file mode 100644
index 0000000..1e9399a
--- /dev/null
+++ b/.github/SPONSORS.json
@@ -0,0 +1,90 @@
+{
+ "_INFO":"This document contains all Open Ticket sponsors.",
+ "SPONSOR_TEMPLATE":{
+ "name":"INSERT_NAME",
+ "pictureUrl":"INSERT_PICTURE_URL",
+ "profileUrl":"INSERT_PROFILE_URL",
+ "sectionId":"INSERT_ID"
+ },
+ "SECTION_TEMPLATE":{
+ "name":"INSERT_NAME",
+ "id":"INSERT_ID",
+ "pfpSize":50,
+ "pfpColumns":5,
+ "withNames":true
+ },
+ "sections":[
+ {
+ "name":"💎 Platinum Sponsors",
+ "id":"platinum",
+ "pfpSize":120,
+ "pfpColumns":4,
+ "withNames":true
+ },
+ {
+ "name":"🥇 Gold Sponsors",
+ "id":"gold",
+ "pfpSize":60,
+ "pfpColumns":8,
+ "withNames":true
+ },
+ {
+ "name":"🥈 Silver Sponsors",
+ "id":"silver",
+ "pfpSize":40,
+ "pfpColumns":16,
+ "withNames":false
+ },
+ {
+ "name":"❤️ Past Sponsors",
+ "id":"past",
+ "pfpSize":30,
+ "pfpColumns":20,
+ "withNames":false
+ }
+ ],
+ "sponsors":[
+ {
+ "name":"Guillee3",
+ "pictureUrl":"https://github.com/guillee3.png",
+ "profileUrl":"https://github.com/guillee3",
+ "sectionId":"platinum"
+ },
+ {
+ "name":"Jacob Humston",
+ "pictureUrl":"https://github.com/jacobhumston.png",
+ "profileUrl":"https://github.com/jacobhumston",
+ "sectionId":"platinum"
+ },
+ {
+ "name":"SpyEye2",
+ "pictureUrl":"https://github.com/SpyEye2.png",
+ "profileUrl":"https://github.com/SpyEye2",
+ "sectionId":"gold"
+ },
+ {
+ "name":"DOSEV5",
+ "pictureUrl":"https://github.com/DOSEV5.png",
+ "profileUrl":"https://github.com/DOSEV5",
+ "sectionId":"gold"
+ },
+ {
+ "name":"YeeetSK",
+ "pictureUrl":"https://github.com/YeeetSK.png",
+ "profileUrl":"https://github.com/YeeetSK",
+ "sectionId":"silver"
+ },
+ {
+ "name":"BENZORICH",
+ "pictureUrl":"https://github.com/BENZORICH.png",
+ "profileUrl":"https://github.com/BENZORICH",
+ "sectionId":"silver"
+ },
+ {
+ "name":"Mods HD",
+ "pictureUrl":"https://github.com/mods-hd.png",
+ "profileUrl":"https://github.com/mods-hd",
+ "sectionId":"silver"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.github/SPONSORS.svg b/.github/SPONSORS.svg
new file mode 100644
index 0000000..e3edf79
--- /dev/null
+++ b/.github/SPONSORS.svg
@@ -0,0 +1,61 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.eggs/README.md b/.github/pterodactyl-eggs/README.md
similarity index 91%
rename from .eggs/README.md
rename to .github/pterodactyl-eggs/README.md
index 4585e89..c22f4a4 100644
--- a/.eggs/README.md
+++ b/.github/pterodactyl-eggs/README.md
@@ -2,7 +2,7 @@
[](https://discord.com/invite/26vT9wt3n3)
-[](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.3)
+[](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.2.0)
[](https://github.com/sponsors/DJj123dj)
[](.eggs/README.md)
@@ -20,6 +20,9 @@ It's recommended to provide at least `1GB` of **Memory/RAM** and `5GB` of **disk
[**`openticket-egg-main.json` (Recommended)**](openticket-egg-main.json)
- This egg will use the `main` branch of Open Ticket.
+[**`openticket-egg-v4.2.0.json`**](openticket-egg-v4.2.0.json)
+- This egg will always use Open Ticket `v4.2.0`. Open Ticket updates will not have an effect on this egg.
+
[**`openticket-egg-v4.1.3.json`**](openticket-egg-v4.1.3.json)
- This egg will always use Open Ticket `v4.1.3`. Open Ticket updates will not have an effect on this egg.
diff --git a/.eggs/openticket-egg-dev.json b/.github/pterodactyl-eggs/openticket-egg-dev.json
similarity index 100%
rename from .eggs/openticket-egg-dev.json
rename to .github/pterodactyl-eggs/openticket-egg-dev.json
diff --git a/.eggs/openticket-egg-main.json b/.github/pterodactyl-eggs/openticket-egg-main.json
similarity index 100%
rename from .eggs/openticket-egg-main.json
rename to .github/pterodactyl-eggs/openticket-egg-main.json
diff --git a/.eggs/openticket-egg-v3.5.9.json b/.github/pterodactyl-eggs/openticket-egg-v3.5.9.json
similarity index 100%
rename from .eggs/openticket-egg-v3.5.9.json
rename to .github/pterodactyl-eggs/openticket-egg-v3.5.9.json
diff --git a/.eggs/openticket-egg-v4.0.7.json b/.github/pterodactyl-eggs/openticket-egg-v4.0.7.json
similarity index 100%
rename from .eggs/openticket-egg-v4.0.7.json
rename to .github/pterodactyl-eggs/openticket-egg-v4.0.7.json
diff --git a/.eggs/openticket-egg-v4.1.0.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.0.json
similarity index 100%
rename from .eggs/openticket-egg-v4.1.0.json
rename to .github/pterodactyl-eggs/openticket-egg-v4.1.0.json
diff --git a/.eggs/openticket-egg-v4.1.1.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.1.json
similarity index 100%
rename from .eggs/openticket-egg-v4.1.1.json
rename to .github/pterodactyl-eggs/openticket-egg-v4.1.1.json
diff --git a/.eggs/openticket-egg-v4.1.2.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.2.json
similarity index 100%
rename from .eggs/openticket-egg-v4.1.2.json
rename to .github/pterodactyl-eggs/openticket-egg-v4.1.2.json
diff --git a/.eggs/openticket-egg-v4.1.3.json b/.github/pterodactyl-eggs/openticket-egg-v4.1.3.json
similarity index 100%
rename from .eggs/openticket-egg-v4.1.3.json
rename to .github/pterodactyl-eggs/openticket-egg-v4.1.3.json
diff --git a/.github/pterodactyl-eggs/openticket-egg-v4.2.0.json b/.github/pterodactyl-eggs/openticket-egg-v4.2.0.json
new file mode 100644
index 0000000..88530ca
--- /dev/null
+++ b/.github/pterodactyl-eggs/openticket-egg-v4.2.0.json
@@ -0,0 +1,62 @@
+{
+ "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
+ "meta": {
+ "version": "PTDL_v2",
+ "update_url": null
+ },
+ "exported_at": "2025-03-16T18:10:18+01:00",
+ "name": "Open Ticket (v4.2.0)",
+ "author": "support@dj-dj.be",
+ "description": "This is the official Pterodactyl egg for Open Ticket v4.2.0, the most advanced & customisable discord ticket bot that you will ever find! You can customise up to 300+ variables! This includes Html Transcripts, Advanced Plugins, Custom Embeds, Questions\/Modals, Stats & more!",
+ "features": null,
+ "docker_images": {
+ "ghcr.io\/parkervcp\/yolks:nodejs_20": "ghcr.io\/parkervcp\/yolks:nodejs_20"
+ },
+ "file_denylist": [],
+ "startup": "if [[ ! -z ${NODE_PACKAGES} ]]; then npm install ${NODE_PACKAGES}; fi; if [[ ! -z ${UNNODE_PACKAGES} ]]; then npm uninstall ${UNNODE_PACKAGES}; fi; if [ -f \/home\/container\/package.json ]; then npm install; fi; node \"\/home\/container\/index.js\" ${NODE_FLAGS};",
+ "config": {
+ "files": "{}",
+ "startup": "{\r\n \"done\": \"STARTUP INFO:\"\r\n}",
+ "logs": "{}",
+ "stop": "^C"
+ },
+ "scripts": {
+ "installation": {
+ "script": "#!\/bin\/bash\r\n# Open Ticket Installation Script (v4.2.0)\r\n# Inspired by: Node.js Installation Script\r\n# \u00a9 DJdj Development\r\n\r\necho -e \"[OT INSTALLER] installing dependencies. please wait...\"\r\napt update\r\napt install -y git curl\r\n\r\necho -e \"[OT INSTALLER] updating npm. please wait...\"\r\nnpm install npm@latest --location=global\r\n\r\nmkdir -p \/mnt\/server\r\ncd \/mnt\/server\r\n\r\nBRANCH=\"v4.2.0\"\r\n\r\nif [ \"$(ls -A \/mnt\/server)\" ]; then\r\n echo -e \"[OT INSTALLER] \/mnt\/server directory is not empty.\"\r\n if [ -d .git ]; then\r\n echo -e \"[OT INSTALLER] .git directory exists\"\r\n if [ -f .git\/config ]; then\r\n echo -e \"[OT INSTALLER] loading info from git config\"\r\n ORIGIN=$(git config --get remote.origin.url)\r\n else\r\n echo -e \"[OT INSTALLER] files found with no git config\"\r\n echo -e \"[OT INSTALLER] closing out without touching things to not break anything\"\r\n exit 10\r\n fi\r\n fi\r\n\r\n if [ \"${ORIGIN}\" == \"https:\/\/github.com\/open-discord-bots\/open-ticket.git\" ]; then\r\n echo \"pulling latest from github\"\r\n git pull\r\n fi\r\nelse\r\n echo -e \"[OT INSTALLER] \/mnt\/server is empty.\"\r\n echo -e \"[OT INSTALLER] cloning files into repo.\"\r\n if [ -z ${BRANCH} ]; then\r\n echo -e \"[OT INSTALLER] cloning default branch\"\r\n git clone https:\/\/github.com\/open-discord-bots\/open-ticket.git .\r\n else\r\n echo -e \"[OT INSTALLER] cloning ${BRANCH}'\"\r\n git clone --single-branch --branch ${BRANCH} https:\/\/github.com\/open-discord-bots\/open-ticket.git .\r\n fi\r\nfi\r\n\r\necho -e \"[OT INSTALLER] installing Open Ticket node.js packages.\"\r\nif [ -f \/mnt\/server\/package.json ]; then\r\n \/usr\/local\/bin\/npm install --omit=dev\r\nfi\r\n\r\necho -e \"[OT INSTALLER] installing custom node.js packages.\"\r\nif [[ ! -z ${NODE_PACKAGES} ]]; then\r\n \/usr\/local\/bin\/npm install ${NODE_PACKAGES}\r\nfi\r\n\r\necho -e \"[OT INSTALLER] install complete!\"\r\nexit 0",
+ "container": "node:latest",
+ "entrypoint": "bash"
+ }
+ },
+ "variables": [
+ {
+ "name": "Additional Npm Packages",
+ "description": "Specify additional npm packages used by Open Ticket plugins. Use spaces to separate.",
+ "env_variable": "NODE_PACKAGES",
+ "default_value": "",
+ "user_viewable": false,
+ "user_editable": true,
+ "rules": "string|nullable",
+ "field_type": "text"
+ },
+ {
+ "name": "Startup Flags",
+ "description": "Start the bot with additional Open Ticket flags. Separate using spaces.\r\nA full reference list can be found in the documentation.",
+ "env_variable": "NODE_FLAGS",
+ "default_value": "",
+ "user_viewable": false,
+ "user_editable": true,
+ "rules": "string|nullable",
+ "field_type": "text"
+ },
+ {
+ "name": "Uninstall Npm Packages",
+ "description": "A list of npm packages to uninstall. Separate by spaces.",
+ "env_variable": "UNNODE_PACKAGES",
+ "default_value": "",
+ "user_viewable": false,
+ "user_editable": true,
+ "rules": "string|nullable",
+ "field_type": "text"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 243efae..c6c9fe1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,10 @@ otdebug.txt
*/*/*/.DS_Store
**/.DS_Store
-.docs/*
-!.docs/createDocs.js
-!.docs/mergeTranslations.js
-!.docs/typedoc-config.json
\ No newline at end of file
+.backup/*
+.tools/*
+!.tools/createSponsors.ts
+!.tools/createContributors.ts
+!.tools/mergeTranslations.ts
+!.tools/docker-compose.yml
+!.tools/dockerfile
\ No newline at end of file
diff --git a/.tools/createContributors.ts b/.tools/createContributors.ts
new file mode 100644
index 0000000..dd5985f
--- /dev/null
+++ b/.tools/createContributors.ts
@@ -0,0 +1,130 @@
+///
+import fs from "fs"
+import path from "path"
+import crypto from "crypto"
+
+const contributorData: {contributors:Contributor[],sections:Section[]} = JSON.parse(fs.readFileSync(path.join(process.cwd(),"./.github/CONTRIBUTORS.json")).toString())
+
+//CONSTANTS
+const CORNER_RADIUS = 10
+const SPACE_MULTIPLIER = 1.2
+const SVG_WIDTH = 1000
+
+//TYPES
+interface Contributor {
+ name:string,
+ pictureUrl:string,
+ profileUrl:string,
+ sectionId:string
+}
+interface Section {
+ name:string,
+ id:string,
+ pfpSize:number,
+ pfpColumns:number,
+ withNames:boolean
+}
+
+
+//FUNCTIONS
+async function downloadPfpToBase64URL(url:string){
+ const res = await fetch(url,{method:"GET"})
+ if (!res.ok) return null
+ const buffer = Buffer.from(await res.arrayBuffer())
+ console.log("Downloaded picture URL:",url)
+ return "data:image/png;base64,"+buffer.toString("base64")
+}
+
+function createTitle(yPos:number,name:string){
+ return `${name} `
+}
+
+async function createPfp(yPos:number,xPos:number,size:number,contributor:Contributor,withNames:boolean){
+ const randomId = crypto.randomBytes(8).toString("hex")
+ const nameElement = (withNames) ? `${contributor.name} ` : ""
+
+ return (`
+
+
+
+
+ ${nameElement}
+ `)
+}
+
+async function generateSection(yPos:number,section:Section,contributors:Contributor[]){
+ let sectionHtml: string = ""
+ sectionHtml += createTitle(yPos,section.name)
+ const nameOffset = (section.withNames) ? 20 : 0
+
+ //divide contributors in rows
+ const groupedContributors: Contributor[][] = []
+ let currentGroup: Contributor[] = []
+ for (const contributor of contributors){
+ currentGroup.push(contributor)
+ if (currentGroup.length == section.pfpColumns){
+ groupedContributors.push(currentGroup)
+ currentGroup = []
+ }
+ }
+ if (currentGroup.length > 0) groupedContributors.push(currentGroup)
+
+ let y = 0
+ for (const contributorGroup of groupedContributors){
+ let x = 0
+ for (const contributor of contributorGroup){
+ const pfpYPos = 40 + yPos + (y * ((section.pfpSize * SPACE_MULTIPLIER) + nameOffset))
+ const pfpXPos = 20 + (x * section.pfpSize * SPACE_MULTIPLIER)
+ sectionHtml += await createPfp(pfpYPos,pfpXPos,section.pfpSize,contributor,section.withNames)
+ x++
+ }
+ y++
+ }
+
+ let sectionHeight: number = 40 + (y * ((section.pfpSize * SPACE_MULTIPLIER) + nameOffset))
+ return {sectionHtml,sectionHeight}
+}
+
+async function generateSections(sections:Section[],contributors:Contributor[]){
+ let finalHeight: number = 10
+ let finalHtml: string = ""
+ for (const section of sections){
+ const sectionContributors = contributors.filter((s) => s.sectionId === section.id)
+ if (sectionContributors.length < 1) continue
+ const {sectionHtml,sectionHeight} = await generateSection(finalHeight,section,sectionContributors)
+
+ finalHeight += sectionHeight
+ finalHtml += sectionHtml
+ }
+
+ finalHeight += 10
+ return {finalHeight,finalHtml}
+}
+
+function generateFinalHtml(sectionsHtml:string,sectionHeight:number){
+ return (`
+
+ ${sectionsHtml}
+ `)
+}
+
+//GENERATE CONTRIBUTORS SVG
+async function main(){
+ const {finalHeight,finalHtml} = await generateSections(contributorData.sections,contributorData.contributors)
+ fs.writeFileSync(path.join(process.cwd(),"./.github/CONTRIBUTORS.svg"),generateFinalHtml(finalHtml,finalHeight))
+}
+main()
\ No newline at end of file
diff --git a/.tools/createSponsors.ts b/.tools/createSponsors.ts
new file mode 100644
index 0000000..2ad05dc
--- /dev/null
+++ b/.tools/createSponsors.ts
@@ -0,0 +1,132 @@
+///
+import fs from "fs"
+import path from "path"
+import crypto from "crypto"
+
+const sponsorData: {sponsors:Sponsor[],sections:Section[]} = JSON.parse(fs.readFileSync(path.join(process.cwd(),"./.github/SPONSORS.json")).toString())
+
+//CONSTANTS
+const CORNER_RADIUS = 10
+const SPACE_MULTIPLIER = 1.2
+const SVG_WIDTH = 1000
+
+//TYPES
+interface Sponsor {
+ name:string,
+ pictureUrl:string,
+ profileUrl:string,
+ sectionId:string
+}
+interface Section {
+ name:string,
+ id:string,
+ pfpSize:number,
+ pfpColumns:number,
+ withNames:boolean
+}
+
+
+//FUNCTIONS
+async function downloadPfpToBase64URL(url:string){
+ const res = await fetch(url,{method:"GET"})
+ if (!res.ok) return null
+ const buffer = Buffer.from(await res.arrayBuffer())
+ console.log("Downloaded picture URL:",url)
+ return "data:image/png;base64,"+buffer.toString("base64")
+}
+
+function createTitle(yPos:number,name:string){
+ return ``
+}
+
+async function createPfp(yPos:number,xPos:number,size:number,sponsor:Sponsor,withNames:boolean){
+ const randomId = crypto.randomBytes(8).toString("hex")
+ const nameElement = (withNames) ? `${sponsor.name} ` : ""
+
+ return (``)
+}
+
+async function generateSection(yPos:number,section:Section,sponsors:Sponsor[]){
+ let sectionHtml: string = ""
+ sectionHtml += createTitle(yPos,section.name)
+ const nameOffset = (section.withNames) ? 20 : 0
+
+ //divide sponsors in rows
+ const groupedSponsors: Sponsor[][] = []
+ let currentGroup: Sponsor[] = []
+ for (const sponsor of sponsors){
+ currentGroup.push(sponsor)
+ if (currentGroup.length == section.pfpColumns){
+ groupedSponsors.push(currentGroup)
+ currentGroup = []
+ }
+ }
+ if (currentGroup.length > 0) groupedSponsors.push(currentGroup)
+
+ let y = 0
+ for (const sponsorGroup of groupedSponsors){
+ const xOffset = Math.round((SVG_WIDTH - (sponsorGroup.length * section.pfpSize * SPACE_MULTIPLIER))/2)
+ let x = 0
+ for (const sponsor of sponsorGroup){
+ const pfpYPos = 40 + yPos + (y * ((section.pfpSize * SPACE_MULTIPLIER) + nameOffset))
+ const pfpXPos = xOffset + (x * section.pfpSize * SPACE_MULTIPLIER)
+ sectionHtml += await createPfp(pfpYPos,pfpXPos,section.pfpSize,sponsor,section.withNames)
+ x++
+ }
+ y++
+ }
+
+ let sectionHeight: number = 40 + (y * ((section.pfpSize * SPACE_MULTIPLIER) + nameOffset))
+ return {sectionHtml,sectionHeight}
+}
+
+async function generateSections(sections:Section[],sponsors:Sponsor[]){
+ let finalHeight: number = 10
+ let finalHtml: string = ""
+ for (const section of sections){
+ const sectionSponsors = sponsors.filter((s) => s.sectionId === section.id)
+ if (sectionSponsors.length < 1) continue
+ const {sectionHtml,sectionHeight} = await generateSection(finalHeight,section,sectionSponsors)
+
+ finalHeight += sectionHeight
+ finalHtml += sectionHtml
+ }
+
+ finalHeight += 10
+ return {finalHeight,finalHtml}
+}
+
+function generateFinalHtml(sectionsHtml:string,sectionHeight:number){
+ return (`
+
+
+ ${sectionsHtml}
+ `)
+}
+
+//GENERATE SPONSORS SVG
+async function main(){
+ const {finalHeight,finalHtml} = await generateSections(sponsorData.sections,sponsorData.sponsors)
+ fs.writeFileSync(path.join(process.cwd(),"./.github/SPONSORS.svg"),generateFinalHtml(finalHtml,finalHeight))
+}
+main()
\ No newline at end of file
diff --git a/docker-compose.yml b/.tools/docker-compose.yml
similarity index 100%
rename from docker-compose.yml
rename to .tools/docker-compose.yml
diff --git a/.docs/mergeTranslations.js b/.tools/mergeTranslations.ts
similarity index 99%
rename from .docs/mergeTranslations.js
rename to .tools/mergeTranslations.ts
index d789c9e..5f9db7f 100644
--- a/.docs/mergeTranslations.js
+++ b/.tools/mergeTranslations.ts
@@ -1,6 +1,7 @@
-//@ts-check
-const fjs = require("formatted-json-stringify")
-const fs = require("fs")
+
+import fjs from "formatted-json-stringify"
+import fs from "fs"
+
const formatter = new fjs.ObjectFormatter(null,true,[
new fjs.ObjectFormatter("_TRANSLATION",true,[
new fjs.PropertyFormatter("otversion"),
diff --git a/README.md b/README.md
index 48f8a8f..3f8a22c 100644
--- a/README.md
+++ b/README.md
@@ -4,186 +4,169 @@
Related Projects:
-
+
-
-
+
-Open Ticket is the most advanced and customizable Discord ticket bot available. With 350+ configurable settings , you have full control over every aspect of your ticket system!
-From HTML transcripts and Advanced Plugins to Claiming & Pinning, Questions & Modals, Detailed Statistics, and much more.
-The bot is fully translated into 36+ languages and has been battle-tested in large Discord servers.
-Need help or want to get involved? Feel free to join our Discord server .
+Open Ticket is the most advanced and customizable Discord ticket bot available right now. It features more than 350+ configurable settings to control almost every aspect of your ticket system.
+From HTML transcripts and Advanced Plugins to Claiming & Pinning, Modal Questions & Limits, Detailed Statistics, and much more.
+The bot is fully translated into 38+ languages and has been battle-tested in large Discord servers. Need help or want to get involved? Feel free to join our Discord server .
⭐️ Support Open Ticket’s growth by starring this repo! ⭐️
-❤️ Love Open Ticket? Sponsorships help fuel our HTML transcript servers and future features! ❤️
+❤️ Love Open Ticket? Sponsorships help fuel our HTML transcript servers and future features! ❤️
+
+
---
-> **[-> Navigate to (⏱️ Quick Setup)](#️-quick-start-using-cli)**
-> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
-> **[-> Navigate to (📞 Support Server)](https://discord.dj-dj.be)**
-
-### 📌 Features
-- **⏳ Quick Setup** - Using the interactive Quick Setup CLI, you can **configure Open Ticket in less than 5min!**
-- **🦇 Pterodactyl Support** - Open Ticket works perfect on Pterodactyl based panels. [(Download official eggs)](.eggs/README.md)
-- **💩 No Credits** - Your bot won't contain any form of bloat or credits. It's all yours!
-- **🔒 Private & Secure** - It has been battletested by thousands of servers and **respects security & privacy.**
-- **📈 Scalable** - Made to handle huge servers and has already been **tested in servers with 100k members.**
-- **📄 HTML Transcripts** - The **built-in HTML Transcripts Service** provides beautiful & easy-to-use transcripts.
-- **✅ Ticket Status** - Close, reopen, delete, claim, pin, rename or move tickets in your server.
-- **🇬🇧 Translation** - Every message has been translated in more than **36 languages** by our community.
-- **🎨 Customisation** - More than **200+ settings** are related to customisation & advanced features.
-- **🖥️ Interactions** - The bot has full support for buttons, dropdowns, slash/text commands & modals.
-- **∞ Unlimited Possibilities** - Create an infinite amount of tickets, questions & panels.
-- **📝 Advanced Plugins** - Create advanced plugins or use [**pre-made plugins**](#-plugins) by our community.
-- **👥 Participants** - Add or remove participants & transfer ownership from one user to another.
-- **📊 Detailed Statistics** - With more than **50+ statistics** for tickets, users & the server.
-- **🚫 Blacklist** - Blacklist users to prevent them from creating new tickets.
-- **🚨 Priorities** - Assign different **priority levels** to tickets to mark them as important.
-- **❓ Modal Questions** - Give users the ability to **answer questions** in a modal before their ticket is created.
-- **✨ Commands** - Manage all your tickets with more than 28+ commands.
-- **🤖 Automation** - Automate ticket handling with **autoclose, autodelete** & slow mode.
-- **😎 Additional Features** - For some weird reason, the bot also supports Reaction Role & URL Buttons.
-
-#### And even more using [pre-made community plugins](#-plugins)!
- - **💬 Reviews** - Create & manage a support review system.
- - **📢 Feedback** - Collect feedback & create forms for users to answer.
- - **⏰ Reminders** - Create & manage customisable reminders.
- - **🏷️ Tags** - Create tags & answer questions automatically using keywords.
- - **📝 Forms** - Create advanced forms and automatically ask for repetitive questions.
- - **🔄 Channel Display** - Create a voice channel with realtime statistics from the ticket system.
- - **💾 SQLite Database** - Use an `SQLite` database for increased performance.
- - **🎉 Custom Embeds** - Create your own embeds and send them using a command.
- - **🎨 Customisation** - Yep, you heard it right. Even more customisation!
- - **😁 And so much more...**
-
-### ⏱️ Quick Start (Using Interactive CLI Tool)
-> 1. Download the latest version of Open Ticket on [Github](https://github.com/open-discord-bots/open-ticket).
-> 2. Make sure Node.js & Npm are installed using `node -v` (minimum `v20`).
-> 3. Install any required dependencies using `npm install`.
-> 4. Start the **Quick Setup CLI** using `npm run setup`.
-> 5. Click on `> ⏱️ Quick Setup` and follow the instructions.
-> 6. Start the bot using `npm start` or `node index.js`
-> - If required, the bot will give a report of errors that must be solved.
-> - Follow the instructions and restart the bot.
-> 7. Enjoy using Open Ticket!
->
-> #### 🚦 Navigation
+> **[-> Navigate to (⏱️ Quick Setup)](#️-quick-start)**
> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
> **[-> Navigate to (📞 Support Server)](https://discord.dj-dj.be)**
-> **[-> Navigate to (🧩 Download Plugins)](https://odplugins.dj-dj.be)**
+> **[-> Navigate to (🧩 Plugins/Addons)](https://odplugins.dj-dj.be)**
+> **[-> Navigate to (🦇 Pterodactyl Eggs)](.github/pterodactyl-eggs/README.md)**
+
+### 📌 Features
+#### Core Features
+- **Ticket Management** - Close, reopen, delete, claim or pin tickets with ease.
+- **Powerful Commands** - Manage your support system with **30+ commands** for staff & users.
+- **Modal Questions** - Ask users **custom questions** before a ticket is created.
+- **Priorities** - Assign **priority levels** to tickets to highlight urgent requests.
+- **Participants** - Add or remove participants & transfer ownership from one user to another.
+- **Adjustments** - Rename tickets, change ticket types or transfer ownership.
+- **Blacklist & Limits** - Prevent users from creating tickets and set per-user or global ticket limits.
+- **Highly Customisable** - Configure **350+ settings** covering appearance and behaviour.
+
+#### Ticket Automation & Workflows
+- **Unlimited Possibilities** - Create unlimited tickets, panels & question flows.
+- **Autoclose Tickets** - Automatically **close tickets** after predefined conditions.
+- **Autodelete Tickets** - Automatically **delete closed tickets** to keep channels clean.
+- **Category Routing** - Move tickets between categories based on claim or close state.
+
+#### Transcripts & Insights
+- **HTML Transcripts** - Generate beautiful, easy-to-read **HTML transcripts** for every ticket.
+- **Detailed Statistics** - Track **50+ statistics** for tickets, users and server activity.
+- **Ticket Logs** - Track **all ticket events** such as creation, closures, and staff actions.
+
+#### User Experience
+- **Fully Translated** - Available in **38+ languages**, translated and maintained by the community.
+- **Modern Interactions** - Full support for buttons, dropdowns, slash/text commands & modals.
+- **Panels** - Create messages with buttons or a dropdown for users to open tickets.
+- **Sub-Panels** - One panel not enough? Use multiple panels to offer more choices.
+
+#### Plugins & Ecosystem
+- **Plugin System** - Use custom plugins to **add new features** or **modify existing behavior** of the bot.
+- **Community Plugins** - Use and share plugins built by the community.
+- **Advanced API** - Build advanced plugins with access to ticket events and internal systems.
+- **Integrations** - Connect Open Ticket with external services to automate workflows across platforms.
+- **Bonus Features** - Somehow, we included Reaction Roles and URL Button support as well.
+
+#### Deployment
+- **Quick Setup** - Easy **5-minute configuration** using the Interactive Setup CLI.
+- **Scalable & Reliable** - Battle-tested in servers with **100k+ members**.
+- **Private & Secure** - Used by thousands of servers with respect for security & privacy.
+- **Pterodactyl Support** - 100% compatible with Pterodactyl panels. [(Download official eggs)](.eggs/README.md)
+- **Docker Support** - Deploy Open Ticket in minutes with Docker containers.
+
+#### Extend functionality even more with our [pre-made community plugins](#-plugins)!
+> - **Reviews** - Create and manage a support review system for tickets.
+> - **Tags** - Define keywords that automatically trigger predefined responses.
+> - **Reminders** - Create and manage custom reminders for users or staff.
+> - **AI Integrations** - Connect to AI providers such as ChatGPT, Claude, or Gemini.
+> - **Channel Display** - Create voice channels that display real-time ticket system statistics.
+> - **Forms** - Build advanced forms for collecting structured information from users.
+> - **Custom Embeds** - Create and send custom embeds via commands.
+> - **Customization Tools** - Additional configuration options for advanced behavior and styling.
+> - **Web Dashboard** - Configure and manage the bot through a remote web dashboard.
+> - **Feedback** - Collect user feedback after ticket deletion using forms.
+> - **SQLite Database** - Use an SQLite backend for improved performance and lightweight storage.
+> - **And more** - Additional community plugins are available and actively expanding.
+
+## ⏱️ Quick Start
+> 1. Download the [latest version of Open Ticket](https://github.com/open-discord-bots/open-ticket/releases/latest).
+> 2. Make sure you have installed Node.js on your system (check using `node -v`, minimum `v20`).
+> 3. Install any required dependencies using `npm install`.
+> 4. Configure the bot in one of the following ways:
+> - Method 1 (Easy): Start the **Quick Setup CLI** using `npm run setup`.
+> - Method 2 (Hard): Manual **JSON configuration** in `./config/...`
+> 5. If using the **Quick Setup CLI**, click on `> ⏱️ Quick Setup` and follow the instructions.
+> 6. Start the bot using `npm start` or `node index.js`
+> - If any config errors occur, the bot will give you a report of how to solve them.
+> - Follow the instructions and restart the bot.
+> 7. Enjoy using Open Ticket!
+> 8. Install plugins from the [**Official Plugin Repository**](https://github.com/open-discord-bots/plugins)
+>
+> #### 🚦 Next Steps
+> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
+> **[-> Navigate to (📞 Support Server)](https://discord.dj-dj.be)**
+> **[-> Navigate to (🧩 Plugins/Addons)](https://odplugins.dj-dj.be)**
+> **[-> Navigate to (🦇 Pterodactyl Eggs)](.github/pterodactyl-eggs/README.md)**
>
> #### 🖥️ Recommended Hosting
> - **A VPS (Virtual Private Server)** - Extra customisation & more stability. Recommended for most servers.
> - **Any Pterodactyl-Based Panel** - Easy installation & configuration.
-### ❤️ Sponsors
-Huge thanks to our sponsors for making this project possible. Your support means everything to us.
-
-
-**Past Sponsors:**
-
-
-
-
-
-
-
## 📸 Preview
-## 🛠️ Contributors
-### 🖥️ Team & Contributors
-A list of amazing people who have contributed or provided supported for **Open Ticket** and **Open Discord**.
-
+## 💬 Translations
+With the amazing support of our translators, we've been able to translate Open Ticket in more than **38 languages**!
+#### Categories: 🟢 Available - 🤖 Partially Made Using AI - 🟠 Incomplete - 🔴 Unavailable/Outdated
-### 💬 Translators
-With the amazing support of our translators, we've been able to translate Open Ticket in more than **36 languages**!
-#### Categories:
-- **🟢 Available**
-- **🤖 Partially Made Using AI**
-- **🟠 Incomplete**
-- **🔴 Unavailable/Outdated**
-
-|🔍 |Languages (36) |Maintainer (Github/Discord) |
-|----|---------------------|--------------------------------|
-|🟢 |🇬🇧 English |djj123dj |
-|🟢 |🇳🇱 Dutch |djj123dj |
-|🟢 |🇩🇪 German |benzorich |
-|🟢 |🇫🇷 French |guillee.3 |
-|🟢 |🇪🇸 Spanish |redactado & josuens |
-|🟢 |🇵🇹 Portuguese |quiradon |
-|🟢 |🇮🇹 Italian |fraden1mvp. & imperatorix_17 |
-|🟢 |🇸🇪 Swedish |NoOneNook |
-|🟢 |🇳🇴 Norwegian |NoOneNook |
-|🟢 |🇹🇭 Thai |modshd |
-|🟢 |🇮🇳 Hindi |challenger_nova |
-|🟢 |🇭🇺 Hungarian |kornel0706 |
-|🟢 |🇮🇩 Indonesian |erxg |
-|🟢 |🇱🇹 Lithuanian |tsgindrius |
-|🟢 |🇺🇦 Ukrainian |anderskiy |
-|🟢 |🇨🇿 Czech |spyeye_ |
-|🟢 |🇷🇴 Romanian |sankedev |
-|🟢 |🇩🇰 Danish |the_gamer |
-|🟢 |🇹🇷 Turkish |palestinian |
-|🟢 |🇦🇪 Arabic |palestinian |
-|🟢 |🇵🇱 Polish |danoglez |
-|🟢 |🇮🇷 Persian |dysashop & zhavis |
-|🟢 |🇧🇩 Bengali |HanumeshGupta |
-|🟢 |❓ Catalan |guillee3 |
-|🤖 |🇪🇪 Estonian |iamnotmega |
-|🤖 |🇫🇮 Finnish |iamnotmega |
-|🤖 |🇯🇵 Japanese |HanumeshGupta |
-|🤖 |🇬🇷 Greek |HanumeshGupta |
-|🤖 |🇸🇮 Slovenian |HanumeshGupta |
-|🤖 |🇰🇷 Korean |HanumeshGupta |
-|🤖 |🇮🇳 Tamil |HanumeshGupta |
-|🤖 |🇨🇳 Simplified Chinese |HanumeshGupta |
-|🤖 |❓ Kurdish |HanumeshGupta |
-|🤖 |🇷🇺 Russian |NoOneNook |
-|🤖 |🇱🇻 Latvian |NoOneNook |
-|🤖 |🇻🇳 Vietnamese |ngocdiep2006 |
-|🔴 |🇨🇳 Traditional Chinese|[⭐ Contribute!](.github/CONTRIBUTING.md)|
+|🔍 |Languages (38) |Config Value |Maintainers (Github/Discord) |
+|----|----------------------|------------------------|--------------------------------|
+|🟢 |🇬🇧 English |`"english"` |djj123dj |
+|🟢 |🇳🇱 Dutch |`"dutch"` |djj123dj |
+|🟢 |🇩🇪 German |`"german"` |benzorich |
+|🟢 |🇫🇷 French |`"french"` |guillee.3 |
+|🟢 |🇪🇸 Spanish |`"spanish"` |Reddishye & josuens |
+|🟢 |🇵🇹 Portuguese |`"portuguese"` |quiradon |
+|🟢 |🇮🇹 Italian |`"italian"` |fraden1mvp. & imperatorix_17 |
+|🟢 |🇸🇪 Swedish |`"swedish"` |NoOneNook |
+|🟢 |🇳🇴 Norwegian |`"norwegian"` |NoOneNook |
+|🟢 |🇹🇭 Thai |`"thai"` |modshd |
+|🟢 |🇮🇳 Hindi |`"hindi"` |challenger_nova |
+|🟢 |🇭🇺 Hungarian |`"hungarian"` |kornel0706 |
+|🟢 |🇮🇩 Indonesian |`"indonesian"` |erxg |
+|🟢 |🇱🇹 Lithuanian |`"lithuanian"` |tsgindrius |
+|🟢 |🇺🇦 Ukrainian |`"ukrainian"` |anderskiy |
+|🟢 |🇨🇿 Czech |`"czech"` |spyeye_ |
+|🟢 |🇷🇴 Romanian |`"romanian"` |sankedev |
+|🟢 |🇩🇰 Danish |`"danish"` |the_gamer |
+|🟢 |🇹🇷 Turkish |`"turkish"` |palestinian |
+|🟢 |🇦🇪 Arabic |`"arabic"` |palestinian |
+|🟢 |🇵🇱 Polish |`"polish"` |danoglez |
+|🟢 |🇮🇷 Persian |`"persian"` |dysashop & zhavis |
+|🟢 |🇧🇩 Bengali |`"bengali"` |HanumeshGupta |
+|🟢 |❓ Catalan |`"catalan"` |guillee3 |
+|🟢 |🇨🇳 Traditional Chinese|`"traditional-chinese"` |me.october |
+|🟢 |🇰🇭 Khmer (Cambodia) |`"khmer"` |yuuslokrobjakkroval |
+|🤖 |🇪🇪 Estonian |`"estonian"` |iamnotmega |
+|🤖 |🇫🇮 Finnish |`"finnish"` |iamnotmega |
+|🤖 |🇯🇵 Japanese |`"japanese"` |HanumeshGupta |
+|🤖 |🇬🇷 Greek |`"greek"` |HanumeshGupta |
+|🤖 |🇸🇮 Slovenian |`"slovenian"` |HanumeshGupta |
+|🤖 |🇰🇷 Korean |`"korean"` |HanumeshGupta |
+|🤖 |🇮🇳 Tamil |`"tamil"` |HanumeshGupta |
+|🤖 |❓ Kurdish |`"kurdish"` |HanumeshGupta |
+|🤖 |🇷🇺 Russian |`"russian"` |NoOneNook |
+|🤖 |🇱🇻 Latvian |`"latvian"` |NoOneNook |
+|🤖 |🇻🇳 Vietnamese |`"vietnamese"` |ngocdiep2006 |
+|🤖 |🇨🇳 Simplified Chinese |`"simplified-chinese"` |HanumeshGupta |
+## 😎 Hall Of Fame
+
+
## ⭐️ Star History
-If you enjoy using Open ticket, **consider starring** this repository.
+If you enjoy using Open ticket, **consider starring** our repository.
This will help us grow and reach even more people!
@@ -194,66 +177,6 @@ This will help us grow and reach even more people!
-## 🧩 Plugins
-**Download all plugins from our [Official Plugin Repository](https://github.com/open-discord-bots/plugins)!**
-> #### ⭐ Featured Plugins (Top 5 Most Used)
-> **[`ot-sqlite-database`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-sqlite-database/),
-> [`ot-reviews`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-reviews/),
-> [`ot-feedback`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-feedback/),
-> [`ot-tags`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-tags/),
-> [`ot-restrictions`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-restrictions/)**
-
-#### Categories:
-- **📄 Example** - These plugins serve as an example or starting template.
-- **📢 Command** - These plugins add new commands to the bot.
-- **⚙️ Utility** - These plugins help with utility systems. You might not notice them as a ticket user/admin directly.
-- **🎨 Customisation** - These plugins add even more customisation to the bot.
-- **💼 Management** - These plugins add features that help you manage your server or ticket system.
-- **🤖 Client** - These plugins add features affecting the Discord Client or bot itself.
-- Please Create a new category when your plugin doesn't fit in one of the available categories.
-
-### 📦 Official *(made by DJdj Development)*
-|Name |Category |Description |
-|----------------------------------------------------------------------|----------------------------|-------------------------|
-|[`example-plugin`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/example-plugin/) |📄 Example |This is just an example plugin for people that want to create their own plugin. |
-|[`example-command`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/example-command/) |📄 Example |Sample custom command using the Open Discord system. |
-|[`ot-jump-to-top`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-jump-to-top/) |📢 Command |Add a simple command to jump to the top of the ticket. |
-|[`ot-kill-switch`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-kill-switch/) |📢 Command |Temporarily disable the ticket system using a kill switch. |
-|[`ot-hosting-status`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-hosting-status/) |📢 Command |A simple command to send hosting status updates to a channel. |
-|[`ot-shutdown`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-shutdown/) |📢 Command |A simple command to turn off the bot from a slash command (server & bot owner only). |
-|[`ot-sqlite-database`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-sqlite-database/) |⚙️ Utility |With this plugin, the database will be an SQLite file. It's a must-have for large servers! |
-|[`ot-no-slash-clear`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-no-slash-clear/) |⚙️ Utility |Disable the automatic removal of slash commands that aren't used by Open Ticket. |
-|[`ot-migrate-v3`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-migrate-v3/) |⚙️ Utility |Use this plugin to migrate all tickets from Open Ticket v3 to v4. |
-|[`ot-ticket-message-extras`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-ticket-message-extras/) |🎨 Customisation |A plugin which adds a few little features to the ticket message. |
-|[`ot-rename-keep-prefix`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-rename-keep-prefix/) |🎨 Customisation |Simple plugin to keep the channel prefix when using the /rename command. |
-|[`ot-customise-buttons`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-customise-buttons/) |🎨 Customisation |Customise almost all built-in buttons. This includes the claim, reopen, close & delete buttons. |
-|[`ot-ephemeral-messages`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-ephemeral-messages/) |🎨 Customisation |Customise for every messages if it needs to be ephemeral or not. |
-|[`ot-footers`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-footers/) |🎨 Customisation |A simple plugin to add footers in all Open Ticket embeds. |
-|[`ot-alt-detector`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-alt-detector/) |💼 Management |Use the discord-alt-detector npm package by DJdj Development in your ticket bot. |
-|[`ot-embeds`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-embeds/) |💼 Management |Create custom premade embeds in the config or use the command to create one from scratch. |
-|[`ot-move-actions`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-move-actions/) |💼 Management |Automatically unclaim/unpin a ticket when it's moved using `/move`. |
-|[`ot-reviews`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-reviews/) |💼 Management |Review system for Open Ticket! It is very customisable and has lots of features. |
-|[`ot-tags`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-tags/) |💼 Management |Use tags to quickly reply with a pre-existing text. |
-|[`ot-restrictions`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-restrictions/) |💼 Management |Restrict which roles can open a specific ticket option. |
-|[`ot-better-status`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-better-status/) |🤖 Client |An advanced status plugin to rotate between states. It also allows for the use of variables. |
-|[`ot-channel-display`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-channel-display/) |🤖 Client |A plugin to show different variables in a voice channel in your server. |
-|[`ot-vanity`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-vanity/) |🤖 Client |A plugin to detect the vanity status of members in the server and give them exclusive privilleges. |
-
-### ✅ Verified *(made by community)*
-|Name |Author |Category |Description |
-|---------------------------------------------------------------------|----------------------------|----------------------------|-------------------------|
-|[`ot-config-reload`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-config-reload/) |guillee.3 |⚙️ Utility |This plugin adds a new command that allows reloading the Open Ticket config files without the need for a restart. |
-|[`ot-feedback`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-feedback/) |an_developer |💼 Management |A plugin to gather feedback of your support service. |
-|[`ot-assign-role`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-assign-role/) |rapid.fast |💼 Management |This plugin assigns a predefined role to a user upon creating a ticket. |
-|[`ot-moderation`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-moderation/) |NotMukundOP |💼 Management |A simple moderation plugin for Open Discord with ban, kick & warnings. |
-|[`ot-template-system`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-template-system/) |DanoGlez |💼 Management |Predefined template system for sending quick messages. |
-|[`ot-volume-warning`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-volume-warning/) |guillee.3 |💼 Management |Alerts ticket creators when too many tickets are open, indicating possible response delays. |
-|[`ot-reminders`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-reminders/) |guillee.3 |💼 Management |Set reminders that will be sent to a channel every specified time. |
-|[`ot-ticket-forms`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-ticket-forms/) |guillee.3 |💼 Management |An advanced forms plugin for Open Ticket. |
-|[`ot-followups`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-followups/) |guillee.3 |💼 Management |Send additional follow-up messages to a ticket. |
-|[`ot-twitch-notifier`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-twitch-notifier/) |guillee.3 |💼 Management |Get notified when your favorite Twitch streamers go live. |
-|[`ot-translate-cmds`](https://github.com/open-discord-bots/plugins/tree/main/open-ticket/ot-translate-cmds/) |guillee.3 |🤖 Client |Translate all built-in command names, descriptions & options. |
-
---
diff --git a/config/general.json b/config/general.json
deleted file mode 100644
index cd43647..0000000
--- a/config/general.json
+++ /dev/null
@@ -1,125 +0,0 @@
-{
- "_INFO":{
- "support":"https://otdocs.dj-dj.be",
- "discord":"https://discord.dj-dj.be",
- "version":"open-ticket-v4.1.3"
- },
-
- "token":"insert your bot token here! (or leave empty when using 'tokenFromENV')",
- "tokenFromENV":false,
-
- "mainColor":"#f8ba00",
- "language":"english",
- "prefix":"!ticket ",
- "serverId":"discord server id",
- "globalAdmins":["discord role id"],
-
- "slashCommands":true,
- "textCommands":true,
-
- "status":{
- "enabled":true,
- "type":"listening OR watching OR playing OR custom",
- "mode":"online OR invisible OR idle OR dnd",
- "text":"/help",
- "state":"(additional text or leave empty)"
- },
-
- "system":{
- "preferSlashOverText":true,
- "sendErrorOnUnknownCommand":true,
- "questionFieldsInCodeBlock":true,
- "displayFieldsWithQuestions":false,
- "showGlobalAdminsInPanelRoles":false,
- "disableVerifyBars":false,
- "useRedErrorEmbeds":true,
- "alwaysShowReason":false,
- "emojiStyle":"before (OR after OR double OR disabled)",
- "pinEmoji":"📌",
-
- "replyOnTicketCreation":true,
- "replyOnReactionRole":true,
- "askPriorityOnTicketCreation":false,
- "removeParticipantsOnClose":false,
- "disableAutocloseAfterReopen":true,
- "autodeleteRequiresClosedTicket":true,
- "adminOnlyDeleteWithoutTranscript":true,
- "allowCloseBeforeMessage":false,
- "allowCloseBeforeAdminMessage":true,
- "useTranslatedConfigChecker":true,
- "pinFirstTicketMessage":false,
-
- "enableTicketClaimButtons":true,
- "enableTicketCloseButtons":true,
- "enableTicketPinButtons":true,
- "enableTicketDeleteButtons":true,
- "enableTicketActionWithReason":true,
- "enableDeleteWithoutTranscript":true,
-
- "logs":{
- "enabled":false,
- "channel":"discord channel id"
- },
-
- "limits":{
- "enabled":true,
- "globalMaximum":50,
- "userMaximum":3
- },
-
- "channelTopic":{
- "showOptionName":true,
- "showOptionDescription":false,
- "showOptionTopic":true,
- "showPriority":false,
- "showClosed":true,
- "showClaimed":false,
- "showPinned":false,
- "showCreator":false,
- "showParticipants":false
- },
-
- "permissions":{
- "help":"everyone (OR admin OR none OR role id)",
- "panel":"admin (OR everyone OR none OR role id)",
- "ticket":"none (OR admin OR everyone OR role id)",
- "close":"everyone (OR admin OR none OR role id)",
- "delete":"admin (OR everyone OR none OR role id)",
- "reopen":"everyone (OR admin OR none OR role id)",
- "claim":"admin (OR everyone OR none OR role id)",
- "unclaim":"admin (OR everyone OR none OR role id)",
- "pin":"admin (OR everyone OR none OR role id)",
- "unpin":"admin (OR everyone OR none OR role id)",
- "move":"admin (OR everyone OR none OR role id)",
- "rename":"admin (OR everyone OR none OR role id)",
- "add":"admin (OR everyone OR none OR role id)",
- "remove":"admin (OR everyone OR none OR role id)",
- "blacklist":"admin (OR everyone OR none OR role id)",
- "stats":"everyone (OR admin OR none OR role id)",
- "clear":"admin (OR everyone OR none OR role id)",
- "autoclose":"admin (OR everyone OR none OR role id)",
- "autodelete":"admin (OR everyone OR none OR role id)",
- "transfer":"admin (OR everyone OR none OR role id)",
- "topic":"admin (OR everyone OR none OR role id)",
- "priority":"admin (OR everyone OR none OR role id)"
- },
-
- "messages":{
- "creation":{"dm":false,"logs":true},
- "closing":{"dm":false,"logs":true},
- "deleting":{"dm":false,"logs":true},
- "reopening":{"dm":false,"logs":true},
- "claiming":{"dm":false,"logs":true},
- "pinning":{"dm":false,"logs":true},
- "adding":{"dm":false,"logs":true},
- "removing":{"dm":false,"logs":true},
- "renaming":{"dm":false,"logs":true},
- "moving":{"dm":false,"logs":true},
- "blacklisting":{"dm":false,"logs":true},
- "transferring":{"dm":false,"logs":true},
- "topicChange":{"dm":false,"logs":true},
- "priorityChange":{"dm":false,"logs":true},
- "reactionRole":{"dm":false,"logs":true}
- }
- }
-}
\ No newline at end of file
diff --git a/config/general.jsonc b/config/general.jsonc
new file mode 100644
index 0000000..a5830b9
--- /dev/null
+++ b/config/general.jsonc
@@ -0,0 +1,175 @@
+/*
+ * Hi there! Thank you for installing Open Ticket.
+ * ----------------------------------------------
+ * If you need any assistance with configuring the bot,
+ * feel free to use the documentation or join our Discord server:
+ * https://otdocs.dj-dj.be
+ * https://discord.dj-dj.be
+ * ----------------------------------------------
+ * SETUP:
+ * 1. Install the required dependencies using the command: "npm install"
+ * 2. Configure the bot in one of the following ways:
+ * a. (easy) Using the Quick Setup CLI Tool
+ * b. (difficult) Using the JSON files in `./config/`
+ *
+ * Start the Quick Setup CLI Tool using the command: "npm run setup"
+ * After configuration, start the bot using the command: "npm start"
+ *
+ * Good luck! DJj123dj & contributors
+ */
+{
+ "_CONFIG_VERSION":"open-ticket-v4.2.0",
+
+ /* Load the bot token from .env or the "token" field below. Leave "token" empty if using "tokenFromENV". */
+ "token":"INSERT_BOT_TOKEN",
+ "tokenFromENV":false,
+
+ "mainColor":"#f8ba00", //Hex color used in most embeds
+ "language":"english", //Visit README.md for list
+ "prefix":"!ticket ", //Prefix used in text commands
+ "serverId":"DISCORD_SERVER_ID",
+ "globalAdmins":["DISCORD_ROLE_ID"], //Have access to all commands
+
+ /* Enable/disable text or slash commands. */
+ "slashCommands":true,
+ "textCommands":true,
+
+ /* Configure the status of the bot. */
+ "status":{
+ "enabled":true,
+ "type":"listening", //Choices: listening, watching, playing, custom
+ "mode":"online", //Choices: online, invisible, idle, dnd
+ "text":"/help",
+ "state":"" //Additional text (Leave empty to disable)
+ },
+
+ /* Send ticket logs to a channel or in DM of the ticket creator. */
+ "logs":{
+ "enabled":false,
+ "channel":"DISCORD_CHANNEL_ID",
+ "logMessages":{
+ "creation":{"dm":false,"logs":true},
+ "closing":{"dm":false,"logs":true},
+ "deleting":{"dm":false,"logs":true},
+ "reopening":{"dm":false,"logs":true},
+ "claiming":{"dm":false,"logs":true},
+ "pinning":{"dm":false,"logs":true},
+ "adding":{"dm":false,"logs":true},
+ "removing":{"dm":false,"logs":true},
+ "renaming":{"dm":false,"logs":true},
+ "moving":{"dm":false,"logs":true},
+ "blacklisting":{"dm":false,"logs":true},
+ "transferring":{"dm":false,"logs":true},
+ "topicChange":{"dm":false,"logs":true},
+ "priorityChange":{"dm":false,"logs":true},
+ "reactionRole":{"dm":false,"logs":true}
+ }
+ },
+
+ /* A large collection of settings for the ticket system. */
+ "ticketSystem":{
+ "preferSlashOverText":true, //Show slashcmds in help menu's
+ "sendErrorOnUnknownCommand":true, //Send error when command not found
+ "questionFieldsInCodeBlock":true, //Put question answers in code blocks
+ "displayFieldsWithQuestions":false, //Display embed fields together with question answers
+ "showGlobalAdminsInPanelRoles":false, //Include "globalAdmins" in panel admin lists
+ "disableVerifyBars":false, //Disable the (❌/✅) buttons
+ "useRedErrorEmbeds":true, //Make errors embeds always red
+ "alwaysShowReason":false, //Show reason even if none is provided
+ "emojiStyle":"before", //The style of emoji's in embeds. Choices: before, after, double, disabled
+ "pinEmoji":"📌", //Channel emoji of pinned tickets (Leave empty to disable)
+ "closeEmoji":"", //Channel emoji of closed tickets (Leave empty to disable)
+
+ "replyOnTicketCreation":true, //Reply with a msg when a ticket is created
+ "replyOnReactionRole":true, //Reply with a msg when a reaction role is used
+ "askPriorityOnTicketCreation":true, //Show a dropdown to select priority
+ "removeParticipantsOnClose":false, //Remove non-admins when ticket is closed
+ "disableAutocloseAfterReopen":true, //Disable autoclose after ticket got reopened
+ "autodeleteRequiresClosedTicket":true, //A ticket must be closed before autodelete works
+ "adminOnlyDeleteWithoutTranscript":true, //Only allow "globalAdmins" to delete a ticket without transcript
+ "allowCloseBeforeMessage":false, //Allow closing before a message is sent
+ "allowCloseBeforeAdminMessage":true, //Allow closing before an admin has sent a message
+ "useTranslatedConfigChecker":true, //Translate config errors in the console
+ "pinFirstTicketMessage":true, //Pin the ticket message to the channel
+
+ /* Enable/disable certain buttons & features of the bot. */
+ "enableTicketClaimButtons":true,
+ "enableTicketCloseButtons":true,
+ "enableTicketPinButtons":true,
+ "enableTicketDeleteButtons":true,
+ "enableTicketActionWithReason":true,
+ "enableDeleteWithoutTranscript":true, //Allow deleting tickets without transcript
+ "enableCreateTicketForOtherUser":true, //Allow creating tickets for other users
+
+ /* Set the maximum amount of simultaneous tickets. */
+ "limits":{
+ "enabled":true,
+ "globalMaximum":50,
+ "userMaximum":3
+ },
+
+ /* Choose which data is shown in the channel topic. */
+ "channelTopic":{
+ "showOptionName":true,
+ "showOptionDescription":false,
+ "showOptionTopic":true,
+ "showPriority":false,
+ "showClosed":true,
+ "showClaimed":false,
+ "showPinned":false,
+ "showCreator":false,
+ "showParticipants":false
+ },
+
+ /* Move closed tickets to a separate category. */
+ "closedCategory":{
+ "enabled":false,
+ "categoryId":"DISCORD_CATEGORY_ID"
+ },
+
+ /* Create tickets in a backup category when the original category exceeds 50 channels. */
+ "backupCategory":{
+ "enabled":false,
+ "categoryId":"DISCORD_CATEGORY_ID"
+ },
+
+ /* Move claimed tickets to a matching category of the user that claimed the ticket. Set to empty list [] to disable. */
+ "claimedCategories":[
+ {"user":"DISCORD_USER_ID","category":"DISCORD_CATEGORY_ID"}
+ ]
+ },
+
+ /*
+ * Set permissions for each individual command, button or action.
+ * CHOICES:
+ * >> "none" -> Command disabled
+ * >> "everyone" -> Allowed for everyone
+ * >> "admin" -> Global & ticket admins only
+ * >> "DISCORD_ROLE_ID" -> Custom role only
+ */
+ "permissions":{
+ "help":"everyone",
+ "panel":"admin",
+ "ticket":"none",
+ "close":"everyone",
+ "delete":"admin",
+ "reopen":"everyone",
+ "claim":"admin",
+ "unclaim":"admin",
+ "pin":"admin",
+ "unpin":"admin",
+ "move":"admin",
+ "rename":"admin",
+ "add":"admin",
+ "remove":"admin",
+ "blacklist":"admin",
+ "stats":"everyone",
+ "clear":"admin",
+ "autoclose":"admin",
+ "autodelete":"admin",
+ "transfer":"admin",
+ "topic":"admin",
+ "priority":"admin",
+ "transcripts":"admin"
+ }
+}
\ No newline at end of file
diff --git a/config/options.json b/config/options.json
deleted file mode 100644
index 981a1bc..0000000
--- a/config/options.json
+++ /dev/null
@@ -1,126 +0,0 @@
-[
- {
- "id":"example-ticket",
- "name":"Question",
- "description":"Create this ticket if you have a question! (or leave empty)",
- "type":"ticket",
-
- "button":{
- "emoji":"🎫 (or leave empty)",
- "label":"question (or leave empty)",
- "color":"gray OR red OR green OR blue"
- },
-
- "ticketAdmins":["discord role id"],
- "readonlyAdmins":["discord role id"],
- "allowCreationByBlacklistedUsers":false,
- "questions":["example-question-1","example-question-2"],
-
- "channel":{
- "prefix":"question-",
- "suffix":"user-name OR user-id OR random-number OR random-hex OR counter-dynamic OR counter-fixed",
- "category":"category id (or leave empty)",
- "closedCategory":"category id (or leave empty)",
- "backupCategory":"category id (or leave empty)",
- "claimedCategory":[
- {"user":"user id","category":"category id"}
- ],
- "topic":"This is the topic of this ticket channel and is visible to everyone! (or leave empty)"
- },
-
- "dmMessage":{
- "enabled":false,
- "text":"Thank you for creating a ticket in our server! (or leave empty)",
- "embed":{
- "enabled":false,
- "title":"Embed Title! (or leave empty)",
- "description":"Description (or leave empty)",
- "customColor":"#f8ab00 (or leave empty)",
-
- "image":"https://www.example.com/image.png (or leave empty)",
- "thumbnail":"https://www.example.com/image.png (or leave empty)",
- "fields":[
- {"name":"field name","value":"field value","inline":false}
- ],
- "timestamp":false
- }
- },
- "ticketMessage":{
- "enabled":true,
- "text":"",
- "embed":{
- "enabled":true,
- "title":"Question Ticket",
- "description":"Thank you for creating a 'Question' ticket in our server!\nOur support team will help you as soon as possible!",
- "customColor":"#f8ab00 (or leave empty)",
-
- "image":"https://www.example.com/image.png (or leave empty)",
- "thumbnail":"https://www.example.com/image.png (or leave empty)",
- "fields":[
- {"name":"field name","value":"field value","inline":false}
- ],
- "timestamp":false
- },
- "ping":{
- "@here":true,
- "@everyone":false,
- "custom":["discord role id"]
- }
- },
- "autoclose":{
- "enableInactiveHours":false,
- "inactiveHours":24,
- "enableUserLeave":false,
- "disableOnClaim":false
- },
- "autodelete":{
- "enableInactiveDays":false,
- "inactiveDays":7,
- "enableUserLeave":false,
- "disableOnClaim":false
- },
- "cooldown":{
- "enabled":false,
- "cooldownMinutes":10
- },
- "limits":{
- "enabled":false,
- "globalMaximum":20,
- "userMaximum":3
- },
- "slowMode":{
- "enabled":false,
- "slowModeSeconds":20
- }
- },
- {
- "id":"example-website",
- "name":"Website",
- "description":"Go to our website.",
- "type":"website",
-
- "button":{
- "emoji":"😃",
- "label":"Visit our website"
- },
-
- "url":"https://www.dj-dj.be"
- },
- {
- "id":"example-role",
- "name":"Update Ping",
- "description":"Click here to get notified on updates!",
- "type":"role",
-
- "button":{
- "emoji":"📢",
- "label":"Update Ping",
- "color":"gray OR red OR green OR blue"
- },
-
- "roles":["discord role id"],
- "mode":"add&remove OR remove OR add",
- "removeRolesOnAdd":["discord role id"],
- "addOnMemberJoin":false
- }
-]
\ No newline at end of file
diff --git a/config/options.jsonc b/config/options.jsonc
new file mode 100644
index 0000000..1948f6e
--- /dev/null
+++ b/config/options.jsonc
@@ -0,0 +1,165 @@
+/*
+ * OPEN TICKET BUTTON OPTIONS
+ * ----------------------------------------------
+ * Create customizable ticket, website, reaction-role or sub-panel button options.
+ * Up to 25 options can be added to each panel in (config/panels.jsonc)
+ * There are 4 types of options available: ticket, website, role, sub-panel
+ *
+ * TIP: Create new options by copying everything between and including the {...} brackets of an option. Paste it after the last option and make sure that they are seperated by a comma.
+ */
+[
+ {
+ /* A ticket option creates a button to open a ticket. */
+ "id":"example-ticket",
+ "name":"Question",
+ "description":"Want to tell us something? Create this ticket for general questions for our support team.", //Leave empty to disable
+ "type":"ticket",
+
+ "button":{
+ /* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
+ "emoji":"🎫",
+ "label":"Question",
+ "color":"gray" //Choices: gray, red, green, blue
+ },
+
+ /* Add up to 5 modal questions IDs from (config/questions.jsonc). */
+ "questions":["example-question-1","example-question-2"],
+
+ "ticketAdmins":["DISCORD_ROLE_ID"],
+ "readonlyAdmins":["DISCORD_ROLE_ID"],
+ "allowCreationByBlacklistedUsers":false,
+
+ "channel":{
+ /* Configure the name, topic and category of the ticket option. */
+ "prefix":"question-",
+ "suffix":"user-name", //Choices: user-name, user-id, random-number, random-hex, counter-dynamic, counter-fixed
+ "category":"DISCORD_CATEGORY_ID", //Leave empty to disable
+ "topic":"The ticket topic shown in the channel." //Leave empty to disable
+ },
+
+ "dmMessage":{
+ /* Send a customisable message in DM when creating a ticket. */
+ "enabled":false,
+ "text":"", //Leave empty to disable
+ "embed":{
+ "enabled":false,
+ "title":"Question Ticket", //Leave empty to disable
+ "description":"Thank you for creating a ticket in our server. We will try to help you as soon as possible.", //Leave empty to disable
+ "customColor":"#f8ab00", //Leave empty to use default color
+
+ "image":"", //Image URL. Leave empty to disable
+ "thumbnail":"", //Image URL. Leave empty to disable
+ /* Embed fields. Set to empty list [] to disable. */
+ "fields":[
+ {"name":"Field name","value":"Field value","inline":false}
+ ],
+ "timestamp":false
+ }
+ },
+ "ticketMessage":{
+ /* Send a customisable message in the ticket with close, claim, delete, ... buttons. */
+ "enabled":true,
+ "text":"", //Leave empty to disable
+ "embed":{
+ "enabled":true,
+ "title":"Question Ticket", //Leave empty to disable
+ "description":"Thank you for creating a ticket in our server.\nOur support team will assist you as soon as possible. (leave empty to disable)", //Leave empty to disable
+ "customColor":"#f8ab00 (leave empty to disable)", //Leave empty to use default color
+
+ "image":"https://www.example.com/image.png (leave empty to disable)", //Image URL. Leave empty to disable
+ "thumbnail":"https://www.example.com/image.png (leave empty to disable)", //Image URL. Leave empty to disable
+ /* Embed fields. Set to empty list [] to disable. */
+ "fields":[
+ {"name":"Field name","value":"Field value","inline":false}
+ ],
+ "timestamp":false
+ },
+ "ping":{
+ /* Customise the user & role mentions of this ticket message. */
+ "@here":true,
+ "@everyone":false,
+ "custom":["DISCORD_ROLE_ID"]
+ }
+ },
+ "autoclose":{
+ /* Autoclose this ticket after a period of inactivity or when the creator leaves the server. */
+ "enableInactiveHours":false,
+ "inactiveHours":24,
+ "enableUserLeave":false,
+ "disableOnClaim":false
+ },
+ "autodelete":{
+ /* Autodelete this ticket after a period of inactivity or when the creator leaves the server. */
+ "enableInactiveDays":false,
+ "inactiveDays":7,
+ "enableUserLeave":false,
+ "disableOnClaim":false
+ },
+ "cooldown":{
+ /* Users must wait a certain period before being able to create another ticket of this type. */
+ "enabled":false,
+ "cooldownMinutes":10
+ },
+ "limits":{
+ /* Set the maximum amount of simultaneous tickets of this option. */
+ "enabled":false,
+ "globalMaximum":20,
+ "userMaximum":3
+ },
+ "slowMode":{
+ /* Enable slow-mode in the ticket channel. */
+ "enabled":false,
+ "slowModeSeconds":20
+ }
+ },
+ {
+ /* A website option creates a button with a URL to an external website. */
+ "id":"example-website",
+ "name":"Website",
+ "description":"Take a look at our amazing website.", //Leave empty to disable
+ "type":"website",
+
+ "button":{
+ /* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
+ "emoji":"😃",
+ "label":"Visit Website"
+ },
+
+ "url":"https://www.dj-dj.be"
+ },
+ {
+ /* A reaction-role option creates a button for members to choose roles. */
+ "id":"example-role",
+ "name":"Update Ping",
+ "description":"Receive notifications about updates in our server.", //Leave empty to disable
+ "type":"role",
+
+ "button":{
+ /* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
+ "emoji":"📢",
+ "label":"Update Ping",
+ "color":"gray" //Choices: gray, red, green, blue
+ },
+
+ "roles":["DISCORD_ROLE_ID"],
+ "mode":"add&remove OR remove OR add", //What to do with the roles. Choices: add&remove, add, remove
+ "removeRolesOnAdd":["DISCORD_ROLE_ID"], //Remove these old roles when new roles are added.
+ "addOnMemberJoin":false //Add these roles automatically when joining the server.
+ },
+ {
+ /* A sub-panel option creates a button which sends another panel for additional options. */
+ "id":"example-sub-panel",
+ "name":"Example Sub-Panel",
+ "description":"This is an example of how to implement a sub-panel in Open Ticket.", //Leave empty to disable
+ "type":"sub-panel",
+
+ "button":{
+ /* Configure the button style of this option. At least one of "emoji" or "label" must be provided. */
+ "emoji":"📋",
+ "label":"Sub-Panel Example",
+ "color":"gray" //Choices: gray, red, green, blue
+ },
+
+ "subPanelId":"example-panel" //Choose a panel ID from (config/panels.jsonc)
+ }
+]
\ No newline at end of file
diff --git a/config/panels.json b/config/panels.json
deleted file mode 100644
index acc1093..0000000
--- a/config/panels.json
+++ /dev/null
@@ -1,39 +0,0 @@
-[
- {
- "id":"example-embed",
- "name":"Example Embed",
- "dropdown":false,
- "options":["example-ticket","example-website","example-role"],
-
- "text":"",
- "embed":{
- "enabled":true,
- "title":"Tickets:",
- "description":"Create a ticket by clicking one of the buttons below!",
-
- "customColor":"#f8ab00 (or leave empty)",
- "url":"https://openticket.dj-dj.be (or leave empty)",
-
- "image":"https://www.example.com/image.png (or leave empty)",
- "thumbnail":"https://www.example.com/image.png (or leave empty)",
-
- "footer":"Open Ticket v4.1.3 (or leave empty)",
- "fields":[
- {"name":"field name","value":"field value","inline":false}
- ],
- "timestamp":false
- },
- "settings":{
- "dropdownPlaceholder":"Create a ticket!",
-
- "enableMaxTicketsWarningInText":false,
- "enableMaxTicketsWarningInEmbed":true,
-
- "describeOptionsLayout":"simple OR normal OR detailed",
- "describeOptionsCustomTitle":"",
- "describeOptionsInText":false,
- "describeOptionsInEmbedFields":true,
- "describeOptionsInEmbedDescription":false
- }
- }
-]
\ No newline at end of file
diff --git a/config/panels.jsonc b/config/panels.jsonc
new file mode 100644
index 0000000..cf5bca8
--- /dev/null
+++ b/config/panels.jsonc
@@ -0,0 +1,57 @@
+/*
+ * OPEN TICKET PANELS
+ * ----------------------------------------------
+ * Create customizable panel messages with buttons or a dropdown.
+ * Add up to 25 options to this panel from (config/options.jsonc)
+ * Panels can be customised with text, images, colors and more.
+ *
+ * Spawn the panel in Discord using: /panel
+ *
+ * TIP: Create new panels by copying everything between and including the {...} brackets of an panel. Paste it after the last panel and make sure that they are seperated by a comma.
+ */
+[
+ {
+ /* A panel is creates a message with up to 25 options as buttons or dropdown. */
+ "id":"example-panel",
+ "name":"Example Panel",
+ "dropdown":false,
+
+ /* Add up to 5 option IDs from (config/options.jsonc). */
+ "options":["example-ticket","example-website","example-role"],
+
+ "text":"", //Leave empty to disable
+ "embed":{
+ "enabled":true,
+ "title":"Tickets:", //Leave empty to disable
+ "description":"Create a ticket by selecting one of the options below. Once selected, a private ticket will be created for you and our support team will be able to assist you directly.", //Leave empty to disable
+
+ "customColor":"#f8ab00", //Leave empty to use default color
+ "url":"", //URL. Leave empty to disable
+
+ "image":"", //Image URL. Leave empty to disable
+ "thumbnail":"", //Image URL. Leave empty to disable
+
+ "footer":"Open Ticket v4.2.0", //Leave empty to disable
+ /* Embed fields. Set to empty list [] to disable. */
+ "fields":[
+ {"name":"Field name","value":"Field value","inline":false}
+ ],
+ "timestamp":false
+ },
+ "settings":{
+ "dropdownPlaceholder":"Create a ticket...", //Leave empty to use default.
+ "maximumButtonsPerRow":5,
+
+ /* Display the maximum amount of tickets per user. */
+ "enableMaxTicketsWarningInText":false,
+ "enableMaxTicketsWarningInEmbed":true,
+
+ /* Automatically generate option descriptions from (config/options.jsonc). */
+ "describeOptionsLayout":"normal", //Choices: simple, normal, detailed
+ "describeOptionsCustomTitle":"",
+ "describeOptionsInText":false,
+ "describeOptionsInEmbedFields":true,
+ "describeOptionsInEmbedDescription":false
+ }
+ }
+]
\ No newline at end of file
diff --git a/config/questions.json b/config/questions.json
deleted file mode 100644
index 0d2556e..0000000
--- a/config/questions.json
+++ /dev/null
@@ -1,28 +0,0 @@
-[
- {
- "id":"example-question-1",
- "name":"Example Question 1",
- "type":"short",
-
- "required":true,
- "placeholder":"Insert your short answer here!",
- "length":{
- "enabled":false,
- "min":0,
- "max":1000
- }
- },
- {
- "id":"example-question-2",
- "name":"Example Question 2",
- "type":"paragraph",
-
- "required":false,
- "placeholder":"Insert your long answer here!",
- "length":{
- "enabled":false,
- "min":0,
- "max":1000
- }
- }
-]
\ No newline at end of file
diff --git a/config/questions.jsonc b/config/questions.jsonc
new file mode 100644
index 0000000..8f9062e
--- /dev/null
+++ b/config/questions.jsonc
@@ -0,0 +1,102 @@
+/*
+ * OPEN TICKET MODAL QUESTIONS
+ * ----------------------------------------------
+ * Create customizable modal questions that will be shown before creating a ticket.
+ * Each ticket option (config/options.jsonc) can contain a maximum of 5 questions.
+ * There are 6 types of questions available: short, paragraph, dropdown, radio-select, checkbox-select, text-display
+ *
+ * TIP: Create new questions by copying everything between and including the {...} brackets of a question. Paste it after the last question and make sure that they are seperated by a comma.
+ */
+[
+ {
+ /* A short text input modal question. */
+ "id":"example-question-1",
+ "name":"Example Question 1",
+ "description":"", //Leave empty to disable
+ "type":"short",
+ "required":true,
+
+ "placeholder":"Insert answer...",
+ "length":{
+ /* Configure length limits for the answer. */
+ "enabled":false,
+ "min":0,
+ "max":1000
+ }
+ },
+ {
+ /* A paragraph text input modal question. */
+ "id":"example-question-2",
+ "name":"Example Question 2",
+ "description":"", //Leave empty to disable
+ "type":"paragraph",
+ "required":false,
+
+ "placeholder":"Insert answer...",
+ "length":{
+ /* Configure length limits for the answer. */
+ "enabled":false,
+ "min":0,
+ "max":1000
+ }
+ },
+ {
+ /* A dropdown menu input modal question with up to 25 choices. "emoji" & "description" fields are optional. */
+ "id":"example-question-3",
+ "name":"Example Question 3",
+ "description":"This is a dropdown question.", //Leave empty to disable
+ "type":"dropdown",
+ "required":false,
+
+ "placeholder":"Choose your answer...",
+ "choices":[
+ {"title":"Choice A","description":"Apple","emoji":"🍎"},
+ {"title":"Choice B","description":"Banana","emoji":"🍌"},
+ {"title":"Choice C","description":"Orange","emoji":"🍊"},
+ {"title":"Choice D","description":"Kiwi","emoji":"🥝"}
+ ]
+ },
+ {
+ /* A radio select input modal question with up to 10 choices. */
+ "id":"example-question-4",
+ "name":"Example Question 4",
+ "description":"This is a radio select question.", //Leave empty to disable
+ "type":"radio-select",
+ "required":true,
+
+ "choices":[
+ {"title":"Choice A","description":"Up","selectedByDefault":false},
+ {"title":"Choice B","description":"Down","selectedByDefault":false},
+ {"title":"Choice C","description":"Left","selectedByDefault":false},
+ {"title":"Choice D","description":"Right","selectedByDefault":false}
+ ]
+ },
+ {
+ /* A checkbox select input modal question with up to 10 choices. */
+ "id":"example-question-5",
+ "name":"Example Question 5",
+ "description":"This is a checkbox select question.", //Leave empty to disable
+ "type":"checkbox-select",
+ "required":true,
+
+ "limits":{
+ /* Configure checkbox amount limits for the answer. */
+ "enabled":false,
+ "min":0,
+ "max":10
+ },
+ "choices":[
+ {"title":"Choice A","description":"Happiness","selectedByDefault":false},
+ {"title":"Choice B","description":"Anger","selectedByDefault":false},
+ {"title":"Choice C","description":"Sadness","selectedByDefault":false},
+ {"title":"Choice D","description":"Fear","selectedByDefault":false}
+ ]
+ },
+ {
+ /* Show text in a modal to provide extra details or explain questions. */
+ "id":"example-text-display",
+ "type":"text-display",
+
+ "textContents":"This is a text display. It isn't a question, but allows you to display additional details."
+ }
+]
\ No newline at end of file
diff --git a/config/transcripts.json b/config/transcripts.json
deleted file mode 100644
index 37651ae..0000000
--- a/config/transcripts.json
+++ /dev/null
@@ -1,55 +0,0 @@
-{
- "general":{
- "enabled":false,
-
- "enableChannel":false,
- "enableCreatorDM":false,
- "enableParticipantDM":false,
- "enableActiveAdminDM":false,
- "enableEveryAdminDM":false,
-
- "channel":"transcript channel id (or leave empty)",
- "mode":"html OR text"
- },
- "embedSettings":{
- "customColor":"#f8ab00 (or leave empty)",
- "listAllParticipants":false,
- "includeTicketStats":false
- },
- "textTranscriptStyle":{
- "layout":"simple OR normal OR detailed",
- "includeStats":true,
- "includeIds":false,
- "includeEmbeds":true,
- "includeFiles":true,
- "includeBotMessages":true,
-
- "fileMode":"custom OR channel-name OR channel-id OR user-name OR user-id",
- "customFileName":"this-is-a-transcript (or leave empty)"
- },
- "htmlTranscriptStyle":{
- "background":{
- "enableCustomBackground":false,
- "backgroundColor":"#f8ba00 (or leave empty)",
- "backgroundImage":"https://www.example.com/image.png (or leave empty)"
- },
- "header":{
- "enableCustomHeader":false,
- "backgroundColor":"#202225",
- "decoColor":"#f8ba00",
- "textColor":"#ffffff"
- },
- "stats":{
- "enableCustomStats":false,
- "backgroundColor":"#202225",
- "keyTextColor":"#737373",
- "valueTextColor":"#ffffff",
- "hideBackgroundColor":"#40444a",
- "hideTextColor":"#ffffff"
- },
- "favicon":{
- "enableCustomFavicon":false,
- "imageUrl":"https://t.dj-dj.be/favicon.png"
- }
- }
-}
\ No newline at end of file
diff --git a/config/transcripts.jsonc b/config/transcripts.jsonc
new file mode 100644
index 0000000..2a441c5
--- /dev/null
+++ b/config/transcripts.jsonc
@@ -0,0 +1,70 @@
+/*
+ * OPEN TICKET TRANSCRIPTS
+ * ----------------------------------------------
+ * Enable transcript creation when tickets are deleted. There are 2 available transcript types: HTML & Text
+ *
+ * HTML Transcripts (recommended):
+ * Generate transcripts as HTML files to view in the browser. No server or domain required. HTML Transcripts use an external service to process and host the transcripts.
+ *
+ * Text Transcripts:
+ * Generate transcripts as simple .txt files with limited details. Processing happens fully local.
+ */
+{
+ "general":{
+ "enabled":false,
+
+ /* Choose which users and channel get the generated transcript. */
+ "enableChannel":false,
+ "enableCreatorDM":false,
+ "enableParticipantDM":false,
+ "enableActiveAdminDM":false,
+ "enableEveryAdminDM":false,
+
+ "channel":"DISCORD_CHANNEL_ID", //Where to send transcripts. Leave empty when disabled.
+ "mode":"html" //The type of transcript to use. Choices: html, text
+ },
+ "embedSettings":{
+ /* Customise the embed which contains the generated transcript file or URL. */
+ "customColor":"#f8ab00", //Leave empty to use default color
+ "listAllParticipants":false,
+ "includeTicketStats":false
+ },
+ "textTranscriptStyle":{
+ /* Customise layout of the text transcripts. */
+ "layout":"normal", //Choices: simple, normal, detailed
+ "includeStats":true,
+ "includeIds":false,
+ "includeEmbeds":true,
+ "includeFiles":true,
+ "includeBotMessages":true,
+
+ "fileMode":"custom", //How to name the transcript file? Choices: custom, channel-name, channel-id, user-name, user-id
+ "customFileName":"transcript" //Custom filename without extension
+ },
+ "htmlTranscriptStyle":{
+ /* Customise layout of the HTML transcripts. */
+ "background":{
+ "enableCustomBackground":false,
+ "backgroundColor":"#f8ba00", //Leave empty to use Open Ticket color (#f8ba00)
+ "backgroundImage":"https://www.example.com/image.png" //Image URL to fill entire background. Leave empty to disable
+ },
+ "header":{
+ "enableCustomHeader":false,
+ "backgroundColor":"#202225",
+ "decoColor":"#f8ba00",
+ "textColor":"#ffffff"
+ },
+ "stats":{
+ "enableCustomStats":false,
+ "backgroundColor":"#202225",
+ "keyTextColor":"#737373",
+ "valueTextColor":"#ffffff",
+ "hideBackgroundColor":"#40444a",
+ "hideTextColor":"#ffffff"
+ },
+ "favicon":{
+ "enableCustomFavicon":false,
+ "imageUrl":"https://t.dj-dj.be/favicon.png"
+ }
+ }
+}
\ No newline at end of file
diff --git a/database/states.json b/database/states.json
new file mode 100644
index 0000000..0637a08
--- /dev/null
+++ b/database/states.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file
diff --git a/index.js b/index.js
index 6cead33..2935154 100644
--- a/index.js
+++ b/index.js
@@ -4,7 +4,6 @@ const flags = [
//PTERODACTYL PANEL
//add startup flags here (e.g. "--no-compile") when running via the panel
]
-process.argv.push(...flags)
/////////////// STARTUP FLAGS ///////////////
/*
@@ -14,170 +13,19 @@ process.argv.push(...flags)
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║
╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║╚██████╗██║ ██╗███████╗ ██║
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝
- v4.1.3 - Made by DJj123dj & Contributors
+ v4.2.0 - Made by DJj123dj & Contributors
Discord: https://discord.dj-dj.be
Docs: https://otdocs.dj-dj.be
Support Us: https://github.com/sponsors/DJj123dj/
*/
+
///////////////////////////////////////////
////////// COMPILATION + STARTUP //////////
///////////////////////////////////////////
-const fs = require("fs")
-const ts = require("typescript")
-const {createHash,Hash} = require("crypto")
-const nodepath = require('path')
-const ansis = require("ansis")
-/** ## What is this?
- * This is a function which compares `./src/` with a hash stored in `./dist/hash.txt`.
- * The hash is based on the modified date & file metadata of all files in `./src/`.
- *
- * If the hash is different, the bot will automatically re-compile.
- * This will help you save CPU resources because the bot shouldn't re-compile when nothing has been changed :)
- *
- * @param {string} dir
- * @param {Hash|null} upperHash
- */
-function computeSourceHash(dir,upperHash){
- const hash = upperHash ? upperHash : createHash("sha256")
- const info = fs.readdirSync(dir,{withFileTypes:true})
-
- for (const file of info) {
- const fullPath = nodepath.join(dir,file.name)
- if (file.isFile() && [".js",".ts",".jsx",".tsx"].some((ext) => file.name.endsWith(ext))){
- const statInfo = fs.statSync(fullPath)
- //compute hash using file metadata
- const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}`
- hash.update(fileInfo)
-
- }else if (file.isDirectory()){
- //recursively compute all folders
- computeSourceHash(fullPath,hash)
- }
- }
- //return when not being called recursively
- if (!upperHash) {
- return hash.digest("hex")
- }
-}
-function requiresCompilation(){
- //check hashes when not using "--compile-only" flag
- if (process.argv.includes("--compile-only")) return true
-
- console.log("OT: Comparing prebuilds with source...")
- const sourceHash = computeSourceHash("./src/")
- const pluginHash = computeSourceHash("./plugins/")
- const hash = sourceHash+":"+pluginHash
-
- if (fs.existsSync("./dist/hash.txt")){
- const distHash = fs.readFileSync("./dist/hash.txt").toString()
- if (distHash === hash) return false
- else return true
- }else return true
-}
-function saveNewCompilationHash(){
- const sourceHash = computeSourceHash("./src/")
- const pluginHash = computeSourceHash("./plugins/")
- const hash = sourceHash+":"+pluginHash
- fs.writeFileSync("./dist/hash.txt",hash)
-}
-
-if (!process.argv.includes("--no-compile")){
- const requiredDependencies = new Set()
- if (fs.existsSync("./plugins")){
- console.log("OT: Reading plugin.json files...")
- for (const pluginDir of fs.readdirSync("./plugins")){
- if (pluginDir === ".DS_Store") continue
- const pluginPath = nodepath.join("./plugins", pluginDir)
- if (!fs.statSync(pluginPath).isDirectory()) continue
-
- const pluginJsonPath = nodepath.join(pluginPath, "plugin.json")
- if (fs.existsSync(pluginJsonPath)){
- try{
- const pluginData = JSON.parse(fs.readFileSync(pluginJsonPath).toString())
- if (pluginData.npmDependencies && Array.isArray(pluginData.npmDependencies)){
- pluginData.npmDependencies.forEach((dep) => {
- if (typeof dep === "string" && dep.trim()){
- requiredDependencies.add(dep.trim())
- }
- })
- }
- }catch(err){
- // skip invalid plugin.json files, will be caught later
- }
- }
- }
-
- if (requiredDependencies.size > 0){
- console.log("OT: Checking plugin npm dependencies...")
- /**@type {string[]} */
- const missingDeps = []
- for (const dep of requiredDependencies){
- try{
- require.resolve(dep)
- }catch(err){
- missingDeps.push(dep)
- }
- }
-
- if (missingDeps.length > 0){
- console.log(ansis.red("OT: ❌ Fatal Error --> Missing npm dependencies required by plugins:\n\n")+ansis.cyan(missingDeps.map((dep) => " - "+dep).join("\n")+"\n"))
- console.log("OT: Please install missing dependencies using the following command:\n> "+ansis.bold.green("npm install " + missingDeps.join(" "))+"\n")
- process.exit(1)
- }
- }
- }
-
- if (requiresCompilation()){
- console.log("OT: Compilation Required...")
-
- //REMOVE EXISTING BUILDS
- console.log("OT: Removing Prebuilds...")
- fs.rmSync("./dist",{recursive:true,force:true})
-
- //COMPILE TYPESCRIPT
- console.log("OT: Compiling Typescript...")
- const configPath = nodepath.resolve('./tsconfig.json')
- const configFile = ts.readConfigFile(configPath,ts.sys.readFile)
-
- //check for tsconfig errors
- if (configFile.error){
- const message = ts.formatDiagnosticsWithColorAndContext([configFile.error],ts.createCompilerHost({}))
- console.error(message)
- process.exit(1)
- }
-
- //parse tsconfig file
- const parsedConfig = ts.parseJsonConfigFileContent(configFile.config,ts.sys,nodepath.dirname(configPath))
-
- //create program/compiler
- const program = ts.createProgram({
- rootNames:parsedConfig.fileNames,
- options:parsedConfig.options
- })
-
- //emit all compiled files
- const emitResult = program.emit()
-
- //print emit errors/warnings (type errors)
- const allDiagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics)
- const formattedDiagnostics = ts.formatDiagnosticsWithColorAndContext(allDiagnostics, ts.createCompilerHost(parsedConfig.options))
- console.log(formattedDiagnostics)
-
- if (emitResult.emitSkipped || allDiagnostics.find((d) => d.category == ts.DiagnosticCategory.Error || d.category == ts.DiagnosticCategory.Warning)){
- console.log("OT: Compilation Failed!")
- process.exit(1)
- }
- }else console.log("OT: No Compilation Required...")
-
- //save new compilation hash
- saveNewCompilationHash()
-}
-
-//START BOT
-console.log("OT: Compilation Succeeded!")
-if (process.argv.includes("--compile-only")) process.exit(0) //exit when only compile is required!
-console.log("OT: Starting Bot!")
-require("./dist/src/index.js")
\ No newline at end of file
+import { frameworkStartup } from "@open-discord-bots/framework"
+frameworkStartup(flags,"openticket",async () => {
+ await import("./dist/src/index.js")
+})
\ No newline at end of file
diff --git a/languages/arabic.json b/languages/arabic.json
index 694bf33..40c7cff 100644
--- a/languages/arabic.json
+++ b/languages/arabic.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["palestinian"],
"lastedited":"16/02/2026",
"language":"Arabic",
diff --git a/languages/bengali.json b/languages/bengali.json
index fe5894f..317f3d5 100644
--- a/languages/bengali.json
+++ b/languages/bengali.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta"],
"lastedited":"16/02/2026",
"language":"Bengali",
diff --git a/languages/catalan.json b/languages/catalan.json
index 1336d34..fed41c0 100644
--- a/languages/catalan.json
+++ b/languages/catalan.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["guillee3"],
"lastedited":"16/02/2026",
"language":"Catalan",
diff --git a/languages/custom.json b/languages/custom.json
index 7b9888d..f22936f 100644
--- a/languages/custom.json
+++ b/languages/custom.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["DJj123dj"],
"lastedited":"16/02/2026",
"language":"Custom",
@@ -13,94 +13,94 @@
"typeWarning":"[WARNING]",
"typeInfo":"[INFO]",
"headerConfigChecker":"CONFIG CHECKER",
- "headerDescription":"check for errors in your config files!",
- "footerError":"the bot won't start until all {0}'s are fixed!",
- "footerWarning":"it's recommended to fix all {0}'s before starting!",
+ "headerDescription":"Validating config files...",
+ "footerError":"The bot will not start until all {0}'s are resolved.",
+ "footerWarning":"The bot may behave unexpectedly until all {0}'s are resolved.",
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
- "compactInformation":"use {0} for more information!",
+ "compactInformation":"Use {0} for a detailed config report.",
"dataPath":"path",
"dataDocs":"docs",
"dataMessages":"message"
},
"messages":{
- "stringTooShort":"This string can't be shorter than {0} characters!",
- "stringTooLong":"This string can't be longer than {0} characters!",
- "stringLengthInvalid":"This string needs to be {0} characters long!",
- "stringStartsWith":"This string needs to start with {0}!",
- "stringEndsWith":"This string needs to end with {0}!",
- "stringContains":"This string needs to contain {0}!",
- "stringChoices":"This string can only be one of the following values: {0}!",
- "stringRegex":"This string is invalid!",
- "stringInvertedContains":"This string is not allowed to contain {0}!",
- "stringLowercase":"This string must be written in lowercase only!",
- "stringUppercase":"This string must be written in uppercase only!",
- "stringSpecialCharacters":"This string is not allowed to contain any special characters! (a-z, 0-9 & space only)",
- "stringNoSpaces":"This string is not allowed to contain spaces!",
- "stringCapitalWord":"It's recommended that each word in this string starts with a capital letter!",
- "stringCapitalSentence":"It looks like some sentences in this string don't start with a capital letter!",
- "stringPunctuation":"It looks like the sentence in this string doesn't end with a punctuation mark!",
+ "stringTooShort":"Text must be at least {0} characters long",
+ "stringTooLong":"Text must be no longer than {0} characters",
+ "stringLengthInvalid":"Text must be exactly {0} characters long",
+ "stringStartsWith":"Text must start with {0}",
+ "stringEndsWith":"Text must end with {0}",
+ "stringContains":"Text must contain {0}",
+ "stringChoices":"Text must be one of the following: {0}",
+ "stringRegex":"Text does not match the required format",
+ "stringInvertedContains":"Text must not contain {0}",
+ "stringLowercase":"Text must be entirely lowercase",
+ "stringUppercase":"Text must be entirely uppercase",
+ "stringSpecialCharacters":"Text must only contain letters (a–z), numbers (0–9), and spaces",
+ "stringNoSpaces":"Text must not contain spaces",
+ "stringCapitalWord":"Each word in this value should start with a capital letter",
+ "stringCapitalSentence":"One or more sentences in this value do not start with a capital letter",
+ "stringPunctuation":"The sentence in this value does not end with a punctuation mark",
- "numberTooShort":"This number can't be shorter than {0} characters!",
- "numberTooLong":"This number can't be longer than {0} characters!",
- "numberLengthInvalid":"This number needs to be {0} characters long!",
- "numberTooSmall":"This number needs to be at least {0}!",
- "numberTooLarge":"This number needs to be at most {0}!",
- "numberNotEqual":"This number needs to be {0}!",
- "numberStep":"This number needs to be a multiple of {0}!",
- "numberStepOffset":"This number needs to be a multiple of {0} starting with {1}!",
- "numberStartsWith":"This number needs to start with {0}!",
- "numberEndsWith":"This number needs to end with {0}!",
- "numberContains":"This number needs to contain {0}!",
- "numberChoices":"This number can only be one of the following values: {0}!",
- "numberFloat":"This number can't be a decimal!",
- "numberNegative":"This number can't be negative!",
- "numberPositive":"This number can't be positive!",
- "numberZero":"This number can't be zero!",
- "numberNan":"This number can't be NaN (Not A Number)!",
- "numberInvertedContains":"This number is not allowed to contain {0}!",
+ "numberTooShort":"Number must be at least {0} digits long",
+ "numberTooLong":"Number must be no longer than {0} digits",
+ "numberLengthInvalid":"Number must be exactly {0} digits long",
+ "numberTooSmall":"Number must be at least {0}",
+ "numberTooLarge":"Number must be at most {0}",
+ "numberNotEqual":"Number must be exactly {0}",
+ "numberStep":"Number must be a multiple of {0}",
+ "numberStepOffset":"Number must be a multiple of {0}, starting from {1}",
+ "numberStartsWith":"Number must start with {0}",
+ "numberEndsWith":"Number must end with {0}",
+ "numberContains":"Number must contain {0}",
+ "numberChoices":"Number must be one of the following: {0}",
+ "numberFloat":"Number must be a whole number",
+ "numberNegative":"Number must be a positive number",
+ "numberPositive":"Number must be a negative number",
+ "numberZero":"Number must not be zero",
+ "numberNan":"Number must be a valid number",
+ "numberInvertedContains":"Number must not contain {0}",
- "booleanTrue":"This boolean can't be true!",
- "booleanFalse":"This boolean can't be false!",
+ "booleanTrue":"Boolean must be false",
+ "booleanFalse":"Boolean must be true",
+
+ "arrayEmptyDisabled":"List must not be empty",
+ "arrayEmptyRequired":"List must be empty",
+ "arrayTooShort":"List must have at least {0} items",
+ "arrayTooLong":"List must have at most {0} items",
+ "arrayLengthInvalid":"List must have exactly {0} items",
+ "arrayInvalidTypes":"List may only contain the following types: {0}",
+ "arrayDouble":"List must not contain duplicate values",
+
+ "discordInvalidId":"Invalid Discord {0} ID",
+ "discordInvalidIdOptions":"Invalid Discord {0} ID. Alternatively, use one of the following: {1}",
+ "discordInvalidToken":"Invalid Discord token",
+ "colorInvalid":"Invalid hex color",
+ "emojiTooShort":"Value must contain at least {0} emoji",
+ "emojiTooLong":"Value must contain at most {0} emoji",
+ "emojiCustom":"Custom Discord emojis are not allowed here",
+ "emojiInvalid":"Invalid emoji",
+ "urlInvalid":"Invalid URL",
+ "urlInvalidHttp":"URL must use the https:// protocol",
+ "urlInvalidProtocol":"URL must use the http:// or https:// protocol",
+ "urlInvalidHostname":"URL hostname is not allowed",
+ "urlInvalidExtension":"Invalid URL extension. Allowed extensions: {0}",
+ "urlInvalidPath":"Invalid URL path",
+ "idNotUnique":"This ID is already in use. Please choose a unique ID",
+ "idNonExistent":"ID {0} does not exist",
+
+ "invalidType":"Property must be of type: {0}",
+ "propertyMissing":"Required property {0} is missing from the object",
+ "propertyOptional":"Property {0} is optional in the object",
+ "objectDisabled":"This object is disabled. Enable it using {0}",
+ "nullInvalid":"Property must not be null",
+ "switchInvalidType":"Value must be one of the following types: {0}",
+ "objectSwitchInvalid":"Object must be one of the following types: {0}",
- "arrayEmptyDisabled":"This array isn't allowed to be empty!",
- "arrayEmptyRequired":"This array is required to be empty!",
- "arrayTooShort":"This array needs to have a length of at least {0}!",
- "arrayTooLong":"This array needs to have a length of at most {0}!",
- "arrayLengthInvalid":"This array needs to have a length of {0}!",
- "arrayInvalidTypes":"This array can only contain the following types: {0}!",
- "arrayDouble":"This array doesn't allow the same value twice!",
-
- "discordInvalidId":"This is an invalid discord {0} id!",
- "discordInvalidIdOptions":"This is an invalid discord {0} id! You can also use one of these: {1}!",
- "discordInvalidToken":"This is an invalid discord token (syntactically)!",
- "colorInvalid":"This is an invalid hex color!",
- "emojiTooShort":"This string needs to have at least {0} emoji's!",
- "emojiTooLong":"This string needs to have at most {0} emoji's!",
- "emojiCustom":"This emoji can't be a custom discord emoji!",
- "emojiInvalid":"This is an invalid emoji!",
- "urlInvalid":"This url is invalid!",
- "urlInvalidHttp":"This url can only use the https:// protocol!",
- "urlInvalidProtocol":"This url can only use the http:// & https:// protocols!",
- "urlInvalidHostname":"This url has a disallowed hostname!",
- "urlInvalidExtension":"This url has an invalid extension! Choose between: {0}!",
- "urlInvalidPath":"This url has an invalid path!",
- "idNotUnique":"This id isn't unique, use another id instead!",
- "idNonExistent":"The id {0} doesn't exist!",
-
- "invalidType":"This property needs to be the type: {0}!",
- "propertyMissing":"The property {0} is missing from this object!",
- "propertyOptional":"The property {0} is optional in this object!",
- "objectDisabled":"This object is disabled, enable it using {0}!",
- "nullInvalid":"This property can't be null!",
- "switchInvalidType":"This needs to be one of the following types: {0}!",
- "objectSwitchInvalid":"This object needs to be one of the following types: {0}!",
-
- "invalidLanguage":"This is an invalid language!",
- "invalidButton":"This button needs to have at least an {0} or {1}!",
- "unusedOption":"The option {0} isn't used anywhere!",
- "unusedQuestion":"The question {0} isn't used anywhere!",
- "dropdownOption":"A panel with dropdown enabled can only contain options of the 'ticket' type!",
- "customInvalidVersion":"The version specified in your config does not match! Make sure you have updated the config to the latest version!"
+ "invalidLanguage":"Invalid language",
+ "invalidButton":"Button must have at least an {0} or {1}",
+ "unusedOption":"Option {0} is not used anywhere",
+ "unusedQuestion":"Question {0} is not used anywhere",
+ "dropdownOption":"Panels with dropdown enabled may only contain options of the 'ticket' type",
+ "customInvalidVersion":"Config version mismatch. Make sure to update your config to the latest version"
}
},
"actions":{
@@ -159,118 +159,118 @@
"transfer":"Ticket Transferred"
},
"descriptions":{
- "create":"Your ticket has been created. Click the button below to access it!",
- "close":"The ticket has been closed successfully!",
- "delete":"The ticket has been deleted successfully!",
- "reopen":"The ticket has been reopened successfully!",
- "claim":"The ticket has been claimed successfully!",
- "unclaim":"The ticket has been unclaimed successfully!",
- "pin":"The ticket has been pinned successfully!",
- "unpin":"The ticket has been unpinned successfully!",
- "rename":"The ticket has been renamed to {0} successfully!",
- "move":"The ticket has been moved to {0} successfully!",
- "add":"{0} has been added to the ticket successfully!",
- "remove":"{0} has been removed from the ticket successfully!",
+ "create":"Your ticket is ready. Click the button below to view and continue.",
+ "close":"The ticket has been closed.",
+ "delete":"The ticket has been deleted.",
+ "reopen":"The ticket has been reopened.",
+ "claim":"The ticket has been claimed.",
+ "unclaim":"The ticket has been unclaimed.",
+ "pin":"The ticket has been pinned.",
+ "unpin":"The ticket has been unpinned.",
+ "rename":"The ticket has been renamed to {0}.",
+ "move":"The ticket has been moved to {0}.",
+ "add":"{0} has been added to the ticket.",
+ "remove":"{0} has been removed from the ticket.",
"helpExplanation":"`` => required parameter\n`[name]` => optional parameter",
- "statsReset":"The bot stats have been reset successfully!",
- "statsError":"Unable to view ticket stats!\n{0} is not a ticket!",
- "blacklistAdd":"{0} has been blacklisted successfully!",
- "blacklistRemove":"{0} has been released successfully!",
- "blacklistGetSuccess":"{0} is currently blacklisted!",
- "blacklistGetEmpty":"{0} is currently not blacklisted!",
- "blacklistViewEmpty":"No-one has been blacklisted yet!",
- "blacklistViewTip":"Use \"/blacklist add\" to blacklist a user!",
- "clearVerify":"Are you sure you want to delete multiple tickets?\nThis action can't be undone!",
- "clearReady":"{0} tickets have been deleted successfully!",
- "rolesEmpty":"No roles have been updated!",
+ "statsReset":"The bot statistics have been reset.",
+ "statsError":"Unable to retrieve ticket statistics.\n{0} is not a valid ticket.",
+ "blacklistAdd":"{0} has been blacklisted.",
+ "blacklistRemove":"{0} has been released.",
+ "blacklistGetSuccess":"{0} is blacklisted!",
+ "blacklistGetEmpty":"{0} is not blacklisted!",
+ "blacklistViewEmpty":"No users have been blacklisted yet.",
+ "blacklistViewTip":"Use \"/blacklist add\" to add a user to the blacklist.",
+ "clearVerify":"Are you sure you want to delete multiple tickets?\nThis action cannot be undone.",
+ "clearReady":"{0} ticket(s) have been deleted.",
+ "rolesEmpty":"No roles were modified.",
- "autocloseLeave":"This ticket has been autoclosed because the creator left the server!",
- "autocloseTimeout":"This ticket has been autoclosed because it has been inactive for more than `{0}h`!",
- "autodeleteLeave":"This ticket has been autodeleted because the creator left the server!",
- "autodeleteTimeout":"This ticket has been autodeleted because it has been inactive for more than `{0} days`!",
- "autocloseEnabled":"Autoclose has been enabled in this ticket!\nIt will be closed when it is inactive for more than `{0}h`!",
- "autocloseDisabled":"Autoclose has been disabled in this ticket!\nIt won't be closed automatically anymore!",
- "autodeleteEnabled":"Autodelete has been enabled in this ticket!\nIt will be deleted when it is inactive for more than `{0} days`!",
- "autodeleteDisabled":"Autodelete has been disabled in this ticket!\nIt won't be deleted automatically anymore!",
+ "autocloseLeave":"This ticket was automatically closed because its creator left the server.",
+ "autocloseTimeout":"This ticket was automatically closed due to inactivity exceeding `{0}h`.",
+ "autodeleteLeave":"This ticket was automatically deleted because its creator left the server.",
+ "autodeleteTimeout":"This ticket was automatically deleted due to inactivity exceeding `{0} days`.",
+ "autocloseEnabled":"Autoclose has been enabled for this ticket.\nIt will close after `{0}h` of inactivity.",
+ "autocloseDisabled":"Autoclose has been disabled for this ticket.\nThis ticket will no longer close automatically.",
+ "autodeleteEnabled":"Autodelete has been enabled for this ticket.\nIt will be deleted after `{0} days` of inactivity.",
+ "autodeleteDisabled":"Autodelete has been disabled for this ticket.\nThis ticket will no longer be deleted automatically.",
- "ticketMessageLimit":"You can only create {0} ticket(s) at the same time!",
- "ticketMessageAutoclose":"This ticket will be autoclosed when inactive for {0}h!",
- "ticketMessageAutodelete":"This ticket will be autodeleted when inactive for {0} days!",
- "panelReady":"The panel is available in the followup message!\nThis message can now be deleted!",
+ "ticketMessageLimit":"You can only have {0} active ticket(s) at a time.",
+ "ticketMessageAutoclose":"This ticket will automatically close after `{0}h` of inactivity.",
+ "ticketMessageAutodelete":"This ticket will automatically be deleted after `{0} days` of inactivity.",
+ "panelReady":"The panel has been sent in the follow-up message.\nYou may now delete this message.",
- "topicSet":"The channel topic has been changed by {0} successfully!",
- "prioritySet":"The ticket priority has been changed to {0} by {1} successfully!",
- "priorityGet":"The current priority of this ticket is {0}.",
- "transfer":"The ticket ownership has been transferred from {0} to {1} by {2} successfully!"
+ "topicSet":"The channel topic has been changed by {0}.",
+ "prioritySet":"The ticket priority has been changed to {0} by {1}.",
+ "priorityGet":"The priority of this ticket is {0}.",
+ "transfer":"The ticket ownership has been transferred from {0} to {1} by {2}."
},
"modal":{
- "closePlaceholder":"Why did you close this ticket?",
- "deletePlaceholder":"Why did you delete this ticket?",
- "reopenPlaceholder":"Why did you reopen this ticket?",
- "claimPlaceholder":"Why did you claim this ticket?",
- "unclaimPlaceholder":"Why did you unclaim this ticket?",
- "pinPlaceholder":"Why did you pin this ticket?",
- "unpinPlaceholder":"Why did you unpin this ticket?"
+ "closePlaceholder":"Why would you like to close this ticket?",
+ "deletePlaceholder":"Why would you like to delete this ticket?",
+ "reopenPlaceholder":"Why would you like to reopen this ticket?",
+ "claimPlaceholder":"Why would you like to claim this ticket?",
+ "unclaimPlaceholder":"Why would you like to unclaim this ticket?",
+ "pinPlaceholder":"Why would you like to pin this ticket?",
+ "unpinPlaceholder":"Why would you like to unpin this ticket?"
},
"logs":{
- "createLog":"A new ticket got created by {0}!",
- "closeLog":"This ticket has been closed by {0}!",
- "closeDm":"Your ticket has been closed in our server!",
- "deleteLog":"This ticket has been deleted by {0}!",
- "deleteDm":"Your ticket has been deleted in our server!",
- "reopenLog":"This ticket has been reopened by {0}!",
- "reopenDm":"Your ticket has been reopened in our server!",
- "claimLog":"This ticket has been claimed by {0}!",
- "claimDm":"Your ticket has been claimed in our server!",
- "unclaimLog":"This ticket has been unclaimed by {0}!",
- "unclaimDm":"Your ticket has been unclaimed in our server!",
- "pinLog":"This ticket has been pinned by {0}!",
- "pinDm":"Your ticket has been pinned in our server!",
- "unpinLog":"This ticket has been unpinned by {0}!",
- "unpinDm":"Your ticket has been unpinned in our server!",
- "renameLog":"This ticket has been renamed to {0} by {1}!",
- "renameDm":"Your ticket has been renamed to {0} in our server!",
- "moveLog":"This ticket has been moved to {0} by {1}!",
- "moveDm":"Your ticket has been moved to {0} in our server!",
- "addLog":"{0} has been added to this ticket by {1}!",
- "addDm":"{0} has been added to your ticket in our server!",
- "removeLog":"{0} has been removed from this ticket by {1}!",
- "removeDm":"{0} has been removed from your ticket in our server!",
+ "createLog":"A new ticket got created by {0}.",
+ "closeLog":"This ticket has been closed by {0}.",
+ "closeDm":"Your ticket has been closed.",
+ "deleteLog":"This ticket has been deleted by {0}.",
+ "deleteDm":"Your ticket has been deleted.",
+ "reopenLog":"This ticket has been reopened by {0}.",
+ "reopenDm":"Your ticket has been reopened.",
+ "claimLog":"This ticket has been claimed by {0}.",
+ "claimDm":"Your ticket has been claimed.",
+ "unclaimLog":"This ticket has been unclaimed by {0}.",
+ "unclaimDm":"Your ticket has been unclaimed.",
+ "pinLog":"This ticket has been pinned by {0}.",
+ "pinDm":"Your ticket has been pinned.",
+ "unpinLog":"This ticket has been unpinned by {0}.",
+ "unpinDm":"Your ticket has been unpinned.",
+ "renameLog":"This ticket has been renamed to {0} by {1}.",
+ "renameDm":"Your ticket has been renamed to {0}.",
+ "moveLog":"This ticket has been moved to {0} by {1}.",
+ "moveDm":"Your ticket has been moved to {0}.",
+ "addLog":"{0} has been added to this ticket by {1}.",
+ "addDm":"{0} has been added to your ticket.",
+ "removeLog":"{0} has been removed from this ticket by {1}.",
+ "removeDm":"{0} has been removed from your ticket.",
- "blacklistAddLog":"{0} was blacklisted by {1}!",
- "blacklistRemoveLog":"{0} was removed from the blacklist by {1}!",
- "blacklistAddDm":"You have been blacklisted in our server!\nFrom now on, you are unable to create a ticket!",
- "blacklistRemoveDm":"You have been removed from the blacklist in our server!\nNow you can create tickets again!",
- "clearLog":"{0} tickets have been deleted by {1}!",
+ "blacklistAddLog":"{0} has been blacklisted by {1}.",
+ "blacklistRemoveLog":"{0} has been removed from the blacklist by {1}.",
+ "blacklistAddDm":"You have been blacklisted from this server.\nYou are no longer able to create tickets.",
+ "blacklistRemoveDm":"You have been removed from the blacklist.\nYou can now create tickets again.",
+ "clearLog":"{0} ticket(s) have been deleted by {1}.",
- "transferLog":"The ownership of this ticket has been transferred from {0} to {1} by {2}!",
- "transferDm":"The ownership of your ticket has been transferred from {0} to {1} in our server!",
- "prioritySetLog":"The priority of this ticket has been changed to {0} by {1}!",
- "prioritySetDm":"The priority of your ticket has been changed to {0} in our server!",
- "roleUpdateLog":"{0} has updated their roles!",
- "roleUpdateDm":"Your roles in our server have been updated!"
+ "transferLog":"Ticket ownership has been transferred from {0} to {1} by {2}.",
+ "transferDm":"Ownership of your ticket has been transferred from {0} to {1}.",
+ "prioritySetLog":"The priority of this ticket has been set to {0} by {1}.",
+ "prioritySetDm":"The priority of your ticket has been set to {0}.",
+ "roleUpdateLog":"{0} has modified their roles.",
+ "roleUpdateDm":"Your roles have been modified."
}
},
"transcripts":{
"success":{
"visit":"Visit Transcript",
"ready":"Transcript Created",
- "textFileDescription":"This is the text transcript of a deleted ticket!",
- "htmlProgress":"Please wait while this html transcript is getting processed...",
-
- "createdChannel":"A new {0} transcript has been created in the server!",
- "createdCreator":"A new {0} transcript has been created for one of your tickets!",
- "createdParticipant":"A new {0} transcript has been created in one of the tickets you participated in!",
- "createdActiveAdmin":"A new {0} transcript has been created in one of the tickets you participated as admin!",
- "createdEveryAdmin":"A new {0} transcript has been created in one of the tickets you were admin in!",
- "createdOther":"A new {0} transcript has been created!"
+ "textFileDescription":"This is a text transcript of a deleted ticket.",
+ "htmlProgress":"Please wait while the HTML transcript is being generated...",
+
+ "createdChannel":"A new {0} transcript has been created in the server.",
+ "createdCreator":"A new {0} transcript has been created for one of your tickets.",
+ "createdParticipant":"A new {0} transcript has been created for a ticket you participated in.",
+ "createdActiveAdmin":"A new {0} transcript has been created for a ticket you participated in as an admin.",
+ "createdEveryAdmin":"A new {0} transcript has been created for a ticket you managed as an admin.",
+ "createdOther":"A new {0} transcript has been created."
},
"errors":{
"retry":"Retry",
"continue":"Delete Without Transcript",
"backup":"Create Backup Transcript",
- "error":"Something went wrong while trying to create the transcript.\nWhat would you like to do?\n\nThis ticket won't be deleted until you click one of these buttons.",
+ "error":"Something went wrong while creating the transcript.\nWhat would you like to do?\n\nThis ticket will not be deleted until you select one of the options below.",
"title":"Transcript Error"
},
"text":{
@@ -279,7 +279,7 @@
"fileTitle":"FILE",
"fieldsTitle":"FIELDS",
"reactionsTitle":"REACTIONS",
- "statsTitle":"STATS",
+ "statsTitle":"STATISTICS",
"emptyContent":"",
"noTitle":"",
"noDesc":""
@@ -302,68 +302,68 @@
"permissionError":"Permission Error"
},
"descriptions":{
- "askForInfo":"Contact the owner of this bot for more info!",
- "askForInfoResolve":"Contact the bot owner of this bot if this issue doesn't resolve after a few tries.",
- "internalError":"Failed to respond to this {0} due to an internal error!",
- "optionMissing":"A required parameter is missing in this command!",
- "optionInvalid":"A parameter in this command is invalid!",
- "optionInvalidChoose":"Choose between",
- "unknownCommand":"Try visiting the help menu for more info!",
- "noPermissions":"You are not allowed to use this {0}!",
- "noPermissionsList":"Required Permissions: (one of them)",
- "noPermissionsCooldown":"You are not allowed to use this {0} because you have a cooldown!",
- "noPermissionsBlacklist":"You are not allowed to use this {0} because you have been blacklisted!",
- "noPermissionsLimitGlobal":"You are not allowed to create a ticket because the server reached the max tickets limit!",
- "noPermissionsLimitGlobalUser":"You are not allowed to create a ticket because you reached the max tickets limit!",
- "noPermissionsLimitOption":"You are not allowed to create a ticket because the server reached the max tickets limit for this option!",
- "noPermissionsLimitOptionUser":"You are not allowed to create a ticket because you reached the max tickets limit for this option!",
- "unknownTicket":"Try this command again in a valid ticket!",
- "deprecatedTicket":"The current channel is not a valid ticket! It might have been a ticket from an old Open Ticket version!",
- "notInGuild":"This {0} doesn't work in DM! Please try it again in a server!",
- "channelRename":"Due to discord ratelimits, it's currently impossible for the bot to rename the channel. The channel will automatically be renamed over 10 minutes if the bot isn't rebooted.",
- "channelRenameSource":"The source of this error is: {0}",
- "busy":"Unable to use this {0}!\nThe ticket is currently being processed by the bot.\n\nPlease try again in a few seconds!",
- "closeBeforeMessage":"This ticket cannot be closed/deleted before a message has been sent by a user.",
- "closeBeforeAdminMessage":"This ticket cannot be closed/deleted before a message has been sent by a ticket admin or support member.",
- "unableToCreateTicket":"You are unable to create a ticket."
+ "askForInfo":"Please contact the bot owner for more information.",
+ "askForInfoResolve":"If the issue persists after a few attempts, please contact the bot owner.",
+ "internalError":"An internal error occurred while processing this {0}.",
+ "optionMissing":"A required parameter is missing for this command.",
+ "optionInvalid":"One or more parameters provided for this command are invalid.",
+ "optionInvalidChoose":"Please choose between",
+ "unknownCommand":"Please use the help menu for more information.",
+ "noPermissions":"You are not permitted to use this {0}.",
+ "noPermissionsList":"Required permissions (one of the following):",
+ "noPermissionsCooldown":"You cannot use this {0} while on cooldown.",
+ "noPermissionsBlacklist":"You cannot use this {0} because you are blacklisted.",
+ "noPermissionsLimitGlobal":"You cannot create a ticket because the server has reached its maximum ticket limit.",
+ "noPermissionsLimitGlobalUser":"You cannot create a ticket because you have reached your maximum ticket limit.",
+ "noPermissionsLimitOption":"You cannot create a ticket because the server has reached the maximum ticket limit for this option.",
+ "noPermissionsLimitOptionUser":"You cannot create a ticket because you have reached the maximum ticket limit for this option.",
+ "unknownTicket":"Please run this command inside a valid ticket channel.",
+ "deprecatedTicket":"This channel is not recognized as a valid ticket. It may have been created with an older version of the bot.",
+ "notInGuild":"This {0} cannot be used in direct messages. Please use it in a server.",
+ "channelRename":"Due to Discord rate limits, the channel could not be renamed immediately. It will be renamed automatically within 10 minutes if the bot remains online.",
+ "channelRenameSource":"Error source: {0}",
+ "busy":"This {0} is currently unavailable.\nThe ticket is being processed by the bot.\n\nPlease try again in a few seconds.",
+ "closeBeforeMessage":"This ticket cannot be closed or deleted before a user has sent a message.",
+ "closeBeforeAdminMessage":"This ticket cannot be closed or deleted before a support member or admin has sent a message.",
+ "unableToCreateTicket":"You are currently unable to create a ticket."
},
"optionInvalidReasons":{
- "stringRegex":"Value doesn't match pattern!",
- "stringMinLength":"Value needs to be at least {0} characters!",
- "stringMaxLength":"Value needs to be at most {0} characters!",
- "numberInvalid":"Invalid number!",
- "numberMin":"Number needs to be at least {0}!",
- "numberMax":"Number needs to be at most {0}!",
- "numberDecimal":"Number is not allowed to be a decimal!",
- "numberNegative":"Number is not allowed to be negative!",
- "numberPositive":"Number is not allowed to be positive!",
- "numberZero":"Number is not allowed to be zero!",
- "channelNotFound":"Unable to find channel!",
- "userNotFound":"Unable to find user!",
- "roleNotFound":"Unable to find role!",
- "memberNotFound":"Unable to find user!",
- "mentionableNotFound":"Unable to find user or role!",
- "channelType":"Invalid channel type!",
- "notInGuild":"This option requires you to be in a server!"
+ "stringRegex":"The value does not match the required pattern.",
+ "stringMinLength":"The value must be at least {0} characters long.",
+ "stringMaxLength":"The value must be at most {0} characters long.",
+ "numberInvalid":"Invalid number provided.",
+ "numberMin":"The number must be at least {0}.",
+ "numberMax":"The number must be at most {0}.",
+ "numberDecimal":"Decimals are not allowed.",
+ "numberNegative":"Negative numbers are not allowed.",
+ "numberPositive":"Positive numbers are not allowed.",
+ "numberZero":"Zero is not allowed.",
+ "channelNotFound":"Channel not found.",
+ "userNotFound":"User not found.",
+ "roleNotFound":"Role not found.",
+ "memberNotFound":"Member not found.",
+ "mentionableNotFound":"User or role not found.",
+ "channelType":"Invalid channel type.",
+ "notInGuild":"This option can only be used in a server."
},
"permissions":{
- "developer":"You need to be the developer of the bot.",
- "owner":"You need to be the server owner.",
- "admin":"You need to be a server admin.",
- "moderator":"You need to be a moderator.",
- "support":"You need to be in the support team.",
- "member":"You need to be a member.",
- "discord-administrator":"You need to have the `ADMINISTRATOR` permission."
+ "developer":"This action is restricted to the bot developer.",
+ "owner":"You must be the server owner to use this.",
+ "admin":"You must have administrator permissions to use this.",
+ "moderator":"You must be a moderator to use this.",
+ "support":"You must be part of the support team to use this.",
+ "member":"You must be a server member to use this.",
+ "discord-administrator":"You must have the `ADMINISTRATOR` permission."
},
"actionInvalid":{
- "close":"Ticket is already closed!",
- "reopen":"Ticket is not closed yet!",
- "claim":"Ticket is already claimed!",
- "unclaim":"Ticket is not claimed yet!",
- "pin":"Ticket is already pinned!",
- "unpin":"Ticket is not pinned yet!",
- "add":"This user is already able to access the ticket!",
- "remove":"Unable to remove this user from the ticket!"
+ "close":"This ticket is already closed.",
+ "reopen":"This ticket is not closed.",
+ "claim":"This ticket is already claimed.",
+ "unclaim":"This ticket is not claimed.",
+ "pin":"This ticket is already pinned.",
+ "unpin":"This ticket is not pinned.",
+ "add":"This user already has access to this ticket.",
+ "remove":"This user does not have access to this ticket."
}
},
"params":{
@@ -432,107 +432,107 @@
}
},
"commands":{
- "reason":"Specify an optional reason that will be visible in logs.",
- "help":"Get a list of all the available commands.",
- "panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
- "panelId":"The identifier of the panel that you want to spawn.",
- "panelAutoUpdate":"Do you want this panel to automatically update when edited?",
- "ticket":"Instantly create a ticket.",
- "ticketId":"The identifier of the ticket that you want to create.",
- "close":"Close a ticket.",
- "delete":"Delete a ticket.",
- "deleteNoTranscript":"Delete this ticket without creating a transcript.",
- "reopen":"Reopen a ticket.",
- "claim":"Claim a ticket.",
- "claimUser":"Claim this ticket to someone else instead of yourself.",
- "unclaim":"Unclaim a ticket.",
- "pin":"Pin a ticket.",
- "unpin":"Unpin a ticket.",
+ "reason":"Optional reason shown in logs.",
+ "help":"Display all available commands.",
+ "panel":"Create a ticket panel (buttons or dropdown).",
+ "panelId":"ID of the panel to spawn.",
+ "panelAutoUpdate":"Automatically update this panel when edited.",
+ "ticket":"Create a ticket instantly.",
+ "ticketId":"ID of the ticket to create.",
+ "close":"Close this ticket.",
+ "delete":"Delete this ticket.",
+ "deleteNoTranscript":"Delete ticket without saving a transcript.",
+ "reopen":"Reopen a closed ticket.",
+ "claim":"Claim this ticket.",
+ "claimUser":"Claim the ticket for another user.",
+ "unclaim":"Unclaim this ticket.",
+ "pin":"Pin this ticket.",
+ "unpin":"Unpin this ticket.",
- "move":"Move a ticket.",
- "moveId":"The identifier of the option that you want to move to.",
- "rename":"Rename a ticket.",
- "renameName":"The new name for this ticket.",
- "add":"Add a user to a ticket.",
- "addUser":"The user to add.",
- "remove":"Remove a user from a ticket.",
- "removeUser":"The user to remove.",
+ "move":"Move ticket to another option.",
+ "moveId":"Target option ID.",
+ "rename":"Rename this ticket.",
+ "renameName":"New name for the ticket.",
+ "add":"Add a user to this ticket.",
+ "addUser":"User to add.",
+ "remove":"Remove a user from this ticket.",
+ "removeUser":"User to remove.",
- "blacklist":"Manage the ticket blacklist.",
- "blacklistView":"View a list of the current blacklist.",
+ "blacklist":"Manage the blacklist.",
+ "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.",
- "blacklistGet":"Get the details from a blacklisted user.",
- "blacklistGetUser":"The user to get details from.",
- "stats":"View statistics from the bot, a member or a ticket.",
- "statsReset":"Reset all the stats of the bot (and start counting from zero).",
- "statsGlobal":"View the global stats.",
- "statsUser":"View the stats from a user in the server.",
- "statsUserUser":"The user to view.",
- "statsTicket":"View the stats of a ticket in the server.",
- "statsTicketTicket":"The ticket to view.",
+ "blacklistGet":"View blacklist entry details.",
+ "blacklistGetUser":"User to look up.",
+ "stats":"View bot, user or ticket statistics.",
+ "statsReset":"Reset all bot statistics.",
+ "statsGlobal":"View global bot statistics.",
+ "statsUser":"View a user's statistics.",
+ "statsUserUser":"User to view.",
+ "statsTicket":"View ticket statistics.",
+ "statsTicketTicket":"Ticket to view.",
- "clear":"Delete multiple tickets at the same time.",
- "clearFilter":"The filter for clearing tickets.",
+ "clear":"Delete multiple tickets at once.",
+ "clearFilter":"Filter used when clearing tickets.",
"clearFilters":{
- "all":"All",
- "open":"Open",
- "close":"Closed",
- "claim":"Claimed",
- "unclaim":"Unclaimed",
- "pin":"Pinned",
- "unpin":"Unpinned",
- "autoclose":"Autoclosed"
+ "all":"All tickets",
+ "open":"Open tickets",
+ "close":"Closed tickets",
+ "claim":"Claimed tickets",
+ "unclaim":"Unclaimed tickets",
+ "pin":"Pinned tickets",
+ "unpin":"Unpinned tickets",
+ "autoclose":"Autoclosed tickets"
},
- "autoclose":"Manage autoclose in a ticket.",
- "autocloseDisable":"Disable autoclose in this ticket.",
- "autocloseEnable":"Enable autoclose in this ticket.",
- "autocloseEnableTime":"The amount of hours this ticket needs to be inactive to close it.",
- "autodelete":"Manage autodelete in a ticket.",
- "autodeleteDisable":"Disable autodelete in this ticket.",
- "autodeleteEnable":"Enable autodelete in this ticket.",
- "autodeleteEnableTime":"The amount of days this ticket needs to be inactive to delete it.",
+ "autoclose":"Manage ticket autoclose.",
+ "autocloseDisable":"Disable autoclose.",
+ "autocloseEnable":"Enable autoclose.",
+ "autocloseEnableTime":"Hours of inactivity before closing.",
+ "autodelete":"Manage ticket autodelete.",
+ "autodeleteDisable":"Disable autodelete.",
+ "autodeleteEnable":"Enable autodelete.",
+ "autodeleteEnableTime":"Days of inactivity before deletion.",
- "topic":"Manage the topic of the ticket channel.",
- "topicSet":"Set the topic of the ticket channel.",
- "topicValue":"The new topic of the channel.",
- "topicList":"Get a list of all tickets with their topic and stats.",
- "priority":"Manage the priority of the ticket.",
- "prioritySet":"Set the priority of the ticket.",
- "priorityValue":"The priority of the channel.",
- "priorityGet":"Get the priority of the ticket.",
- "priorityList":"Get a list of all tickets with their priority status.",
- "transfer":"Transfer the ticket ownership from one user to another.",
- "transferUser":"The user to transfer to."
+ "topic":"Manage ticket channel topic.",
+ "topicSet":"Set the ticket channel topic.",
+ "topicValue":"New channel topic text.",
+ "topicList":"List all ticket channel topics.",
+ "priority":"Manage ticket priority.",
+ "prioritySet":"Set ticket priority.",
+ "priorityValue":"Priority level.",
+ "priorityGet":"View ticket priority.",
+ "priorityList":"List all ticket priorities.",
+ "transfer":"Transfer ticket ownership.",
+ "transferUser":"User to transfer to."
},
"helpMenu":{
- "help":"Get a list of all the available commands.",
- "ticket":"Instantly create a ticket.",
- "close":"Close a ticket, this disables writing in this channel.",
- "delete":"Delete a ticket, this creates a transcript when enabled.",
- "reopen":"Reopen a ticket, this enables writing in this channel again.",
- "pin":"Pin a ticket. This will move the ticket to the top and will add a '📌' emoij to the name.",
- "unpin":"Unpin a ticket. The ticket will stay on it's position but will lose the '📌' emoij.",
- "move":"Move a ticket. This will change the type of this ticket.",
- "rename":"Rename a ticket. This will change the channel name of this ticket.",
- "claim":"Claim a ticket. With this, you can let your team know you are handling this ticket.",
- "unclaim":"Unclaim a ticket. With this, you can let your team know that this ticket is free again.",
- "add":"Add a user to a ticket. This will allow the user to read & write in this ticket.",
- "remove":"Remove a user from a ticket. This will remove the ability to read & write for a user in this ticket.",
- "panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
- "blacklistView":"View a list of the current blacklist.",
+ "help":"View all available commands.",
+ "ticket":"Create a ticket instantly.",
+ "close":"Close this ticket and disable messaging in the channel.",
+ "delete":"Delete this ticket (creates a transcript if enabled).",
+ "reopen":"Reopen a closed ticket and restore messaging.",
+ "pin":"Pin this ticket and move it to the top with '📌'.",
+ "unpin":"Unpin this ticket and remove the '📌' emoji.",
+ "move":"Move this ticket to a different option or ticket type.",
+ "rename":"Rename this ticket channel.",
+ "claim":"Claim this ticket to show you are handling it.",
+ "unclaim":"Unclaim this ticket to mark it as available.",
+ "add":"Add a user to this ticket.",
+ "remove":"Remove a user's access from this ticket.",
+ "panel":"Create a ticket panel with buttons or a dropdown.",
+ "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.",
- "blacklistGet":"Get the details from a blacklisted user.",
- "statsGlobal":"View the global stats.",
- "statsTicket":"View the stats of a ticket in the server.",
- "statsUser":"View the stats from a user in the server.",
- "statsReset":"Reset all the stats of the bot (and start counting from zero).",
- "autocloseDisable":"Disable autoclose in this ticket.",
- "autocloseEnable":"Enable autoclose in this ticket.",
- "autodeleteDisable":"Disable autodelete in this ticket.",
- "autodeleteEnable":"Enable autodelete in this ticket.",
+ "blacklistGet":"View details of a blacklisted user.",
+ "statsGlobal":"View global bot statistics.",
+ "statsTicket":"View statistics for a ticket.",
+ "statsUser":"View statistics for a user.",
+ "statsReset":"Reset all bot statistics.",
+ "autocloseDisable":"Disable autoclose for this ticket.",
+ "autocloseEnable":"Enable autoclose for this ticket.",
+ "autodeleteDisable":"Disable autodelete for this ticket.",
+ "autodeleteEnable":"Enable autodelete for this ticket.",
"categories":{
"general":"General Commands",
"basicTicket":"Basic Ticket Commands",
@@ -545,10 +545,10 @@
},
"stats":{
"scopes":{
- "global":"Global Stats",
- "system":"System Stats",
- "user":"User Stats",
- "ticket":"Ticket Stats",
+ "global":"Global Statistics",
+ "system":"System Statistics",
+ "user":"User Statistics",
+ "ticket":"Ticket Statistics",
"participants":"Participants",
"messages":"Messages"
},
@@ -592,9 +592,9 @@
}
},
"panel":{
- "selectTicket":"Select your ticket",
- "selectRole":"Select your role",
- "selectOption":"Select your option"
+ "selectTicket":"Select a ticket",
+ "selectRole":"Select a role",
+ "selectOption":"Select an option"
},
"priorities":{
"urgent":"Urgent",
diff --git a/languages/czech.json b/languages/czech.json
index ef4a93a..03b8bc3 100644
--- a/languages/czech.json
+++ b/languages/czech.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["spyeye_"],
"lastedited":"16/02/2026",
"language":"Czech",
diff --git a/languages/danish.json b/languages/danish.json
index 4f93fed..ab42fd0 100644
--- a/languages/danish.json
+++ b/languages/danish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["the_gamer"],
"lastedited":"16/02/2026",
"language":"Danish",
diff --git a/languages/dutch.json b/languages/dutch.json
index f13ddfc..9c19866 100644
--- a/languages/dutch.json
+++ b/languages/dutch.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["DJj123dj"],
"lastedited":"16/02/2026",
"language":"Dutch",
diff --git a/languages/english.json b/languages/english.json
index a833cf8..7244893 100644
--- a/languages/english.json
+++ b/languages/english.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["DJj123dj"],
"lastedited":"16/02/2026",
"language":"English",
@@ -13,94 +13,94 @@
"typeWarning":"[WARNING]",
"typeInfo":"[INFO]",
"headerConfigChecker":"CONFIG CHECKER",
- "headerDescription":"check for errors in your config files!",
- "footerError":"the bot won't start until all {0}'s are fixed!",
- "footerWarning":"it's recommended to fix all {0}'s before starting!",
+ "headerDescription":"Validating config files...",
+ "footerError":"The bot will not start until all {0}'s are resolved.",
+ "footerWarning":"The bot may behave unexpectedly until all {0}'s are resolved.",
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
- "compactInformation":"use {0} for more information!",
+ "compactInformation":"Use {0} for a detailed config report.",
"dataPath":"path",
"dataDocs":"docs",
"dataMessages":"message"
},
"messages":{
- "stringTooShort":"This string can't be shorter than {0} characters!",
- "stringTooLong":"This string can't be longer than {0} characters!",
- "stringLengthInvalid":"This string needs to be {0} characters long!",
- "stringStartsWith":"This string needs to start with {0}!",
- "stringEndsWith":"This string needs to end with {0}!",
- "stringContains":"This string needs to contain {0}!",
- "stringChoices":"This string can only be one of the following values: {0}!",
- "stringRegex":"This string is invalid!",
- "stringInvertedContains":"This string is not allowed to contain {0}!",
- "stringLowercase":"This string must be written in lowercase only!",
- "stringUppercase":"This string must be written in uppercase only!",
- "stringSpecialCharacters":"This string is not allowed to contain any special characters! (a-z, 0-9 & space only)",
- "stringNoSpaces":"This string is not allowed to contain spaces!",
- "stringCapitalWord":"It's recommended that each word in this string starts with a capital letter!",
- "stringCapitalSentence":"It looks like some sentences in this string don't start with a capital letter!",
- "stringPunctuation":"It looks like the sentence in this string doesn't end with a punctuation mark!",
+ "stringTooShort":"Text must be at least {0} characters long",
+ "stringTooLong":"Text must be no longer than {0} characters",
+ "stringLengthInvalid":"Text must be exactly {0} characters long",
+ "stringStartsWith":"Text must start with {0}",
+ "stringEndsWith":"Text must end with {0}",
+ "stringContains":"Text must contain {0}",
+ "stringChoices":"Text must be one of the following: {0}",
+ "stringRegex":"Text does not match the required format",
+ "stringInvertedContains":"Text must not contain {0}",
+ "stringLowercase":"Text must be entirely lowercase",
+ "stringUppercase":"Text must be entirely uppercase",
+ "stringSpecialCharacters":"Text must only contain letters (a–z), numbers (0–9), and spaces",
+ "stringNoSpaces":"Text must not contain spaces",
+ "stringCapitalWord":"Each word in this value should start with a capital letter",
+ "stringCapitalSentence":"One or more sentences in this value do not start with a capital letter",
+ "stringPunctuation":"The sentence in this value does not end with a punctuation mark",
- "numberTooShort":"This number can't be shorter than {0} characters!",
- "numberTooLong":"This number can't be longer than {0} characters!",
- "numberLengthInvalid":"This number needs to be {0} characters long!",
- "numberTooSmall":"This number needs to be at least {0}!",
- "numberTooLarge":"This number needs to be at most {0}!",
- "numberNotEqual":"This number needs to be {0}!",
- "numberStep":"This number needs to be a multiple of {0}!",
- "numberStepOffset":"This number needs to be a multiple of {0} starting with {1}!",
- "numberStartsWith":"This number needs to start with {0}!",
- "numberEndsWith":"This number needs to end with {0}!",
- "numberContains":"This number needs to contain {0}!",
- "numberChoices":"This number can only be one of the following values: {0}!",
- "numberFloat":"This number can't be a decimal!",
- "numberNegative":"This number can't be negative!",
- "numberPositive":"This number can't be positive!",
- "numberZero":"This number can't be zero!",
- "numberNan":"This number can't be NaN (Not A Number)!",
- "numberInvertedContains":"This number is not allowed to contain {0}!",
+ "numberTooShort":"Number must be at least {0} digits long",
+ "numberTooLong":"Number must be no longer than {0} digits",
+ "numberLengthInvalid":"Number must be exactly {0} digits long",
+ "numberTooSmall":"Number must be at least {0}",
+ "numberTooLarge":"Number must be at most {0}",
+ "numberNotEqual":"Number must be exactly {0}",
+ "numberStep":"Number must be a multiple of {0}",
+ "numberStepOffset":"Number must be a multiple of {0}, starting from {1}",
+ "numberStartsWith":"Number must start with {0}",
+ "numberEndsWith":"Number must end with {0}",
+ "numberContains":"Number must contain {0}",
+ "numberChoices":"Number must be one of the following: {0}",
+ "numberFloat":"Number must be a whole number",
+ "numberNegative":"Number must be a positive number",
+ "numberPositive":"Number must be a negative number",
+ "numberZero":"Number must not be zero",
+ "numberNan":"Number must be a valid number",
+ "numberInvertedContains":"Number must not contain {0}",
- "booleanTrue":"This boolean can't be true!",
- "booleanFalse":"This boolean can't be false!",
+ "booleanTrue":"Boolean must be false",
+ "booleanFalse":"Boolean must be true",
+
+ "arrayEmptyDisabled":"List must not be empty",
+ "arrayEmptyRequired":"List must be empty",
+ "arrayTooShort":"List must have at least {0} items",
+ "arrayTooLong":"List must have at most {0} items",
+ "arrayLengthInvalid":"List must have exactly {0} items",
+ "arrayInvalidTypes":"List may only contain the following types: {0}",
+ "arrayDouble":"List must not contain duplicate values",
+
+ "discordInvalidId":"Invalid Discord {0} ID",
+ "discordInvalidIdOptions":"Invalid Discord {0} ID. Alternatively, use one of the following: {1}",
+ "discordInvalidToken":"Invalid Discord token",
+ "colorInvalid":"Invalid hex color",
+ "emojiTooShort":"Value must contain at least {0} emoji",
+ "emojiTooLong":"Value must contain at most {0} emoji",
+ "emojiCustom":"Custom Discord emojis are not allowed here",
+ "emojiInvalid":"Invalid emoji",
+ "urlInvalid":"Invalid URL",
+ "urlInvalidHttp":"URL must use the https:// protocol",
+ "urlInvalidProtocol":"URL must use the http:// or https:// protocol",
+ "urlInvalidHostname":"URL hostname is not allowed",
+ "urlInvalidExtension":"Invalid URL extension. Allowed extensions: {0}",
+ "urlInvalidPath":"Invalid URL path",
+ "idNotUnique":"This ID is already in use. Please choose a unique ID",
+ "idNonExistent":"ID {0} does not exist",
+
+ "invalidType":"Property must be of type: {0}",
+ "propertyMissing":"Required property {0} is missing from the object",
+ "propertyOptional":"Property {0} is optional in the object",
+ "objectDisabled":"This object is disabled. Enable it using {0}",
+ "nullInvalid":"Property must not be null",
+ "switchInvalidType":"Value must be one of the following types: {0}",
+ "objectSwitchInvalid":"Object must be one of the following types: {0}",
- "arrayEmptyDisabled":"This array isn't allowed to be empty!",
- "arrayEmptyRequired":"This array is required to be empty!",
- "arrayTooShort":"This array needs to have a length of at least {0}!",
- "arrayTooLong":"This array needs to have a length of at most {0}!",
- "arrayLengthInvalid":"This array needs to have a length of {0}!",
- "arrayInvalidTypes":"This array can only contain the following types: {0}!",
- "arrayDouble":"This array doesn't allow the same value twice!",
-
- "discordInvalidId":"This is an invalid discord {0} id!",
- "discordInvalidIdOptions":"This is an invalid discord {0} id! You can also use one of these: {1}!",
- "discordInvalidToken":"This is an invalid discord token (syntactically)!",
- "colorInvalid":"This is an invalid hex color!",
- "emojiTooShort":"This string needs to have at least {0} emoji's!",
- "emojiTooLong":"This string needs to have at most {0} emoji's!",
- "emojiCustom":"This emoji can't be a custom discord emoji!",
- "emojiInvalid":"This is an invalid emoji!",
- "urlInvalid":"This url is invalid!",
- "urlInvalidHttp":"This url can only use the https:// protocol!",
- "urlInvalidProtocol":"This url can only use the http:// & https:// protocols!",
- "urlInvalidHostname":"This url has a disallowed hostname!",
- "urlInvalidExtension":"This url has an invalid extension! Choose between: {0}!",
- "urlInvalidPath":"This url has an invalid path!",
- "idNotUnique":"This id isn't unique, use another id instead!",
- "idNonExistent":"The id {0} doesn't exist!",
-
- "invalidType":"This property needs to be the type: {0}!",
- "propertyMissing":"The property {0} is missing from this object!",
- "propertyOptional":"The property {0} is optional in this object!",
- "objectDisabled":"This object is disabled, enable it using {0}!",
- "nullInvalid":"This property can't be null!",
- "switchInvalidType":"This needs to be one of the following types: {0}!",
- "objectSwitchInvalid":"This object needs to be one of the following types: {0}!",
-
- "invalidLanguage":"This is an invalid language!",
- "invalidButton":"This button needs to have at least an {0} or {1}!",
- "unusedOption":"The option {0} isn't used anywhere!",
- "unusedQuestion":"The question {0} isn't used anywhere!",
- "dropdownOption":"A panel with dropdown enabled can only contain options of the 'ticket' type!",
- "customInvalidVersion":"The version specified in your config does not match! Make sure you have updated the config to the latest version!"
+ "invalidLanguage":"Invalid language",
+ "invalidButton":"Button must have at least an {0} or {1}",
+ "unusedOption":"Option {0} is not used anywhere",
+ "unusedQuestion":"Question {0} is not used anywhere",
+ "dropdownOption":"Panels with dropdown enabled may only contain options of the 'ticket' type",
+ "customInvalidVersion":"Config version mismatch. Make sure to update your config to the latest version"
}
},
"actions":{
@@ -159,118 +159,118 @@
"transfer":"Ticket Transferred"
},
"descriptions":{
- "create":"Your ticket has been created. Click the button below to access it!",
- "close":"The ticket has been closed successfully!",
- "delete":"The ticket has been deleted successfully!",
- "reopen":"The ticket has been reopened successfully!",
- "claim":"The ticket has been claimed successfully!",
- "unclaim":"The ticket has been unclaimed successfully!",
- "pin":"The ticket has been pinned successfully!",
- "unpin":"The ticket has been unpinned successfully!",
- "rename":"The ticket has been renamed to {0} successfully!",
- "move":"The ticket has been moved to {0} successfully!",
- "add":"{0} has been added to the ticket successfully!",
- "remove":"{0} has been removed from the ticket successfully!",
+ "create":"Your ticket is ready. Click the button below to view and continue.",
+ "close":"The ticket has been closed.",
+ "delete":"The ticket has been deleted.",
+ "reopen":"The ticket has been reopened.",
+ "claim":"The ticket has been claimed.",
+ "unclaim":"The ticket has been unclaimed.",
+ "pin":"The ticket has been pinned.",
+ "unpin":"The ticket has been unpinned.",
+ "rename":"The ticket has been renamed to {0}.",
+ "move":"The ticket has been moved to {0}.",
+ "add":"{0} has been added to the ticket.",
+ "remove":"{0} has been removed from the ticket.",
"helpExplanation":"`` => required parameter\n`[name]` => optional parameter",
- "statsReset":"The bot stats have been reset successfully!",
- "statsError":"Unable to view ticket stats!\n{0} is not a ticket!",
- "blacklistAdd":"{0} has been blacklisted successfully!",
- "blacklistRemove":"{0} has been released successfully!",
- "blacklistGetSuccess":"{0} is currently blacklisted!",
- "blacklistGetEmpty":"{0} is currently not blacklisted!",
- "blacklistViewEmpty":"No-one has been blacklisted yet!",
- "blacklistViewTip":"Use \"/blacklist add\" to blacklist a user!",
- "clearVerify":"Are you sure you want to delete multiple tickets?\nThis action can't be undone!",
- "clearReady":"{0} tickets have been deleted successfully!",
- "rolesEmpty":"No roles have been updated!",
+ "statsReset":"The bot statistics have been reset.",
+ "statsError":"Unable to retrieve ticket statistics.\n{0} is not a valid ticket.",
+ "blacklistAdd":"{0} has been blacklisted.",
+ "blacklistRemove":"{0} has been released.",
+ "blacklistGetSuccess":"{0} is blacklisted!",
+ "blacklistGetEmpty":"{0} is not blacklisted!",
+ "blacklistViewEmpty":"No users have been blacklisted yet.",
+ "blacklistViewTip":"Use \"/blacklist add\" to add a user to the blacklist.",
+ "clearVerify":"Are you sure you want to delete multiple tickets?\nThis action cannot be undone.",
+ "clearReady":"{0} ticket(s) have been deleted.",
+ "rolesEmpty":"No roles were modified.",
- "autocloseLeave":"This ticket has been autoclosed because the creator left the server!",
- "autocloseTimeout":"This ticket has been autoclosed because it has been inactive for more than `{0}h`!",
- "autodeleteLeave":"This ticket has been autodeleted because the creator left the server!",
- "autodeleteTimeout":"This ticket has been autodeleted because it has been inactive for more than `{0} days`!",
- "autocloseEnabled":"Autoclose has been enabled in this ticket!\nIt will be closed when it is inactive for more than `{0}h`!",
- "autocloseDisabled":"Autoclose has been disabled in this ticket!\nIt won't be closed automatically anymore!",
- "autodeleteEnabled":"Autodelete has been enabled in this ticket!\nIt will be deleted when it is inactive for more than `{0} days`!",
- "autodeleteDisabled":"Autodelete has been disabled in this ticket!\nIt won't be deleted automatically anymore!",
+ "autocloseLeave":"This ticket was automatically closed because its creator left the server.",
+ "autocloseTimeout":"This ticket was automatically closed due to inactivity exceeding `{0}h`.",
+ "autodeleteLeave":"This ticket was automatically deleted because its creator left the server.",
+ "autodeleteTimeout":"This ticket was automatically deleted due to inactivity exceeding `{0} days`.",
+ "autocloseEnabled":"Autoclose has been enabled for this ticket.\nIt will close after `{0}h` of inactivity.",
+ "autocloseDisabled":"Autoclose has been disabled for this ticket.\nThis ticket will no longer close automatically.",
+ "autodeleteEnabled":"Autodelete has been enabled for this ticket.\nIt will be deleted after `{0} days` of inactivity.",
+ "autodeleteDisabled":"Autodelete has been disabled for this ticket.\nThis ticket will no longer be deleted automatically.",
- "ticketMessageLimit":"You can only create {0} ticket(s) at the same time!",
- "ticketMessageAutoclose":"This ticket will be autoclosed when inactive for {0}h!",
- "ticketMessageAutodelete":"This ticket will be autodeleted when inactive for {0} days!",
- "panelReady":"The panel is available in the followup message!\nThis message can now be deleted!",
+ "ticketMessageLimit":"You can only have {0} active ticket(s) at a time.",
+ "ticketMessageAutoclose":"This ticket will automatically close after `{0}h` of inactivity.",
+ "ticketMessageAutodelete":"This ticket will automatically be deleted after `{0} days` of inactivity.",
+ "panelReady":"The panel has been sent in the follow-up message.\nYou may now delete this message.",
- "topicSet":"The channel topic has been changed by {0} successfully!",
- "prioritySet":"The ticket priority has been changed to {0} by {1} successfully!",
- "priorityGet":"The current priority of this ticket is {0}.",
- "transfer":"The ticket ownership has been transferred from {0} to {1} by {2} successfully!"
+ "topicSet":"The channel topic has been changed by {0}.",
+ "prioritySet":"The ticket priority has been changed to {0} by {1}.",
+ "priorityGet":"The priority of this ticket is {0}.",
+ "transfer":"The ticket ownership has been transferred from {0} to {1} by {2}."
},
"modal":{
- "closePlaceholder":"Why did you close this ticket?",
- "deletePlaceholder":"Why did you delete this ticket?",
- "reopenPlaceholder":"Why did you reopen this ticket?",
- "claimPlaceholder":"Why did you claim this ticket?",
- "unclaimPlaceholder":"Why did you unclaim this ticket?",
- "pinPlaceholder":"Why did you pin this ticket?",
- "unpinPlaceholder":"Why did you unpin this ticket?"
+ "closePlaceholder":"Why would you like to close this ticket?",
+ "deletePlaceholder":"Why would you like to delete this ticket?",
+ "reopenPlaceholder":"Why would you like to reopen this ticket?",
+ "claimPlaceholder":"Why would you like to claim this ticket?",
+ "unclaimPlaceholder":"Why would you like to unclaim this ticket?",
+ "pinPlaceholder":"Why would you like to pin this ticket?",
+ "unpinPlaceholder":"Why would you like to unpin this ticket?"
},
"logs":{
- "createLog":"A new ticket got created by {0}!",
- "closeLog":"This ticket has been closed by {0}!",
- "closeDm":"Your ticket has been closed in our server!",
- "deleteLog":"This ticket has been deleted by {0}!",
- "deleteDm":"Your ticket has been deleted in our server!",
- "reopenLog":"This ticket has been reopened by {0}!",
- "reopenDm":"Your ticket has been reopened in our server!",
- "claimLog":"This ticket has been claimed by {0}!",
- "claimDm":"Your ticket has been claimed in our server!",
- "unclaimLog":"This ticket has been unclaimed by {0}!",
- "unclaimDm":"Your ticket has been unclaimed in our server!",
- "pinLog":"This ticket has been pinned by {0}!",
- "pinDm":"Your ticket has been pinned in our server!",
- "unpinLog":"This ticket has been unpinned by {0}!",
- "unpinDm":"Your ticket has been unpinned in our server!",
- "renameLog":"This ticket has been renamed to {0} by {1}!",
- "renameDm":"Your ticket has been renamed to {0} in our server!",
- "moveLog":"This ticket has been moved to {0} by {1}!",
- "moveDm":"Your ticket has been moved to {0} in our server!",
- "addLog":"{0} has been added to this ticket by {1}!",
- "addDm":"{0} has been added to your ticket in our server!",
- "removeLog":"{0} has been removed from this ticket by {1}!",
- "removeDm":"{0} has been removed from your ticket in our server!",
+ "createLog":"A new ticket got created by {0}.",
+ "closeLog":"This ticket has been closed by {0}.",
+ "closeDm":"Your ticket has been closed.",
+ "deleteLog":"This ticket has been deleted by {0}.",
+ "deleteDm":"Your ticket has been deleted.",
+ "reopenLog":"This ticket has been reopened by {0}.",
+ "reopenDm":"Your ticket has been reopened.",
+ "claimLog":"This ticket has been claimed by {0}.",
+ "claimDm":"Your ticket has been claimed.",
+ "unclaimLog":"This ticket has been unclaimed by {0}.",
+ "unclaimDm":"Your ticket has been unclaimed.",
+ "pinLog":"This ticket has been pinned by {0}.",
+ "pinDm":"Your ticket has been pinned.",
+ "unpinLog":"This ticket has been unpinned by {0}.",
+ "unpinDm":"Your ticket has been unpinned.",
+ "renameLog":"This ticket has been renamed to {0} by {1}.",
+ "renameDm":"Your ticket has been renamed to {0}.",
+ "moveLog":"This ticket has been moved to {0} by {1}.",
+ "moveDm":"Your ticket has been moved to {0}.",
+ "addLog":"{0} has been added to this ticket by {1}.",
+ "addDm":"{0} has been added to your ticket.",
+ "removeLog":"{0} has been removed from this ticket by {1}.",
+ "removeDm":"{0} has been removed from your ticket.",
- "blacklistAddLog":"{0} was blacklisted by {1}!",
- "blacklistRemoveLog":"{0} was removed from the blacklist by {1}!",
- "blacklistAddDm":"You have been blacklisted in our server!\nFrom now on, you are unable to create a ticket!",
- "blacklistRemoveDm":"You have been removed from the blacklist in our server!\nNow you can create tickets again!",
- "clearLog":"{0} tickets have been deleted by {1}!",
+ "blacklistAddLog":"{0} has been blacklisted by {1}.",
+ "blacklistRemoveLog":"{0} has been removed from the blacklist by {1}.",
+ "blacklistAddDm":"You have been blacklisted from this server.\nYou are no longer able to create tickets.",
+ "blacklistRemoveDm":"You have been removed from the blacklist.\nYou can now create tickets again.",
+ "clearLog":"{0} ticket(s) have been deleted by {1}.",
- "transferLog":"The ownership of this ticket has been transferred from {0} to {1} by {2}!",
- "transferDm":"The ownership of your ticket has been transferred from {0} to {1} in our server!",
- "prioritySetLog":"The priority of this ticket has been changed to {0} by {1}!",
- "prioritySetDm":"The priority of your ticket has been changed to {0} in our server!",
- "roleUpdateLog":"{0} has updated their roles!",
- "roleUpdateDm":"Your roles in our server have been updated!"
+ "transferLog":"Ticket ownership has been transferred from {0} to {1} by {2}.",
+ "transferDm":"Ownership of your ticket has been transferred from {0} to {1}.",
+ "prioritySetLog":"The priority of this ticket has been set to {0} by {1}.",
+ "prioritySetDm":"The priority of your ticket has been set to {0}.",
+ "roleUpdateLog":"{0} has modified their roles.",
+ "roleUpdateDm":"Your roles have been modified."
}
},
"transcripts":{
"success":{
"visit":"Visit Transcript",
"ready":"Transcript Created",
- "textFileDescription":"This is the text transcript of a deleted ticket!",
- "htmlProgress":"Please wait while this html transcript is getting processed...",
-
- "createdChannel":"A new {0} transcript has been created in the server!",
- "createdCreator":"A new {0} transcript has been created for one of your tickets!",
- "createdParticipant":"A new {0} transcript has been created in one of the tickets you participated in!",
- "createdActiveAdmin":"A new {0} transcript has been created in one of the tickets you participated as admin!",
- "createdEveryAdmin":"A new {0} transcript has been created in one of the tickets you were admin in!",
- "createdOther":"A new {0} transcript has been created!"
+ "textFileDescription":"This is a text transcript of a deleted ticket.",
+ "htmlProgress":"Please wait while the HTML transcript is being generated...",
+
+ "createdChannel":"A new {0} transcript has been created in the server.",
+ "createdCreator":"A new {0} transcript has been created for one of your tickets.",
+ "createdParticipant":"A new {0} transcript has been created for a ticket you participated in.",
+ "createdActiveAdmin":"A new {0} transcript has been created for a ticket you participated in as an admin.",
+ "createdEveryAdmin":"A new {0} transcript has been created for a ticket you managed as an admin.",
+ "createdOther":"A new {0} transcript has been created."
},
"errors":{
"retry":"Retry",
"continue":"Delete Without Transcript",
"backup":"Create Backup Transcript",
- "error":"Something went wrong while trying to create the transcript.\nWhat would you like to do?\n\nThis ticket won't be deleted until you click one of these buttons.",
+ "error":"Something went wrong while creating the transcript.\nWhat would you like to do?\n\nThis ticket will not be deleted until you select one of the options below.",
"title":"Transcript Error"
},
"text":{
@@ -279,7 +279,7 @@
"fileTitle":"FILE",
"fieldsTitle":"FIELDS",
"reactionsTitle":"REACTIONS",
- "statsTitle":"STATS",
+ "statsTitle":"STATISTICS",
"emptyContent":"",
"noTitle":"",
"noDesc":""
@@ -302,68 +302,68 @@
"permissionError":"Permission Error"
},
"descriptions":{
- "askForInfo":"Contact the owner of this bot for more info!",
- "askForInfoResolve":"Contact the bot owner of this bot if this issue doesn't resolve after a few tries.",
- "internalError":"Failed to respond to this {0} due to an internal error!",
- "optionMissing":"A required parameter is missing in this command!",
- "optionInvalid":"A parameter in this command is invalid!",
- "optionInvalidChoose":"Choose between",
- "unknownCommand":"Try visiting the help menu for more info!",
- "noPermissions":"You are not allowed to use this {0}!",
- "noPermissionsList":"Required Permissions: (one of them)",
- "noPermissionsCooldown":"You are not allowed to use this {0} because you have a cooldown!",
- "noPermissionsBlacklist":"You are not allowed to use this {0} because you have been blacklisted!",
- "noPermissionsLimitGlobal":"You are not allowed to create a ticket because the server reached the max tickets limit!",
- "noPermissionsLimitGlobalUser":"You are not allowed to create a ticket because you reached the max tickets limit!",
- "noPermissionsLimitOption":"You are not allowed to create a ticket because the server reached the max tickets limit for this option!",
- "noPermissionsLimitOptionUser":"You are not allowed to create a ticket because you reached the max tickets limit for this option!",
- "unknownTicket":"Try this command again in a valid ticket!",
- "deprecatedTicket":"The current channel is not a valid ticket! It might have been a ticket from an old Open Ticket version!",
- "notInGuild":"This {0} doesn't work in DM! Please try it again in a server!",
- "channelRename":"Due to discord ratelimits, it's currently impossible for the bot to rename the channel. The channel will automatically be renamed over 10 minutes if the bot isn't rebooted.",
- "channelRenameSource":"The source of this error is: {0}",
- "busy":"Unable to use this {0}!\nThe ticket is currently being processed by the bot.\n\nPlease try again in a few seconds!",
- "closeBeforeMessage":"This ticket cannot be closed/deleted before a message has been sent by a user.",
- "closeBeforeAdminMessage":"This ticket cannot be closed/deleted before a message has been sent by a ticket admin or support member.",
- "unableToCreateTicket":"You are unable to create a ticket."
+ "askForInfo":"Please contact the bot owner for more information.",
+ "askForInfoResolve":"If the issue persists after a few attempts, please contact the bot owner.",
+ "internalError":"An internal error occurred while processing this {0}.",
+ "optionMissing":"A required parameter is missing for this command.",
+ "optionInvalid":"One or more parameters provided for this command are invalid.",
+ "optionInvalidChoose":"Please choose between",
+ "unknownCommand":"Please use the help menu for more information.",
+ "noPermissions":"You are not permitted to use this {0}.",
+ "noPermissionsList":"Required permissions (one of the following):",
+ "noPermissionsCooldown":"You cannot use this {0} while on cooldown.",
+ "noPermissionsBlacklist":"You cannot use this {0} because you are blacklisted.",
+ "noPermissionsLimitGlobal":"You cannot create a ticket because the server has reached its maximum ticket limit.",
+ "noPermissionsLimitGlobalUser":"You cannot create a ticket because you have reached your maximum ticket limit.",
+ "noPermissionsLimitOption":"You cannot create a ticket because the server has reached the maximum ticket limit for this option.",
+ "noPermissionsLimitOptionUser":"You cannot create a ticket because you have reached the maximum ticket limit for this option.",
+ "unknownTicket":"Please run this command inside a valid ticket channel.",
+ "deprecatedTicket":"This channel is not recognized as a valid ticket. It may have been created with an older version of the bot.",
+ "notInGuild":"This {0} cannot be used in direct messages. Please use it in a server.",
+ "channelRename":"Due to Discord rate limits, the channel could not be renamed immediately. It will be renamed automatically within 10 minutes if the bot remains online.",
+ "channelRenameSource":"Error source: {0}",
+ "busy":"This {0} is currently unavailable.\nThe ticket is being processed by the bot.\n\nPlease try again in a few seconds.",
+ "closeBeforeMessage":"This ticket cannot be closed or deleted before a user has sent a message.",
+ "closeBeforeAdminMessage":"This ticket cannot be closed or deleted before a support member or admin has sent a message.",
+ "unableToCreateTicket":"You are currently unable to create a ticket."
},
"optionInvalidReasons":{
- "stringRegex":"Value doesn't match pattern!",
- "stringMinLength":"Value needs to be at least {0} characters!",
- "stringMaxLength":"Value needs to be at most {0} characters!",
- "numberInvalid":"Invalid number!",
- "numberMin":"Number needs to be at least {0}!",
- "numberMax":"Number needs to be at most {0}!",
- "numberDecimal":"Number is not allowed to be a decimal!",
- "numberNegative":"Number is not allowed to be negative!",
- "numberPositive":"Number is not allowed to be positive!",
- "numberZero":"Number is not allowed to be zero!",
- "channelNotFound":"Unable to find channel!",
- "userNotFound":"Unable to find user!",
- "roleNotFound":"Unable to find role!",
- "memberNotFound":"Unable to find user!",
- "mentionableNotFound":"Unable to find user or role!",
- "channelType":"Invalid channel type!",
- "notInGuild":"This option requires you to be in a server!"
+ "stringRegex":"The value does not match the required pattern.",
+ "stringMinLength":"The value must be at least {0} characters long.",
+ "stringMaxLength":"The value must be at most {0} characters long.",
+ "numberInvalid":"Invalid number provided.",
+ "numberMin":"The number must be at least {0}.",
+ "numberMax":"The number must be at most {0}.",
+ "numberDecimal":"Decimals are not allowed.",
+ "numberNegative":"Negative numbers are not allowed.",
+ "numberPositive":"Positive numbers are not allowed.",
+ "numberZero":"Zero is not allowed.",
+ "channelNotFound":"Channel not found.",
+ "userNotFound":"User not found.",
+ "roleNotFound":"Role not found.",
+ "memberNotFound":"Member not found.",
+ "mentionableNotFound":"User or role not found.",
+ "channelType":"Invalid channel type.",
+ "notInGuild":"This option can only be used in a server."
},
"permissions":{
- "developer":"You need to be the developer of the bot.",
- "owner":"You need to be the server owner.",
- "admin":"You need to be a server admin.",
- "moderator":"You need to be a moderator.",
- "support":"You need to be in the support team.",
- "member":"You need to be a member.",
- "discord-administrator":"You need to have the `ADMINISTRATOR` permission."
+ "developer":"This action is restricted to the bot developer.",
+ "owner":"You must be the server owner to use this.",
+ "admin":"You must have administrator permissions to use this.",
+ "moderator":"You must be a moderator to use this.",
+ "support":"You must be part of the support team to use this.",
+ "member":"You must be a server member to use this.",
+ "discord-administrator":"You must have the `ADMINISTRATOR` permission."
},
"actionInvalid":{
- "close":"Ticket is already closed!",
- "reopen":"Ticket is not closed yet!",
- "claim":"Ticket is already claimed!",
- "unclaim":"Ticket is not claimed yet!",
- "pin":"Ticket is already pinned!",
- "unpin":"Ticket is not pinned yet!",
- "add":"This user is already able to access the ticket!",
- "remove":"Unable to remove this user from the ticket!"
+ "close":"This ticket is already closed.",
+ "reopen":"This ticket is not closed.",
+ "claim":"This ticket is already claimed.",
+ "unclaim":"This ticket is not claimed.",
+ "pin":"This ticket is already pinned.",
+ "unpin":"This ticket is not pinned.",
+ "add":"This user already has access to this ticket.",
+ "remove":"This user does not have access to this ticket."
}
},
"params":{
@@ -432,107 +432,107 @@
}
},
"commands":{
- "reason":"Specify an optional reason that will be visible in logs.",
- "help":"Get a list of all the available commands.",
- "panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
- "panelId":"The identifier of the panel that you want to spawn.",
- "panelAutoUpdate":"Do you want this panel to automatically update when edited?",
- "ticket":"Instantly create a ticket.",
- "ticketId":"The identifier of the ticket that you want to create.",
- "close":"Close a ticket.",
- "delete":"Delete a ticket.",
- "deleteNoTranscript":"Delete this ticket without creating a transcript.",
- "reopen":"Reopen a ticket.",
- "claim":"Claim a ticket.",
- "claimUser":"Claim this ticket to someone else instead of yourself.",
- "unclaim":"Unclaim a ticket.",
- "pin":"Pin a ticket.",
- "unpin":"Unpin a ticket.",
+ "reason":"Optional reason shown in logs.",
+ "help":"Display all available commands.",
+ "panel":"Create a ticket panel (buttons or dropdown).",
+ "panelId":"ID of the panel to spawn.",
+ "panelAutoUpdate":"Automatically update this panel when edited.",
+ "ticket":"Create a ticket instantly.",
+ "ticketId":"ID of the ticket to create.",
+ "close":"Close this ticket.",
+ "delete":"Delete this ticket.",
+ "deleteNoTranscript":"Delete ticket without saving a transcript.",
+ "reopen":"Reopen a closed ticket.",
+ "claim":"Claim this ticket.",
+ "claimUser":"Claim the ticket for another user.",
+ "unclaim":"Unclaim this ticket.",
+ "pin":"Pin this ticket.",
+ "unpin":"Unpin this ticket.",
- "move":"Move a ticket.",
- "moveId":"The identifier of the option that you want to move to.",
- "rename":"Rename a ticket.",
- "renameName":"The new name for this ticket.",
- "add":"Add a user to a ticket.",
- "addUser":"The user to add.",
- "remove":"Remove a user from a ticket.",
- "removeUser":"The user to remove.",
+ "move":"Move ticket to another option.",
+ "moveId":"Target option ID.",
+ "rename":"Rename this ticket.",
+ "renameName":"New name for the ticket.",
+ "add":"Add a user to this ticket.",
+ "addUser":"User to add.",
+ "remove":"Remove a user from this ticket.",
+ "removeUser":"User to remove.",
- "blacklist":"Manage the ticket blacklist.",
- "blacklistView":"View a list of the current blacklist.",
+ "blacklist":"Manage the blacklist.",
+ "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.",
- "blacklistGet":"Get the details from a blacklisted user.",
- "blacklistGetUser":"The user to get details from.",
- "stats":"View statistics from the bot, a member or a ticket.",
- "statsReset":"Reset all the stats of the bot (and start counting from zero).",
- "statsGlobal":"View the global stats.",
- "statsUser":"View the stats from a user in the server.",
- "statsUserUser":"The user to view.",
- "statsTicket":"View the stats of a ticket in the server.",
- "statsTicketTicket":"The ticket to view.",
+ "blacklistGet":"View blacklist entry details.",
+ "blacklistGetUser":"User to look up.",
+ "stats":"View bot, user or ticket statistics.",
+ "statsReset":"Reset all bot statistics.",
+ "statsGlobal":"View global bot statistics.",
+ "statsUser":"View a user's statistics.",
+ "statsUserUser":"User to view.",
+ "statsTicket":"View ticket statistics.",
+ "statsTicketTicket":"Ticket to view.",
- "clear":"Delete multiple tickets at the same time.",
- "clearFilter":"The filter for clearing tickets.",
+ "clear":"Delete multiple tickets at once.",
+ "clearFilter":"Filter used when clearing tickets.",
"clearFilters":{
- "all":"All",
- "open":"Open",
- "close":"Closed",
- "claim":"Claimed",
- "unclaim":"Unclaimed",
- "pin":"Pinned",
- "unpin":"Unpinned",
- "autoclose":"Autoclosed"
+ "all":"All tickets",
+ "open":"Open tickets",
+ "close":"Closed tickets",
+ "claim":"Claimed tickets",
+ "unclaim":"Unclaimed tickets",
+ "pin":"Pinned tickets",
+ "unpin":"Unpinned tickets",
+ "autoclose":"Autoclosed tickets"
},
- "autoclose":"Manage autoclose in a ticket.",
- "autocloseDisable":"Disable autoclose in this ticket.",
- "autocloseEnable":"Enable autoclose in this ticket.",
- "autocloseEnableTime":"The amount of hours this ticket needs to be inactive to close it.",
- "autodelete":"Manage autodelete in a ticket.",
- "autodeleteDisable":"Disable autodelete in this ticket.",
- "autodeleteEnable":"Enable autodelete in this ticket.",
- "autodeleteEnableTime":"The amount of days this ticket needs to be inactive to delete it.",
+ "autoclose":"Manage ticket autoclose.",
+ "autocloseDisable":"Disable autoclose.",
+ "autocloseEnable":"Enable autoclose.",
+ "autocloseEnableTime":"Hours of inactivity before closing.",
+ "autodelete":"Manage ticket autodelete.",
+ "autodeleteDisable":"Disable autodelete.",
+ "autodeleteEnable":"Enable autodelete.",
+ "autodeleteEnableTime":"Days of inactivity before deletion.",
- "topic":"Manage the topic of the ticket channel.",
- "topicSet":"Set the topic of the ticket channel.",
- "topicValue":"The new topic of the channel.",
- "topicList":"Get a list of all tickets with their topic and stats.",
- "priority":"Manage the priority of the ticket.",
- "prioritySet":"Set the priority of the ticket.",
- "priorityValue":"The priority of the channel.",
- "priorityGet":"Get the priority of the ticket.",
- "priorityList":"Get a list of all tickets with their priority status.",
- "transfer":"Transfer the ticket ownership from one user to another.",
- "transferUser":"The user to transfer to."
+ "topic":"Manage ticket channel topic.",
+ "topicSet":"Set the ticket channel topic.",
+ "topicValue":"New channel topic text.",
+ "topicList":"List all ticket channel topics.",
+ "priority":"Manage ticket priority.",
+ "prioritySet":"Set ticket priority.",
+ "priorityValue":"Priority level.",
+ "priorityGet":"View ticket priority.",
+ "priorityList":"List all ticket priorities.",
+ "transfer":"Transfer ticket ownership.",
+ "transferUser":"User to transfer to."
},
"helpMenu":{
- "help":"Get a list of all the available commands.",
- "ticket":"Instantly create a ticket.",
- "close":"Close a ticket, this disables writing in this channel.",
- "delete":"Delete a ticket, this creates a transcript when enabled.",
- "reopen":"Reopen a ticket, this enables writing in this channel again.",
- "pin":"Pin a ticket. This will move the ticket to the top and will add a '📌' emoij to the name.",
- "unpin":"Unpin a ticket. The ticket will stay on it's position but will lose the '📌' emoij.",
- "move":"Move a ticket. This will change the type of this ticket.",
- "rename":"Rename a ticket. This will change the channel name of this ticket.",
- "claim":"Claim a ticket. With this, you can let your team know you are handling this ticket.",
- "unclaim":"Unclaim a ticket. With this, you can let your team know that this ticket is free again.",
- "add":"Add a user to a ticket. This will allow the user to read & write in this ticket.",
- "remove":"Remove a user from a ticket. This will remove the ability to read & write for a user in this ticket.",
- "panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
- "blacklistView":"View a list of the current blacklist.",
+ "help":"View all available commands.",
+ "ticket":"Create a ticket instantly.",
+ "close":"Close this ticket and disable messaging in the channel.",
+ "delete":"Delete this ticket (creates a transcript if enabled).",
+ "reopen":"Reopen a closed ticket and restore messaging.",
+ "pin":"Pin this ticket and move it to the top with '📌'.",
+ "unpin":"Unpin this ticket and remove the '📌' emoji.",
+ "move":"Move this ticket to a different option or ticket type.",
+ "rename":"Rename this ticket channel.",
+ "claim":"Claim this ticket to show you are handling it.",
+ "unclaim":"Unclaim this ticket to mark it as available.",
+ "add":"Add a user to this ticket.",
+ "remove":"Remove a user's access from this ticket.",
+ "panel":"Create a ticket panel with buttons or a dropdown.",
+ "blacklistView":"View all blacklisted users.",
"blacklistAdd":"Add a user to the blacklist.",
"blacklistRemove":"Remove a user from the blacklist.",
- "blacklistGet":"Get the details from a blacklisted user.",
- "statsGlobal":"View the global stats.",
- "statsTicket":"View the stats of a ticket in the server.",
- "statsUser":"View the stats from a user in the server.",
- "statsReset":"Reset all the stats of the bot (and start counting from zero).",
- "autocloseDisable":"Disable autoclose in this ticket.",
- "autocloseEnable":"Enable autoclose in this ticket.",
- "autodeleteDisable":"Disable autodelete in this ticket.",
- "autodeleteEnable":"Enable autodelete in this ticket.",
+ "blacklistGet":"View details of a blacklisted user.",
+ "statsGlobal":"View global bot statistics.",
+ "statsTicket":"View statistics for a ticket.",
+ "statsUser":"View statistics for a user.",
+ "statsReset":"Reset all bot statistics.",
+ "autocloseDisable":"Disable autoclose for this ticket.",
+ "autocloseEnable":"Enable autoclose for this ticket.",
+ "autodeleteDisable":"Disable autodelete for this ticket.",
+ "autodeleteEnable":"Enable autodelete for this ticket.",
"categories":{
"general":"General Commands",
"basicTicket":"Basic Ticket Commands",
@@ -545,10 +545,10 @@
},
"stats":{
"scopes":{
- "global":"Global Stats",
- "system":"System Stats",
- "user":"User Stats",
- "ticket":"Ticket Stats",
+ "global":"Global Statistics",
+ "system":"System Statistics",
+ "user":"User Statistics",
+ "ticket":"Ticket Statistics",
"participants":"Participants",
"messages":"Messages"
},
@@ -592,9 +592,9 @@
}
},
"panel":{
- "selectTicket":"Select your ticket",
- "selectRole":"Select your role",
- "selectOption":"Select your option"
+ "selectTicket":"Select a ticket",
+ "selectRole":"Select a role",
+ "selectOption":"Select an option"
},
"priorities":{
"urgent":"Urgent",
diff --git a/languages/estonian.json b/languages/estonian.json
index 241bfec..1225d79 100644
--- a/languages/estonian.json
+++ b/languages/estonian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["iamnotmega","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Estonian",
diff --git a/languages/finnish.json b/languages/finnish.json
index d922108..895a1bf 100644
--- a/languages/finnish.json
+++ b/languages/finnish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["iamnotmega","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Finnish",
diff --git a/languages/french.json b/languages/french.json
index d50f971..38b582f 100644
--- a/languages/french.json
+++ b/languages/french.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["guillee3"],
"lastedited":"16/02/2026",
"language":"French",
diff --git a/languages/german.json b/languages/german.json
index 5ab33e5..0c8e1c4 100644
--- a/languages/german.json
+++ b/languages/german.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["benzorich"],
"lastedited":"16/02/2026",
"language":"German",
@@ -14,8 +14,8 @@
"typeInfo":"[INFO]",
"headerConfigChecker":"CONFIG CHECKER",
"headerDescription":"Prüfen Sie auf Fehler in Ihrer Konfigurationsdateien!",
- "footerError":"Der Bot wird nicht starten, bis alle {0}'s repariert sind!",
- "footerWarning":"Es wird empfohlen, vor dem Start alle {0}'s zu korrigieren!",
+ "footerError":"Der Bot wird nicht starten, bis alle {0}en repariert sind!",
+ "footerWarning":"Es wird empfohlen, vor dem Start alle {0}en zu korrigieren!",
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
"compactInformation":"Verwenden Sie {0} für weitere Informationen!",
"dataPath":"Pfad",
diff --git a/languages/greek.json b/languages/greek.json
index 998e304..bc11230 100644
--- a/languages/greek.json
+++ b/languages/greek.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Greek",
diff --git a/languages/hindi.json b/languages/hindi.json
index 30dd621..0addf7e 100644
--- a/languages/hindi.json
+++ b/languages/hindi.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["challenger_nova"],
"lastedited":"16/02/2026",
"language":"Hindi",
diff --git a/languages/hungarian.json b/languages/hungarian.json
index bf989b3..7908d10 100644
--- a/languages/hungarian.json
+++ b/languages/hungarian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["Kornel0706"],
"lastedited":"16/02/2026",
"language":"Hungarian",
diff --git a/languages/indonesian.json b/languages/indonesian.json
index 66c1483..7ea791d 100644
--- a/languages/indonesian.json
+++ b/languages/indonesian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["erxg"],
"lastedited":"16/02/2026",
"language":"Indonesian",
diff --git a/languages/italian.json b/languages/italian.json
index 28a6723..e7be54b 100644
--- a/languages/italian.json
+++ b/languages/italian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["fraden1mvp.","imperatorix_17"],
"lastedited":"16/02/2026",
"language":"Italian",
diff --git a/languages/japanese.json b/languages/japanese.json
index f528a9a..ad91014 100644
--- a/languages/japanese.json
+++ b/languages/japanese.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Japanese",
diff --git a/languages/khmer.json b/languages/khmer.json
new file mode 100644
index 0000000..4cd5c55
--- /dev/null
+++ b/languages/khmer.json
@@ -0,0 +1,608 @@
+{
+ "_TRANSLATION":{
+ "otversion":"v4.2.0",
+ "translators":["yuuslokrobjakkroval"],
+ "lastedited":"20/05/2026",
+ "language":"Khmer",
+ "automated":false
+ },
+ "checker":{
+ "system":{
+ "typeError":"[កំហុស]",
+ "headerOpenTicket":"OPEN TICKET",
+ "typeWarning":"[ព្រមាន]",
+ "typeInfo":"[ព័ត៌មាន]",
+ "headerConfigChecker":"CONFIG CHECKER",
+ "headerDescription":"ពិនិត្យមើលកំហុសក្នុងឯកសារកំណត់រចនាសម្ព័ន្ធ!",
+ "footerError":"បូតនឹងមិនចាប់ផ្តើមទេ រហូតដល់ {0} ទាំងអស់ត្រូវបានជួសជុល!",
+ "footerWarning":"វាត្រូវបានណែនាំឱ្យជួសជុល {0} ទាំងអស់មុនពេលចាប់ផ្តើម!",
+ "footerSupport":"ជំនួយ: {0} - ឯកសារ: {1}",
+ "compactInformation":"ប្រើ {0} សម្រាប់ព័ត៌មានបន្ថែម!",
+ "dataPath":"ផ្លូវ",
+ "dataDocs":"ឯកសារ",
+ "dataMessages":"សារ"
+ },
+ "messages":{
+ "stringTooShort":"ខ្សែអក្សរនេះមិនអាចខ្លីជាង {0} តួអក្សរ!",
+ "stringTooLong":"ខ្សែអក្សរនេះមិនអាចវែងជាង {0} តួអក្សរ!",
+ "stringLengthInvalid":"ខ្សែអក្សរនេះត្រូវតែមាន {0} តួអក្សរ!",
+ "stringStartsWith":"ខ្សែអក្សរនេះត្រូវតែចាប់ផ្តើមដោយ {0}!",
+ "stringEndsWith":"ខ្សែអក្សរនេះត្រូវតែបញ្ចប់ដោយ {0}!",
+ "stringContains":"ខ្សែអក្សរនេះត្រូវតែមាន {0}!",
+ "stringChoices":"ខ្សែអក្សរនេះអាចជាតម្លៃដូចខាងក្រោមប៉ុណ្ណោះ: {0}!",
+ "stringRegex":"ខ្សែអក្សរនេះមិនត្រឹមត្រូវ!",
+ "stringInvertedContains":"ខ្សែអក្សរនេះមិនត្រូវបានអនុញ្ញាតឱ្យមាន {0}!",
+ "stringLowercase":"ខ្សែអក្សរនេះត្រូវតែសរសេរជាអក្សរតូចប៉ុណ្ណោះ!",
+ "stringUppercase":"ខ្សែអក្សរនេះត្រូវតែសរសេរជាអក្សរធំប៉ុណ្ណោះ!",
+ "stringSpecialCharacters":"ខ្សែអក្សរនេះមិនត្រូវបានអនុញ្ញាតឱ្យមានតួអក្សរពិសេស! (a-z, 0-9 និងដកឃ្លាប៉ុណ្ណោះ)",
+ "stringNoSpaces":"ខ្សែអក្សរនេះមិនត្រូវបានអនុញ្ញាតឱ្យមានដកឃ្លា!",
+ "stringCapitalWord":"វាត្រូវបានណែនាំឱ្យពាក្យនីមួយៗក្នុងខ្សែអក្សរនេះចាប់ផ្តើមដោយអក្សរធំ!",
+ "stringCapitalSentence":"វាមើលទៅថាប្រយោគខ្លះក្នុងខ្សែអក្សរនេះមិនចាប់ផ្តើមដោយអក្សរធំ!",
+ "stringPunctuation":"វាមើលទៅថាប្រយោគក្នុងខ្សែអក្សរនេះមិនបញ្ចប់ដោយសញ្ញាវណ្ណយុត្តិ!",
+
+ "numberTooShort":"លេខនេះមិនអាចខ្លីជាង {0} តួអក្សរ!",
+ "numberTooLong":"លេខនេះមិនអាចវែងជាង {0} តួអក្សរ!",
+ "numberLengthInvalid":"លេខនេះត្រូវតែមាន {0} តួអក្សរ!",
+ "numberTooSmall":"លេខនេះត្រូវតែយ៉ាងហោចណាស់ {0}!",
+ "numberTooLarge":"លេខនេះត្រូវតែច្រើនបំផុត {0}!",
+ "numberNotEqual":"លេខនេះត្រូវតែជា {0}!",
+ "numberStep":"លេខនេះត្រូវតែជាច្រើនដង {0}!",
+ "numberStepOffset":"លេខនេះត្រូវតែជាច្រើនដង {0} ចាប់ផ្តើមពី {1}!",
+ "numberStartsWith":"លេខនេះត្រូវតែចាប់ផ្តើមដោយ {0}!",
+ "numberEndsWith":"លេខនេះត្រូវតែបញ្ចប់ដោយ {0}!",
+ "numberContains":"លេខនេះត្រូវតែមាន {0}!",
+ "numberChoices":"លេខនេះអាចជាតម្លៃដូចខាងក្រោមប៉ុណ្ណោះ: {0}!",
+ "numberFloat":"លេខនេះមិនអាចជាទសភាគ!",
+ "numberNegative":"លេខនេះមិនអាចជាអវិជ្ជមាន!",
+ "numberPositive":"លេខនេះមិនអាចជាវិជ្ជមាន!",
+ "numberZero":"លេខនេះមិនអាចជាសូន្យ!",
+ "numberNan":"លេខនេះមិនអាចជា NaN (មិនមែនជាលេខ)!",
+ "numberInvertedContains":"លេខនេះមិនត្រូវបានអនុញ្ញាតឱ្យមាន {0}!",
+
+ "booleanTrue":"Boolean នេះមិនអាចជា true!",
+ "booleanFalse":"Boolean នេះមិនអាចជា false!",
+
+ "arrayEmptyDisabled":"អារ៉េនេះមិនត្រូវបានអនុញ្ញាតឱ្យទទេ!",
+ "arrayEmptyRequired":"អារ៉េនេះត្រូវបានទាមទារឱ្យទទេ!",
+ "arrayTooShort":"អារ៉េនេះត្រូវការប្រវែងយ៉ាងហោចណាស់ {0}!",
+ "arrayTooLong":"អារ៉េនេះត្រូវការប្រវែងច្រើនបំផុត {0}!",
+ "arrayLengthInvalid":"អារ៉េនេះត្រូវការប្រវែង {0}!",
+ "arrayInvalidTypes":"អារ៉េនេះអាចមានប្រភេទដូចខាងក្រោមប៉ុណ្ណោះ: {0}!",
+ "arrayDouble":"អារ៉េនេះមិនអនុញ្ញាតឱ្យតម្លៃដូចគ្នា!",
+
+ "discordInvalidId":"នេះជា discord {0} id មិនត្រឹមត្រូវ!",
+ "discordInvalidIdOptions":"នេះជា discord {0} id មិនត្រឹមត្រូវ! អ្នកក៏អាចប្រើ: {1}!",
+ "discordInvalidToken":"នេះជា discord token មិនត្រឹមត្រូវ (ក្នុងទម្រង់)!",
+ "colorInvalid":"នេះជាពណ៌ hex មិនត្រឹមត្រូវ!",
+ "emojiTooShort":"ខ្សែអក្សរនេះត្រូវការ emoji យ៉ាងហោចណាស់ {0}!",
+ "emojiTooLong":"ខ្សែអក្សរនេះត្រូវការ emoji ច្រើនបំផុត {0}!",
+ "emojiCustom":"Emoji នេះមិនអាចជា custom discord emoji!",
+ "emojiInvalid":"នេះជា emoji មិនត្រឹមត្រូវ!",
+ "urlInvalid":"URL នេះមិនត្រឹមត្រូវ!",
+ "urlInvalidHttp":"URL នេះអាចប្រើតែ https:// protocol ប៉ុណ្ណោះ!",
+ "urlInvalidProtocol":"URL នេះអាចប្រើតែ http:// និង https:// protocols ប៉ុណ្ណោះ!",
+ "urlInvalidHostname":"URL នេះមាន hostname មិនត្រូវបានអនុញ្ញាត!",
+ "urlInvalidExtension":"URL នេះមានផ្នែកបន្ថែមមិនត្រឹមត្រូវ! ជ្រើសរើស: {0}!",
+ "urlInvalidPath":"URL នេះមានផ្លូវមិនត្រឹមត្រូវ!",
+ "idNotUnique":"id នេះមិនតែមួយ, ប្រើ id ផ្សេងទៀត!",
+ "idNonExistent":"id {0} មិនមាន!",
+
+ "invalidType":"លក្ខណៈសម្បត្តិនេះត្រូវជាប្រភេទ: {0}!",
+ "propertyMissing":"លក្ខណៈសម្បត្តិ {0} បាត់ពីវត្ថុនេះ!",
+ "propertyOptional":"លក្ខណៈសម្បត្តិ {0} ជាជម្រើសសម្រាប់វត្ថុនេះ!",
+ "objectDisabled":"វត្ថុនេះត្រូវបានបិទ, បើកវាដោយប្រើ {0}!",
+ "nullInvalid":"លក្ខណៈសម្បត្តិនេះមិនអាចជា null!",
+ "switchInvalidType":"នេះត្រូវជាប្រភេទដូចខាងក្រោម: {0}!",
+ "objectSwitchInvalid":"វត្ថុនេះត្រូវជាប្រភេទដូចខាងក្រោម: {0}!",
+
+ "invalidLanguage":"នេះជាភាសាមិនត្រឹមត្រូវ!",
+ "invalidButton":"ប៊ូតុននេះត្រូវការ {0} ឬ {1} យ៉ាងតិចណាស់!",
+ "unusedOption":"ជម្រើស {0} មិនត្រូវបានប្រើ!",
+ "unusedQuestion":"សំណួរ {0} មិនត្រូវបានប្រើ!",
+ "dropdownOption":"Panel ដែលមាន dropdown បើកអាចមានតែជម្រើសប្រភេទ 'ticket' ប៉ុណ្ណោះ!",
+ "customInvalidVersion":"កំណែដែលបានបញ្ជាក់ក្នុង config របស់អ្នកមិនត្រូវគ្នា! សូមប្រាកដថាអ្នកបានធ្វើបច្ចុប្បន្នភាព config ទៅកំណែថ្មីបំផុត!"
+ }
+ },
+ "actions":{
+ "buttons":{
+ "create":"ចូលមើលសំបុត្រ",
+ "close":"បិទសំបុត្រ",
+ "delete":"លុបសំបុត្រ",
+ "reopen":"បើកសំបុត្រឡើងវិញ",
+ "claim":"ទទួលសំបុត្រ",
+ "unclaim":"លែងទទួលសំបុត្រ",
+ "pin":"ដាក់ម្ជុលសំបុត្រ",
+ "unpin":"ដកម្ជុលសំបុត្រ",
+ "clear":"លុបសំបុត្រទាំងអស់",
+ "helpSwitchSlash":"មើលពាក្យបញ្ជា Slash",
+ "helpSwitchText":"មើលពាក្យបញ្ជាអក្សរ",
+ "helpPage":"ទំព័រ {0}",
+ "withReason":"ជាមួយហេតុផល",
+ "withoutTranscript":"គ្មាន Transcript"
+ },
+ "titles":{
+ "created":"បានបង្កើតសំបុត្រ",
+ "close":"បានបិទសំបុត្រ",
+ "delete":"បានលុបសំបុត្រ",
+ "reopen":"បានបើកសំបុត្រឡើងវិញ",
+ "claim":"បានទទួលសំបុត្រ",
+ "unclaim":"បានលែងទទួលសំបុត្រ",
+ "pin":"បានដាក់ម្ជុលសំបុត្រ",
+ "unpin":"បានដកម្ជុលសំបុត្រ",
+ "rename":"បានប្តូរឈ្មោះសំបុត្រ",
+ "move":"បានផ្លាស់ប្តូរសំបុត្រ",
+ "add":"បានបន្ថែមអ្នកប្រើប្រាស់ទៅសំបុត្រ",
+ "remove":"បានដកអ្នកប្រើប្រាស់ពីសំបុត្រ",
+
+ "help":"ពាក្យបញ្ជាដែលមាន",
+ "statsReset":"កំណត់ស្ថិតិឡើងវិញ",
+ "blacklistAdd":"អ្នកប្រើប្រាស់ត្រូវបានដាក់ក្នុងបញ្ជីខ្មៅ",
+ "blacklistRemove":"អ្នកប្រើប្រាស់ត្រូវបានដោះលែង",
+ "blacklistGet":"អ្នកប្រើប្រាស់ក្នុងបញ្ជីខ្មៅ",
+ "blacklistView":"បញ្ជីខ្មៅបច្ចុប្បន្ន",
+ "blacklistAddDm":"ត្រូវបានបន្ថែមទៅបញ្ជីខ្មៅ",
+ "blacklistRemoveDm":"ត្រូវបានដកចេញពីបញ្ជីខ្មៅ",
+ "clear":"បានសម្អាតសំបុត្រ",
+ "clearTickets":"សម្អាតសំបុត្រ",
+ "roles":"តួនាទីបានធ្វើបច្ចុប្បន្នភាព",
+
+ "autoclose":"សំបុត្របានបិទដោយស្វ័យប្រវត្តិ",
+ "autocloseEnabled":"បានបើក Autoclose",
+ "autocloseDisabled":"បានបិទ Autoclose",
+ "autodelete":"សំបុត្របានលុបដោយស្វ័យប្រវត្តិ",
+ "autodeleteEnabled":"បានបើក Autodelete",
+ "autodeleteDisabled":"បានបិទ Autodelete",
+
+ "topicSet":"បានប្តូរប្រធានបទ",
+ "prioritySet":"បានប្តូរអាទិភាព",
+ "priorityGet":"អាទិភាពសំបុត្រ",
+ "transfer":"បានផ្ទេរសំបុត្រ"
+ },
+ "descriptions":{
+ "create":"សំបុត្ររបស់អ្នកត្រូវបានបង្កើត។ ចុចប៊ូតុងខាងក្រោមដើម្បីចូលប្រើ!",
+ "close":"សំបុត្រត្រូវបានបិទដោយជោគជ័យ!",
+ "delete":"សំបុត្រត្រូវបានលុបដោយជោគជ័យ!",
+ "reopen":"សំបុត្រត្រូវបានបើកឡើងវិញដោយជោគជ័យ!",
+ "claim":"សំបុត្រត្រូវបានទទួលដោយជោគជ័យ!",
+ "unclaim":"សំបុត្រត្រូវបានលែងទទួលដោយជោគជ័យ!",
+ "pin":"សំបុត្រត្រូវបានដាក់ម្ជុលដោយជោគជ័យ!",
+ "unpin":"សំបុត្រត្រូវបានដកម្ជុលដោយជោគជ័យ!",
+ "rename":"សំបុត្រត្រូវបានប្តូរឈ្មោះទៅ {0} ដោយជោគជ័យ!",
+ "move":"សំបុត្រត្រូវបានផ្លាស់ប្តូរទៅ {0} ដោយជោគជ័យ!",
+ "add":"{0} ត្រូវបានបន្ថែមទៅសំបុត្រដោយជោគជ័យ!",
+ "remove":"{0} ត្រូវបានដកចេញពីសំបុត្រដោយជោគជ័យ!",
+
+ "helpExplanation":"`` => ប៉ារ៉ាម៉ែត្រចាំបាច់\n`[name]` => ប៉ារ៉ាម៉ែត្រស្រេចចិត្ត",
+ "statsReset":"ស្ថិតិបូតត្រូវបានកំណត់ឡើងវិញដោយជោគជ័យ!",
+ "statsError":"មិនអាចមើលស្ថិតិសំបុត្រ!\n{0} មិនមែនជាសំបុត្រ!",
+ "blacklistAdd":"{0} ត្រូវបានដាក់ក្នុងបញ្ជីខ្មៅដោយជោគជ័យ!",
+ "blacklistRemove":"{0} ត្រូវបានដោះលែងដោយជោគជ័យ!",
+ "blacklistGetSuccess":"{0} ស្ថិតក្នុងបញ្ជីខ្មៅបច្ចុប្បន្ន!",
+ "blacklistGetEmpty":"{0} មិនស្ថិតក្នុងបញ្ជីខ្មៅបច្ចុប្បន្ន!",
+ "blacklistViewEmpty":"មិនទាន់មានអ្នកណាត្រូវបានដាក់ក្នុងបញ្ជីខ្មៅ!",
+ "blacklistViewTip":"ប្រើ \"/blacklist add\" ដើម្បីដាក់អ្នកប្រើក្នុងបញ្ជីខ្មៅ!",
+ "clearVerify":"តើអ្នកប្រាកដថាចង់លុបសំបុត្រច្រើន?\nសកម្មភាពនេះមិនអាចត្រឡប់មកវិញ!",
+ "clearReady":"សំបុត្រ {0} ត្រូវបានលុបដោយជោគជ័យ!",
+ "rolesEmpty":"មិនមានតួនាទីណាត្រូវបានធ្វើបច្ចុប្បន្នភាព!",
+
+ "autocloseLeave":"សំបុត្រនេះត្រូវបានបិទដោយស្វ័យប្រវត្តិ ដោយសារអ្នកបង្កើតបានចាកចេញពីម៉ាស៊ីនបម្រើ!",
+ "autocloseTimeout":"សំបុត្រនេះត្រូវបានបិទដោយស្វ័យប្រវត្តិ ដោយសារវាមិនសកម្មលើសពី `{0}h`!",
+ "autodeleteLeave":"សំបុត្រនេះត្រូវបានលុបដោយស្វ័យប្រវត្តិ ដោយសារអ្នកបង្កើតបានចាកចេញពីម៉ាស៊ីនបម្រើ!",
+ "autodeleteTimeout":"សំបុត្រនេះត្រូវបានលុបដោយស្វ័យប្រវត្តិ ដោយសារវាមិនសកម្មលើសពី `{0} ថ្ងៃ`!",
+ "autocloseEnabled":"Autoclose ត្រូវបានបើកក្នុងសំបុត្រនេះ!\nវានឹងត្រូវបានបិទនៅពេលមិនសកម្មលើសពី `{0}h`!",
+ "autocloseDisabled":"Autoclose ត្រូវបានបិទក្នុងសំបុត្រនេះ!\nវានឹងមិនត្រូវបានបិទដោយស្វ័យប្រវត្តិទៀតទេ!",
+ "autodeleteEnabled":"Autodelete ត្រូវបានបើកក្នុងសំបុត្រនេះ!\nវានឹងត្រូវបានលុបនៅពេលមិនសកម្មលើសពី `{0} ថ្ងៃ`!",
+ "autodeleteDisabled":"Autodelete ត្រូវបានបិទក្នុងសំបុត្រនេះ!\nវានឹងមិនត្រូវបានលុបដោយស្វ័យប្រវត្តិទៀតទេ!",
+
+ "ticketMessageLimit":"អ្នកអាចបង្កើតសំបុត្រ {0} ក្នុងពេលតែមួយ!",
+ "ticketMessageAutoclose":"សំបុត្រនេះនឹងត្រូវបានបិទដោយស្វ័យប្រវត្តិ នៅពេលមិនសកម្ម {0}h!",
+ "ticketMessageAutodelete":"សំបុត្រនេះនឹងត្រូវបានលុបដោយស្វ័យប្រវត្តិ នៅពេលមិនសកម្ម {0} ថ្ងៃ!",
+ "panelReady":"Panel មាននៅក្នុងសារបន្ត!\nសារនេះអាចលុបបានហើយ!",
+
+ "topicSet":"ប្រធានបទបណ្តាញត្រូវបានប្តូរដោយ {0} ដោយជោគជ័យ!",
+ "prioritySet":"អាទិភាពសំបុត្រត្រូវបានប្តូរទៅ {0} ដោយ {1} ដោយជោគជ័យ!",
+ "priorityGet":"អាទិភាពបច្ចុប្បន្នរបស់សំបុត្រនេះគឺ {0}។",
+ "transfer":"ភាពជាម្ចាស់សំបុត្រត្រូវបានផ្ទេរពី {0} ទៅ {1} ដោយ {2} ដោយជោគជ័យ!"
+ },
+ "modal":{
+ "closePlaceholder":"ហេតុអ្វីអ្នកបិទសំបុត្រនេះ?",
+ "deletePlaceholder":"ហេតុអ្វីអ្នកលុបសំបុត្រនេះ?",
+ "reopenPlaceholder":"ហេតុអ្វីអ្នកបើកសំបុត្រនេះឡើងវិញ?",
+ "claimPlaceholder":"ហេតុអ្វីអ្នកទទួលសំបុត្រនេះ?",
+ "unclaimPlaceholder":"ហេតុអ្វីអ្នកលែងទទួលសំបុត្រនេះ?",
+ "pinPlaceholder":"ហេតុអ្វីអ្នកដាក់ម្ជុលសំបុត្រនេះ?",
+ "unpinPlaceholder":"ហេតុអ្វីអ្នកដកម្ជុលសំបុត្រនេះ?"
+ },
+ "logs":{
+ "createLog":"សំបុត្រថ្មីត្រូវបានបង្កើតដោយ {0}!",
+ "closeLog":"សំបុត្រនេះត្រូវបានបិទដោយ {0}!",
+ "closeDm":"សំបុត្ររបស់អ្នកត្រូវបានបិទនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "deleteLog":"សំបុត្រនេះត្រូវបានលុបដោយ {0}!",
+ "deleteDm":"សំបុត្ររបស់អ្នកត្រូវបានលុបនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "reopenLog":"សំបុត្រនេះត្រូវបានបើកឡើងវិញដោយ {0}!",
+ "reopenDm":"សំបុត្ររបស់អ្នកត្រូវបានបើកឡើងវិញនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "claimLog":"សំបុត្រនេះត្រូវបានទទួលដោយ {0}!",
+ "claimDm":"សំបុត្ររបស់អ្នកត្រូវបានទទួលនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "unclaimLog":"សំបុត្រនេះត្រូវបានលែងទទួលដោយ {0}!",
+ "unclaimDm":"សំបុត្ររបស់អ្នកត្រូវបានលែងទទួលនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "pinLog":"សំបុត្រនេះត្រូវបានដាក់ម្ជុលដោយ {0}!",
+ "pinDm":"សំបុត្ររបស់អ្នកត្រូវបានដាក់ម្ជុលនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "unpinLog":"សំបុត្រនេះត្រូវបានដកម្ជុលដោយ {0}!",
+ "unpinDm":"សំបុត្ររបស់អ្នកត្រូវបានដកម្ជុលនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "renameLog":"សំបុត្រនេះត្រូវបានប្តូរឈ្មោះទៅ {0} ដោយ {1}!",
+ "renameDm":"សំបុត្ររបស់អ្នកត្រូវបានប្តូរឈ្មោះទៅ {0} នៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "moveLog":"សំបុត្រនេះត្រូវបានផ្លាស់ប្តូរទៅ {0} ដោយ {1}!",
+ "moveDm":"សំបុត្ររបស់អ្នកត្រូវបានផ្លាស់ប្តូរទៅ {0} នៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "addLog":"{0} ត្រូវបានបន្ថែមទៅសំបុត្រនេះដោយ {1}!",
+ "addDm":"{0} ត្រូវបានបន្ថែមទៅសំបុត្ររបស់អ្នកនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "removeLog":"{0} ត្រូវបានដកចេញពីសំបុត្រនេះដោយ {1}!",
+ "removeDm":"{0} ត្រូវបានដកចេញពីសំបុត្ររបស់អ្នកនៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+
+ "blacklistAddLog":"{0} ត្រូវបានដាក់ក្នុងបញ្ជីខ្មៅដោយ {1}!",
+ "blacklistRemoveLog":"{0} ត្រូវបានដកចេញពីបញ្ជីខ្មៅដោយ {1}!",
+ "blacklistAddDm":"អ្នកត្រូវបានដាក់ក្នុងបញ្ជីខ្មៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!\nចាប់ពីពេលនេះ អ្នកមិនអាចបង្កើតសំបុត្រ!",
+ "blacklistRemoveDm":"អ្នកត្រូវបានដកចេញពីបញ្ជីខ្មៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!\nឥឡូវអ្នកអាចបង្កើតសំបុត្របានម្តងទៀត!",
+ "clearLog":"សំបុត្រ {0} ត្រូវបានលុបដោយ {1}!",
+
+ "transferLog":"ភាពជាម្ចាស់សំបុត្រនេះត្រូវបានផ្ទេរពី {0} ទៅ {1} ដោយ {2}!",
+ "transferDm":"ភាពជាម្ចាស់សំបុត្ររបស់អ្នកត្រូវបានផ្ទេរពី {0} ទៅ {1} នៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "prioritySetLog":"អាទិភាពសំបុត្រនេះត្រូវបានប្តូរទៅ {0} ដោយ {1}!",
+ "prioritySetDm":"អាទិភាពសំបុត្ររបស់អ្នកត្រូវបានប្តូរទៅ {0} នៅក្នុងម៉ាស៊ីនបម្រើរបស់យើង!",
+ "roleUpdateLog":"{0} បានធ្វើបច្ចុប្បន្នភាពតួនាទីរបស់ខ្លួន!",
+ "roleUpdateDm":"តួនាទីរបស់អ្នកក្នុងម៉ាស៊ីនបម្រើរបស់យើងត្រូវបានធ្វើបច្ចុប្បន្នភាព!"
+ }
+ },
+ "transcripts":{
+ "success":{
+ "visit":"ចូលមើល Transcript",
+ "ready":"Transcript ត្រូវបានបង្កើត",
+ "textFileDescription":"នេះជា transcript អក្សររបស់សំបុត្រដែលបានលុប!",
+ "htmlProgress":"សូមរង់ចាំ ខណៈ html transcript កំពុងត្រូវបានដំណើរការ...",
+
+ "createdChannel":"transcript {0} ថ្មីត្រូវបានបង្កើតក្នុងម៉ាស៊ីនបម្រើ!",
+ "createdCreator":"transcript {0} ថ្មីត្រូវបានបង្កើតសម្រាប់សំបុត្ររបស់អ្នក!",
+ "createdParticipant":"transcript {0} ថ្មីត្រូវបានបង្កើតក្នុងសំបុត្រដែលអ្នកបានចូលរួម!",
+ "createdActiveAdmin":"transcript {0} ថ្មីត្រូវបានបង្កើតក្នុងសំបុត្រដែលអ្នកបានចូលរួមជាអ្នកគ្រប់គ្រង!",
+ "createdEveryAdmin":"transcript {0} ថ្មីត្រូវបានបង្កើតក្នុងសំបុត្រដែលអ្នកជាអ្នកគ្រប់គ្រង!",
+ "createdOther":"transcript {0} ថ្មីត្រូវបានបង្កើត!"
+ },
+ "errors":{
+ "retry":"ព្យាយាមម្តងទៀត",
+ "continue":"លុបដោយគ្មាន Transcript",
+ "backup":"បង្កើត Transcript បម្រុង",
+ "error":"មានបញ្ហាខ្លះក្នុងការបង្កើត transcript។\nអ្នកចង់ធ្វើអ្វី?\n\nសំបុត្រនេះនឹងមិនត្រូវបានលុបទេ រហូតអ្នកចុចប៊ូតុងណាមួយ។",
+ "title":"កំហុស Transcript"
+ },
+ "text":{
+ "messagesTitle":"សារ",
+ "embedTitle":"EMBED",
+ "fileTitle":"ឯកសារ",
+ "fieldsTitle":"វាល",
+ "reactionsTitle":"ប្រតិកម្ម",
+ "statsTitle":"ស្ថិតិ",
+ "emptyContent":"<មាតិកាទទេ>",
+ "noTitle":"<គ្មានចំណងជើង>",
+ "noDesc":"<គ្មានការពិពណ៌នា>"
+ }
+ },
+ "errors":{
+ "titles":{
+ "internalError":"កំហុសផ្ទៃក្នុង",
+ "optionMissing":"ជម្រើសពាក្យបញ្ជាបាត់",
+ "optionInvalid":"ជម្រើសពាក្យបញ្ជាមិនត្រឹមត្រូវ",
+ "unknownCommand":"ពាក្យបញ្ជាមិនស្គាល់",
+ "noPermissions":"គ្មានសិទ្ធិ",
+ "unknownTicket":"សំបុត្រមិនស្គាល់",
+ "deprecatedTicket":"សំបុត្រហួសសម័យ",
+ "unknownOption":"ជម្រើសមិនស្គាល់",
+ "unknownPanel":"Panel មិនស្គាល់",
+ "notInGuild":"មិននៅក្នុងម៉ាស៊ីនបម្រើ",
+ "channelRename":"មិនអាចប្តូរឈ្មោះបណ្តាញ",
+ "busy":"សំបុត្រកំពុងដំណើរការ",
+ "permissionError":"កំហុសសិទ្ធិ"
+ },
+ "descriptions":{
+ "askForInfo":"ទំនាក់ទំនងម្ចាស់បូតនេះសម្រាប់ព័ត៌មានបន្ថែម!",
+ "askForInfoResolve":"ទំនាក់ទំនងម្ចាស់បូតនេះ ប្រសិនបើបញ្ហានេះមិនដោះស្រាយបន្ទាប់ពីព្យាយាមមួយចំនួន។",
+ "internalError":"បរាជ័យក្នុងការឆ្លើយតប {0} ដោយសារកំហុសផ្ទៃក្នុង!",
+ "optionMissing":"ប៉ារ៉ាម៉ែត្រចាំបាច់ខ្វះក្នុងពាក្យបញ្ជានេះ!",
+ "optionInvalid":"ប៉ារ៉ាម៉ែត្រក្នុងពាក្យបញ្ជានេះមិនត្រឹមត្រូវ!",
+ "optionInvalidChoose":"ជ្រើសរើសរវាង",
+ "unknownCommand":"សូមចូលមើលម៉ឺនុយជំនួយសម្រាប់ព័ត៌មានបន្ថែម!",
+ "noPermissions":"អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យប្រើ {0} នេះ!",
+ "noPermissionsList":"សិទ្ធិដែលត្រូវការ: (មួយក្នុងចំណោម)",
+ "noPermissionsCooldown":"អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យប្រើ {0} នេះ ដោយសារអ្នកមានរយៈពេលត្រជាក់!",
+ "noPermissionsBlacklist":"អ្នកមិនត្រូវបានអនុញ្ញាតឱ្យប្រើ {0} នេះ ដោយសារអ្នកត្រូវបានដាក់ក្នុងបញ្ជីខ្មៅ!",
+ "noPermissionsLimitGlobal":"អ្នកមិនអាចបង្កើតសំបុត្រ ដោយសារម៉ាស៊ីនបម្រើឈានដល់ដែនកំណត់សំបុត្រច្រើនបំផុត!",
+ "noPermissionsLimitGlobalUser":"អ្នកមិនអាចបង្កើតសំបុត្រ ដោយសារអ្នកឈានដល់ដែនកំណត់សំបុត្រច្រើនបំផុត!",
+ "noPermissionsLimitOption":"អ្នកមិនអាចបង្កើតសំបុត្រ ដោយសារម៉ាស៊ីនបម្រើឈានដល់ដែនកំណត់សំបុត្រច្រើនបំផុតសម្រាប់ជម្រើសនេះ!",
+ "noPermissionsLimitOptionUser":"អ្នកមិនអាចបង្កើតសំបុត្រ ដោយសារអ្នកឈានដល់ដែនកំណត់សំបុត្រច្រើនបំផុតសម្រាប់ជម្រើសនេះ!",
+ "unknownTicket":"សូមសាកល្បងពាក្យបញ្ជានេះម្តងទៀតក្នុងសំបុត្រត្រឹមត្រូវ!",
+ "deprecatedTicket":"បណ្តាញបច្ចុប្បន្នមិនមែនជាសំបុត្រត្រឹមត្រូវ! វាប្រហែលជាសំបុត្រពី Open Ticket កំណែចាស់!",
+ "notInGuild":"{0} នេះមិនដំណើរការក្នុង DM! សូមសាកល្បងម្តងទៀតក្នុងម៉ាស៊ីនបម្រើ!",
+ "channelRename":"ដោយសារ discord ratelimits, វាមិនអាចទៅបានសម្រាប់បូតក្នុងការប្តូរឈ្មោះបណ្តាញ។ បណ្តាញនឹងត្រូវបានប្តូរឈ្មោះដោយស្វ័យប្រវត្តិ ក្នុងរយៈពេល 10 នាទី ប្រសិនបើបូតមិនបានចាប់ផ្តើមឡើងវិញ។",
+ "channelRenameSource":"ប្រភពកំហុសនេះគឺ: {0}",
+ "busy":"មិនអាចប្រើ {0} នេះ!\nសំបុត្រកំពុងត្រូវបានដំណើរការដោយបូត។\n\nសូមព្យាយាមម្តងទៀតក្នុងពីរបីវិនាទី!",
+ "closeBeforeMessage":"សំបុត្រនេះមិនអាចបិទ/លុបមុនមានសារពីអ្នកប្រើ។",
+ "closeBeforeAdminMessage":"សំបុត្រនេះមិនអាចបិទ/លុបមុនមានសារពីអ្នកគ្រប់គ្រងសំបុត្រ ឬសមាជិកជំនួយ។",
+ "unableToCreateTicket":"អ្នកមិនអាចបង្កើតសំបុត្រ។"
+ },
+ "optionInvalidReasons":{
+ "stringRegex":"តម្លៃមិនត្រូវនឹងលំនាំ!",
+ "stringMinLength":"តម្លៃត្រូវការយ៉ាងហោចណាស់ {0} តួអក្សរ!",
+ "stringMaxLength":"តម្លៃត្រូវការច្រើនបំផុត {0} តួអក្សរ!",
+ "numberInvalid":"លេខមិនត្រឹមត្រូវ!",
+ "numberMin":"លេខត្រូវការយ៉ាងហោចណាស់ {0}!",
+ "numberMax":"លេខត្រូវការច្រើនបំផុត {0}!",
+ "numberDecimal":"លេខមិនត្រូវបានអនុញ្ញាតជាទសភាគ!",
+ "numberNegative":"លេខមិនត្រូវបានអនុញ្ញាតជាអវិជ្ជមាន!",
+ "numberPositive":"លេខមិនត្រូវបានអនុញ្ញាតជាវិជ្ជមាន!",
+ "numberZero":"លេខមិនត្រូវបានអនុញ្ញាតជាសូន្យ!",
+ "channelNotFound":"រកបណ្តាញមិនឃើញ!",
+ "userNotFound":"រកអ្នកប្រើប្រាស់មិនឃើញ!",
+ "roleNotFound":"រកតួនាទីមិនឃើញ!",
+ "memberNotFound":"រកអ្នកប្រើប្រាស់មិនឃើញ!",
+ "mentionableNotFound":"រកអ្នកប្រើប្រាស់ ឬតួនាទីមិនឃើញ!",
+ "channelType":"ប្រភេទបណ្តាញមិនត្រឹមត្រូវ!",
+ "notInGuild":"ជម្រើសនេះទាមទារឱ្យអ្នកនៅក្នុងម៉ាស៊ីនបម្រើ!"
+ },
+ "permissions":{
+ "developer":"អ្នកត្រូវជា developer របស់បូត។",
+ "owner":"អ្នកត្រូវជាម្ចាស់ម៉ាស៊ីនបម្រើ។",
+ "admin":"អ្នកត្រូវជា admin ម៉ាស៊ីនបម្រើ។",
+ "moderator":"អ្នកត្រូវជាអ្នកសម្រុះសម្រួល។",
+ "support":"អ្នកត្រូវនៅក្នុងក្រុមជំនួយ។",
+ "member":"អ្នកត្រូវជាសមាជិក។",
+ "discord-administrator":"អ្នកត្រូវមានសិទ្ធិ `ADMINISTRATOR`។"
+ },
+ "actionInvalid":{
+ "close":"សំបុត្របានបិទហើយ!",
+ "reopen":"សំបុត្រមិនទាន់បិទ!",
+ "claim":"សំបុត្របានទទួលហើយ!",
+ "unclaim":"សំបុត្រមិនទាន់ត្រូវបានទទួល!",
+ "pin":"សំបុត្របានដាក់ម្ជុលហើយ!",
+ "unpin":"សំបុត្រមិនទាន់ត្រូវបានដាក់ម្ជុល!",
+ "add":"អ្នកប្រើប្រាស់នេះអាចចូលប្រើសំបុត្រហើយ!",
+ "remove":"មិនអាចដកអ្នកប្រើប្រាស់នេះចេញពីសំបុត្រ!"
+ }
+ },
+ "params":{
+ "uppercase":{
+ "ticket":"សំបុត្រ",
+ "tickets":"សំបុត្រ",
+ "reason":"មូលហេតុ",
+ "creator":"អ្នកបង្កើត",
+ "remaining":"ពេលវេលានៅសល់",
+ "added":"បន្ថែម",
+ "removed":"ដក",
+ "filter":"តម្រង",
+ "method":"វិធីសាស្ត្រ",
+ "type":"ប្រភេទ",
+ "blacklisted":"ក្នុងបញ្ជីខ្មៅ",
+ "panel":"Panel",
+ "command":"ពាក្យបញ្ជា",
+ "system":"ប្រព័ន្ធ",
+ "true":"ពិត",
+ "false":"មិនពិត",
+ "syntax":"វាក្យសម្ព័ន្ធ",
+ "originalName":"ឈ្មោះដើម",
+ "newName":"ឈ្មោះថ្មី",
+ "until":"រហូតដល់",
+ "validOptions":"ជម្រើសត្រឹមត្រូវ",
+ "validPanels":"Panel ត្រឹមត្រូវ",
+ "autoclose":"Autoclose",
+ "autodelete":"Autodelete",
+ "startupDate":"កាលបរិច្ឆេទចាប់ផ្តើម",
+ "version":"កំណែ",
+ "name":"ឈ្មោះ",
+ "role":"តួនាទី",
+ "status":"ស្ថានភាព",
+ "claimed":"ទទួលហើយ",
+ "pinned":"ដាក់ម្ជុលហើយ",
+ "creationDate":"កាលបរិច្ឆេទបង្កើត",
+
+ "noone":"គ្មាននរណា",
+ "open":"បើក",
+ "closed":"បិទ",
+ "priority":"អាទិភាព",
+ "participants":"អ្នកចូលរួម",
+ "yes":"បាទ/ចាស",
+ "no":"ទេ",
+ "option":"ជម្រើស",
+ "topic":"ប្រធានបទ",
+ "uptime":"ពេលដំណើរការប្រព័ន្ធ",
+ "messages":"សារ",
+ "embeds":"Embeds",
+ "files":"ឯកសារ",
+ "components":"ធាតុ",
+ "cooldown":"រយៈពេលត្រជាក់",
+ "maxTickets":"សំបុត្រច្រើនបំផុត",
+ "admins":"អ្នកគ្រប់គ្រង",
+ "roles":"តួនាទី",
+ "size":"ទំហំ"
+ },
+ "lowercase":{
+ "text":"អក្សរ",
+ "html":"html",
+ "command":"ពាក្យបញ្ជា",
+ "modal":"modal",
+ "button":"ប៊ូតុង",
+ "dropdown":"dropdown",
+ "method":"វិធីសាស្ត្រ"
+ }
+ },
+ "commands":{
+ "reason":"បញ្ជាក់មូលហេតុស្រេចចិត្តដែលនឹងបង្ហាញក្នុង logs។",
+ "help":"ទទួលបានបញ្ជីពាក្យបញ្ជាដែលមាន។",
+ "panel":"បង្ហាញសារជាមួយ dropdown ឬ buttons (សម្រាប់ការបង្កើតសំបុត្រ)។",
+ "panelId":"អ្នកកំណត់អត្តសញ្ញាណ panel ដែលអ្នកចង់បង្ហាញ។",
+ "panelAutoUpdate":"តើអ្នកចង់ panel នេះធ្វើបច្ចុប្បន្នភាពដោយស្វ័យប្រវត្តិ នៅពេលកែប្រែ?",
+ "ticket":"បង្កើតសំបុត្រភ្លាមៗ។",
+ "ticketId":"អ្នកកំណត់អត្តសញ្ញាណសំបុត្រដែលអ្នកចង់បង្កើត។",
+ "close":"បិទសំបុត្រ។",
+ "delete":"លុបសំបុត្រ។",
+ "deleteNoTranscript":"លុបសំបុត្រនេះដោយគ្មានការបង្កើត transcript។",
+ "reopen":"បើកសំបុត្រឡើងវិញ។",
+ "claim":"ទទួលសំបុត្រ។",
+ "claimUser":"ទទួលសំបុត្រនេះទៅឱ្យនរណាម្នាក់ផ្សេងទៀត ជំនួសអ្នក។",
+ "unclaim":"លែងទទួលសំបុត្រ។",
+ "pin":"ដាក់ម្ជុលសំបុត្រ។",
+ "unpin":"ដកម្ជុលសំបុត្រ។",
+
+ "move":"ផ្លាស់ប្តូរសំបុត្រ។",
+ "moveId":"អ្នកកំណត់អត្តសញ្ញាណជម្រើសដែលអ្នកចង់ផ្លាស់ប្តូរទៅ។",
+ "rename":"ប្តូរឈ្មោះសំបុត្រ។",
+ "renameName":"ឈ្មោះថ្មីសម្រាប់សំបុត្រនេះ។",
+ "add":"បន្ថែមអ្នកប្រើប្រាស់ទៅសំបុត្រ។",
+ "addUser":"អ្នកប្រើប្រាស់ដែលត្រូវបន្ថែម។",
+ "remove":"ដកអ្នកប្រើប្រាស់ចេញពីសំបុត្រ។",
+ "removeUser":"អ្នកប្រើប្រាស់ដែលត្រូវដក។",
+
+ "blacklist":"គ្រប់គ្រងបញ្ជីខ្មៅសំបុត្រ។",
+ "blacklistView":"មើលបញ្ជីបញ្ជីខ្មៅបច្ចុប្បន្ន។",
+ "blacklistAdd":"បន្ថែមអ្នកប្រើប្រាស់ទៅបញ្ជីខ្មៅ។",
+ "blacklistRemove":"ដកអ្នកប្រើប្រាស់ចេញពីបញ្ជីខ្មៅ។",
+ "blacklistGet":"ទទួលបានព័ត៌មានលម្អិតពីអ្នកប្រើប្រាស់ក្នុងបញ្ជីខ្មៅ។",
+ "blacklistGetUser":"អ្នកប្រើប្រាស់ដែលត្រូវទទួលព័ត៌មានលម្អិត។",
+ "stats":"មើលស្ថិតិពីបូត, សមាជិក ឬសំបុត្រ។",
+ "statsReset":"កំណត់ស្ថិតិបូតទាំងអស់ឡើងវិញ (ចាប់ផ្តើមរាប់ពីសូន្យ)។",
+ "statsGlobal":"មើលស្ថិតិសរុប។",
+ "statsUser":"មើលស្ថិតិពីអ្នកប្រើប្រាស់ក្នុងម៉ាស៊ីនបម្រើ។",
+ "statsUserUser":"អ្នកប្រើប្រាស់ដែលត្រូវមើល។",
+ "statsTicket":"មើលស្ថិតិពីសំបុត្រក្នុងម៉ាស៊ីនបម្រើ។",
+ "statsTicketTicket":"សំបុត្រដែលត្រូវមើល។",
+
+ "clear":"លុបសំបុត្រច្រើនក្នុងពេលតែមួយ។",
+ "clearFilter":"តម្រងសម្រាប់ការសម្អាតសំបុត្រ។",
+ "clearFilters":{
+ "all":"ទាំងអស់",
+ "open":"បើក",
+ "close":"បិទ",
+ "claim":"ទទួលហើយ",
+ "unclaim":"មិនទាន់ទទួល",
+ "pin":"ដាក់ម្ជុលហើយ",
+ "unpin":"មិនទាន់ដាក់ម្ជុល",
+ "autoclose":"បិទដោយស្វ័យប្រវត្តិ"
+ },
+
+ "autoclose":"គ្រប់គ្រង autoclose ក្នុងសំបុត្រ។",
+ "autocloseDisable":"បិទ autoclose ក្នុងសំបុត្រនេះ។",
+ "autocloseEnable":"បើក autoclose ក្នុងសំបុត្រនេះ។",
+ "autocloseEnableTime":"ចំនួនម៉ោងដែលសំបុត្រនេះត្រូវមិនសកម្ម ដើម្បីបិទ។",
+ "autodelete":"គ្រប់គ្រង autodelete ក្នុងសំបុត្រ។",
+ "autodeleteDisable":"បិទ autodelete ក្នុងសំបុត្រនេះ។",
+ "autodeleteEnable":"បើក autodelete ក្នុងសំបុត្រនេះ។",
+ "autodeleteEnableTime":"ចំនួនថ្ងៃដែលសំបុត្រនេះត្រូវមិនសកម្ម ដើម្បីលុប។",
+
+ "topic":"គ្រប់គ្រងប្រធានបទបណ្តាញសំបុត្រ។",
+ "topicSet":"កំណត់ប្រធានបទបណ្តាញសំបុត្រ។",
+ "topicValue":"ប្រធានបទថ្មីរបស់បណ្តាញ។",
+ "topicList":"ទទួលបានបញ្ជីសំបុត្រទាំងអស់ ជាមួយប្រធានបទ និងស្ថិតិ។",
+ "priority":"គ្រប់គ្រងអាទិភាពសំបុត្រ។",
+ "prioritySet":"កំណត់អាទិភាពសំបុត្រ។",
+ "priorityValue":"អាទិភាពរបស់បណ្តាញ។",
+ "priorityGet":"ទទួលបានអាទិភាពសំបុត្រ។",
+ "priorityList":"ទទួលបានបញ្ជីសំបុត្រទាំងអស់ ជាមួយស្ថានភាពអាទិភាព។",
+ "transfer":"ផ្ទេរភាពជាម្ចាស់សំបុត្រពីអ្នកប្រើប្រាស់ម្នាក់ទៅម្នាក់ទៀត។",
+ "transferUser":"អ្នកប្រើប្រាស់ដែលត្រូវផ្ទេរទៅ។"
+ },
+ "helpMenu":{
+ "help":"ទទួលបានបញ្ជីពាក្យបញ្ជាដែលមាន។",
+ "ticket":"បង្កើតសំបុត្រភ្លាមៗ។",
+ "close":"បិទសំបុត្រ, វិធីនេះបិទការសរសេរក្នុងបណ្តាញ។",
+ "delete":"លុបសំបុត្រ, វិធីនេះបង្កើត transcript នៅពេលបើក។",
+ "reopen":"បើកសំបុត្រឡើងវិញ, វិធីនេះបើកការសរសេរក្នុងបណ្តាញម្តងទៀត។",
+ "pin":"ដាក់ម្ជុលសំបុត្រ។ វានឹងផ្លាស់សំបុត្រទៅខាងលើ ហើយបន្ថែម '📌' ទៅឈ្មោះ។",
+ "unpin":"ដកម្ជុលសំបុត្រ។ សំបុត្រនឹងនៅតំណែងដដែល ប៉ុន្តែនឹងបាត់ '📌'។",
+ "move":"ផ្លាស់ប្តូរសំបុត្រ។ វានឹងប្តូរប្រភេទរបស់សំបុត្រ។",
+ "rename":"ប្តូរឈ្មោះសំបុត្រ។ វានឹងប្តូរឈ្មោះបណ្តាញរបស់សំបុត្រ។",
+ "claim":"ទទួលសំបុត្រ។ ដោយវិធីនេះ អ្នកអាចប្រាប់ក្រុមរបស់អ្នកថាអ្នកកំពុងដោះស្រាយសំបុត្រនេះ។",
+ "unclaim":"លែងទទួលសំបុត្រ។ ដោយវិធីនេះ អ្នកអាចប្រាប់ក្រុមរបស់អ្នកថាសំបុត្រនេះទំនេរ។",
+ "add":"បន្ថែមអ្នកប្រើប្រាស់ទៅសំបុត្រ។ វានឹងអនុញ្ញាតឱ្យអ្នកប្រើប្រាស់អាននិងសរសេរក្នុងសំបុត្រ។",
+ "remove":"ដកអ្នកប្រើប្រាស់ចេញពីសំបុត្រ។ វានឹងដកសិទ្ធិអាននិងសរសេររបស់អ្នកប្រើប្រាស់ក្នុងសំបុត្រ។",
+ "panel":"បង្ហាញសារជាមួយ dropdown ឬ buttons (សម្រាប់ការបង្កើតសំបុត្រ)។",
+ "blacklistView":"មើលបញ្ជីបញ្ជីខ្មៅបច្ចុប្បន្ន។",
+ "blacklistAdd":"បន្ថែមអ្នកប្រើប្រាស់ទៅបញ្ជីខ្មៅ។",
+ "blacklistRemove":"ដកអ្នកប្រើប្រាស់ចេញពីបញ្ជីខ្មៅ។",
+ "blacklistGet":"ទទួលបានព័ត៌មានលម្អិតពីអ្នកប្រើប្រាស់ក្នុងបញ្ជីខ្មៅ។",
+ "statsGlobal":"មើលស្ថិតិសរុប។",
+ "statsTicket":"មើលស្ថិតិពីសំបុត្រក្នុងម៉ាស៊ីនបម្រើ។",
+ "statsUser":"មើលស្ថិតិពីអ្នកប្រើប្រាស់ក្នុងម៉ាស៊ីនបម្រើ។",
+ "statsReset":"កំណត់ស្ថិតិបូតទាំងអស់ឡើងវិញ (ចាប់ផ្តើមរាប់ពីសូន្យ)។",
+ "autocloseDisable":"បិទ autoclose ក្នុងសំបុត្រនេះ។",
+ "autocloseEnable":"បើក autoclose ក្នុងសំបុត្រនេះ។",
+ "autodeleteDisable":"បិទ autodelete ក្នុងសំបុត្រនេះ។",
+ "autodeleteEnable":"បើក autodelete ក្នុងសំបុត្រនេះ។",
+ "categories":{
+ "general":"ពាក្យបញ្ជាទូទៅ",
+ "basicTicket":"ពាក្យបញ្ជាសំបុត្រមូលដ្ឋាន",
+ "advancedTicket":"ពាក្យបញ្ជាសំបុត្រកម្រិតខ្ពស់",
+ "userTicket":"ពាក្យបញ្ជាសំបុត្រអ្នកប្រើប្រាស់",
+ "admin":"ពាក្យបញ្ជា Admin",
+ "advanced":"ពាក្យបញ្ជាកម្រិតខ្ពស់",
+ "extra":"ពាក្យបញ្ជាបន្ថែម"
+ }
+ },
+ "stats":{
+ "scopes":{
+ "global":"ស្ថិតិសរុប",
+ "system":"ស្ថិតិប្រព័ន្ធ",
+ "user":"ស្ថិតិអ្នកប្រើប្រាស់",
+ "ticket":"ស្ថិតិសំបុត្រ",
+ "participants":"អ្នកចូលរួម",
+ "messages":"សារ"
+ },
+ "properties":{
+ "ticketsCreated":"សំបុត្របានបង្កើត",
+ "ticketsClosed":"សំបុត្របានបិទ",
+ "ticketsDeleted":"សំបុត្របានលុប",
+ "ticketsReopened":"សំបុត្របានបើកឡើងវិញ",
+ "ticketsAutoclosed":"សំបុត្របានបិទដោយស្វ័យប្រវត្តិ",
+ "ticketsClaimed":"សំបុត្របានទទួល",
+ "ticketsPinned":"សំបុត្របានដាក់ម្ជុល",
+ "ticketsMoved":"សំបុត្របានផ្លាស់ប្តូរ",
+ "usersBlacklisted":"អ្នកប្រើប្រាស់ក្នុងបញ្ជីខ្មៅ",
+ "transcriptsCreated":"Transcript បានបង្កើត",
+ "ticketsAutodeleted":"សំបុត្របានលុបដោយស្វ័យប្រវត្តិ",
+ "ticketsTransferred":"សំបុត្របានផ្ទេរ",
+ "ticketVolume":"ចំនួនសំបុត្រ",
+ "averageTickets":"ចំនួនសំបុត្រជាមធ្យម/អ្នកប្រើ",
+ "currentTickets":"សំបុត្របច្ចុប្បន្ន",
+ "age":"អាយុសំបុត្រ",
+ "responseTime":"ពេលឆ្លើយតប",
+ "resolutionTime":"ពេលដោះស្រាយ",
+ "createdOn":"បង្កើតនៅ",
+ "createdBy":"បង្កើតដោយ",
+ "closedOn":"បិទនៅ",
+ "closedBy":"បិទដោយ",
+ "claimedOn":"ទទួលនៅ",
+ "claimedBy":"ទទួលដោយ",
+ "pinnedOn":"ដាក់ម្ជុលនៅ",
+ "pinnedBy":"ដាក់ម្ជុលដោយ",
+ "deletedOn":"លុបនៅ",
+ "deletedBy":"លុបដោយ"
+ },
+ "roles":{
+ "developer":"Developer",
+ "serverOwner":"ម្ចាស់ម៉ាស៊ីនបម្រើ",
+ "serverAdmin":"Admin ម៉ាស៊ីនបម្រើ",
+ "moderator":"ក្រុមអ្នកសម្រុះសម្រួល",
+ "support":"ក្រុមជំនួយ",
+ "member":"សមាជិក"
+ }
+ },
+ "panel":{
+ "selectTicket":"ជ្រើសរើសសំបុត្ររបស់អ្នក",
+ "selectRole":"ជ្រើសរើសតួនាទីរបស់អ្នក",
+ "selectOption":"ជ្រើសរើសជម្រើសរបស់អ្នក"
+ },
+ "priorities":{
+ "urgent":"បន្ទាន់ខ្លាំង",
+ "veryHigh":"ខ្ពស់ណាស់",
+ "high":"ខ្ពស់",
+ "normal":"ធម្មតា",
+ "low":"ទាប",
+ "veryLow":"ទាបណាស់",
+ "none":"គ្មាន"
+ }
+}
\ No newline at end of file
diff --git a/languages/korean.json b/languages/korean.json
index 00e2d6b..17234c6 100644
--- a/languages/korean.json
+++ b/languages/korean.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Korean",
diff --git a/languages/kurdish.json b/languages/kurdish.json
index 0b14b78..be9547e 100644
--- a/languages/kurdish.json
+++ b/languages/kurdish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Kurdish",
diff --git a/languages/latvian.json b/languages/latvian.json
index 859e8ce..16755a1 100644
--- a/languages/latvian.json
+++ b/languages/latvian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["NoOneNook"],
"lastedited":"16/02/2026",
"language":"Latvian",
diff --git a/languages/lithuanian.json b/languages/lithuanian.json
index ba21919..9c32861 100644
--- a/languages/lithuanian.json
+++ b/languages/lithuanian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["TsgIndrius"],
"lastedited":"16/02/2026",
"language":"Lithuanian",
diff --git a/languages/norwegian.json b/languages/norwegian.json
index 42b6ff5..a87a119 100644
--- a/languages/norwegian.json
+++ b/languages/norwegian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["NoOneNook"],
"lastedited":"16/02/2026",
"language":"Norwegian",
diff --git a/languages/persian.json b/languages/persian.json
index f262ff9..2d79b24 100644
--- a/languages/persian.json
+++ b/languages/persian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["dysashop","zhavis"],
"lastedited":"16/02/2026",
"language":"Persian",
diff --git a/languages/polish.json b/languages/polish.json
index ae3bcc9..b30c1c0 100644
--- a/languages/polish.json
+++ b/languages/polish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["DanoGlez"],
"lastedited":"16/02/2026",
"language":"Polish",
diff --git a/languages/portuguese.json b/languages/portuguese.json
index 182a73d..3e3ad64 100644
--- a/languages/portuguese.json
+++ b/languages/portuguese.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["quiradon"],
"lastedited":"16/02/2026",
"language":"Portuguese",
diff --git a/languages/romanian.json b/languages/romanian.json
index 36e26ee..3521dc7 100644
--- a/languages/romanian.json
+++ b/languages/romanian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["SankeDev"],
"lastedited":"16/02/2026",
"language":"Romanian",
diff --git a/languages/russian.json b/languages/russian.json
index adc1081..16e833c 100644
--- a/languages/russian.json
+++ b/languages/russian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["NoOneNook"],
"lastedited":"16/02/2026",
"language":"Russian",
diff --git a/languages/simplified-chinese.json b/languages/simplified-chinese.json
index 07457d7..4d1564c 100644
--- a/languages/simplified-chinese.json
+++ b/languages/simplified-chinese.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Simplified Chainese",
diff --git a/languages/slovenian.json b/languages/slovenian.json
index 6ec6988..305d3e4 100644
--- a/languages/slovenian.json
+++ b/languages/slovenian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Solvenian",
diff --git a/languages/spanish.json b/languages/spanish.json
index f9d7335..cf15d56 100644
--- a/languages/spanish.json
+++ b/languages/spanish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["Redactado","Josuens"],
"lastedited":"16/02/2026",
"language":"Spanish",
diff --git a/languages/swedish.json b/languages/swedish.json
index d71f506..15571cc 100644
--- a/languages/swedish.json
+++ b/languages/swedish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["NoOneNook"],
"lastedited":"16/02/2026",
"language":"Svenska",
diff --git a/languages/tamil.json b/languages/tamil.json
index 0a52857..9b68dc7 100644
--- a/languages/tamil.json
+++ b/languages/tamil.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["HanumeshGupta","ChatGPT"],
"lastedited":"16/02/2026",
"language":"Tamil",
diff --git a/languages/thai.json b/languages/thai.json
index 71f1294..f2b4b6a 100644
--- a/languages/thai.json
+++ b/languages/thai.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["modshd"],
"lastedited":"16/02/2026",
"language":"Thai",
diff --git a/languages/traditional-chinese.json b/languages/traditional-chinese.json
new file mode 100644
index 0000000..d44f21c
--- /dev/null
+++ b/languages/traditional-chinese.json
@@ -0,0 +1,608 @@
+{
+ "_TRANSLATION":{
+ "otversion":"v4.2.0",
+ "translators":["me.october"],
+ "lastedited":"10/03/2026",
+ "language":"Traditional Chinese",
+ "automated":false
+ },
+ "checker":{
+ "system":{
+ "typeError":"[錯誤]",
+ "headerOpenTicket":"開啟工單",
+ "typeWarning":"[警告]",
+ "typeInfo":"[信息]",
+ "headerConfigChecker":"配置檢查器",
+ "headerDescription":"檢查您的配置文件中的錯誤!",
+ "footerError":"機器人將無法啟動,直到所有{0}錯誤被修複!",
+ "footerWarning":"建議在啟動前修複所有{0}警告!",
+ "footerSupport":"支援:{0} - 文檔:{1}",
+ "compactInformation":"使用{0}獲取更多信息!",
+ "dataPath":"路徑",
+ "dataDocs":"文檔",
+ "dataMessages":"消息"
+ },
+ "messages":{
+ "stringTooShort":"此字符串不能少於{0}個字符!",
+ "stringTooLong":"此字符串不能超過{0}個字符!",
+ "stringLengthInvalid":"此字符串長度必須為{0}個字符!",
+ "stringStartsWith":"此字符串必須以{0}開頭!",
+ "stringEndsWith":"此字符串必須以{0}結尾!",
+ "stringContains":"此字符串必須包含{0}!",
+ "stringChoices":"此字符串隻能是以下值之一:{0}!",
+ "stringRegex":"此字符串無效!",
+ "stringInvertedContains":"此字符串不能包含 {0}!",
+ "stringLowercase":"此字符串必須全部使用小寫字母!",
+ "stringUppercase":"此字符串必須全部使用大寫字母!",
+ "stringSpecialCharacters":"此字符串不能包含任何特殊字符!(僅允許 a-z、0-9 和空格)",
+ "stringNoSpaces":"此字符串不能包含空格!",
+ "stringCapitalWord":"建議此字符串中的每個單詞都以大寫字母開頭!",
+ "stringCapitalSentence":"此字符串中的某些句子似乎冇有以大寫字母開頭!",
+ "stringPunctuation":"此字符串中的句子似乎冇有以標點符號結尾!",
+
+ "numberTooShort":"此數字不能少於{0}位!",
+ "numberTooLong":"此數字不能超過{0}位!",
+ "numberLengthInvalid":"此數字長度必須為{0}位!",
+ "numberTooSmall":"此數字至少為{0}!",
+ "numberTooLarge":"此數字最多為{0}!",
+ "numberNotEqual":"此數字必須為{0}!",
+ "numberStep":"此數字必須是{0}的倍數!",
+ "numberStepOffset":"此數字必須是{0}的倍數,起始值為{1}!",
+ "numberStartsWith":"此數字必須以{0}開頭!",
+ "numberEndsWith":"此數字必須以{0}結尾!",
+ "numberContains":"此數字必須包含{0}!",
+ "numberChoices":"此數字隻能是以下值之一:{0}!",
+ "numberFloat":"此數字不能為小數!",
+ "numberNegative":"此數字不能為負數!",
+ "numberPositive":"此數字不能為正數!",
+ "numberZero":"此數字不能為零!",
+ "numberNan":"此數字不能為 NaN(非數字)!",
+ "numberInvertedContains":"此數字不能包含 {0}!",
+
+ "booleanTrue":"此佈爾值不能為真!",
+ "booleanFalse":"此佈爾值不能為假!",
+
+ "arrayEmptyDisabled":"此數組不允許為空!",
+ "arrayEmptyRequired":"此數組必須為空!",
+ "arrayTooShort":"此數組長度至少為{0}!",
+ "arrayTooLong":"此數組長度最多為{0}!",
+ "arrayLengthInvalid":"此數組長度必須為{0}!",
+ "arrayInvalidTypes":"此數組隻能包含以下類型:{0}!",
+ "arrayDouble":"此數組不允許重複值!",
+
+ "discordInvalidId":"這是無效的Discord {0} ID!",
+ "discordInvalidIdOptions":"這是無效的Discord {0} ID!您還可以使用以下之一:{1}!",
+ "discordInvalidToken":"這是無效的Discord令牌(文法上)!",
+ "colorInvalid":"這是無效的十六進製顔色!",
+ "emojiTooShort":"此字符串至少需要{0}個錶情符號!",
+ "emojiTooLong":"此字符串最多隻能有{0}個錶情符號!",
+ "emojiCustom":"此錶情符號不能是自定義Discord錶情符號!",
+ "emojiInvalid":"這是無效的錶情符號!",
+ "urlInvalid":"此URL無效!",
+ "urlInvalidHttp":"This url can only use the https:// protocol!",
+ "urlInvalidProtocol":"This url can only use the http:// & https:// protocols!",
+ "urlInvalidHostname":"此URL的主機名不被允許!",
+ "urlInvalidExtension":"此URL的擴展名無效!請選擇:{0}!",
+ "urlInvalidPath":"此URL的路徑無效!",
+ "idNotUnique":"此ID不唯一,請使用其他ID!",
+ "idNonExistent":"ID {0}不存在!",
+
+ "invalidType":"此屬性必須為類型:{0}!",
+ "propertyMissing":"此對象缺少屬性{0}!",
+ "propertyOptional":"此對象中的屬性{0}是可選的!",
+ "objectDisabled":"此對象已禁用,請使用{0}啟用!",
+ "nullInvalid":"此屬性不能為null!",
+ "switchInvalidType":"此屬性必須是以下類型之一:{0}!",
+ "objectSwitchInvalid":"此對象必須是以下類型之一:{0}!",
+
+ "invalidLanguage":"這是無效的語言!",
+ "invalidButton":"此按鈕必須至少有一個{0}或{1}!",
+ "unusedOption":"選項{0}未在任何地方使用!",
+ "unusedQuestion":"問題{0}未在任何地方使用!",
+ "dropdownOption":"啟用下拉菜單的麵闆隻能包含“ticket”類型的選項!",
+ "customInvalidVersion":"配置文件中指定的版本不匹配!請確保您已將配置更新至最新版本!"
+ }
+ },
+ "actions":{
+ "buttons":{
+ "create":"訪問工單",
+ "close":"關閉工單",
+ "delete":"刪除工單",
+ "reopen":"重新開啟工單",
+ "claim":"認領工單",
+ "unclaim":"取消認領工單",
+ "pin":"置頂工單",
+ "unpin":"取消置頂工單",
+ "clear":"刪除工單",
+ "helpSwitchSlash":"檢視斜杠命令",
+ "helpSwitchText":"檢視文本命令",
+ "helpPage":"第{0}頁",
+ "withReason":"帶原因",
+ "withoutTranscript":"不帶記錄"
+ },
+ "titles":{
+ "created":"工單已創建",
+ "close":"工單已關閉",
+ "delete":"工單已刪除",
+ "reopen":"工單已重新開啟",
+ "claim":"工單已認領",
+ "unclaim":"工單已取消認領",
+ "pin":"工單已置頂",
+ "unpin":"工單已取消置頂",
+ "rename":"工單已重命名",
+ "move":"工單已移動",
+ "add":"工單用戶已添加",
+ "remove":"工單用戶已移除",
+
+ "help":"可用命令",
+ "statsReset":"重置統計",
+ "blacklistAdd":"用戶已拉黑",
+ "blacklistRemove":"用戶已解禁",
+ "blacklistGet":"已拉黑用戶",
+ "blacklistView":"當前黑名單",
+ "blacklistAddDm":"已加入黑名單",
+ "blacklistRemoveDm":"已從黑名單移除",
+ "clear":"工單已清除",
+ "clearTickets":"清除工單",
+ "roles":"角色已更新",
+
+ "autoclose":"工單自動關閉",
+ "autocloseEnabled":"自動關閉已啟用",
+ "autocloseDisabled":"自動關閉已禁用",
+ "autodelete":"工單自動刪除",
+ "autodeleteEnabled":"自動刪除已啟用",
+ "autodeleteDisabled":"自動刪除已禁用",
+
+ "topicSet":"主題已更改",
+ "prioritySet":"優先級已更改",
+ "priorityGet":"工單優先級",
+ "transfer":"工單已轉移"
+ },
+ "descriptions":{
+ "create":"您的工單已創建。點選下方按鈕訪問!",
+ "close":"工單已成功關閉!",
+ "delete":"工單已成功刪除!",
+ "reopen":"工單已成功重新開啟!",
+ "claim":"工單已成功認領!",
+ "unclaim":"工單已成功取消認領!",
+ "pin":"工單已成功置頂!",
+ "unpin":"工單已成功取消置頂!",
+ "rename":"工單已成功重命名為{0}!",
+ "move":"工單已成功移動到{0}!",
+ "add":"{0}已成功添加到工單!",
+ "remove":"{0}已成功從工單移除!",
+
+ "helpExplanation":"`<名稱>` => 必填參數\n`[名稱]` => 可選參數",
+ "statsReset":"機器人統計已成功重置!",
+ "statsError":"無法檢視工單統計!\n{0}不是工單!",
+ "blacklistAdd":"{0}已成功拉黑!",
+ "blacklistRemove":"{0}已成功解禁!",
+ "blacklistGetSuccess":"{0}當前已被拉黑!",
+ "blacklistGetEmpty":"{0}當前未被拉黑!",
+ "blacklistViewEmpty":"尚未有人被拉黑!",
+ "blacklistViewTip":"使用“/blacklist add”拉黑用戶!",
+ "clearVerify":"確定要刪除多個工單嗎?\n此操作無法撤銷!",
+ "clearReady":"{0}個工單已成功刪除!",
+ "rolesEmpty":"未更新任何角色!",
+
+ "autocloseLeave":"此工單已自動關閉,因為創建者離開了服務器!",
+ "autocloseTimeout":"此工單已自動關閉,因為它已超過`{0}小時`未活動!",
+ "autodeleteLeave":"此工單已自動刪除,因為創建者離開了服務器!",
+ "autodeleteTimeout":"此工單已自動刪除,因為它已超過`{0}天`未活動!",
+ "autocloseEnabled":"此工單已啟用自動關閉!\n超過`{0}小時`未活動後將自動關閉!",
+ "autocloseDisabled":"此工單已禁用自動關閉!\n不再自動關閉!",
+ "autodeleteEnabled":"此工單已啟用自動刪除!\n超過`{0}天`未活動後將自動刪除!",
+ "autodeleteDisabled":"此工單已禁用自動刪除!\n不再自動刪除!",
+
+ "ticketMessageLimit":"您隻能同時創建{0}個工單!",
+ "ticketMessageAutoclose":"此工單將在超過{0}小時未活動後自動關閉!",
+ "ticketMessageAutodelete":"此工單將在超過{0}天未活動後自動刪除!",
+ "panelReady":"麵闆已在後續消息中可用!\n此消息現在可以刪除!",
+
+ "topicSet":"頻道主題已由 {0} 成功更改!",
+ "prioritySet":"工單優先級已由 {1} 成功更改為 {0}!",
+ "priorityGet":"此工單當前的優先級為 {0}。",
+ "transfer":"工單所有權已由 {2} 成功從 {0} 轉移至 {1}!"
+ },
+ "modal":{
+ "closePlaceholder":"您為什麼關閉此工單?",
+ "deletePlaceholder":"您為什麼刪除此工單?",
+ "reopenPlaceholder":"您為什麼重新開啟此工單?",
+ "claimPlaceholder":"您為什麼認領此工單?",
+ "unclaimPlaceholder":"您為什麼取消認領此工單?",
+ "pinPlaceholder":"您為什麼置頂此工單?",
+ "unpinPlaceholder":"您為什麼取消置頂此工單?"
+ },
+ "logs":{
+ "createLog":"{0}創建了一個新工單!",
+ "closeLog":"此工單已被{0}關閉!",
+ "closeDm":"您的工單已在我們的服務器中關閉!",
+ "deleteLog":"此工單已被{0}刪除!",
+ "deleteDm":"您的工單已在我們的服務器中刪除!",
+ "reopenLog":"此工單已被{0}重新開啟!",
+ "reopenDm":"您的工單已在我們的服務器中重新開啟!",
+ "claimLog":"此工單已被{0}認領!",
+ "claimDm":"您的工單已在我們的服務器中被認領!",
+ "unclaimLog":"此工單已被{0}取消認領!",
+ "unclaimDm":"您的工單已在我們的服務器中取消認領!",
+ "pinLog":"此工單已被{0}置頂!",
+ "pinDm":"您的工單已在我們的服務器中置頂!",
+ "unpinLog":"此工單已被{0}取消置頂!",
+ "unpinDm":"您的工單已在我們的服務器中取消置頂!",
+ "renameLog":"此工單已被{1}重命名為{0}!",
+ "renameDm":"您的工單已在我們的服務器中重命名為{0}!",
+ "moveLog":"此工單已被{1}移動到{0}!",
+ "moveDm":"您的工單已在我們的服務器中移動到{0}!",
+ "addLog":"{0}已被{1}添加到此工單!",
+ "addDm":"{0}已被添加到您的工單中!",
+ "removeLog":"{0}已被{1}從此工單移除!",
+ "removeDm":"{0}已被從您的工單中移除!",
+
+ "blacklistAddLog":"{0}被{1}拉黑!",
+ "blacklistRemoveLog":"{0}被{1}從黑名單移除!",
+ "blacklistAddDm":"您已被我們的服務器拉黑!\n從現在起,您無法創建工單!",
+ "blacklistRemoveDm":"您已被我們的服務器解禁!\n現在您可以再次創建工單!",
+ "clearLog":"{0}個工單已被{1}刪除!",
+
+ "transferLog":"此工單的所有權已由 {2} 從 {0} 轉移至 {1}!",
+ "transferDm":"您在服務器中的工單所有權已從 {0} 轉移至 {1}!",
+ "prioritySetLog":"此工單的優先級已由 {1} 更改為 {0}!",
+ "prioritySetDm":"您在服務器中的工單優先級已更改為 {0}!",
+ "roleUpdateLog":"{0} 已更新其角色!",
+ "roleUpdateDm":"您在服務器中的角色已更新!"
+ }
+ },
+ "transcripts":{
+ "success":{
+ "visit":"檢視記錄",
+ "ready":"記錄已創建",
+ "textFileDescription":"這是已刪除工單的文本記錄!",
+ "htmlProgress":"請等待此HTML記錄處理完成...",
+
+ "createdChannel":"服務器中已創建一個新的{0}記錄!",
+ "createdCreator":"已為您的工單創建一個新的{0}記錄!",
+ "createdParticipant":"您參與的工單中已創建一個新的{0}記錄!",
+ "createdActiveAdmin":"您作為管理員參與的工單中已創建一個新的{0}記錄!",
+ "createdEveryAdmin":"您曾擔任管理員的工單中已創建一個新的{0}記錄!",
+ "createdOther":"已創建一個新的{0}記錄!"
+ },
+ "errors":{
+ "retry":"重試",
+ "continue":"刪除無記錄",
+ "backup":"創建備份記錄",
+ "error":"創建記錄時出錯。\n您想怎麼做?\n\n在您點選以下按鈕之前,此工單不會被刪除。",
+ "title":"記錄錯誤"
+ },
+ "text":{
+ "messagesTitle":"消息",
+ "embedTitle":"EMBED",
+ "fileTitle":"文件",
+ "fieldsTitle":"字段",
+ "reactionsTitle":"反應",
+ "statsTitle":"統計",
+ "emptyContent":"<內容為空>",
+ "noTitle":"<無標題>",
+ "noDesc":"<無描述>"
+ }
+ },
+ "errors":{
+ "titles":{
+ "internalError":"內部錯誤",
+ "optionMissing":"命令選項缺失",
+ "optionInvalid":"命令選項無效",
+ "unknownCommand":"未知命令",
+ "noPermissions":"無權限",
+ "unknownTicket":"未知工單",
+ "deprecatedTicket":"過時工單",
+ "unknownOption":"未知選項",
+ "unknownPanel":"未知麵闆",
+ "notInGuild":"不在服務器中",
+ "channelRename":"無法重命名頻道",
+ "busy":"工單繁忙",
+ "permissionError":"權限錯誤"
+ },
+ "descriptions":{
+ "askForInfo":"請聯係此機器人的所有者獲取更多信息!",
+ "askForInfoResolve":"如果此問題在多次嘗試後仍未解決,請聯係此機器人的所有者。",
+ "internalError":"由於內部錯誤,無法回響此{0}!",
+ "optionMissing":"此命令缺少必填參數!",
+ "optionInvalid":"此命令中的參數無效!",
+ "optionInvalidChoose":"請選擇",
+ "unknownCommand":"請訪問幫助菜單獲取更多信息!",
+ "noPermissions":"您無權使用此{0}!",
+ "noPermissionsList":"所需權限:(其中之一)",
+ "noPermissionsCooldown":"您因冷卻時間無法使用此{0}!",
+ "noPermissionsBlacklist":"您因被拉黑無法使用此{0}!",
+ "noPermissionsLimitGlobal":"您無法創建工單,因為服務器已達到最大工單限製!",
+ "noPermissionsLimitGlobalUser":"您無法創建工單,因為您已達到最大工單限製!",
+ "noPermissionsLimitOption":"您無法創建工單,因為服務器已達到此選項的最大工單限製!",
+ "noPermissionsLimitOptionUser":"您無法創建工單,因為您已達到此選項的最大工單限製!",
+ "unknownTicket":"請在有效工單中重試此命令!",
+ "deprecatedTicket":"當前頻道不是有效工單!可能是舊版Open Ticket的工單!",
+ "notInGuild":"此{0}在私信中無效!請在服務器中重試!",
+ "channelRename":"由於Discord速率限製,機器人目前無法重命名頻道。如果機器人未重啟,頻道將在10分鍾後自動重命名。",
+ "channelRenameSource":"此錯誤的來源是:{0}",
+ "busy":"無法使用此{0}!\n工單當前正在被機器人處理。\n\n請幾秒後重試!",
+ "closeBeforeMessage":"用戶發送消息之前,無法關閉或刪除此工單。",
+ "closeBeforeAdminMessage":"工單管理員或支援成員發送消息之前,無法關閉或刪除此工單。",
+ "unableToCreateTicket":"您無法創建工單。"
+ },
+ "optionInvalidReasons":{
+ "stringRegex":"值不符合模式!",
+ "stringMinLength":"值至少需要{0}個字符!",
+ "stringMaxLength":"值最多需要{0}個字符!",
+ "numberInvalid":"無效數字!",
+ "numberMin":"數字至少為{0}!",
+ "numberMax":"數字最多為{0}!",
+ "numberDecimal":"數字不能為小數!",
+ "numberNegative":"數字不能為負數!",
+ "numberPositive":"數字不能為正數!",
+ "numberZero":"數字不能為零!",
+ "channelNotFound":"無法找到頻道!",
+ "userNotFound":"無法找到用戶!",
+ "roleNotFound":"無法找到角色!",
+ "memberNotFound":"無法找到用戶!",
+ "mentionableNotFound":"無法找到用戶或角色!",
+ "channelType":"無效的頻道類型!",
+ "notInGuild":"此選項需要您在服務器中!"
+ },
+ "permissions":{
+ "developer":"您需要是機器人的開發者。",
+ "owner":"您需要是服務器所有者。",
+ "admin":"您需要是服務器管理員。",
+ "moderator":"您需要是版主。",
+ "support":"您需要是支援團隊成員。",
+ "member":"您需要是成員。",
+ "discord-administrator":"您需要擁有`ADMINISTRATOR`權限。"
+ },
+ "actionInvalid":{
+ "close":"工單已關閉!",
+ "reopen":"工單未關閉!",
+ "claim":"工單已認領!",
+ "unclaim":"工單未認領!",
+ "pin":"工單已置頂!",
+ "unpin":"工單未置頂!",
+ "add":"此用戶已可訪問工單!",
+ "remove":"無法從此工單移除此用戶!"
+ }
+ },
+ "params":{
+ "uppercase":{
+ "ticket":"工單",
+ "tickets":"工單",
+ "reason":"原因",
+ "creator":"創建者",
+ "remaining":"剩餘時間",
+ "added":"已添加",
+ "removed":"已移除",
+ "filter":"篩選",
+ "method":"方式",
+ "type":"類型",
+ "blacklisted":"已拉黑",
+ "panel":"麵闆",
+ "command":"命令",
+ "system":"係統",
+ "true":"是",
+ "false":"否",
+ "syntax":"文法",
+ "originalName":"原名稱",
+ "newName":"新名稱",
+ "until":"直到",
+ "validOptions":"有效選項",
+ "validPanels":"有效麵闆",
+ "autoclose":"自動關閉",
+ "autodelete":"自動刪除",
+ "startupDate":"啟動日期",
+ "version":"版本",
+ "name":"名稱",
+ "role":"角色",
+ "status":"狀態",
+ "claimed":"已認領",
+ "pinned":"已置頂",
+ "creationDate":"創建日期",
+
+ "noone":"無人",
+ "open":"開啟",
+ "closed":"關閉",
+ "priority":"優先級",
+ "participants":"參與者",
+ "yes":"是",
+ "no":"否",
+ "option":"選項",
+ "topic":"主題",
+ "uptime":"係統運行時間",
+ "messages":"消息",
+ "embeds":"嵌入",
+ "files":"文件",
+ "components":"組件",
+ "cooldown":"冷卻時間",
+ "maxTickets":"最大工單數",
+ "admins":"管理員",
+ "roles":"角色",
+ "size":"大小"
+ },
+ "lowercase":{
+ "text":"文本",
+ "html":"HTML",
+ "command":"命令",
+ "modal":"模態框",
+ "button":"按鈕",
+ "dropdown":"下拉菜單",
+ "method":"方式"
+ }
+ },
+ "commands":{
+ "reason":"指定一個可選原因,該原因將在日誌中可見。",
+ "help":"獲取所有可用命令的列錶。",
+ "panel":"生成帶有下拉菜單或按鈕的消息(用於工單創建)。",
+ "panelId":"您想要生成的麵闆的標識符。",
+ "panelAutoUpdate":"您希望此麵闆在編輯時自動更新嗎?",
+ "ticket":"立即創建一個工單。",
+ "ticketId":"您想要創建的工單的標識符。",
+ "close":"關閉一個工單。",
+ "delete":"刪除一個工單。",
+ "deleteNoTranscript":"刪除此工單而不創建記錄。",
+ "reopen":"重新開啟一個工單。",
+ "claim":"認領一個工單。",
+ "claimUser":"將此工單認領給其他人而不是您自己。",
+ "unclaim":"取消認領一個工單。",
+ "pin":"置頂一個工單。",
+ "unpin":"取消置頂一個工單。",
+
+ "move":"移動一個工單。",
+ "moveId":"您想要移動到的選項的標識符。",
+ "rename":"重命名一個工單。",
+ "renameName":"此工單的新名稱。",
+ "add":"將用戶添加到工單。",
+ "addUser":"要添加的用戶。",
+ "remove":"從工單中移除用戶。",
+ "removeUser":"要移除的用戶。",
+
+ "blacklist":"管理工單黑名單。",
+ "blacklistView":"檢視當前黑名單的列錶。",
+ "blacklistAdd":"將用戶添加到黑名單。",
+ "blacklistRemove":"從黑名單中移除用戶。",
+ "blacklistGet":"獲取被拉黑用戶的詳細信息。",
+ "blacklistGetUser":"要獲取詳細信息的用戶。",
+ "stats":"檢視機器人、成員或工單的統計信息。",
+ "statsReset":"重置機器人的所有統計信息(並從零開始計數)。",
+ "statsGlobal":"檢視全局統計信息。",
+ "statsUser":"檢視服務器中用戶的統計信息。",
+ "statsUserUser":"要檢視的用戶。",
+ "statsTicket":"檢視服務器中工單的統計信息。",
+ "statsTicketTicket":"要檢視的工單。",
+
+ "clear":"同時刪除多個工單。",
+ "clearFilter":"清除工單的篩選條件。",
+ "clearFilters":{
+ "all":"全部",
+ "open":"開啟",
+ "close":"關閉",
+ "claim":"已認領",
+ "unclaim":"未認領",
+ "pin":"已置頂",
+ "unpin":"未置頂",
+ "autoclose":"自動關閉"
+ },
+
+ "autoclose":"管理工單中的自動關閉。",
+ "autocloseDisable":"禁用此工單的自動關閉。",
+ "autocloseEnable":"啟用此工單的自動關閉。",
+ "autocloseEnableTime":"工單需要多少小時不活動才能自動關閉。",
+ "autodelete":"管理工單中的自動刪除。",
+ "autodeleteDisable":"禁用此工單的自動刪除。",
+ "autodeleteEnable":"啟用此工單的自動刪除。",
+ "autodeleteEnableTime":"工單需要多少天不活動才能自動刪除。",
+
+ "topic":"管理工單頻道的主題。",
+ "topicSet":"設定工單頻道的主題。",
+ "topicValue":"頻道的新主題。",
+ "topicList":"獲取所有工單及其主題和統計信息的列錶。",
+ "priority":"管理工單的優先級。",
+ "prioritySet":"設定工單的優先級。",
+ "priorityValue":"頻道的優先級。",
+ "priorityGet":"獲取工單的優先級。",
+ "priorityList":"獲取所有工單的優先級狀態列錶。",
+ "transfer":"將工單所有權從一位用戶轉移至另一位用戶。",
+ "transferUser":"要轉移給的用戶。"
+ },
+ "helpMenu":{
+ "help":"獲取所有可用命令的列錶。",
+ "ticket":"立即創建一個工單。",
+ "close":"關閉一個工單,這將禁用此頻道的寫入權限。",
+ "delete":"刪除一個工單,啟用時會創建記錄。",
+ "reopen":"重新開啟一個工單,這將重新啟用此頻道的寫入權限。",
+ "pin":"置頂一個工單。這將把工單移動到頂部,並在名稱前添加'📌'錶情符號。",
+ "unpin":"取消置頂一個工單。工單將保持當前位置,但會移除'📌'錶情符號。",
+ "move":"移動一個工單。這將更改此工單的類型。",
+ "rename":"重命名一個工單。這將更改此工單的頻道名稱。",
+ "claim":"認領一個工單。通過此操作,您可以告知團隊您正在處理此工單。",
+ "unclaim":"取消認領一個工單。通過此操作,您可以告知團隊此工單已空閒。",
+ "add":"將用戶添加到工單。這將允許用戶在此工單中讀取和寫入。",
+ "remove":"從工單中移除用戶。這將移除用戶在此工單中讀取和寫入的權限。",
+ "panel":"生成帶有下拉菜單或按鈕的消息(用於工單創建)。",
+ "blacklistView":"檢視當前黑名單的列錶。",
+ "blacklistAdd":"將用戶添加到黑名單。",
+ "blacklistRemove":"從黑名單中移除用戶。",
+ "blacklistGet":"獲取被拉黑用戶的詳細信息。",
+ "statsGlobal":"檢視全局統計信息。",
+ "statsTicket":"檢視服務器中工單的統計信息。",
+ "statsUser":"檢視服務器中用戶的統計信息。",
+ "statsReset":"重置機器人的所有統計信息(並從零開始計數)。",
+ "autocloseDisable":"禁用此工單的自動關閉。",
+ "autocloseEnable":"啟用此工單的自動關閉。",
+ "autodeleteDisable":"禁用此工單的自動刪除。",
+ "autodeleteEnable":"啟用此工單的自動刪除。",
+ "categories":{
+ "general":"通用命令",
+ "basicTicket":"基礎工單命令",
+ "advancedTicket":"高級工單命令",
+ "userTicket":"用戶工單命令",
+ "admin":"管理員命令",
+ "advanced":"高級命令",
+ "extra":"額外命令"
+ }
+ },
+ "stats":{
+ "scopes":{
+ "global":"全局統計",
+ "system":"係統統計",
+ "user":"用戶統計",
+ "ticket":"工單統計",
+ "participants":"參與者",
+ "messages":"消息"
+ },
+ "properties":{
+ "ticketsCreated":"工單已創建",
+ "ticketsClosed":"工單已關閉",
+ "ticketsDeleted":"工單已刪除",
+ "ticketsReopened":"工單已重新開啟",
+ "ticketsAutoclosed":"工單已自動關閉",
+ "ticketsClaimed":"工單已認領",
+ "ticketsPinned":"工單已置頂",
+ "ticketsMoved":"工單已移動",
+ "usersBlacklisted":"用戶已拉黑",
+ "transcriptsCreated":"記錄已創建",
+ "ticketsAutodeleted":"自動刪除的工單",
+ "ticketsTransferred":"已轉移的工單",
+ "ticketVolume":"工單量",
+ "averageTickets":"平均工單數/用戶",
+ "currentTickets":"當前工單",
+ "age":"工單時長",
+ "responseTime":"回響時間",
+ "resolutionTime":"解決時間",
+ "createdOn":"創建於",
+ "createdBy":"創建者",
+ "closedOn":"關閉於",
+ "closedBy":"關閉者",
+ "claimedOn":"認領於",
+ "claimedBy":"認領者",
+ "pinnedOn":"固定於",
+ "pinnedBy":"固定者",
+ "deletedOn":"刪除於",
+ "deletedBy":"刪除者"
+ },
+ "roles":{
+ "developer":"開發者",
+ "serverOwner":"服務器所有者",
+ "serverAdmin":"服務器管理員",
+ "moderator":"管理團隊",
+ "support":"支援團隊",
+ "member":"成員"
+ }
+ },
+ "panel":{
+ "selectTicket":"選擇您的工單",
+ "selectRole":"選擇您的角色",
+ "selectOption":"選擇您的選項"
+ },
+ "priorities":{
+ "urgent":"緊急",
+ "veryHigh":"非常高",
+ "high":"高",
+ "normal":"普通",
+ "low":"低",
+ "veryLow":"非常低",
+ "none":"無"
+ }
+}
\ No newline at end of file
diff --git a/languages/turkish.json b/languages/turkish.json
index ee66fc5..09e949b 100644
--- a/languages/turkish.json
+++ b/languages/turkish.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["palestinian"],
"lastedited":"16/02/2026",
"language":"Turkish",
diff --git a/languages/ukrainian.json b/languages/ukrainian.json
index 416da30..c1c2a19 100644
--- a/languages/ukrainian.json
+++ b/languages/ukrainian.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["Anderskiy"],
"lastedited":"16/02/2026",
"language":"Ukrainian",
diff --git a/languages/vietnamese.json b/languages/vietnamese.json
index 12d6318..24f43c0 100644
--- a/languages/vietnamese.json
+++ b/languages/vietnamese.json
@@ -1,6 +1,6 @@
{
"_TRANSLATION":{
- "otversion":"v4.1.3",
+ "otversion":"v4.2.0",
"translators":["ngocdiep2006"],
"lastedited":"16/02/2026",
"language":"Vietnamese",
diff --git a/package.json b/package.json
index 087e7b3..83b1c84 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "open-ticket",
"author": "DJdj Development",
- "version": "4.1.3",
+ "version": "4.2.0",
"description": "The most advanced open-source discord ticket bot with HTML transcripts, plugins, questions, claiming, pinning & more! Using discord.js v14 & JSON database! ",
"keywords": [
"ticket-bot",
@@ -19,20 +19,22 @@
"test": "node index.js --dev-config --dev-database --soft-plugins",
"testsetup": "node index.js --cli --dev-config --dev-database --soft-plugins",
"testnc": "node index.js --no-compile --dev-config --dev-database --soft-plugins",
- "docs": "npx typedoc --options .docs/typedoc-config.json && node .docs/createDocs.js",
- "mergelang": "node .docs/mergeTranslations.js"
+ "tools:mergelang": "bun run .tools/mergeTranslations.js",
+ "tools:sponsors": "bun run .tools/createSponsors.ts",
+ "tools:contributors": "bun run .tools/createContributors.ts"
},
- "type": "commonjs",
+ "type": "module",
"license": "GPL-3.0-only",
"dependencies": {
- "@discordjs/rest": "^2.6.0",
+ "@discordjs/rest": "^2.6.1",
+ "@open-discord-bots/framework": "^0.5.2",
"@types/node": "^22.5.0",
"@types/terminal-kit": "^2.5.7",
"ansis": "^4.2.0",
- "discord.js": "^14.24.2",
- "formatted-json-stringify": "^1.2.1",
+ "discord.js": "^14.26.4",
+ "formatted-json-stringify": "^1.3.2",
"terminal-kit": "^3.1.2",
- "typescript": "^5.9.3"
+ "typescript": "^6.0.3"
},
"repository": {
"type": "git",
@@ -45,7 +47,7 @@
"homepage": "https://openticket.dj-dj.be",
"imports": {
"#opendiscord": "./dist/src/index.js",
- "#opendiscord-types": "./dist/src/core/api/api.js"
+ "#opendiscord-types": "./dist/src/core/api.js"
},
"funding": {
"type": "individual",
diff --git a/plugins/example-plugin/index.ts b/plugins/example-plugin/index.ts
index 5441b05..68b5b6a 100644
--- a/plugins/example-plugin/index.ts
+++ b/plugins/example-plugin/index.ts
@@ -6,15 +6,15 @@ import * as discord from "discord.js"
//// Enable it in the plugin.json file! ////
/////////////////////////////////////////////
-if (utilities.project != "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!")
+if (opendiscord.project != "openticket") throw new api.ODPluginError("This plugin only works in Open Ticket!")
//Add Typescript autocomplete support for plugin data. (!!!OPTIONAL!!!)
declare module "#opendiscord-types" {
- export interface ODPluginManagerIds_Default {
+ export interface ODPluginManagerIdMappings {
"example-plugin":api.ODPlugin
}
- export interface ODConfigManagerIds_Default {
- "example-plugin:config":api.ODJsonConfig
+ export interface ODConfigManagerIdMappings {
+ "example-plugin:config":api.ODJsonConfig<{testVariable1:boolean,testVariable2:number,testVariable3:string}>
}
}
@@ -30,7 +30,7 @@ opendiscord.events.get("onConfigLoad").listen((configManager) => {
//Let's also log it to the console to let us know it worked!
const ourConfig = configManager.get("example-plugin:config")
opendiscord.log("The example config loaded successfully!","plugin",[
- {key:"var-1",value:ourConfig.data.testVariable1},
+ {key:"var-1",value:ourConfig.data.testVariable1.toString()},
{key:"var-2",value:ourConfig.data.testVariable2.toString()},
{key:"var-3",value:ourConfig.data.testVariable3.toString()}
])
diff --git a/src/actions/addTicketUser.ts b/src/actions/addTicketUser.ts
index d595597..27da7ce 100644
--- a/src/actions/addTicketUser.ts
+++ b/src/actions/addTicketUser.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//TICKET ADD USER SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:add-ticket-user"))
opendiscord.actions.get("opendiscord:add-ticket-user").workers.add([
- new api.ODWorker("opendiscord:add-ticket-user",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:add-ticket-user",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to add user to ticket! Open Ticket doesn't support threads!")
@@ -34,44 +34,31 @@ export const registerActions = async () => {
opendiscord.log("Failed to add channel permission overwrites on add-ticket-user","error")
}
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket user adding!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value,hidden:true}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:add-message").build(source,{guild,channel,user,ticket,reason,data})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:add-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUserAdded").emit([ticket,user,data,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.adding.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.adding.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"add",reason,additionalData:data}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"add",reason,additionalData:data}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.adding.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"add",reason,additionalData:data}))
+ if (creator && generalConfig.data.logs.logMessages.adding.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"add",reason,additionalData:data}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,data} = params
opendiscord.log(user.displayName+" added "+data.displayName+" to a ticket!","info",[
@@ -80,7 +67,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/calculateTicketCategory.ts b/src/actions/calculateTicketCategory.ts
new file mode 100644
index 0000000..dcc2c49
--- /dev/null
+++ b/src/actions/calculateTicketCategory.ts
@@ -0,0 +1,129 @@
+///////////////////////////////////////
+//CALCULATE TICKET CATEGORY SYSTEM
+///////////////////////////////////////
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
+import * as discord from "discord.js"
+
+const generalConfig = opendiscord.configs.get("opendiscord:general")
+
+export async function registerActions(){
+ opendiscord.actions.add(new api.ODAction("opendiscord:calculate-ticket-category"))
+ opendiscord.actions.get("opendiscord:calculate-ticket-category").workers.add([
+ new api.ODWorker("opendiscord:default-category",2,async (instance,params,origin,cancel) => {
+ //handle default category
+ const {guild,user,channel,option,ticket,currentCategoryId} = params
+
+ const defaultCategoryId = option.get("opendiscord:channel-category").value
+ if (!defaultCategoryId){
+ //default category is disabled
+ instance.newCategoryId = null
+ instance.newCategoryMode = null
+ instance.newCategory = null
+ instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
+ }else{
+ const defaultCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,defaultCategoryId)
+ if (defaultCategory){
+ //default category is enabled
+ instance.newCategoryId = defaultCategoryId
+ instance.newCategoryMode = "default"
+ instance.newCategory = defaultCategory
+ instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
+ }else{
+ //default category is not found (do not switch categories)
+ opendiscord.log("Unable to find ticket category '"+defaultCategoryId+"' #1","error",[
+ {key:"categoryid",value:defaultCategoryId},
+ {key:"type",value:"default"}
+ ])
+ instance.newCategoryId = null
+ instance.newCategoryMode = null
+ instance.newCategory = null
+ instance.shouldChangeCategory = false
+ }
+ }
+ }),
+ new api.ODWorker("opendiscord:close-category",1,async (instance,params,origin,cancel) => {
+ //handle close category
+ const {guild,user,channel,option,ticket,currentCategoryId} = params
+ if (!ticket) return
+ if (!ticket.get("opendiscord:closed").value) return
+ if (!generalConfig.data.ticketSystem.closedCategory.enabled) return
+
+ const closeCategoryId = generalConfig.data.ticketSystem.closedCategory.categoryId
+ if (!closeCategoryId) return
+ const closeCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,closeCategoryId)
+ if (closeCategory){
+ //close category is enabled
+ instance.newCategoryId = closeCategoryId
+ instance.newCategoryMode = "close"
+ instance.newCategory = closeCategory
+ instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
+ }else{
+ //close category is not found (do not switch categories)
+ opendiscord.log("Unable to find ticket category '"+closeCategoryId+"' #2","error",[
+ {key:"categoryid",value:closeCategoryId},
+ {key:"type",value:"close"}
+ ])
+ instance.newCategoryId = null
+ instance.newCategoryMode = null
+ instance.newCategory = null
+ instance.shouldChangeCategory = false
+ }
+ }),
+ new api.ODWorker("opendiscord:claim-category",0,async (instance,params,origin,cancel) => {
+ //handle claim category
+ const {guild,user,channel,option,ticket,currentCategoryId} = params
+ if (!ticket) return
+ if (!ticket.get("opendiscord:claimed").value) return
+
+ const claimedCategoryIds = generalConfig.data.ticketSystem.claimedCategories
+ const claimCategoryId = claimedCategoryIds.find((c) => c.user == user.id)?.category
+ if (!claimCategoryId) return
+ const claimCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,claimCategoryId)
+ if (claimCategory){
+ //claim category is enabled
+ instance.newCategoryId = claimCategoryId
+ instance.newCategoryMode = "claim"
+ instance.newCategory = claimCategory
+ instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
+ }else{
+ //claim category is not found (do not switch categories)
+ opendiscord.log("Unable to find ticket category '"+claimCategoryId+"' #3","error",[
+ {key:"categoryid",value:claimCategoryId},
+ {key:"type",value:"claim"}
+ ])
+ instance.newCategoryId = null
+ instance.newCategoryMode = null
+ instance.newCategory = null
+ instance.shouldChangeCategory = false
+ }
+ }),
+ new api.ODWorker("opendiscord:backup-category",-100,async (instance,params,origin,cancel) => {
+ //handle backup category
+ const {guild,user,channel,option,ticket,currentCategoryId} = params
+ if (!instance.newCategory || !instance.newCategoryId || !instance.shouldChangeCategory) return
+ if (instance.newCategory.children.cache.size < 50) return
+ if (!generalConfig.data.ticketSystem.backupCategory.enabled) return
+
+ const backupCategoryId = generalConfig.data.ticketSystem.backupCategory.categoryId
+ if (!backupCategoryId) return
+ const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,backupCategoryId)
+ if (backupCategory){
+ //backup category is enabled
+ instance.newCategoryId = backupCategoryId
+ instance.newCategoryMode = "backup"
+ instance.newCategory = backupCategory
+ instance.shouldChangeCategory = (instance.newCategoryId !== currentCategoryId)
+ }else{
+ //backup category is not found (do not switch categories)
+ opendiscord.log("Unable to find ticket category '"+backupCategoryId+"' #4","error",[
+ {key:"categoryid",value:backupCategoryId},
+ {key:"type",value:"backup"}
+ ])
+ instance.newCategoryId = null
+ instance.newCategoryMode = null
+ instance.newCategory = null
+ instance.shouldChangeCategory = false
+ }
+ })
+ ])
+}
\ No newline at end of file
diff --git a/src/actions/calculateTicketName.ts b/src/actions/calculateTicketName.ts
new file mode 100644
index 0000000..57930fc
--- /dev/null
+++ b/src/actions/calculateTicketName.ts
@@ -0,0 +1,31 @@
+///////////////////////////////////////
+//CALCULATE TICKET NAME SYSTEM
+///////////////////////////////////////
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
+import * as discord from "discord.js"
+
+const generalConfig = opendiscord.configs.get("opendiscord:general")
+
+export async function registerActions(){
+ opendiscord.actions.add(new api.ODAction("opendiscord:calculate-ticket-name"))
+ opendiscord.actions.get("opendiscord:calculate-ticket-name").workers.add([
+ new api.ODWorker("opendiscord:calculate-ticket-name",0,async (instance,params,origin,cancel) => {
+ const {guild,user,channel,option,ticket,currentChannelName} = params
+
+ //calculate base channel name
+ const channelPrefix = option.get("opendiscord:channel-prefix").value
+ const channelSuffix = (ticket) ? ticket.get("opendiscord:channel-suffix").value : (await opendiscord.options.suffix.getSuffixFromOption(option,user,guild) ?? "unknown")
+ const channelRenamed = (ticket && ticket.exists("opendiscord:channel-renamed")) ? ticket.get("opendiscord:channel-renamed").value : null
+ const baseChannelName = (channelRenamed) ? channelRenamed : channelPrefix+channelSuffix
+
+ //calculate status emojis
+ const pinEmoji = (ticket && ticket.get("opendiscord:pinned").value) ? generalConfig.data.ticketSystem.pinEmoji : ""
+ const closeEmoji = (ticket && ticket.get("opendiscord:closed").value) ? generalConfig.data.ticketSystem.closeEmoji : ""
+ const priorityEmoji = (ticket) ? (opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? "") : ""
+
+ instance.newChannelName = pinEmoji+closeEmoji+priorityEmoji+baseChannelName
+ instance.newChannelSuffix = channelSuffix
+ instance.shouldChangeName = (instance.newChannelName !== currentChannelName)
+ })
+ ])
+}
\ No newline at end of file
diff --git a/src/actions/claimTicket.ts b/src/actions/claimTicket.ts
index 502db01..e6a8c79 100644
--- a/src/actions/claimTicket.ts
+++ b/src/actions/claimTicket.ts
@@ -1,15 +1,16 @@
///////////////////////////////////////
//TICKET CLAIMING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:claim-ticket"))
opendiscord.actions.get("opendiscord:claim-ticket").workers.add([
- new api.ODWorker("opendiscord:claim-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:claim-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to claim ticket! Open Ticket doesn't support threads!")
@@ -22,67 +23,66 @@ export const registerActions = async () => {
ticket.get("opendiscord:busy").value = true
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-claimed",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-claimed",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-claimed",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-claimed",user.id,1,"increase")
- //update category
+ //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
- const rawClaimCategory = ticket.option.get("opendiscord:channel-categories-claimed").value.find((c) => c.user == user.id)
- const claimCategory = (rawClaimCategory) ? rawClaimCategory.category : null
- if (claimCategory){
- try {
- channel.setParent(claimCategory,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = "claimed"
- ticket.get("opendiscord:category").value = claimCategory
- }catch(e){
- opendiscord.log("Unable to move ticket to 'claimed category'!","error",[
+ const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("claim-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
+ if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
+ const originalCategoryName = channel.parent?.name ?? ""
+ const newCategoryName = categoryResult.newCategory?.name ?? ""
+ try{
+ await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
+ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
+ })
+ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
+ ticket.get("opendiscord:category").value = categoryResult.newCategoryId
+ }catch(err){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-claim",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ opendiscord.log("Unable to move ticket to claimed category.","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
- {key:"categoryid",value:claimCategory}
+ {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
}
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket claiming!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user,ticket,reason})).message)
+ if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
+ messageType:"claim-message",
+ messageOrigin:"other",
+ messageAuthor:user.id,
+ messageReason:reason
+ },false)
+ }
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketClaimed").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.claiming.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.claiming.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"claim",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" claimed a ticket!","info",[
@@ -91,7 +91,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
@@ -99,184 +99,4 @@ export const registerActions = async () => {
//set busy to false in case of crash or cancel
params.ticket.get("opendiscord:busy").value = false
})
-}
-
-export const registerVerifyBars = async () => {
- //CLAIM TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.claim
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when already claimed
- if (ticket.get("opendiscord:claimed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start claiming ticket
- if (params.data == "reason"){
- //claim with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //claim without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:claim-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //CLAIM TICKET UNCLAIM MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket-unclaim-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-unclaim-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.claim
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when already claimed
- if (ticket.get("opendiscord:claimed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start claiming ticket
- if (params.data == "reason"){
- //claim with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:claim-ticket-reason").build("unclaim-message",{guild,channel,user,ticket}))
- }else{
- //claim without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:claim-ticket").run("unclaim-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("unclaim-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").failure.add([
- new api.ODWorker("opendiscord:back-to-unclaim-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
}
\ No newline at end of file
diff --git a/src/actions/clearTickets.ts b/src/actions/clearTickets.ts
index f2fac57..3c15e2b 100644
--- a/src/actions/clearTickets.ts
+++ b/src/actions/clearTickets.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//CLEAR TICKETS SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:clear-tickets"))
opendiscord.actions.get("opendiscord:clear-tickets").workers.add([
- new api.ODWorker("opendiscord:clear-tickets",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:clear-tickets",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,filter,list} = params
await opendiscord.events.get("onTicketsClear").emit([list,user,channel,filter])
@@ -43,21 +43,21 @@ export const registerActions = async () => {
instance.list = nameList
await opendiscord.events.get("afterTicketsCleared").emit([list,user,channel,filter])
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,filter,list} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.deleting.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.deleting.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:clear-logs").build(source,{guild,channel,user,filter,list:instance.list ?? []}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:clear-logs").build(origin,{guild,channel,user,filter,list:instance.list ?? []}))
}
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,user,filter,list} = params
opendiscord.log(user.displayName+" cleared "+list.length+" tickets!","info",[
{key:"user",value:user.username},
{key:"userid",value:user.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"filter",value:filter}
])
})
diff --git a/src/actions/closeTicket.ts b/src/actions/closeTicket.ts
index e09bb2c..a151a2f 100644
--- a/src/actions/closeTicket.ts
+++ b/src/actions/closeTicket.ts
@@ -1,16 +1,17 @@
///////////////////////////////////////
//TICKET CLOSING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:close-ticket"))
opendiscord.actions.get("opendiscord:close-ticket").workers.add([
- new api.ODWorker("opendiscord:close-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:close-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to close ticket! Open Ticket doesn't support threads!")
@@ -25,33 +26,57 @@ export const registerActions = async () => {
ticket.get("opendiscord:reopened-by").value = null
ticket.get("opendiscord:reopened-on").value = null
- if (source == "autoclose") ticket.get("opendiscord:autoclosed").value = true
+ if (origin == "autoclose") ticket.get("opendiscord:autoclosed").value = true
ticket.get("opendiscord:open").value = false
ticket.get("opendiscord:busy").value = true
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-closed",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-closed",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-closed",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-closed",user.id,1,"increase")
- //update category
+ //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
- const closeCategory = ticket.option.get("opendiscord:channel-category-closed").value
- if (closeCategory !== ""){
- try {
- channel.setParent(closeCategory,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = "closed"
- ticket.get("opendiscord:category").value = closeCategory
- }catch(e){
- opendiscord.log("Unable to move ticket to 'closed category'!","error",[
+ const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("close-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
+ if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
+ const originalCategoryName = channel.parent?.name ?? ""
+ const newCategoryName = categoryResult.newCategory?.name ?? ""
+ try{
+ await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
+ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
+ })
+ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
+ ticket.get("opendiscord:category").value = categoryResult.newCategoryId
+ }catch(err){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-close",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ opendiscord.log("Unable to move ticket to closed category.","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
- {key:"categoryid",value:closeCategory}
+ {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
}
}
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("close-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
+ try{
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket close","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while closing ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
+ ])
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-close",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ }
+ }
+
//update permissions (non-staff => readonly)
const permissions: discord.OverwriteResolvable[] = [{
type:discord.OverwriteType.Role,
@@ -93,7 +118,7 @@ export const registerActions = async () => {
ticket.get("opendiscord:participants").value.forEach((participant) => {
//all participants that aren't roles/admins => readonly (OR non-viewable when enabled)
if (participant.type == "user"){
- if (generalConfig.data.system.removeParticipantsOnClose) permissions.push({
+ if (generalConfig.data.ticketSystem.removeParticipantsOnClose) permissions.push({
type:discord.OverwriteType.Member,
id:participant.id,
allow:[],
@@ -109,44 +134,39 @@ export const registerActions = async () => {
})
channel.permissionOverwrites.set(permissions)
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket closing!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason})).message)
+ if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
+ messageType:"close-message",
+ messageOrigin:"other",
+ messageAuthor:user.id,
+ messageReason:reason
+ },false)
+ }
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketClosed").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.closing.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.closing.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"close",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"close",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.closing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"close",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.closing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"close",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" closed a ticket!","info",[
@@ -155,7 +175,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
@@ -163,172 +183,4 @@ export const registerActions = async () => {
//set busy to false in case of crash or cancel
params.ticket.get("opendiscord:busy").value = false
})
-}
-
-export const registerVerifyBars = async () => {
- //CLOSE TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source,cancel) => {
- const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when already closed
- if (ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:lang.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
-
- //start closing ticket
- if (params.data == "reason"){
- //close with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //close without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:close-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //CLOSE TICKET REOPEN MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket-reopen-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-reopen-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").success.add([
- new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source,cancel) => {
- const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when already closed
- if (ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:lang.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
-
- //start closing ticket
- if (params.data == "reason"){
- //close with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:close-ticket-reason").build("reopen-message",{guild,channel,user,ticket}))
- }else{
- //close without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:close-ticket").run("reopen-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("reopen-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").failure.add([
- new api.ODWorker("opendiscord:back-to-reopen-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
}
\ No newline at end of file
diff --git a/src/actions/createTicket.ts b/src/actions/createTicket.ts
index 2e62699..c8ff9ca 100644
--- a/src/actions/createTicket.ts
+++ b/src/actions/createTicket.ts
@@ -1,63 +1,36 @@
///////////////////////////////////////
//TICKET CREATION SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket"))
opendiscord.actions.get("opendiscord:create-ticket").workers.add([
- new api.ODWorker("opendiscord:create-ticket",3,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:create-ticket",3,async (instance,params,origin,cancel) => {
const {guild,user,answers,option} = params
await opendiscord.events.get("onTicketCreate").emit([user])
await opendiscord.events.get("onTicketChannelCreation").emit([option,user])
//get channel properties
- const channelPrefix = option.get("opendiscord:channel-prefix").value
- const channelCategory = option.get("opendiscord:channel-category").value
- const channelBackupCategory = option.get("opendiscord:channel-category-backup").value
const channelTopicText = option.get("opendiscord:channel-topic").value
- const channelSuffix = await opendiscord.options.suffix.getSuffixFromOption(option,user,guild)
- const channelName = channelPrefix+channelSuffix
- //handle category
- let category: string|null = null
- let categoryMode: "backup"|"normal"|null = null
- if (channelCategory != ""){
- //category enabled
- const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
- if (!normalCategory){
- //default category was not found
- opendiscord.log("Ticket Creation Error: Unable to find category! #1","error",[
- {key:"categoryid",value:channelCategory},
- {key:"backup",value:"false"}
- ])
- }else{
- //default category was found
- if (normalCategory.children.cache.size >= 50 && channelBackupCategory != ""){
- //use backup category
- const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
- if (!backupCategory){
- //default category was not found
- opendiscord.log("Ticket Creation Error: Unable to find category! #2","error",[
- {key:"categoryid",value:channelBackupCategory},
- {key:"backup",value:"true"}
- ])
- }else{
- category = backupCategory.id
- categoryMode = "backup"
- }
- }else{
- //use default category
- category = normalCategory.id
- categoryMode = "normal"
- }
- }
- }
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("create-ticket",{guild,user,option,channel:null,ticket:null,currentChannelName:null})
+ if (!channelNameResult) return opendiscord.log("Ticket Creation Error: Unable to calculate ticket name.","error")
+ const channelName = (channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined") ? channelNameResult.newChannelName : "ot-unnamed-ticket"
+ const channelSuffix = (typeof channelNameResult.newChannelSuffix !== "undefined") ? channelNameResult.newChannelSuffix : "unknown"
+
+ //calculate category
+ const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("create-ticket",{guild,user,option,channel:null,ticket:null,currentCategoryId:null})
+ if (!categoryResult) return opendiscord.log("Ticket Creation Error: Unable to calculate ticket category.","error")
+ const ticketCategoryId = (categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined") ? categoryResult.newCategoryId : undefined
+ const ticketCategoryMode = (categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryMode !== "undefined") ? categoryResult.newCategoryMode : undefined
//handle permissions
const permissions: discord.OverwriteResolvable[] = [{
@@ -118,15 +91,15 @@ export const registerActions = async () => {
//handle channel topic
const channelTopics: string[] = []
- if (generalConfig.data.system.channelTopic.showOptionName) channelTopics.push(option.get("opendiscord:name").value)
- if (generalConfig.data.system.channelTopic.showOptionDescription) channelTopics.push(option.get("opendiscord:description").value)
- if (generalConfig.data.system.channelTopic.showOptionTopic) channelTopics.push(channelTopicText)
- if (generalConfig.data.system.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.get("opendiscord:none").renderDisplayName())
- if (generalConfig.data.system.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+lang.getTranslation("params.uppercase.open"))
- if (generalConfig.data.system.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+lang.getTranslation("params.uppercase.noone"))
- if (generalConfig.data.system.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+lang.getTranslation("params.uppercase.no"))
- if (generalConfig.data.system.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(user.id))
- if (generalConfig.data.system.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+participants.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", "))
+ if (generalConfig.data.ticketSystem.channelTopic.showOptionName) channelTopics.push(option.get("opendiscord:name").value)
+ if (generalConfig.data.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(option.get("opendiscord:description").value)
+ if (generalConfig.data.ticketSystem.channelTopic.showOptionTopic) channelTopics.push(channelTopicText)
+ if (generalConfig.data.ticketSystem.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.get("opendiscord:none").renderDisplayName())
+ if (generalConfig.data.ticketSystem.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+lang.getTranslation("params.uppercase.open"))
+ if (generalConfig.data.ticketSystem.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+lang.getTranslation("params.uppercase.noone"))
+ if (generalConfig.data.ticketSystem.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+lang.getTranslation("params.uppercase.no"))
+ if (generalConfig.data.ticketSystem.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(user.id))
+ if (generalConfig.data.ticketSystem.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+participants.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", "))
//create channel
const channel = await guild.channels.create({
@@ -134,7 +107,7 @@ export const registerActions = async () => {
name:channelName,
nsfw:false,
topic:(channelTopics.length > 0) ? channelTopics.join(" • ") : undefined,
- parent:category,
+ parent:ticketCategoryId,
reason:"Ticket Created By "+user.displayName,
permissionOverwrites:permissions,
rateLimitPerUser:slowMode
@@ -148,6 +121,7 @@ export const registerActions = async () => {
new api.ODTicketData("opendiscord:ticket-message",null),
new api.ODTicketData("opendiscord:participants",participants),
new api.ODTicketData("opendiscord:channel-suffix",channelSuffix),
+ new api.ODTicketData("opendiscord:channel-renamed",null),
new api.ODTicketData("opendiscord:previous-creators",[]),
new api.ODTicketData("opendiscord:open",true),
@@ -167,8 +141,8 @@ export const registerActions = async () => {
new api.ODTicketData("opendiscord:pinned-on",null),
new api.ODTicketData("opendiscord:for-deletion",false),
- new api.ODTicketData("opendiscord:category",category),
- new api.ODTicketData("opendiscord:category-mode",categoryMode),
+ new api.ODTicketData("opendiscord:category",ticketCategoryId ?? null),
+ new api.ODTicketData("opendiscord:category-mode",ticketCategoryMode ?? null),
new api.ODTicketData("opendiscord:autoclose-enabled",option.get("opendiscord:autoclose-enable-hours").value),
new api.ODTicketData("opendiscord:autoclose-hours",(option.get("opendiscord:autoclose-enable-hours").value ? option.get("opendiscord:autoclose-hours").value : 0)),
@@ -184,8 +158,8 @@ export const registerActions = async () => {
])
//manage stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-created",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-created",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-created",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-created",user.id,1,"increase")
//manage bot permissions
await opendiscord.events.get("onTicketPermissionsCreated").emit([option,opendiscord.permissions,channel,user])
@@ -197,7 +171,7 @@ export const registerActions = async () => {
instance.ticket = ticket
opendiscord.tickets.add(ticket)
}),
- new api.ODWorker("opendiscord:send-ticket-message",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:send-ticket-message",2,async (instance,params,origin,cancel) => {
const {guild,user,answers,option} = params
const {ticket,channel} = instance
@@ -207,17 +181,23 @@ export const registerActions = async () => {
//check if ticket message is enabled
if (!option.get("opendiscord:ticket-message-enabled").value) return
try {
- const msg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build(source,{guild,channel,user,ticket})).message)
+ const ticketMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build(origin,{guild,channel,user,ticket})).message)
- ticket.get("opendiscord:ticket-message").value = msg.id
+ if (ticketMsg) await interactiveMsgState.setMsgState({channel,message:ticketMsg},{
+ messageType:"ticket-message",
+ messageOrigin:"other",
+ messageAuthor:user.id
+ },false)
+
+ ticket.get("opendiscord:ticket-message").value = ticketMsg.id
//pin ticket message (if required)
- if (generalConfig.data.system.pinFirstTicketMessage && msg.pinnable) await msg.pin("Ticket Message")
+ if (generalConfig.data.ticketSystem.pinFirstTicketMessage && ticketMsg.pinnable) await ticketMsg.pin("Ticket Message")
//manage stats
- await opendiscord.stats.get("opendiscord:ticket").setStat("opendiscord:messages-sent",ticket.id.value,1,"increase")
+ await opendiscord.statistics.get("opendiscord:ticket").setStat("opendiscord:messages-sent",ticket.id.value,1,"increase")
- await opendiscord.events.get("afterTicketMainMessageCreated").emit([ticket,msg,channel,user])
+ await opendiscord.events.get("afterTicketMainMessageCreated").emit([ticket,ticketMsg,channel,user])
}catch(err){
process.emit("uncaughtException",err)
//something went wrong while sending the ticket message
@@ -225,20 +205,22 @@ export const registerActions = async () => {
}
await opendiscord.events.get("afterTicketCreated").emit([ticket,user,channel])
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,user,answers,option} = params
const {ticket,channel} = instance
+ if (!ticket || !channel) return opendiscord.log("Ticket Creation Error: Unable to send ticket message. Previous worker failed!","error")
+
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.creation.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.creation.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-logs").build(source,{guild,channel,user,ticket}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-logs").build(origin,{guild,channel,user,ticket}))
}
//to dm
- if (generalConfig.data.system.messages.creation.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-dm").build(source,{guild,channel,user,ticket}))
+ if (generalConfig.data.logs.logMessages.creation.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:ticket-created-dm").build(origin,{guild,channel,user,ticket}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,user,answers,option} = params
const {ticket,channel} = instance
@@ -249,7 +231,7 @@ export const registerActions = async () => {
{key:"userid",value:user.id,hidden:true},
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"option",value:option.id.value}
])
})
diff --git a/src/actions/createTicketPermissions.ts b/src/actions/createTicketPermissions.ts
index 2c1bb06..0617124 100644
--- a/src/actions/createTicketPermissions.ts
+++ b/src/actions/createTicketPermissions.ts
@@ -1,13 +1,13 @@
///////////////////////////////////////
//TICKET CREATION SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:create-ticket-permissions"))
opendiscord.actions.get("opendiscord:create-ticket-permissions").workers.add([
- new api.ODWorker("opendiscord:check-blacklist",4,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:check-blacklist",4,(instance,params,origin,cancel) => {
if (!params.option.get("opendiscord:allow-blacklisted-users").value && opendiscord.blacklist.exists(params.user.id)){
instance.valid = false
instance.reason = "blacklist"
@@ -19,7 +19,7 @@ export const registerActions = async () => {
return cancel()
}
}),
- new api.ODWorker("opendiscord:check-cooldown",3,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:check-cooldown",3,(instance,params,origin,cancel) => {
const cooldown = opendiscord.cooldowns.get("opendiscord:option-cooldown_"+params.option.id.value)
if (cooldown && cooldown instanceof api.ODTimeoutCooldown && cooldown.use(params.user.id)){
instance.valid = false
@@ -36,16 +36,16 @@ export const registerActions = async () => {
return cancel()
}
}),
- new api.ODWorker("opendiscord:check-global-limits",2,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:check-global-limits",2,(instance,params,origin,cancel) => {
const generalConfig = opendiscord.configs.get("opendiscord:general")
- if (!generalConfig.data.system.limits.enabled) return
+ if (!generalConfig.data.ticketSystem.limits.enabled) return
const allTickets = opendiscord.tickets.getAll()
const globalTicketCount = allTickets.length
const userTickets = opendiscord.tickets.getFiltered((ticket) => ticket.exists("opendiscord:opened-by") && (ticket.get("opendiscord:opened-by").value == params.user.id))
const userTicketCount = userTickets.length
- if (globalTicketCount >= generalConfig.data.system.limits.globalMaximum){
+ if (globalTicketCount >= generalConfig.data.ticketSystem.limits.globalMaximum){
instance.valid = false
instance.reason = "global-limit"
opendiscord.log(params.user.displayName+" tried to create a ticket but reached the limit!","info",[
@@ -55,7 +55,7 @@ export const registerActions = async () => {
{key:"limit",value:"global"}
])
return cancel()
- }else if (userTicketCount >= generalConfig.data.system.limits.userMaximum){
+ }else if (userTicketCount >= generalConfig.data.ticketSystem.limits.userMaximum){
instance.valid = false
instance.reason = "global-user-limit"
opendiscord.log(params.user.displayName+" tried to create a ticket, but reached the limit!","info",[
@@ -67,7 +67,7 @@ export const registerActions = async () => {
return cancel()
}
}),
- new api.ODWorker("opendiscord:check-option-limits",1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:check-option-limits",1,(instance,params,origin,cancel) => {
if (!params.option.exists("opendiscord:limits-enabled") || !params.option.get("opendiscord:limits-enabled").value) return
const allTickets = opendiscord.tickets.getFiltered((ticket) => ticket.option.id.value == params.option.id.value)
@@ -97,7 +97,7 @@ export const registerActions = async () => {
return cancel()
}
}),
- new api.ODWorker("opendiscord:valid",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:valid",0,(instance,params,origin,cancel) => {
instance.valid = true
instance.reason = null
cancel()
diff --git a/src/actions/createTranscript.ts b/src/actions/createTranscript.ts
index 825a142..2bbcb3f 100644
--- a/src/actions/createTranscript.ts
+++ b/src/actions/createTranscript.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//TRANSCRIPT CREATION SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:create-transcript"))
opendiscord.actions.get("opendiscord:create-transcript").workers.add([
- new api.ODWorker("opendiscord:select-compiler",4,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:select-compiler",4,async (instance,params,origin,cancel) => {
const {channel,user,ticket} = params
if (channel.type != discord.ChannelType.GuildText) return cancel()
if (!transcriptConfig.data.general.enabled) return cancel()
@@ -29,10 +29,15 @@ export const registerActions = async () => {
if (transcriptConfig.data.general.mode == "text") instance.compiler = opendiscord.transcripts.get("opendiscord:text-compiler")
else if (transcriptConfig.data.general.mode == "html") instance.compiler = opendiscord.transcripts.get("opendiscord:html-compiler")
}),
- new api.ODWorker("opendiscord:init-transcript",3,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:init-transcript",3,async (instance,params,origin,cancel) => {
const {channel,user,ticket} = params
if (channel.type != discord.ChannelType.GuildText) return cancel()
if (!transcriptConfig.data.general.enabled) return cancel()
+ if (!instance.compiler){
+ instance.success = false
+ cancel()
+ throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:init-transcript) => Instance is missing transcript compiler!")
+ }
//run transcript compiler init()
await opendiscord.events.get("onTranscriptInit").emit([opendiscord.transcripts,ticket,channel,user])
@@ -63,7 +68,7 @@ export const registerActions = async () => {
}
await opendiscord.events.get("afterTranscriptInitiated").emit([opendiscord.transcripts,ticket,channel,user])
}),
- new api.ODWorker("opendiscord:compile-transcript",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:compile-transcript",2,async (instance,params,origin,cancel) => {
const {channel,user,ticket} = params
if (channel.type != discord.ChannelType.GuildText) return cancel()
if (!instance.compiler){
@@ -71,6 +76,11 @@ export const registerActions = async () => {
cancel()
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:compile-transcript) => Instance is missing transcript compiler!")
}
+ if (typeof instance.initData == "undefined"){
+ instance.success = false
+ cancel()
+ throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:compile-transcript) => Instance is missing transcript initData!")
+ }
//run transcript compiler compile()
await opendiscord.events.get("onTranscriptCompile").emit([opendiscord.transcripts,ticket,channel,user])
@@ -93,15 +103,31 @@ export const registerActions = async () => {
}
await opendiscord.events.get("afterTranscriptCompiled").emit([opendiscord.transcripts,ticket,channel,user])
}),
- new api.ODWorker("opendiscord:ready-transcript",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:ready-transcript",1,async (instance,params,origin,cancel) => {
+ if (!instance.compiler){
+ instance.success = false
+ cancel()
+ throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript compiler! (1)")
+ }
if (!instance.result){
instance.success = false
cancel()
- throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript result!")
+ throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript result! (1)")
}
//run transcript compiler ready()
utilities.runAsync(async () => {
+ if (!instance.compiler){
+ instance.success = false
+ cancel()
+ throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript compiler! (2)")
+ }
+ if (!instance.result){
+ instance.success = false
+ cancel()
+ throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:ready-transcript) => Instance is missing transcript result! (2)")
+ }
+
await opendiscord.events.get("onTranscriptReady").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user])
if (instance.compiler.ready){
try{
@@ -109,9 +135,9 @@ export const registerActions = async () => {
//send channel message
if (transcriptConfig.data.general.enableChannel && channelMessage){
- if (instance.pendingMessage && instance.pendingMessage.message && instance.pendingMessage.success){
+ if (instance.pendingMessage && instance.pendingMessage.success){
//edit "pending" message to be the "ready" message
- instance.pendingMessage.message.edit(channelMessage.message)
+ instance.pendingMessage.message.edit(utilities.getMessageFromBuildResult(channelMessage,"message"))
}else{
//send ready message to channel
const post = opendiscord.posts.get("opendiscord:transcripts")
@@ -149,11 +175,11 @@ export const registerActions = async () => {
})
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:transcripts-created",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:transcripts-created",params.user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:transcripts-created",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:transcripts-created",params.user.id,1,"increase")
await opendiscord.events.get("afterTranscriptCreated").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user])
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {user,channel,ticket} = params
opendiscord.log(user.displayName+" created a transcript!","info",[
{key:"user",value:user.username},
@@ -161,8 +187,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"option",value:ticket.option.id.value},
- {key:"method",value:source,hidden:true},
- {key:"compiler",value:instance.compiler.id.value},
+ {key:"method",value:origin,hidden:true},
+ {key:"compiler",value:instance.compiler?.id.value ?? ""},
])
})
])
diff --git a/src/actions/deleteTicket.ts b/src/actions/deleteTicket.ts
index 68b0d16..500ab61 100644
--- a/src/actions/deleteTicket.ts
+++ b/src/actions/deleteTicket.ts
@@ -1,16 +1,16 @@
///////////////////////////////////////
//TICKET DELETION SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:delete-ticket"))
opendiscord.actions.get("opendiscord:delete-ticket").workers.add([
- new api.ODWorker("opendiscord:delete-ticket",3,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:delete-ticket",3,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to delete ticket! Open Ticket doesn't support threads!")
@@ -20,31 +20,18 @@ export const registerActions = async () => {
ticket.get("opendiscord:for-deletion").value = true
ticket.get("opendiscord:busy").value = true
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket deletion!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(origin,{guild,channel,user,ticket,reason})).message)
//create transcript
if (!params.withoutTranscript){
- const transcriptRes = await opendiscord.actions.get("opendiscord:create-transcript").run(source,{guild,channel,user,ticket})
+ const transcriptRes = await opendiscord.actions.get("opendiscord:create-transcript").run(origin,{guild,channel,user,ticket})
//transcript failure
if (typeof transcriptRes.success == "boolean" && !transcriptRes.success && transcriptRes.compiler){
const {compiler} = transcriptRes
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transcript-error").build(source,{guild,channel,user,ticket,compiler,reason:transcriptRes.errorReason ?? null})).message)
+ await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transcript-error").build(origin,{guild,channel,user,ticket,compiler,reason:transcriptRes.errorReason ?? null})).message)
.catch((reason) => opendiscord.log("Unable to send transcript failure to ticket channel!","error",[{key:"id",value:channel.id}]))
//undo deletion
@@ -59,8 +46,8 @@ export const registerActions = async () => {
}
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-deleted",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-deleted",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-deleted",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-deleted",user.id,1,"increase")
//delete ticket from manager
opendiscord.tickets.remove(ticket.id)
@@ -68,21 +55,21 @@ export const registerActions = async () => {
//delete permissions from manager
await (await import("../data/framework/permissionLoader.js")).removeTicketPermissions(ticket)
}),
- new api.ODWorker("opendiscord:discord-logs",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",2,async (instance,params,origin,cancel) => {
//logs before channel deletion => channel might still be used in log embeds
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.deleting.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.deleting.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.deleting.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.deleting.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"delete",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:delete-channel",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:delete-channel",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//delete channel & events
await opendiscord.events.get("onTicketChannelDeletion").emit([ticket,channel,user])
@@ -94,7 +81,7 @@ export const registerActions = async () => {
await opendiscord.events.get("afterTicketDeleted").emit([ticket,user,reason])
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" deleted a ticket!","info",[
@@ -103,7 +90,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"transcript",value:(!params.withoutTranscript).toString()},
])
})
@@ -113,357 +100,4 @@ export const registerActions = async () => {
params.ticket.get("opendiscord:busy").value = false
params.ticket.get("opendiscord:for-deletion").value = false
})
-}
-
-export const registerVerifyBars = async () => {
- //DELETE TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
- const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //don't allow deleteWithoutTranscript to non-global-admins when enabled
- if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
-
- //start deleting ticket
- if (params.data == "reason"){
- //delete with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //delete without reason
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true,withoutTranscript:(params.data == "no-transcript")})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //DELETE TICKET CLOSE MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-close-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-close-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").success.add([
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
- const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //don't allow deleteWithoutTranscript to non-global-admins when enabled
- if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
-
- //start deleting ticket
- if (params.data == "reason"){
- //delete with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("close-message",{guild,channel,user,ticket}))
- }else{
- //delete without reason
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run("close-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("close-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").failure.add([
- new api.ODWorker("opendiscord:back-to-close-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
-
- //DELETE TICKET REOPEN MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-reopen-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-reopen-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").success.add([
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
- const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //don't allow deleteWithoutTranscript to non-global-admins when enabled
- if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
-
- //start deleting ticket
- if (params.data == "reason"){
- //delete with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("reopen-message",{guild,channel,user,ticket}))
- }else{
- //delete without reason
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run("reopen-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("reopen-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").failure.add([
- new api.ODWorker("opendiscord:back-to-reopen-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
-
- //DELETE TICKET AUTOCLOSE MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket-autoclose-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-autoclose-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").success.add([
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
- const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //don't allow deleteWithoutTranscript to non-global-admins when enabled
- if (params.data == "no-transcript" && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
-
- //start deleting ticket
- if (params.data == "reason"){
- //delete with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:delete-ticket-reason").build("autoclose-message",{guild,channel,user,ticket}))
- }else{
- //delete without reason
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run("autoclose-message",{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript:(params.data == "no-transcript")})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("autoclose-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").failure.add([
- new api.ODWorker("opendiscord:back-to-autoclose-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket}))
- })
- ])
}
\ No newline at end of file
diff --git a/src/actions/handleTranscriptErrors.ts b/src/actions/handleTranscriptErrors.ts
index bc0cf9a..d9548d0 100644
--- a/src/actions/handleTranscriptErrors.ts
+++ b/src/actions/handleTranscriptErrors.ts
@@ -1,76 +1,43 @@
///////////////////////////////////////
//TRANSCRIPT ERROR SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
+import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//TRANSCRIPT ERROR RETRY
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-retry",/^od:transcript-error-retry_([^_]+)/))
opendiscord.responders.buttons.get("opendiscord:transcript-error-retry").workers.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.delete
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const originalSource = instance.interaction.customId.split("_")[1] as api.ODActionManagerIds_Default["opendiscord:delete-ticket"]["source"]
+ new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,member} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+ //fetch data
+ const originalOrigin = instance.interaction.customId.split("_")[1] as api.ODActionManagerIdMappings["opendiscord:delete-ticket"]["origin"]
+
//start deleting ticket (without reason)
await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason:"Transcript Error (Retried)",sendMessage:false,withoutTranscript:false})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason:"Transcript Error (Retried)",sendMessage:false,withoutTranscript:false})
+
+ ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Retried)"}))
-
}),
- new api.ODWorker("opendiscord:logs",-1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,async (instance,params,origin,cancel) => {
const {user,channel} = instance
if (channel.isDMBased()) return
opendiscord.log(user.displayName+" retried deleting a ticket with transcript!","info",[
@@ -78,7 +45,7 @@ export const registerButtonResponders = async () => {
{key:"userid",value:user.id,hidden:true},
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
@@ -86,68 +53,35 @@ export const registerButtonResponders = async () => {
//TRANSCRIPT ERROR CONTINUE
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-continue",/^od:transcript-error-continue_([^_]+)/))
opendiscord.responders.buttons.get("opendiscord:transcript-error-continue").workers.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.delete
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
const {guild,channel,user} = instance
- const originalSource = instance.interaction.customId.split("_")[1] as api.ODActionManagerIds_Default["opendiscord:delete-ticket"]["source"]
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
- //start deleting ticket (without reason)
+ //fetch data
+ const originalOrigin = instance.interaction.customId.split("_")[1] as api.ODActionManagerIdMappings["opendiscord:delete-ticket"]["origin"]
+
+ //start deleting ticket (without reason & without transcript)
await instance.defer("update",false)
//don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason:"Transcript Error (Continued)",sendMessage:false,withoutTranscript:true})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{guild,channel,user,ticket,reason:"Transcript Error (Continued)",sendMessage:false,withoutTranscript:true})
+
+ ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Continued)"}))
}),
- new api.ODWorker("opendiscord:logs",-1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,async (instance,params,origin,cancel) => {
const {user,channel} = instance
if (channel.isDMBased()) return
opendiscord.log(user.displayName+" continued deleting a ticket without transcript!","info",[
@@ -155,7 +89,7 @@ export const registerButtonResponders = async () => {
{key:"userid",value:user.id,hidden:true},
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/handleVerifyBar.ts b/src/actions/handleVerifyBar.ts
index 2794d71..3eb6960 100644
--- a/src/actions/handleVerifyBar.ts
+++ b/src/actions/handleVerifyBar.ts
@@ -1,32 +1,22 @@
///////////////////////////////////////
//VERIFYBAR SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
+import * as discord from "discord.js"
-export const registerButtonResponders = async () => {
- //VERIFYBAR SUCCESS
- opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-success",/^od:verifybar-success_([^_]+)/))
- opendiscord.responders.buttons.get("opendiscord:verifybar-success").workers.add(
- new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,source,cancel) => {
- const id = instance.interaction.customId.split("_")[1]
- const customData = instance.interaction.customId.split("_")[2] as string|undefined
+export async function registerButtonResponders(){
+ //HANDLE VERIFYBAR BUTTON
+ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-button",/^od:verifybar\|([^|]+)\|([^|]+)/))
+ opendiscord.responders.buttons.get("opendiscord:verifybar-button").workers.add(
+ new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,origin,cancel) => {
+ const match = /^od:verifybar\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const verifyBarId = match[1]
+ const verifyButtonId = match[2]
- const verifybar = opendiscord.verifybars.get(id)
+ const verifybar = opendiscord.verifybars.get(verifyBarId)
if (!verifybar) return
- if (verifybar.success) await verifybar.success.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message})
- })
- )
-
- //VERIFYBAR FAILURE
- opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-failure",/^od:verifybar-failure_([^_]+)/))
- opendiscord.responders.buttons.get("opendiscord:verifybar-failure").workers.add(
- new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,source,cancel) => {
- const id = instance.interaction.customId.split("_")[1]
- const customData = instance.interaction.customId.split("_")[2] as string|undefined
-
- const verifybar = opendiscord.verifybars.get(id)
- if (!verifybar) return
- if (verifybar.failure) await verifybar.failure.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message})
+ await verifybar.activate(instance,verifyButtonId)
})
)
}
\ No newline at end of file
diff --git a/src/actions/moveTicket.ts b/src/actions/moveTicket.ts
index 591aef6..2679368 100644
--- a/src/actions/moveTicket.ts
+++ b/src/actions/moveTicket.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//TICKET MOVING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:move-ticket"))
opendiscord.actions.get("opendiscord:move-ticket").workers.add([
- new api.ODWorker("opendiscord:move-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:move-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to move ticket! Open Ticket doesn't support threads!")
@@ -17,78 +17,31 @@ export const registerActions = async () => {
ticket.option = data
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-moved",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-moved",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-moved",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-moved",user.id,1,"increase")
- //get new channel properties
- const channelPrefix = ticket.option.get("opendiscord:channel-prefix").value
- const channelSuffix = ticket.get("opendiscord:channel-suffix").value
- const channelCategory = ticket.option.get("opendiscord:channel-category").value
- const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value
- const rawClaimCategory = ticket.option.get("opendiscord:channel-categories-claimed").value.find((c) => c.user == user.id)
- const claimCategory = (rawClaimCategory) ? rawClaimCategory.category : null
- const closeCategory = ticket.option.get("opendiscord:channel-category-closed").value
- const channelTopic = ticket.option.get("opendiscord:channel-topic").value
-
- //handle category
- let category: string|null = null
- let categoryMode: "backup"|"normal"|"closed"|"claimed"|null = null
- if (claimCategory){
- //use claim category
- category = claimCategory
- categoryMode = "claimed"
- }else if (closeCategory != "" && ticket.get("opendiscord:closed").value){
- //use close category
- category = closeCategory
- categoryMode = "closed"
- }else if (channelCategory != ""){
- //category enabled
- const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
- if (!normalCategory){
- //default category was not found
- opendiscord.log("Ticket Move Error: Unable to find category! #1","error",[
- {key:"categoryid",value:channelCategory},
- {key:"backup",value:"false"}
+ //calculate & update category
+ const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("move-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
+ if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
+ const originalCategoryName = channel.parent?.name ?? ""
+ const newCategoryName = categoryResult.newCategory?.name ?? ""
+ try{
+ await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
+ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
+ })
+ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
+ ticket.get("opendiscord:category").value = categoryResult.newCategoryId
+ }catch(err){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-move",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ opendiscord.log("Unable to move ticket to moved category.","error",[
+ {key:"channel",value:"#"+channel.name},
+ {key:"channelid",value:channel.id,hidden:true},
+ {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
])
- }else{
- //default category was found
- if (normalCategory.children.cache.size >= 50 && channelBackupCategory != ""){
- //use backup category
- const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
- if (!backupCategory){
- //default category was not found
- opendiscord.log("Ticket Move Error: Unable to find category! #2","error",[
- {key:"categoryid",value:channelBackupCategory},
- {key:"backup",value:"true"}
- ])
- }else{
- category = backupCategory.id
- categoryMode = "backup"
- }
- }else{
- //use default category
- category = normalCategory.id
- categoryMode = "normal"
- }
}
}
- try {
- //only move category when not the same.
- if (channel.parentId != category) await utilities.timedAwait(channel.setParent(category,{lockPermissions:false}),2500,(err) => {
- opendiscord.log("Failed to change channel category on ticket move","error")
- })
- ticket.get("opendiscord:category-mode").value = categoryMode
- ticket.get("opendiscord:category").value = category
- }catch(e){
- opendiscord.log("Unable to move ticket to 'moved category'!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"categoryid",value:category ?? "/"}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
-
//handle permissions
const permissions: discord.OverwriteResolvable[] = [{
type:discord.OverwriteType.Role,
@@ -153,58 +106,50 @@ export const registerActions = async () => {
ticket.get("opendiscord:participants").value = participants
ticket.get("opendiscord:participants").refreshDatabase()
- //rename channel (and give error when crashed)
- const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
- const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
-
- const originalName = channel.name
- const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channelPrefix+channelSuffix)
- try{
- await utilities.timedAwait(channel.setName(newName),2500,(err) => {
- opendiscord.log("Failed to rename channel on ticket move","error")
- })
- }catch(err){
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-move",{guild,channel,user,originalName,newName:newName})).message)
- }
-
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("move-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket moving!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket move","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while moving ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-move",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
}
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
+
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:move-message").build(source,{guild,channel,user,ticket,reason,data})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:move-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketMoved").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.moving.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.moving.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"move",reason,additionalData:data}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"move",reason,additionalData:data}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.moving.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"move",reason,additionalData:data}))
+ if (creator && generalConfig.data.logs.logMessages.moving.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"move",reason,additionalData:data}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" moved a ticket!","info",[
@@ -213,7 +158,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/pinTicket.ts b/src/actions/pinTicket.ts
index a388ae0..6d52953 100644
--- a/src/actions/pinTicket.ts
+++ b/src/actions/pinTicket.ts
@@ -1,15 +1,16 @@
///////////////////////////////////////
//TICKET PINNING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:pin-ticket"))
opendiscord.actions.get("opendiscord:pin-ticket").workers.add([
- new api.ODWorker("opendiscord:pin-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:pin-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to pin ticket! Open Ticket doesn't support threads!")
@@ -22,66 +23,66 @@ export const registerActions = async () => {
ticket.get("opendiscord:busy").value = true
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-pinned",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-pinned",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-pinned",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-pinned",user.id,1,"increase")
//move to top of category
if (channel.parent){
await channel.setPosition(0,{reason:"Ticket Pinned!"})
}
- //rename channel (and give error when crashed)
- const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
- const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
-
- const originalName = channel.name
- const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
- try{
- await utilities.timedAwait(channel.setName(newName),2500,(err) => {
- opendiscord.log("Failed to rename channel on ticket pin","error")
- })
- }catch(err){
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-pin",{guild,channel,user,originalName,newName})).message)
- }
-
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("pin-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket pinning!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"message",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket pin","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while pinning ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-pin",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
}
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
+
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason})).message)
+ if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
+ messageType:"pin-message",
+ messageOrigin:"other",
+ messageAuthor:user.id,
+ messageReason:reason
+ },false)
+ }
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketPinned").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.pinning.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.pinning.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"pin",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" pinned a ticket!","info",[
@@ -90,192 +91,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
-}
-
-export const registerVerifyBars = async () => {
- //PIN TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.pin
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when already pinned
- if (ticket.get("opendiscord:pinned").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start pinning ticket
- if (params.data == "reason"){
- //pin with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //pin without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:pin-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //PIN TICKET UNPIN MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket-unpin-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-unpin-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.pin
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when already pinned
- if (ticket.get("opendiscord:pinned").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start pinning ticket
- if (params.data == "reason"){
- //pin with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:pin-ticket-reason").build("unpin-message",{guild,channel,user,ticket}))
- }else{
- //pin without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:pin-ticket").run("unpin-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("unpin-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").failure.add([
- new api.ODWorker("opendiscord:back-to-unpin-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
- opendiscord.actions.get("opendiscord:pin-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
- //set busy to false in case of crash or cancel
- params.ticket.get("opendiscord:busy").value = false
- })
}
\ No newline at end of file
diff --git a/src/actions/reactionRole.ts b/src/actions/reactionRole.ts
index 84760e1..8a0a116 100644
--- a/src/actions/reactionRole.ts
+++ b/src/actions/reactionRole.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//REACTION ROLE SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:reaction-role"))
opendiscord.actions.get("opendiscord:reaction-role").workers.add([
- new api.ODWorker("opendiscord:reaction-role",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:reaction-role",2,async (instance,params,origin,cancel) => {
const {guild,user,option,overwriteMode} = params
const role = opendiscord.roles.get(option.id)
if (!role) throw new api.ODSystemError("ODAction(ot:reaction-role) => Unknown reaction role (ODRole)")
@@ -83,25 +83,25 @@ export const registerActions = async () => {
instance.result = result
await opendiscord.events.get("afterRolesUpdated").emit([user,role])
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,user,option,overwriteMode} = params
if (!instance.role || !instance.result) return
//to logs
- if (generalConfig.data.system.logs.enabled && (generalConfig.data.system.messages.reactionRole.logs)){
+ if (generalConfig.data.logs.enabled && (generalConfig.data.logs.logMessages.reactionRole.logs)){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-logs").build(source,{guild,user,role:instance.role,result:instance.result}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-logs").build(origin,{guild,user,role:instance.role,result:instance.result}))
}
//to dm
- if (generalConfig.data.system.messages.reactionRole.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-dm").build(source,{guild,user,role:instance.role,result:instance.result}))
+ if (generalConfig.data.logs.logMessages.reactionRole.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:reaction-role-dm").build(origin,{guild,user,role:instance.role,result:instance.result}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,user,option} = params
opendiscord.log(user.displayName+" updated his roles!","info",[
{key:"user",value:user.username},
{key:"userid",value:user.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"option",value:option.id.value}
])
})
diff --git a/src/actions/removeTicketUser.ts b/src/actions/removeTicketUser.ts
index 9a8ef9f..93737fc 100644
--- a/src/actions/removeTicketUser.ts
+++ b/src/actions/removeTicketUser.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//TICKET REMOVE USER SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:remove-ticket-user"))
opendiscord.actions.get("opendiscord:remove-ticket-user").workers.add([
- new api.ODWorker("opendiscord:remove-ticket-user",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:remove-ticket-user",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to remove user from ticket! Open Ticket doesn't support threads!")
@@ -29,43 +29,31 @@ export const registerActions = async () => {
opendiscord.log("Failed to remove channel permission overwrites on remove-ticket-user","error")
}
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket user removal!","error",[
- {key:"channel",value:channel.id},
- {key:"message",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:remove-message").build(source,{guild,channel,user,ticket,reason,data})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:remove-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUserRemoved").emit([ticket,user,data,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.removing.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.removing.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.removing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data}))
+ if (creator && generalConfig.data.logs.logMessages.removing.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"remove",reason,additionalData:data}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,data} = params
opendiscord.log(user.displayName+" removed "+data.displayName+" from a ticket!","info",[
@@ -74,7 +62,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/renameTicket.ts b/src/actions/renameTicket.ts
index a110f16..7ffd071 100644
--- a/src/actions/renameTicket.ts
+++ b/src/actions/renameTicket.ts
@@ -1,72 +1,67 @@
///////////////////////////////////////
//TICKET RENAMING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:rename-ticket"))
opendiscord.actions.get("opendiscord:rename-ticket").workers.add([
- new api.ODWorker("opendiscord:rename-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:rename-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to rename ticket! Open Ticket doesn't support threads!")
await opendiscord.events.get("onTicketRename").emit([ticket,user,channel,reason])
- //rename channel (and give error when crashed)
- const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
- const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
+ //update ticket
+ ticket.get("opendiscord:channel-renamed").value = data
- const originalName = channel.name
- const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(data)
- try{
- await utilities.timedAwait(channel.setName(newName),2500,(err) => {
- opendiscord.log("Failed to rename channel on ticket rename","error")
- })
- }catch(err){
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-rename",{guild,channel,user,originalName,newName:data})).message)
- }
-
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("rename-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket renaming!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket rename","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while renaming ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-rename",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
}
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
+
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:rename-message").build(source,{guild,channel,user,ticket,reason,data})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:rename-message").build(origin,{guild,channel,user,ticket,reason,data})).message)
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketRenamed").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,data} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.renaming.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.renaming.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.renaming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data}))
+ if (creator && generalConfig.data.logs.logMessages.renaming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"rename",reason,additionalData:data}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" renamed a ticket!","info",[
@@ -75,7 +70,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/reopenTicket.ts b/src/actions/reopenTicket.ts
index 5112f66..76c06b7 100644
--- a/src/actions/reopenTicket.ts
+++ b/src/actions/reopenTicket.ts
@@ -1,15 +1,16 @@
///////////////////////////////////////
//TICKET REOPENING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:reopen-ticket"))
opendiscord.actions.get("opendiscord:reopen-ticket").workers.add([
- new api.ODWorker("opendiscord:reopen-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:reopen-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to reopen ticket! Open Ticket doesn't support threads!")
@@ -28,65 +29,56 @@ export const registerActions = async () => {
ticket.get("opendiscord:open").value = true
ticket.get("opendiscord:busy").value = true
- if (generalConfig.data.system.disableAutocloseAfterReopen){
+ if (generalConfig.data.ticketSystem.disableAutocloseAfterReopen){
//disable autoclose after reopen
ticket.get("opendiscord:autoclose-enabled").value = false
ticket.get("opendiscord:autoclose-hours").value = 0
}
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-reopened",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-reopened",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-reopened",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-reopened",user.id,1,"increase")
- //update category
+ //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
- const channelCategory = ticket.option.get("opendiscord:channel-category").value
- const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value
- if (channelCategory !== ""){
- //category enabled
- try {
- const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
- if (!normalCategory){
- //default category was not found
- opendiscord.log("Ticket Reopening Error: Unable to find category! #1","error",[
- {key:"categoryid",value:channelCategory},
- {key:"backup",value:"false"}
- ])
- }else{
- //default category was found
- if (normalCategory.children.cache.size >= 49 && channelBackupCategory != ""){
- //use backup category
- const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
- if (!backupCategory){
- //default category was not found
- opendiscord.log("Ticket Reopening Error: Unable to find category! #2","error",[
- {key:"categoryid",value:channelBackupCategory},
- {key:"backup",value:"true"}
- ])
- }else{
- //use backup category
- channel.setParent(backupCategory,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = "backup"
- ticket.get("opendiscord:category").value = backupCategory.id
- }
- }else{
- //use default category
- channel.setParent(normalCategory,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = "normal"
- ticket.get("opendiscord:category").value = normalCategory.id
- }
- }
- }catch(e){
- opendiscord.log("Unable to move ticket to 'reopened category'!","error",[
+ const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("reopen-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
+ if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
+ const originalCategoryName = channel.parent?.name ?? ""
+ const newCategoryName = categoryResult.newCategory?.name ?? ""
+ try{
+ await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
+ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
+ })
+ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
+ ticket.get("opendiscord:category").value = categoryResult.newCategoryId
+ }catch(err){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-reopen",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ opendiscord.log("Unable to move ticket to reopened category.","error",[
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
+ {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
- }else{
- channel.setParent(null,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = null
- ticket.get("opendiscord:category").value = null
+ }
+ }
+
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("reopen-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
+ try{
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket reopen","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while reopening ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
+ ])
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-reopen",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
}
@@ -141,43 +133,38 @@ export const registerActions = async () => {
})
channel.permissionOverwrites.set(permissions)
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket reopening!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason})).message)
+ if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
+ messageType:"reopen-message",
+ messageOrigin:"other",
+ messageAuthor:user.id,
+ messageReason:reason
+ },false)
+ }
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketReopened").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.reopening.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.reopening.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.reopening.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.reopening.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"reopen",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" reopened a ticket!","info",[
@@ -186,280 +173,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
-}
-
-export const registerVerifyBars = async () => {
- //REOPEN TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.reopen
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not closed
- if (!ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start reopening ticket
- if (params.data == "reason"){
- //reopen with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //reopen without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //REOPEN TICKET CLOSE MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-close-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-close-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.reopen
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not closed
- if (!ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start reopening ticket
- if (params.data == "reason"){
- //reopen with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("close-message",{guild,channel,user,ticket}))
- }else{
- //reopen without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run("close-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("close-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").failure.add([
- new api.ODWorker("opendiscord:back-to-close-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
-
- //REOPEN TICKET AUTOCLOSE MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket-autoclose-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-autoclose-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.reopen
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not closed
- if (!ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start reopening ticket
- if (params.data == "reason"){
- //reopen with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:reopen-ticket-reason").build("autoclose-message",{guild,channel,user,ticket}))
- }else{
- //reopen without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run("autoclose-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("autoclose-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").failure.add([
- new api.ODWorker("opendiscord:back-to-autoclose-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket}))
- })
- ])
- opendiscord.actions.get("opendiscord:reopen-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
- //set busy to false in case of crash or cancel
- params.ticket.get("opendiscord:busy").value = false
- })
}
\ No newline at end of file
diff --git a/src/actions/transferTicket.ts b/src/actions/transferTicket.ts
index 85887dc..59ae605 100644
--- a/src/actions/transferTicket.ts
+++ b/src/actions/transferTicket.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//TICKET TRANSFER SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:transfer-ticket"))
opendiscord.actions.get("opendiscord:transfer-ticket").workers.add([
- new api.ODWorker("opendiscord:transfer-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:transfer-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason,newCreator} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to transfer ticket! Open Ticket doesn't support threads!")
@@ -33,12 +33,8 @@ export const registerActions = async () => {
}
//update stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-transferred",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-transferred",user.id,1,"increase")
-
- //get new channel properties
- const channelPrefix = ticket.option.get("opendiscord:channel-prefix").value
- const channelSuffix = ticket.get("opendiscord:channel-suffix").value
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-transferred",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:tickets-transferred",user.id,1,"increase")
//handle permissions
const permissions: discord.OverwriteResolvable[] = [{
@@ -93,48 +89,40 @@ export const registerActions = async () => {
opendiscord.log("Failed to reset channel permissions on ticket transfer!","error")
}
- //rename channel (and give error when crashed)
- const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
- const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
-
- const originalName = channel.name
- const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channelPrefix+channelSuffix)
- try{
- await utilities.timedAwait(channel.setName(newName),2500,(err) => {
- opendiscord.log("Failed to rename channel on ticket transfer","error")
- })
- }catch(err){
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-transfer",{guild,channel,user,originalName,newName:newName})).message)
- }
-
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("transfer-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket transferring!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket transfer","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while transferring ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-transfer",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
}
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
+
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transfer-message").build(source,{guild,channel,user,ticket,oldCreator,newCreator,reason})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:transfer-message").build(origin,{guild,channel,user,ticket,oldCreator,newCreator,reason})).message)
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketTransferred").emit([ticket,user,channel,oldCreator,newCreator,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newCreator,reason} = params
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newCreator} = params
opendiscord.log(user.displayName+" transferred a ticket to '"+newCreator.displayName+"'!","info",[
@@ -143,7 +131,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/unclaimTicket.ts b/src/actions/unclaimTicket.ts
index 6a04c1e..e91b4ef 100644
--- a/src/actions/unclaimTicket.ts
+++ b/src/actions/unclaimTicket.ts
@@ -1,15 +1,16 @@
///////////////////////////////////////
//TICKET UNCLAIMING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:unclaim-ticket"))
opendiscord.actions.get("opendiscord:unclaim-ticket").workers.add([
- new api.ODWorker("opendiscord:unclaim-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:unclaim-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to unclaim ticket! Open Ticket doesn't support threads!")
@@ -21,97 +22,63 @@ export const registerActions = async () => {
ticket.get("opendiscord:claimed-on").value = null
ticket.get("opendiscord:busy").value = true
- //update category
+ //calculate & update category
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
- const channelCategory = ticket.option.get("opendiscord:channel-category").value
- const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value
- if (channelCategory !== ""){
- //category enabled
- try {
- const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
- if (!normalCategory){
- //default category was not found
- opendiscord.log("Ticket Unclaiming Error: Unable to find category! #1","error",[
- {key:"categoryid",value:channelCategory},
- {key:"backup",value:"false"}
- ])
- }else{
- //default category was found
- if (normalCategory.children.cache.size >= 49 && channelBackupCategory != ""){
- //use backup category
- const backupCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelBackupCategory)
- if (!backupCategory){
- //default category was not found
- opendiscord.log("Ticket Unclaiming Error: Unable to find category! #2","error",[
- {key:"categoryid",value:channelBackupCategory},
- {key:"backup",value:"true"}
- ])
- }else{
- //use backup category
- channel.setParent(backupCategory,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = "backup"
- ticket.get("opendiscord:category").value = backupCategory.id
- }
- }else{
- //use default category
- channel.setParent(normalCategory,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = "normal"
- ticket.get("opendiscord:category").value = normalCategory.id
- }
- }
-
- }catch(e){
- opendiscord.log("Unable to move ticket to 'unclaimed category'!","error",[
+ const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("unclaim-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
+ if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
+ const originalCategoryName = channel.parent?.name ?? ""
+ const newCategoryName = categoryResult.newCategory?.name ?? ""
+ try{
+ await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
+ process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
+ })
+ ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
+ ticket.get("opendiscord:category").value = categoryResult.newCategoryId
+ }catch(err){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-category").build("ticket-unclaim",{guild,channel,user,originalCategory:originalCategoryName,newCategory:newCategoryName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ opendiscord.log("Unable to move ticket to unclaimed category.","error",[
{key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true}
+ {key:"channelid",value:channel.id,hidden:true},
+ {key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
}
- }else{
- channel.setParent(null,{lockPermissions:false})
- ticket.get("opendiscord:category-mode").value = null
- ticket.get("opendiscord:category").value = null
}
}
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket unclaiming!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason})).message)
+ if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
+ messageType:"unclaim-message",
+ messageOrigin:"other",
+ messageAuthor:user.id,
+ messageReason:reason
+ },false)
+ }
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUnclaimed").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.claiming.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.claiming.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.claiming.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"unclaim",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" unclaimed a ticket!","info",[
@@ -120,192 +87,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
-}
-
-export const registerVerifyBars = async () => {
- //UNCLAIM TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.unclaim
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not claimed
- if (!ticket.get("opendiscord:claimed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start unclaiming ticket
- if (params.data == "reason"){
- //unclaim with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //unclaim without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unclaim-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //UNCLAIM TICKET CLAIM MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket-claim-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-claim-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.unclaim
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not claimed
- if (!ticket.get("opendiscord:claimed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start unclaiming ticket
- if (params.data == "reason"){
- //unclaim with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unclaim-ticket-reason").build("claim-message",{guild,channel,user,ticket}))
- }else{
- //unclaim without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unclaim-ticket").run("claim-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("claim-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").failure.add([
- new api.ODWorker("opendiscord:back-to-claim-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
- opendiscord.actions.get("opendiscord:unclaim-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
- //set busy to false in case of crash or cancel
- params.ticket.get("opendiscord:busy").value = false
- })
}
\ No newline at end of file
diff --git a/src/actions/unpinTicket.ts b/src/actions/unpinTicket.ts
index 931ef38..747754a 100644
--- a/src/actions/unpinTicket.ts
+++ b/src/actions/unpinTicket.ts
@@ -1,15 +1,16 @@
///////////////////////////////////////
//TICKET UNPINNING SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:unpin-ticket"))
opendiscord.actions.get("opendiscord:unpin-ticket").workers.add([
- new api.ODWorker("opendiscord:unpin-ticket",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:unpin-ticket",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
if (channel.isThread()) throw new api.ODSystemError("Unable to unpin ticket! Open Ticket doesn't support threads!")
@@ -21,58 +22,58 @@ export const registerActions = async () => {
ticket.get("opendiscord:pinned-on").value = null
ticket.get("opendiscord:busy").value = true
- //rename channel (and give error when crashed)
- const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
- const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
-
- const originalName = channel.name
- const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
- try{
- await utilities.timedAwait(channel.setName(newName),2500,(err) => {
- opendiscord.log("Failed to rename channel on ticket unpin","error")
- })
- }catch(err){
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-unpin",{guild,channel,user,originalName,newName})).message)
- }
-
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("unpin-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on ticket unpinning!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on ticket unpin","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while unpinning ticket! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-unpin",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
}
}
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
+
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(source,{guild,channel,user,ticket,reason})).message)
+ if (params.sendMessage){
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason})).message)
+ if (sentMsg) await interactiveMsgState.setMsgState({channel,message:sentMsg},{
+ messageType:"unpin-message",
+ messageOrigin:"other",
+ messageAuthor:user.id,
+ messageReason:reason
+ },false)
+ }
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketUnpinned").emit([ticket,user,channel,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,reason} = params
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.pinning.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.pinning.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null}))
}
//to dm
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
- if (creator && generalConfig.data.system.messages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null}))
+ if (creator && generalConfig.data.logs.logMessages.pinning.dm) await opendiscord.client.sendUserDm(creator,await opendiscord.builders.messages.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,ticket,mode:"unpin",reason,additionalData:null}))
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
opendiscord.log(user.displayName+" unpinned a ticket!","info",[
@@ -81,192 +82,8 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"reason",value:params.reason ?? "/"},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
-}
-
-export const registerVerifyBars = async () => {
- //UNPIN TICKET TICKET MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket-ticket-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-ticket-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.unpin
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not pinned
- if (!ticket.get("opendiscord:pinned").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start unpining ticket
- if (params.data == "reason"){
- //unpin with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("ticket-message",{guild,channel,user,ticket}))
- }else{
- //unpin without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unpin-ticket").run("ticket-message",{guild,channel,user,ticket,reason:null,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").failure.add([
- new api.ODWorker("opendiscord:back-to-ticket-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- })
- ])
-
- //UNPIN TICKET PIN MESSAGE
- opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket-pin-message",opendiscord.builders.messages.getSafe("opendiscord:verifybar-pin-message"),!generalConfig.data.system.disableVerifyBars))
- opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").success.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.unpin
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when not pinned
- if (!ticket.get("opendiscord:pinned").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //start unpinning ticket
- if (params.data == "reason"){
- //unpin with reason
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:unpin-ticket-reason").build("pin-message",{guild,channel,user,ticket}))
- }else{
- //unpin without reason
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unpin-ticket").run("pin-message",{guild,channel,user,ticket,reason:null,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("pin-message",{guild,channel,user,ticket,reason:null}))
- }
- })
- ])
- opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").failure.add([
- new api.ODWorker("opendiscord:back-to-pin-message",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- const {verifybarMessage} = params
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const rawReason = (verifybarMessage && verifybarMessage.embeds[0] && verifybarMessage.embeds[0].fields[0]) ? verifybarMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason}))
- })
- ])
- opendiscord.actions.get("opendiscord:unpin-ticket").workers.backupWorker = new api.ODWorker("opendiscord:cancel-busy",0,(instance,params) => {
- //set busy to false in case of crash or cancel
- params.ticket.get("opendiscord:busy").value = false
- })
}
\ No newline at end of file
diff --git a/src/actions/updateTicketPriority.ts b/src/actions/updateTicketPriority.ts
index de328a7..76be4ec 100644
--- a/src/actions/updateTicketPriority.ts
+++ b/src/actions/updateTicketPriority.ts
@@ -1,15 +1,15 @@
///////////////////////////////////////
//TICKET TOPIC SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-priority"))
opendiscord.actions.get("opendiscord:update-ticket-priority").workers.add([
- new api.ODWorker("opendiscord:update-ticket-priority",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:update-ticket-priority",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newPriority,reason} = params
if (channel.isThread() || !(channel instanceof discord.TextChannel)) throw new api.ODSystemError("Unable to set priority of ticket! Open Ticket doesn't support threads!")
@@ -20,32 +20,37 @@ export const registerActions = async () => {
ticket.get("opendiscord:busy").value = true
if (newPriority) ticket.get("opendiscord:priority").value = newPriority.priority
- //rename channel (and give error when crashed)
- const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
- const priorityEmoji = newPriority.channelEmoji ?? ""
-
- const originalName = channel.name
- const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
- try{
- await utilities.timedAwait(channel.setName(newName),2500,(err) => {
- opendiscord.log("Failed to rename channel on ticket priority update","error")
- })
- }catch(err){
- await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-priority",{guild,channel,user,originalName,newName})).message)
+ //calculate channel name
+ const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("priority-change",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
+ if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
+ const originalName = channel.name
+ const newName = channelNameResult.newChannelName
+ try{
+ await utilities.timedAwait(channel.setName(newName),2500,(err) => {
+ opendiscord.log("Failed to rename channel on priority change","error")
+ })
+ }catch(err){
+ opendiscord.log("Unable to rename channel while updating ticket priority! Waiting until ratelimit expires...","warning",[
+ {key:"oldName",value:originalName},
+ {key:"newName",value:newName}
+ ])
+ const sentMsg = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-priority",{guild,channel,user,originalName,newName})).message)
+ setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
+ }
}
//reply with new message
- if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:priority-set").build(source,{guild,channel,user,ticket,priority:newPriority,reason})).message)
+ if (params.sendMessage) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:priority-set").build(origin,{guild,channel,user,ticket,priority:newPriority,reason})).message)
ticket.get("opendiscord:busy").value = false
await opendiscord.events.get("afterTicketPriorityChanged").emit([ticket,user,channel,oldPriority,newPriority,reason])
//update channel topic
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newPriority} = params
opendiscord.log(user.displayName+" changed the priority of a ticket!","info",[
@@ -54,7 +59,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"priority",value:newPriority.id.value},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/updateTicketTopic.ts b/src/actions/updateTicketTopic.ts
index 1b544b0..207a5d7 100644
--- a/src/actions/updateTicketTopic.ts
+++ b/src/actions/updateTicketTopic.ts
@@ -1,16 +1,16 @@
///////////////////////////////////////
//TICKET TOPIC SYSTEM
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
-export const registerActions = async () => {
+export async function registerActions(){
opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-topic"))
opendiscord.actions.get("opendiscord:update-ticket-topic").workers.add([
- new api.ODWorker("opendiscord:update-ticket-topic",2,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:update-ticket-topic",2,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newTopic} = params
if (channel.isThread() || !(channel instanceof discord.TextChannel)) throw new api.ODSystemError("Unable to set topic of ticket! Open Ticket doesn't support threads!")
@@ -29,28 +29,28 @@ export const registerActions = async () => {
//handle channel topic
const channelTopics: string[] = []
- if (generalConfig.data.system.channelTopic.showOptionName) channelTopics.push(ticket.option.get("opendiscord:name").value)
- if (generalConfig.data.system.channelTopic.showOptionDescription) channelTopics.push(ticket.option.get("opendiscord:description").value)
- if (generalConfig.data.system.channelTopic.showOptionTopic) channelTopics.push(ticket.get("opendiscord:topic").value)
- if (generalConfig.data.system.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).renderDisplayName())
- if (generalConfig.data.system.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+(closed ? lang.getTranslation("params.uppercase.closed") : lang.getTranslation("params.uppercase.open")))
- if (generalConfig.data.system.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+(claimedBy ? discord.userMention(claimedBy) : lang.getTranslation("params.uppercase.noone")))
- if (generalConfig.data.system.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+(pinned ? lang.getTranslation("params.uppercase.yes") : lang.getTranslation("params.uppercase.no")))
- if (generalConfig.data.system.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(creator))
- if (generalConfig.data.system.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+ticket.get("opendiscord:participants").value.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", "))
+ if (generalConfig.data.ticketSystem.channelTopic.showOptionName) channelTopics.push(ticket.option.get("opendiscord:name").value)
+ if (generalConfig.data.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(ticket.option.get("opendiscord:description").value)
+ if (generalConfig.data.ticketSystem.channelTopic.showOptionTopic) channelTopics.push(ticket.get("opendiscord:topic").value)
+ if (generalConfig.data.ticketSystem.channelTopic.showPriority) channelTopics.push("**"+lang.getTranslation("params.uppercase.priority")+":** "+opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).renderDisplayName())
+ if (generalConfig.data.ticketSystem.channelTopic.showClosed) channelTopics.push("**"+lang.getTranslation("params.uppercase.status")+":** "+(closed ? lang.getTranslation("params.uppercase.closed") : lang.getTranslation("params.uppercase.open")))
+ if (generalConfig.data.ticketSystem.channelTopic.showClaimed) channelTopics.push("**"+lang.getTranslation("stats.properties.claimedBy")+":** "+(claimedBy ? discord.userMention(claimedBy) : lang.getTranslation("params.uppercase.noone")))
+ if (generalConfig.data.ticketSystem.channelTopic.showPinned) channelTopics.push("**"+lang.getTranslation("params.uppercase.pinned")+":** "+(pinned ? lang.getTranslation("params.uppercase.yes") : lang.getTranslation("params.uppercase.no")))
+ if (generalConfig.data.ticketSystem.channelTopic.showCreator) channelTopics.push("**"+lang.getTranslation("params.uppercase.creator")+":** "+discord.userMention(creator))
+ if (generalConfig.data.ticketSystem.channelTopic.showParticipants) channelTopics.push("**"+lang.getTranslation("params.uppercase.participants")+":** "+ticket.get("opendiscord:participants").value.map((p) => (p.type == "user") ? discord.userMention(p.id) : discord.roleMention(p.id)).join(", "))
//update channel
channel.setTopic(channelTopics.join(" • "),"Topic Changed")
//reply with new message
- if (params.sendMessage && newTopic) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:topic-set").build(source,{guild,channel,user,ticket,topic:newTopic})).message)
+ if (params.sendMessage && newTopic) await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:topic-set").build(origin,{guild,channel,user,ticket,topic:newTopic})).message)
ticket.get("opendiscord:busy").value = false
if (newTopic) await opendiscord.events.get("afterTicketTopicChanged").emit([ticket,user,channel,oldTopic,newTopic])
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user,ticket} = params
}),
- new api.ODWorker("opendiscord:logs",0,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",0,(instance,params,origin,cancel) => {
const {guild,channel,user,ticket,newTopic} = params
if (newTopic) opendiscord.log(user.displayName+" changed the topic of a ticket!","info",[
@@ -59,7 +59,7 @@ export const registerActions = async () => {
{key:"channel",value:"#"+channel.name},
{key:"channelid",value:channel.id,hidden:true},
{key:"topic",value:newTopic},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/actions/utilities.ts b/src/actions/utilities.ts
new file mode 100644
index 0000000..25f9b45
--- /dev/null
+++ b/src/actions/utilities.ts
@@ -0,0 +1,196 @@
+///////////////////////////////////////
+//OPEN TICKET UTILITY FUNCTIONS
+///////////////////////////////////////
+import {opendiscord, api, utilities} from "../index.js"
+import * as discord from "discord.js"
+
+/**Check the ticket creation permissions like: cooldown, limits, blacklist, ... */
+export async function checkTicketCreationPerms(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance|api.ODCommandResponderInstance,origin:api.ODActionManagerIdMappings["opendiscord:create-ticket-permissions"]["origin"],guild:discord.Guild,user:discord.User,option:api.ODTicketOption){
+ //check ticket permissions
+ const lang = opendiscord.languages
+ const permsRes = await opendiscord.actions.get("opendiscord:create-ticket-permissions").run(origin,{guild,user,option})
+ if (!permsRes.valid && instance.channel){
+ //error
+ const newOrigin = (origin === "slash" || origin === "text") ? origin : "other"
+ if (permsRes.reason == "blacklist") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-blacklisted").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ else if (permsRes.reason == "cooldown") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-cooldown").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,until:permsRes.cooldownUntil}))
+ else if (permsRes.reason == "global-limit") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global"}))
+ else if (permsRes.reason == "global-user-limit") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global-user"}))
+ else if (permsRes.reason == "option-limit") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option"}))
+ else if (permsRes.reason == "option-user-limit") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option-user"}))
+ else if (permsRes.reason == "custom") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,layout:"simple",error:permsRes.customReason ?? lang.getTranslation("errors.descriptions.unableToCreateTicket")+" `Unknown invalid_permission_reason => no reason specified by plugin`",customTitle:lang.getTranslation("errors.titles.permissionError")}))
+ else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(newOrigin,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Unknown invalid_permission reason => calculation failed #1",layout:"advanced"}))
+ return false
+ }else return true
+}
+
+/**Fetch the interactive message state. If not present, auto replies with error and returns `null`. When `null` is received, the worker should be returned and canceled. */
+export async function replyInteractiveMessageState(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",channel:discord.TextBasedChannel,message:discord.Message|null,replacementCommandName:string){
+ //check message state
+ const {user,member,guild} = instance
+ const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
+
+ if (!message){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"Unable to locate message of interaction. Use the command `{0}` instead.".replace("{0}",replacementCommandName),layout:"simple",customTitle:"Message State Error"}))
+ return null
+ }
+
+ const state = await interactiveMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This interaction is no longer valid or has expired. Use the command `{0}` instead. It is normal to receive this error after a major Open Ticket update.".replace("{0}",replacementCommandName),layout:"simple",customTitle:"Message State Expired"}))
+ return null
+ }else return state
+}
+
+/**Check the permissions for this command. If not allowed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyHasPermissions(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",commandName:keyof api.ODGeneralJsonConfig_SystemPermissions,settings?:api.ODPermissionSettings) {
+ //check permissions
+ const {user,member,channel,guild} = instance
+ const generalConfig = opendiscord.configs.get("opendiscord:general")
+ const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.permissions[commandName],"support",user,member,channel,guild,settings)
+
+ if (!permsResult.hasPerms){
+ if (permsResult.reason == "not-in-server" && channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
+ else if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]}))
+ return false
+ }else return true
+}
+
+/**Check if channel is in guild/server. If not, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyIsInGuild(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other"){
+ //check is in guild/server
+ const {user,member,channel,guild} = instance
+
+ if (!guild){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user}))
+ return false
+ }else return true
+}
+
+/**Check if channel is valid ticket. If not, auto replies with error and returns `null`. When `null` is received, the worker should be returned and canceled. */
+export async function replyIsTicket(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other") {
+ //check if ticket exists
+ const {user,member,channel,guild} = instance
+ if (!channel) return null
+ const ticket = opendiscord.tickets.get(channel.id)
+
+ if (!ticket || channel.isDMBased()){
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build(origin,{guild,channel,user}))
+ return null
+ }else return ticket
+}
+
+/**Check if ticket is not busy and available. If not, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketIsAvailable(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
+ //return when busy
+ const {user,member,channel,guild} = instance
+
+ if (ticket.get("opendiscord:busy").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build(origin,{guild,channel,user}))
+ return false
+ }else return true
+}
+
+/**Check if ticket is open. If closed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketMustBeOpen(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket){
+ //return when already closed
+ const {user,member,channel,guild} = instance
+ if (ticket.get("opendiscord:closed").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
+ return false
+ }else return true
+}
+
+/**Check if ticket is closed. If open, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketMustBeClosed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
+ //return when already open
+ const {user,member,channel,guild} = instance
+ if (!ticket.get("opendiscord:closed").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
+ return false
+ }else return true
+}
+
+/**Check if ticket is unclaimed. If claimed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketMustBeUnclaimed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
+ //return when already claimed
+ const {user,member,channel,guild} = instance
+ if (ticket.get("opendiscord:claimed").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
+ return false
+ }else return true
+}
+
+/**Check if ticket is claimed. If unclaimed, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketMustBeClaimed(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
+ //return when already unclaimed
+ const {user,member,channel,guild} = instance
+ if (!ticket.get("opendiscord:claimed").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
+ return false
+ }else return true
+}
+
+/**Check if ticket is unpinned. If pinned, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketMustBeUnpinned(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
+ //return when already pinned
+ const {user,member,channel,guild} = instance
+ if (ticket.get("opendiscord:pinned").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
+ return false
+ }else return true
+}
+
+/**Check if ticket is pinned. If unpinned, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyTicketMustBePinned(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket) {
+ //return when already unpinned
+ const {user,member,channel,guild} = instance
+ if (!ticket.get("opendiscord:pinned").value){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
+ return false
+ }else return true
+}
+
+/**Check if the ticket can be closed/deleted before a message has been sent by an admin or user. If not passing the test, auto replies with error and returns `false`. When `false` is received, the worker should be returned and canceled. */
+export async function replyMessageMustBeSentBeforeClose(instance:api.ODButtonResponderInstance|api.ODCommandResponderInstance|api.ODDropdownResponderInstance,origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other",ticket:api.ODTicket,commandName:keyof api.ODGeneralJsonConfig_SystemPermissions) {
+ //return when not allowed because of missing messages
+ const {user,member,channel,guild} = instance
+ const generalConfig = opendiscord.configs.get("opendiscord:general")
+ const lang = opendiscord.languages
+ const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.permissions[commandName],"support",user,member,channel,guild)
+
+ if (!permsResult.hasPerms) throw new api.ODSystemError("Please check permissions before using replyMessageMustBeSentBeforeClose()")
+ if (!guild || channel.isDMBased()) throw new api.ODSystemError("replyMessageMustBeSentBeforeClose() must be used in a guild and not a DM channel.")
+
+ if (!permsResult.isAdmin && (!generalConfig.data.ticketSystem.allowCloseBeforeMessage || !generalConfig.data.ticketSystem.allowCloseBeforeAdminMessage)){
+ const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
+ if (analysis && !generalConfig.data.ticketSystem.allowCloseBeforeMessage && analysis.totalMessages < 1){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
+ return false
+ }
+ if (analysis && !generalConfig.data.ticketSystem.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
+ if (channel) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
+ return false
+ }
+ return true
+ }else return true
+}
+
+/**Update the ticket message from a given ticket channel. This should be used after every change to the `ODTicket` after an action. */
+export async function updateTicketMessage(guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:api.ODTicket){
+ const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
+ if (!ticketMessage || !user || !channel || !guild || channel.isDMBased()) return
+ try{
+ await ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
+ }catch(e){
+ opendiscord.log("Unable to edit ticket message!","error",[
+ {key:"channel",value:"#"+channel.name},
+ {key:"channelid",value:channel.id,hidden:true},
+ {key:"messageid",value:ticketMessage.id},
+ {key:"option",value:ticket.option.id.value}
+ ])
+ opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ }
+}
\ No newline at end of file
diff --git a/src/builders/buttons.ts b/src/builders/buttons.ts
index cc9cba9..81b2fd0 100644
--- a/src/builders/buttons.ts
+++ b/src/builders/buttons.ts
@@ -1,15 +1,37 @@
///////////////////////////////////////
//BUTTON BUILDERS
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
const buttons = opendiscord.builders.buttons
const lang = opendiscord.languages
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerAllButtons = async () => {
- verifybarButtons()
+export async function registerAllButtons(){
+ //VERIFYBAR BUTTON
+ buttons.add(new api.ODButton("opendiscord:verifybar-button"))
+ buttons.get("opendiscord:verifybar-button").workers.add(
+ new api.ODWorker("opendiscord:verifybar-button",0,async (instance,params) => {
+ const {verifybar,verifyButtonId} = params
+ if (params.verifyButtonId.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-button => verifyButtonId '"+verifyButtonId+"' exceeds 40 characters limit!")
+
+ const color = ("customColor" in params && params.customColor) ? params.customColor : "gray"
+ //TODO TRANSLATION!!!
+ const defaultLabel = (params.defaultButtonType == "✅") ? "Accept" : "Cancel"
+ const defaultEmoji = (params.defaultButtonType == "✅") ? "✅" : "❌"
+
+ const label = ("customLabel" in params && params.customLabel) ? params.customLabel : (params.useDefaultLabels ? defaultLabel : null)
+ const emoji = ("customEmoji" in params && params.customEmoji) ? params.customEmoji : defaultEmoji
+
+ instance.setCustomId("od:verifybar|"+verifybar.id.value+"|"+verifyButtonId)
+ instance.setMode("button")
+ instance.setColor(color)
+ if (label) instance.setLabel(label)
+ if (emoji) instance.setEmoji(emoji)
+ })
+ )
+
errorButtons()
helpMenuButtons()
panelButtons()
@@ -18,50 +40,6 @@ export const registerAllButtons = async () => {
clearButtons()
}
-const verifybarButtons = () => {
- //VERIFYBAR SUCCESS
- buttons.add(new api.ODButton("opendiscord:verifybar-success"))
- buttons.get("opendiscord:verifybar-success").workers.add(
- new api.ODWorker("opendiscord:verifybar-success",0,async (instance,params) => {
- const {verifybar,customData,customColor,customLabel,customEmoji} = params
-
- if (customData && customData.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-success => customData exceeds 40 characters limit!")
-
- const newData = (customData) ? "_"+customData : ""
- const newColor = customColor ?? "gray"
- const newLabel = customLabel ?? ""
- const newEmoji = customEmoji ?? "✅"
-
- instance.setCustomId("od:verifybar-success_"+verifybar.id.value+newData)
- instance.setMode("button")
- instance.setColor(newColor)
- if (newLabel) instance.setLabel(newLabel)
- if (newEmoji) instance.setEmoji(newEmoji)
- })
- )
-
- //VERIFYBAR FAILURE
- buttons.add(new api.ODButton("opendiscord:verifybar-failure"))
- buttons.get("opendiscord:verifybar-failure").workers.add(
- new api.ODWorker("opendiscord:verifybar-failure",0,async (instance,params) => {
- const {verifybar,customData,customColor,customLabel,customEmoji} = params
-
- if (customData && customData.length > 40) throw new api.ODSystemError("ODButton:opendiscord:verifybar-success => customData exceeds 40 characters limit!")
-
- const newData = (customData) ? "_"+customData : ""
- const newColor = customColor ?? "gray"
- const newLabel = customLabel ?? ""
- const newEmoji = customEmoji ?? "❌"
-
- instance.setCustomId("od:verifybar-failure_"+verifybar.id.value+newData)
- instance.setMode("button")
- instance.setColor(newColor)
- if (newLabel) instance.setLabel(newLabel)
- if (newEmoji) instance.setEmoji(newEmoji)
- })
- )
-}
-
const errorButtons = () => {
//ERROR TICKET DEPRECATED TRANSCRIPT
buttons.add(new api.ODButton("opendiscord:error-ticket-deprecated-transcript"))
@@ -145,7 +123,7 @@ const panelButtons = () => {
new api.ODWorker("opendiscord:ticket-option",0,async (instance,params) => {
const {panel,option} = params
- instance.setCustomId("od:ticket-option_"+panel.id.value+"_"+option.id.value)
+ instance.setCustomId("od:ticket-option|"+option.id.value)
instance.setMode("button")
instance.setColor(option.get("opendiscord:button-color").value)
if (option.get("opendiscord:button-emoji").value) instance.setEmoji(option.get("opendiscord:button-emoji").value)
@@ -174,7 +152,22 @@ const panelButtons = () => {
new api.ODWorker("opendiscord:role-option",0,async (instance,params) => {
const {panel,option} = params
- instance.setCustomId("od:role-option_"+panel.id.value+"_"+option.id.value)
+ instance.setCustomId("od:role-option|"+option.id.value)
+ instance.setMode("button")
+ instance.setColor(option.get("opendiscord:button-color").value)
+ if (option.get("opendiscord:button-emoji").value) instance.setEmoji(option.get("opendiscord:button-emoji").value)
+ if (option.get("opendiscord:button-label").value) instance.setLabel(option.get("opendiscord:button-label").value)
+ if (!option.get("opendiscord:button-emoji").value && !option.get("opendiscord:button-label").value) instance.setLabel("<"+option.id.value+">")
+ })
+ )
+
+ //SUB-PANEL OPTION
+ buttons.add(new api.ODButton("opendiscord:subpanel-option"))
+ buttons.get("opendiscord:subpanel-option").workers.add(
+ new api.ODWorker("opendiscord:subpanel-option",0,async (instance,params) => {
+ const {panel,option} = params
+
+ instance.setCustomId("od:subpanel-option|"+option.id.value)
instance.setMode("button")
instance.setColor(option.get("opendiscord:button-color").value)
if (option.get("opendiscord:button-emoji").value) instance.setEmoji(option.get("opendiscord:button-emoji").value)
@@ -201,11 +194,11 @@ const ticketButtons = () => {
//CLOSE TICKET
buttons.add(new api.ODButton("opendiscord:close-ticket"))
buttons.get("opendiscord:close-ticket").workers.add(
- new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:close-ticket_"+source)
+ instance.setCustomId("od:close-ticket")
instance.setColor("gray")
instance.setEmoji("🔒")
instance.setLabel(lang.getTranslation("actions.buttons.close"))
@@ -215,11 +208,11 @@ const ticketButtons = () => {
//DELETE TICKET
buttons.add(new api.ODButton("opendiscord:delete-ticket"))
buttons.get("opendiscord:delete-ticket").workers.add(
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:delete-ticket_"+source)
+ instance.setCustomId("od:delete-ticket")
instance.setColor("red")
instance.setEmoji("✖")
instance.setLabel(lang.getTranslation("actions.buttons.delete"))
@@ -229,11 +222,11 @@ const ticketButtons = () => {
//REOPEN TICKET
buttons.add(new api.ODButton("opendiscord:reopen-ticket"))
buttons.get("opendiscord:reopen-ticket").workers.add(
- new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:reopen-ticket_"+source)
+ instance.setCustomId("od:reopen-ticket")
instance.setColor("green")
instance.setEmoji("🔓")
instance.setLabel(lang.getTranslation("actions.buttons.reopen"))
@@ -243,11 +236,11 @@ const ticketButtons = () => {
//CLAIM TICKET
buttons.add(new api.ODButton("opendiscord:claim-ticket"))
buttons.get("opendiscord:claim-ticket").workers.add(
- new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:claim-ticket_"+source)
+ instance.setCustomId("od:claim-ticket")
instance.setColor("green")
instance.setEmoji("👋")
instance.setLabel(lang.getTranslation("actions.buttons.claim"))
@@ -257,11 +250,11 @@ const ticketButtons = () => {
//UNCLAIM TICKET
buttons.add(new api.ODButton("opendiscord:unclaim-ticket"))
buttons.get("opendiscord:unclaim-ticket").workers.add(
- new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:unclaim-ticket_"+source)
+ instance.setCustomId("od:unclaim-ticket")
instance.setColor("green")
instance.setEmoji("↩️")
instance.setLabel(lang.getTranslation("actions.buttons.unclaim"))
@@ -271,13 +264,13 @@ const ticketButtons = () => {
//PIN TICKET
buttons.add(new api.ODButton("opendiscord:pin-ticket"))
buttons.get("opendiscord:pin-ticket").workers.add(
- new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:pin-ticket_"+source)
+ instance.setCustomId("od:pin-ticket")
instance.setColor("gray")
- instance.setEmoji(generalConfig.data.system.pinEmoji)
+ instance.setEmoji(generalConfig.data.ticketSystem.pinEmoji)
instance.setLabel(lang.getTranslation("actions.buttons.pin"))
})
)
@@ -285,13 +278,13 @@ const ticketButtons = () => {
//UNPIN TICKET
buttons.add(new api.ODButton("opendiscord:unpin-ticket"))
buttons.get("opendiscord:unpin-ticket").workers.add(
- new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin) => {
const {guild,channel,ticket} = params
instance.setMode("button")
- instance.setCustomId("od:unpin-ticket_"+source)
+ instance.setCustomId("od:unpin-ticket")
instance.setColor("gray")
- instance.setEmoji(generalConfig.data.system.pinEmoji)
+ instance.setEmoji(generalConfig.data.ticketSystem.pinEmoji)
instance.setLabel(lang.getTranslation("actions.buttons.unpin"))
})
)
@@ -301,7 +294,7 @@ const transcriptButtons = () => {
//TRANSCRIPT HTML VISIT
buttons.add(new api.ODButton("opendiscord:transcript-html-visit"))
buttons.get("opendiscord:transcript-html-visit").workers.add(
- new api.ODWorker("opendiscord:transcript-html-visit",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-html-visit",0,async (instance,params,origin) => {
const {result} = params
instance.setMode("url")
if (result.data) instance.setUrl(result.data.url)
@@ -314,9 +307,9 @@ const transcriptButtons = () => {
//TRANSCRIPT ERROR RETRY
buttons.add(new api.ODButton("opendiscord:transcript-error-retry"))
buttons.get("opendiscord:transcript-error-retry").workers.add(
- new api.ODWorker("opendiscord:transcript-error-retry",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-error-retry",0,async (instance,params,origin) => {
instance.setMode("button")
- instance.setCustomId("od:transcript-error-retry_"+source)
+ instance.setCustomId("od:transcript-error-retry_"+origin)
instance.setColor("gray")
instance.setEmoji("🔄")
instance.setLabel(lang.getTranslation("transcripts.errors.retry"))
@@ -326,9 +319,9 @@ const transcriptButtons = () => {
//TRANSCRIPT ERROR CONTINUE
buttons.add(new api.ODButton("opendiscord:transcript-error-continue"))
buttons.get("opendiscord:transcript-error-continue").workers.add(
- new api.ODWorker("opendiscord:transcript-error-continue",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-error-continue",0,async (instance,params,origin) => {
instance.setMode("button")
- instance.setCustomId("od:transcript-error-continue_"+source)
+ instance.setCustomId("od:transcript-error-continue_"+origin)
instance.setColor("red")
instance.setEmoji("✖")
instance.setLabel(lang.getTranslation("transcripts.errors.continue"))
@@ -340,12 +333,13 @@ const clearButtons = () => {
//CLEAR CONTINUE
buttons.add(new api.ODButton("opendiscord:clear-continue"))
buttons.get("opendiscord:clear-continue").workers.add(
- new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,origin) => {
instance.setMode("button")
- instance.setCustomId("od:clear-continue_"+source+"_"+params.filter)
+ instance.setCustomId("od:clear-continue")
instance.setColor("red")
instance.setEmoji("✖")
instance.setLabel(lang.getTranslation("actions.buttons.clear"))
+ instance.setDisabled(params.inProgress)
})
)
}
\ No newline at end of file
diff --git a/src/builders/dropdowns.ts b/src/builders/dropdowns.ts
index 2f675c5..2bb2c04 100644
--- a/src/builders/dropdowns.ts
+++ b/src/builders/dropdowns.ts
@@ -1,37 +1,63 @@
///////////////////////////////////////
//DROPDOWN BUILDERS
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
const dropdowns = opendiscord.builders.dropdowns
-export const registerAllDropdowns = async () => {
+export async function registerAllDropdowns(){
panelDropdowns()
}
const panelDropdowns = () => {
//TICKET OPTION
- dropdowns.add(new api.ODDropdown("opendiscord:panel-dropdown-tickets"))
- dropdowns.get("opendiscord:panel-dropdown-tickets").workers.add(
- new api.ODWorker("opendiscord:panel-dropdown-tickets",0,async (instance,params) => {
+ dropdowns.add(new api.ODDropdown("opendiscord:panel-dropdown"))
+ dropdowns.get("opendiscord:panel-dropdown").workers.add(
+ new api.ODWorker("opendiscord:panel-dropdown",0,async (instance,params) => {
const {panel,options} = params
const parsedOptions: api.ODDropdownData["options"] = options.map((option) => {
- const label = option.get("opendiscord:button-label").value.substring(0,100)
- const desc = option.get("opendiscord:description").value.substring(0,100)
- const emoji = option.get("opendiscord:button-emoji").value
-
- return {
- label:(label.length > 0) ? label : "",
- value:"od:ticket-option_"+panel.id.value+"_"+option.id.value,
- emoji:(emoji.length > 0) ? emoji : undefined,
- description:(desc.length > 0) ? desc : undefined,
- default:false
- }
+ if (option instanceof api.ODTicketOption){
+ const label = option.get("opendiscord:button-label").value.substring(0,100)
+ const desc = option.get("opendiscord:description").value.substring(0,100)
+ const emoji = option.get("opendiscord:button-emoji").value
+
+ return {
+ label:(label.length > 0) ? label : "",
+ value:"od:ticket-option|"+option.id.value,
+ emoji:(emoji.length > 0) ? emoji : undefined,
+ description:(desc.length > 0) ? desc : undefined,
+ default:false
+ }
+ }else if (option instanceof api.ODRoleOption){
+ const label = option.get("opendiscord:button-label").value.substring(0,100)
+ const desc = option.get("opendiscord:description").value.substring(0,100)
+ const emoji = option.get("opendiscord:button-emoji").value
+
+ return {
+ label:(label.length > 0) ? label : "",
+ value:"od:role-option|"+option.id.value,
+ emoji:(emoji.length > 0) ? emoji : undefined,
+ description:(desc.length > 0) ? desc : undefined,
+ default:false
+ }
+ }else if (option instanceof api.ODSubPanelOption){
+ const label = option.get("opendiscord:button-label").value.substring(0,100)
+ const desc = option.get("opendiscord:description").value.substring(0,100)
+ const emoji = option.get("opendiscord:button-emoji").value
+
+ return {
+ label:(label.length > 0) ? label : "",
+ value:"od:subpanel-option|"+option.id.value,
+ emoji:(emoji.length > 0) ? emoji : undefined,
+ description:(desc.length > 0) ? desc : undefined,
+ default:false
+ }
+ }else throw new api.ODSystemError("Unable to create panel dropdown with options that don't match: ticket, role, sub-panel!")
})
- instance.setCustomId("od:panel-dropdown_"+panel.id.value)
+ instance.setCustomId("od:panel-dropdown")
instance.setType("string")
instance.setMaxValues(1)
instance.setMinValues(0)
diff --git a/src/builders/embeds.ts b/src/builders/embeds.ts
index 5d7cc2c..d3ce6a4 100644
--- a/src/builders/embeds.ts
+++ b/src/builders/embeds.ts
@@ -1,7 +1,7 @@
///////////////////////////////////////
//EMBED BUILDERS
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
import nodepath from "path"
@@ -9,7 +9,7 @@ const embeds = opendiscord.builders.embeds
const lang = opendiscord.languages
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerAllEmbeds = async () => {
+export async function registerAllEmbeds(){
errorEmbeds()
helpMenuEmbeds()
statsEmbeds()
@@ -23,12 +23,12 @@ export const registerAllEmbeds = async () => {
extraEmbeds()
}
-/**Utility function to get the translated "method" from the source. Mostly used in error embeds. */
-const getMethodFromSource = (source:"slash"|"text"|"button"|"dropdown"|"modal"|"other"): string => {
- if (source == "slash" || source == "text") return lang.getTranslation("params.lowercase.command")
- else if (source == "button") return lang.getTranslation("params.lowercase.button")
- else if (source == "dropdown") return lang.getTranslation("params.lowercase.dropdown")
- else if (source == "modal") return lang.getTranslation("params.lowercase.modal")
+/**Utility function to get the translated "method" from the origin. Mostly used in error embeds. */
+const getMethodFromOrigin = (origin:"slash"|"text"|"button"|"dropdown"|"modal"|"other"): string => {
+ if (origin == "slash" || origin == "text") return lang.getTranslation("params.lowercase.command")
+ else if (origin == "button") return lang.getTranslation("params.lowercase.button")
+ else if (origin == "dropdown") return lang.getTranslation("params.lowercase.dropdown")
+ else if (origin == "modal") return lang.getTranslation("params.lowercase.modal")
else return lang.getTranslation("params.lowercase.method")
}
//lang.getTranslation()
@@ -37,12 +37,12 @@ const errorEmbeds = () => {
//ERROR
embeds.add(new api.ODEmbed("opendiscord:error"))
embeds.get("opendiscord:error").workers.add(
- new api.ODWorker("opendiscord:error",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error",0,async (instance,params,origin) => {
const {user,error,layout,customTitle} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",customTitle ?? lang.getTranslation("errors.titles.internalError")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method]) + (layout == "simple") ? "\n"+error : "")
@@ -75,7 +75,7 @@ const errorEmbeds = () => {
})
const commandSyntax = "**"+error.prefix+error.name+" "+optionSyntax.join(" ")+"**"
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.optionMissing")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.optionMissing"))
@@ -130,7 +130,7 @@ const errorEmbeds = () => {
else if (error.reason == "channel_type" && error.option.type == "channel") reasonValue = lang.getTranslation("errors.optionInvalidReasons.channelType")
else if (error.reason == "not_in_guild") reasonValue = lang.getTranslation("errors.optionInvalidReasons.notInGuild")
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.optionInvalid")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.optionInvalid")+"\n"+reasonTitle+": `"+reasonValue+"`")
@@ -144,7 +144,7 @@ const errorEmbeds = () => {
new api.ODWorker("opendiscord:error-unknown-command",0,async (instance,params) => {
const {user} = params
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownCommand")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.unknownCommand"))
@@ -154,10 +154,10 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions"))
embeds.get("opendiscord:error-no-permissions").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions",0,async (instance,params,origin) => {
const {user,permissions} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
const renderedPerms = permissions.map((perm) => {
if (perm == "developer") return "- "+lang.getTranslation("errors.permissions.developer")
@@ -169,7 +169,7 @@ const errorEmbeds = () => {
else if (perm == "discord-administrator") return "- "+lang.getTranslation("errors.permissions.discord-administrator")
}).join("\n")
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissions",[method]))
@@ -180,12 +180,12 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS COOLDOWN
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-cooldown"))
embeds.get("opendiscord:error-no-permissions-cooldown").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions-cooldown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions-cooldown",0,async (instance,params,origin) => {
const {user} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsCooldown",[method]))
@@ -196,12 +196,12 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS BLACKLISTED
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-blacklisted"))
embeds.get("opendiscord:error-no-permissions-blacklisted").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions-blacklisted",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions-blacklisted",0,async (instance,params,origin) => {
const {user} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.noPermissionsBlacklist",[method]))
@@ -211,10 +211,10 @@ const errorEmbeds = () => {
//ERROR NO PERMISSIONS LIMITS
embeds.add(new api.ODEmbed("opendiscord:error-no-permissions-limits"))
embeds.get("opendiscord:error-no-permissions-limits").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,origin) => {
const {user,limit} = params
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.noPermissions")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
if (limit == "global") instance.setDescription(lang.getTranslation("errors.descriptions.noPermissionsLimitGlobal"))
@@ -227,12 +227,12 @@ const errorEmbeds = () => {
//ERROR RESPONDER TIMEOUT
embeds.add(new api.ODEmbed("opendiscord:error-responder-timeout"))
embeds.get("opendiscord:error-responder-timeout").workers.add(
- new api.ODWorker("opendiscord:error-responder-timeout",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-responder-timeout",0,async (instance,params,origin) => {
const {user} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.internalError")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.internalError",[method]))
@@ -244,10 +244,10 @@ const errorEmbeds = () => {
//ERROR TICKET UNKNOWN
embeds.add(new api.ODEmbed("opendiscord:error-ticket-unknown"))
embeds.get("opendiscord:error-ticket-unknown").workers.add(
- new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,origin) => {
const {user} = params
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownTicket")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.unknownTicket"))
@@ -258,10 +258,10 @@ const errorEmbeds = () => {
//ERROR TICKET DEPRECATED
embeds.add(new api.ODEmbed("opendiscord:error-ticket-deprecated"))
embeds.get("opendiscord:error-ticket-deprecated").workers.add(
- new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,origin) => {
const {user} = params
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.deprecatedTicket")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.deprecatedTicket"))
@@ -272,7 +272,7 @@ const errorEmbeds = () => {
//ERROR OPTION UNKNOWN
embeds.add(new api.ODEmbed("opendiscord:error-option-unknown"))
embeds.get("opendiscord:error-option-unknown").workers.add(
- new api.ODWorker("opendiscord:error-option-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-option-unknown",0,async (instance,params,origin) => {
const {user} = params
const renderedTicketOptions = opendiscord.options.getAll().map((option) => {
@@ -281,7 +281,7 @@ const errorEmbeds = () => {
}else return "- `"+option.id.value+"`"
}).join("\n")
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownOption")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo"))
@@ -292,7 +292,7 @@ const errorEmbeds = () => {
//ERROR PANEL UNKNOWN
embeds.add(new api.ODEmbed("opendiscord:error-panel-unknown"))
embeds.get("opendiscord:error-panel-unknown").workers.add(
- new api.ODWorker("opendiscord:error-panel-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-panel-unknown",0,async (instance,params,origin) => {
const {user} = params
const renderedPanels = opendiscord.panels.getAll().map((panel) => {
@@ -301,7 +301,7 @@ const errorEmbeds = () => {
}else return "- `"+panel.id.value+"`"
}).join("\n")
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownPanel")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.addFields({name:lang.getTranslation("params.uppercase.validPanels")+":",value:renderedPanels})
@@ -312,12 +312,12 @@ const errorEmbeds = () => {
//ERROR NOT IN GUILD
embeds.add(new api.ODEmbed("opendiscord:error-not-in-guild"))
embeds.get("opendiscord:error-not-in-guild").workers.add(
- new api.ODWorker("opendiscord:error-not-in-guild",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-not-in-guild",0,async (instance,params,origin) => {
const {user} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.notInGuild")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.notInGuild",[method]))
@@ -327,19 +327,43 @@ const errorEmbeds = () => {
//ERROR CHANNEL RENAME
embeds.add(new api.ODEmbed("opendiscord:error-channel-rename"))
embeds.get("opendiscord:error-channel-rename").workers.add(
- new api.ODWorker("opendiscord:error-channel-rename",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-channel-rename",0,async (instance,params,origin) => {
const {channel,user,originalName,newName} = params
- const method = (source == "ticket-move" || source == "ticket-pin" || source == "ticket-rename" || source == "ticket-unpin" || source == "ticket-priority" || source == "ticket-transfer") ? source : getMethodFromSource(source)
+ const method = (origin == "ticket-move" || origin == "ticket-pin" || origin == "ticket-close" || origin == "ticket-reopen" || origin == "ticket-rename" || origin == "ticket-unpin" || origin == "ticket-priority" || origin == "ticket-transfer") ? origin : getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.channelRename")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslation("errors.descriptions.channelRename"))
instance.setFooter(lang.getTranslationWithParams("errors.descriptions.channelRenameSource",[method]))
instance.addFields(
- {name:lang.getTranslation("params.uppercase.originalName")+":",value:"```#"+originalName+"```",inline:false},
- {name:lang.getTranslation("params.uppercase.newName")+":",value:"```#"+newName+"```",inline:false}
+ {name:lang.getTranslation("params.uppercase.originalName")+":",value:"```#"+originalName+"```",inline:true},
+ {name:lang.getTranslation("params.uppercase.newName")+":",value:"```#"+newName+"```",inline:true}
+ )
+ })
+ )
+
+ //ERROR CHANNEL CATEGORY
+ embeds.add(new api.ODEmbed("opendiscord:error-channel-category"))
+ embeds.get("opendiscord:error-channel-category").workers.add(
+ new api.ODWorker("opendiscord:error-channel-category",0,async (instance,params,origin) => {
+ const {channel,user,originalCategory,newCategory} = params
+
+ const method = (origin == "ticket-create" || origin == "ticket-close" || origin == "ticket-reopen" || origin == "ticket-claim" || origin == "ticket-unclaim" || origin == "ticket-move") ? origin : getMethodFromOrigin(origin)
+
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ //TODO TRANSLATION!!!
+ instance.setTitle(utilities.emojiTitle("❌","Unable To Change Category"))
+ instance.setAuthor(user.displayName,user.displayAvatarURL())
+ //TODO TRANSLATION!!!
+ instance.setDescription("Due to Discord rate limits, the channel category could not be changed immediately. It will be changed automatically within 10 minutes if the bot remains online.")
+ instance.setFooter(lang.getTranslationWithParams("errors.descriptions.channelRenameSource",[method]))
+ instance.addFields(
+ //TODO TRANSLATION!!!
+ {name:"Original Category"+":",value:"```"+originalCategory+"```",inline:true},
+ //TODO TRANSLATION!!!
+ {name:"New Category"+":",value:"```"+newCategory+"```",inline:true}
)
})
)
@@ -347,12 +371,12 @@ const errorEmbeds = () => {
//ERROR TICKET BUSY
embeds.add(new api.ODEmbed("opendiscord:error-ticket-busy"))
embeds.get("opendiscord:error-ticket-busy").workers.add(
- new api.ODWorker("opendiscord:error-ticket-busy",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-ticket-busy",0,async (instance,params,origin) => {
const {user} = params
- const method = getMethodFromSource(source)
+ const method = getMethodFromOrigin(origin)
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.busy")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("errors.descriptions.busy",[method]))
@@ -387,7 +411,7 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-global",0,async (instance,params) => {
const {guild,channel,user} = params
- const scope = opendiscord.stats.get("opendiscord:global")
+ const scope = opendiscord.statistics.get("opendiscord:global")
if (!scope) return
const data = await scope.render("GLOBAL",guild,channel,user)
@@ -397,7 +421,7 @@ const statsEmbeds = () => {
if (opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(user,channel,guild))){
//show system data when owner or developer
- const systemScope = opendiscord.stats.get("opendiscord:system")
+ const systemScope = opendiscord.statistics.get("opendiscord:system")
if (!systemScope) return
const systemData = await systemScope.render("GLOBAL",guild,channel,user)
instance.addFields({name:systemScope.name,value:systemData,inline:false})
@@ -411,9 +435,9 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-ticket",0,async (instance,params) => {
const {guild,channel,user,scopeData} = params
- const scope = opendiscord.stats.get("opendiscord:ticket")
- const participantsScope = opendiscord.stats.get("opendiscord:participants")
- const messagesScope = opendiscord.stats.get("opendiscord:messages")
+ const scope = opendiscord.statistics.get("opendiscord:ticket")
+ const participantsScope = opendiscord.statistics.get("opendiscord:participants")
+ const messagesScope = opendiscord.statistics.get("opendiscord:messages")
if (!scope || !participantsScope || !messagesScope) return
const data = await scope.render(scopeData.id.value,guild,channel,user)
const participantsData = await participantsScope.render(scopeData.id.value,guild,channel,user)
@@ -433,7 +457,7 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-user",0,async (instance,params) => {
const {guild,channel,user,scopeData} = params
- const scope = opendiscord.stats.get("opendiscord:user")
+ const scope = opendiscord.statistics.get("opendiscord:user")
if (!scope) return
const data = await scope.render(scopeData.id,guild,channel,user)
@@ -477,7 +501,7 @@ const statsEmbeds = () => {
new api.ODWorker("opendiscord:stats-ticket-unknown",0,async (instance,params) => {
const {user,id} = params
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("errors.titles.unknownTicket")))
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.statsError",[discord.channelMention(id)]))
@@ -510,8 +534,8 @@ const panelEmbeds = () => {
instance.setDescription(embedOptions.description)
}
- if (panel.get("opendiscord:enable-max-tickets-warning-embed").value && generalConfig.data.system.limits.enabled){
- instance.setDescription(instance.data.description+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.system.limits.userMaximum.toString()])+"*")
+ if (panel.get("opendiscord:enable-max-tickets-warning-embed").value && generalConfig.data.ticketSystem.limits.enabled){
+ instance.setDescription(instance.data.description+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.ticketSystem.limits.userMaximum.toString()])+"*")
}
if (panel.get("opendiscord:describe-options-in-embed-fields").value){
@@ -529,7 +553,7 @@ const ticketEmbeds = () => {
//TICKET CREATED
embeds.add(new api.ODEmbed("opendiscord:ticket-created"))
embeds.get("opendiscord:ticket-created").workers.add(
- new api.ODWorker("opendiscord:ticket-created",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-created",0,async (instance,params,origin) => {
const {user} = params
instance.setColor(generalConfig.data.mainColor)
@@ -543,7 +567,7 @@ const ticketEmbeds = () => {
//TICKET CREATED DM
embeds.add(new api.ODEmbed("opendiscord:ticket-created-dm"))
embeds.get("opendiscord:ticket-created-dm").workers.add(
- new api.ODWorker("opendiscord:ticket-created-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-created-dm",0,async (instance,params,origin) => {
const {user,ticket} = params
const embedOptions = ticket.option.get("opendiscord:dm-message-embed").value
@@ -563,10 +587,10 @@ const ticketEmbeds = () => {
//TICKET CREATED LOGS
embeds.add(new api.ODEmbed("opendiscord:ticket-created-logs"))
embeds.get("opendiscord:ticket-created-logs").workers.add(
- new api.ODWorker("opendiscord:ticket-created-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-created-logs",0,async (instance,params,origin) => {
const {user,ticket} = params
- const method = (source == "panel-button" || source == "panel-dropdown") ? lang.getTranslation("params.uppercase.panel") : (source == "slash" || source == "text") ? lang.getTranslation("params.uppercase.command") : lang.getTranslation("params.uppercase.system")
+ const method = (origin == "panel-button" || origin == "panel-dropdown") ? lang.getTranslation("params.uppercase.panel") : (origin == "slash" || origin == "text") ? lang.getTranslation("params.uppercase.command") : lang.getTranslation("params.uppercase.system")
const blacklisted = opendiscord.blacklist.exists(user.id) ? lang.getTranslation("params.uppercase.true") : lang.getTranslation("params.uppercase.false")
instance.setColor(generalConfig.data.mainColor)
@@ -586,7 +610,7 @@ const ticketEmbeds = () => {
//TICKET MESSAGE
embeds.add(new api.ODEmbed("opendiscord:ticket-message"))
embeds.get("opendiscord:ticket-message").workers.add(
- new api.ODWorker("opendiscord:ticket-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-message",0,async (instance,params,origin) => {
const {user,ticket} = params
const embedOptions = ticket.option.get("opendiscord:ticket-message-embed").value
@@ -599,14 +623,22 @@ const ticketEmbeds = () => {
if (ticket.option.get("opendiscord:questions").value.length > 0){
//show config fields if mixing is allowed
- if (generalConfig.data.system.displayFieldsWithQuestions) instance.addFields(...embedOptions.fields)
+ if (generalConfig.data.ticketSystem.displayFieldsWithQuestions) instance.addFields(...embedOptions.fields)
const answers = ticket.get("opendiscord:answers").value
- answers.forEach((answer) => {
- if (!answer.value || answer.value.length == 0) return
- if (generalConfig.data.system.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value+"```",inline:false})
- else instance.addFields({name:answer.name,value:answer.value,inline:false})
- })
+ for (const answer of answers){
+ if (answer.type == "file-upload"){
+ //render file upload fields
+ if (!answer.files) continue
+ const renderedFiles = answer.files.map((file) => `- [${file.name}](${file.url})`).join("\n")
+ instance.addFields({name:answer.name,value:renderedFiles,inline:false})
+
+ }else if (typeof answer.value == "string" && answer.value.length > 0){
+ //render other fields
+ if (generalConfig.data.ticketSystem.questionFieldsInCodeBlock) instance.addFields({name:answer.name,value:"```"+answer.value.slice(0,1024-6)+"```",inline:false})
+ else instance.addFields({name:answer.name,value:answer.value,inline:false})
+ }
+ }
}else if (embedOptions.fields){
instance.setFields(embedOptions.fields)
}
@@ -625,161 +657,161 @@ const ticketEmbeds = () => {
//TICKET CLOSED
embeds.add(new api.ODEmbed("opendiscord:close-message"))
embeds.get("opendiscord:close-message").workers.add(
- new api.ODWorker("opendiscord:close-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:close-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔒",lang.getTranslation("actions.titles.close")))
instance.setDescription(lang.getTranslation("actions.descriptions.close"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET REOPENED
embeds.add(new api.ODEmbed("opendiscord:reopen-message"))
embeds.get("opendiscord:reopen-message").workers.add(
- new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔓",lang.getTranslation("actions.titles.reopen")))
instance.setDescription(lang.getTranslation("actions.descriptions.reopen"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET DELETED
embeds.add(new api.ODEmbed("opendiscord:delete-message"))
embeds.get("opendiscord:delete-message").workers.add(
- new api.ODWorker("opendiscord:delete-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:delete-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🗑️",lang.getTranslation("actions.titles.delete")))
instance.setDescription(lang.getTranslation("actions.descriptions.delete"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET CLAIMED
embeds.add(new api.ODEmbed("opendiscord:claim-message"))
embeds.get("opendiscord:claim-message").workers.add(
- new api.ODWorker("opendiscord:claim-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:claim-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("👋",lang.getTranslation("actions.titles.claim")))
instance.setDescription(lang.getTranslation("actions.descriptions.claim"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET UNCLAIMED
embeds.add(new api.ODEmbed("opendiscord:unclaim-message"))
embeds.get("opendiscord:unclaim-message").workers.add(
- new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim")))
instance.setDescription(lang.getTranslation("actions.descriptions.unclaim"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET PINNED
embeds.add(new api.ODEmbed("opendiscord:pin-message"))
embeds.get("opendiscord:pin-message").workers.add(
- new api.ODWorker("opendiscord:pin-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:pin-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
- instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.pin")))
+ instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.pin")))
instance.setDescription(lang.getTranslation("actions.descriptions.pin"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET UNPINNED
embeds.add(new api.ODEmbed("opendiscord:unpin-message"))
embeds.get("opendiscord:unpin-message").workers.add(
- new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
- instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.unpin")))
+ instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.unpin")))
instance.setDescription(lang.getTranslation("actions.descriptions.unpin"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET RENAMED
embeds.add(new api.ODEmbed("opendiscord:rename-message"))
embeds.get("opendiscord:rename-message").workers.add(
- new api.ODWorker("opendiscord:rename-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:rename-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.rename",["`#"+data+"`"]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET MOVED
embeds.add(new api.ODEmbed("opendiscord:move-message"))
embeds.get("opendiscord:move-message").workers.add(
- new api.ODWorker("opendiscord:move-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:move-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔀",lang.getTranslation("actions.titles.move")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.move",["`"+data.get("opendiscord:name").value+"`"]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET USER ADDED
embeds.add(new api.ODEmbed("opendiscord:add-message"))
embeds.get("opendiscord:add-message").workers.add(
- new api.ODWorker("opendiscord:add-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:add-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("👤",lang.getTranslation("actions.titles.add")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.add",[discord.userMention(data.id)]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET USER REMOVED
embeds.add(new api.ODEmbed("opendiscord:remove-message"))
embeds.get("opendiscord:remove-message").workers.add(
- new api.ODWorker("opendiscord:remove-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:remove-message",0,async (instance,params,origin) => {
const {user,ticket,reason,data} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("👤",lang.getTranslation("actions.titles.remove")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.remove",[discord.userMention(data.id)]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//TICKET ACTION DM
embeds.add(new api.ODEmbed("opendiscord:ticket-action-dm"))
embeds.get("opendiscord:ticket-action-dm").workers.add(
- new api.ODWorker("opendiscord:ticket-action-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-action-dm",0,async (instance,params,origin) => {
const {user,mode,ticket,reason,additionalData} = params
const channel = await opendiscord.tickets.getTicketChannel(ticket)
@@ -804,10 +836,10 @@ const ticketEmbeds = () => {
instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim")))
instance.setDescription(lang.getTranslation("actions.logs.unclaimDm"))
}else if (mode == "pin"){
- instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.pin")))
+ instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.pin")))
instance.setDescription(lang.getTranslation("actions.logs.pinDm"))
}else if (mode == "unpin"){
- instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.unpin")))
+ instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.unpin")))
instance.setDescription(lang.getTranslation("actions.logs.unpinDm"))
}else if (mode == "rename"){
instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename")))
@@ -828,7 +860,7 @@ const ticketEmbeds = () => {
//TICKET ACTION LOGS
embeds.add(new api.ODEmbed("opendiscord:ticket-action-logs"))
embeds.get("opendiscord:ticket-action-logs").workers.add(
- new api.ODWorker("opendiscord:ticket-action-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-action-logs",0,async (instance,params,origin) => {
const {user,mode,ticket,reason,additionalData} = params
const channel = await opendiscord.tickets.getTicketChannel(ticket)
@@ -840,7 +872,7 @@ const ticketEmbeds = () => {
{name:lang.getTranslation("params.uppercase.ticket")+":",value:"```#"+(channel ? channel.name : "")+"```",inline:false},
{name:lang.getTranslation("params.uppercase.option")+":",value:"```"+(ticket.option.get("opendiscord:name").value)+"```",inline:false},
)
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```",inline:false})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```",inline:false})
if (mode == "close"){
instance.setTitle(utilities.emojiTitle("🔒",lang.getTranslation("actions.titles.close")))
@@ -858,10 +890,10 @@ const ticketEmbeds = () => {
instance.setTitle(utilities.emojiTitle("↩️",lang.getTranslation("actions.titles.unclaim")))
instance.setDescription(lang.getTranslationWithParams("actions.logs.unclaimLog",[discord.userMention(user.id)]))
}else if (mode == "pin"){
- instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.pin")))
+ instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.pin")))
instance.setDescription(lang.getTranslationWithParams("actions.logs.pinLog",[discord.userMention(user.id)]))
}else if (mode == "unpin"){
- instance.setTitle(utilities.emojiTitle(generalConfig.data.system.pinEmoji,lang.getTranslation("actions.titles.unpin")))
+ instance.setTitle(utilities.emojiTitle(generalConfig.data.ticketSystem.pinEmoji,lang.getTranslation("actions.titles.unpin")))
instance.setDescription(lang.getTranslationWithParams("actions.logs.unpinLog",[discord.userMention(user.id)]))
}else if (mode == "rename"){
instance.setTitle(utilities.emojiTitle("🔄",lang.getTranslation("actions.titles.rename")))
@@ -884,7 +916,7 @@ const blacklistEmbeds = () => {
//BLACKLIST VIEW
embeds.add(new api.ODEmbed("opendiscord:blacklist-view"))
embeds.get("opendiscord:blacklist-view").workers.add(
- new api.ODWorker("opendiscord:blacklist-view",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-view",0,async (instance,params,origin) => {
const {user} = params
const renderedUsers: string[] = []
@@ -904,7 +936,7 @@ const blacklistEmbeds = () => {
//BLACKLIST GET
embeds.add(new api.ODEmbed("opendiscord:blacklist-get"))
embeds.get("opendiscord:blacklist-get").workers.add(
- new api.ODWorker("opendiscord:blacklist-get",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-get",0,async (instance,params,origin) => {
const {user,data} = params
const blacklist = opendiscord.blacklist.get(data.id)
@@ -914,7 +946,7 @@ const blacklistEmbeds = () => {
if (blacklist){
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistGetSuccess",[discord.userMention(data.id)]))
- if (blacklist.reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(blacklist.reason ?? "/")+"```"})
+ if (blacklist.reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(blacklist.reason ?? "/")+"```"})
}else instance.setDescription("*"+lang.getTranslationWithParams("actions.descriptions.blacklistGetEmpty",[discord.userMention(data.id)])+"*")
})
@@ -923,35 +955,35 @@ const blacklistEmbeds = () => {
//BLACKLIST ADD
embeds.add(new api.ODEmbed("opendiscord:blacklist-add"))
embeds.get("opendiscord:blacklist-add").workers.add(
- new api.ODWorker("opendiscord:blacklist-add",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-add",0,async (instance,params,origin) => {
const {user,data,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🚫",lang.getTranslation("actions.titles.blacklistAdd")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistAdd",[discord.userMention(data.id)]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//BLACKLIST REMOVE
embeds.add(new api.ODEmbed("opendiscord:blacklist-remove"))
embeds.get("opendiscord:blacklist-remove").workers.add(
- new api.ODWorker("opendiscord:blacklist-remove",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-remove",0,async (instance,params,origin) => {
const {user,data,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🆓",lang.getTranslation("actions.titles.blacklistRemove")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.blacklistRemove",[discord.userMention(data.id)]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//BLACKLIST DM
embeds.add(new api.ODEmbed("opendiscord:blacklist-dm"))
embeds.get("opendiscord:blacklist-dm").workers.add(
- new api.ODWorker("opendiscord:blacklist-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-dm",0,async (instance,params,origin) => {
const {user,mode,data,reason} = params
const title = (mode == "add") ? lang.getTranslation("actions.titles.blacklistAddDm") : lang.getTranslation("actions.titles.blacklistRemoveDm")
@@ -961,14 +993,14 @@ const blacklistEmbeds = () => {
instance.setTitle(utilities.emojiTitle((mode == "add") ? "🚫" : "🆓",title))
instance.setTimestamp(new Date())
instance.setDescription(text)
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//BLACKLIST LOGS
embeds.add(new api.ODEmbed("opendiscord:blacklist-logs"))
embeds.get("opendiscord:blacklist-logs").workers.add(
- new api.ODWorker("opendiscord:blacklist-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-logs",0,async (instance,params,origin) => {
const {user,mode,data,reason} = params
const title = (mode == "add") ? lang.getTranslation("actions.titles.blacklistAdd") : lang.getTranslation("actions.titles.blacklistRemove")
@@ -980,7 +1012,7 @@ const blacklistEmbeds = () => {
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setTimestamp(new Date())
instance.setDescription(text)
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
}
@@ -989,7 +1021,7 @@ const transcriptEmbeds = () => {
//TRANSCRIPT TEXT READY
embeds.add(new api.ODEmbed("opendiscord:transcript-text-ready"))
embeds.get("opendiscord:transcript-text-ready").workers.add(
- new api.ODWorker("opendiscord:transcript-text-ready",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-text-ready",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler} = params
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
@@ -1007,11 +1039,11 @@ const transcriptEmbeds = () => {
}catch{}
}
- if (source == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.text")]))
- else if (source == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.text")]))
- else if (source == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.text")]))
- else if (source == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.text")]))
- else if (source == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.text")]))
+ if (origin == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.text")]))
+ else if (origin == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.text")]))
+ else if (origin == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.text")]))
+ else if (origin == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.text")]))
+ else if (origin == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.text")]))
else instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdOther",[lang.getTranslation("params.lowercase.text")]))
})
)
@@ -1019,7 +1051,7 @@ const transcriptEmbeds = () => {
//TRANSCRIPT HTML READY
embeds.add(new api.ODEmbed("opendiscord:transcript-html-ready"))
embeds.get("opendiscord:transcript-html-ready").workers.add(
- new api.ODWorker("opendiscord:transcript-html-ready",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-html-ready",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,result} = params
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
@@ -1038,11 +1070,11 @@ const transcriptEmbeds = () => {
}catch{}
}
- if (source == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.html")]))
- else if (source == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.html")]))
- else if (source == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.html")]))
- else if (source == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.html")]))
- else if (source == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.html")]))
+ if (origin == "channel") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdChannel",[lang.getTranslation("params.lowercase.html")]))
+ else if (origin == "creator-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdCreator",[lang.getTranslation("params.lowercase.html")]))
+ else if (origin == "participant-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdParticipant",[lang.getTranslation("params.lowercase.html")]))
+ else if (origin == "active-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdActiveAdmin",[lang.getTranslation("params.lowercase.html")]))
+ else if (origin == "every-admin-dm") instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdEveryAdmin",[lang.getTranslation("params.lowercase.html")]))
else instance.setDescription(lang.getTranslationWithParams("transcripts.success.createdOther",[lang.getTranslation("params.lowercase.html")]))
})
)
@@ -1050,7 +1082,7 @@ const transcriptEmbeds = () => {
//TRANSCRIPT HTML PROGRESS
embeds.add(new api.ODEmbed("opendiscord:transcript-html-progress"))
embeds.get("opendiscord:transcript-html-progress").workers.add(
- new api.ODWorker("opendiscord:transcript-html-progress",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-html-progress",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,remaining} = params
const remainingDate = new Date(new Date().getTime()+remaining)
@@ -1076,15 +1108,15 @@ const transcriptEmbeds = () => {
//TRANSCRIPT ERROR
embeds.add(new api.ODEmbed("opendiscord:transcript-error"))
embeds.get("opendiscord:transcript-error").workers.add(
- new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,reason} = params
- instance.setColor(generalConfig.data.system.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
+ instance.setColor(generalConfig.data.ticketSystem.useRedErrorEmbeds ? "Red" : generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("❌",lang.getTranslation("transcripts.errors.title")))
instance.setTimestamp(new Date())
instance.setDescription(lang.getTranslation("transcripts.errors.error"))
instance.setFooter(lang.getTranslation("errors.descriptions.askForInfo"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
}
@@ -1093,7 +1125,7 @@ const roleEmbeds = () => {
//REACTION ROLE
embeds.add(new api.ODEmbed("opendiscord:reaction-role"))
embeds.get("opendiscord:reaction-role").workers.add(
- new api.ODWorker("opendiscord:reaction-role",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reaction-role",0,async (instance,params,origin) => {
const {guild,user,role,result} = params
instance.setColor(generalConfig.data.mainColor)
@@ -1117,7 +1149,7 @@ const roleEmbeds = () => {
//REACTION ROLE DM
embeds.add(new api.ODEmbed("opendiscord:reaction-role-dm"))
embeds.get("opendiscord:reaction-role-dm").workers.add(
- new api.ODWorker("opendiscord:reaction-role-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reaction-role-dm",0,async (instance,params,origin) => {
const {guild,user,role,result} = params
instance.setColor(generalConfig.data.mainColor)
@@ -1143,7 +1175,7 @@ const roleEmbeds = () => {
//REACTION ROLE LOGS
embeds.add(new api.ODEmbed("opendiscord:reaction-role-logs"))
embeds.get("opendiscord:reaction-role-logs").workers.add(
- new api.ODWorker("opendiscord:reaction-role-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reaction-role-logs",0,async (instance,params,origin) => {
const {guild,user,role,result} = params
instance.setColor(generalConfig.data.mainColor)
@@ -1171,7 +1203,7 @@ const clearEmbeds = () => {
//CLEAR VERIFY MESSAGE
embeds.add(new api.ODEmbed("opendiscord:clear-verify-message"))
embeds.get("opendiscord:clear-verify-message").workers.add(
- new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params
instance.setColor(generalConfig.data.mainColor)
@@ -1189,7 +1221,7 @@ const clearEmbeds = () => {
//CLEAR MESSAGE
embeds.add(new api.ODEmbed("opendiscord:clear-message"))
embeds.get("opendiscord:clear-message").workers.add(
- new api.ODWorker("opendiscord:clear-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:clear-message",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params
instance.setColor(generalConfig.data.mainColor)
@@ -1206,7 +1238,7 @@ const clearEmbeds = () => {
//CLEAR LOGS
embeds.add(new api.ODEmbed("opendiscord:clear-logs"))
embeds.get("opendiscord:clear-logs").workers.add(
- new api.ODWorker("opendiscord:clear-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:clear-logs",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params
instance.setColor(generalConfig.data.mainColor)
@@ -1226,10 +1258,10 @@ const autoEmbeds = () => {
//AUTOCLOSE MESSAGE
embeds.add(new api.ODEmbed("opendiscord:autoclose-message"))
embeds.get("opendiscord:autoclose-message").workers.add(
- new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,origin) => {
const {user,ticket} = params
const hours: number = ticket.get("opendiscord:autoclose-hours").value
- const description = (source == "leave") ? lang.getTranslation("actions.descriptions.autocloseLeave") : lang.getTranslationWithParams("actions.descriptions.autocloseTimeout",[hours.toString()])
+ const description = (origin == "leave") ? lang.getTranslation("actions.descriptions.autocloseLeave") : lang.getTranslationWithParams("actions.descriptions.autocloseTimeout",[hours.toString()])
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
@@ -1242,10 +1274,10 @@ const autoEmbeds = () => {
//AUTODELETE MESSAGE
embeds.add(new api.ODEmbed("opendiscord:autodelete-message"))
embeds.get("opendiscord:autodelete-message").workers.add(
- new api.ODWorker("opendiscord:autodelete-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autodelete-message",0,async (instance,params,origin) => {
const {user,ticket} = params
const days: number = ticket.get("opendiscord:autodelete-days").value
- const description = (source == "leave") ? lang.getTranslation("actions.descriptions.autodeleteLeave") : lang.getTranslationWithParams("actions.descriptions.autodeleteTimeout",[days.toString()])
+ const description = (origin == "leave") ? lang.getTranslation("actions.descriptions.autodeleteLeave") : lang.getTranslationWithParams("actions.descriptions.autodeleteTimeout",[days.toString()])
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
@@ -1258,56 +1290,56 @@ const autoEmbeds = () => {
//AUTOCLOSE ENABLE
embeds.add(new api.ODEmbed("opendiscord:autoclose-enable"))
embeds.get("opendiscord:autoclose-enable").workers.add(
- new api.ODWorker("opendiscord:autoclose-enable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autoclose-enable",0,async (instance,params,origin) => {
const {user,ticket,reason,time} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autocloseEnabled")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.autocloseEnabled",[time.toString()]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//AUTODELETE ENABLE
embeds.add(new api.ODEmbed("opendiscord:autodelete-enable"))
embeds.get("opendiscord:autodelete-enable").workers.add(
- new api.ODWorker("opendiscord:autodelete-enable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autodelete-enable",0,async (instance,params,origin) => {
const {user,ticket,reason,time} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autodeleteEnabled")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.autodeleteEnabled",[time.toString()]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//AUTOCLOSE DISABLE
embeds.add(new api.ODEmbed("opendiscord:autoclose-disable"))
embeds.get("opendiscord:autoclose-disable").workers.add(
- new api.ODWorker("opendiscord:autoclose-disable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autoclose-disable",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autocloseDisabled")))
instance.setDescription(lang.getTranslation("actions.descriptions.autocloseDisabled"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//AUTODELETE DISABLE
embeds.add(new api.ODEmbed("opendiscord:autodelete-disable"))
embeds.get("opendiscord:autodelete-disable").workers.add(
- new api.ODWorker("opendiscord:autodelete-disable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autodelete-disable",0,async (instance,params,origin) => {
const {user,ticket,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("⏱️",lang.getTranslation("actions.titles.autodeleteDisabled")))
instance.setDescription(lang.getTranslation("actions.descriptions.autodeleteDisabled"))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
}
@@ -1316,7 +1348,7 @@ const extraEmbeds = () => {
//TOPIC SET
embeds.add(new api.ODEmbed("opendiscord:topic-set"))
embeds.get("opendiscord:topic-set").workers.add(
- new api.ODWorker("opendiscord:topic-set",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:topic-set",0,async (instance,params,origin) => {
const {user,topic} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
@@ -1330,21 +1362,21 @@ const extraEmbeds = () => {
//PRIORITY SET
embeds.add(new api.ODEmbed("opendiscord:priority-set"))
embeds.get("opendiscord:priority-set").workers.add(
- new api.ODWorker("opendiscord:priority-set",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:priority-set",0,async (instance,params,origin) => {
const {user,priority,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🚨",lang.getTranslation("actions.titles.prioritySet")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.prioritySet",["**"+priority.renderDisplayName()+"**",discord.userMention(user.id)]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
//PRIORITY GET
embeds.add(new api.ODEmbed("opendiscord:priority-get"))
embeds.get("opendiscord:priority-get").workers.add(
- new api.ODWorker("opendiscord:priority-get",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:priority-get",0,async (instance,params,origin) => {
const {user,priority} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
@@ -1357,14 +1389,14 @@ const extraEmbeds = () => {
//TRANSFER MESSAGE
embeds.add(new api.ODEmbed("opendiscord:transfer-message"))
embeds.get("opendiscord:transfer-message").workers.add(
- new api.ODWorker("opendiscord:transfer-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transfer-message",0,async (instance,params,origin) => {
const {user,oldCreator,newCreator,reason} = params
instance.setAuthor(user.displayName,user.displayAvatarURL())
instance.setColor(generalConfig.data.mainColor)
instance.setTitle(utilities.emojiTitle("🔀",lang.getTranslation("actions.titles.transfer")))
instance.setDescription(lang.getTranslationWithParams("actions.descriptions.transfer",[discord.userMention(oldCreator.id),discord.userMention(newCreator.id),discord.userMention(user.id)]))
- if (reason || generalConfig.data.system.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
+ if (reason || generalConfig.data.ticketSystem.alwaysShowReason) instance.addFields({name:lang.getTranslation("params.uppercase.reason")+":",value:"```"+(reason ?? "/")+"```"})
})
)
}
\ No newline at end of file
diff --git a/src/builders/files.ts b/src/builders/files.ts
index 9a30548..252a719 100644
--- a/src/builders/files.ts
+++ b/src/builders/files.ts
@@ -1,14 +1,14 @@
///////////////////////////////////////
//FILE BUILDERS
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
const files = opendiscord.builders.files
const lang = opendiscord.languages
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
-export const registerAllFiles = async () => {
+export async function registerAllFiles(){
transcriptFiles()
}
@@ -17,7 +17,7 @@ const transcriptFiles = () => {
//TEXT TRANSCRIPT
files.add(new api.ODFile("opendiscord:text-transcript"))
files.get("opendiscord:text-transcript").workers.add(
- new api.ODWorker("opendiscord:text-transcript",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:text-transcript",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,result} = params
const fileMode = transcriptConfig.data.textTranscriptStyle.fileMode
diff --git a/src/builders/messages.ts b/src/builders/messages.ts
index 0b89c1b..7d6665a 100644
--- a/src/builders/messages.ts
+++ b/src/builders/messages.ts
@@ -1,7 +1,7 @@
///////////////////////////////////////
//MESSAGE BUILDERS
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
const messages = opendiscord.builders.messages
@@ -12,8 +12,7 @@ const embeds = opendiscord.builders.embeds
const lang = opendiscord.languages
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerAllMessages = async () => {
- verifyBarMessages()
+export async function registerAllMessages(){
errorMessages()
helpMenuMessages()
statsMessages()
@@ -27,314 +26,13 @@ export const registerAllMessages = async () => {
extraMessages()
}
-const verifyBarMessages = () => {
- //VERIFYBAR TICKET MESSAGE
- messages.add(new api.ODMessage("opendiscord:verifybar-ticket-message"))
- messages.get("opendiscord:verifybar-ticket-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-ticket-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-ticket-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-ticket-message`")
- return
- }
- const option = ticket.option
-
- //add pings
- const pingOptions = option.get("opendiscord:ticket-message-ping").value
- const pings: string[] = []
- const creator = ticket.get("opendiscord:opened-by").value
- if (creator) pings.push(discord.userMention(creator))
- if (pingOptions["@everyone"]) pings.push("@everyone")
- if (pingOptions["@here"]) pings.push("@here")
- pingOptions.custom.forEach((ping) => pings.push(discord.roleMention(ping)))
- const pingText = (pings.length > 0) ? pings.join(" ")+"\n" : ""
-
- //add text
- const text = option.get("opendiscord:ticket-message-text").value
- if (text !== "") instance.setContent(pingText+text)
- else instance.setContent(pingText)
-
- //add embed
- if (option.get("opendiscord:ticket-message-embed").value.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:claim-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:unclaim-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:pin-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:unpin-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:close-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:reopen-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:delete-ticket-ticket-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"}))
- }
- })
- )
-
- //TICKET CLOSED
- messages.add(new api.ODMessage("opendiscord:verifybar-close-message"))
- messages.get("opendiscord:verifybar-close-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-close-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-close-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-close-message`")
- return
- }
-
- const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:reopen-ticket-close-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:delete-ticket-close-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"}))
- }
- })
- )
-
- //TICKET REOPENED
- messages.add(new api.ODMessage("opendiscord:verifybar-reopen-message"))
- messages.get("opendiscord:verifybar-reopen-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-reopen-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-reopen-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-reopen-message`")
- return
- }
-
- const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:close-ticket-reopen-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:delete-ticket-reopen-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"}))
- }
- })
- )
-
- //TICKET CLAIM
- messages.add(new api.ODMessage("opendiscord:verifybar-claim-message"))
- messages.get("opendiscord:verifybar-claim-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-claim-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-claim-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-claim-message`")
- return
- }
-
- const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:unclaim-ticket-claim-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- }
- })
- )
-
- //TICKET UNCLAIM
- messages.add(new api.ODMessage("opendiscord:verifybar-unclaim-message"))
- messages.get("opendiscord:verifybar-unclaim-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-unclaim-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-unclaim-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-unclaim-message`")
- return
- }
-
- const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:claim-ticket-unclaim-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- }
- })
- )
-
- //TICKET PIN
- messages.add(new api.ODMessage("opendiscord:verifybar-pin-message"))
- messages.get("opendiscord:verifybar-pin-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-pin-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-pin-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-pin-message`")
- return
- }
-
- const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:unpin-ticket-pin-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- }
- })
- )
-
- //TICKET UNPIN
- messages.add(new api.ODMessage("opendiscord:verifybar-unpin-message"))
- messages.get("opendiscord:verifybar-unpin-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-unpin-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-unpin-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-unpin-message`")
- return
- }
-
- const rawReason = (originalMessage.embeds[0] && originalMessage.embeds[0].fields[0]) ? originalMessage.embeds[0].fields[0].value : null
- const reason = (rawReason == null) ? null : rawReason.substring(3,rawReason.length-3)
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:pin-ticket-unpin-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- }
- })
- )
-
- //TICKET AUTOCLOSED
- messages.add(new api.ODMessage("opendiscord:verifybar-autoclose-message"))
- messages.get("opendiscord:verifybar-autoclose-message").workers.add(
- new api.ODWorker("opendiscord:verifybar-autoclose-message",0,async (instance,params,source) => {
- const {guild,channel,user,verifybar,originalMessage} = params
- if (!guild || channel.isDMBased()){
- instance.setContent("ODError: Not In Guild => `opendiscord:verifybar-autoclose-message`")
- return
- }
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket){
- instance.setContent("ODError: Unknown Ticket => `opendiscord:verifybar-autoclose-message`")
- return
- }
-
- //add embed
- instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-message").build("other",{guild,channel,user,ticket}))
-
- //add verifybar components
- if (verifybar.id.value == "opendiscord:reopen-ticket-autoclose-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
-
- }else if (verifybar.id.value == "opendiscord:delete-ticket-autoclose-message"){
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar}))
- instance.addComponent(await buttons.getSafe("opendiscord:verifybar-failure").build("verifybar",{guild,channel,user,verifybar}))
- if (generalConfig.data.system.enableTicketActionWithReason) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"reason",customEmoji:"✏️",customLabel:lang.getTranslation("actions.buttons.withReason"),customColor:"blue"}))
- if (generalConfig.data.system.enableDeleteWithoutTranscript) instance.addComponent(await buttons.getSafe("opendiscord:verifybar-success").build("verifybar",{guild,channel,user,verifybar,customData:"no-transcript",customEmoji:"📄",customLabel:lang.getTranslation("actions.buttons.withoutTranscript"),customColor:"red"}))
- }
- })
- )
-}
-
const errorMessages = () => {
//ERROR
messages.add(new api.ODMessage("opendiscord:error"))
messages.get("opendiscord:error").workers.add(
- new api.ODWorker("opendiscord:error",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error",0,async (instance,params,origin) => {
const {guild,channel,user,error,layout,customTitle} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error").build(source,{guild,channel,user,error,layout,customTitle}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error").build(origin,{guild,channel,user,error,layout,customTitle}))
instance.setEphemeral(true)
})
)
@@ -342,9 +40,9 @@ const errorMessages = () => {
//ERROR OPTION MISSING
messages.add(new api.ODMessage("opendiscord:error-option-missing"))
messages.get("opendiscord:error-option-missing").workers.add(
- new api.ODWorker("opendiscord:error-option-missing",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-option-missing",0,async (instance,params,origin) => {
const {guild,channel,user,error} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-option-missing").build(source,{guild,channel,user,error}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-option-missing").build(origin,{guild,channel,user,error}))
instance.setEphemeral(true)
})
)
@@ -352,9 +50,9 @@ const errorMessages = () => {
//ERROR OPTION INVALID
messages.add(new api.ODMessage("opendiscord:error-option-invalid"))
messages.get("opendiscord:error-option-invalid").workers.add(
- new api.ODWorker("opendiscord:error-option-invalid",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-option-invalid",0,async (instance,params,origin) => {
const {guild,channel,user,error} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-option-invalid").build(source,{guild,channel,user,error}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-option-invalid").build(origin,{guild,channel,user,error}))
instance.setEphemeral(true)
})
)
@@ -362,9 +60,9 @@ const errorMessages = () => {
//ERROR UNKNOWN COMMAND
messages.add(new api.ODMessage("opendiscord:error-unknown-command"))
messages.get("opendiscord:error-unknown-command").workers.add(
- new api.ODWorker("opendiscord:error-unknown-command",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-unknown-command",0,async (instance,params,origin) => {
const {guild,channel,user,error} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-unknown-command").build(source,{guild,channel,user,error}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-unknown-command").build(origin,{guild,channel,user,error}))
instance.setEphemeral(true)
})
)
@@ -372,9 +70,9 @@ const errorMessages = () => {
//ERROR NO PERMISSIONS
messages.add(new api.ODMessage("opendiscord:error-no-permissions"))
messages.get("opendiscord:error-no-permissions").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions",0,async (instance,params,origin) => {
const {guild,channel,user,permissions} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions}))
instance.setEphemeral(true)
})
)
@@ -382,9 +80,9 @@ const errorMessages = () => {
//ERROR NO PERMISSIONS COOLDOWN
messages.add(new api.ODMessage("opendiscord:error-no-permissions-cooldown"))
messages.get("opendiscord:error-no-permissions-cooldown").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions-cooldown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions-cooldown",0,async (instance,params,origin) => {
const {guild,channel,user,until} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions-cooldown").build(source,{guild,channel,user,until}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions-cooldown").build(origin,{guild,channel,user,until}))
instance.setEphemeral(true)
})
)
@@ -392,9 +90,9 @@ const errorMessages = () => {
//ERROR NO PERMISSIONS BLACKLISTED
messages.add(new api.ODMessage("opendiscord:error-no-permissions-blacklisted"))
messages.get("opendiscord:error-no-permissions-blacklisted").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions-blacklisted",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions-blacklisted",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions-blacklisted").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions-blacklisted").build(origin,{guild,channel,user}))
instance.setEphemeral(true)
})
)
@@ -402,9 +100,9 @@ const errorMessages = () => {
//ERROR NO PERMISSIONS LIMITS
messages.add(new api.ODMessage("opendiscord:error-no-permissions-limits"))
messages.get("opendiscord:error-no-permissions-limits").workers.add(
- new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-no-permissions-limits",0,async (instance,params,origin) => {
const {guild,channel,user,limit} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild,channel,user,limit}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-no-permissions-limits").build(origin,{guild,channel,user,limit}))
instance.setEphemeral(true)
})
)
@@ -412,9 +110,9 @@ const errorMessages = () => {
//ERROR RESPONDER TIMEOUT
messages.add(new api.ODMessage("opendiscord:error-responder-timeout"))
messages.get("opendiscord:error-responder-timeout").workers.add(
- new api.ODWorker("opendiscord:error-responder-timeout",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-responder-timeout",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-responder-timeout").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-responder-timeout").build(origin,{guild,channel,user}))
instance.setEphemeral(true)
})
)
@@ -422,9 +120,9 @@ const errorMessages = () => {
//ERROR TICKET UNKNOWN
messages.add(new api.ODMessage("opendiscord:error-ticket-unknown"))
messages.get("opendiscord:error-ticket-unknown").workers.add(
- new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-ticket-unknown",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-ticket-unknown").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-ticket-unknown").build(origin,{guild,channel,user}))
instance.setEphemeral(true)
})
)
@@ -432,10 +130,10 @@ const errorMessages = () => {
//ERROR TICKET DEPRECATED
messages.add(new api.ODMessage("opendiscord:error-ticket-deprecated"))
messages.get("opendiscord:error-ticket-deprecated").workers.add(
- new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-ticket-deprecated",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-ticket-deprecated").build(source,{guild,channel,user}))
- instance.addComponent(await buttons.getSafe("opendiscord:error-ticket-deprecated-transcript").build(source,{}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-ticket-deprecated").build(origin,{guild,channel,user}))
+ instance.addComponent(await buttons.getSafe("opendiscord:error-ticket-deprecated-transcript").build(origin,{}))
instance.setEphemeral(true)
})
)
@@ -443,9 +141,9 @@ const errorMessages = () => {
//ERROR OPTION UNKNOWN
messages.add(new api.ODMessage("opendiscord:error-option-unknown"))
messages.get("opendiscord:error-option-unknown").workers.add(
- new api.ODWorker("opendiscord:error-option-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-option-unknown",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-option-unknown").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-option-unknown").build(origin,{guild,channel,user}))
instance.setEphemeral(true)
})
)
@@ -453,9 +151,9 @@ const errorMessages = () => {
//ERROR PANEL UNKNOWN
messages.add(new api.ODMessage("opendiscord:error-panel-unknown"))
messages.get("opendiscord:error-panel-unknown").workers.add(
- new api.ODWorker("opendiscord:error-panel-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-panel-unknown",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-panel-unknown").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-panel-unknown").build(origin,{guild,channel,user}))
instance.setEphemeral(true)
})
)
@@ -463,9 +161,9 @@ const errorMessages = () => {
//ERROR NOT IN GUILD
messages.add(new api.ODMessage("opendiscord:error-not-in-guild"))
messages.get("opendiscord:error-not-in-guild").workers.add(
- new api.ODWorker("opendiscord:error-not-in-guild",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-not-in-guild",0,async (instance,params,origin) => {
const {channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-not-in-guild").build(origin,{channel,user}))
instance.setEphemeral(true)
})
)
@@ -473,9 +171,19 @@ const errorMessages = () => {
//ERROR CHANNEL RENAME
messages.add(new api.ODMessage("opendiscord:error-channel-rename"))
messages.get("opendiscord:error-channel-rename").workers.add(
- new api.ODWorker("opendiscord:error-channel-rename",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-channel-rename",0,async (instance,params,origin) => {
const {guild,channel,user,originalName,newName} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-channel-rename").build(source,{guild,channel,user,originalName,newName}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-channel-rename").build(origin,{guild,channel,user,originalName,newName}))
+ instance.setEphemeral(true)
+ })
+ )
+
+ //ERROR CHANNEL CATEGORY
+ messages.add(new api.ODMessage("opendiscord:error-channel-category"))
+ messages.get("opendiscord:error-channel-category").workers.add(
+ new api.ODWorker("opendiscord:error-channel-category",0,async (instance,params,origin) => {
+ const {guild,channel,user,originalCategory,newCategory} = params
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-channel-category").build(origin,{guild,channel,user,originalCategory,newCategory}))
instance.setEphemeral(true)
})
)
@@ -483,9 +191,9 @@ const errorMessages = () => {
//ERROR TICKET BUSY
messages.add(new api.ODMessage("opendiscord:error-ticket-busy"))
messages.get("opendiscord:error-ticket-busy").workers.add(
- new api.ODWorker("opendiscord:error-ticket-busy",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:error-ticket-busy",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:error-ticket-busy").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:error-ticket-busy").build(origin,{guild,channel,user}))
instance.setEphemeral(true)
})
)
@@ -495,20 +203,20 @@ const helpMenuMessages = () => {
//HELP MENU
messages.add(new api.ODMessage("opendiscord:help-menu"))
messages.get("opendiscord:help-menu").workers.add(
- new api.ODWorker("opendiscord:help-menu",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:help-menu",0,async (instance,params,origin) => {
const {mode,page} = params
const totalPages = (await opendiscord.helpmenu.render(mode)).length
- const embed = await embeds.getSafe("opendiscord:help-menu").build(source,{mode,page})
+ const embed = await embeds.getSafe("opendiscord:help-menu").build(origin,{mode,page})
instance.addEmbed(embed)
if (totalPages > 1){
//when more than 1 page
- instance.addComponent(await buttons.getSafe("opendiscord:help-menu-previous").build(source,{mode,page}))
- instance.addComponent(await buttons.getSafe("opendiscord:help-menu-page").build(source,{mode,page}))
- instance.addComponent(await buttons.getSafe("opendiscord:help-menu-next").build(source,{mode,page}))
+ instance.addComponent(await buttons.getSafe("opendiscord:help-menu-previous").build(origin,{mode,page}))
+ instance.addComponent(await buttons.getSafe("opendiscord:help-menu-page").build(origin,{mode,page}))
+ instance.addComponent(await buttons.getSafe("opendiscord:help-menu-next").build(origin,{mode,page}))
instance.addComponent(buttons.getNewLine("opendiscord:help-menu-divider"))
}
- if (generalConfig.data.textCommands && generalConfig.data.slashCommands) instance.addComponent(await buttons.get("opendiscord:help-menu-switch").build(source,{mode,page}))
+ if (generalConfig.data.textCommands && generalConfig.data.slashCommands) instance.addComponent(await buttons.get("opendiscord:help-menu-switch").build(origin,{mode,page}))
})
)
}
@@ -517,45 +225,45 @@ const statsMessages = () => {
//STATS GLOBAL
messages.add(new api.ODMessage("opendiscord:stats-global"))
messages.get("opendiscord:stats-global").workers.add(
- new api.ODWorker("opendiscord:stats-global",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:stats-global",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:stats-global").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:stats-global").build(origin,{guild,channel,user}))
})
)
//STATS TICKET
messages.add(new api.ODMessage("opendiscord:stats-ticket"))
messages.get("opendiscord:stats-ticket").workers.add(
- new api.ODWorker("opendiscord:stats-ticket",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:stats-ticket",0,async (instance,params,origin) => {
const {guild,channel,user,scopeData} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:stats-ticket").build(source,{guild,channel,user,scopeData}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:stats-ticket").build(origin,{guild,channel,user,scopeData}))
})
)
//STATS USER
messages.add(new api.ODMessage("opendiscord:stats-user"))
messages.get("opendiscord:stats-user").workers.add(
- new api.ODWorker("opendiscord:stats-user",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:stats-user",0,async (instance,params,origin) => {
const {guild,channel,user,scopeData} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:stats-user").build(source,{guild,channel,user,scopeData}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:stats-user").build(origin,{guild,channel,user,scopeData}))
})
)
//STATS RESET
messages.add(new api.ODMessage("opendiscord:stats-reset"))
messages.get("opendiscord:stats-reset").workers.add(
- new api.ODWorker("opendiscord:stats-reset",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:stats-reset",0,async (instance,params,origin) => {
const {guild,channel,user,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:stats-reset").build(source,{guild,channel,user,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:stats-reset").build(origin,{guild,channel,user,reason}))
})
)
//STATS TICKET UNKNOWN
messages.add(new api.ODMessage("opendiscord:stats-ticket-unknown"))
messages.get("opendiscord:stats-ticket-unknown").workers.add(
- new api.ODWorker("opendiscord:stats-ticket-unknown",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:stats-ticket-unknown",0,async (instance,params,origin) => {
const {guild,channel,user,id} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:stats-ticket-unknown").build(source,{guild,channel,user,id}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:stats-ticket-unknown").build(origin,{guild,channel,user,id}))
instance.setEphemeral(true)
})
)
@@ -565,8 +273,11 @@ const panelMessages = () => {
//PANEL
messages.add(new api.ODMessage("opendiscord:panel"))
messages.get("opendiscord:panel").workers.add([
- new api.ODWorker("opendiscord:panel-layout",1,async (instance,params,source) => {
- const {guild,channel,user,panel} = params
+ new api.ODWorker("opendiscord:panel-layout",1,async (instance,params,origin) => {
+ const {guild,channel,user,panel,isSubPanel} = params
+
+ //ephemeral if sub-panel
+ if (isSubPanel) instance.setEphemeral(true)
//add text
const text = panel.get("opendiscord:text").value
@@ -578,15 +289,15 @@ const panelMessages = () => {
instance.setContent(text)
}
- if (panel.get("opendiscord:enable-max-tickets-warning-text").value && generalConfig.data.system.limits.enabled){
- instance.setContent(instance.data.content+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.system.limits.userMaximum.toString()])+"*")
+ if (panel.get("opendiscord:enable-max-tickets-warning-text").value && generalConfig.data.ticketSystem.limits.enabled){
+ instance.setContent(instance.data.content+"\n\n*"+lang.getTranslationWithParams("actions.descriptions.ticketMessageLimit",[generalConfig.data.ticketSystem.limits.userMaximum.toString()])+"*")
}
//add embed
const embedOptions = panel.get("opendiscord:embed").value
- if (embedOptions.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:panel").build(source,{guild,channel,user,panel}))
+ if (embedOptions.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:panel").build(origin,{guild,channel,user,panel,isSubPanel}))
}),
- new api.ODWorker("opendiscord:panel-components",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:panel-components",0,async (instance,params,origin) => {
const {guild,channel,user,panel} = params
const options: api.ODOption[] = []
panel.get("opendiscord:options").value.forEach((id) => {
@@ -596,17 +307,27 @@ const panelMessages = () => {
if (panel.get("opendiscord:dropdown").value){
//dropdown
- const ticketOptions: api.ODTicketOption[] = []
+ const ticketOptions: (api.ODTicketOption|api.ODRoleOption|api.ODSubPanelOption)[] = []
options.forEach((option) => {
if (option instanceof api.ODTicketOption) ticketOptions.push(option)
+ if (option instanceof api.ODRoleOption) ticketOptions.push(option)
+ if (option instanceof api.ODSubPanelOption) ticketOptions.push(option)
})
- instance.addComponent(await dropdowns.getSafe("opendiscord:panel-dropdown-tickets").build(source,{guild,channel,user,panel,options:ticketOptions}))
+ instance.addComponent(await dropdowns.getSafe("opendiscord:panel-dropdown").build(origin,{guild,channel,user,panel,options:ticketOptions}))
}else{
//buttons
+ let rowButtonCount: number = 0
for (const option of options){
- if (option instanceof api.ODTicketOption) instance.addComponent(await buttons.getSafe("opendiscord:ticket-option").build(source,{guild,channel,user,panel,option}))
- else if (option instanceof api.ODWebsiteOption) instance.addComponent(await buttons.getSafe("opendiscord:website-option").build(source,{guild,channel,user,panel,option}))
- else if (option instanceof api.ODRoleOption) instance.addComponent(await buttons.getSafe("opendiscord:role-option").build(source,{guild,channel,user,panel,option}))
+ if (rowButtonCount >= panel.get("opendiscord:maximum-buttons-per-row").value){
+ instance.addComponent({id:new api.ODId("opendiscord:new-row"),component:"\n"})
+ rowButtonCount = 0
+ }
+ if (option instanceof api.ODTicketOption) instance.addComponent(await buttons.getSafe("opendiscord:ticket-option").build(origin,{guild,channel,user,panel,option}))
+ else if (option instanceof api.ODWebsiteOption) instance.addComponent(await buttons.getSafe("opendiscord:website-option").build(origin,{guild,channel,user,panel,option}))
+ else if (option instanceof api.ODRoleOption) instance.addComponent(await buttons.getSafe("opendiscord:role-option").build(origin,{guild,channel,user,panel,option}))
+ else if (option instanceof api.ODSubPanelOption) instance.addComponent(await buttons.getSafe("opendiscord:subpanel-option").build(origin,{guild,channel,user,panel,option}))
+
+ rowButtonCount++
}
}
})
@@ -615,7 +336,7 @@ const panelMessages = () => {
//PANEL READY
messages.add(new api.ODMessage("opendiscord:panel-ready"))
messages.get("opendiscord:panel-ready").workers.add(
- new api.ODWorker("opendiscord:panel-ready",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:panel-ready",0,async (instance,params,origin) => {
instance.setContent("## "+lang.getTranslation("actions.descriptions.panelReady"))
instance.setEphemeral(true)
})
@@ -626,10 +347,10 @@ const ticketMessages = () => {
//TICKET CREATED
messages.add(new api.ODMessage("opendiscord:ticket-created"))
messages.get("opendiscord:ticket-created").workers.add(
- new api.ODWorker("opendiscord:ticket-created",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-created",0,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:ticket-created").build(source,{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:ticket-created").build(origin,{guild,channel,user,ticket}))
instance.addComponent(await buttons.getSafe("opendiscord:visit-ticket").build("ticket-created",{guild,channel,user,ticket}))
instance.setEphemeral(true)
})
@@ -638,7 +359,7 @@ const ticketMessages = () => {
//TICKET CREATED DM
messages.add(new api.ODMessage("opendiscord:ticket-created-dm"))
messages.get("opendiscord:ticket-created-dm").workers.add(
- new api.ODWorker("opendiscord:ticket-created-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-created-dm",0,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
//add text
@@ -646,7 +367,7 @@ const ticketMessages = () => {
if (text !== "") instance.setContent(text)
//add embed
- if (ticket.option.get("opendiscord:dm-message-embed").value.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:ticket-created-dm").build(source,{guild,channel,user,ticket}))
+ if (ticket.option.get("opendiscord:dm-message-embed").value.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:ticket-created-dm").build(origin,{guild,channel,user,ticket}))
//add components
instance.addComponent(await buttons.getSafe("opendiscord:visit-ticket").build("ticket-created",{guild,channel,user,ticket}))
@@ -656,10 +377,10 @@ const ticketMessages = () => {
//TICKET CREATED LOGS
messages.add(new api.ODMessage("opendiscord:ticket-created-logs"))
messages.get("opendiscord:ticket-created-logs").workers.add(
- new api.ODWorker("opendiscord:ticket-created-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-created-logs",0,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:ticket-created-logs").build(source,{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:ticket-created-logs").build(origin,{guild,channel,user,ticket}))
instance.addComponent(await buttons.getSafe("opendiscord:visit-ticket").build("ticket-created",{guild,channel,user,ticket}))
})
)
@@ -667,7 +388,7 @@ const ticketMessages = () => {
//TICKET MESSAGE
messages.add(new api.ODMessage("opendiscord:ticket-message"))
messages.get("opendiscord:ticket-message").workers.add([
- new api.ODWorker("opendiscord:ticket-message-layout",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-message-layout",0,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
//add pings
@@ -686,12 +407,12 @@ const ticketMessages = () => {
else instance.setContent(pingText)
//add embed
- if (ticket.option.get("opendiscord:ticket-message-embed").value.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:ticket-message").build(source,{guild,channel,user,ticket}))
+ if (ticket.option.get("opendiscord:ticket-message-embed").value.enabled) instance.addEmbed(await embeds.getSafe("opendiscord:ticket-message").build(origin,{guild,channel,user,ticket}))
}),
- new api.ODWorker("opendiscord:ticket-message-components",1,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-message-components",1,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
//add components
- if (generalConfig.data.system.enableTicketClaimButtons && !ticket.get("opendiscord:closed").value){
+ if (generalConfig.data.ticketSystem.enableTicketClaimButtons && !ticket.get("opendiscord:closed").value){
//enable ticket claiming
if (ticket.get("opendiscord:claimed").value){
instance.addComponent(await buttons.getSafe("opendiscord:unclaim-ticket").build("ticket-message",{guild,channel,user,ticket}))
@@ -699,7 +420,7 @@ const ticketMessages = () => {
instance.addComponent(await buttons.getSafe("opendiscord:claim-ticket").build("ticket-message",{guild,channel,user,ticket}))
}
}
- if (generalConfig.data.system.enableTicketPinButtons && !ticket.get("opendiscord:closed").value){
+ if (generalConfig.data.ticketSystem.enableTicketPinButtons && !ticket.get("opendiscord:closed").value){
//enable ticket pinning
if (ticket.get("opendiscord:pinned").value){
instance.addComponent(await buttons.getSafe("opendiscord:unpin-ticket").build("ticket-message",{guild,channel,user,ticket}))
@@ -707,7 +428,7 @@ const ticketMessages = () => {
instance.addComponent(await buttons.getSafe("opendiscord:pin-ticket").build("ticket-message",{guild,channel,user,ticket}))
}
}
- if (generalConfig.data.system.enableTicketCloseButtons){
+ if (generalConfig.data.ticketSystem.enableTicketCloseButtons){
//enable ticket closing
if (ticket.get("opendiscord:closed").value){
instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("ticket-message",{guild,channel,user,ticket}))
@@ -716,9 +437,9 @@ const ticketMessages = () => {
}
}
//enable ticket deletion
- if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("ticket-message",{guild,channel,user,ticket}))
+ if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("ticket-message",{guild,channel,user,ticket}))
}),
- new api.ODWorker("opendiscord:ticket-message-disable-components",2,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-message-disable-components",2,async (instance,params,origin) => {
const {ticket} = params
if (ticket.get("opendiscord:for-deletion").value){
//disable all buttons when ticket is being prepared for deletion
@@ -734,125 +455,125 @@ const ticketMessages = () => {
//TICKET CLOSED
messages.add(new api.ODMessage("opendiscord:close-message"))
messages.get("opendiscord:close-message").workers.add(
- new api.ODWorker("opendiscord:close-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:close-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:close-message").build(source,{guild,channel,user,ticket,reason}))
- if (generalConfig.data.system.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("close-message",{guild,channel,user,ticket}))
- if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("close-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (generalConfig.data.ticketSystem.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("close-message",{guild,channel,user,ticket}))
+ if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("close-message",{guild,channel,user,ticket}))
})
)
//TICKET REOPENED
messages.add(new api.ODMessage("opendiscord:reopen-message"))
messages.get("opendiscord:reopen-message").workers.add(
- new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reopen-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:reopen-message").build(source,{guild,channel,user,ticket,reason}))
- if (generalConfig.data.system.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:close-ticket").build("reopen-message",{guild,channel,user,ticket}))
- if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("reopen-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (generalConfig.data.ticketSystem.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:close-ticket").build("reopen-message",{guild,channel,user,ticket}))
+ if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("reopen-message",{guild,channel,user,ticket}))
})
)
//TICKET DELETED
messages.add(new api.ODMessage("opendiscord:delete-message"))
messages.get("opendiscord:delete-message").workers.add(
- new api.ODWorker("opendiscord:delete-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:delete-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:delete-message").build(source,{guild,channel,user,ticket,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:delete-message").build(origin,{guild,channel,user,ticket,reason}))
})
)
//TICKET CLAIMED
messages.add(new api.ODMessage("opendiscord:claim-message"))
messages.get("opendiscord:claim-message").workers.add(
- new api.ODWorker("opendiscord:claim-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:claim-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:claim-message").build(source,{guild,channel,user,ticket,reason}))
- if (generalConfig.data.system.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:unclaim-ticket").build("claim-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (generalConfig.data.ticketSystem.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:unclaim-ticket").build("claim-message",{guild,channel,user,ticket}))
})
)
//TICKET UNCLAIMED
messages.add(new api.ODMessage("opendiscord:unclaim-message"))
messages.get("opendiscord:unclaim-message").workers.add(
- new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:unclaim-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:unclaim-message").build(source,{guild,channel,user,ticket,reason}))
- if (generalConfig.data.system.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:claim-ticket").build("unclaim-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (generalConfig.data.ticketSystem.enableTicketClaimButtons) instance.addComponent(await buttons.getSafe("opendiscord:claim-ticket").build("unclaim-message",{guild,channel,user,ticket}))
})
)
//TICKET PINNED
messages.add(new api.ODMessage("opendiscord:pin-message"))
messages.get("opendiscord:pin-message").workers.add(
- new api.ODWorker("opendiscord:pin-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:pin-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:pin-message").build(source,{guild,channel,user,ticket,reason}))
- if (generalConfig.data.system.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:unpin-ticket").build("pin-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (generalConfig.data.ticketSystem.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:unpin-ticket").build("pin-message",{guild,channel,user,ticket}))
})
)
//TICKET UNPINNED
messages.add(new api.ODMessage("opendiscord:unpin-message"))
messages.get("opendiscord:unpin-message").workers.add(
- new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:unpin-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:unpin-message").build(source,{guild,channel,user,ticket,reason}))
- if (generalConfig.data.system.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:pin-ticket").build("unpin-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (generalConfig.data.ticketSystem.enableTicketPinButtons) instance.addComponent(await buttons.getSafe("opendiscord:pin-ticket").build("unpin-message",{guild,channel,user,ticket}))
})
)
//TICKET RENAMED
messages.add(new api.ODMessage("opendiscord:rename-message"))
messages.get("opendiscord:rename-message").workers.add(
- new api.ODWorker("opendiscord:rename-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:rename-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason,data} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:rename-message").build(source,{guild,channel,user,ticket,reason,data}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:rename-message").build(origin,{guild,channel,user,ticket,reason,data}))
})
)
//TICKET MOVED
messages.add(new api.ODMessage("opendiscord:move-message"))
messages.get("opendiscord:move-message").workers.add(
- new api.ODWorker("opendiscord:move-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:move-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason,data} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:move-message").build(source,{guild,channel,user,ticket,reason,data}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:move-message").build(origin,{guild,channel,user,ticket,reason,data}))
})
)
//TICKET USER ADDED
messages.add(new api.ODMessage("opendiscord:add-message"))
messages.get("opendiscord:add-message").workers.add(
- new api.ODWorker("opendiscord:add-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:add-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason,data} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:add-message").build(source,{guild,channel,user,ticket,reason,data}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:add-message").build(origin,{guild,channel,user,ticket,reason,data}))
})
)
//TICKET USER REMOVED
messages.add(new api.ODMessage("opendiscord:remove-message"))
messages.get("opendiscord:remove-message").workers.add(
- new api.ODWorker("opendiscord:remove-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:remove-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason,data} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:remove-message").build(source,{guild,channel,user,ticket,reason,data}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:remove-message").build(origin,{guild,channel,user,ticket,reason,data}))
})
)
//TICKET ACTION DM
messages.add(new api.ODMessage("opendiscord:ticket-action-dm"))
messages.get("opendiscord:ticket-action-dm").workers.add(
- new api.ODWorker("opendiscord:ticket-action-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-action-dm",0,async (instance,params,origin) => {
const {guild,channel,user,mode,ticket,reason,additionalData} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:ticket-action-dm").build(source,{guild,channel,user,mode,ticket,reason,additionalData}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:ticket-action-dm").build(origin,{guild,channel,user,mode,ticket,reason,additionalData}))
})
)
//TICKET ACTION LOGS
messages.add(new api.ODMessage("opendiscord:ticket-action-logs"))
messages.get("opendiscord:ticket-action-logs").workers.add(
- new api.ODWorker("opendiscord:ticket-action-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:ticket-action-logs",0,async (instance,params,origin) => {
const {guild,channel,user,mode,ticket,reason,additionalData} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:ticket-action-logs").build(source,{guild,channel,user,mode,ticket,reason,additionalData}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:ticket-action-logs").build(origin,{guild,channel,user,mode,ticket,reason,additionalData}))
})
)
}
@@ -861,54 +582,54 @@ const blacklistMessages = () => {
//BLACKLIST VIEW
messages.add(new api.ODMessage("opendiscord:blacklist-view"))
messages.get("opendiscord:blacklist-view").workers.add(
- new api.ODWorker("opendiscord:blacklist-view",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-view",0,async (instance,params,origin) => {
const {guild,channel,user} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-view").build(source,{guild,channel,user}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-view").build(origin,{guild,channel,user}))
})
)
//BLACKLIST GET
messages.add(new api.ODMessage("opendiscord:blacklist-get"))
messages.get("opendiscord:blacklist-get").workers.add(
- new api.ODWorker("opendiscord:blacklist-get",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-get",0,async (instance,params,origin) => {
const {guild,channel,user,data} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-get").build(source,{guild,channel,user,data}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-get").build(origin,{guild,channel,user,data}))
})
)
//BLACKLIST ADD
messages.add(new api.ODMessage("opendiscord:blacklist-add"))
messages.get("opendiscord:blacklist-add").workers.add(
- new api.ODWorker("opendiscord:blacklist-add",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-add",0,async (instance,params,origin) => {
const {guild,channel,user,data,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-add").build(source,{guild,channel,user,data,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-add").build(origin,{guild,channel,user,data,reason}))
})
)
//BLACKLIST REMOVE
messages.add(new api.ODMessage("opendiscord:blacklist-remove"))
messages.get("opendiscord:blacklist-remove").workers.add(
- new api.ODWorker("opendiscord:blacklist-remove",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-remove",0,async (instance,params,origin) => {
const {guild,channel,user,data,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-remove").build(source,{guild,channel,user,data,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-remove").build(origin,{guild,channel,user,data,reason}))
})
)
//BLACKLIST DM
messages.add(new api.ODMessage("opendiscord:blacklist-dm"))
messages.get("opendiscord:blacklist-dm").workers.add(
- new api.ODWorker("opendiscord:blacklist-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-dm",0,async (instance,params,origin) => {
const {guild,channel,user,mode,data,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-dm").build(source,{guild,channel,user,mode,data,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-dm").build(origin,{guild,channel,user,mode,data,reason}))
})
)
//BLACKLIST LOGS
messages.add(new api.ODMessage("opendiscord:blacklist-logs"))
messages.get("opendiscord:blacklist-logs").workers.add(
- new api.ODWorker("opendiscord:blacklist-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:blacklist-logs",0,async (instance,params,origin) => {
const {guild,channel,user,mode,data,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-logs").build(source,{guild,channel,user,mode,data,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:blacklist-logs").build(origin,{guild,channel,user,mode,data,reason}))
})
)
}
@@ -917,40 +638,40 @@ const transcriptMessages = () => {
//TRANSCRIPT TEXT READY
messages.add(new api.ODMessage("opendiscord:transcript-text-ready"))
messages.get("opendiscord:transcript-text-ready").workers.add(
- new api.ODWorker("opendiscord:transcript-text-ready",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-text-ready",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,result} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:transcript-text-ready").build(source,{guild,channel,user,ticket,compiler,result}))
- instance.addFile(await files.getSafe("opendiscord:text-transcript").build(source,{guild,channel,user,ticket,compiler,result}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:transcript-text-ready").build(origin,{guild,channel,user,ticket,compiler,result}))
+ instance.addFile(await files.getSafe("opendiscord:text-transcript").build(origin,{guild,channel,user,ticket,compiler,result}))
})
)
//TRANSCRIPT HTML READY
messages.add(new api.ODMessage("opendiscord:transcript-html-ready"))
messages.get("opendiscord:transcript-html-ready").workers.add(
- new api.ODWorker("opendiscord:transcript-html-ready",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-html-ready",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,result} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:transcript-html-ready").build(source,{guild,channel,user,ticket,compiler,result}))
- instance.addComponent(await buttons.getSafe("opendiscord:transcript-html-visit").build(source,{guild,channel,user,ticket,compiler,result}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:transcript-html-ready").build(origin,{guild,channel,user,ticket,compiler,result}))
+ instance.addComponent(await buttons.getSafe("opendiscord:transcript-html-visit").build(origin,{guild,channel,user,ticket,compiler,result}))
})
)
//TRANSCRIPT HTML PROGRESS
messages.add(new api.ODMessage("opendiscord:transcript-html-progress"))
messages.get("opendiscord:transcript-html-progress").workers.add(
- new api.ODWorker("opendiscord:transcript-html-progress",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-html-progress",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,remaining} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:transcript-html-progress").build(source,{guild,channel,user,ticket,compiler,remaining}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:transcript-html-progress").build(origin,{guild,channel,user,ticket,compiler,remaining}))
})
)
//TRANSCRIPT ERROR
messages.add(new api.ODMessage("opendiscord:transcript-error"))
messages.get("opendiscord:transcript-error").workers.add(
- new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transcript-error",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,compiler,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:transcript-error").build(source,{guild,channel,user,ticket,compiler,reason}))
- instance.addComponent(await buttons.getSafe("opendiscord:transcript-error-retry").build(source,{guild,channel,user,ticket,compiler,reason}))
- instance.addComponent(await buttons.getSafe("opendiscord:transcript-error-continue").build(source,{guild,channel,user,ticket,compiler,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:transcript-error").build(origin,{guild,channel,user,ticket,compiler,reason}))
+ instance.addComponent(await buttons.getSafe("opendiscord:transcript-error-retry").build(origin,{guild,channel,user,ticket,compiler,reason}))
+ instance.addComponent(await buttons.getSafe("opendiscord:transcript-error-continue").build(origin,{guild,channel,user,ticket,compiler,reason}))
})
)
}
@@ -959,9 +680,9 @@ const roleMessages = () => {
//REACTION ROLE
messages.add(new api.ODMessage("opendiscord:reaction-role"))
messages.get("opendiscord:reaction-role").workers.add(
- new api.ODWorker("opendiscord:reaction-role",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reaction-role",0,async (instance,params,origin) => {
const {guild,user,role,result} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:reaction-role").build(source,{guild,user,role,result}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:reaction-role").build(origin,{guild,user,role,result}))
instance.setEphemeral(true)
})
)
@@ -969,18 +690,18 @@ const roleMessages = () => {
//REACTION ROLE DM
messages.add(new api.ODMessage("opendiscord:reaction-role-dm"))
messages.get("opendiscord:reaction-role-dm").workers.add(
- new api.ODWorker("opendiscord:reaction-role-dm",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reaction-role-dm",0,async (instance,params,origin) => {
const {guild,user,role,result} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:reaction-role-dm").build(source,{guild,user,role,result}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:reaction-role-dm").build(origin,{guild,user,role,result}))
})
)
//REACTION ROLE LOGS
messages.add(new api.ODMessage("opendiscord:reaction-role-logs"))
messages.get("opendiscord:reaction-role-logs").workers.add(
- new api.ODWorker("opendiscord:reaction-role-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:reaction-role-logs",0,async (instance,params,origin) => {
const {guild,user,role,result} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:reaction-role-logs").build(source,{guild,user,role,result}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:reaction-role-logs").build(origin,{guild,user,role,result}))
})
)
}
@@ -989,10 +710,10 @@ const clearMessages = () => {
//CLEAR VERIFY MESSAGE
messages.add(new api.ODMessage("opendiscord:clear-verify-message"))
messages.get("opendiscord:clear-verify-message").workers.add(
- new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,source) => {
- const {guild,channel,user,filter,list} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:clear-verify-message").build(source,{guild,channel,user,filter,list}))
- instance.addComponent(await buttons.getSafe("opendiscord:clear-continue").build(source,{guild,channel,user,filter,list}))
+ new api.ODWorker("opendiscord:clear-verify-message",0,async (instance,params,origin) => {
+ const {guild,channel,user,filter,list,inProgress} = params
+ instance.addEmbed(await embeds.getSafe("opendiscord:clear-verify-message").build(origin,{guild,channel,user,filter,list,inProgress}))
+ instance.addComponent(await buttons.getSafe("opendiscord:clear-continue").build(origin,{guild,channel,user,filter,list,inProgress}))
instance.setEphemeral(true)
})
)
@@ -1000,9 +721,9 @@ const clearMessages = () => {
//CLEAR MESSAGE
messages.add(new api.ODMessage("opendiscord:clear-message"))
messages.get("opendiscord:clear-message").workers.add(
- new api.ODWorker("opendiscord:clear-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:clear-message",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:clear-message").build(source,{guild,channel,user,filter,list}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:clear-message").build(origin,{guild,channel,user,filter,list}))
instance.setEphemeral(true)
})
)
@@ -1010,9 +731,9 @@ const clearMessages = () => {
//CLEAR LOGS
messages.add(new api.ODMessage("opendiscord:clear-logs"))
messages.get("opendiscord:clear-logs").workers.add(
- new api.ODWorker("opendiscord:clear-logs",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:clear-logs",0,async (instance,params,origin) => {
const {guild,channel,user,filter,list} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:clear-logs").build(source,{guild,channel,user,filter,list}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:clear-logs").build(origin,{guild,channel,user,filter,list}))
})
)
}
@@ -1021,56 +742,56 @@ const autoMessages = () => {
//AUTOCLOSE MESSAGE
messages.add(new api.ODMessage("opendiscord:autoclose-message"))
messages.get("opendiscord:autoclose-message").workers.add(
- new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autoclose-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-message").build(source,{guild,channel,user,ticket}))
- if (generalConfig.data.system.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("autoclose-message",{guild,channel,user,ticket}))
- if (generalConfig.data.system.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("autoclose-message",{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-message").build(origin,{guild,channel,user,ticket}))
+ if (generalConfig.data.ticketSystem.enableTicketCloseButtons) instance.addComponent(await buttons.getSafe("opendiscord:reopen-ticket").build("autoclose-message",{guild,channel,user,ticket}))
+ if (generalConfig.data.ticketSystem.enableTicketDeleteButtons) instance.addComponent(await buttons.getSafe("opendiscord:delete-ticket").build("autoclose-message",{guild,channel,user,ticket}))
})
)
//AUTODELETE MESSAGE
messages.add(new api.ODMessage("opendiscord:autodelete-message"))
messages.get("opendiscord:autodelete-message").workers.add(
- new api.ODWorker("opendiscord:autodelete-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autodelete-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:autodelete-message").build(source,{guild,channel,user,ticket}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:autodelete-message").build(origin,{guild,channel,user,ticket}))
})
)
//AUTOCLOSE ENABLE
messages.add(new api.ODMessage("opendiscord:autoclose-enable"))
messages.get("opendiscord:autoclose-enable").workers.add(
- new api.ODWorker("opendiscord:autoclose-enable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autoclose-enable",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason,time} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-enable").build(source,{guild,channel,user,ticket,reason,time}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-enable").build(origin,{guild,channel,user,ticket,reason,time}))
})
)
//AUTODELETE ENABLE
messages.add(new api.ODMessage("opendiscord:autodelete-enable"))
messages.get("opendiscord:autodelete-enable").workers.add(
- new api.ODWorker("opendiscord:autodelete-enable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autodelete-enable",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason,time} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:autodelete-enable").build(source,{guild,channel,user,ticket,reason,time}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:autodelete-enable").build(origin,{guild,channel,user,ticket,reason,time}))
})
)
//AUTOCLOSE DISABLE
messages.add(new api.ODMessage("opendiscord:autoclose-disable"))
messages.get("opendiscord:autoclose-disable").workers.add(
- new api.ODWorker("opendiscord:autoclose-disable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autoclose-disable",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-disable").build(source,{guild,channel,user,ticket,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:autoclose-disable").build(origin,{guild,channel,user,ticket,reason}))
})
)
//AUTODELETE DISABLE
messages.add(new api.ODMessage("opendiscord:autodelete-disable"))
messages.get("opendiscord:autodelete-disable").workers.add(
- new api.ODWorker("opendiscord:autodelete-disable",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:autodelete-disable",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:autodelete-disable").build(source,{guild,channel,user,ticket,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:autodelete-disable").build(origin,{guild,channel,user,ticket,reason}))
})
)
}
@@ -1079,36 +800,36 @@ const extraMessages = () => {
//TOPIC SET
messages.add(new api.ODMessage("opendiscord:topic-set"))
messages.get("opendiscord:topic-set").workers.add(
- new api.ODWorker("opendiscord:topic-set",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:topic-set",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,topic} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:topic-set").build(source,{guild,channel,user,ticket,topic}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:topic-set").build(origin,{guild,channel,user,ticket,topic}))
})
)
//PRIORITY SET
messages.add(new api.ODMessage("opendiscord:priority-set"))
messages.get("opendiscord:priority-set").workers.add(
- new api.ODWorker("opendiscord:priority-set",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:priority-set",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,priority,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:priority-set").build(source,{guild,channel,user,ticket,priority,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:priority-set").build(origin,{guild,channel,user,ticket,priority,reason}))
})
)
//PRIORITY GET
messages.add(new api.ODMessage("opendiscord:priority-get"))
messages.get("opendiscord:priority-get").workers.add(
- new api.ODWorker("opendiscord:priority-get",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:priority-get",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,priority} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:priority-get").build(source,{guild,channel,user,ticket,priority}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:priority-get").build(origin,{guild,channel,user,ticket,priority}))
})
)
//TRANSFER MESSAGE
messages.add(new api.ODMessage("opendiscord:transfer-message"))
messages.get("opendiscord:transfer-message").workers.add(
- new api.ODWorker("opendiscord:transfer-message",0,async (instance,params,source) => {
+ new api.ODWorker("opendiscord:transfer-message",0,async (instance,params,origin) => {
const {guild,channel,user,ticket,oldCreator,newCreator,reason} = params
- instance.addEmbed(await embeds.getSafe("opendiscord:transfer-message").build(source,{guild,channel,user,ticket,oldCreator,newCreator,reason}))
+ instance.addEmbed(await embeds.getSafe("opendiscord:transfer-message").build(origin,{guild,channel,user,ticket,oldCreator,newCreator,reason}))
})
)
}
\ No newline at end of file
diff --git a/src/builders/modals.ts b/src/builders/modals.ts
deleted file mode 100644
index df7d222..0000000
--- a/src/builders/modals.ts
+++ /dev/null
@@ -1,173 +0,0 @@
-///////////////////////////////////////
-//MODAL BUILDERS
-///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
-import * as discord from "discord.js"
-
-const modals = opendiscord.builders.modals
-const lang = opendiscord.languages
-
-export const registerAllModals = async () => {
- ticketModals()
-}
-const ticketModals = () => {
- //TICKET QUESTIONS
- modals.add(new api.ODModal("opendiscord:ticket-questions"))
- modals.get("opendiscord:ticket-questions").workers.add(
- new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,source) => {
- const {option} = params
-
- instance.setCustomId("od:ticket-questions_"+option.id.value+"_"+source)
- instance.setTitle(option.exists("opendiscord:name") ? option.get("opendiscord:name").value : option.id.value)
- const questionIds = option.get("opendiscord:questions").value
- questionIds.forEach((id) => {
- const question = opendiscord.questions.get(id)
- if (!question) return
- if (question instanceof api.ODShortQuestion) instance.addQuestion({
- customId:question.id.value,
- label:question.get("opendiscord:name").value,
- style:"short",
- required:question.get("opendiscord:required").value,
- placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
- minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
- maxLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : undefined
- })
- else if (question instanceof api.ODParagraphQuestion) instance.addQuestion({
- customId:question.id.value,
- label:question.get("opendiscord:name").value,
- style:"paragraph",
- required:question.get("opendiscord:required").value,
- placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
- minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
- maxLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : undefined
- })
- })
- })
- )
-
- //CLOSE TICKET REASON
- modals.add(new api.ODModal("opendiscord:close-ticket-reason"))
- modals.get("opendiscord:close-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:close-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.close"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.closePlaceholder")
- })
- })
- )
-
- //REOPEN TICKET REASON
- modals.add(new api.ODModal("opendiscord:reopen-ticket-reason"))
- modals.get("opendiscord:reopen-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:reopen-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.reopen"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.reopenPlaceholder")
- })
- })
- )
-
- //DELETE TICKET REASON
- modals.add(new api.ODModal("opendiscord:delete-ticket-reason"))
- modals.get("opendiscord:delete-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:delete-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.delete"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.deletePlaceholder")
- })
- })
- )
-
- //CLAIM TICKET REASON
- modals.add(new api.ODModal("opendiscord:claim-ticket-reason"))
- modals.get("opendiscord:claim-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:claim-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.claim"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.claimPlaceholder")
- })
- })
- )
-
- //UNCLAIM TICKET REASON
- modals.add(new api.ODModal("opendiscord:unclaim-ticket-reason"))
- modals.get("opendiscord:unclaim-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:unclaim-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.unclaim"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.unclaimPlaceholder")
- })
- })
- )
-
- //PIN TICKET REASON
- modals.add(new api.ODModal("opendiscord:pin-ticket-reason"))
- modals.get("opendiscord:pin-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:pin-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.pin"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.pinPlaceholder")
- })
- })
- )
-
- //UNPIN TICKET REASON
- modals.add(new api.ODModal("opendiscord:unpin-ticket-reason"))
- modals.get("opendiscord:unpin-ticket-reason").workers.add(
- new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,source) => {
- const {ticket} = params
-
- instance.setCustomId("od:unpin-ticket-reason_"+ticket.id.value+"_"+source)
- instance.setTitle(lang.getTranslation("actions.buttons.unpin"))
- instance.addQuestion({
- customId:"reason",
- label:lang.getTranslation("params.uppercase.reason"),
- style:"paragraph",
- required:true,
- placeholder:lang.getTranslation("actions.modal.unpinPlaceholder")
- })
- })
- )
-}
\ No newline at end of file
diff --git a/src/commands/add.ts b/src/commands/add.ts
index 43d4b89..dd1dec6 100644
--- a/src/commands/add.ts
+++ b/src/commands/add.ts
@@ -1,45 +1,32 @@
///////////////////////////////////////
//ADD COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//ADD COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:add",generalConfig.data.prefix,"add"))
opendiscord.responders.commands.get("opendiscord:add").workers.add([
- new api.ODWorker("opendiscord:add",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:add",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.add,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check if in guild/Server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"add")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+ //fetch data
const data = instance.options.getUser("user",true)
const reason = instance.options.getString("reason",false)
@@ -52,15 +39,15 @@ export const registerCommandResponders = async () => {
//start adding user to ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:add-ticket-user").run(source,{guild,channel,user,ticket,reason,sendMessage:false,data})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:add-message").build(source,{guild,channel,user,ticket,reason,data}))
+ await opendiscord.actions.get("opendiscord:add-ticket-user").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,data})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:add-message").build(origin,{guild,channel,user,ticket,reason,data}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'add' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/autoclose.ts b/src/commands/autoclose.ts
index bdf5a8b..ba66cf7 100644
--- a/src/commands/autoclose.ts
+++ b/src/commands/autoclose.ts
@@ -1,50 +1,33 @@
///////////////////////////////////////
//AUTOCLOSE COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//AUTOCLOSE COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:autoclose",generalConfig.data.prefix,/^autoclose/))
opendiscord.responders.commands.get("opendiscord:autoclose").workers.add([
- new api.ODWorker("opendiscord:autoclose",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:autoclose",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.autoclose,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"autoclose")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
-
- //return when already closed
- if (ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ const isTicketOpen = await openticketUtils.replyTicketMustBeOpen(instance,origin,ticket)
+ if (!isTicketOpen) return cancel()
//subcommands
const scope = instance.options.getSubCommand()
@@ -54,40 +37,27 @@ export const registerCommandResponders = async () => {
const reason = instance.options.getString("reason",false)
ticket.get("opendiscord:autoclose-enabled").value = false
ticket.get("opendiscord:autoclose-hours").value = 0
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-disable").build(source,{guild,channel,user,ticket,reason}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-disable").build(origin,{guild,channel,user,ticket,reason}))
}else if (scope == "enable"){
const time = instance.options.getNumber("time",true)
const reason = instance.options.getString("reason",false)
ticket.get("opendiscord:autoclose-enabled").value = true
ticket.get("opendiscord:autoclose-hours").value = time
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-enable").build(source,{guild,channel,user,ticket,reason,time}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-enable").build(origin,{guild,channel,user,ticket,reason,time}))
}
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on autoclose "+scope+"!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
const scope = instance.options.getSubCommand()
const reason = instance.options.getString("reason",false)
opendiscord.log(instance.user.displayName+" used the 'autoclose "+scope+"' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"reason",value:reason ?? "/"},
])
})
diff --git a/src/commands/autocomplete.ts b/src/commands/autocomplete.ts
index e7cac2a..2dbd7f2 100644
--- a/src/commands/autocomplete.ts
+++ b/src/commands/autocomplete.ts
@@ -1,13 +1,13 @@
///////////////////////////////////////
//AUTOCOMPLETE COMMAND UTILS
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities} from "../index.js"
import * as discord from "discord.js"
-export const registerAutocompleteResponders = async () => {
+export async function registerAutocompleteResponders(){
//PANEL ID AUTOCOMPLETE
opendiscord.responders.autocomplete.add(new api.ODAutocompleteResponder("opendiscord:panel-id","panel","id"))
- opendiscord.responders.autocomplete.get("opendiscord:panel-id").workers.add(new api.ODWorker("opendiscord:panel-id",0,async (instance,params,source,cancel) => {
+ opendiscord.responders.autocomplete.get("opendiscord:panel-id").workers.add(new api.ODWorker("opendiscord:panel-id",0,async (instance,params,origin,cancel) => {
//create panel choices
const panelChoices : {name:string, value:string}[] = []
opendiscord.configs.get("opendiscord:panels").data.forEach((panel) => {
@@ -19,7 +19,7 @@ export const registerAutocompleteResponders = async () => {
//OPTION ID AUTOCOMPLETE
opendiscord.responders.autocomplete.add(new api.ODAutocompleteResponder("opendiscord:option-id",/ticket|move/,"id"))
- opendiscord.responders.autocomplete.get("opendiscord:option-id").workers.add(new api.ODWorker("opendiscord:option-id",0,async (instance,params,source,cancel) => {
+ opendiscord.responders.autocomplete.get("opendiscord:option-id").workers.add(new api.ODWorker("opendiscord:option-id",0,async (instance,params,origin,cancel) => {
//create ticket choices
const ticketChoices : {name:string, value:string}[] = []
opendiscord.configs.get("opendiscord:options").data.forEach((option) => {
diff --git a/src/commands/autodelete.ts b/src/commands/autodelete.ts
index f912668..235c2cf 100644
--- a/src/commands/autodelete.ts
+++ b/src/commands/autodelete.ts
@@ -1,45 +1,30 @@
///////////////////////////////////////
//AUTODELETE COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//AUTODELETE COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:autodelete",generalConfig.data.prefix,/^autodelete/))
opendiscord.responders.commands.get("opendiscord:autodelete").workers.add([
- new api.ODWorker("opendiscord:autodelete",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:autodelete",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.autodelete,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"autodelete")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
//subcommands
const scope = instance.options.getSubCommand()
@@ -49,40 +34,27 @@ export const registerCommandResponders = async () => {
const reason = instance.options.getString("reason",false)
ticket.get("opendiscord:autodelete-enabled").value = false
ticket.get("opendiscord:autodelete-days").value = 0
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autodelete-disable").build(source,{guild,channel,user,ticket,reason}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autodelete-disable").build(origin,{guild,channel,user,ticket,reason}))
}else if (scope == "enable"){
const time = instance.options.getNumber("time",true)
const reason = instance.options.getString("reason",false)
ticket.get("opendiscord:autodelete-enabled").value = true
ticket.get("opendiscord:autodelete-days").value = time
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autodelete-enable").build(source,{guild,channel,user,ticket,reason,time}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:autodelete-enable").build(origin,{guild,channel,user,ticket,reason,time}))
}
- //update ticket message
- const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
- if (ticketMessage){
- try{
- ticketMessage.edit((await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket})).message)
- }catch(e){
- opendiscord.log("Unable to edit ticket message on autodelete "+scope+"!","error",[
- {key:"channel",value:"#"+channel.name},
- {key:"channelid",value:channel.id,hidden:true},
- {key:"messageid",value:ticketMessage.id},
- {key:"option",value:ticket.option.id.value}
- ])
- opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
- }
- }
+ //update ticket message (no await)
+ openticketUtils.updateTicketMessage(guild,channel,user,ticket)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
const scope = instance.options.getSubCommand()
const reason = instance.options.getString("reason",false)
opendiscord.log(instance.user.displayName+" used the 'autodelete "+scope+"' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"reason",value:reason ?? "/"},
])
})
diff --git a/src/commands/blacklist.ts b/src/commands/blacklist.ts
index 16e8548..10d0d18 100644
--- a/src/commands/blacklist.ts
+++ b/src/commands/blacklist.ts
@@ -1,29 +1,29 @@
///////////////////////////////////////
//BLACKLIST COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//BLACKLIST COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:blacklist",generalConfig.data.prefix,/^blacklist/))
opendiscord.responders.commands.get("opendiscord:blacklist").workers.add([
- new api.ODWorker("opendiscord:blacklist",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:blacklist",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
//check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.blacklist,"support",user,member,channel,guild)
+ const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.permissions.blacklist,"support",user,member,channel,guild)
if (!permsResult.hasPerms){
if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
+ else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild,channel,user,permissions:["support"]}))
return cancel()
}
//check is in guild/server
if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(origin,{channel:instance.channel,user:instance.user}))
return cancel()
}
@@ -31,11 +31,11 @@ export const registerCommandResponders = async () => {
const scope = instance.options.getSubCommand()
if (!scope || (scope != "add" && scope != "get" && scope != "remove" && scope != "view")) return
if (scope == "view"){
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-view").build(source,{guild,channel,user}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-view").build(origin,{guild,channel,user}))
}else if (scope == "get"){
const data = instance.options.getUser("user",true)
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-get").build(source,{guild,channel,user,data}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-get").build(origin,{guild,channel,user,data}))
}else if (scope == "add"){
const data = instance.options.getUser("user",true)
@@ -46,15 +46,15 @@ export const registerCommandResponders = async () => {
{key:"user",value:user.username},
{key:"userid",value:user.id,hidden:true},
{key:"channelid",value:channel.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"reason",value:reason ?? "/"}
])
//manage stats
- await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:users-blacklisted",1,"increase")
- await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:users-blacklisted",user.id,1,"increase")
+ await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:users-blacklisted",1,"increase")
+ await opendiscord.statistics.get("opendiscord:user").setStat("opendiscord:users-blacklisted",user.id,1,"increase")
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-add").build(source,{guild,channel,user,data,reason}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-add").build(origin,{guild,channel,user,data,reason}))
}else if (scope == "remove"){
const data = instance.options.getUser("user",true)
@@ -65,14 +65,14 @@ export const registerCommandResponders = async () => {
{key:"user",value:user.username},
{key:"userid",value:user.id,hidden:true},
{key:"channelid",value:channel.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"reason",value:reason ?? "/"}
])
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-remove").build(source,{guild,channel,user,data,reason}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-remove").build(origin,{guild,channel,user,data,reason}))
}
}),
- new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:discord-logs",1,async (instance,params,origin,cancel) => {
const {guild,channel,user} = instance
if (!guild) return
@@ -83,21 +83,21 @@ export const registerCommandResponders = async () => {
const reason = instance.options.getString("reason",false)
//to logs
- if (generalConfig.data.system.logs.enabled && generalConfig.data.system.messages.blacklisting.logs){
+ if (generalConfig.data.logs.enabled && generalConfig.data.logs.logMessages.blacklisting.logs){
const logChannel = opendiscord.posts.get("opendiscord:logs")
- if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-logs").build(source,{guild,channel,user,mode:scope,data,reason}))
+ if (logChannel) logChannel.send(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-logs").build(origin,{guild,channel,user,mode:scope,data,reason}))
}
//to dm
- if (generalConfig.data.system.messages.blacklisting.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:blacklist-dm").build(source,{guild,channel,user,mode:scope,data,reason}))
+ if (generalConfig.data.logs.logMessages.blacklisting.dm) await opendiscord.client.sendUserDm(user,await opendiscord.builders.messages.getSafe("opendiscord:blacklist-dm").build(origin,{guild,channel,user,mode:scope,data,reason}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
const scope = instance.options.getSubCommand()
opendiscord.log(instance.user.displayName+" used the 'blacklist "+scope+"' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/claim.ts b/src/commands/claim.ts
index 72c2b6c..a2eb3a9 100644
--- a/src/commands/claim.ts
+++ b/src/commands/claim.ts
@@ -1,119 +1,235 @@
///////////////////////////////////////
//CLAIM COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//CLAIM COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:claim",generalConfig.data.prefix,"claim"))
opendiscord.responders.commands.get("opendiscord:claim").workers.add([
- new api.ODWorker("opendiscord:claim",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:claim",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.claim,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when already claimed
- if (ticket.get("opendiscord:claimed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const claimUser = instance.options.getUser("user",false) ?? user
- const reason = instance.options.getString("reason",false)
-
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"claim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnclaimed = await openticketUtils.replyTicketMustBeUnclaimed(instance,origin,ticket)
+ if (!isTicketUnclaimed) return cancel()
+
//start claiming ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:claim-ticket").run(source,{guild,channel,user:claimUser,ticket,reason,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(source,{guild,channel,user:claimUser,ticket,reason}))
+ const reason = instance.options.getString("reason",false)
+ const claimUser = instance.options.getUser("user",false) ?? user
+ await opendiscord.actions.get("opendiscord:claim-ticket").run(origin,{guild,channel,user:claimUser,ticket,reason,sendMessage:false})
+
+ //send message & set state
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(origin,{guild,channel,user:claimUser,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"claim-message",
+ messageOrigin:origin,
+ messageAuthor:claimUser.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'claim' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//CLAIM TICKET BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:claim-ticket",/^od:claim-ticket/))
opendiscord.responders.buttons.get("opendiscord:claim-ticket").workers.add(
- new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"claim")
+ if (!hasPerms) return cancel()
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:claim-ticket-ticket-message").activate(instance)
- else if (originalSource == "unclaim-message") await opendiscord.verifybars.get("opendiscord:claim-ticket-unclaim-message").activate(instance)
- else await instance.defer("update",false)
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/claim")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnclaimed = await openticketUtils.replyTicketMustBeUnclaimed(instance,origin,ticket)
+ if (!isTicketUnclaimed) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:claim-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:claim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "unclaim-message"){
+ //unclaim message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:claim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:unclaim-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
})
)
}
-export const registerModalResponders = async () => {
- //CLAIM WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:claim-ticket-reason",/^od:claim-ticket-reason_/))
- opendiscord.responders.modals.get("opendiscord:claim-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
-
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
- const reason = instance.values.getTextField("reason",true)
-
- //claim with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:claim-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "unclaim-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:claim-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:claim-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- }
+export async function registerVerifyBars(){
+ //CLAIM TICKET
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:claim-ticket"))
+ opendiscord.verifybars.get("opendiscord:claim-ticket").workers.add([
+ new api.ODWorker("opendiscord:claim-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"claim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/claim")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnclaimed = await openticketUtils.replyTicketMustBeUnclaimed(instance,origin,ticket)
+ if (!isTicketUnclaimed) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start claiming ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "unclaim-message"){
+ //unclaim message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
+ }else if (params.selectedButtonId == "accept"){
+ //CLAIM TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "unclaim-message"){
+ //converted to claim message
+ await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"claim-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //CLAIM WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:claim-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
+ //CLAIM WITH REASON MODAL RESPONDER
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:claim-ticket-reason",/^od:claim-ticket-reason\|([^|]+)\|([^|]+)/))
+ opendiscord.responders.modals.get("opendiscord:claim-ticket-reason").workers.add([
+ new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
+
+ const match = /^od:claim-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"claim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/claim")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnclaimed = await openticketUtils.replyTicketMustBeUnclaimed(instance,origin,ticket)
+ if (!isTicketUnclaimed) return cancel()
+
+ //fetch state details
+ const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
+
+ //start claiming ticket
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
+
+ }else if (originalMsgType == "unclaim-message"){
+ //converted to claim message
+ await opendiscord.actions.get("opendiscord:claim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"claim-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
+ }
})
])
}
\ No newline at end of file
diff --git a/src/commands/clear.ts b/src/commands/clear.ts
index 1de6e25..06093d9 100644
--- a/src/commands/clear.ts
+++ b/src/commands/clear.ts
@@ -1,35 +1,31 @@
///////////////////////////////////////
//CLEAR COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const clearMsgState = opendiscord.states.get("opendiscord:clear-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//CLEAR COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:clear",generalConfig.data.prefix,"clear"))
opendiscord.responders.commands.get("opendiscord:clear").workers.add([
- new api.ODWorker("opendiscord:clear",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:clear",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
-
+
+ //responder checks
//check permissions (only allow global admins: ticket admins aren't allowed to clear tickets)
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.clear,"support",user,member,channel,guild,{allowChannelUserScope:false,allowChannelRoleScope:false})
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"clear",{allowChannelUserScope:false,allowChannelRoleScope:false})
+ if (!hasPerms) return cancel()
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ //fetch data
const tempFilter = instance.options.getString("filter",false)
const filter = (tempFilter) ? tempFilter.toLowerCase() as api.ODTicketClearFilter : "all"
- const list: string[] = []
+ const channelNameList: string[] = []
const ticketList = opendiscord.tickets.getAll().filter((ticket) => {
if (filter == "all") return true
else if (filter == "open" && ticket.get("opendiscord:open").value) return true
@@ -43,46 +39,70 @@ export const registerCommandResponders = async () => {
})
for (const ticket of ticketList){
const ticketChannel = await opendiscord.tickets.getTicketChannel(ticket)
- if (ticketChannel) list.push("#"+ticketChannel.name)
+ if (ticketChannel) channelNameList.push("#"+ticketChannel.name)
}
//reply with clear verify
await instance.defer(true)
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:clear-verify-message").build(source,{guild,channel,user,filter,list}))
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:clear-verify-message").build(origin,{guild,channel,user,filter,list:channelNameList,inProgress:false}))
+ if (sentMsg.success) await clearMsgState.setMsgState({channel,message:sentMsg.message,user},{
+ messageOrigin:origin,
+ clearFilter:filter,
+ clearChannelNameList:channelNameList
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'clear' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//CLEAR CONTINUE BUTTON RESPONDER
- opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:clear-continue",/^od:clear-continue_/))
+ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:clear-continue","od:clear-continue"))
opendiscord.responders.buttons.get("opendiscord:clear-continue").workers.add(
- new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild || channel.isDMBased()) return
- const originalSource = instance.interaction.customId.split("_")[1] as api.ODActionManagerIds_Default["opendiscord:clear-tickets"]["source"]
- const filter = instance.interaction.customId.split("_")[2] as api.ODTicketClearFilter
+ new api.ODWorker("opendiscord:clear-continue",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //check message state
+ const state = await clearMsgState.getMsgState({channel,message,user})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This interaction is no longer valid or has expired. Use the command `{0}` instead. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/clear"),layout:"simple",customTitle:"Message State Expired"}))
+ return cancel()
+ }
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"clear")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.userId) ? await opendiscord.client.fetchUser(state.userId) : user) ?? user
+ const originalOrigin = state.data.messageOrigin
+ const originalClearFilter = state.data.clearFilter
+ const originalClearChannelNameList = state.data.clearChannelNameList
//start ticket clear
- await instance.defer("update",true)
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:clear-verify-message").build(originalOrigin,{guild,channel,user:originalUser,filter:originalClearFilter,list:originalClearChannelNameList,inProgress:true}))
+
const list: string[] = []
const ticketList = opendiscord.tickets.getAll().filter((ticket) => {
- if (filter == "all") return true
- else if (filter == "open" && ticket.get("opendiscord:open").value) return true
- else if (filter == "closed" && ticket.get("opendiscord:closed").value) return true
- else if (filter == "claimed" && ticket.get("opendiscord:claimed").value) return true
- else if (filter == "pinned" && ticket.get("opendiscord:pinned").value) return true
- else if (filter == "unclaimed" && !ticket.get("opendiscord:claimed").value) return true
- else if (filter == "unpinned" && !ticket.get("opendiscord:pinned").value) return true
- else if (filter == "autoclosed" && ticket.get("opendiscord:closed").value) return true
+ if (originalClearFilter == "all") return true
+ else if (originalClearFilter == "open" && ticket.get("opendiscord:open").value) return true
+ else if (originalClearFilter == "closed" && ticket.get("opendiscord:closed").value) return true
+ else if (originalClearFilter == "claimed" && ticket.get("opendiscord:claimed").value) return true
+ else if (originalClearFilter == "pinned" && ticket.get("opendiscord:pinned").value) return true
+ else if (originalClearFilter == "unclaimed" && !ticket.get("opendiscord:claimed").value) return true
+ else if (originalClearFilter == "unpinned" && !ticket.get("opendiscord:pinned").value) return true
+ else if (originalClearFilter == "autoclosed" && ticket.get("opendiscord:closed").value) return true
else return false
})
for (const ticket of ticketList){
@@ -90,8 +110,8 @@ export const registerButtonResponders = async () => {
if (ticketChannel) list.push("#"+ticketChannel.name)
}
- await opendiscord.actions.get("opendiscord:clear-tickets").run(originalSource,{guild,channel,user,filter,list:ticketList})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:clear-message").build(originalSource,{guild,channel,user,filter,list}))
+ await opendiscord.actions.get("opendiscord:clear-tickets").run(originalOrigin,{guild,channel,user,filter:originalClearFilter,list:ticketList})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:clear-message").build(originalOrigin,{guild,channel,user,filter:originalClearFilter,list}))
})
)
}
\ No newline at end of file
diff --git a/src/commands/close.ts b/src/commands/close.ts
index 8f2c01b..ce0526d 100644
--- a/src/commands/close.ts
+++ b/src/commands/close.ts
@@ -1,131 +1,243 @@
///////////////////////////////////////
//CLOSE COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//CLOSE COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:close",generalConfig.data.prefix,"close"))
opendiscord.responders.commands.get("opendiscord:close").workers.add([
- new api.ODWorker("opendiscord:close",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:close",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when already closed
- if (ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"close")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketOpen = await openticketUtils.replyTicketMustBeOpen(instance,origin,ticket)
+ if (!isTicketOpen) return cancel()
+
+ const messagesHaveBeenSent = await openticketUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"close")
+ if (!messagesHaveBeenSent) return cancel()
//start closing ticket
await instance.defer(false)
const reason = instance.options.getString("reason",false)
- await opendiscord.actions.get("opendiscord:close-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(source,{guild,channel,user,ticket,reason}))
+ await opendiscord.actions.get("opendiscord:close-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false})
+
+ //send message & set state
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"close-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'close' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//CLOSE TICKET BUTTON RESPONDER
- opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:close-ticket",/^od:close-ticket_/))
+ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:close-ticket",/^od:close-ticket/))
opendiscord.responders.buttons.get("opendiscord:close-ticket").workers.add(
- new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,message,user,member} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"close")
+ if (!hasPerms) return cancel()
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:close-ticket-ticket-message").activate(instance)
- else if (originalSource == "reopen-message") await opendiscord.verifybars.get("opendiscord:close-ticket-reopen-message").activate(instance)
- else await instance.defer("update",false)
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/close")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketOpen = await openticketUtils.replyTicketMustBeOpen(instance,origin,ticket)
+ if (!isTicketOpen) return cancel()
+
+ const messagesHaveBeenSent = await openticketUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"close")
+ if (!messagesHaveBeenSent) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:close-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:close-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "reopen-message"){
+ //reopen message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:close-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:reopen-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
})
)
}
-export const registerModalResponders = async () => {
- //CLOSE WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:close-ticket-reason",/^od:close-ticket-reason_/))
- opendiscord.responders.modals.get("opendiscord:close-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
+export async function registerVerifyBars(){
+ //CLOSE TICKET VERIFYBAR
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:close-ticket"))
+ opendiscord.verifybars.get("opendiscord:close-ticket").workers.add([
+ new api.ODWorker("opendiscord:close-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
- const reason = instance.values.getTextField("reason",true)
-
- //close with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:close-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "reopen-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:close-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:close-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"close")
+ if (!hasPerms) return cancel()
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/close")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketOpen = await openticketUtils.replyTicketMustBeOpen(instance,origin,ticket)
+ if (!isTicketOpen) return cancel()
+
+ const messagesHaveBeenSent = await openticketUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"close")
+ if (!messagesHaveBeenSent) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start closing ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "reopen-message"){
+ //reopen message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
+ }else if (params.selectedButtonId == "accept"){
+ //CLOSE TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "reopen-message"){
+ //converted to close message
+ await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"close-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //CLOSE WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:close-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
+ //CLOSE WITH REASON MODAL RESPONDER
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:close-ticket-reason",/^od:close-ticket-reason\|([^|]+)\|([^|]+)/))
+ opendiscord.responders.modals.get("opendiscord:close-ticket-reason").workers.add([
+ new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
+
+ const match = /^od:close-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"close")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/close")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketOpen = await openticketUtils.replyTicketMustBeOpen(instance,origin,ticket)
+ if (!isTicketOpen) return cancel()
+
+ //fetch state details
+ const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
+
+ //start closing ticket
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
+
+ }else if (originalMsgType == "reopen-message"){
+ //converted to close message
+ await opendiscord.actions.get("opendiscord:close-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"close-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
+ }
})
])
}
\ No newline at end of file
diff --git a/src/commands/delete.ts b/src/commands/delete.ts
index ebe4c32..400fdf3 100644
--- a/src/commands/delete.ts
+++ b/src/commands/delete.ts
@@ -1,64 +1,42 @@
///////////////////////////////////////
//DELETE COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//DELETE COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:delete",generalConfig.data.prefix,"delete"))
opendiscord.responders.commands.get("opendiscord:delete").workers.add([
- new api.ODWorker("opendiscord:delete",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:delete",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
+ if (!hasPerms) return cancel()
- //return when not allowed because of missing messages
- if (!permsResult.isAdmin && (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage)){
- const analysis = await opendiscord.transcripts.collector.ticketUserMessagesAnalysis(ticket,guild,channel)
- if (analysis && !generalConfig.data.system.allowCloseBeforeMessage && analysis.totalMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- if (analysis && !generalConfig.data.system.allowCloseBeforeAdminMessage && analysis.adminMessages < 1){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,layout:"simple",error:lang.getTranslation("errors.descriptions.closeBeforeAdminMessage"),customTitle:lang.getTranslation("errors.titles.noPermissions")}))
- return cancel()
- }
- }
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketOpen = await openticketUtils.replyTicketMustBeOpen(instance,origin,ticket)
+ if (!isTicketOpen) return cancel()
- const reason = instance.options.getString("reason",false)
- const withoutTranscript = instance.options.getBoolean("notranscript",false) ?? false
+ const messagesHaveBeenSent = await openticketUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"delete")
+ if (!messagesHaveBeenSent) return cancel()
//don't allow deleteWithoutTranscript to non-global-admins when enabled
- if (withoutTranscript && generalConfig.data.system.adminOnlyDeleteWithoutTranscript){
+ const withoutTranscript = instance.options.getBoolean("notranscript",false) ?? false
+ if (withoutTranscript && generalConfig.data.ticketSystem.adminOnlyDeleteWithoutTranscript){
if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
return cancel()
@@ -67,84 +45,227 @@ export const registerCommandResponders = async () => {
//start deleting ticket
await instance.defer(false)
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(source,{guild,channel,user,ticket,reason}))
- await opendiscord.actions.get("opendiscord:delete-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript})
+ const reason = instance.options.getString("reason",false)
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(origin,{guild,channel,user,ticket,reason}))
+ await opendiscord.actions.get("opendiscord:delete-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript})
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'delete' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//DELETE TICKET BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:delete-ticket",/^od:delete-ticket/))
opendiscord.responders.buttons.get("opendiscord:delete-ticket").workers.add(
- new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,message,user,member} = instance
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-ticket-message").activate(instance)
- else if (originalSource == "close-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-close-message").activate(instance)
- else if (originalSource == "reopen-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-reopen-message").activate(instance)
- else if (originalSource == "autoclose-message") await opendiscord.verifybars.get("opendiscord:delete-ticket-autoclose-message").activate(instance)
- else await instance.defer("update",false)
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/delete")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const messagesHaveBeenSent = await openticketUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"delete")
+ if (!messagesHaveBeenSent) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:delete-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "close-message"){
+ //close message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:close-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }else if (originalMsgType == "reopen-message"){
+ //reopen message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:reopen-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }else if (originalMsgType == "autoclose-message"){
+ //autoclose message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:delete-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:autoclose-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket}))
+ }
})
)
}
-export const registerModalResponders = async () => {
- //REOPEN WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:delete-ticket-reason",/^od:delete-ticket-reason_/))
+export async function registerVerifyBars(){
+ //DELETE TICKET
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:delete-ticket"))
+ opendiscord.verifybars.get("opendiscord:delete-ticket").workers.add([
+ new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/delete")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const messagesHaveBeenSent = await openticketUtils.replyMessageMustBeSentBeforeClose(instance,origin,ticket,"delete")
+ if (!messagesHaveBeenSent) return cancel()
+
+ //don't allow deleteWithoutTranscript to non-global-admins when enabled
+ const withoutTranscript = (params.selectedButtonId == "accept-without-transcript")
+ if (withoutTranscript && generalConfig.data.ticketSystem.adminOnlyDeleteWithoutTranscript){
+ if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelRoleScope:false,allowChannelUserScope:false,allowGlobalRoleScope:true,allowGlobalUserScope:true}))){
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
+ return cancel()
+ }
+ }
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start deleting ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "close-message"){
+ //close message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }else if (originalMsgType == "reopen-message"){
+ //reopen message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }else if (originalMsgType == "autoclose-message"){
+ //autoclose message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("verifybar",{guild,channel,user:originalUser,ticket}))
+ }
+ }else if (params.selectedButtonId == "accept" || params.selectedButtonId == "accept-without-transcript"){
+ //DELETE TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true,withoutTranscript})
+ ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
+
+ }else if (originalMsgType == "close-message"){
+ //converted to delete message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason:null}))
+
+ }else if (originalMsgType == "reopen-message"){
+ //converted to delete message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason:null}))
+
+ }else if (originalMsgType == "autoclose-message"){
+ //converted to delete message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false,withoutTranscript})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason:null}))
+
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //DELETE WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:delete-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
+ //DELETE WITH REASON MODAL RESPONDER
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:delete-ticket-reason",/^od:delete-ticket-reason\|([^|]+)\|([^|]+)/))
opendiscord.responders.modals.get("opendiscord:delete-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
+ new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
+ const match = /^od:delete-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/delete")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ //fetch state details
const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
- //delete with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true,withoutTranscript:false})
- //update ticket (for ticket message) => no-await doesn't wait for the action to set this variable
- ticket.get("opendiscord:for-deletion").value = true
+ //start deleting ticket
+ //don't await DELETE action => else it will update the message after the channel has been deleted
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:true,withoutTranscript:false})
+ ticket.get("opendiscord:for-deletion").value = true //disable ticket message buttons
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "close-message"){
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason}))
- }else if (originalSource == "reopen-message"){
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason}))
- }else if (originalSource == "autoclose-message"){
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- //don't await DELETE action => else it will update the message after the channel has been deleted
- opendiscord.actions.get("opendiscord:delete-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true,withoutTranscript:false})
+
+ }else if (originalMsgType == "close-message"){
+ //converted to delete message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+
+ }else if (originalMsgType == "reopen-message"){
+ //converted to delete message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+
+ }else if (originalMsgType == "autoclose-message"){
+ //converted to delete message
+ opendiscord.actions.get("opendiscord:delete-ticket").run(originalMsgType,{guild,channel,user,ticket,reason,sendMessage:false,withoutTranscript:false})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+
}
})
])
diff --git a/src/commands/help.ts b/src/commands/help.ts
index a8eb799..1ad49a2 100644
--- a/src/commands/help.ts
+++ b/src/commands/help.ts
@@ -1,50 +1,46 @@
///////////////////////////////////////
//HELP COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//HELP COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:help",generalConfig.data.prefix,"help"))
opendiscord.responders.commands.get("opendiscord:help").workers.add([
- new api.ODWorker("opendiscord:help",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:help",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.help,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"help")
+ if (!hasPerms) return cancel()
//calculate slash/text mode for help menu
let mode: "slash"|"text"
- if (generalConfig.data.slashCommands && generalConfig.data.textCommands) mode = (generalConfig.data.system.preferSlashOverText) ? "slash" : "text"
+ if (generalConfig.data.slashCommands && generalConfig.data.textCommands) mode = (generalConfig.data.ticketSystem.preferSlashOverText) ? "slash" : "text"
else if (!generalConfig.data.slashCommands) mode = "text"
else mode = "slash"
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:help-menu").build(source,{mode,page:0}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:help-menu").build(origin,{mode,page:0}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'help' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//HELP MENU SWITCH BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:help-menu-switch",/^od:help-menu-switch_(slash|text)/))
opendiscord.responders.buttons.get("opendiscord:help-menu-switch").workers.add(
- new api.ODWorker("opendiscord:update-help-menu",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:update-help-menu",0,async (instance,params,origin,cancel) => {
const mode = instance.interaction.customId.split("_")[1] as "slash"|"text"
const pageButton = instance.getMessageComponent("button",/^od:help-menu-page_([0-9]+)/)
const currentPage = (pageButton && pageButton.customId) ? Number(pageButton.customId.split("_")[1]) : 0
@@ -59,7 +55,7 @@ export const registerButtonResponders = async () => {
//HELP MENU PREVIOUS BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:help-menu-previous",/^od:help-menu-previous/))
opendiscord.responders.buttons.get("opendiscord:help-menu-previous").workers.add(
- new api.ODWorker("opendiscord:update-help-menu",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:update-help-menu",0,async (instance,params,origin,cancel) => {
const switchButton = instance.getMessageComponent("button",/^od:help-menu-switch_(slash|text)/)
const pageButton = instance.getMessageComponent("button",/^od:help-menu-page_([0-9]+)/)
const currentPage = (pageButton && pageButton.customId) ? Number(pageButton.customId.split("_")[1]) : 0
@@ -73,7 +69,7 @@ export const registerButtonResponders = async () => {
//HELP MENU NEXT BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:help-menu-next",/^od:help-menu-next/))
opendiscord.responders.buttons.get("opendiscord:help-menu-next").workers.add(
- new api.ODWorker("opendiscord:update-help-menu",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:update-help-menu",0,async (instance,params,origin,cancel) => {
const switchButton = instance.getMessageComponent("button",/^od:help-menu-switch_(slash|text)/)
const pageButton = instance.getMessageComponent("button",/^od:help-menu-page_([0-9]+)/)
const currentPage = (pageButton && pageButton.customId) ? Number(pageButton.customId.split("_")[1]) : 0
diff --git a/src/commands/move.ts b/src/commands/move.ts
index 93ad8ed..3ec418f 100644
--- a/src/commands/move.ts
+++ b/src/commands/move.ts
@@ -1,48 +1,36 @@
///////////////////////////////////////
//MOVE COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//MOVE COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:move",generalConfig.data.prefix,"move"))
opendiscord.responders.commands.get("opendiscord:move").workers.add([
- new api.ODWorker("opendiscord:move",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:move",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.move,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check if in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"move")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+ //fetch data
const id = instance.options.getString("id",true)
const reason = instance.options.getString("reason",false)
-
const option = opendiscord.options.get(id)
+
//return if unknown option
if (!option || !(option instanceof api.ODTicketOption)){
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.titles.unknownOption"),layout:"simple"}))
@@ -56,15 +44,15 @@ export const registerCommandResponders = async () => {
//start moving ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:move-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false,data:option})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:move-message").build(source,{guild,channel,user,ticket,reason,data:option}))
+ await opendiscord.actions.get("opendiscord:move-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,data:option})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:move-message").build(origin,{guild,channel,user,ticket,reason,data:option}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'move' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/panel.ts b/src/commands/panel.ts
index cb84407..434b62b 100644
--- a/src/commands/panel.ts
+++ b/src/commands/panel.ts
@@ -1,59 +1,300 @@
///////////////////////////////////////
//STATS COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const panelMsgState = opendiscord.states.get("opendiscord:panel-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//PANEL COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:panel",generalConfig.data.prefix,/^panel/))
opendiscord.responders.commands.get("opendiscord:panel").workers.add([
- new api.ODWorker("opendiscord:panel",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:panel",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.panel,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild || instance.channel.type == discord.ChannelType.GroupDM){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
- return cancel()
- }
- //get panel data
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"panel")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ //fetch data
const id = instance.options.getString("id",true)
const panel = opendiscord.panels.get(id)
if (!panel){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-panel-unknown").build(source,{guild,channel,user}))
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-panel-unknown").build(origin,{guild,channel,user}))
return cancel()
}
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:panel-ready").build(source,{guild,channel,user,panel}))
- const panelMessage = await instance.channel.send((await opendiscord.builders.messages.getSafe("opendiscord:panel").build(source,{guild,channel,user,panel})).message)
-
- //add panel to database (this way, the bot knows where all panels are located)
- const globalDatabase = opendiscord.databases.get("opendiscord:global")
- await globalDatabase.set("opendiscord:panel-message",panelMessage.channel.id+"_"+panelMessage.id,panel.id.value)
-
- //add panel to database for auto-update
- if (instance.options.getBoolean("auto-update",false)){
- await globalDatabase.set("opendiscord:panel-update",panelMessage.channel.id+"_"+panelMessage.id,panel.id.value)
- }
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:panel-ready").build(origin,{guild,channel,user,panel}))
+ const panelMessage = await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:panel").build(origin,{guild,channel,user,panel,isSubPanel:false})).message)
+ if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
+ messageOrigin:origin,
+ panelId:panel.id.value,
+ panelOptionIds:panel.get("opendiscord:options").value,
+ panelAutoUpdate:(instance.options.getBoolean("auto-update",false) ?? false),
+ isSubPanel:false
+ },panelMessage.flags.has("Ephemeral"))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'panel' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
+}
+
+export async function registerButtonResponders(){
+ //SUBPANEL OPTION BUTTON RESPONDER
+ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:subpanel-option",/^od:subpanel-option\|([^|]+)/))
+ opendiscord.responders.buttons.get("opendiscord:subpanel-option").workers.add(
+ new api.ODWorker("opendiscord:subpanel-option",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ const match = /^od:subpanel-option\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const optionId = match[1]
+
+ //check message state
+ const state = await panelMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
+ return cancel()
+ }
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ //get option data
+ const option = opendiscord.options.get(optionId)
+ if (!option || !(option instanceof api.ODSubPanelOption)){
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ return cancel()
+ }
+
+ //get panel data
+ const subPanel = opendiscord.panels.get(option.get("opendiscord:panel-id").value)
+ if (!subPanel){
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-panel-unknown").build(origin,{guild,channel,user}))
+ return cancel()
+ }
+
+ //send sub-panel message (ephemeral)
+ const panelMessage = await instance.reply((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("sub-panel",{guild,channel,user,panel:subPanel,isSubPanel:true})))
+ if (panelMessage.success) await panelMsgState.setMsgState({channel,message:panelMessage.message},{
+ messageOrigin:"sub-panel",
+ panelId:subPanel.id.value,
+ panelOptionIds:subPanel.get("opendiscord:options").value,
+ panelAutoUpdate:false,
+ isSubPanel:true
+ },panelMessage.ephemeral)
+
+ opendiscord.log(instance.user.displayName+" created a sub-panel!","info",[
+ {key:"user",value:instance.user.username},
+ {key:"userid",value:instance.user.id,hidden:true},
+ {key:"channelid",value:instance.channel.id,hidden:true},
+ {key:"method",value:origin}
+ ])
+ })
+ )
+}
+
+export async function registerDropdownResponders(){
+ opendiscord.responders.dropdowns.add(new api.ODDropdownResponder("opendiscord:panel-dropdown",/^od:panel-dropdown/))
+
+ //TICKET DROPDOWN RESPONDER
+ opendiscord.responders.dropdowns.get("opendiscord:panel-dropdown").workers.add(
+ new api.ODWorker("opendiscord:dropdown-ticket",2,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //RETURN WHEN NOT OF TYPE TICKET (role or sub-panel responders might catch it)
+ const match = /^od:ticket-option\|([^|]+)/.exec(instance.values.getStringValues()[0])
+ if (!match) return
+ const optionId = match[1]
+
+ //check message state
+ const state = await panelMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
+ return cancel()
+ }
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ //get option data
+
+ const option = opendiscord.options.get(optionId)
+ if (!option || !(option instanceof api.ODTicketOption)){
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ return cancel()
+ }
+
+ //start ticket creation
+ if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
+ //SEND MODAL
+ instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option}))
+ }else{
+ //check ticket permissions (modals need check after submit)
+ if (!(await openticketUtils.checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option))) return cancel()
+
+ //CREATE TICKET
+ await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true)
+
+ const res = await opendiscord.actions.get("opendiscord:create-ticket").run("panel-dropdown",{guild,user,answers:[],option})
+ if (!res.channel || !res.ticket){
+ //error
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"}))
+ return cancel()
+ }
+ if (generalConfig.data.ticketSystem.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-dropdown",{guild,channel:res.channel,user,ticket:res.ticket}))
+ }
+
+ //update panel after dropdown usage (reset panel choice)
+ const panel = opendiscord.panels.get(state.data.panelId)
+ if (panel){
+ const panelMessage = await instance.message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild,channel,user,panel,isSubPanel:state.data.isSubPanel})).message)
+ if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
+ messageOrigin:"auto-update",
+ panelId:panel.id.value,
+ panelOptionIds:panel.get("opendiscord:options").value,
+ panelAutoUpdate:state.data.panelAutoUpdate, //same value
+ isSubPanel:state.data.isSubPanel //same value
+ },panelMessage.flags.has("Ephemeral"))
+ }
+ })
+ )
+
+ //ROLE DROPDOWN RESPONDER
+ opendiscord.responders.dropdowns.get("opendiscord:panel-dropdown").workers.add(
+ new api.ODWorker("opendiscord:dropdown-role",1,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //RETURN WHEN NOT OF TYPE ROLE (ticket or sub-panel responders might catch it)
+ const match = /^od:role-option\|([^|]+)/.exec(instance.values.getStringValues()[0])
+ if (!match) return
+ const optionId = match[1]
+
+ //check message state
+ const state = await panelMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
+ return cancel()
+ }
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ //get option data
+ const option = opendiscord.options.get(optionId)
+ if (!option || !(option instanceof api.ODRoleOption)){
+ //error
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ return cancel()
+ }
+
+ //reaction role
+ await instance.defer(generalConfig.data.ticketSystem.replyOnReactionRole ? "reply" : "update",true)
+ const res = await opendiscord.actions.get("opendiscord:reaction-role").run("panel-button",{guild,user,option,overwriteMode:null})
+ if (!res.result || !res.role){
+ //error
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive role update data from worker!",layout:"advanced"}))
+ return cancel()
+ }
+ if (generalConfig.data.ticketSystem.replyOnReactionRole) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role").build("panel-button",{guild,user,role:res.role,result:res.result}))
+
+ //update panel after dropdown usage (reset panel choice)
+ const panel = opendiscord.panels.get(state.data.panelId)
+ if (panel){
+ const panelMessage = await instance.message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild,channel,user,panel,isSubPanel:state.data.isSubPanel})).message)
+ if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
+ messageOrigin:"auto-update",
+ panelId:panel.id.value,
+ panelOptionIds:panel.get("opendiscord:options").value,
+ panelAutoUpdate:state.data.panelAutoUpdate, //same value
+ isSubPanel:state.data.isSubPanel //same value
+ },panelMessage.flags.has("Ephemeral"))
+ }
+ })
+ )
+
+ //SUB-PANEL DROPDOWN RESPONDER
+ opendiscord.responders.dropdowns.get("opendiscord:panel-dropdown").workers.add(
+ new api.ODWorker("opendiscord:dropdown-subpanel",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //RETURN WHEN NOT OF TYPE SUB-PANEL (ticket or role responders might catch it)
+ const match = /^od:subpanel-option\|([^|]+)/.exec(instance.values.getStringValues()[0])
+ if (!match) return
+ const optionId = match[1]
+
+ //check message state
+ const state = await panelMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
+ return cancel()
+ }
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ //get option data
+ const option = opendiscord.options.get(optionId)
+ if (!option || !(option instanceof api.ODSubPanelOption)){
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ return cancel()
+ }
+
+ //get panel data
+ const subPanel = opendiscord.panels.get(option.get("opendiscord:panel-id").value)
+ if (!subPanel){
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-panel-unknown").build(origin,{guild,channel,user}))
+ return cancel()
+ }
+
+ //send sub-panel message (ephemeral)
+ const panelMessage = await instance.reply((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("sub-panel",{guild,channel,user,panel:subPanel,isSubPanel:true})))
+ if (panelMessage.success) await panelMsgState.setMsgState({channel,message:panelMessage.message},{
+ messageOrigin:"sub-panel",
+ panelId:subPanel.id.value,
+ panelOptionIds:subPanel.get("opendiscord:options").value,
+ panelAutoUpdate:false,
+ isSubPanel:true
+ },panelMessage.ephemeral)
+
+ opendiscord.log(instance.user.displayName+" created a sub-panel!","info",[
+ {key:"user",value:instance.user.username},
+ {key:"userid",value:instance.user.id,hidden:true},
+ {key:"channelid",value:instance.channel.id,hidden:true},
+ {key:"method",value:origin}
+ ])
+
+ //update panel after dropdown usage (reset panel choice)
+ const panel = opendiscord.panels.get(state.data.panelId)
+ if (panel){
+ const panelMessage = await instance.message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild,channel,user,panel,isSubPanel:state.data.isSubPanel})).message)
+ if (panelMessage) await panelMsgState.setMsgState({channel,message:panelMessage},{
+ messageOrigin:"auto-update",
+ panelId:panel.id.value,
+ panelOptionIds:panel.get("opendiscord:options").value,
+ panelAutoUpdate:state.data.panelAutoUpdate, //same value
+ isSubPanel:state.data.isSubPanel //same value
+ },panelMessage.flags.has("Ephemeral"))
+ }
+ })
+ )
}
\ No newline at end of file
diff --git a/src/commands/pin.ts b/src/commands/pin.ts
index f1a8499..413be79 100644
--- a/src/commands/pin.ts
+++ b/src/commands/pin.ts
@@ -1,151 +1,235 @@
///////////////////////////////////////
//PIN COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//PIN COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:pin",generalConfig.data.prefix,"pin"))
opendiscord.responders.commands.get("opendiscord:pin").workers.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.pin
-
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:pin",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:pin",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.pin,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when already pinned
- if (ticket.get("opendiscord:pinned").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"pin")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnpinned = await openticketUtils.replyTicketMustBeUnpinned(instance,origin,ticket)
+ if (!isTicketUnpinned) return cancel()
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const reason = instance.options.getString("reason",false)
-
//start pinning ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:pin-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(source,{guild,channel,user,ticket,reason}))
+ const reason = instance.options.getString("reason",false)
+ await opendiscord.actions.get("opendiscord:pin-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false})
+
+ //send message & set state
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"pin-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'pin' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//PIN TICKET BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:pin-ticket",/^od:pin-ticket/))
opendiscord.responders.buttons.get("opendiscord:pin-ticket").workers.add(
- new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"pin")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:pin-ticket-ticket-message").activate(instance)
- else if (originalSource == "unpin-message") await opendiscord.verifybars.get("opendiscord:pin-ticket-unpin-message").activate(instance)
- else await instance.defer("update",false)
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/pin")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnpinned = await openticketUtils.replyTicketMustBeUnpinned(instance,origin,ticket)
+ if (!isTicketUnpinned) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:pin-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:pin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "unpin-message"){
+ //unpin message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:pin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:unpin-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
})
)
}
-export const registerModalResponders = async () => {
- //PIN WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:pin-ticket-reason",/^od:pin-ticket-reason_/))
- opendiscord.responders.modals.get("opendiscord:pin-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
- const reason = instance.values.getTextField("reason",true)
-
- //pin with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:pin-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "unpin-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:pin-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:pin-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- }
+export async function registerVerifyBars(){
+ //PIN TICKET
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:pin-ticket"))
+ opendiscord.verifybars.get("opendiscord:pin-ticket").workers.add([
+ new api.ODWorker("opendiscord:pin-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"pin")
+ if (!hasPerms) return cancel()
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/pin")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnpinned = await openticketUtils.replyTicketMustBeUnpinned(instance,origin,ticket)
+ if (!isTicketUnpinned) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start pinning ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "unpin-message"){
+ //unpin message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
+ }else if (params.selectedButtonId == "accept"){
+ //PIN TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "unpin-message"){
+ //converted to pin message
+ await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"pin-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //PIN WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:pin-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
+ //PIN WITH REASON MODAL RESPONDER
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:pin-ticket-reason",/^od:pin-ticket-reason\|([^|]+)\|([^|]+)/))
+ opendiscord.responders.modals.get("opendiscord:pin-ticket-reason").workers.add([
+ new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
+
+ const match = /^od:pin-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"pin")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/pin")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketUnpinned = await openticketUtils.replyTicketMustBeUnpinned(instance,origin,ticket)
+ if (!isTicketUnpinned) return cancel()
+
+ //fetch state details
+ const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
+
+ //start pinning ticket
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
+
+ }else if (originalMsgType == "unpin-message"){
+ //converted to pin message
+ await opendiscord.actions.get("opendiscord:pin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"pin-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
+ }
})
])
}
\ No newline at end of file
diff --git a/src/commands/priority.ts b/src/commands/priority.ts
index 39812ca..2125e41 100644
--- a/src/commands/priority.ts
+++ b/src/commands/priority.ts
@@ -1,44 +1,30 @@
///////////////////////////////////////
//PRIORITY COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//PRIORITY COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:priority",generalConfig.data.prefix,"priority"))
opendiscord.responders.commands.get("opendiscord:priority").workers.add([
- new api.ODWorker("opendiscord:priority",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:priority",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.priority,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"priority")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
//subcommands
const scope = instance.options.getSubCommand()
@@ -56,21 +42,21 @@ export const registerCommandResponders = async () => {
//start changing ticket priority
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:update-ticket-priority").run(source,{guild,channel,user,ticket,newPriority:priority,sendMessage:false,reason})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:priority-set").build(source,{guild,channel,user,ticket,priority,reason}))
+ await opendiscord.actions.get("opendiscord:update-ticket-priority").run(origin,{guild,channel,user,ticket,newPriority:priority,sendMessage:false,reason})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:priority-set").build(origin,{guild,channel,user,ticket,priority,reason}))
}else if (scope == "get"){
const priority = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value)
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:priority-get").build(source,{guild,channel,user,ticket,priority}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:priority-get").build(origin,{guild,channel,user,ticket,priority}))
}
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
const scope = instance.options.getSubCommand()
opendiscord.log(instance.user.displayName+" used the 'priority "+scope+"' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/remove.ts b/src/commands/remove.ts
index c6ec472..554178d 100644
--- a/src/commands/remove.ts
+++ b/src/commands/remove.ts
@@ -1,45 +1,32 @@
///////////////////////////////////////
//REMOVE COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//REMOVE COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:remove",generalConfig.data.prefix,"remove"))
opendiscord.responders.commands.get("opendiscord:remove").workers.add([
- new api.ODWorker("opendiscord:remove",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:remove",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.remove,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"remove")
+ if (!hasPerms) return cancel()
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+ //fetch data
const data = instance.options.getUser("user",true)
const reason = instance.options.getString("reason",false)
@@ -52,15 +39,15 @@ export const registerCommandResponders = async () => {
//start removing user from ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:remove-ticket-user").run(source,{guild,channel,user,ticket,reason,sendMessage:false,data})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:remove-message").build(source,{guild,channel,user,ticket,reason,data}))
+ await opendiscord.actions.get("opendiscord:remove-ticket-user").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,data})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:remove-message").build(origin,{guild,channel,user,ticket,reason,data}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'remove' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/rename.ts b/src/commands/rename.ts
index 7bbee26..6b2dee6 100644
--- a/src/commands/rename.ts
+++ b/src/commands/rename.ts
@@ -1,59 +1,46 @@
///////////////////////////////////////
//RENAME COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//RENAME COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:rename",generalConfig.data.prefix,"rename"))
opendiscord.responders.commands.get("opendiscord:rename").workers.add([
- new api.ODWorker("opendiscord:rename",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:rename",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.rename,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"rename")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+ //fetch data
const name = instance.options.getString("name",true)
const reason = instance.options.getString("reason",false)
//start renaming ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:rename-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false,data:name})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:rename-message").build(source,{guild,channel,user,ticket,reason,data:name}))
+ await opendiscord.actions.get("opendiscord:rename-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,data:name})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:rename-message").build(origin,{guild,channel,user,ticket,reason,data:name}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'rename' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/reopen.ts b/src/commands/reopen.ts
index fb86a30..d2fcc55 100644
--- a/src/commands/reopen.ts
+++ b/src/commands/reopen.ts
@@ -1,123 +1,261 @@
///////////////////////////////////////
//REOPEN COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//REOPEN COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:reopen",generalConfig.data.prefix,"reopen"))
opendiscord.responders.commands.get("opendiscord:reopen").workers.add([
- new api.ODWorker("opendiscord:reopen",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:reopen",0,async (instance,params,origin,cancel) => {
const {guild,channel,user,member} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.reopen,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not closed
- if (!ticket.get("opendiscord:closed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const reason = instance.options.getString("reason",false)
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"reopen")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClosed = await openticketUtils.replyTicketMustBeClosed(instance,origin,ticket)
+ if (!isTicketClosed) return cancel()
//start reopening ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(source,{guild,channel,user,ticket,reason}))
+ const reason = instance.options.getString("reason",false)
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false})
+
+ //send message & set state
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"reopen-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'reopen' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//REOPEN TICKET BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:reopen-ticket",/^od:reopen-ticket/))
opendiscord.responders.buttons.get("opendiscord:reopen-ticket").workers.add(
- new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,message,user,member} = instance
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:reopen-ticket-ticket-message").activate(instance)
- else if (originalSource == "close-message") await opendiscord.verifybars.get("opendiscord:reopen-ticket-close-message").activate(instance)
- else if (originalSource == "autoclose-message") await opendiscord.verifybars.get("opendiscord:reopen-ticket-autoclose-message").activate(instance)
- else await instance.defer("update",false)
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"reopen")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/reopen")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClosed = await openticketUtils.replyTicketMustBeClosed(instance,origin,ticket)
+ if (!isTicketClosed) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:reopen-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:reopen-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "close-message"){
+ //close message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:reopen-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:close-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }else if (originalMsgType == "autoclose-message"){
+ //autoclose message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:reopen-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:autoclose-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket}))
+ }
})
)
}
-export const registerModalResponders = async () => {
- //REOPEN WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:reopen-ticket-reason",/^od:reopen-ticket-reason_/))
- opendiscord.responders.modals.get("opendiscord:reopen-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
-
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
- const reason = instance.values.getTextField("reason",true)
-
- //reopen with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "close-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
- }else if (originalSource == "autoclose-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
- }
+export async function registerVerifyBars(){
+ //REOPEN TICKET
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:reopen-ticket"))
+ opendiscord.verifybars.get("opendiscord:reopen-ticket").workers.add([
+ new api.ODWorker("opendiscord:reopen-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"reopen")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/reopen")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClosed = await openticketUtils.replyTicketMustBeClosed(instance,origin,ticket)
+ if (!isTicketClosed) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start reopening ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "close-message"){
+ //close message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }else if (originalMsgType == "autoclose-message"){
+ //autoclose message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:autoclose-message").build("verifybar",{guild,channel,user:originalUser,ticket}))
+ }
+ }else if (params.selectedButtonId == "accept"){
+ //REOPEN TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "close-message"){
+ //converted to reopen message
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"reopen-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }else if (originalMsgType == "autoclose-message"){
+ //converted to reopen message
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"reopen-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //REOPEN WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:reopen-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
+ //REOPEN WITH REASON MODAL RESPONDER
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:reopen-ticket-reason",/^od:reopen-ticket-reason\|([^|]+)\|([^|]+)/))
+ opendiscord.responders.modals.get("opendiscord:reopen-ticket-reason").workers.add([
+ new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
+
+ const match = /^od:reopen-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"reopen")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/reopen")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClosed = await openticketUtils.replyTicketMustBeClosed(instance,origin,ticket)
+ if (!isTicketClosed) return cancel()
+
+ //fetch state details
+ const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
+
+ //start reopening ticket
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
+
+ }else if (originalMsgType == "close-message"){
+ //converted to reopen message
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"reopen-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
+ }else if (originalMsgType == "autoclose-message"){
+ //converted to reopen message
+ await opendiscord.actions.get("opendiscord:reopen-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:reopen-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"reopen-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
+ }
})
])
}
\ No newline at end of file
diff --git a/src/commands/role.ts b/src/commands/role.ts
index e9de633..f0cc7b7 100644
--- a/src/commands/role.ts
+++ b/src/commands/role.ts
@@ -1,42 +1,52 @@
///////////////////////////////////////
//ROLE BUTTON (not command)
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const panelMsgState = opendiscord.states.get("opendiscord:panel-message")
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//ROLE OPTION BUTTON RESPONDER
- opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:role-option",/^od:role-option_/))
+ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:role-option",/^od:role-option\|([^|]+)/))
opendiscord.responders.buttons.get("opendiscord:role-option").workers.add(
- new api.ODWorker("opendiscord:role-option",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
+ new api.ODWorker("opendiscord:role-option",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ const match = /^od:role-option\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const optionId = match[1]
+
+ //check message state
+ const state = await panelMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
return cancel()
}
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
//get option data
- const optionId = instance.interaction.customId.split("_")[2]
const option = opendiscord.options.get(optionId)
if (!option || !(option instanceof api.ODRoleOption)){
//error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
return cancel()
}
//reaction role
- await instance.defer("reply",true)
+ await instance.defer(generalConfig.data.ticketSystem.replyOnReactionRole ? "reply" : "update",true)
const res = await opendiscord.actions.get("opendiscord:reaction-role").run("panel-button",{guild,user,option,overwriteMode:null})
if (!res.result || !res.role){
//error
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild,channel:instance.channel,user,error:"Unable to receive role update data from worker!",layout:"advanced"}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive role update data from worker!",layout:"advanced"}))
return cancel()
}
- if (generalConfig.data.system.replyOnReactionRole) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role").build("panel-button",{guild,user,role:res.role,result:res.result}))
+ if (generalConfig.data.ticketSystem.replyOnReactionRole) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:reaction-role").build("panel-button",{guild,user,role:res.role,result:res.result}))
})
)
}
\ No newline at end of file
diff --git a/src/commands/stats.ts b/src/commands/stats.ts
index 46be1fb..d6d6da6 100644
--- a/src/commands/stats.ts
+++ b/src/commands/stats.ts
@@ -1,117 +1,58 @@
///////////////////////////////////////
//STATS COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//STATS COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:stats",generalConfig.data.prefix,/^stats/))
opendiscord.responders.commands.get("opendiscord:stats").workers.add([
- new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
- const permissionMode = generalConfig.data.system.permissions.stats
-
- //command is disabled
- if (permissionMode == "none"){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }
-
- //reset subcommand is owner/developer only
- if (instance.options.getSubCommand() == "reset"){
- if (!opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["owner","developer"]}))
- return cancel()
- }else return
- }
-
- //permissions for normal scopes
- if (permissionMode == "everyone") return
- else if (permissionMode == "admin"){
- if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]}))
- return cancel()
- }else return
- }else{
- if (!instance.guild || !instance.member){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"}))
- return cancel()
- }
- const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode)
- if (!role){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"}))
- return cancel()
- }
- if (!role.members.has(instance.member.id)){
- //no permissions
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
- }else return
- }
- }),
- new api.ODWorker("opendiscord:stats",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:stats",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
//check permissions
- if (generalConfig.data.system.permissions.stats === "none"){
- //command is disabled
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
- return cancel()
-
- }else if (instance.options.getSubCommand() === "reset" && !opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
+ if (instance.options.getSubCommand() === "reset" && !opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){
//reset --> owner/developer role is required
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["owner","developer"]}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["owner","developer"]}))
return cancel()
-
}else{
//default permissions check
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.stats,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"stats")
+ if (!hasPerms) return cancel()
}
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
- return cancel()
- }
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
//subcommands
const scope = instance.options.getSubCommand()
if (!scope || (scope != "global" && scope != "ticket" && scope != "user" && scope != "reset")) return
if (scope == "global"){
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-global").build(source,{guild,channel,user}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-global").build(origin,{guild,channel,user}))
}else if (scope == "ticket"){
const id = instance.options.getChannel("ticket",false)?.id ?? channel.id
const ticket = opendiscord.tickets.get(id)
- if (ticket) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-ticket").build(source,{guild,channel,user,scopeData:ticket}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-ticket-unknown").build(source,{guild,channel,user,id}))
+ if (ticket) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-ticket").build(origin,{guild,channel,user,scopeData:ticket}))
+ else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-ticket-unknown").build(origin,{guild,channel,user,id}))
}else if (scope == "user"){
const statsUser = instance.options.getUser("user",false) ?? user
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-user").build(source,{guild,channel,user,scopeData:statsUser}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-user").build(origin,{guild,channel,user,scopeData:statsUser}))
}else if (scope == "reset"){
const reason = instance.options.getString("reason",false)
- opendiscord.stats.reset()
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-reset").build(source,{guild,channel,user,reason}))
-
+ opendiscord.statistics.reset()
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:stats-reset").build(origin,{guild,channel,user,reason}))
}
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
const scope = instance.options.getSubCommand()
let data: string
if (scope == "ticket"){
@@ -123,7 +64,7 @@ export const registerCommandResponders = async () => {
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source},
+ {key:"method",value:origin},
{key:"data",value:data},
])
})
diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts
index ce26854..de83f8c 100644
--- a/src/commands/ticket.ts
+++ b/src/commands/ticket.ts
@@ -1,244 +1,197 @@
///////////////////////////////////////
//TICKET COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
const lang = opendiscord.languages
+const panelMsgState = opendiscord.states.get("opendiscord:panel-message")
-async function checkTicketCreationPerms(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance|api.ODCommandResponderInstance,source:api.ODActionManagerIds_Default["opendiscord:create-ticket-permissions"]["source"],guild:discord.Guild,user:discord.User,option:api.ODTicketOption){
- //check ticket permissions
- const permsRes = await opendiscord.actions.get("opendiscord:create-ticket-permissions").run(source,{guild,user,option})
- if (!permsRes.valid && instance.channel){
- //error
- const newSource = (source === "slash" || source === "text") ? source : "other"
- if (permsRes.reason == "blacklist") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-blacklisted").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user}))
- else if (permsRes.reason == "cooldown") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-cooldown").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,until:permsRes.cooldownUntil}))
- else if (permsRes.reason == "global-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global"}))
- else if (permsRes.reason == "global-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global-user"}))
- else if (permsRes.reason == "option-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option"}))
- else if (permsRes.reason == "option-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option-user"}))
- else if (permsRes.reason == "custom") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,layout:"simple",error:permsRes.customReason ?? lang.getTranslation("errors.descriptions.unableToCreateTicket")+" `Unknown invalid_permission_reason => no reason specified by plugin`",customTitle:lang.getTranslation("errors.titles.permissionError")}))
- else instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Unknown invalid_permission reason => calculation failed #1",layout:"advanced"}))
- return false
- }else return true
-}
-
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//TICKET COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:ticket",generalConfig.data.prefix,/^ticket/))
opendiscord.responders.commands.get("opendiscord:ticket").workers.add([
- new api.ODWorker("opendiscord:ticket",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:ticket",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.ticket,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
- return cancel()
- }
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"ticket")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
//get option data
const optionId = instance.options.getString("id",true)
const option = opendiscord.options.get(optionId)
if (!option || !(option instanceof api.ODTicketOption)){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
return cancel()
}
//start ticket creation
if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
- //send modal
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build(source,{guild,channel,user,option}))
+ //SEND MODAL
+ instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build(origin,{guild,channel,user,option}))
}else{
- //check ticket permissions
- if (!(await checkTicketCreationPerms(instance,source,guild,user,option))) return cancel()
-
- //create ticket
+ //check ticket permissions (modals need check after submit)
+ if (!(await openticketUtils.checkTicketCreationPerms(instance,origin,guild,user,option))) return cancel()
+
+ //CREATE TICKET
await instance.defer(true)
- const res = await opendiscord.actions.get("opendiscord:create-ticket").run(source,{guild,user,answers:[],option})
+ const res = await opendiscord.actions.get("opendiscord:create-ticket").run(origin,{guild,user,answers:[],option})
if (!res.channel || !res.ticket){
//error
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"}))
return cancel()
}
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build(source,{guild,channel:res.channel,user,ticket:res.ticket}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build(origin,{guild,channel:res.channel,user,ticket:res.ticket}))
}
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'ticket' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//TICKET OPTION BUTTON RESPONDER
- opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:ticket-option",/^od:ticket-option_/))
+ opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:ticket-option",/^od:ticket-option\|([^|]+)/))
opendiscord.responders.buttons.get("opendiscord:ticket-option").workers.add(
- new api.ODWorker("opendiscord:ticket-option",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
+ new api.ODWorker("opendiscord:ticket-option",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ const match = /^od:ticket-option\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const optionId = match[1]
+
+ //check message state
+ const state = await panelMsgState.getMsgState({channel,message})
+ if (!state){
+ //TODO TRANSLATION!!!
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"This panel is no longer valid or has expired. Create a new panel using `{0}` to solve the issue. It is normal to receive this error after a major Open Ticket update.".replace("{0}","/panel"),layout:"simple",customTitle:"Message State Expired"}))
return cancel()
}
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
- //get option
- const optionId = instance.interaction.customId.split("_")[2]
+ //get option data
const option = opendiscord.options.get(optionId)
if (!option || !(option instanceof api.ODTicketOption)){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user}))
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel:instance.channel,user:instance.user}))
return cancel()
}
//start ticket creation
if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
- //send modal
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option}))
+ //SEND MODAL
+ instance.modal(await opendiscord.components.modals.get("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option}))
}else{
- //check ticket permissions
- if (!(await checkTicketCreationPerms(instance,"panel-button",guild,user,option))) return cancel()
-
- //create ticket
- await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true)
+ //check ticket permissions (modals need check after submit)
+ if (!(await openticketUtils.checkTicketCreationPerms(instance,"panel-button",guild,user,option))) return cancel()
+
+ //CREATE TICKET
+ await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true)
const res = await opendiscord.actions.get("opendiscord:create-ticket").run("panel-button",{guild,user,answers:[],option})
if (!res.channel || !res.ticket){
//error
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"}))
return cancel()
}
- if (generalConfig.data.system.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-button",{guild,channel:res.channel,user,ticket:res.ticket}))
+ if (generalConfig.data.ticketSystem.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-button",{guild,channel:res.channel,user,ticket:res.ticket}))
}
})
)
}
-export const registerDropdownResponders = async () => {
- //PANEL DROPDOWN TICKETS DROPDOWN RESPONDER
- opendiscord.responders.dropdowns.add(new api.ODDropdownResponder("opendiscord:panel-dropdown-tickets",/^od:panel-dropdown_/))
- opendiscord.responders.dropdowns.get("opendiscord:panel-dropdown-tickets").workers.add(
- new api.ODWorker("opendiscord:panel-dropdown-tickets",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user}))
- return cancel()
- }
-
- //get option
- const optionId = instance.values.getStringValues()[0].split("_")[2]
- const option = opendiscord.options.get(optionId)
- if (!option || !(option instanceof api.ODTicketOption)){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user}))
- return cancel()
- }
-
- //start ticket creation
- if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){
- //send modal
- instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option}))
- }else{
- //check ticket permissions
- if (!(await checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option))) return cancel()
-
- //create ticket
- await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true)
-
- const res = await opendiscord.actions.get("opendiscord:create-ticket").run("panel-dropdown",{guild,user,answers:[],option})
- if (!res.channel || !res.ticket){
- //error
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild,channel:instance.channel,user,error:"Unable to receive ticket or channel from callback! #1",layout:"advanced"}))
- return cancel()
- }
- if (generalConfig.data.system.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build("panel-dropdown",{guild,channel:res.channel,user,ticket:res.ticket}))
- }
-
- //update panel after dropdown usage (reset panel choice)
- const globalDatabase = opendiscord.databases.get("opendiscord:global")
- const rawPanelId = await globalDatabase.get("opendiscord:panel-message",instance.message.channel.id+"_"+instance.message.id)
- if (rawPanelId){
- const panel = opendiscord.panels.get(rawPanelId)
- if (panel) await instance.message.edit((await opendiscord.builders.messages.getSafe("opendiscord:panel").build("auto-update",{guild,channel,user,panel})).message)
- }
- })
- )
-}
-
-export const registerModalResponders = async () => {
+export async function registerModalResponders(){
//TICKET QUESTIONS RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:ticket-questions",/^od:ticket-questions_/))
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:ticket-questions",/^od:ticket-questions\|([^|]+)\|([^|]+)/))
opendiscord.responders.modals.get("opendiscord:ticket-questions").workers.add([
- new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,origin,cancel) => {
const {guild,channel,user} = instance
- await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true)
- if (!channel) throw new api.ODSystemError("The 'Ticket Questions' modal requires a channel for responding!")
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const originalSource = instance.interaction.customId.split("_")[2] as ("panel-button"|"panel-dropdown"|"slash"|"text"|"other")
+ const match = /^od:ticket-questions\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const optionId = match[1]
+ const originalOrigin = match[2] as ("panel-button"|"panel-dropdown"|"slash"|"text"|"other")
+
+ //responder checks
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
- //get option
- const optionId = instance.interaction.customId.split("_")[1]
+ //get option data
const option = opendiscord.options.get(optionId)
if (!option || !(option instanceof api.ODTicketOption)){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(source,{guild:instance.guild,channel,user:instance.user}))
+ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-option-unknown").build(origin,{guild:instance.guild,channel,user:instance.user}))
return cancel()
}
+ //check ticket permissions (modals need check after submit)
+ if (!(await openticketUtils.checkTicketCreationPerms(instance,originalOrigin,guild,user,option))) return cancel()
+
//get answers
- const answers: {id:string,name:string,type:"short"|"paragraph",value:string|null}[] = []
- option.get("opendiscord:questions").value.forEach((id) => {
- const question = opendiscord.questions.get(id)
- if (!question) return
- if (question instanceof api.ODShortQuestion){
- answers.push({
- id,
- name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : id,
- type:"short",
- value:instance.values.getTextField(id,false)
- })
- }else if (question instanceof api.ODParagraphQuestion){
- answers.push({
- id,
- name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : id,
- type:"paragraph",
- value:instance.values.getTextField(id,false)
- })
- }
- })
+ const answers: api.ODQuestionAnswer[] = []
+ for (const questionId of option.get("opendiscord:questions").value){
+ const question = opendiscord.questions.get(questionId)
+ if (!question) continue
+ if (question instanceof api.ODShortQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"short",
+ value:instance.values.getTextField(questionId,false)
+ })
+ else if (question instanceof api.ODParagraphQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"paragraph",
+ value:instance.values.getTextField(questionId,false)
+ })
+ else if (question instanceof api.ODDropdownQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"dropdown",
+ value:instance.values.getStringDropdownValues(questionId)[0] ?? null
+ })
+ else if (question instanceof api.ODRadioSelectQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"radio-select",
+ value:instance.values.getRadioGroup(questionId,false)
+ })
+ else if (question instanceof api.ODCheckboxSelectQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"checkbox-select",
+ value:(instance.values.getCheckboxGroup(questionId).length > 0) ? instance.values.getCheckboxGroup(questionId).map((opt) => "> "+opt).join("\n") : null
+ })
+ else if (question instanceof api.ODFileUploadQuestion) answers.push({
+ id:questionId,
+ name:question.exists("opendiscord:name") ? question.get("opendiscord:name")?.value : questionId,
+ type:"file-upload",
+ files:(instance.values.getUploadedFiles(questionId).length > 0) ? instance.values.getUploadedFiles(questionId).map(({id,url,name,title,description,contentType}) => ({id,url,name,title,description,contentType})) : []
+ })
+ }
+
+ await instance.defer((generalConfig.data.ticketSystem.replyOnTicketCreation) ? "reply" : "update",true)
- //check ticket permissions
- if (!(await checkTicketCreationPerms(instance,originalSource,guild,user,option))) return cancel()
-
- //create ticket
- const res = await opendiscord.actions.get("opendiscord:create-ticket").run(originalSource,{guild,user,answers,option})
+ //CREATE TICKET
+ const res = await opendiscord.actions.get("opendiscord:create-ticket").run(originalOrigin,{guild,user,answers,option})
if (!res.channel || !res.ticket){
//error
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild,channel,user,error:"Unable to receive ticket or channel from callback! #2",layout:"advanced"}))
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(origin,{guild,channel,user,error:"Unable to receive ticket or channel from callback! #2",layout:"advanced"}))
return cancel()
}
- if (generalConfig.data.system.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build(originalSource,{guild,channel:res.channel,user,ticket:res.ticket}))
+ if (generalConfig.data.ticketSystem.replyOnTicketCreation) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:ticket-created").build(originalOrigin,{guild,channel:res.channel,user,ticket:res.ticket}))
})
])
}
\ No newline at end of file
diff --git a/src/commands/topic.ts b/src/commands/topic.ts
index 79992c2..b2b15ad 100644
--- a/src/commands/topic.ts
+++ b/src/commands/topic.ts
@@ -1,44 +1,29 @@
///////////////////////////////////////
//TOPIC COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//TOPIC COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:topic",generalConfig.data.prefix,"topic"))
opendiscord.responders.commands.get("opendiscord:topic").workers.add([
- new api.ODWorker("opendiscord:topic",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:topic",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.topic,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/Server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"topic")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
//subcommands
const scope = instance.options.getSubCommand()
@@ -48,16 +33,16 @@ export const registerCommandResponders = async () => {
const topic = instance.options.getString("topic",true)
//start changing ticket topic
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:update-ticket-topic").run(source,{guild,channel,user,ticket,newTopic:topic,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:topic-set").build(source,{guild,channel,user,ticket,topic}))
+ await opendiscord.actions.get("opendiscord:update-ticket-topic").run(origin,{guild,channel,user,ticket,newTopic:topic,sendMessage:false})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:topic-set").build(origin,{guild,channel,user,ticket,topic}))
}
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'topic set' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/transfer.ts b/src/commands/transfer.ts
index 5aa2298..7857ef8 100644
--- a/src/commands/transfer.ts
+++ b/src/commands/transfer.ts
@@ -1,60 +1,47 @@
///////////////////////////////////////
//TRANSFER COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//TRANSFER COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:transfer",generalConfig.data.prefix,"transfer"))
opendiscord.responders.commands.get("opendiscord:transfer").workers.add([
- new api.ODWorker("opendiscord:transfer",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:transfer",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.transfer,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/Server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"transfer")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+ //fetch data
const oldCreator = await opendiscord.tickets.getTicketUser(ticket,"creator") ?? opendiscord.client.client.user
const newCreator = instance.options.getUser("user",true)
const reason = instance.options.getString("reason",false)
//start transferring ticket ownership
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:transfer-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false,newCreator})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:transfer-message").build(source,{guild,channel,user,ticket,oldCreator,newCreator,reason}))
+ await opendiscord.actions.get("opendiscord:transfer-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false,newCreator})
+ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:transfer-message").build(origin,{guild,channel,user,ticket,oldCreator,newCreator,reason}))
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'transfer' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
diff --git a/src/commands/unclaim.ts b/src/commands/unclaim.ts
index 73cb608..ba48bba 100644
--- a/src/commands/unclaim.ts
+++ b/src/commands/unclaim.ts
@@ -1,116 +1,233 @@
///////////////////////////////////////
//UNCLAIM COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//UNCLAIM COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:unclaim",generalConfig.data.prefix,"unclaim"))
opendiscord.responders.commands.get("opendiscord:unclaim").workers.add([
- new api.ODWorker("opendiscord:unclaim",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:unclaim",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.unclaim,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/Server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not claimed
- if (!ticket.get("opendiscord:claimed").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"}))
- return cancel()
- }
-
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const reason = instance.options.getString("reason",false)
-
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unclaim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClaimed = await openticketUtils.replyTicketMustBeClaimed(instance,origin,ticket)
+ if (!isTicketClaimed) return cancel()
+
//start unclaiming ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:unclaim-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(source,{guild,channel,user,ticket,reason}))
+ const reason = instance.options.getString("reason",false)
+ await opendiscord.actions.get("opendiscord:unclaim-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false})
+
+ //send message & set state
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"unclaim-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'unclaim' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//UNCLAIM TICKET BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:unclaim-ticket",/^od:unclaim-ticket/))
opendiscord.responders.buttons.get("opendiscord:unclaim-ticket").workers.add(
- new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:unclaim-ticket-ticket-message").activate(instance)
- else if (originalSource == "claim-message") await opendiscord.verifybars.get("opendiscord:unclaim-ticket-claim-message").activate(instance)
- else await instance.defer("update",false)
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unclaim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unclaim")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClaimed = await openticketUtils.replyTicketMustBeClaimed(instance,origin,ticket)
+ if (!isTicketClaimed) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:unclaim-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unclaim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "claim-message"){
+ //claim message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unclaim-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:claim-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
})
)
}
-export const registerModalResponders = async () => {
+export async function registerVerifyBars(){
+ //UNCLAIM TICKET
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unclaim-ticket"))
+ opendiscord.verifybars.get("opendiscord:unclaim-ticket").workers.add([
+ new api.ODWorker("opendiscord:unclaim-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unclaim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unclaim")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClaimed = await openticketUtils.replyTicketMustBeClaimed(instance,origin,ticket)
+ if (!isTicketClaimed) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start unclaiming ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "claim-message"){
+ //claim message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:claim-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
+ }else if (params.selectedButtonId == "accept"){
+ //UNCLAIM TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "claim-message"){
+ //converted to unclaim message
+ await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"unclaim-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //UNCLAIM WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:unclaim-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
//UNCLAIM WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unclaim-ticket-reason",/^od:unclaim-ticket-reason_/))
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unclaim-ticket-reason",/^od:unclaim-ticket-reason\|([^|]+)\|([^|]+)/))
opendiscord.responders.modals.get("opendiscord:unclaim-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
+ new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
+
+ const match = /^od:unclaim-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unclaim")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unclaim")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketClaimed = await openticketUtils.replyTicketMustBeClaimed(instance,origin,ticket)
+ if (!isTicketClaimed) return cancel()
+
+ //fetch state details
const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
- //unclaim with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
+ //start claiming ticket
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "claim-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
+
+ }else if (originalMsgType == "claim-message"){
+ //converted to unclaim message
+ await opendiscord.actions.get("opendiscord:unclaim-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unclaim-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"unclaim-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}
})
])
diff --git a/src/commands/unpin.ts b/src/commands/unpin.ts
index 30a9579..627e156 100644
--- a/src/commands/unpin.ts
+++ b/src/commands/unpin.ts
@@ -1,116 +1,233 @@
///////////////////////////////////////
//UNPIN COMMAND
///////////////////////////////////////
-import {opendiscord, api, utilities} from "../index"
+import {opendiscord, api, utilities, openticketUtils} from "../index.js"
import * as discord from "discord.js"
const generalConfig = opendiscord.configs.get("opendiscord:general")
+const lang = opendiscord.languages
+const interactiveMsgState = opendiscord.states.get("opendiscord:interactive-message")
-export const registerCommandResponders = async () => {
+export async function registerCommandResponders(){
//UNPIN COMMAND RESPONDER
opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:unpin",generalConfig.data.prefix,"unpin"))
opendiscord.responders.commands.get("opendiscord:unpin").workers.add([
- new api.ODWorker("opendiscord:unpin",0,async (instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:unpin",0,async (instance,params,origin,cancel) => {
const {user,member,channel,guild} = instance
-
- //check permissions
- const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.unpin,"support",user,member,channel,guild)
- if (!permsResult.hasPerms){
- if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]}))
- return cancel()
- }
-
- //check is in guild/Server
- if (!guild){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
- return cancel()
- }
-
- //check if ticket exists
- const ticket = opendiscord.tickets.get(channel.id)
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return cancel()
- }
-
- //return when not pinned yet
- if (!ticket.get("opendiscord:pinned").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"}))
- return cancel()
- }
- //return when busy
- if (ticket.get("opendiscord:busy").value){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
- return cancel()
- }
-
- const reason = instance.options.getString("reason",false)
-
- //start unpinning ticket
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unpin")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketPinned = await openticketUtils.replyTicketMustBePinned(instance,origin,ticket)
+ if (!isTicketPinned) return cancel()
+
+ //start unpining ticket
await instance.defer(false)
- await opendiscord.actions.get("opendiscord:unpin-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(source,{guild,channel,user,ticket,reason}))
+ const reason = instance.options.getString("reason",false)
+ await opendiscord.actions.get("opendiscord:unpin-ticket").run(origin,{guild,channel,user,ticket,reason,sendMessage:false})
+
+ //send message & set state
+ const sentMsg = await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(origin,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"unpin-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}),
- new api.ODWorker("opendiscord:logs",-1,(instance,params,source,cancel) => {
+ new api.ODWorker("opendiscord:logs",-1,(instance,params,origin,cancel) => {
opendiscord.log(instance.user.displayName+" used the 'unpin' command!","info",[
{key:"user",value:instance.user.username},
{key:"userid",value:instance.user.id,hidden:true},
{key:"channelid",value:instance.channel.id,hidden:true},
- {key:"method",value:source}
+ {key:"method",value:origin}
])
})
])
}
-export const registerButtonResponders = async () => {
+export async function registerButtonResponders(){
//UNPIN TICKET BUTTON RESPONDER
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:unpin-ticket",/^od:unpin-ticket/))
opendiscord.responders.buttons.get("opendiscord:unpin-ticket").workers.add(
- new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,source,cancel) => {
- const originalSource = instance.interaction.customId.split("_")[1] as Exclude
+ new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin,cancel) => {
+ const {guild,channel,user,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unpin")
+ if (!hasPerms) return cancel()
- if (originalSource == "ticket-message") await opendiscord.verifybars.get("opendiscord:unpin-ticket-ticket-message").activate(instance)
- else if (originalSource == "pin-message") await opendiscord.verifybars.get("opendiscord:unpin-ticket-pin-message").activate(instance)
- else await instance.defer("update",false)
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unpin")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketPinned = await openticketUtils.replyTicketMustBePinned(instance,origin,ticket)
+ if (!isTicketPinned) return cancel()
+
+ //fetch state details
+ const verifybar = opendiscord.verifybars.get("opendiscord:unpin-ticket")
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //send verifybar
+ if (generalConfig.data.ticketSystem.disableVerifyBars){
+ //verifybar disabled, directly run response
+ await verifybar.activate(instance,"accept")
+
+ }else if (originalMsgType == "ticket-message"){
+ //ticket message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unpin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:ticket-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "pin-message"){
+ //pin message verifybar
+ const modifiedMsg = opendiscord.components.modifiers.get("opendiscord:unpin-ticket-verifybar").modify(opendiscord.builders.messages.getSafe("opendiscord:pin-message"),originalMsgType,{guild,channel,user,verifybar})
+ await instance.update(await modifiedMsg.build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
})
)
}
-export const registerModalResponders = async () => {
+export async function registerVerifyBars(){
+ //UNPIN TICKET
+ opendiscord.verifybars.add(new api.ODVerifyBar("opendiscord:unpin-ticket"))
+ opendiscord.verifybars.get("opendiscord:unpin-ticket").workers.add([
+ new api.ODWorker("opendiscord:unpin-ticket",0,async (instance,params,origin,cancel) => {
+ const {user,member,channel,guild,message} = instance
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unpin")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || channel.isDMBased()) return cancel()
+
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unpin")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketPinned = await openticketUtils.replyTicketMustBePinned(instance,origin,ticket)
+ if (!isTicketPinned) return cancel()
+
+ //fetch state details
+ const originalUser = ((state.data.messageAuthor) ? await opendiscord.client.fetchUser(state.data.messageAuthor) : user) ?? user
+ const originalReason = state.data.messageReason ?? null
+ const originalMsgType = state.data.messageType
+
+ //start unpinning ticket
+ if (params.selectedButtonId == "cancel"){
+ //CANCEL
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "pin-message"){
+ //pin message
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:pin-message").build("verifybar",{guild,channel,user:originalUser,ticket,reason:originalReason}))
+ }
+ }else if (params.selectedButtonId == "accept"){
+ //UNPIN TICKET
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
+ await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("verifybar",{guild,channel,user,ticket}))
+ }else if (originalMsgType == "pin-message"){
+ //converted to unpin message
+ await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("verifybar",{guild,channel,user,ticket,reason:null}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"unpin-message",
+ messageOrigin:origin,
+ messageAuthor:user.id,
+ messageReason:null
+ },sentMsg.ephemeral)
+ }
+ }else if (params.selectedButtonId == "accept-with-reason"){
+ //UNPIN WITH REASON (MODAL)
+ instance.modal(await opendiscord.components.modals.get("opendiscord:unpin-ticket-reason").build("other",{guild,channel,user,ticket,message}))
+ }
+ })
+ ])
+}
+
+export async function registerModalResponders(){
//UNPIN WITH REASON MODAL RESPONDER
- opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unpin-ticket-reason",/^od:unpin-ticket-reason_/))
+ opendiscord.responders.modals.add(new api.ODModalResponder("opendiscord:unpin-ticket-reason",/^od:unpin-ticket-reason\|([^|]+)\|([^|]+)/))
opendiscord.responders.modals.get("opendiscord:unpin-ticket-reason").workers.add([
- new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,source,cancel) => {
- const {guild,channel,user} = instance
- if (!channel) return
- if (!guild){
- //error
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel,user:instance.user}))
- return cancel()
- }
- const ticket = opendiscord.tickets.get(instance.interaction.customId.split("_")[1])
- if (!ticket || channel.isDMBased()){
- instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
- return
- }
+ new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin,cancel) => {
+ const {guild,user} = instance
+
+ const match = /^od:unpin-ticket-reason\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
+ if (!match) return cancel()
+ const channel = await opendiscord.client.fetchTextChannel(match[1])
+ const message = await opendiscord.client.fetchChannelMessage(match[1],match[2])
+
+ //responder checks
+ const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"unpin")
+ if (!hasPerms) return cancel()
+
+ const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
+ if (!isInGuild || !guild || !channel || channel.isDMBased()) return cancel()
- const originalSource = instance.interaction.customId.split("_")[2] as Exclude
+ const state = await openticketUtils.replyInteractiveMessageState(instance,origin,channel,message,"/unpin")
+ if (!state) return cancel()
+
+ const ticket = await openticketUtils.replyIsTicket(instance,origin)
+ if (!ticket) return cancel()
+
+ const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
+ if (!isAvailable) return cancel()
+
+ const isTicketPinned = await openticketUtils.replyTicketMustBePinned(instance,origin,ticket)
+ if (!isTicketPinned) return cancel()
+
+ //fetch state details
const reason = instance.values.getTextField("reason",true)
+ const originalMsgOrigin = state.data.messageOrigin
+ const originalMsgType = state.data.messageType
- //unpin with reason
- if (originalSource == "ticket-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
+ //start pinning ticket
+ await instance.defer("update",false)
+
+ if (originalMsgType == "ticket-message"){
+ //ticket message
+ await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:true})
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:ticket-message").build("other",{guild,channel,user,ticket}))
- }else if (originalSource == "pin-message"){
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:false})
- await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build("other",{guild,channel,user,ticket,reason}))
- }else{
- await instance.defer("update",false)
- await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalSource,{guild,channel,user,ticket,reason,sendMessage:true})
+
+ }else if (originalMsgType == "pin-message"){
+ //converted to unpin message
+ await opendiscord.actions.get("opendiscord:unpin-ticket").run(originalMsgType,{guild,channel,user,ticket,reason:null,sendMessage:false})
+ const sentMsg = await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:unpin-message").build(originalMsgType,{guild,channel,user,ticket,reason}))
+ if (sentMsg.success) await interactiveMsgState.setMsgState({channel,message:sentMsg.message},{
+ messageType:"unpin-message",
+ messageOrigin:originalMsgOrigin,
+ messageAuthor:user.id,
+ messageReason:reason
+ },sentMsg.ephemeral)
}
})
])
diff --git a/src/components/_INFO.md b/src/components/_INFO.md
new file mode 100644
index 0000000..ccf360e
--- /dev/null
+++ b/src/components/_INFO.md
@@ -0,0 +1,13 @@
+Open Discord Components:
+------------------------
+
+The "Components" system will be the new way of creating message and modal templates in Open Discord with support for Discord components v2.
+
+Messages, embeds, modals, buttons, etc are currently constructed using the "Builders" system located in `./src/builders/...`.
+
+This will be replaced with the new component factories in `./src/components/...`.
+
+### Timing
+Messages, modals & components will slowly be migrated to the new system during upcoming updates. The full migration will happen after `Open Ticket v4.3` and the HTML Transcripts v3 are ready for it.
+
+For more information, contact [DJj123dj](https://github.com/DJj123dj) on Discord, Github or via email
\ No newline at end of file
diff --git a/src/components/modals.ts b/src/components/modals.ts
new file mode 100644
index 0000000..c1ed285
--- /dev/null
+++ b/src/components/modals.ts
@@ -0,0 +1,302 @@
+///////////////////////////////////////
+//REGISTER MODAL COMPONENTS
+///////////////////////////////////////
+import {opendiscord, api, utilities} from "../index.js"
+import * as discord from "discord.js"
+
+const modals = opendiscord.components.modals
+const lang = opendiscord.languages
+const generalConfig = opendiscord.configs.get("opendiscord:general")
+
+export async function registerModalComponents(){
+ //TICKET QUESTIONS
+ modals.add(new api.ODComponentFactory("opendiscord:ticket-questions"))
+ modals.get("opendiscord:ticket-questions").workers.add(
+ new api.ODWorker("opendiscord:ticket-questions",0,(instance,params,origin) => {
+ const {option} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:questions-modal",{
+ customId:"od:ticket-questions|"+option.id.value+"|"+origin,
+ title:lang.getTranslation("params.uppercase.ticket")+": "+(option.exists("opendiscord:name")) ? option.get("opendiscord:name").value : option.id.value
+ }))
+
+ for (const questionId of option.get("opendiscord:questions").value){
+ const question = opendiscord.questions.get(questionId)
+ if (!question) continue
+
+ if (question instanceof api.ODShortQuestion){
+ //SHORT QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODShortInputComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
+ minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
+ maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODParagraphQuestion){
+ //PARAGRAPH QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODParagraphInputComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
+ minLength:(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-min").value : undefined,
+ maxLength:Math.min(1024-6,(question.get("opendiscord:length-enabled").value) ? question.get("opendiscord:length-max").value : (1024-6)) //embed field limit - 6x` characters
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODDropdownQuestion){
+ //DROPDOWN QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODDropdownComponent(question.id.value,{
+ type:"string",
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ placeholder:(question.get("opendiscord:placeholder").value) ? question.get("opendiscord:placeholder").value : undefined,
+ maxValues:1,
+ options:question.get("opendiscord:choices").value.map((choice) => ({
+ label:choice.title,
+ emoji:choice.emoji,
+ description:choice.description,
+ value:choice.title
+ }))
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODRadioSelectQuestion){
+ //RADIO SELECT QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODRadioGroupComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ options:question.get("opendiscord:choices").value.map((choice) => ({
+ label:choice.title,
+ default:choice.selectedByDefault,
+ description:choice.description,
+ value:choice.title
+ }))
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODCheckboxSelectQuestion){
+ //CHECKBOX SELECT QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODCheckboxGroupComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ minValues:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-min").value : undefined,
+ maxValues:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-max").value : undefined,
+ options:question.get("opendiscord:choices").value.map((choice) => ({
+ label:choice.title,
+ default:choice.selectedByDefault,
+ description:choice.description,
+ value:choice.title
+ }))
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODFileUploadQuestion){
+ //FILE UPLOAD QUESTION
+ const component = new api.ODLabelComponent(question.id.value,{
+ title:question.get("opendiscord:name").value,
+ description:(question.get("opendiscord:description").value) ? question.get("opendiscord:description").value : undefined,
+ })
+ component.setComponent(new api.ODFileUploadComponent(question.id.value,{
+ customId:question.id.value,
+ required:question.get("opendiscord:required").value,
+ minAmount:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-min").value : undefined,
+ maxAmount:(question.get("opendiscord:limits-enabled").value) ? question.get("opendiscord:limits-max").value : undefined,
+ }))
+ modal.addComponent(component,"end")
+ }else if (question instanceof api.ODTextDisplayQuestion){
+ //TEXT DISPLAY QUESTION
+ const component = new api.ODTextComponent(question.id.value,{
+ content:question.get("opendiscord:text-contents").value
+ })
+ modal.addComponent(component,"end")
+ }
+ }
+ })
+ )
+
+ //CLOSE TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:close-ticket-reason"))
+ modals.get("opendiscord:close-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:close-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:close-ticket-reason",{
+ customId:"od:close-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.close")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.closePlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //REOPEN TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:reopen-ticket-reason"))
+ modals.get("opendiscord:reopen-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:reopen-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:reopen-ticket-reason",{
+ customId:"od:reopen-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.reopen")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.reopenPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //DELETE TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:delete-ticket-reason"))
+ modals.get("opendiscord:delete-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:delete-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:delete-ticket-reason",{
+ customId:"od:delete-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.delete")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.deletePlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //CLAIM TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:claim-ticket-reason"))
+ modals.get("opendiscord:claim-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:claim-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:claim-ticket-reason",{
+ customId:"od:claim-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.claim")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.claimPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //UNCLAIM TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:unclaim-ticket-reason"))
+ modals.get("opendiscord:unclaim-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:unclaim-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:unclaim-ticket-reason",{
+ customId:"od:unclaim-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.unclaim")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.unclaimPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //PIN TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:pin-ticket-reason"))
+ modals.get("opendiscord:pin-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:pin-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:pin-ticket-reason",{
+ customId:"od:pin-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.pin")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.pinPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+
+ //UNPIN TICKET REASON
+ modals.add(new api.ODComponentFactory("opendiscord:unpin-ticket-reason"))
+ modals.get("opendiscord:unpin-ticket-reason").workers.add(
+ new api.ODWorker("opendiscord:unpin-ticket-reason",0,async (instance,params,origin) => {
+ const {channel,message} = params
+
+ const modal = instance.setComponent(new api.ODModalComponent("opendiscord:unpin-ticket-reason",{
+ customId:"od:unpin-ticket-reason|"+channel.id+"|"+message.id,
+ title:lang.getTranslation("actions.buttons.unpin")
+ }))
+
+ const reasonComponent = new api.ODLabelComponent("reason",{
+ title:lang.getTranslation("params.uppercase.reason"),
+ description:lang.getTranslation("actions.modal.unpinPlaceholder")
+ })
+ reasonComponent.setComponent(new api.ODParagraphInputComponent("reason",{
+ customId:"reason",
+ required:true,
+ placeholder:lang.getTranslation("params.uppercase.reason")
+ }))
+ modal.addComponent(reasonComponent,"end")
+ })
+ )
+}
\ No newline at end of file
diff --git a/src/components/verifybarModifiers.ts b/src/components/verifybarModifiers.ts
new file mode 100644
index 0000000..60d35ed
--- /dev/null
+++ b/src/components/verifybarModifiers.ts
@@ -0,0 +1,138 @@
+///////////////////////////////////////
+//VERIFYBAR MESSAGE MODIFIERS
+///////////////////////////////////////
+import {opendiscord, api, utilities} from "../index.js"
+import * as discord from "discord.js"
+
+const modifiers = opendiscord.components.modifiers
+const lang = opendiscord.languages
+const generalConfig = opendiscord.configs.get("opendiscord:general")
+
+export async function addVerifyButton(instance:api.ODMessageInstance|api.ODComponentFactoryInstance,params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:api.ODVerifyBar},defaultButtonType:"✅"|"❌",useDefaultLabels:boolean,verifyButtonId:string,customLabel?:string,customColor?:api.ODValidButtonColor,customEmoji?:string){
+ const {guild,channel,user,verifybar} = params
+ if (instance instanceof api.ODMessageInstance){
+ //message builders
+ instance.addComponent(await opendiscord.builders.buttons.getSafe("opendiscord:verifybar-button").build("verifybar",{
+ guild,channel,user,verifybar,
+ defaultButtonType,useDefaultLabels,customColor,customEmoji,customLabel,
+ verifyButtonId
+ }))
+ }else{
+ //message components
+ throw new api.ODSystemError("registerAllVerifyBarModifiers addVerifyButton() => verifybar doesn't support ODComponents v2 yet!")
+ //const message = instance.getComponent()
+ //if (!message) return
+ //const actionRow: api.ODActionRowComponent|null = message.getComponentsOfType("action-row")[0]
+ //if (actionRow) actionRow.addComponent(new api.ODButtonComponent("opendiscord:verifybar-button",{
+ // //TODO
+ //}),"end")
+ }
+}
+
+export async function registerAllVerifyBarModifiers(){
+ //CLOSE TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:close-ticket-verifybar"))
+ modifiers.get("opendiscord:close-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:close-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or close with reason
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.close"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ }))
+
+ //REOPEN TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:reopen-ticket-verifybar"))
+ modifiers.get("opendiscord:reopen-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:reopen-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or reopen with reason
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.reopen"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ }))
+
+ //DELETE TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:delete-ticket-verifybar"))
+ modifiers.get("opendiscord:delete-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:delete-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or delete with reason or without transcript
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.delete"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ if (generalConfig.data.ticketSystem.enableDeleteWithoutTranscript) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithoutTranscript,lang.getTranslation("actions.buttons.withoutTranscript"),"red","📄")
+ }))
+
+ //CLAIM TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:claim-ticket-verifybar"))
+ modifiers.get("opendiscord:claim-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:claim-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or claim with reason
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.claim"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ }))
+
+ //UNCLAIM TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:unclaim-ticket-verifybar"))
+ modifiers.get("opendiscord:unclaim-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:unclaim-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or unclaim with reason
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.unclaim"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ }))
+
+ //PIN TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:pin-ticket-verifybar"))
+ modifiers.get("opendiscord:pin-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:pin-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or pin with reason
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.pin"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ }))
+
+ //UNPIN TICKET VERIFYBAR
+ modifiers.add(new api.ODMessageComponentModifier("opendiscord:unpin-ticket-verifybar"))
+ modifiers.get("opendiscord:unpin-ticket-verifybar").workers.add(new api.ODWorker("opendiscord:unpin-ticket-verifybar",100,async (instance,params,origin,cancel) => {
+ if (instance instanceof api.ODMessageInstance){
+ instance.data.components = [] //clear actionrow
+ }else{
+ throw new api.ODSystemError("registerAllVerifyBarModifiers()... => verifybars don't support ODComponents v2 yet!")
+ }
+
+ //cancel, accept or unpin with reason
+ await addVerifyButton(instance,params,"❌",true,api.ODVerifyButtonId.Cancel)
+ await addVerifyButton(instance,params,"✅",true,api.ODVerifyButtonId.Accept,lang.getTranslation("actions.buttons.unpin"))
+ if (generalConfig.data.ticketSystem.enableTicketActionWithReason) await addVerifyButton(instance,params,"✅",false,api.ODVerifyButtonId.AcceptWithReason,lang.getTranslation("actions.buttons.withReason"),"blue","✏️")
+ }))
+}
\ No newline at end of file
diff --git a/src/core/api.ts b/src/core/api.ts
new file mode 100644
index 0000000..d9df578
--- /dev/null
+++ b/src/core/api.ts
@@ -0,0 +1,43 @@
+//EXPORT FRAMEWORK
+export * from "@open-discord-bots/framework/api"
+
+//EXPORT OPEN TICKET MAPPINGS
+export * from "./mappings/action.js"
+export * from "./mappings/base.js"
+export * from "./mappings/builder.js"
+export * from "./mappings/checker.js"
+export * from "./mappings/client.js"
+export * from "./mappings/code.js"
+export * from "./mappings/component.js"
+export * from "./mappings/config.js"
+export * from "./mappings/console.js"
+export * from "./mappings/cooldown.js"
+export * from "./mappings/database.js"
+export * from "./mappings/event.js"
+export * from "./mappings/flag.js"
+export * from "./mappings/fuse.js"
+export * from "./mappings/helpmenu.js"
+export * from "./mappings/language.js"
+export * from "./mappings/permission.js"
+export * from "./mappings/plugin.js"
+export * from "./mappings/post.js"
+export * from "./mappings/progressbar.js"
+export * from "./mappings/responder.js"
+export * from "./mappings/session.js"
+export * from "./mappings/startscreen.js"
+export * from "./mappings/state.js"
+export * from "./mappings/statistic.js"
+export * from "./mappings/verifybar.js"
+
+//EXPORT OPENTICKET MODULES
+export * from "./api/blacklist.js"
+export * from "./api/option.js"
+export * from "./api/panel.js"
+export * from "./api/priority.js"
+export * from "./api/question.js"
+export * from "./api/role.js"
+export * from "./api/ticket.js"
+export * from "./api/transcript.js"
+
+//EXPORT MAIN MODULE
+export { ODOpenTicketMain } from "./main.js"
\ No newline at end of file
diff --git a/src/core/api/api.ts b/src/core/api/api.ts
deleted file mode 100644
index 7286d8f..0000000
--- a/src/core/api/api.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-//MAIN MODULE
-export * from "./main"
-
-//BASE MODULES
-export * from "./modules/base"
-export * from "./modules/event"
-export * from "./modules/config"
-export * from "./modules/database"
-export * from "./modules/language"
-export * from "./modules/flag"
-export * from "./modules/console"
-export * from "./modules/defaults"
-export * from "./modules/plugin"
-export * from "./modules/checker"
-export * from "./modules/client"
-export * from "./modules/worker"
-export * from "./modules/builder"
-export * from "./modules/responder"
-export * from "./modules/action"
-export * from "./modules/permission"
-export * from "./modules/helpmenu"
-export * from "./modules/session"
-export * from "./modules/stat"
-export * from "./modules/code"
-export * from "./modules/cooldown"
-export * from "./modules/post"
-export * from "./modules/verifybar"
-export * from "./modules/progressbar"
-export * from "./modules/startscreen"
-
-//OPENTICKET DEFAULT MODULES
-export * from "./defaults/base"
-export * from "./defaults/event"
-export * from "./defaults/config"
-export * from "./defaults/database"
-export * from "./defaults/plugin"
-export * from "./defaults/checker"
-export * from "./defaults/client"
-export * from "./defaults/language"
-export * from "./defaults/builder"
-export * from "./defaults/responder"
-export * from "./defaults/action"
-export * from "./defaults/flag"
-export * from "./defaults/permission"
-export * from "./defaults/helpmenu"
-export * from "./defaults/session"
-export * from "./defaults/stat"
-export * from "./defaults/worker"
-export * from "./defaults/code"
-export * from "./defaults/cooldown"
-export * from "./defaults/post"
-export * from "./defaults/progressbar"
-export * from "./defaults/startscreen"
-export * from "./defaults/console"
-
-//OPENTICKET MODULES
-export * from "./openticket/question"
-export * from "./openticket/option"
-export * from "./openticket/panel"
-export * from "./openticket/ticket"
-export * from "./openticket/blacklist"
-export * from "./openticket/transcript"
-export * from "./openticket/role"
-export * from "./openticket/priority"
\ No newline at end of file
diff --git a/src/core/api/openticket/blacklist.ts b/src/core/api/blacklist.ts
similarity index 69%
rename from src/core/api/openticket/blacklist.ts
rename to src/core/api/blacklist.ts
index d7dedcd..391f526 100644
--- a/src/core/api/openticket/blacklist.ts
+++ b/src/core/api/blacklist.ts
@@ -1,8 +1,7 @@
///////////////////////////////////////
//OPENTICKET BLACKLIST MODULE
///////////////////////////////////////
-import { ODManager, ODManagerData, ODValidId } from "../modules/base"
-import { ODDebugger } from "../modules/console"
+import * as api from "@open-discord-bots/framework/api"
/**## ODBlacklist `class`
* This is an Open Ticket blacklisted user.
@@ -11,22 +10,22 @@ import { ODDebugger } from "../modules/console"
*
* Create this class & add it to the `ODBlacklistManager` to blacklist someone!
*/
-export class ODBlacklist extends ODManagerData {
+export class ODBlacklist extends api.ODManagerData {
/**The reason why this user got blacklisted. (optional) */
- #reason: string|null
+ private rawReason: string|null
- constructor(id:ODValidId,reason:string|null){
+ constructor(id:api.ODValidId,reason:string|null){
super(id)
- this.#reason = reason
+ this.rawReason = reason
}
/**The reason why this user got blacklisted. (optional) */
set reason(reason:string|null) {
- this.#reason = reason
+ this.rawReason = reason
this._change()
}
get reason(){
- return this.#reason
+ return this.rawReason
}
}
@@ -37,8 +36,8 @@ export class ODBlacklist extends ODManagerData {
*
* All `ODBlacklist`'s added, removed & edited in this list will be synced automatically with the database.
*/
-export class ODBlacklistManager extends ODManager {
- constructor(debug:ODDebugger){
+export class ODBlacklistManager extends api.ODManager {
+ constructor(debug:api.ODDebugger){
super(debug,"blacklist")
}
}
\ No newline at end of file
diff --git a/src/core/api/defaults/base.ts b/src/core/api/defaults/base.ts
deleted file mode 100644
index 2cfa279..0000000
--- a/src/core/api/defaults/base.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-///////////////////////////////////////
-//BASE MODULE
-///////////////////////////////////////
-import { ODVersion, ODVersionManager, ODValidId } from "../modules/base"
-
-/**## ODVersionManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODVersionManager` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODVersionManagerIds_Default {
- "opendiscord:version":ODVersion,
- "opendiscord:last-version":ODVersion,
- "opendiscord:api":ODVersion,
- "opendiscord:transcripts":ODVersion,
- "opendiscord:livestatus":ODVersion
-}
-
-/**## ODFlagManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODFlagManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.flags`!
- */
-export class ODVersionManager_Default extends ODVersionManager {
- get(id:VersionId): ODVersionManagerIds_Default[VersionId]
- get(id:ODValidId): ODVersion|null
-
- get(id:ODValidId): ODVersion|null {
- return super.get(id)
- }
-
- remove(id:VersionId): ODVersionManagerIds_Default[VersionId]
- remove(id:ODValidId): ODVersion|null
-
- remove(id:ODValidId): ODVersion|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODVersionManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/builder.ts b/src/core/api/defaults/builder.ts
deleted file mode 100644
index 96c652b..0000000
--- a/src/core/api/defaults/builder.ts
+++ /dev/null
@@ -1,549 +0,0 @@
-///////////////////////////////////////
-//DEFAULT BUILDER MODULE
-///////////////////////////////////////
-import { ODValidButtonColor, ODValidId } from "../modules/base"
-import { ODBuilderManager, ODButton, ODButtonInstance, ODButtonManager, ODDropdown, ODDropdownInstance, ODDropdownManager, ODEmbed, ODEmbedInstance, ODEmbedManager, ODFile, ODFileInstance, ODFileManager, ODMessage, ODMessageInstance, ODMessageManager, ODModal, ODModalInstance, ODModalManager } from "../modules/builder"
-import { ODWorkerManager_Default } from "./worker"
-import { ODTicket, ODTicketClearFilter } from "../openticket/ticket"
-import { ODPermissionEmbedType } from "../defaults/permission"
-import { ODTextCommandErrorInvalidOption, ODTextCommandErrorMissingOption, ODTextCommandErrorUnknownCommand } from "../modules/client"
-import { ODPanel } from "../openticket/panel"
-import { ODRoleOption, ODTicketOption, ODWebsiteOption } from "../openticket/option"
-import { ODVerifyBar } from "../modules/verifybar"
-import * as discord from "discord.js"
-import { ODTranscriptCompiler, ODTranscriptCompilerCompileResult } from "../openticket/transcript"
-import { ODRole, ODRoleUpdateResult } from "../openticket/role"
-import { ODPriorityLevel } from "../openticket/priority"
-
-/**## ODBuilderManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODBuilderManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders`!
- */
-export class ODBuilderManager_Default extends ODBuilderManager {
- declare buttons: ODButtonManager_Default
- declare dropdowns: ODDropdownManager_Default
- declare files: ODFileManager_Default
- declare embeds: ODEmbedManager_Default
- declare messages: ODMessageManager_Default
- declare modals: ODModalManager_Default
-}
-
-/**## ODButtonManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODButtonManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODButtonManagerIds_Default {
- "opendiscord:verifybar-success":{source:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,customData?:string,customColor?:ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-success"},
- "opendiscord:verifybar-failure":{source:"verifybar"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,customData?:string,customColor?:ODValidButtonColor,customLabel?:string,customEmoji?:string},workers:"opendiscord:verifybar-failure"},
-
- "opendiscord:error-ticket-deprecated-transcript":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{},workers:"opendiscord:error-ticket-deprecated-transcript"},
-
- "opendiscord:help-menu-previous":{source:"text"|"slash"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu-previous"},
- "opendiscord:help-menu-next":{source:"text"|"slash"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu-next"},
- "opendiscord:help-menu-page":{source:"text"|"slash"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu-page"}
- "opendiscord:help-menu-switch":{source:"text"|"slash"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu-switch"},
-
- "opendiscord:ticket-option":{source:"slash"|"text"|"auto-update"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel,option:ODTicketOption},workers:"opendiscord:ticket-option"},
- "opendiscord:website-option":{source:"slash"|"text"|"auto-update"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel,option:ODWebsiteOption},workers:"opendiscord:website-option"},
- "opendiscord:role-option":{source:"slash"|"text"|"auto-update"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel,option:ODRoleOption},workers:"opendiscord:role-option"}
-
- "opendiscord:visit-ticket":{source:"ticket-created"|"dm"|"logs"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:visit-ticket"},
-
- "opendiscord:close-ticket":{source:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:close-ticket"},
- "opendiscord:delete-ticket":{source:"ticket-message"|"close-message"|"autoclose-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:delete-ticket"},
- "opendiscord:reopen-ticket":{source:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:reopen-ticket"},
- "opendiscord:claim-ticket":{source:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:claim-ticket"},
- "opendiscord:unclaim-ticket":{source:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:unclaim-ticket"},
- "opendiscord:pin-ticket":{source:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:pin-ticket"},
- "opendiscord:unpin-ticket":{source:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:unpin-ticket"},
-
- "opendiscord:transcript-html-visit":{source:"channel"|"creator-dm"|"participant-dm"|"active-admin-dm"|"every-admin-dm"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{url:string,availableUntil:Date},{auth:string}>,result:ODTranscriptCompilerCompileResult<{url:string,availableUntil:Date}>},workers:"opendiscord:transcript-html-visit"},
- "opendiscord:transcript-error-retry":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,reason:string|null},workers:"opendiscord:transcript-error-retry"},
- "opendiscord:transcript-error-continue":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,reason:string|null},workers:"opendiscord:transcript-error-continue"},
-
- "opendiscord:clear-continue":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-continue"},
-}
-
-/**## ODButtonManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODButtonManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders.buttons`!
- */
-export class ODButtonManager_Default extends ODButtonManager {
- get(id:ButtonId): ODButton_Default
- get(id:ODValidId): ODButton|null
-
- get(id:ODValidId): ODButton|null {
- return super.get(id)
- }
-
- remove(id:ButtonId): ODButton_Default
- remove(id:ODValidId): ODButton|null
-
- remove(id:ODValidId): ODButton|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODButtonManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- getSafe(id:ButtonId): ODButton_Default
- getSafe(id:ODValidId): ODButton
-
- getSafe(id:ODValidId): ODButton {
- return super.getSafe(id)
- }
-}
-
-/**## ODButton_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODButton class.
- * It doesn't add any extra features!
- *
- * This default class is made for the default `ODButton`'s!
- */
-export class ODButton_Default extends ODButton {
- declare workers: ODWorkerManager_Default
-}
-
-/**## ODDropdownManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODDropdownManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODDropdownManagerIds_Default {
- "opendiscord:panel-dropdown-tickets":{source:"slash"|"text"|"auto-update"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel,options:ODTicketOption[]},workers:"opendiscord:panel-dropdown-tickets"}
-}
-
-/**## ODDropdownManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODDropdownManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders.dropdowns`!
- */
-export class ODDropdownManager_Default extends ODDropdownManager {
- get(id:DropdownId): ODDropdown_Default
- get(id:ODValidId): ODDropdown|null
-
- get(id:ODValidId): ODDropdown|null {
- return super.get(id)
- }
-
- remove(id:DropdownId): ODDropdown_Default
- remove(id:ODValidId): ODDropdown|null
-
- remove(id:ODValidId): ODDropdown|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODDropdownManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- getSafe(id:DropdownId): ODDropdown_Default
- getSafe(id:ODValidId): ODDropdown
-
- getSafe(id:ODValidId): ODDropdown {
- return super.getSafe(id)
- }
-}
-
-/**## ODDropdown_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODDropdown class.
- * It doesn't add any extra features!
- *
- * This default class is made for the default `ODDropdown`'s!
- */
-export class ODDropdown_Default extends ODDropdown {
- declare workers: ODWorkerManager_Default
-}
-
-/**## ODFileManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODFileManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODFileManagerIds_Default {
- "opendiscord:text-transcript":{source:"channel"|"creator-dm"|"participant-dm"|"active-admin-dm"|"every-admin-dm"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,result:ODTranscriptCompilerCompileResult},workers:"opendiscord:text-transcript"}
-}
-
-/**## ODFileManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODFileManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders.files`!
- */
-export class ODFileManager_Default extends ODFileManager {
- get(id:FileId): ODFile_Default
- get(id:ODValidId): ODFile|null
-
- get(id:ODValidId): ODFile|null {
- return super.get(id)
- }
-
- remove(id:FileId): ODFile_Default
- remove(id:ODValidId): ODFile|null
-
- remove(id:ODValidId): ODFile|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODFileManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- getSafe(id:FileId): ODFile_Default
- getSafe(id:ODValidId): ODFile
-
- getSafe(id:ODValidId): ODFile {
- return super.getSafe(id)
- }
-}
-
-/**## ODFile_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODFile class.
- * It doesn't add any extra features!
- *
- * This default class is made for the default `ODFile`'s!
- */
-export class ODFile_Default extends ODFile {
- declare workers: ODWorkerManager_Default
-}
-
-/**## ODEmbedManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODEmbedManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODEmbedManagerIds_Default {
- "opendiscord:error":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:string,layout:"simple"|"advanced",customTitle?:string},workers:"opendiscord:error"},
- "opendiscord:error-option-missing":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorMissingOption},workers:"opendiscord:error-option-missing"},
- "opendiscord:error-option-invalid":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorInvalidOption},workers:"opendiscord:error-option-invalid"},
- "opendiscord:error-unknown-command":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorUnknownCommand},workers:"opendiscord:error-unknown-command"},
- "opendiscord:error-no-permissions":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,permissions:ODPermissionEmbedType[]},workers:"opendiscord:error-no-permissions"},
- "opendiscord:error-no-permissions-cooldown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,until?:Date},workers:"opendiscord:error-no-permissions-cooldown"},
- "opendiscord:error-no-permissions-blacklisted":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-no-permissions-blacklisted"},
- "opendiscord:error-no-permissions-limits":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,limit:"global"|"global-user"|"option"|"option-user"},workers:"opendiscord:error-no-permissions-limits"},
- "opendiscord:error-responder-timeout":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-responder-timeout"},
- "opendiscord:error-ticket-unknown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-ticket-unknown"},
- "opendiscord:error-ticket-deprecated":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-ticket-deprecated"},
- "opendiscord:error-option-unknown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-option-unknown"},
- "opendiscord:error-panel-unknown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-panel-unknown"},
- "opendiscord:error-not-in-guild":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-not-in-guild"},
- "opendiscord:error-channel-rename":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"ticket-pin"|"ticket-unpin"|"ticket-rename"|"ticket-move"|"ticket-priority"|"ticket-transfer"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,originalName:string,newName:string},workers:"opendiscord:error-channel-rename"},
- "opendiscord:error-ticket-busy":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-ticket-busy"},
-
- "opendiscord:help-menu":{source:"text"|"slash"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu"},
-
- "opendiscord:stats-global":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:stats-global"},
- "opendiscord:stats-ticket":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,scopeData:ODTicket},workers:"opendiscord:stats-ticket"},
- "opendiscord:stats-user":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,scopeData:discord.User},workers:"opendiscord:stats-user"|"opendiscord:easter-egg"},
- "opendiscord:stats-reset":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,reason:string|null},workers:"opendiscord:stats-reset"},
- "opendiscord:stats-ticket-unknown":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,id:string},workers:"opendiscord:stats-ticket-unknown"},
-
- "opendiscord:panel":{source:"slash"|"text"|"auto-update"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel},workers:"opendiscord:panel"},
- "opendiscord:ticket-created":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created"},
- "opendiscord:ticket-created-dm":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-dm"},
- "opendiscord:ticket-created-logs":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-logs"},
- "opendiscord:ticket-message":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-message"},
- "opendiscord:close-message":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"autoclose"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:close-message"},
- "opendiscord:reopen-message":{source:"slash"|"text"|"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:reopen-message"},
- "opendiscord:delete-message":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:delete-message"},
- "opendiscord:claim-message":{source:"slash"|"text"|"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:claim-message"},
- "opendiscord:unclaim-message":{source:"slash"|"text"|"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unclaim-message"},
- "opendiscord:pin-message":{source:"slash"|"text"|"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:pin-message"},
- "opendiscord:unpin-message":{source:"slash"|"text"|"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unpin-message"},
- "opendiscord:rename-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:string},workers:"opendiscord:rename-message"},
- "opendiscord:move-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:ODTicketOption},workers:"opendiscord:move-message"},
- "opendiscord:add-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:discord.User},workers:"opendiscord:add-message"},
- "opendiscord:remove-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:discord.User},workers:"opendiscord:remove-message"},
- "opendiscord:ticket-action-dm":{source:"slash"|"text"|"ticket-message"|"close-message"|"reopen-message"|"delete-message"|"claim-message"|"unclaim-message"|"pin-message"|"unpin-message"|"autoclose-message"|"autoclose"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"close"|"reopen"|"delete"|"claim"|"unclaim"|"pin"|"unpin"|"rename"|"move"|"add"|"remove",ticket:ODTicket,reason:string|null,additionalData:null|string|discord.User|ODTicketOption},workers:"opendiscord:ticket-action-dm"},
- "opendiscord:ticket-action-logs":{source:"slash"|"text"|"ticket-message"|"close-message"|"reopen-message"|"delete-message"|"claim-message"|"unclaim-message"|"pin-message"|"unpin-message"|"autoclose-message"|"autoclose"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"close"|"reopen"|"delete"|"claim"|"unclaim"|"pin"|"unpin"|"rename"|"move"|"add"|"remove",ticket:ODTicket,reason:string|null,additionalData:null|string|discord.User|ODTicketOption},workers:"opendiscord:ticket-action-logs"},
-
- "opendiscord:blacklist-view":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:blacklist-view"},
- "opendiscord:blacklist-get":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,data:discord.User},workers:"opendiscord:blacklist-get"},
- "opendiscord:blacklist-add":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,data:discord.User,reason:string|null},workers:"opendiscord:blacklist-add"},
- "opendiscord:blacklist-remove":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,data:discord.User,reason:string|null},workers:"opendiscord:blacklist-remove"}
- "opendiscord:blacklist-dm":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"add"|"remove",data:discord.User,reason:string|null},workers:"opendiscord:blacklist-dm"},
- "opendiscord:blacklist-logs":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"add"|"remove",data:discord.User,reason:string|null},workers:"opendiscord:blacklist-logs"},
-
- "opendiscord:transcript-text-ready":{source:"channel"|"creator-dm"|"participant-dm"|"active-admin-dm"|"every-admin-dm"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{contents:string},null>,result:ODTranscriptCompilerCompileResult<{contents:string}>},workers:"opendiscord:transcript-text-ready"},
- "opendiscord:transcript-html-ready":{source:"channel"|"creator-dm"|"participant-dm"|"active-admin-dm"|"every-admin-dm"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{url:string,availableUntil:Date},{auth:string}>,result:ODTranscriptCompilerCompileResult<{url:string,availableUntil:Date}>},workers:"opendiscord:transcript-html-ready"},
- "opendiscord:transcript-html-progress":{source:"channel"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{url:string,availableUntil:Date},{auth:string}>,remaining:number},workers:"opendiscord:transcript-html-progress"},
- "opendiscord:transcript-error":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,reason:string|null},workers:"opendiscord:transcript-error"},
-
- "opendiscord:reaction-role":{source:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role"},
- "opendiscord:reaction-role-dm":{source:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-dm"},
- "opendiscord:reaction-role-logs":{source:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-logs"},
-
- "opendiscord:clear-verify-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-verify-message"},
- "opendiscord:clear-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-message"},
- "opendiscord:clear-logs":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-logs"},
-
- "opendiscord:autoclose-message":{source:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autoclose-message"},
- "opendiscord:autodelete-message":{source:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autodelete-message"},
- "opendiscord:autoclose-enable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autoclose-enable"},
- "opendiscord:autodelete-enable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autodelete-enable"},
- "opendiscord:autoclose-disable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:autoclose-disable"},
- "opendiscord:autodelete-disable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:autodelete-disable"},
-
- "opendiscord:topic-set":{source:"slash"|"text"|"ticket-action"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,topic:string},workers:"opendiscord:topic-set"},
- "opendiscord:priority-set":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,priority:ODPriorityLevel,reason:string|null},workers:"opendiscord:priority-set"},
- "opendiscord:priority-get":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,priority:ODPriorityLevel},workers:"opendiscord:priority-get"},
- "opendiscord:transfer-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,oldCreator:discord.User,newCreator:discord.User,reason:string|null},workers:"opendiscord:transfer-message"},
-}
-
-/**## ODEmbedManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODEmbedManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders.embeds`!
- */
-export class ODEmbedManager_Default extends ODEmbedManager {
- get(id:EmbedId): ODEmbed_Default
- get(id:ODValidId): ODEmbed|null
-
- get(id:ODValidId): ODEmbed|null {
- return super.get(id)
- }
-
- remove(id:EmbedId): ODEmbed_Default
- remove(id:ODValidId): ODEmbed|null
-
- remove(id:ODValidId): ODEmbed|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODEmbedManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- getSafe(id:EmbedId): ODEmbed_Default
- getSafe(id:ODValidId): ODEmbed
-
- getSafe(id:ODValidId): ODEmbed {
- return super.getSafe(id)
- }
-}
-
-/**## ODEmbed_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODEmbed class.
- * It doesn't add any extra features!
- *
- * This default class is made for the default `ODEmbed`'s!
- */
-export class ODEmbed_Default extends ODEmbed {
- declare workers: ODWorkerManager_Default
-}
-
-/**## ODMessageManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODMessageManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODMessageManagerIds_Default {
- "opendiscord:verifybar-ticket-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-ticket-message"},
- "opendiscord:verifybar-close-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-close-message"},
- "opendiscord:verifybar-reopen-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-reopen-message"},
- "opendiscord:verifybar-claim-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-claim-message"},
- "opendiscord:verifybar-unclaim-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unclaim-message"},
- "opendiscord:verifybar-pin-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-pin-message"},
- "opendiscord:verifybar-unpin-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-unpin-message"}
- "opendiscord:verifybar-autoclose-message":{source:"verifybar",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,verifybar:ODVerifyBar,originalMessage:discord.Message},workers:"opendiscord:verifybar-autoclose-message"}
-
- "opendiscord:error":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:string,layout:"simple"|"advanced",customTitle?:string},workers:"opendiscord:error"},
- "opendiscord:error-option-missing":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorMissingOption},workers:"opendiscord:error-option-missing"},
- "opendiscord:error-option-invalid":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorInvalidOption},workers:"opendiscord:error-option-invalid"},
- "opendiscord:error-unknown-command":{source:"slash"|"text"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,error:ODTextCommandErrorUnknownCommand},workers:"opendiscord:error-unknown-command"},
- "opendiscord:error-no-permissions":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,permissions:ODPermissionEmbedType[]},workers:"opendiscord:error-no-permissions"},
- "opendiscord:error-no-permissions-cooldown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,until?:Date},workers:"opendiscord:error-no-permissions-cooldown"},
- "opendiscord:error-no-permissions-blacklisted":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-no-permissions-blacklisted"},
- "opendiscord:error-no-permissions-limits":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,limit:"global"|"global-user"|"option"|"option-user"},workers:"opendiscord:error-no-permissions-limits"},
- "opendiscord:error-responder-timeout":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-responder-timeout"},
- "opendiscord:error-ticket-unknown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-ticket-unknown"},
- "opendiscord:error-ticket-deprecated":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-ticket-deprecated"},
- "opendiscord:error-option-unknown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-option-unknown"},
- "opendiscord:error-panel-unknown":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-panel-unknown"},
- "opendiscord:error-not-in-guild":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-not-in-guild"},
- "opendiscord:error-channel-rename":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"ticket-pin"|"ticket-unpin"|"ticket-rename"|"ticket-move"|"ticket-priority"|"ticket-transfer"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User,originalName:string,newName:string},workers:"opendiscord:error-channel-rename"},
- "opendiscord:error-ticket-busy":{source:"slash"|"text"|"button"|"dropdown"|"modal"|"other",params:{guild:discord.Guild|null,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:error-ticket-busy"},
-
- "opendiscord:help-menu":{source:"slash"|"text"|"button"|"other",params:{mode:"slash"|"text",page:number},workers:"opendiscord:help-menu"},
-
- "opendiscord:stats-global":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:stats-global"},
- "opendiscord:stats-ticket":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,scopeData:ODTicket},workers:"opendiscord:stats-ticket"},
- "opendiscord:stats-user":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,scopeData:discord.User},workers:"opendiscord:stats-user"|"opendiscord:easter-egg"},
- "opendiscord:stats-reset":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,reason:string|null},workers:"opendiscord:stats-reset"},
- "opendiscord:stats-ticket-unknown":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,id:string},workers:"opendiscord:stats-ticket-unknown"},
-
- "opendiscord:panel":{source:"slash"|"text"|"auto-update"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel},workers:"opendiscord:panel-layout"|"opendiscord:panel-components"},
- "opendiscord:panel-ready":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,panel:ODPanel},workers:"opendiscord:panel-ready"},
-
- "opendiscord:ticket-created":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created"},
- "opendiscord:ticket-created-dm":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-dm"},
- "opendiscord:ticket-created-logs":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-created-logs"},
- "opendiscord:ticket-message":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:ticket-message-layout"|"opendiscord:ticket-message-components"|"opendiscord:ticket-message-disable-components"},
- "opendiscord:close-message":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"autoclose"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:close-message"},
- "opendiscord:reopen-message":{source:"slash"|"text"|"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:reopen-message"},
- "opendiscord:delete-message":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:delete-message"},
- "opendiscord:claim-message":{source:"slash"|"text"|"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:claim-message"},
- "opendiscord:unclaim-message":{source:"slash"|"text"|"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unclaim-message"},
- "opendiscord:pin-message":{source:"slash"|"text"|"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:pin-message"},
- "opendiscord:unpin-message":{source:"slash"|"text"|"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:unpin-message"},
- "opendiscord:rename-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:string},workers:"opendiscord:rename-message"},
- "opendiscord:move-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:ODTicketOption},workers:"opendiscord:move-message"},
- "opendiscord:add-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:discord.User},workers:"opendiscord:add-message"},
- "opendiscord:remove-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null,data:discord.User},workers:"opendiscord:remove-message"},
- "opendiscord:ticket-action-dm":{source:"slash"|"text"|"ticket-message"|"close-message"|"reopen-message"|"delete-message"|"claim-message"|"unclaim-message"|"pin-message"|"unpin-message"|"autoclose-message"|"autoclose"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"close"|"reopen"|"delete"|"claim"|"unclaim"|"pin"|"unpin"|"rename"|"move"|"add"|"remove",ticket:ODTicket,reason:string|null,additionalData:null|string|discord.User|ODTicketOption},workers:"opendiscord:ticket-action-dm"},
- "opendiscord:ticket-action-logs":{source:"slash"|"text"|"ticket-message"|"close-message"|"reopen-message"|"delete-message"|"claim-message"|"unclaim-message"|"pin-message"|"unpin-message"|"autoclose-message"|"autoclose"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"close"|"reopen"|"delete"|"claim"|"unclaim"|"pin"|"unpin"|"rename"|"move"|"add"|"remove",ticket:ODTicket,reason:string|null,additionalData:null|string|discord.User|ODTicketOption},workers:"opendiscord:ticket-action-logs"},
-
- "opendiscord:blacklist-view":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User},workers:"opendiscord:blacklist-view"},
- "opendiscord:blacklist-get":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,data:discord.User},workers:"opendiscord:blacklist-get"},
- "opendiscord:blacklist-add":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,data:discord.User,reason:string|null},workers:"opendiscord:blacklist-add"},
- "opendiscord:blacklist-remove":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,data:discord.User,reason:string|null},workers:"opendiscord:blacklist-remove"},
- "opendiscord:blacklist-dm":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"add"|"remove",data:discord.User,reason:string|null},workers:"opendiscord:blacklist-dm"},
- "opendiscord:blacklist-logs":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,mode:"add"|"remove",data:discord.User,reason:string|null},workers:"opendiscord:blacklist-logs"},
-
- "opendiscord:transcript-text-ready":{source:"channel"|"creator-dm"|"participant-dm"|"active-admin-dm"|"every-admin-dm"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{contents:string},null>,result:ODTranscriptCompilerCompileResult<{contents:string}>},workers:"opendiscord:transcript-text-ready"},
- "opendiscord:transcript-html-ready":{source:"channel"|"creator-dm"|"participant-dm"|"active-admin-dm"|"every-admin-dm"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{url:string,availableUntil:Date},{auth:string}>,result:ODTranscriptCompilerCompileResult<{url:string,availableUntil:Date}>},workers:"opendiscord:transcript-html-ready"},
- "opendiscord:transcript-html-progress":{source:"channel"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler<{url:string,availableUntil:Date},{auth:string}>,remaining:number},workers:"opendiscord:transcript-html-progress"},
- "opendiscord:transcript-error":{source:"slash"|"text"|"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"autodelete"|"clear"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,compiler:ODTranscriptCompiler,reason:string|null},workers:"opendiscord:transcript-error"},
-
- "opendiscord:reaction-role":{source:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role"},
- "opendiscord:reaction-role-dm":{source:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-dm"},
- "opendiscord:reaction-role-logs":{source:"panel-button"|"other",params:{guild:discord.Guild,user:discord.User,role:ODRole,result:ODRoleUpdateResult[]},workers:"opendiscord:reaction-role-logs"},
-
- "opendiscord:clear-verify-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-verify-message"},
- "opendiscord:clear-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-message"},
- "opendiscord:clear-logs":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,filter:ODTicketClearFilter,list:string[]},workers:"opendiscord:clear-logs"},
-
- "opendiscord:autoclose-message":{source:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autoclose-message"},
- "opendiscord:autodelete-message":{source:"timeout"|"leave"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:autodelete-message"},
- "opendiscord:autoclose-enable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autoclose-enable"},
- "opendiscord:autodelete-enable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,time:number,reason:string|null},workers:"opendiscord:autodelete-enable"},
- "opendiscord:autoclose-disable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:autoclose-disable"},
- "opendiscord:autodelete-disable":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,reason:string|null},workers:"opendiscord:autodelete-disable"},
-
- "opendiscord:topic-set":{source:"slash"|"text"|"ticket-action"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,topic:string},workers:"opendiscord:topic-set"},
- "opendiscord:priority-set":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,priority:ODPriorityLevel,reason:string|null},workers:"opendiscord:priority-set"},
- "opendiscord:priority-get":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,priority:ODPriorityLevel},workers:"opendiscord:priority-get"},
- "opendiscord:transfer-message":{source:"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.GuildTextBasedChannel,user:discord.User,ticket:ODTicket,oldCreator:discord.User,newCreator:discord.User,reason:string|null},workers:"opendiscord:transfer-message"},
-}
-
-/**## ODMessageManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODMessageManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders.messages`!
- */
-export class ODMessageManager_Default extends ODMessageManager {
- get(id:MessageId): ODMessage_Default
- get(id:ODValidId): ODMessage|null
-
- get(id:ODValidId): ODMessage|null {
- return super.get(id)
- }
-
- remove(id:MessageId): ODMessage_Default
- remove(id:ODValidId): ODMessage|null
-
- remove(id:ODValidId): ODMessage|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODMessageManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- getSafe(id:MessageId): ODMessage_Default
- getSafe(id:ODValidId): ODMessage
-
- getSafe(id:ODValidId): ODMessage {
- return super.getSafe(id)
- }
-}
-
-/**## ODMessage_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODMessage class.
- * It doesn't add any extra features!
- *
- * This default class is made for the default `ODMessage`'s!
- */
-export class ODMessage_Default extends ODMessage {
- declare workers: ODWorkerManager_Default
-}
-
-/**## ODModalManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODModalManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODModalManagerIds_Default {
- "opendiscord:ticket-questions":{source:"panel-button"|"panel-dropdown"|"slash"|"text"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,option:ODTicketOption},workers:"opendiscord:ticket-questions"}
- "opendiscord:close-ticket-reason":{source:"ticket-message"|"reopen-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:close-ticket-reason"}
- "opendiscord:reopen-ticket-reason":{source:"ticket-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:reopen-ticket-reason"}
- "opendiscord:delete-ticket-reason":{source:"ticket-message"|"reopen-message"|"close-message"|"autoclose-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:delete-ticket-reason"}
- "opendiscord:claim-ticket-reason":{source:"ticket-message"|"unclaim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:claim-ticket-reason"}
- "opendiscord:unclaim-ticket-reason":{source:"ticket-message"|"claim-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:unclaim-ticket-reason"}
- "opendiscord:pin-ticket-reason":{source:"ticket-message"|"unpin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:pin-ticket-reason"}
- "opendiscord:unpin-ticket-reason":{source:"ticket-message"|"pin-message"|"other",params:{guild:discord.Guild,channel:discord.TextBasedChannel,user:discord.User,ticket:ODTicket},workers:"opendiscord:unpin-ticket-reason"}
-}
-
-/**## ODModalManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODModalManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.builders.modals`!
- */
-export class ODModalManager_Default extends ODModalManager {
- get(id:ModalId): ODModal_Default
- get(id:ODValidId): ODModal|null
-
- get(id:ODValidId): ODModal|null {
- return super.get(id)
- }
-
- remove(id:ModalId): ODModal_Default
- remove(id:ODValidId): ODModal|null
-
- remove(id:ODValidId): ODModal|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODModalManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- getSafe(id:ModalId): ODModal_Default
- getSafe(id:ODValidId): ODModal
-
- getSafe(id:ODValidId): ODModal {
- return super.getSafe(id)
- }
-}
-
-/**## ODModal_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODModal class.
- * It doesn't add any extra features!
- *
- * This default class is made for the default `ODModal`'s!
- */
-export class ODModal_Default extends ODModal {
- declare workers: ODWorkerManager_Default
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/checker.ts b/src/core/api/defaults/checker.ts
deleted file mode 100644
index 9cc654c..0000000
--- a/src/core/api/defaults/checker.ts
+++ /dev/null
@@ -1,385 +0,0 @@
-///////////////////////////////////////
-//DEFAULT CONFIG CHECKER MODULE
-///////////////////////////////////////
-import { ODLanguageManager_Default } from "../api"
-import { ODValidId } from "../modules/base"
-import { ODCheckerManager, ODChecker, ODCheckerTranslationRegister, ODCheckerRenderer, ODCheckerFunctionManager, ODCheckerResult, ODCheckerFunction } from "../modules/checker"
-import ansis from "ansis"
-
-/**## ODCheckerManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODCheckerManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODCheckerManagerIds_Default {
- "opendiscord:general":ODChecker,
- "opendiscord:questions":ODChecker,
- "opendiscord:options":ODChecker,
- "opendiscord:panels":ODChecker,
- "opendiscord:transcripts":ODChecker
-}
-
-/**## ODCheckerManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODCheckerManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.checkers`!
- */
-export class ODCheckerManager_Default extends ODCheckerManager {
- declare translation: ODCheckerTranslationRegister_Default
- declare renderer: ODCheckerRenderer_Default
- declare functions: ODCheckerFunctionManager_Default
-
- get(id:CheckerId): ODCheckerManagerIds_Default[CheckerId]
- get(id:ODValidId): ODChecker|null
-
- get(id:ODValidId): ODChecker|null {
- return super.get(id)
- }
-
- remove(id:CheckerId): ODCheckerManagerIds_Default[CheckerId]
- remove(id:ODValidId): ODChecker|null
-
- remove(id:ODValidId): ODChecker|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODCheckerManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODCheckerRenderer_Default `default_class`
- * This is a special class that adds type definitions & features to the ODCheckerRenderer class.
- * It contains the code that renders the default config checker.
- *
- * This default class is made for the global variable `opendiscord.checkers.renderer`!
- */
-export class ODCheckerRenderer_Default extends ODCheckerRenderer {
- extraHeaderText: string[] = []
- extraFooterText: string[] = []
- extraTopText: string[] = []
- extraBottomText: string[] = []
-
- horizontalFiller: string = "="
- verticalFiller: string = "|"
- descriptionSeparator: string = " => "
- headerSeparator: string = " => "
- footerTipPrefix: string = "=> "
-
- disableHeader: boolean = false
- disableFooter: boolean = false
-
- getComponents(compact:boolean, renderEmpty:boolean, translation:ODCheckerTranslationRegister_Default, data:ODCheckerResult): string[] {
- const tm = translation
- const t = {
- headerOpenticket:tm.get("other","opendiscord:header-openticket") ?? "OPEN TICKET",
- headerConfigchecker:tm.get("other","opendiscord:header-configchecker") ?? "CONFIG CHECKER",
- headerDescription:tm.get("other","opendiscord:header-description") ?? "check for errors in your config files!",
- footerError:tm.get("other","opendiscord:footer-error") ?? "the bot won't start until all {0}'s are fixed!",
- footerWarning:tm.get("other","opendiscord:footer-warning") ?? "it's recommended to fix all {0}'s before starting!",
- footerSupport:tm.get("other","opendiscord:footer-support") ?? "SUPPORT: {0} - DOCS: {1}",
- error:tm.get("other","opendiscord:type-error") ?? "[ERROR]",
- warning:tm.get("other","opendiscord:type-warning") ?? "[WARNING]",
- info:tm.get("other","opendiscord:type-info") ?? "[INFO]",
- compactInfo:tm.get("other","opendiscord:compact-information") ?? "use {0} for more information!",
- dataPath:tm.get("other","opendiscord:data-path") ?? "path",
- dataDocs:tm.get("other","opendiscord:data-docs") ?? "docs",
- dataMessage:tm.get("other","opendiscord:data-message") ?? "message"
- }
- const hasErrors = data.messages.filter((m) => m.type == "error").length > 0
- const hasWarnings = data.messages.filter((m) => m.type == "warning").length > 0
- const hasInfo = data.messages.filter((m) => m.type == "info").length > 0
-
- if (!renderEmpty && !hasErrors && !hasWarnings && (!hasInfo || compact)) return []
-
- const headerText = ansis.bold.hex("#f8ba00")(t.headerOpenticket)+" "+t.headerConfigchecker+this.headerSeparator+ansis.hex("#f8ba00")(t.headerDescription)
- const footerErrorText = (hasErrors) ? this.footerTipPrefix+ansis.gray(tm.insertTranslationParams(t.footerError,[ansis.bold.red(t.error)])) : ""
- const footerWarningText = (hasWarnings) ? this.footerTipPrefix+ansis.gray(tm.insertTranslationParams(t.footerWarning,[ansis.bold.yellow(t.warning)])) : ""
- const footerSupportText = tm.insertTranslationParams(t.footerSupport,[ansis.green("https://discord.dj-dj.be"),ansis.green("https://otdocs.dj-dj.be")])
- const bottomCompactInfo = (compact) ? ansis.gray(tm.insertTranslationParams(t.compactInfo,[ansis.bold.green("npm start -- --checker")])) : ""
-
- const finalHeader = [headerText,...this.extraHeaderText]
- const finalFooter = [footerErrorText,footerWarningText,footerSupportText,...this.extraFooterText]
- const finalTop = [...this.extraTopText]
- const finalBottom = [bottomCompactInfo,...this.extraBottomText]
- const borderLength = this.#getLongestLength([...finalHeader,...finalFooter])
-
- const finalComponents: string[] = []
-
- //header
- if (!this.disableHeader){
- finalHeader.forEach((text) => {
- if (text.length < 1) return
- finalComponents.push(this.#createBlockFromText(text,borderLength))
- })
- }
- finalComponents.push(this.#getHorizontalDivider(borderLength+4))
-
- //top
- finalTop.forEach((text) => {
- if (text.length < 1) return
- finalComponents.push(this.verticalFiller+" "+text)
- })
- finalComponents.push(this.verticalFiller)
-
- //messages
- if (compact){
- //use compact messages
- data.messages.forEach((msg,index) => {
- //compact mode doesn't render info
- if (msg.type == "info") return
-
- //check if translation available & use it if possible
- const rawTranslation = tm.get("message",msg.messageId.value)
- const translatedMessage = (rawTranslation) ? tm.insertTranslationParams(rawTranslation,msg.translationParams) : msg.message
-
- if (msg.type == "error") finalComponents.push(this.verticalFiller+" "+ansis.bold.red(`${t.error} ${translatedMessage}`))
- else if (msg.type == "warning") finalComponents.push(this.verticalFiller+" "+ansis.bold.yellow(`${t.warning} ${translatedMessage}`))
-
- const pathSplitter = msg.path ? ":" : ""
- finalComponents.push(this.verticalFiller+ansis.bold(this.descriptionSeparator)+ansis.cyan(`${ansis.magenta(msg.filepath+pathSplitter)} ${msg.path}`))
- if (index != data.messages.length-1) finalComponents.push(this.verticalFiller)
- })
- }else{
- //use full messages
- data.messages.forEach((msg,index) => {
- //check if translation available & use it if possible
- const rawTranslation = tm.get("message",msg.messageId.value)
- const translatedMessage = (rawTranslation) ? tm.insertTranslationParams(rawTranslation,msg.translationParams) : msg.message
-
- if (msg.type == "error") finalComponents.push(this.verticalFiller+" "+ansis.bold.red(`${t.error} ${translatedMessage}`))
- else if (msg.type == "warning") finalComponents.push(this.verticalFiller+" "+ansis.bold.yellow(`${t.warning} ${translatedMessage}`))
- else if (msg.type == "info") finalComponents.push(this.verticalFiller+" "+ansis.bold.blue(`${t.info} ${translatedMessage}`))
-
- const pathSplitter = msg.path ? ":" : ""
- finalComponents.push(this.verticalFiller+" "+ansis.bold((t.dataPath)+this.descriptionSeparator)+ansis.cyan(`${ansis.magenta(msg.filepath+pathSplitter)} ${msg.path}`))
- if (msg.locationDocs) finalComponents.push(this.verticalFiller+" "+ansis.bold(t.dataDocs+this.descriptionSeparator)+ansis.italic.gray(msg.locationDocs))
- if (msg.messageDocs) finalComponents.push(this.verticalFiller+" "+ansis.bold(t.dataMessage+this.descriptionSeparator)+ansis.italic.gray(msg.messageDocs))
- if (index != data.messages.length-1) finalComponents.push(this.verticalFiller)
- })
- }
-
- //bottom
- finalComponents.push(this.verticalFiller)
- finalBottom.forEach((text) => {
- if (text.length < 1) return
- finalComponents.push(this.verticalFiller+" "+text)
- })
-
- //footer
- finalComponents.push(this.#getHorizontalDivider(borderLength+4))
- if (!this.disableFooter){
- finalFooter.forEach((text) => {
- if (text.length < 1) return
- finalComponents.push(this.#createBlockFromText(text,borderLength))
- })
- finalComponents.push(this.#getHorizontalDivider(borderLength+4))
- }
-
- //return all components
- return finalComponents
- }
- /**Get the length of the longest string in the array. */
- #getLongestLength(texts:string[]): number {
- return Math.max(...texts.map((t) => ansis.strip(t).length))
- }
- /**Get a horizontal divider used between different parts of the config checker result. */
- #getHorizontalDivider(width:number): string {
- if (width > 2) width = width-2
- else return this.verticalFiller+this.verticalFiller
- let divider = this.verticalFiller + this.horizontalFiller.repeat(width) + this.verticalFiller
- return divider
- }
- /**Create a block of text with a vertical divider on the left & right side. */
- #createBlockFromText(text:string,width:number): string {
- if (width < 3) return this.verticalFiller+this.verticalFiller
- let newWidth = width-ansis.strip(text).length+1
- let final = this.verticalFiller+" "+text+" ".repeat(newWidth)+this.verticalFiller
- return final
- }
-}
-
-/**## ODCheckerTranslationRegisterOtherIds_Default `interface`
- * This interface is a list of ids available in the `ODCheckerTranslationRegister_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export type ODCheckerTranslationRegisterOtherIds_Default = (
- "opendiscord:header-openticket"|
- "opendiscord:header-configchecker"|
- "opendiscord:header-description"|
- "opendiscord:type-error"|
- "opendiscord:type-warning"|
- "opendiscord:type-info"|
- "opendiscord:data-path"|
- "opendiscord:data-docs"|
- "opendiscord:data-message"|
- "opendiscord:compact-information"|
- "opendiscord:footer-error"|
- "opendiscord:footer-warning"|
- "opendiscord:footer-support"
-)
-
-/**## ODCheckerTranslationRegisterMessageIds_Default `interface`
- * This interface is a list of ids available in the `ODCheckerTranslationRegister_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export type ODCheckerTranslationRegisterMessageIds_Default = (
- "opendiscord:invalid-type"|
- "opendiscord:property-missing"|
- "opendiscord:property-optional"|
- "opendiscord:object-disabled"|
- "opendiscord:null-invalid"|
- "opendiscord:switch-invalid-type"|
- "opendiscord:object-switch-invalid-type"|
-
- "opendiscord:string-too-short"|
- "opendiscord:string-too-long"|
- "opendiscord:string-length-invalid"|
- "opendiscord:string-starts-with"|
- "opendiscord:string-ends-with"|
- "opendiscord:string-contains"|
- "opendiscord:string-inverted-contains"|
- "opendiscord:string-choices"|
- "opendiscord:string-lowercase"|
- "opendiscord:string-uppercase"|
- "opendiscord:string-special-characters"|
- "opendiscord:string-no-spaces"|
- "opendiscord:string-regex"|
- "opendiscord:string-capital-word"|
- "opendiscord:string-capital-sentence"|
- "opendiscord:string-punctuation"|
-
- "opendiscord:number-nan"|
- "opendiscord:number-too-short"|
- "opendiscord:number-too-long"|
- "opendiscord:number-length-invalid"|
- "opendiscord:number-too-small"|
- "opendiscord:number-too-large"|
- "opendiscord:number-not-equal"|
- "opendiscord:number-step"|
- "opendiscord:number-step-offset"|
- "opendiscord:number-starts-with"|
- "opendiscord:number-ends-with"|
- "opendiscord:number-contains"|
- "opendiscord:number-inverted-contains"|
- "opendiscord:number-choices"|
- "opendiscord:number-float"|
- "opendiscord:number-negative"|
- "opendiscord:number-positive"|
- "opendiscord:number-zero"|
-
- "opendiscord:boolean-true"|
- "opendiscord:boolean-false"|
-
- "opendiscord:array-empty-disabled"|
- "opendiscord:array-empty-required"|
- "opendiscord:array-too-short"|
- "opendiscord:array-too-long"|
- "opendiscord:array-length-invalid"|
- "opendiscord:array-invalid-types"|
- "opendiscord:array-double"|
-
- "opendiscord:discord-invalid-id"|
- "opendiscord:discord-invalid-id-options"|
- "opendiscord:discord-invalid-token"|
- "opendiscord:color-invalid"|
- "opendiscord:emoji-too-short"|
- "opendiscord:emoji-too-long"|
- "opendiscord:emoji-custom"|
- "opendiscord:emoji-invalid"|
- "opendiscord:url-invalid"|
- "opendiscord:url-invalid-http"|
- "opendiscord:url-invalid-protocol"|
- "opendiscord:url-invalid-hostname"|
- "opendiscord:url-invalid-extension"|
- "opendiscord:url-invalid-path"|
- "opendiscord:id-not-unique"|
- "opendiscord:id-non-existent"|
-
- "opendiscord:invalid-language"|
- "opendiscord:invalid-button"|
- "opendiscord:unused-option"|
- "opendiscord:unused-question"|
- "opendiscord:dropdown-option"
-)
-
-/**## ODCheckerTranslationRegister_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODCheckerTranslationRegister class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.checkers.translation`!
- */
-export class ODCheckerTranslationRegister_Default extends ODCheckerTranslationRegister {
- get(type:"other", id:ODCheckerTranslationRegisterOtherIds_Default): string
- get(type:"message", id:ODCheckerTranslationRegisterMessageIds_Default): string
- get(type:"message"|"other", id:string): string|null
-
- get(type:"message"|"other", id:string): string|null {
- return super.get(type,id)
- }
-
- set(type:"other", id:ODCheckerTranslationRegisterOtherIds_Default, translation:string): boolean
- set(type:"message", id:ODCheckerTranslationRegisterMessageIds_Default, translation:string): boolean
- set(type:"message"|"other", id:string, translation:string): boolean
-
- set(type:"message"|"other", id:string, translation:string): boolean {
- return super.set(type,id,translation)
- }
-
- delete(type:"other", id:ODCheckerTranslationRegisterOtherIds_Default): boolean
- delete(type:"message", id:ODCheckerTranslationRegisterMessageIds_Default): boolean
- delete(type:"message"|"other", id:string): boolean
-
- delete(type:"message"|"other", id:string): boolean {
- return super.delete(type,id)
- }
-
- quickTranslate(manager:ODLanguageManager_Default, translationId:string, type:"other"|"message", id:ODCheckerTranslationRegisterOtherIds_Default|ODCheckerTranslationRegisterMessageIds_Default)
- quickTranslate(manager:ODLanguageManager_Default, translationId:string, type:"other"|"message", id:string)
-
- quickTranslate(manager:ODLanguageManager_Default, translationId:string, type:"other"|"message", id:ODCheckerTranslationRegisterOtherIds_Default|ODCheckerTranslationRegisterMessageIds_Default|string){
- super.quickTranslate(manager,translationId,type,id)
- }
-}
-
-/**## ODCheckerFunctionManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODCheckerFunctionManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODCheckerFunctionManagerIds_Default {
- "opendiscord:unused-options":ODCheckerFunction,
- "opendiscord:unused-questions":ODCheckerFunction,
- "opendiscord:dropdown-options":ODCheckerFunction
-}
-
-/**## ODCheckerFunctionManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODCheckerFunctionManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.checkers.functions`!
- */
-export class ODCheckerFunctionManager_Default extends ODCheckerFunctionManager {
- get(id:CheckerFunctionId): ODCheckerFunctionManagerIds_Default[CheckerFunctionId]
- get(id:ODValidId): ODCheckerFunction|null
-
- get(id:ODValidId): ODCheckerFunction|null {
- return super.get(id)
- }
-
- remove(id:CheckerFunctionId): ODCheckerFunctionManagerIds_Default[CheckerFunctionId]
- remove(id:ODValidId): ODCheckerFunction|null
-
- remove(id:ODValidId): ODCheckerFunction|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODCheckerFunctionManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/client.ts b/src/core/api/defaults/client.ts
deleted file mode 100644
index 7b5a540..0000000
--- a/src/core/api/defaults/client.ts
+++ /dev/null
@@ -1,207 +0,0 @@
-///////////////////////////////////////
-//DEFAULT CLIENT MODULE
-///////////////////////////////////////
-import { ODValidId } from "../modules/base"
-import { ODClientManager, ODSlashCommand, ODTextCommand, ODSlashCommandManager, ODTextCommandManager, ODSlashCommandInteractionCallback, ODTextCommandInteractionCallback, ODContextMenu, ODContextMenuManager, ODContextMenuInteractionCallback } from "../modules/client"
-
-/** (CONTRIBUTOR GUIDE) HOW TO ADD NEW COMMANDS?
- * - Register the command in loadAllSlashCommands() & loadAllTextCommands() in (./src/data/framework/commandLoader.ts)
- * - Add autocomplete for the command in OD(Slash/Text)CommandManagerIds_Default in (./src/core/api/defaults/client.ts)
- * - Add the command to the help menu in (./src/data/framework/helpMenuLoader.ts)
- * - If required, new config variables should be added (incl. logs, dm-logs & permissions).
- * - Update the Open Ticket Documentation.
- * - If the command contains complex logic or can be executed from a button/dropdown, it should be placed inside an `ODAction`.
- * - Check all files, test the bot carefully & try a lot of different scenario's with different settings.
- */
-
-/**## ODClientManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODClientManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.client`!
- */
-export class ODClientManager_Default extends ODClientManager {
- declare slashCommands: ODSlashCommandManager_Default
- declare textCommands: ODTextCommandManager_Default
- declare contextMenus: ODContextMenuManager_Default
-}
-
-/**## ODSlashCommandManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODSlashCommandManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODSlashCommandManagerIds_Default {
- "opendiscord:help":ODSlashCommand,
- "opendiscord:panel":ODSlashCommand,
- "opendiscord:ticket":ODSlashCommand,
- "opendiscord:close":ODSlashCommand,
- "opendiscord:delete":ODSlashCommand,
- "opendiscord:reopen":ODSlashCommand,
- "opendiscord:claim":ODSlashCommand,
- "opendiscord:unclaim":ODSlashCommand,
- "opendiscord:pin":ODSlashCommand,
- "opendiscord:unpin":ODSlashCommand,
- "opendiscord:move":ODSlashCommand,
- "opendiscord:rename":ODSlashCommand,
- "opendiscord:add":ODSlashCommand,
- "opendiscord:remove":ODSlashCommand,
- "opendiscord:blacklist":ODSlashCommand,
- "opendiscord:stats":ODSlashCommand,
- "opendiscord:clear":ODSlashCommand,
- "opendiscord:autoclose":ODSlashCommand,
- "opendiscord:autodelete":ODSlashCommand,
- "opendiscord:topic":ODSlashCommand,
- "opendiscord:priority":ODSlashCommand,
- "opendiscord:transfer":ODSlashCommand,
-}
-
-/**## ODSlashCommandManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODSlashCommandManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.client.slashCommands`!
- */
-export class ODSlashCommandManager_Default extends ODSlashCommandManager {
- get(id:SlashCommandId): ODSlashCommandManagerIds_Default[SlashCommandId]
- get(id:ODValidId): ODSlashCommand|null
-
- get(id:ODValidId): ODSlashCommand|null {
- return super.get(id)
- }
-
- remove(id:SlashCommandId): ODSlashCommandManagerIds_Default[SlashCommandId]
- remove(id:ODValidId): ODSlashCommand|null
-
- remove(id:ODValidId): ODSlashCommand|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODSlashCommandManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- onInteraction(commandName:keyof ODSlashCommandManagerIds_Default, callback:ODSlashCommandInteractionCallback): void
- onInteraction(commandName:string|RegExp, callback:ODSlashCommandInteractionCallback): void
-
- onInteraction(commandName:string|RegExp, callback:ODSlashCommandInteractionCallback): void {
- return super.onInteraction(commandName,callback)
- }
-}
-
-/**## ODTextCommandManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODTextCommandManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODTextCommandManagerIds_Default {
- "opendiscord:dump":ODTextCommand,
- "opendiscord:help":ODTextCommand,
- "opendiscord:panel":ODTextCommand,
- "opendiscord:close":ODTextCommand,
- "opendiscord:delete":ODTextCommand,
- "opendiscord:reopen":ODTextCommand,
- "opendiscord:claim":ODTextCommand,
- "opendiscord:unclaim":ODTextCommand,
- "opendiscord:pin":ODTextCommand,
- "opendiscord:unpin":ODTextCommand,
- "opendiscord:move":ODTextCommand,
- "opendiscord:rename":ODTextCommand,
- "opendiscord:add":ODTextCommand,
- "opendiscord:remove":ODTextCommand,
- "opendiscord:blacklist-view":ODTextCommand,
- "opendiscord:blacklist-add":ODTextCommand,
- "opendiscord:blacklist-remove":ODTextCommand,
- "opendiscord:blacklist-get":ODTextCommand,
- "opendiscord:stats-global":ODTextCommand,
- "opendiscord:stats-reset":ODTextCommand,
- "opendiscord:stats-ticket":ODTextCommand,
- "opendiscord:stats-user":ODTextCommand,
- "opendiscord:clear":ODTextCommand,
- "opendiscord:autoclose-disable":ODTextCommand,
- "opendiscord:autoclose-enable":ODTextCommand,
- "opendiscord:autodelete-disable":ODTextCommand,
- "opendiscord:autodelete-enable":ODTextCommand,
- "opendiscord:topic-set":ODTextCommand,
- "opendiscord:priority-set":ODTextCommand,
- "opendiscord:priority-get":ODTextCommand,
- "opendiscord:transfer":ODTextCommand,
-}
-
-/**## ODTextCommandManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODTextCommandManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.client.textCommands`!
- */
-export class ODTextCommandManager_Default extends ODTextCommandManager {
- get(id:TextCommandId): ODTextCommandManagerIds_Default[TextCommandId]
- get(id:ODValidId): ODTextCommand|null
-
- get(id:ODValidId): ODTextCommand|null {
- return super.get(id)
- }
-
- remove(id:TextCommandId): ODTextCommandManagerIds_Default[TextCommandId]
- remove(id:ODValidId): ODTextCommand|null
-
- remove(id:ODValidId): ODTextCommand|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODTextCommandManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- onInteraction(commandPrefix:string, commandName:string|RegExp, callback:ODTextCommandInteractionCallback): void {
- return super.onInteraction(commandPrefix,commandName,callback)
- }
-}
-
-/**## ODContextMenuManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODContextMenuManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODContextMenuManagerIds_Default {
- //"opendiscord:test-menu":ODContextMenu
-}
-
-/**## ODContextMenuManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODContextMenuManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.client.contextMenus`!
- */
-export class ODContextMenuManager_Default extends ODContextMenuManager {
- get(id:ContextMenuId): ODContextMenuManagerIds_Default[ContextMenuId]
- get(id:ODValidId): ODContextMenu|null
-
- get(id:ODValidId): ODContextMenu|null {
- return super.get(id)
- }
-
- remove(id:ContextMenuId): ODContextMenuManagerIds_Default[ContextMenuId]
- remove(id:ODValidId): ODContextMenu|null
-
- remove(id:ODValidId): ODContextMenu|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODContextMenuManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-
- onInteraction(menuName:keyof ODContextMenuManagerIds_Default, callback:ODContextMenuInteractionCallback): void
- onInteraction(menuName:string|RegExp, callback:ODContextMenuInteractionCallback): void
-
- onInteraction(menuName:string|RegExp, callback:ODContextMenuInteractionCallback): void {
- return super.onInteraction(menuName,callback)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/code.ts b/src/core/api/defaults/code.ts
deleted file mode 100644
index 7ef19a8..0000000
--- a/src/core/api/defaults/code.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-///////////////////////////////////////
-//DEFAULT CODE MODULE
-///////////////////////////////////////
-import { ODValidId } from "../modules/base"
-import { ODCode, ODCodeManager } from "../modules/code"
-
-/**## ODCodeManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODCodeManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODCodeManagerIds_Default {
- "opendiscord:command-error-handling":ODCode,
- "opendiscord:start-listening-interactions":ODCode,
- "opendiscord:panel-database-cleaner":ODCode,
- "opendiscord:suffix-database-cleaner":ODCode,
- "opendiscord:option-database-cleaner":ODCode,
- "opendiscord:user-database-cleaner":ODCode,
- "opendiscord:ticket-database-cleaner":ODCode,
- "opendiscord:panel-auto-update":ODCode,
- "opendiscord:ticket-saver":ODCode,
- "opendiscord:blacklist-saver":ODCode,
- "opendiscord:auto-role-on-join":ODCode,
- "opendiscord:autoclose-timeout":ODCode,
- "opendiscord:autoclose-leave":ODCode,
- "opendiscord:autodelete-timeout":ODCode,
- "opendiscord:autodelete-leave":ODCode,
- "opendiscord:ticket-anti-busy":ODCode,
-}
-
-/**## ODCodeManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODCodeManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.code`!
- */
-export class ODCodeManager_Default extends ODCodeManager {
- get(id:CodeId): ODCodeManagerIds_Default[CodeId]
- get(id:ODValidId): ODCode|null
-
- get(id:ODValidId): ODCode|null {
- return super.get(id)
- }
-
- remove(id:CodeId): ODCodeManagerIds_Default[CodeId]
- remove(id:ODValidId): ODCode|null
-
- remove(id:ODValidId): ODCode|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODCodeManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/console.ts b/src/core/api/defaults/console.ts
deleted file mode 100644
index 6b4d0da..0000000
--- a/src/core/api/defaults/console.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-///////////////////////////////////////
-//DEFAULT CONSOLE MODULE
-///////////////////////////////////////
-import { ODValidId } from "../modules/base"
-import { ODLiveStatusUrlSource, ODLiveStatusManager, ODLiveStatusSource } from "../modules/console"
-
-/**## ODLiveStatusManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODLiveStatusManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODLiveStatusManagerIds_Default {
- "opendiscord:default-djdj-dev":ODLiveStatusUrlSource
-}
-
-/**## ODLiveStatusManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODLiveStatusManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.livestatus`!
- */
-export class ODLiveStatusManager_Default extends ODLiveStatusManager {
- get(id:LiveStatusId): ODLiveStatusManagerIds_Default[LiveStatusId]
- get(id:ODValidId): ODLiveStatusSource|null
-
- get(id:ODValidId): ODLiveStatusSource|null {
- return super.get(id)
- }
-
- remove(id:LiveStatusId): ODLiveStatusManagerIds_Default[LiveStatusId]
- remove(id:ODValidId): ODLiveStatusSource|null
-
- remove(id:ODValidId): ODLiveStatusSource|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODLiveStatusManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/cooldown.ts b/src/core/api/defaults/cooldown.ts
deleted file mode 100644
index 75a53e7..0000000
--- a/src/core/api/defaults/cooldown.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-///////////////////////////////////////
-//DEFAULT COOLDOWN MODULE
-///////////////////////////////////////
-import { ODValidId } from "../modules/base"
-import { ODCooldown, ODCooldownManager } from "../modules/cooldown"
-
-/**## ODCooldownManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODCooldownManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODCooldownManagerIds_Default {
-
-}
-
-/**## ODCooldownManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODCooldownManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.cooldowns`!
- */
-export class ODCooldownManager_Default extends ODCooldownManager {
- get(id:CooldownId): ODCooldownManagerIds_Default[CooldownId]
- get(id:ODValidId): ODCooldown|null
-
- get(id:ODValidId): ODCooldown|null {
- return super.get(id)
- }
-
- remove(id:CooldownId): ODCooldownManagerIds_Default[CooldownId]
- remove(id:ODValidId): ODCooldown|null
-
- remove(id:ODValidId): ODCooldown|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODCooldownManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/database.ts b/src/core/api/defaults/database.ts
deleted file mode 100644
index 8e73a10..0000000
--- a/src/core/api/defaults/database.ts
+++ /dev/null
@@ -1,257 +0,0 @@
-///////////////////////////////////////
-//DEFAULT DATABASE MODULE
-///////////////////////////////////////
-import { ODOptionalPromise, ODValidId, ODValidJsonType } from "../modules/base"
-import { ODDatabaseManager, ODDatabase, ODFormattedJsonDatabase } from "../modules/database"
-import { ODTicketJson } from "../openticket/ticket"
-import { ODOptionJson } from "../openticket/option"
-
-/**## ODDatabaseManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODDatabaseManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODDatabaseManagerIds_Default {
- "opendiscord:global":ODFormattedJsonDatabase_DefaultGlobal,
- "opendiscord:stats":ODFormattedJsonDatabase,
- "opendiscord:tickets":ODFormattedJsonDatabase_DefaultTickets,
- "opendiscord:users":ODFormattedJsonDatabase_DefaultUsers,
- "opendiscord:options":ODFormattedJsonDatabase_DefaultOptions,
-}
-
-/**## ODDatabaseManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODDatabaseManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.databases`!
- */
-export class ODDatabaseManager_Default extends ODDatabaseManager {
- get(id:DatabaseId): ODDatabaseManagerIds_Default[DatabaseId]
- get(id:ODValidId): ODDatabase|null
-
- get(id:ODValidId): ODDatabase|null {
- return super.get(id)
- }
-
- remove(id:DatabaseId): ODDatabaseManagerIds_Default[DatabaseId]
- remove(id:ODValidId): ODDatabase|null
-
- remove(id:ODValidId): ODDatabase|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODDatabaseManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODFormattedJsonDatabaseIds_DefaultGlobal `type`
- * This interface is a list of ids available in the `ODFormattedJsonDatabase_DefaultGlobal` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODFormattedJsonDatabaseIds_DefaultGlobal {
- "opendiscord:panel-message":string,
- "opendiscord:panel-update":string,
- "opendiscord:option-suffix-counter":number,
- "opendiscord:option-suffix-history":string[],
- "opendiscord:last-version":string
-}
-
-/**## ODFormattedJsonDatabase_DefaultGlobal `default_class`
- * This is a special class that adds type definitions & typescript to the ODFormattedJsonDatabase class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `global.json` database!
- */
-export class ODFormattedJsonDatabase_DefaultGlobal extends ODFormattedJsonDatabase {
- set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultGlobal[CategoryId]): ODOptionalPromise
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise
-
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise {
- return super.set(category,key,value)
- }
-
- get(category:CategoryId, key:string): ODOptionalPromise
- get(category:string, key:string): ODOptionalPromise
-
- get(category:string, key:string): ODOptionalPromise {
- return super.get(category,key)
- }
-
- delete(category:CategoryId, key:string): ODOptionalPromise
- delete(category:string, key:string): ODOptionalPromise
-
- delete(category:string, key:string): ODOptionalPromise {
- return super.delete(category,key)
- }
-
- exists(category:keyof ODFormattedJsonDatabaseIds_DefaultGlobal, key:string): ODOptionalPromise
- exists(category:string, key:string): ODOptionalPromise
-
- exists(category:string, key:string): ODOptionalPromise {
- return super.exists(category,key)
- }
-
- getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultGlobal[CategoryId]}[]|undefined>
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined>
-
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> {
- return super.getCategory(category)
- }
-}
-
-/**## ODFormattedJsonDatabaseIds_DefaultTickets `type`
- * This interface is a list of ids available in the `ODDatabaseManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODFormattedJsonDatabaseIds_DefaultTickets {
- "opendiscord:ticket":ODTicketJson
-}
-
-/**## ODFormattedJsonDatabase_DefaultTickets `default_class`
- * This is a special class that adds type definitions & typescript to the ODFormattedJsonDatabase class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `tickets.json` database!
- */
-export class ODFormattedJsonDatabase_DefaultTickets extends ODFormattedJsonDatabase {
- set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultTickets[CategoryId]): ODOptionalPromise
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise
-
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise {
- return super.set(category,key,value)
- }
-
- get(category:CategoryId, key:string): ODOptionalPromise
- get(category:string, key:string): ODOptionalPromise
-
- get(category:string, key:string): ODOptionalPromise {
- return super.get(category,key)
- }
-
- delete(category:CategoryId, key:string): ODOptionalPromise
- delete(category:string, key:string): ODOptionalPromise
-
- delete(category:string, key:string): ODOptionalPromise {
- return super.delete(category,key)
- }
-
- exists(category:keyof ODFormattedJsonDatabaseIds_DefaultTickets, key:string): ODOptionalPromise
- exists(category:string, key:string): ODOptionalPromise
-
- exists(category:string, key:string): ODOptionalPromise {
- return super.exists(category,key)
- }
-
- getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultTickets[CategoryId]}[]|undefined>
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined>
-
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> {
- return super.getCategory(category)
- }
-}
-
-/**## ODFormattedJsonDatabaseIds_DefaultUsers `type`
- * This interface is a list of ids available in the `ODDatabaseManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODFormattedJsonDatabaseIds_DefaultUsers {
- "opendiscord:blacklist":ODTicketJson
-}
-
-/**## ODFormattedJsonDatabase_DefaultUsers `default_class`
- * This is a special class that adds type definitions & typescript to the ODFormattedJsonDatabase class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `users.json` database!
- */
-export class ODFormattedJsonDatabase_DefaultUsers extends ODFormattedJsonDatabase {
- set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultUsers[CategoryId]): ODOptionalPromise
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise
-
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise {
- return super.set(category,key,value)
- }
-
- get(category:CategoryId, key:string): ODOptionalPromise
- get(category:string, key:string): ODOptionalPromise
-
- get(category:string, key:string): ODOptionalPromise {
- return super.get(category,key)
- }
-
- delete(category:CategoryId, key:string): ODOptionalPromise
- delete(category:string, key:string): ODOptionalPromise
-
- delete(category:string, key:string): ODOptionalPromise {
- return super.delete(category,key)
- }
-
- exists(category:keyof ODFormattedJsonDatabaseIds_DefaultUsers, key:string): ODOptionalPromise
- exists(category:string, key:string): ODOptionalPromise
-
- exists(category:string, key:string): ODOptionalPromise {
- return super.exists(category,key)
- }
-
- getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultUsers[CategoryId]}[]|undefined>
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined>
-
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> {
- return super.getCategory(category)
- }
-}
-
-
-/**## ODFormattedJsonDatabaseIds_DefaultOptions `type`
- * This interface is a list of ids available in the `ODDatabaseManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODFormattedJsonDatabaseIds_DefaultOptions {
- "opendiscord:used-option":ODOptionJson
-}
-
-/**## ODFormattedJsonDatabase_DefaultOptions `default_class`
- * This is a special class that adds type definitions & typescript to the ODFormattedJsonDatabase class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `options.json` database!
- */
-export class ODFormattedJsonDatabase_DefaultOptions extends ODFormattedJsonDatabase {
- set(category:CategoryId, key:string, value:ODFormattedJsonDatabaseIds_DefaultOptions[CategoryId]): ODOptionalPromise
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise
-
- set(category:string, key:string, value:ODValidJsonType): ODOptionalPromise {
- return super.set(category,key,value)
- }
-
- get(category:CategoryId, key:string): ODOptionalPromise
- get(category:string, key:string): ODOptionalPromise
-
- get(category:string, key:string): ODOptionalPromise {
- return super.get(category,key)
- }
-
- delete(category:CategoryId, key:string): ODOptionalPromise
- delete(category:string, key:string): ODOptionalPromise
-
- delete(category:string, key:string): ODOptionalPromise {
- return super.delete(category,key)
- }
-
- exists(category:keyof ODFormattedJsonDatabaseIds_DefaultOptions, key:string): ODOptionalPromise
- exists(category:string, key:string): ODOptionalPromise
-
- exists(category:string, key:string): ODOptionalPromise {
- return super.exists(category,key)
- }
-
- getCategory(category:CategoryId): ODOptionalPromise<{key:string, value:ODFormattedJsonDatabaseIds_DefaultOptions[CategoryId]}[]|undefined>
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined>
-
- getCategory(category:string): ODOptionalPromise<{key:string, value:ODValidJsonType}[]|undefined> {
- return super.getCategory(category)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/event.ts b/src/core/api/defaults/event.ts
deleted file mode 100644
index 86496fc..0000000
--- a/src/core/api/defaults/event.ts
+++ /dev/null
@@ -1,390 +0,0 @@
-///////////////////////////////////////
-//DEFAULT EVENT MODULE
-///////////////////////////////////////
-//BASE MODULES
-import { ODPromiseVoid, ODValidId } from "../modules/base"
-import { ODConsoleManager, ODError } from "../modules/console"
-import { ODCheckerResult, ODCheckerStorage } from "../modules/checker"
-import { ODDefaultsManager } from "../modules/defaults"
-import { ODLanguage } from "../modules/language"
-import { ODClientActivityManager } from "../modules/client"
-import { ODEvent, ODEventManager } from "../modules/event"
-import * as discord from "discord.js"
-
-//DEFAULT MODULES
-import { ODPluginClassManager_Default, ODPluginManager_Default } from "./plugin"
-import { ODConfigManager_Default} from "./config"
-import { ODDatabaseManager_Default } from "./database"
-import { ODFlagManager_Default } from "./flag"
-import { ODSessionManager_Default } from "./session"
-import { ODLanguageManager_Default } from "./language"
-import { ODCheckerFunctionManager_Default, ODCheckerManager_Default, ODCheckerRenderer_Default, ODCheckerTranslationRegister_Default } from "./checker"
-import { ODClientManager_Default, ODContextMenuManager_Default, ODSlashCommandManager_Default, ODTextCommandManager_Default } from "./client"
-import { ODBuilderManager_Default, ODButtonManager_Default, ODDropdownManager_Default, ODEmbedManager_Default, ODFileManager_Default, ODMessageManager_Default, ODModalManager_Default } from "./builder"
-import { ODAutocompleteResponderManager_Default, ODButtonResponderManager_Default, ODCommandResponderManager_Default, ODContextMenuResponderManager_Default, ODDropdownResponderManager_Default, ODModalResponderManager_Default, ODResponderManager_Default } from "./responder"
-import { ODActionManager_Default } from "./action"
-import { ODPermissionManager_Default } from "./permission"
-import { ODHelpMenuManager_Default } from "./helpmenu"
-import { ODStatsManager_Default } from "./stat"
-import { ODCodeManager_Default } from "./code"
-import { ODCooldownManager_Default } from "./cooldown"
-import { ODPostManager_Default } from "./post"
-import { ODVerifyBarManager_Default } from "./verifybar"
-import { ODStartScreenManager_Default } from "./startscreen"
-import { ODLiveStatusManager_Default } from "./console"
-import { ODProgressBarManager_Default, ODProgressBarRendererManager_Default } from "./progressbar"
-
-//OPEN TICKET MODULES
-import { ODOptionManager, ODTicketOption } from "../openticket/option"
-import { ODPanel, ODPanelManager } from "../openticket/panel"
-import { ODTicket, ODTicketClearFilter, ODTicketManager } from "../openticket/ticket"
-import { ODQuestionManager } from "../openticket/question"
-import { ODBlacklistManager } from "../openticket/blacklist"
-import { ODTranscriptManager_Default } from "../openticket/transcript"
-import { ODRole, ODRoleManager } from "../openticket/role"
-import { ODPriorityLevel, ODPriorityManager_Default } from "../openticket/priority"
-
-/**## ODEventIds_Default `interface`
- * This interface is a list of ids available in the `ODEvent_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODEventIds_Default {
- //error handling
- "onErrorHandling": ODEvent_Default<(error:Error, origin:NodeJS.UncaughtExceptionOrigin) => ODPromiseVoid>
- "afterErrorHandling": ODEvent_Default<(error:Error, origin:NodeJS.UncaughtExceptionOrigin, message:ODError) => ODPromiseVoid>
-
- //plugins
- "afterPluginsLoaded": ODEvent_Default<(plugins:ODPluginManager_Default) => ODPromiseVoid>
- "onPluginClassLoad": ODEvent_Default<(classes:ODPluginClassManager_Default, plugins:ODPluginManager_Default) => ODPromiseVoid>
- "afterPluginClassesLoaded": ODEvent_Default<(classes:ODPluginClassManager_Default, plugins:ODPluginManager_Default) => ODPromiseVoid>
-
- //flags
- "onFlagLoad": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid>
- "afterFlagsLoaded": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid>
- "onFlagInit": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid>
- "afterFlagsInitiated": ODEvent_Default<(flags:ODFlagManager_Default) => ODPromiseVoid>
-
- //progress bars
- "onProgressBarRendererLoad": ODEvent_Default<(renderers:ODProgressBarRendererManager_Default) => ODPromiseVoid>
- "afterProgressBarRenderersLoaded": ODEvent_Default<(renderers:ODProgressBarRendererManager_Default) => ODPromiseVoid>
- "onProgressBarLoad": ODEvent_Default<(progressbars:ODProgressBarManager_Default) => ODPromiseVoid>
- "afterProgressBarsLoaded": ODEvent_Default<(progressbars:ODProgressBarManager_Default) => ODPromiseVoid>
-
- //configs
- "onConfigLoad": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid>
- "afterConfigsLoaded": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid>
- "onConfigInit": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid>
- "afterConfigsInitiated": ODEvent_Default<(configs:ODConfigManager_Default) => ODPromiseVoid>
-
- //databases
- "onDatabaseLoad": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid>
- "afterDatabasesLoaded": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid>
- "onDatabaseInit": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid>
- "afterDatabasesInitiated": ODEvent_Default<(databases:ODDatabaseManager_Default) => ODPromiseVoid>
-
- //languages
- "onLanguageLoad": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid>
- "afterLanguagesLoaded": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid>
- "onLanguageInit": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid>
- "afterLanguagesInitiated": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid>
- "onLanguageSelect": ODEvent_Default<(languages:ODLanguageManager_Default) => ODPromiseVoid>
- "afterLanguagesSelected": ODEvent_Default<(main:ODLanguage|null, backup:ODLanguage|null, languages:ODLanguageManager_Default) => ODPromiseVoid>
-
- //sessions
- "onSessionLoad": ODEvent_Default<(languages:ODSessionManager_Default) => ODPromiseVoid>
- "afterSessionsLoaded": ODEvent_Default<(languages:ODSessionManager_Default) => ODPromiseVoid>
-
- //config checkers
- "onCheckerLoad": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "afterCheckersLoaded": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "onCheckerFunctionLoad": ODEvent_Default<(functions:ODCheckerFunctionManager_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "afterCheckerFunctionsLoaded": ODEvent_Default<(functions:ODCheckerFunctionManager_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "onCheckerExecute": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "afterCheckersExecuted": ODEvent_Default<(result:ODCheckerResult, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "onCheckerTranslationLoad": ODEvent_Default<(translations:ODCheckerTranslationRegister_Default, enabled:boolean, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "afterCheckerTranslationsLoaded": ODEvent_Default<(translations:ODCheckerTranslationRegister_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "onCheckerRender": ODEvent_Default<(renderer:ODCheckerRenderer_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "afterCheckersRendered": ODEvent_Default<(renderer:ODCheckerRenderer_Default, checkers:ODCheckerManager_Default) => ODPromiseVoid>
- "onCheckerQuit": ODEvent_Default<(checkers:ODCheckerManager_Default) => ODPromiseVoid>
-
- //plugin loading before client
- "onPluginBeforeClientLoad": ODEvent_Default<() => ODPromiseVoid>,
- "afterPluginBeforeClientLoaded": ODEvent_Default<() => ODPromiseVoid>,
-
- //client configuration
- "onClientLoad": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid>
- "afterClientLoaded": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid>
- "onClientInit": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid>
- "afterClientInitiated": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid>
- "onClientReady": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid>
- "afterClientReady": ODEvent_Default<(client:ODClientManager_Default) => ODPromiseVoid>
- "onClientActivityLoad": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid>
- "afterClientActivityLoaded": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid>
- "onClientActivityInit": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid>
- "afterClientActivityInitiated": ODEvent_Default<(activity:ODClientActivityManager, client:ODClientManager_Default) => ODPromiseVoid>
-
- //priority levels
- "onPriorityLoad": ODEvent_Default<(priorities:ODPriorityManager_Default) => ODPromiseVoid>
- "afterPrioritiesLoaded": ODEvent_Default<(priorities:ODPriorityManager_Default) => ODPromiseVoid>
-
- //client slash commands
- "onSlashCommandLoad": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
- "afterSlashCommandsLoaded": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
- "onSlashCommandRegister": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
- "afterSlashCommandsRegistered": ODEvent_Default<(slash:ODSlashCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
-
- //client context menus
- "onContextMenuLoad": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
- "afterContextMenusLoaded": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
- "onContextMenuRegister": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
- "afterContextMenusRegistered": ODEvent_Default<(menu:ODContextMenuManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
-
- //client text commands
- "onTextCommandLoad": ODEvent_Default<(text:ODTextCommandManager_Default, client:ODClientManager_Default,) => ODPromiseVoid>
- "afterTextCommandsLoaded": ODEvent_Default<(text:ODTextCommandManager_Default, client:ODClientManager_Default) => ODPromiseVoid>
-
- //plugin loading before managers
- "onPluginBeforeManagerLoad": ODEvent_Default<() => ODPromiseVoid>,
- "afterPluginBeforeManagerLoaded": ODEvent_Default<() => ODPromiseVoid>,
-
- //questions
- "onQuestionLoad": ODEvent_Default<(questions:ODQuestionManager) => ODPromiseVoid>
- "afterQuestionsLoaded": ODEvent_Default<(questions:ODQuestionManager) => ODPromiseVoid>
-
- //options
- "onOptionLoad": ODEvent_Default<(options:ODOptionManager) => ODPromiseVoid>
- "afterOptionsLoaded": ODEvent_Default<(options:ODOptionManager) => ODPromiseVoid>
-
- //panels
- "onPanelLoad": ODEvent_Default<(panels:ODPanelManager) => ODPromiseVoid>
- "afterPanelsLoaded": ODEvent_Default<(panels:ODPanelManager) => ODPromiseVoid>
- "onPanelSpawn": ODEvent_Default<(panel:ODPanel) => ODPromiseVoid>
- "afterPanelSpawned": ODEvent_Default<(panel:ODPanel) => ODPromiseVoid>
-
- //tickets
- "onTicketLoad": ODEvent_Default<(tickets:ODTicketManager) => ODPromiseVoid>
- "afterTicketsLoaded": ODEvent_Default<(tickets:ODTicketManager) => ODPromiseVoid>
-
- //ticket creation
- "onTicketChannelCreation": ODEvent_Default<(option:ODTicketOption, user:discord.User) => ODPromiseVoid>
- "afterTicketChannelCreated": ODEvent_Default<(option:ODTicketOption, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid>
- "onTicketChannelDeletion": ODEvent_Default<(ticket:ODTicket, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid>
- "afterTicketChannelDeleted": ODEvent_Default<(ticket:ODTicket, user:discord.User) => ODPromiseVoid>
- "onTicketPermissionsCreated": ODEvent_Default<(option:ODTicketOption, permissions:ODPermissionManager_Default, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid>
- "afterTicketPermissionsCreated": ODEvent_Default<(option:ODTicketOption, permissions:ODPermissionManager_Default, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid>
- "onTicketMainMessageCreated": ODEvent_Default<(ticket:ODTicket, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid>
- "afterTicketMainMessageCreated": ODEvent_Default<(ticket:ODTicket, message:discord.Message, channel:discord.GuildTextBasedChannel, user:discord.User) => ODPromiseVoid>
-
- //ticket actions
- "onTicketCreate": ODEvent_Default<(creator:discord.User) => ODPromiseVoid>
- "afterTicketCreated": ODEvent_Default<(ticket:ODTicket, creator:discord.User, channel:discord.GuildTextBasedChannel) => ODPromiseVoid>
- "onTicketClose": ODEvent_Default<(ticket:ODTicket, closer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketClosed": ODEvent_Default<(ticket:ODTicket, closer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketReopen": ODEvent_Default<(ticket:ODTicket, reopener:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketReopened": ODEvent_Default<(ticket:ODTicket, reopener:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketDelete": ODEvent_Default<(ticket:ODTicket, deleter:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketDeleted": ODEvent_Default<(ticket:ODTicket, deleter:discord.User, reason:string|null) => ODPromiseVoid>
- "onTicketMove": ODEvent_Default<(ticket:ODTicket, mover:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketMoved": ODEvent_Default<(ticket:ODTicket, mover:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketClaim": ODEvent_Default<(ticket:ODTicket, claimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketClaimed": ODEvent_Default<(ticket:ODTicket, claimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketUnclaim": ODEvent_Default<(ticket:ODTicket, unclaimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketUnclaimed": ODEvent_Default<(ticket:ODTicket, unclaimer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketPin": ODEvent_Default<(ticket:ODTicket, pinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketPinned": ODEvent_Default<(ticket:ODTicket, pinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketUnpin": ODEvent_Default<(ticket:ODTicket, unpinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketUnpinned": ODEvent_Default<(ticket:ODTicket, unpinner:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketUserAdd": ODEvent_Default<(ticket:ODTicket, adder:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketUserAdded": ODEvent_Default<(ticket:ODTicket, adder:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketUserRemove": ODEvent_Default<(ticket:ODTicket, remover:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketUserRemoved": ODEvent_Default<(ticket:ODTicket, remover:discord.User, user:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketRename": ODEvent_Default<(ticket:ODTicket, renamer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "afterTicketRenamed": ODEvent_Default<(ticket:ODTicket, renamer:discord.User, channel:discord.GuildTextBasedChannel, reason:string|null) => ODPromiseVoid>
- "onTicketsClear": ODEvent_Default<(tickets:ODTicket[], clearer:discord.User, channel:discord.GuildTextBasedChannel, filter:ODTicketClearFilter) => ODPromiseVoid>
- "afterTicketsCleared": ODEvent_Default<(tickets:ODTicket[], clearer:discord.User, channel:discord.GuildTextBasedChannel, filter:ODTicketClearFilter) => ODPromiseVoid>
- "onTicketTopicChange": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldTopic:string, newTopic:string) => ODPromiseVoid>
- "afterTicketTopicChanged": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldTopic:string, newTopic:string) => ODPromiseVoid>
- "onTicketPriorityChange": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldPriority:ODPriorityLevel, newPriority:ODPriorityLevel, reason:string|null) => ODPromiseVoid>
- "afterTicketPriorityChanged": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldPriority:ODPriorityLevel, newPriority:ODPriorityLevel, reason:string|null) => ODPromiseVoid>
- "onTicketTransfer": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldCreator:discord.User, newCreator:discord.User, reason:string|null) => ODPromiseVoid>
- "afterTicketTransferred": ODEvent_Default<(ticket:ODTicket, changer:discord.User, channel:discord.GuildTextBasedChannel, oldCreator:discord.User, newCreator:discord.User, reason:string|null) => ODPromiseVoid>
-
- //roles
- "onRoleLoad": ODEvent_Default<(roles:ODRoleManager) => ODPromiseVoid>
- "afterRolesLoaded": ODEvent_Default<(roles:ODRoleManager) => ODPromiseVoid>
- "onRoleUpdate": ODEvent_Default<(user:discord.User,role:ODRole) => ODPromiseVoid>
- "afterRolesUpdated": ODEvent_Default<(user:discord.User,role:ODRole) => ODPromiseVoid>
-
- //blacklist
- "onBlacklistLoad": ODEvent_Default<(blacklist:ODBlacklistManager) => ODPromiseVoid>
- "afterBlacklistLoaded": ODEvent_Default<(blacklist:ODBlacklistManager) => ODPromiseVoid>
-
- //transcripts
- "onTranscriptCompilerLoad": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid>
- "afterTranscriptCompilersLoaded": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid>
- "onTranscriptHistoryLoad": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid>
- "afterTranscriptHistoryLoaded": ODEvent_Default<(transcripts:ODTranscriptManager_Default) => ODPromiseVoid>
-
- //transcript creation
- "onTranscriptCreate": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "afterTranscriptCreated": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "onTranscriptInit": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "afterTranscriptInitiated": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "onTranscriptCompile": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "afterTranscriptCompiled": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "onTranscriptReady": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
- "afterTranscriptReady": ODEvent_Default<(transcripts:ODTranscriptManager_Default,ticket:ODTicket,channel:discord.TextChannel,user:discord.User) => ODPromiseVoid>
-
- //plugin loading before builders
- "onPluginBeforeBuilderLoad": ODEvent_Default<() => ODPromiseVoid>,
- "afterPluginBeforeBuilderLoaded": ODEvent_Default<() => ODPromiseVoid>,
-
- //builders
- "onButtonBuilderLoad": ODEvent_Default<(buttons:ODButtonManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterButtonBuildersLoaded": ODEvent_Default<(buttons:ODButtonManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onDropdownBuilderLoad": ODEvent_Default<(dropdowns:ODDropdownManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterDropdownBuildersLoaded": ODEvent_Default<(dropdowns:ODDropdownManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onFileBuilderLoad": ODEvent_Default<(files:ODFileManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterFileBuildersLoaded": ODEvent_Default<(files:ODFileManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onEmbedBuilderLoad": ODEvent_Default<(embeds:ODEmbedManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterEmbedBuildersLoaded": ODEvent_Default<(embeds:ODEmbedManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onMessageBuilderLoad": ODEvent_Default<(messages:ODMessageManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterMessageBuildersLoaded": ODEvent_Default<(messages:ODMessageManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onModalBuilderLoad": ODEvent_Default<(modals:ODModalManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterModalBuildersLoaded": ODEvent_Default<(modals:ODModalManager_Default, builders:ODBuilderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
-
- //plugin loading before responders
- "onPluginBeforeResponderLoad": ODEvent_Default<() => ODPromiseVoid>,
- "afterPluginBeforeResponderLoaded": ODEvent_Default<() => ODPromiseVoid>,
-
- //responders
- "onCommandResponderLoad": ODEvent_Default<(commands:ODCommandResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterCommandRespondersLoaded": ODEvent_Default<(commands:ODCommandResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onButtonResponderLoad": ODEvent_Default<(buttons:ODButtonResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterButtonRespondersLoaded": ODEvent_Default<(buttons:ODButtonResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onDropdownResponderLoad": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterDropdownRespondersLoaded": ODEvent_Default<(dropdowns:ODDropdownResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onModalResponderLoad": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterModalRespondersLoaded": ODEvent_Default<(modals:ODModalResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onContextMenuResponderLoad": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterContextMenuRespondersLoaded": ODEvent_Default<(menus:ODContextMenuResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "onAutocompleteResponderLoad": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
- "afterAutocompleteRespondersLoaded": ODEvent_Default<(autocomplete:ODAutocompleteResponderManager_Default, responders:ODResponderManager_Default, actions:ODActionManager_Default) => ODPromiseVoid>
-
- //plugin loading before finalizations
- "onPluginBeforeFinalizationLoad": ODEvent_Default<() => ODPromiseVoid>,
- "afterPluginBeforeFinalizationLoaded": ODEvent_Default<() => ODPromiseVoid>,
-
- //actions
- "onActionLoad": ODEvent_Default<(actions:ODActionManager_Default) => ODPromiseVoid>
- "afterActionsLoaded": ODEvent_Default<(actions:ODActionManager_Default) => ODPromiseVoid>
-
- //verifybars
- "onVerifyBarLoad": ODEvent_Default<(verifybars:ODVerifyBarManager_Default) => ODPromiseVoid>
- "afterVerifyBarsLoaded": ODEvent_Default<(verifybars:ODVerifyBarManager_Default) => ODPromiseVoid>
-
- //permissions
- "onPermissionLoad": ODEvent_Default<(permissions:ODPermissionManager_Default) => ODPromiseVoid>
- "afterPermissionsLoaded": ODEvent_Default<(permissions:ODPermissionManager_Default) => ODPromiseVoid>
-
- //posts
- "onPostLoad": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid>
- "afterPostsLoaded": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid>
- "onPostInit": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid>
- "afterPostsInitiated": ODEvent_Default<(posts:ODPostManager_Default) => ODPromiseVoid>
-
- //cooldowns
- "onCooldownLoad": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid>
- "afterCooldownsLoaded": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid>
- "onCooldownInit": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid>
- "afterCooldownsInitiated": ODEvent_Default<(cooldowns:ODCooldownManager_Default) => ODPromiseVoid>
-
- //help menu
- "onHelpMenuCategoryLoad": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid>
- "afterHelpMenuCategoriesLoaded": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid>
- "onHelpMenuComponentLoad": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid>
- "afterHelpMenuComponentsLoaded": ODEvent_Default<(menu:ODHelpMenuManager_Default) => ODPromiseVoid>
-
- //stats
- "onStatScopeLoad": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid>
- "afterStatScopesLoaded": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid>
- "onStatLoad": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid>
- "afterStatsLoaded": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid>
- "onStatInit": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid>
- "afterStatsInitiated": ODEvent_Default<(stats:ODStatsManager_Default) => ODPromiseVoid>
-
- //plugin loading before code
- "onPluginBeforeCodeLoad": ODEvent_Default<() => ODPromiseVoid>,
- "afterPluginBeforeCodeLoaded": ODEvent_Default<() => ODPromiseVoid>,
-
- //code
- "onCodeLoad": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid>
- "afterCodeLoaded": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid>
- "onCodeExecute": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid>
- "afterCodeExecuted": ODEvent_Default<(code:ODCodeManager_Default) => ODPromiseVoid>
-
- //livestatus
- "onLiveStatusSourceLoad": ODEvent_Default<(livestatus:ODLiveStatusManager_Default) => ODPromiseVoid>
- "afterLiveStatusSourcesLoaded": ODEvent_Default<(livestatus:ODLiveStatusManager_Default) => ODPromiseVoid>
-
- //startscreen
- "onStartScreenLoad": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid>
- "afterStartScreensLoaded": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid>
- "onStartScreenRender": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid>
- "afterStartScreensRendered": ODEvent_Default<(startscreen:ODStartScreenManager_Default) => ODPromiseVoid>
-
- //ready
- "beforeReadyForUsage": ODEvent_Default<() => ODPromiseVoid>
- "onReadyForUsage": ODEvent_Default<() => ODPromiseVoid>
-}
-
-/**## ODEventManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODEvent class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.events`!
- */
-export class ODEventManager_Default extends ODEventManager {
- get(id:StartScreenId): ODEventIds_Default[StartScreenId]
- get(id:ODValidId): ODEvent|null
-
- get(id:ODValidId): ODEvent|null {
- return super.get(id)
- }
-
- remove(id:StartScreenId): ODEventIds_Default[StartScreenId]
- remove(id:ODValidId): ODEvent|null
-
- remove(id:ODValidId): ODEvent|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODEventIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODEventManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODEvent class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.events`!
- */
-export class ODEvent_Default ODPromiseVoid)> extends ODEvent {
- listen(callback:Callback): void {
- return super.listen(callback)
- }
- listenOnce(callback:Callback): void {
- return super.listenOnce(callback)
- }
- wait(): Promise>
- wait(): Promise {
- return super.wait()
- }
- emit(params:Parameters): Promise {
- return super.emit(params)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/flag.ts b/src/core/api/defaults/flag.ts
deleted file mode 100644
index 8830cc2..0000000
--- a/src/core/api/defaults/flag.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-///////////////////////////////////////
-//DEFAULT PROCESS MODULE
-///////////////////////////////////////
-import { ODValidId } from "../modules/base"
-import { ODFlagManager, ODFlag } from "../modules/flag"
-
-/**## ODFlagManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODFlagManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODFlagManagerIds_Default {
- "opendiscord:no-migration":ODFlag,
- "opendiscord:dev-config":ODFlag,
- "opendiscord:dev-database":ODFlag,
- "opendiscord:debug":ODFlag,
- "opendiscord:crash":ODFlag,
- "opendiscord:no-transcripts":ODFlag,
- "opendiscord:no-checker":ODFlag,
- "opendiscord:checker":ODFlag,
- "opendiscord:no-easter":ODFlag,
- "opendiscord:no-plugins":ODFlag,
- "opendiscord:soft-plugins":ODFlag,
- "opendiscord:force-slash-update":ODFlag,
- "opendiscord:no-compile":ODFlag,
- "opendiscord:compile-only":ODFlag,
- "opendiscord:silent":ODFlag,
- "opendiscord:cli":ODFlag,
-}
-
-/**## ODFlagManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODFlagManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.flags`!
- */
-export class ODFlagManager_Default extends ODFlagManager {
- get(id:FlagId): ODFlagManagerIds_Default[FlagId]
- get(id:ODValidId): ODFlag|null
-
- get(id:ODValidId): ODFlag|null {
- return super.get(id)
- }
-
- remove(id:FlagId): ODFlagManagerIds_Default[FlagId]
- remove(id:ODValidId): ODFlag|null
-
- remove(id:ODValidId): ODFlag|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODFlagManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
\ No newline at end of file
diff --git a/src/core/api/defaults/helpmenu.ts b/src/core/api/defaults/helpmenu.ts
deleted file mode 100644
index 9864f18..0000000
--- a/src/core/api/defaults/helpmenu.ts
+++ /dev/null
@@ -1,338 +0,0 @@
-///////////////////////////////////////
-//DEFAULT HELP MODULE
-///////////////////////////////////////
-import { ODValidId } from "../modules/base"
-import { ODHelpMenuCategory, ODHelpMenuCommandComponent, ODHelpMenuComponent, ODHelpMenuManager } from "../modules/helpmenu"
-
-/** (CONTRIBUTOR GUIDE) HOW TO ADD NEW COMMANDS?
- * - Register the command in loadAllSlashCommands() & loadAllTextCommands() in (./src/data/framework/commandLoader.ts)
- * - Add autocomplete for the command in OD(Slash/Text)CommandManagerIds_Default in (./src/core/api/defaults/client.ts)
- * - Add the command to the help menu in (./src/data/framework/helpMenuLoader.ts)
- * - If required, new config variables should be added (incl. logs, dm-logs & permissions).
- * - Update the Open Ticket Documentation.
- * - If the command contains complex logic or can be executed from a button/dropdown, it should be placed inside an `ODAction`.
- * - Check all files, test the bot carefully & try a lot of different scenario's with different settings.
- */
-
-/**## ODHelpMenuManagerIds_Default `interface`
- * This interface is a list of ids available in the `ODHelpMenuManager_Default` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODHelpMenuManagerIds_Default {
- "opendiscord:general":ODHelpMenuCategory_DefaultGeneral,
- "opendiscord:ticket-basic":ODHelpMenuCategory_DefaultTicketBasic,
- "opendiscord:ticket-advanced":ODHelpMenuCategory_DefaultTicketAdvanced,
- "opendiscord:ticket-user":ODHelpMenuCategory_DefaultTicketUser,
- "opendiscord:admin":ODHelpMenuCategory_DefaultAdmin,
- "opendiscord:advanced":ODHelpMenuCategory_DefaultAdvanced,
- "opendiscord:extra":ODHelpMenuCategory_DefaultExtra
-}
-
-/**## ODHelpMenuManager_Default `default_class`
- * This is a special class that adds type definitions & typescript to the ODHelpMenuManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the global variable `opendiscord.helpmenu`!
- */
-export class ODHelpMenuManager_Default extends ODHelpMenuManager {
- get(id:HelpMenuCategoryId): ODHelpMenuManagerIds_Default[HelpMenuCategoryId]
- get(id:ODValidId): ODHelpMenuCategory|null
-
- get(id:ODValidId): ODHelpMenuCategory|null {
- return super.get(id)
- }
-
- remove(id:HelpMenuCategoryId): ODHelpMenuManagerIds_Default[HelpMenuCategoryId]
- remove(id:ODValidId): ODHelpMenuCategory|null
-
- remove(id:ODValidId): ODHelpMenuCategory|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODHelpMenuManagerIds_Default): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODHelpMenuManagerCategoryIds_DefaultGeneral `type`
- * This interface is a list of ids available in the `ODHelpMenuCategory_DefaultGeneral` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODHelpMenuManagerCategoryIds_DefaultGeneral {
- "opendiscord:help":ODHelpMenuCommandComponent,
- "opendiscord:ticket":ODHelpMenuCommandComponent|null
-}
-
-/**## ODHelpMenuCategory_DefaultGeneral `default_class`
- * This is a special class that adds type definitions & typescript to the ODHelpMenuManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `opendiscord:general` category in `opendiscord.helpmenu`!
- */
-export class ODHelpMenuCategory_DefaultGeneral extends ODHelpMenuCategory {
- get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultGeneral[HelpMenuCategoryId]
- get(id:ODValidId): ODHelpMenuComponent|null
-
- get(id:ODValidId): ODHelpMenuComponent|null {
- return super.get(id)
- }
-
- remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultGeneral[HelpMenuCategoryId]
- remove(id:ODValidId): ODHelpMenuComponent|null
-
- remove(id:ODValidId): ODHelpMenuComponent|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultGeneral): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODHelpMenuManagerCategoryIds_DefaultTicketBasic `type`
- * This interface is a list of ids available in the `ODHelpMenuCategory_DefaultTicketBasic` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODHelpMenuManagerCategoryIds_DefaultTicketBasic {
- "opendiscord:close":ODHelpMenuCommandComponent,
- "opendiscord:delete":ODHelpMenuCommandComponent,
- "opendiscord:reopen":ODHelpMenuCommandComponent
-}
-
-/**## ODHelpMenuCategory_DefaultTicketBasic `default_class`
- * This is a special class that adds type definitions & typescript to the ODHelpMenuManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `opendiscord:ticket` category in `opendiscord.helpmenu`!
- */
-export class ODHelpMenuCategory_DefaultTicketBasic extends ODHelpMenuCategory {
- get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketBasic[HelpMenuCategoryId]
- get(id:ODValidId): ODHelpMenuComponent|null
-
- get(id:ODValidId): ODHelpMenuComponent|null {
- return super.get(id)
- }
-
- remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketBasic[HelpMenuCategoryId]
- remove(id:ODValidId): ODHelpMenuComponent|null
-
- remove(id:ODValidId): ODHelpMenuComponent|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultTicketBasic): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced `type`
- * This interface is a list of ids available in the `ODHelpMenuCategory_DefaultTicketAdvanced` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced {
- "opendiscord:pin":ODHelpMenuCommandComponent,
- "opendiscord:unpin":ODHelpMenuCommandComponent,
- "opendiscord:move":ODHelpMenuCommandComponent,
- "opendiscord:rename":ODHelpMenuCommandComponent
-}
-
-/**## ODHelpMenuCategory_DefaultTicketAdvanced `default_class`
- * This is a special class that adds type definitions & typescript to the ODHelpMenuManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `opendiscord:ticket` category in `opendiscord.helpmenu`!
- */
-export class ODHelpMenuCategory_DefaultTicketAdvanced extends ODHelpMenuCategory {
- get(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced[HelpMenuCategoryId]
- get(id:ODValidId): ODHelpMenuComponent|null
-
- get(id:ODValidId): ODHelpMenuComponent|null {
- return super.get(id)
- }
-
- remove(id:HelpMenuCategoryId): ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced[HelpMenuCategoryId]
- remove(id:ODValidId): ODHelpMenuComponent|null
-
- remove(id:ODValidId): ODHelpMenuComponent|null {
- return super.remove(id)
- }
-
- exists(id:keyof ODHelpMenuManagerCategoryIds_DefaultTicketAdvanced): boolean
- exists(id:ODValidId): boolean
-
- exists(id:ODValidId): boolean {
- return super.exists(id)
- }
-}
-
-/**## ODHelpMenuManagerCategoryIds_DefaultTicketUser `type`
- * This interface is a list of ids available in the `ODHelpMenuCategory_DefaultTicketUser` class.
- * It's used to generate typescript declarations for this class.
- */
-export interface ODHelpMenuManagerCategoryIds_DefaultTicketUser {
- "opendiscord:claim":ODHelpMenuCommandComponent,
- "opendiscord:unclaim":ODHelpMenuCommandComponent,
- "opendiscord:add":ODHelpMenuCommandComponent,
- "opendiscord:remove":ODHelpMenuCommandComponent,
- "opendiscord:transfer":ODHelpMenuCommandComponent,
-}
-
-/**## ODHelpMenuCategory_DefaultTicketUser `default_class`
- * This is a special class that adds type definitions & typescript to the ODHelpMenuManager class.
- * It doesn't add any extra features!
- *
- * This default class is made for the `opendiscord:ticket` category in `opendiscord.helpmenu`!
- */
-export class ODHelpMenuCategory_DefaultTicketUser extends ODHelpMenuCategory {
- get