Merge branch 'dev-v4.2' into pr/208
This commit is contained in:
@@ -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")
|
|
||||||
@@ -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": "../"
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Contributing Guidelines
|
# Contributing Guidelines
|
||||||
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px">
|
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px">
|
||||||
|
|
||||||
[](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!<br>
|
These are the Contributing Guidelines of Open Ticket!<br>
|
||||||
Here you can find everything you need to know about contributing to Open Ticket.<br>
|
Here you can find everything you need to know about contributing to Open Ticket.<br>
|
||||||
|
|||||||
@@ -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":""}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 2.4 MiB |
+8
-11
@@ -19,18 +19,15 @@ This list will be updated on every release.
|
|||||||
|
|
||||||
| Version | Supported | Notes |
|
| Version | Supported | Notes |
|
||||||
|------------|-----------|---------------------------------------------------------------|
|
|------------|-----------|---------------------------------------------------------------|
|
||||||
| 4.2.0 | 🟦 | In Development |
|
| 4.2.x | 🟦 | In Development |
|
||||||
| 4.1.x | 🟦 | In Development |
|
| 4.2.1 | 🟦 | In Development |
|
||||||
| 4.1.3 | ✅ | |
|
| 4.2.0 | ✅ | |
|
||||||
| 4.1.2 | ✅ | |
|
| 4.1.3 | ✅ | (LTS) Long-Term-Support, Until September 2026 |
|
||||||
| 4.1.1 | ✅ | Supported Until April 2026 (LTS) |
|
| 4.1.2 | 🚧 | |
|
||||||
|
| 4.1.1 | 🚧 | |
|
||||||
| 4.1.0 | 🚧 | |
|
| 4.1.0 | 🚧 | |
|
||||||
| 4.0.7 | 🚧 | |
|
| 4.0.7 | 🟧 | Deprecated |
|
||||||
| 4.0.6 | 🚧 | |
|
| < 4.0.7 | ❌ | |
|
||||||
| 4.0.5 | 🟧 | Deprecated |
|
|
||||||
| 4.0.4 | 🟧 | Deprecated |
|
|
||||||
| < 4.0.4 | 🟧 | Deprecated, Transcripts v2.0, Documentation Only |
|
|
||||||
| < 4.0.0 | ❌ | |
|
|
||||||
|
|
||||||
### 🕷️ Reporting Vulnerabilities
|
### 🕷️ Reporting Vulnerabilities
|
||||||
You can report vulnerabilities, errors & bugs using one of the following methods:
|
You can report vulnerabilities, errors & bugs using one of the following methods:
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 124 KiB |
@@ -2,7 +2,7 @@
|
|||||||
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px">
|
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="500px">
|
||||||
|
|
||||||
[](https://discord.com/invite/26vT9wt3n3)
|
[](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)
|
[](https://github.com/sponsors/DJj123dj)
|
||||||
[](.eggs/README.md)
|
[](.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)
|
[**`openticket-egg-main.json` (Recommended)**](openticket-egg-main.json)
|
||||||
- This egg will use the `main` branch of Open Ticket.
|
- 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)
|
[**`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.
|
- This egg will always use Open Ticket `v4.1.3`. Open Ticket updates will not have an effect on this egg.
|
||||||
|
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
+7
-4
@@ -17,7 +17,10 @@ otdebug.txt
|
|||||||
*/*/*/.DS_Store
|
*/*/*/.DS_Store
|
||||||
**/.DS_Store
|
**/.DS_Store
|
||||||
|
|
||||||
.docs/*
|
.backup/*
|
||||||
!.docs/createDocs.js
|
.tools/*
|
||||||
!.docs/mergeTranslations.js
|
!.tools/createSponsors.ts
|
||||||
!.docs/typedoc-config.json
|
!.tools/createContributors.ts
|
||||||
|
!.tools/mergeTranslations.ts
|
||||||
|
!.tools/docker-compose.yml
|
||||||
|
!.tools/dockerfile
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/// <reference types="node"/>
|
||||||
|
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 `<text x="${20}" y="${yPos+20}" text-anchor="start" class="contributor-tier-title">${name}</text>`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createPfp(yPos:number,xPos:number,size:number,contributor:Contributor,withNames:boolean){
|
||||||
|
const randomId = crypto.randomBytes(8).toString("hex")
|
||||||
|
const nameElement = (withNames) ? `<text x="${Math.round(xPos+(size/2))}" y="${yPos+size+20}" text-anchor="middle" fill="currentColor">${contributor.name}</text>` : ""
|
||||||
|
|
||||||
|
return (`<a href="${contributor.profileUrl}" class="contributor-link" target="_blank">
|
||||||
|
<clipPath id="clipPath-${randomId}">
|
||||||
|
<rect x="${xPos}" y="${yPos}" width="${size}" height="${size}" rx="${CORNER_RADIUS}" ry="${CORNER_RADIUS}"/>
|
||||||
|
</clipPath>
|
||||||
|
<image x="${xPos}" y="${yPos}" width="${size}" height="${size}" href="${await downloadPfpToBase64URL(contributor.pictureUrl)}" clip-path="url(#clipPath-${randomId})"/>
|
||||||
|
${nameElement}
|
||||||
|
</a>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${SVG_WIDTH} ${sectionHeight}" width="${SVG_WIDTH}" height="${sectionHeight}">
|
||||||
|
<style>
|
||||||
|
text {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 14px;
|
||||||
|
fill: #777777;
|
||||||
|
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
}
|
||||||
|
.contributor-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.contributor-tier-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
${sectionsHtml}
|
||||||
|
</svg>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//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()
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/// <reference types="node"/>
|
||||||
|
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 `<text x="${Math.round(SVG_WIDTH/2)}" y="${yPos+20}" text-anchor="middle" class="sponsor-tier-title">${name}</text>`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createPfp(yPos:number,xPos:number,size:number,sponsor:Sponsor,withNames:boolean){
|
||||||
|
const randomId = crypto.randomBytes(8).toString("hex")
|
||||||
|
const nameElement = (withNames) ? `<text x="${Math.round(xPos+(size/2))}" y="${yPos+size+20}" text-anchor="middle" fill="currentColor">${sponsor.name}</text>` : ""
|
||||||
|
|
||||||
|
return (`<a href="${sponsor.profileUrl}" class="sponsor-link" target="_blank">
|
||||||
|
<clipPath id="clipPath-${randomId}">
|
||||||
|
<rect x="${xPos}" y="${yPos}" width="${size}" height="${size}" rx="${CORNER_RADIUS}" ry="${CORNER_RADIUS}"/>
|
||||||
|
</clipPath>
|
||||||
|
<image x="${xPos}" y="${yPos}" width="${size}" height="${size}" href="${await downloadPfpToBase64URL(sponsor.pictureUrl)}" clip-path="url(#clipPath-${randomId})"/>
|
||||||
|
${nameElement}
|
||||||
|
</a>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 ${SVG_WIDTH} ${sectionHeight}" width="${SVG_WIDTH}" height="${sectionHeight}">
|
||||||
|
<style>
|
||||||
|
text {
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 14px;
|
||||||
|
fill: #777777;
|
||||||
|
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
}
|
||||||
|
.sponsor-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.sponsor-tier-title {
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<rect x="2" y="2" width="${SVG_WIDTH-4}" height="${sectionHeight-4}" rx="20" ry="20" style="fill:transparent;stroke:#f8ba00;stroke-width:3"></rect>
|
||||||
|
${sectionsHtml}
|
||||||
|
</svg>`)
|
||||||
|
}
|
||||||
|
|
||||||
|
//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()
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
//@ts-check
|
|
||||||
const fjs = require("formatted-json-stringify")
|
import fjs from "formatted-json-stringify"
|
||||||
const fs = require("fs")
|
import fs from "fs"
|
||||||
|
|
||||||
const formatter = new fjs.ObjectFormatter(null,true,[
|
const formatter = new fjs.ObjectFormatter(null,true,[
|
||||||
new fjs.ObjectFormatter("_TRANSLATION",true,[
|
new fjs.ObjectFormatter("_TRANSLATION",true,[
|
||||||
new fjs.PropertyFormatter("otversion"),
|
new fjs.PropertyFormatter("otversion"),
|
||||||
@@ -4,186 +4,169 @@
|
|||||||
<sub align="center">Related Projects:</sub><br>
|
<sub align="center">Related Projects:</sub><br>
|
||||||
<a href="https://odplugins.dj-dj.be"><img src="https://apis.dj-dj.be/cdn/opendiscord/logo.png" alt="Open Discord" height="55px"></a><br><br>
|
<a href="https://odplugins.dj-dj.be"><img src="https://apis.dj-dj.be/cdn/opendiscord/logo.png" alt="Open Discord" height="55px"></a><br><br>
|
||||||
<a href="https://discord.com/invite/26vT9wt3n3"><img alt="Discord Invite Link" src="https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord"></img></a>
|
<a href="https://discord.com/invite/26vT9wt3n3"><img alt="Discord Invite Link" src="https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord"></img></a>
|
||||||
<a href="https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.3"><img alt="Open Ticket Version" src="https://img.shields.io/badge/version-4.1.3-brightgreen.svg?style=flat-square"></img></a>
|
<a href="https://github.com/open-discord-bots/open-ticket/releases/tag/v4.2.0"><img alt="Open Ticket Version" src="https://img.shields.io/badge/version-4.2.0-brightgreen.svg?style=flat-square"></img></a>
|
||||||
<a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Documentation" src="https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm"></img></a>
|
<a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Documentation" src="https://img.shields.io/badge/discord.js-v14-CB3837.svg?style=flat-square&logo=npm"></img></a>
|
||||||
<a href="https://github.com/open-discord-bots/open-ticket/blob/main/LICENSE"><img alt="Open Ticket License" src="https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square"></img></a>
|
<a href="https://github.com/open-discord-bots/open-ticket/blob/main/LICENSE"><img alt="Open Ticket License" src="https://img.shields.io/badge/license-GPL%203.0-important.svg?style=flat-square"></img></a>
|
||||||
<a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Stars" src="https://img.shields.io/github/stars/djj123dj/open-ticket?color=yellow&label=stars&logo=github&style=flat-square"></img></a>
|
<a href="https://otdocs.dj-dj.be"><img alt="Open Ticket Stars" src="https://img.shields.io/github/stars/djj123dj/open-ticket?color=yellow&label=stars&logo=github&style=flat-square"></img></a>
|
||||||
<br>
|
|
||||||
<a href="https://github.com/sponsors/DJj123dj"><img alt="Sponsor DJj123dj" src="https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors"></img></a>
|
<a href="https://github.com/sponsors/DJj123dj"><img alt="Sponsor DJj123dj" src="https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors"></img></a>
|
||||||
<a href="https://hub.docker.com/repository/docker/djj123dj/open-ticket"><img alt="Open Ticket supports Docker!" src="https://img.shields.io/badge/docker-supported-2496ED?style=flat-square&logo=docker"></img></a>
|
<a href="https://hub.docker.com/repository/docker/djj123dj/open-ticket"><img alt="Open Ticket supports Docker!" src="https://img.shields.io/badge/docker-supported-2496ED?style=flat-square&logo=docker"></img></a>
|
||||||
<a href=".eggs/README.md"><img alt="Open Ticket supports Pterodactyl Eggs!" src="https://img.shields.io/badge/pterodactyl-supported-10539F?style=flat-square&logo=pterodactyl"></img></a>
|
<a href=".github/pterodactyl-eggs/README.md"><img alt="Open Ticket supports Pterodactyl Eggs!" src="https://img.shields.io/badge/pterodactyl-supported-10539F?style=flat-square&logo=pterodactyl"></img></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
Open Ticket is the most <b>advanced and customizable</b> Discord ticket bot available. With <b>350+ configurable settings</b>, you have full control over every aspect of your ticket system!
|
Open Ticket is the most <b>advanced and customizable</b> Discord ticket bot available right now. It features more than <b>350+ configurable settings</b> to control almost every aspect of your ticket system.
|
||||||
From <code>HTML transcripts</code> and <code>Advanced Plugins</code> to <code>Claiming & Pinning</code>, <code>Questions & Modals</code>, <code>Detailed Statistics</code>, and much more.<br><br>
|
From <code>HTML transcripts</code> and <code>Advanced Plugins</code> to <code>Claiming & Pinning</code>, <code>Modal Questions & Limits</code>, <code>Detailed Statistics</code>, and much more.
|
||||||
The bot is fully translated into <b>36+ languages</b> and has been battle-tested in large Discord servers.<br>
|
The bot is fully translated into <b>38+ languages</b> and has been battle-tested in large Discord servers. Need help or want to get involved? Feel free to join our <a href="https://discord.dj-dj.be"><b>Discord server</b></a>.
|
||||||
Need help or want to get involved? Feel free to join our <a href="https://discord.dj-dj.be"><b>Discord server</b></a>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 align="center"><b>⭐️ Support Open Ticket’s growth by starring this repo! ⭐️</b></h3>
|
<h3 align="center"><b>⭐️ Support Open Ticket’s growth by starring this repo! ⭐️</b></h3>
|
||||||
<p align="center"><sup>❤️ Love Open Ticket? <a href="https://github.com/sponsors/DJj123dj">Sponsorships</a> help fuel our HTML transcript servers and future features! ❤️</sup></p>
|
<p align="center"><sup>❤️ Love Open Ticket? <a href="https://github.com/sponsors/DJj123dj">Sponsorships</a> help fuel our HTML transcript servers and future features! ❤️</sup><br>
|
||||||
|
<img align="center" src=".github/SPONSORS.svg" alt="Open Ticket" width="800px">
|
||||||
|
</p>
|
||||||
|
|
||||||
---
|
---
|
||||||
> **[-> Navigate to (⏱️ Quick Setup)](#️-quick-start-using-cli)**
|
> **[-> Navigate to (⏱️ Quick Setup)](#️-quick-start)**
|
||||||
> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
|
> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
|
||||||
> **[-> Navigate to (📞 Support Server)](https://discord.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)**
|
||||||
|
|
||||||
### 📌 Features
|
### 📌 Features
|
||||||
- **⏳ Quick Setup** - Using the interactive Quick Setup CLI, you can **configure Open Ticket in less than 5min!**
|
#### Core Features
|
||||||
- **🦇 Pterodactyl Support** - Open Ticket works perfect on Pterodactyl based panels. [(Download official eggs)](.eggs/README.md)
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-management.svg"></img> **Ticket Management** - Close, reopen, delete, claim or pin tickets with ease.
|
||||||
- **💩 No Credits** - Your bot won't contain any form of bloat or credits. It's all yours!
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-commands.svg"></img> **Powerful Commands** - Manage your support system with **30+ commands** for staff & users.
|
||||||
- **🔒 Private & Secure** - It has been battletested by thousands of servers and **respects security & privacy.**
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-questions.svg"></img> **Modal Questions** - Ask users **custom questions** before a ticket is created.
|
||||||
- **📈 Scalable** - Made to handle huge servers and has already been **tested in servers with 100k members.**
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-priorities.svg"></img> **Priorities** - Assign **priority levels** to tickets to highlight urgent requests.
|
||||||
- **📄 HTML Transcripts** - The **built-in HTML Transcripts Service** provides beautiful & easy-to-use transcripts.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-participants.svg"></img> **Participants** - Add or remove participants & transfer ownership from one user to another.
|
||||||
- **✅ Ticket Status** - Close, reopen, delete, claim, pin, rename or move tickets in your server.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-adjustments.svg"></img> **Adjustments** - Rename tickets, change ticket types or transfer ownership.
|
||||||
- **🇬🇧 Translation** - Every message has been translated in more than **36 languages** by our community.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-blacklist.svg"></img> **Blacklist & Limits** - Prevent users from creating tickets and set per-user or global ticket limits.
|
||||||
- **🎨 Customisation** - More than **200+ settings** are related to customisation & advanced features.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-customisable.svg"></img> **Highly Customisable** - Configure **350+ settings** covering appearance and behaviour.
|
||||||
- **🖥️ 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)!
|
#### Ticket Automation & Workflows
|
||||||
- **💬 Reviews** - Create & manage a support review system.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/automation-unlimited.svg"></img> **Unlimited Possibilities** - Create unlimited tickets, panels & question flows.
|
||||||
- **📢 Feedback** - Collect feedback & create forms for users to answer.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/automation-autoclose.svg"></img> **Autoclose Tickets** - Automatically **close tickets** after predefined conditions.
|
||||||
- **⏰ Reminders** - Create & manage customisable reminders.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/automation-autodelete.svg"></img> **Autodelete Tickets** - Automatically **delete closed tickets** to keep channels clean.
|
||||||
- **🏷️ Tags** - Create tags & answer questions automatically using keywords.
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/automation-categories.svg"></img> **Category Routing** - Move tickets between categories based on claim or close state.
|
||||||
- **📝 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)
|
#### Transcripts & Insights
|
||||||
> 1. Download the latest version of Open Ticket on [Github](https://github.com/open-discord-bots/open-ticket).
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/insights-transcripts.svg"></img> **HTML Transcripts** - Generate beautiful, easy-to-read **HTML transcripts** for every ticket.
|
||||||
> 2. Make sure Node.js & Npm are installed using `node -v` (minimum `v20`).
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/insights-stats.svg"></img> **Detailed Statistics** - Track **50+ statistics** for tickets, users and server activity.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/insights-logs.svg"></img> **Ticket Logs** - Track **all ticket events** such as creation, closures, and staff actions.
|
||||||
|
|
||||||
|
#### User Experience
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ux-translated.svg"></img> **Fully Translated** - Available in **38+ languages**, translated and maintained by the community.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ux-interactions.svg"></img> **Modern Interactions** - Full support for buttons, dropdowns, slash/text commands & modals.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ux-panels.svg"></img> **Panels** - Create messages with buttons or a dropdown for users to open tickets.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ux-sub-panels.svg"></img> **Sub-Panels** - One panel not enough? Use multiple panels to offer more choices.
|
||||||
|
|
||||||
|
#### Plugins & Ecosystem
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ecosystem-plugins.svg"></img> **Plugin System** - Use custom plugins to **add new features** or **modify existing behavior** of the bot.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ecosystem-community.svg"></img> **Community Plugins** - Use and share plugins built by the community.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ecosystem-api.svg"></img> **Advanced API** - Build advanced plugins with access to ticket events and internal systems.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ecosystem-integrations.svg"></img> **Integrations** - Connect Open Ticket with external services to automate workflows across platforms.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/ecosystem-bonus.svg"></img> **Bonus Features** - Somehow, we included Reaction Roles and URL Button support as well.
|
||||||
|
|
||||||
|
#### Deployment
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/deployment-quick.svg"></img> **Quick Setup** - Easy **5-minute configuration** using the Interactive Setup CLI.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/deployment-scale.svg"></img> **Scalable & Reliable** - Battle-tested in servers with **100k+ members**.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/deployment-secure.svg"></img> **Private & Secure** - Used by thousands of servers with respect for security & privacy.
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/deployment-pterodactyl.svg"></img> **Pterodactyl Support** - 100% compatible with Pterodactyl panels. [(Download official eggs)](.eggs/README.md)
|
||||||
|
- <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/deployment-docker.svg"></img> **Docker Support** - Deploy Open Ticket in minutes with Docker containers.
|
||||||
|
|
||||||
|
#### Extend functionality even more with our [pre-made community plugins](#-plugins)!
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-reviews.svg"></img> **Reviews** - Create and manage a support review system for tickets.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-tags.svg"></img> **Tags** - Define keywords that automatically trigger predefined responses.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-reminders.svg"></img> **Reminders** - Create and manage custom reminders for users or staff.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-ai.svg"></img> **AI Integrations** - Connect to AI providers such as ChatGPT, Claude, or Gemini.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-display.svg"></img> **Channel Display** - Create voice channels that display real-time ticket system statistics.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-forms.svg"></img> **Forms** - Build advanced forms for collecting structured information from users.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-embeds.svg"></img> **Custom Embeds** - Create and send custom embeds via commands.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/core-customisable.svg"></img> **Customization Tools** - Additional configuration options for advanced behavior and styling.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-dashboard.svg"></img> **Web Dashboard** - Configure and manage the bot through a remote web dashboard.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-feedback.svg"></img> **Feedback** - Collect user feedback after ticket deletion using forms.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-sqlite.svg"></img> **SQLite Database** - Use an SQLite backend for improved performance and lightweight storage.
|
||||||
|
> - <img align="center" src="https://apis.dj-dj.be/cdn/openticket/readme-icons/plugin-more.svg"></img> **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`.
|
> 3. Install any required dependencies using `npm install`.
|
||||||
> 4. Start the **Quick Setup CLI** using `npm run setup`.
|
> 4. Configure the bot in one of the following ways:
|
||||||
> 5. Click on `> ⏱️ Quick Setup` and follow the instructions.
|
> - 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`
|
> 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.
|
> - If any config errors occur, the bot will give you a report of how to solve them.
|
||||||
> - Follow the instructions and restart the bot.
|
> - Follow the instructions and restart the bot.
|
||||||
> 7. Enjoy using Open Ticket!
|
> 7. Enjoy using Open Ticket!
|
||||||
|
> 8. Install plugins from the [**Official Plugin Repository**](https://github.com/open-discord-bots/plugins)
|
||||||
>
|
>
|
||||||
> #### 🚦 Navigation
|
> #### 🚦 Next Steps
|
||||||
> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
|
> **[-> Navigate to (📚 Documentation)](https://otdocs.dj-dj.be)**
|
||||||
> **[-> Navigate to (📞 Support Server)](https://discord.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)**
|
||||||
>
|
>
|
||||||
> #### 🖥️ Recommended Hosting
|
> #### 🖥️ Recommended Hosting
|
||||||
> - **A VPS (Virtual Private Server)** - Extra customisation & more stability. Recommended for most servers.
|
> - **A VPS (Virtual Private Server)** - Extra customisation & more stability. Recommended for most servers.
|
||||||
> - **Any Pterodactyl-Based Panel** - Easy installation & configuration.
|
> - **Any Pterodactyl-Based Panel** - Easy installation & configuration.
|
||||||
|
|
||||||
### ❤️ Sponsors
|
|
||||||
Huge thanks to our sponsors for making this project possible. Your support means everything to us.
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td><img src="https://github.com/guillee3.png" alt="Profile Picture" width="100px"></td>
|
|
||||||
<td><img src="https://github.com/yeeetSK.png" alt="Profile Picture" width="100px"></td>
|
|
||||||
<td><img src="https://github.com/jacobhumston.png" alt="Profile Picture" width="100px"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><a href="https://github.com/guillee3"><b>guillee3</b></a></td>
|
|
||||||
<td align="center"><a href="https://github.com/yeeetSK"><b>yeeetSK</b></a></td>
|
|
||||||
<td align="center"><a href="https://github.com/jacobhumston"><b>jacobhumston</b></a></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
**Past Sponsors:**<br>
|
|
||||||
<a href="https://github.com/sponsors/DJj123dj">
|
|
||||||
<img src="https://github.com/SpyEye2.png" alt="SpyEye" width="40px">
|
|
||||||
<img src="https://github.com/mods-hd.png" alt="Mods HD" width="40px">
|
|
||||||
<img src="https://github.com/DOSEV5.png" alt="DOSEV5" width="40px">
|
|
||||||
<img src="https://github.com/BENZORICH.png" alt="BENZORICH" width="40px">
|
|
||||||
</a>
|
|
||||||
|
|
||||||
## 📸 Preview
|
## 📸 Preview
|
||||||
<img alt="An example of a panel." src="https://apis.dj-dj.be/cdn/openticket/preview-v4/panel-examples.png">
|
<img alt="An example of a panel." src="https://apis.dj-dj.be/cdn/openticket/preview-v4/panel-examples.png">
|
||||||
<img alt="An example of a ticket message." src="https://apis.dj-dj.be/cdn/openticket/preview-v4/ticket-example.png">
|
<img alt="An example of a ticket message." src="https://apis.dj-dj.be/cdn/openticket/preview-v4/ticket-example.png">
|
||||||
<img alt="Examples of built-in commands." src="https://apis.dj-dj.be/cdn/openticket/preview-v4/command-examples.png">
|
<img alt="Examples of built-in commands." src="https://apis.dj-dj.be/cdn/openticket/preview-v4/command-examples.png">
|
||||||
|
|
||||||
## 🛠️ Contributors
|
## 💬 Translations
|
||||||
### 🖥️ Team & Contributors
|
With the amazing support of our translators, we've been able to translate Open Ticket in more than **38 languages**!
|
||||||
A list of amazing people who have contributed or provided supported for **Open Ticket** and **Open Discord**.
|
#### Categories: 🟢 Available - 🤖 Partially Made Using AI - 🟠 Incomplete - 🔴 Unavailable/Outdated
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<td align="center"><img src="https://github.com/DJj123dj.png" alt="Profile Picture" width="80px"></td>
|
|
||||||
<td align="center"><img src="https://github.com/guillee3.png" alt="Profile Picture" width="80px"></td>
|
|
||||||
<td align="center"><img src="https://github.com/smetsliam.png" alt="Profile Picture" width="80px"></td>
|
|
||||||
<td align="center"><img src="https://github.com/FrankVissers.png" alt="Profile Picture" width="80px"></td>
|
|
||||||
<td align="center"><img src="https://github.com/Sank34.png" alt="Profile Picture" width="80px"></td>
|
|
||||||
<td align="center"><img src="https://github.com/SKaranjaN.png" alt="Profile Picture" width="80px"></td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://github.com/DJj123dj">💻🧩💬 DJj123dj</a></th>
|
|
||||||
<th><a href="https://github.com/guillee3">🧩💬 Guillee3</a></th>
|
|
||||||
<th><a href="https://github.com/smetsliam">💬 smetsliam</a></th>
|
|
||||||
<th><a href="https://github.com/FrankVissers">💬 Frank Vissers</a></th>
|
|
||||||
<th><a href="https://github.com/Sank34">💬 Sanke</a></th>
|
|
||||||
<th><a href="https://github.com/SKaranjaN">🧩 SKaranjaN</a></th>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
### 💬 Translators
|
|🔍 |Languages (38) |Config Value |Maintainers (Github/Discord) |
|
||||||
With the amazing support of our translators, we've been able to translate Open Ticket in more than **36 languages**!
|
|----|----------------------|------------------------|--------------------------------|
|
||||||
#### Categories:
|
|🟢 |🇬🇧 English |`"english"` |djj123dj |
|
||||||
- **🟢 Available**
|
|🟢 |🇳🇱 Dutch |`"dutch"` |djj123dj |
|
||||||
- **🤖 Partially Made Using AI**
|
|🟢 |🇩🇪 German |`"german"` |benzorich |
|
||||||
- **🟠 Incomplete**
|
|🟢 |🇫🇷 French |`"french"` |guillee.3 |
|
||||||
- **🔴 Unavailable/Outdated**
|
|🟢 |🇪🇸 Spanish |`"spanish"` |Reddishye & josuens |
|
||||||
|
|🟢 |🇵🇹 Portuguese |`"portuguese"` |quiradon |
|
||||||
|🔍 |Languages (36) |Maintainer (Github/Discord) |
|
|🟢 |🇮🇹 Italian |`"italian"` |fraden1mvp. & imperatorix_17 |
|
||||||
|----|---------------------|--------------------------------|
|
|🟢 |🇸🇪 Swedish |`"swedish"` |NoOneNook |
|
||||||
|🟢 |🇬🇧 English |djj123dj |
|
|🟢 |🇳🇴 Norwegian |`"norwegian"` |NoOneNook |
|
||||||
|🟢 |🇳🇱 Dutch |djj123dj |
|
|🟢 |🇹🇭 Thai |`"thai"` |modshd |
|
||||||
|🟢 |🇩🇪 German |benzorich |
|
|🟢 |🇮🇳 Hindi |`"hindi"` |challenger_nova |
|
||||||
|🟢 |🇫🇷 French |guillee.3 |
|
|🟢 |🇭🇺 Hungarian |`"hungarian"` |kornel0706 |
|
||||||
|🟢 |🇪🇸 Spanish |redactado & josuens |
|
|🟢 |🇮🇩 Indonesian |`"indonesian"` |erxg |
|
||||||
|🟢 |🇵🇹 Portuguese |quiradon |
|
|🟢 |🇱🇹 Lithuanian |`"lithuanian"` |tsgindrius |
|
||||||
|🟢 |🇮🇹 Italian |fraden1mvp. & imperatorix_17 |
|
|🟢 |🇺🇦 Ukrainian |`"ukrainian"` |anderskiy |
|
||||||
|🟢 |🇸🇪 Swedish |NoOneNook |
|
|🟢 |🇨🇿 Czech |`"czech"` |spyeye_ |
|
||||||
|🟢 |🇳🇴 Norwegian |NoOneNook |
|
|🟢 |🇷🇴 Romanian |`"romanian"` |sankedev |
|
||||||
|🟢 |🇹🇭 Thai |modshd |
|
|🟢 |🇩🇰 Danish |`"danish"` |the_gamer |
|
||||||
|🟢 |🇮🇳 Hindi |challenger_nova |
|
|🟢 |🇹🇷 Turkish |`"turkish"` |palestinian |
|
||||||
|🟢 |🇭🇺 Hungarian |kornel0706 |
|
|🟢 |🇦🇪 Arabic |`"arabic"` |palestinian |
|
||||||
|🟢 |🇮🇩 Indonesian |erxg |
|
|🟢 |🇵🇱 Polish |`"polish"` |danoglez |
|
||||||
|🟢 |🇱🇹 Lithuanian |tsgindrius |
|
|🟢 |🇮🇷 Persian |`"persian"` |dysashop & zhavis |
|
||||||
|🟢 |🇺🇦 Ukrainian |anderskiy |
|
|🟢 |🇧🇩 Bengali |`"bengali"` |HanumeshGupta |
|
||||||
|🟢 |🇨🇿 Czech |spyeye_ |
|
|🟢 |❓ Catalan |`"catalan"` |guillee3 |
|
||||||
|🟢 |🇷🇴 Romanian |sankedev |
|
|🟢 |🇨🇳 Traditional Chinese|`"traditional-chinese"` |me.october |
|
||||||
|🟢 |🇩🇰 Danish |the_gamer |
|
|🟢 |🇰🇭 Khmer (Cambodia) |`"khmer"` |yuuslokrobjakkroval |
|
||||||
|🟢 |🇹🇷 Turkish |palestinian |
|
|🤖 |🇪🇪 Estonian |`"estonian"` |iamnotmega |
|
||||||
|🟢 |🇦🇪 Arabic |palestinian |
|
|🤖 |🇫🇮 Finnish |`"finnish"` |iamnotmega |
|
||||||
|🟢 |🇵🇱 Polish |danoglez |
|
|🤖 |🇯🇵 Japanese |`"japanese"` |HanumeshGupta |
|
||||||
|🟢 |🇮🇷 Persian |dysashop & zhavis |
|
|🤖 |🇬🇷 Greek |`"greek"` |HanumeshGupta |
|
||||||
|🟢 |🇧🇩 Bengali |HanumeshGupta |
|
|🤖 |🇸🇮 Slovenian |`"slovenian"` |HanumeshGupta |
|
||||||
|🟢 |❓ Catalan |guillee3 |
|
|🤖 |🇰🇷 Korean |`"korean"` |HanumeshGupta |
|
||||||
|🤖 |🇪🇪 Estonian |iamnotmega |
|
|🤖 |🇮🇳 Tamil |`"tamil"` |HanumeshGupta |
|
||||||
|🤖 |🇫🇮 Finnish |iamnotmega |
|
|🤖 |❓ Kurdish |`"kurdish"` |HanumeshGupta |
|
||||||
|🤖 |🇯🇵 Japanese |HanumeshGupta |
|
|🤖 |🇷🇺 Russian |`"russian"` |NoOneNook |
|
||||||
|🤖 |🇬🇷 Greek |HanumeshGupta |
|
|🤖 |🇱🇻 Latvian |`"latvian"` |NoOneNook |
|
||||||
|🤖 |🇸🇮 Slovenian |HanumeshGupta |
|
|🤖 |🇻🇳 Vietnamese |`"vietnamese"` |ngocdiep2006 |
|
||||||
|🤖 |🇰🇷 Korean |HanumeshGupta |
|
|🤖 |🇨🇳 Simplified Chinese |`"simplified-chinese"` |HanumeshGupta |
|
||||||
|🤖 |🇮🇳 Tamil |HanumeshGupta |
|
|
||||||
|🤖 |🇨🇳 Simplified Chinese |HanumeshGupta |
|
|
||||||
|🤖 |❓ Kurdish |HanumeshGupta |
|
|
||||||
|🤖 |🇷🇺 Russian |NoOneNook |
|
|
||||||
|🤖 |🇱🇻 Latvian |NoOneNook |
|
|
||||||
|🤖 |🇻🇳 Vietnamese |ngocdiep2006 |
|
|
||||||
|🔴 |🇨🇳 Traditional Chinese|[⭐ Contribute!](.github/CONTRIBUTING.md)|
|
|
||||||
<!--[⭐ Contribute!](.github/CONTRIBUTING.md) -->
|
<!--[⭐ Contribute!](.github/CONTRIBUTING.md) -->
|
||||||
|
|
||||||
|
## 😎 Hall Of Fame
|
||||||
|
<img alt="The full list of contributors for Open Ticket and Open Discord." src=".github/CONTRIBUTORS.svg">
|
||||||
|
|
||||||
## ⭐️ Star History
|
## ⭐️ 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!
|
This will help us grow and reach even more people!
|
||||||
|
|
||||||
<a href="https://star-history.com/#open-discord-bots/open-ticket&Date">
|
<a href="https://star-history.com/#open-discord-bots/open-ticket&Date">
|
||||||
@@ -194,66 +177,6 @@ This will help us grow and reach even more people!
|
|||||||
</picture>
|
</picture>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
## 🧩 Plugins
|
|
||||||
**Download all plugins from our [Official Plugin Repository](https://github.com/open-discord-bots/plugins)!**<br>
|
|
||||||
> #### ⭐ 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. |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="170px">
|
<img src="https://apis.dj-dj.be/cdn/openticket/logo.png" alt="Open Ticket Logo" width="170px">
|
||||||
|
|
||||||
|
|||||||
@@ -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}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -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 <id>
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@@ -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."
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[]
|
||||||
@@ -4,7 +4,6 @@ const flags = [
|
|||||||
//PTERODACTYL PANEL
|
//PTERODACTYL PANEL
|
||||||
//add startup flags here (e.g. "--no-compile") when running via the panel
|
//add startup flags here (e.g. "--no-compile") when running via the panel
|
||||||
]
|
]
|
||||||
process.argv.push(...flags)
|
|
||||||
/////////////// STARTUP 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
|
Discord: https://discord.dj-dj.be
|
||||||
Docs: https://otdocs.dj-dj.be
|
Docs: https://otdocs.dj-dj.be
|
||||||
Support Us: https://github.com/sponsors/DJj123dj/
|
Support Us: https://github.com/sponsors/DJj123dj/
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
////////// COMPILATION + STARTUP //////////
|
////////// 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?
|
import { frameworkStartup } from "@open-discord-bots/framework"
|
||||||
* This is a function which compares `./src/` with a hash stored in `./dist/hash.txt`.
|
frameworkStartup(flags,"openticket",async () => {
|
||||||
* The hash is based on the modified date & file metadata of all files in `./src/`.
|
await import("./dist/src/index.js")
|
||||||
*
|
|
||||||
* 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")
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["palestinian"],
|
"translators":["palestinian"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Arabic",
|
"language":"Arabic",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta"],
|
"translators":["HanumeshGupta"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Bengali",
|
"language":"Bengali",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["guillee3"],
|
"translators":["guillee3"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Catalan",
|
"language":"Catalan",
|
||||||
|
|||||||
+318
-318
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["DJj123dj"],
|
"translators":["DJj123dj"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Custom",
|
"language":"Custom",
|
||||||
@@ -13,94 +13,94 @@
|
|||||||
"typeWarning":"[WARNING]",
|
"typeWarning":"[WARNING]",
|
||||||
"typeInfo":"[INFO]",
|
"typeInfo":"[INFO]",
|
||||||
"headerConfigChecker":"CONFIG CHECKER",
|
"headerConfigChecker":"CONFIG CHECKER",
|
||||||
"headerDescription":"check for errors in your config files!",
|
"headerDescription":"Validating config files...",
|
||||||
"footerError":"the bot won't start until all {0}'s are fixed!",
|
"footerError":"The bot will not start until all {0}'s are resolved.",
|
||||||
"footerWarning":"it's recommended to fix all {0}'s before starting!",
|
"footerWarning":"The bot may behave unexpectedly until all {0}'s are resolved.",
|
||||||
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
|
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
|
||||||
"compactInformation":"use {0} for more information!",
|
"compactInformation":"Use {0} for a detailed config report.",
|
||||||
"dataPath":"path",
|
"dataPath":"path",
|
||||||
"dataDocs":"docs",
|
"dataDocs":"docs",
|
||||||
"dataMessages":"message"
|
"dataMessages":"message"
|
||||||
},
|
},
|
||||||
"messages":{
|
"messages":{
|
||||||
"stringTooShort":"This string can't be shorter than {0} characters!",
|
"stringTooShort":"Text must be at least {0} characters long",
|
||||||
"stringTooLong":"This string can't be longer than {0} characters!",
|
"stringTooLong":"Text must be no longer than {0} characters",
|
||||||
"stringLengthInvalid":"This string needs to be {0} characters long!",
|
"stringLengthInvalid":"Text must be exactly {0} characters long",
|
||||||
"stringStartsWith":"This string needs to start with {0}!",
|
"stringStartsWith":"Text must start with {0}",
|
||||||
"stringEndsWith":"This string needs to end with {0}!",
|
"stringEndsWith":"Text must end with {0}",
|
||||||
"stringContains":"This string needs to contain {0}!",
|
"stringContains":"Text must contain {0}",
|
||||||
"stringChoices":"This string can only be one of the following values: {0}!",
|
"stringChoices":"Text must be one of the following: {0}",
|
||||||
"stringRegex":"This string is invalid!",
|
"stringRegex":"Text does not match the required format",
|
||||||
"stringInvertedContains":"This string is not allowed to contain {0}!",
|
"stringInvertedContains":"Text must not contain {0}",
|
||||||
"stringLowercase":"This string must be written in lowercase only!",
|
"stringLowercase":"Text must be entirely lowercase",
|
||||||
"stringUppercase":"This string must be written in uppercase only!",
|
"stringUppercase":"Text must be entirely uppercase",
|
||||||
"stringSpecialCharacters":"This string is not allowed to contain any special characters! (a-z, 0-9 & space only)",
|
"stringSpecialCharacters":"Text must only contain letters (a–z), numbers (0–9), and spaces",
|
||||||
"stringNoSpaces":"This string is not allowed to contain spaces!",
|
"stringNoSpaces":"Text must not contain spaces",
|
||||||
"stringCapitalWord":"It's recommended that each word in this string starts with a capital letter!",
|
"stringCapitalWord":"Each word in this value should start with a capital letter",
|
||||||
"stringCapitalSentence":"It looks like some sentences in this string don't start with a capital letter!",
|
"stringCapitalSentence":"One or more sentences in this value do not start with a capital letter",
|
||||||
"stringPunctuation":"It looks like the sentence in this string doesn't end with a punctuation mark!",
|
"stringPunctuation":"The sentence in this value does not end with a punctuation mark",
|
||||||
|
|
||||||
"numberTooShort":"This number can't be shorter than {0} characters!",
|
"numberTooShort":"Number must be at least {0} digits long",
|
||||||
"numberTooLong":"This number can't be longer than {0} characters!",
|
"numberTooLong":"Number must be no longer than {0} digits",
|
||||||
"numberLengthInvalid":"This number needs to be {0} characters long!",
|
"numberLengthInvalid":"Number must be exactly {0} digits long",
|
||||||
"numberTooSmall":"This number needs to be at least {0}!",
|
"numberTooSmall":"Number must be at least {0}",
|
||||||
"numberTooLarge":"This number needs to be at most {0}!",
|
"numberTooLarge":"Number must be at most {0}",
|
||||||
"numberNotEqual":"This number needs to be {0}!",
|
"numberNotEqual":"Number must be exactly {0}",
|
||||||
"numberStep":"This number needs to be a multiple of {0}!",
|
"numberStep":"Number must be a multiple of {0}",
|
||||||
"numberStepOffset":"This number needs to be a multiple of {0} starting with {1}!",
|
"numberStepOffset":"Number must be a multiple of {0}, starting from {1}",
|
||||||
"numberStartsWith":"This number needs to start with {0}!",
|
"numberStartsWith":"Number must start with {0}",
|
||||||
"numberEndsWith":"This number needs to end with {0}!",
|
"numberEndsWith":"Number must end with {0}",
|
||||||
"numberContains":"This number needs to contain {0}!",
|
"numberContains":"Number must contain {0}",
|
||||||
"numberChoices":"This number can only be one of the following values: {0}!",
|
"numberChoices":"Number must be one of the following: {0}",
|
||||||
"numberFloat":"This number can't be a decimal!",
|
"numberFloat":"Number must be a whole number",
|
||||||
"numberNegative":"This number can't be negative!",
|
"numberNegative":"Number must be a positive number",
|
||||||
"numberPositive":"This number can't be positive!",
|
"numberPositive":"Number must be a negative number",
|
||||||
"numberZero":"This number can't be zero!",
|
"numberZero":"Number must not be zero",
|
||||||
"numberNan":"This number can't be NaN (Not A Number)!",
|
"numberNan":"Number must be a valid number",
|
||||||
"numberInvertedContains":"This number is not allowed to contain {0}!",
|
"numberInvertedContains":"Number must not contain {0}",
|
||||||
|
|
||||||
"booleanTrue":"This boolean can't be true!",
|
"booleanTrue":"Boolean must be false",
|
||||||
"booleanFalse":"This boolean can't be false!",
|
"booleanFalse":"Boolean must be true",
|
||||||
|
|
||||||
"arrayEmptyDisabled":"This array isn't allowed to be empty!",
|
"arrayEmptyDisabled":"List must not be empty",
|
||||||
"arrayEmptyRequired":"This array is required to be empty!",
|
"arrayEmptyRequired":"List must be empty",
|
||||||
"arrayTooShort":"This array needs to have a length of at least {0}!",
|
"arrayTooShort":"List must have at least {0} items",
|
||||||
"arrayTooLong":"This array needs to have a length of at most {0}!",
|
"arrayTooLong":"List must have at most {0} items",
|
||||||
"arrayLengthInvalid":"This array needs to have a length of {0}!",
|
"arrayLengthInvalid":"List must have exactly {0} items",
|
||||||
"arrayInvalidTypes":"This array can only contain the following types: {0}!",
|
"arrayInvalidTypes":"List may only contain the following types: {0}",
|
||||||
"arrayDouble":"This array doesn't allow the same value twice!",
|
"arrayDouble":"List must not contain duplicate values",
|
||||||
|
|
||||||
"discordInvalidId":"This is an invalid discord {0} id!",
|
"discordInvalidId":"Invalid Discord {0} ID",
|
||||||
"discordInvalidIdOptions":"This is an invalid discord {0} id! You can also use one of these: {1}!",
|
"discordInvalidIdOptions":"Invalid Discord {0} ID. Alternatively, use one of the following: {1}",
|
||||||
"discordInvalidToken":"This is an invalid discord token (syntactically)!",
|
"discordInvalidToken":"Invalid Discord token",
|
||||||
"colorInvalid":"This is an invalid hex color!",
|
"colorInvalid":"Invalid hex color",
|
||||||
"emojiTooShort":"This string needs to have at least {0} emoji's!",
|
"emojiTooShort":"Value must contain at least {0} emoji",
|
||||||
"emojiTooLong":"This string needs to have at most {0} emoji's!",
|
"emojiTooLong":"Value must contain at most {0} emoji",
|
||||||
"emojiCustom":"This emoji can't be a custom discord emoji!",
|
"emojiCustom":"Custom Discord emojis are not allowed here",
|
||||||
"emojiInvalid":"This is an invalid emoji!",
|
"emojiInvalid":"Invalid emoji",
|
||||||
"urlInvalid":"This url is invalid!",
|
"urlInvalid":"Invalid URL",
|
||||||
"urlInvalidHttp":"This url can only use the https:// protocol!",
|
"urlInvalidHttp":"URL must use the https:// protocol",
|
||||||
"urlInvalidProtocol":"This url can only use the http:// & https:// protocols!",
|
"urlInvalidProtocol":"URL must use the http:// or https:// protocol",
|
||||||
"urlInvalidHostname":"This url has a disallowed hostname!",
|
"urlInvalidHostname":"URL hostname is not allowed",
|
||||||
"urlInvalidExtension":"This url has an invalid extension! Choose between: {0}!",
|
"urlInvalidExtension":"Invalid URL extension. Allowed extensions: {0}",
|
||||||
"urlInvalidPath":"This url has an invalid path!",
|
"urlInvalidPath":"Invalid URL path",
|
||||||
"idNotUnique":"This id isn't unique, use another id instead!",
|
"idNotUnique":"This ID is already in use. Please choose a unique ID",
|
||||||
"idNonExistent":"The id {0} doesn't exist!",
|
"idNonExistent":"ID {0} does not exist",
|
||||||
|
|
||||||
"invalidType":"This property needs to be the type: {0}!",
|
"invalidType":"Property must be of type: {0}",
|
||||||
"propertyMissing":"The property {0} is missing from this object!",
|
"propertyMissing":"Required property {0} is missing from the object",
|
||||||
"propertyOptional":"The property {0} is optional in this object!",
|
"propertyOptional":"Property {0} is optional in the object",
|
||||||
"objectDisabled":"This object is disabled, enable it using {0}!",
|
"objectDisabled":"This object is disabled. Enable it using {0}",
|
||||||
"nullInvalid":"This property can't be null!",
|
"nullInvalid":"Property must not be null",
|
||||||
"switchInvalidType":"This needs to be one of the following types: {0}!",
|
"switchInvalidType":"Value must be one of the following types: {0}",
|
||||||
"objectSwitchInvalid":"This object needs to be one of the following types: {0}!",
|
"objectSwitchInvalid":"Object must be one of the following types: {0}",
|
||||||
|
|
||||||
"invalidLanguage":"This is an invalid language!",
|
"invalidLanguage":"Invalid language",
|
||||||
"invalidButton":"This button needs to have at least an {0} or {1}!",
|
"invalidButton":"Button must have at least an {0} or {1}",
|
||||||
"unusedOption":"The option {0} isn't used anywhere!",
|
"unusedOption":"Option {0} is not used anywhere",
|
||||||
"unusedQuestion":"The question {0} isn't used anywhere!",
|
"unusedQuestion":"Question {0} is not used anywhere",
|
||||||
"dropdownOption":"A panel with dropdown enabled can only contain options of the 'ticket' type!",
|
"dropdownOption":"Panels with dropdown enabled may 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!"
|
"customInvalidVersion":"Config version mismatch. Make sure to update your config to the latest version"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions":{
|
"actions":{
|
||||||
@@ -159,118 +159,118 @@
|
|||||||
"transfer":"Ticket Transferred"
|
"transfer":"Ticket Transferred"
|
||||||
},
|
},
|
||||||
"descriptions":{
|
"descriptions":{
|
||||||
"create":"Your ticket has been created. Click the button below to access it!",
|
"create":"Your ticket is ready. Click the button below to view and continue.",
|
||||||
"close":"The ticket has been closed successfully!",
|
"close":"The ticket has been closed.",
|
||||||
"delete":"The ticket has been deleted successfully!",
|
"delete":"The ticket has been deleted.",
|
||||||
"reopen":"The ticket has been reopened successfully!",
|
"reopen":"The ticket has been reopened.",
|
||||||
"claim":"The ticket has been claimed successfully!",
|
"claim":"The ticket has been claimed.",
|
||||||
"unclaim":"The ticket has been unclaimed successfully!",
|
"unclaim":"The ticket has been unclaimed.",
|
||||||
"pin":"The ticket has been pinned successfully!",
|
"pin":"The ticket has been pinned.",
|
||||||
"unpin":"The ticket has been unpinned successfully!",
|
"unpin":"The ticket has been unpinned.",
|
||||||
"rename":"The ticket has been renamed to {0} successfully!",
|
"rename":"The ticket has been renamed to {0}.",
|
||||||
"move":"The ticket has been moved to {0} successfully!",
|
"move":"The ticket has been moved to {0}.",
|
||||||
"add":"{0} has been added to the ticket successfully!",
|
"add":"{0} has been added to the ticket.",
|
||||||
"remove":"{0} has been removed from the ticket successfully!",
|
"remove":"{0} has been removed from the ticket.",
|
||||||
|
|
||||||
"helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter",
|
"helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter",
|
||||||
"statsReset":"The bot stats have been reset successfully!",
|
"statsReset":"The bot statistics have been reset.",
|
||||||
"statsError":"Unable to view ticket stats!\n{0} is not a ticket!",
|
"statsError":"Unable to retrieve ticket statistics.\n{0} is not a valid ticket.",
|
||||||
"blacklistAdd":"{0} has been blacklisted successfully!",
|
"blacklistAdd":"{0} has been blacklisted.",
|
||||||
"blacklistRemove":"{0} has been released successfully!",
|
"blacklistRemove":"{0} has been released.",
|
||||||
"blacklistGetSuccess":"{0} is currently blacklisted!",
|
"blacklistGetSuccess":"{0} is blacklisted!",
|
||||||
"blacklistGetEmpty":"{0} is currently not blacklisted!",
|
"blacklistGetEmpty":"{0} is not blacklisted!",
|
||||||
"blacklistViewEmpty":"No-one has been blacklisted yet!",
|
"blacklistViewEmpty":"No users have been blacklisted yet.",
|
||||||
"blacklistViewTip":"Use \"/blacklist add\" to blacklist a user!",
|
"blacklistViewTip":"Use \"/blacklist add\" to add a user to the blacklist.",
|
||||||
"clearVerify":"Are you sure you want to delete multiple tickets?\nThis action can't be undone!",
|
"clearVerify":"Are you sure you want to delete multiple tickets?\nThis action cannot be undone.",
|
||||||
"clearReady":"{0} tickets have been deleted successfully!",
|
"clearReady":"{0} ticket(s) have been deleted.",
|
||||||
"rolesEmpty":"No roles have been updated!",
|
"rolesEmpty":"No roles were modified.",
|
||||||
|
|
||||||
"autocloseLeave":"This ticket has been autoclosed because the creator left the server!",
|
"autocloseLeave":"This ticket was automatically closed because its creator left the server.",
|
||||||
"autocloseTimeout":"This ticket has been autoclosed because it has been inactive for more than `{0}h`!",
|
"autocloseTimeout":"This ticket was automatically closed due to inactivity exceeding `{0}h`.",
|
||||||
"autodeleteLeave":"This ticket has been autodeleted because the creator left the server!",
|
"autodeleteLeave":"This ticket was automatically deleted because its creator left the server.",
|
||||||
"autodeleteTimeout":"This ticket has been autodeleted because it has been inactive for more than `{0} days`!",
|
"autodeleteTimeout":"This ticket was automatically deleted due to inactivity exceeding `{0} days`.",
|
||||||
"autocloseEnabled":"Autoclose has been enabled in this ticket!\nIt will be closed when it is inactive for more than `{0}h`!",
|
"autocloseEnabled":"Autoclose has been enabled for this ticket.\nIt will close after `{0}h` of inactivity.",
|
||||||
"autocloseDisabled":"Autoclose has been disabled in this ticket!\nIt won't be closed automatically anymore!",
|
"autocloseDisabled":"Autoclose has been disabled for this ticket.\nThis ticket will no longer close automatically.",
|
||||||
"autodeleteEnabled":"Autodelete has been enabled in this ticket!\nIt will be deleted when it is inactive for more than `{0} days`!",
|
"autodeleteEnabled":"Autodelete has been enabled for this ticket.\nIt will be deleted after `{0} days` of inactivity.",
|
||||||
"autodeleteDisabled":"Autodelete has been disabled in this ticket!\nIt won't be deleted automatically anymore!",
|
"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!",
|
"ticketMessageLimit":"You can only have {0} active ticket(s) at a time.",
|
||||||
"ticketMessageAutoclose":"This ticket will be autoclosed when inactive for {0}h!",
|
"ticketMessageAutoclose":"This ticket will automatically close after `{0}h` of inactivity.",
|
||||||
"ticketMessageAutodelete":"This ticket will be autodeleted when inactive for {0} days!",
|
"ticketMessageAutodelete":"This ticket will automatically be deleted after `{0} days` of inactivity.",
|
||||||
"panelReady":"The panel is available in the followup message!\nThis message can now be deleted!",
|
"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!",
|
"topicSet":"The channel topic has been changed by {0}.",
|
||||||
"prioritySet":"The ticket priority has been changed to {0} by {1} successfully!",
|
"prioritySet":"The ticket priority has been changed to {0} by {1}.",
|
||||||
"priorityGet":"The current priority of this ticket is {0}.",
|
"priorityGet":"The priority of this ticket is {0}.",
|
||||||
"transfer":"The ticket ownership has been transferred from {0} to {1} by {2} successfully!"
|
"transfer":"The ticket ownership has been transferred from {0} to {1} by {2}."
|
||||||
},
|
},
|
||||||
"modal":{
|
"modal":{
|
||||||
"closePlaceholder":"Why did you close this ticket?",
|
"closePlaceholder":"Why would you like to close this ticket?",
|
||||||
"deletePlaceholder":"Why did you delete this ticket?",
|
"deletePlaceholder":"Why would you like to delete this ticket?",
|
||||||
"reopenPlaceholder":"Why did you reopen this ticket?",
|
"reopenPlaceholder":"Why would you like to reopen this ticket?",
|
||||||
"claimPlaceholder":"Why did you claim this ticket?",
|
"claimPlaceholder":"Why would you like to claim this ticket?",
|
||||||
"unclaimPlaceholder":"Why did you unclaim this ticket?",
|
"unclaimPlaceholder":"Why would you like to unclaim this ticket?",
|
||||||
"pinPlaceholder":"Why did you pin this ticket?",
|
"pinPlaceholder":"Why would you like to pin this ticket?",
|
||||||
"unpinPlaceholder":"Why did you unpin this ticket?"
|
"unpinPlaceholder":"Why would you like to unpin this ticket?"
|
||||||
},
|
},
|
||||||
"logs":{
|
"logs":{
|
||||||
"createLog":"A new ticket got created by {0}!",
|
"createLog":"A new ticket got created by {0}.",
|
||||||
"closeLog":"This ticket has been closed by {0}!",
|
"closeLog":"This ticket has been closed by {0}.",
|
||||||
"closeDm":"Your ticket has been closed in our server!",
|
"closeDm":"Your ticket has been closed.",
|
||||||
"deleteLog":"This ticket has been deleted by {0}!",
|
"deleteLog":"This ticket has been deleted by {0}.",
|
||||||
"deleteDm":"Your ticket has been deleted in our server!",
|
"deleteDm":"Your ticket has been deleted.",
|
||||||
"reopenLog":"This ticket has been reopened by {0}!",
|
"reopenLog":"This ticket has been reopened by {0}.",
|
||||||
"reopenDm":"Your ticket has been reopened in our server!",
|
"reopenDm":"Your ticket has been reopened.",
|
||||||
"claimLog":"This ticket has been claimed by {0}!",
|
"claimLog":"This ticket has been claimed by {0}.",
|
||||||
"claimDm":"Your ticket has been claimed in our server!",
|
"claimDm":"Your ticket has been claimed.",
|
||||||
"unclaimLog":"This ticket has been unclaimed by {0}!",
|
"unclaimLog":"This ticket has been unclaimed by {0}.",
|
||||||
"unclaimDm":"Your ticket has been unclaimed in our server!",
|
"unclaimDm":"Your ticket has been unclaimed.",
|
||||||
"pinLog":"This ticket has been pinned by {0}!",
|
"pinLog":"This ticket has been pinned by {0}.",
|
||||||
"pinDm":"Your ticket has been pinned in our server!",
|
"pinDm":"Your ticket has been pinned.",
|
||||||
"unpinLog":"This ticket has been unpinned by {0}!",
|
"unpinLog":"This ticket has been unpinned by {0}.",
|
||||||
"unpinDm":"Your ticket has been unpinned in our server!",
|
"unpinDm":"Your ticket has been unpinned.",
|
||||||
"renameLog":"This ticket has been renamed to {0} by {1}!",
|
"renameLog":"This ticket has been renamed to {0} by {1}.",
|
||||||
"renameDm":"Your ticket has been renamed to {0} in our server!",
|
"renameDm":"Your ticket has been renamed to {0}.",
|
||||||
"moveLog":"This ticket has been moved to {0} by {1}!",
|
"moveLog":"This ticket has been moved to {0} by {1}.",
|
||||||
"moveDm":"Your ticket has been moved to {0} in our server!",
|
"moveDm":"Your ticket has been moved to {0}.",
|
||||||
"addLog":"{0} has been added to this ticket by {1}!",
|
"addLog":"{0} has been added to this ticket by {1}.",
|
||||||
"addDm":"{0} has been added to your ticket in our server!",
|
"addDm":"{0} has been added to your ticket.",
|
||||||
"removeLog":"{0} has been removed from this ticket by {1}!",
|
"removeLog":"{0} has been removed from this ticket by {1}.",
|
||||||
"removeDm":"{0} has been removed from your ticket in our server!",
|
"removeDm":"{0} has been removed from your ticket.",
|
||||||
|
|
||||||
"blacklistAddLog":"{0} was blacklisted by {1}!",
|
"blacklistAddLog":"{0} has been blacklisted by {1}.",
|
||||||
"blacklistRemoveLog":"{0} was removed from the blacklist by {1}!",
|
"blacklistRemoveLog":"{0} has been removed from the blacklist by {1}.",
|
||||||
"blacklistAddDm":"You have been blacklisted in our server!\nFrom now on, you are unable to create a ticket!",
|
"blacklistAddDm":"You have been blacklisted from this server.\nYou are no longer able to create tickets.",
|
||||||
"blacklistRemoveDm":"You have been removed from the blacklist in our server!\nNow you can create tickets again!",
|
"blacklistRemoveDm":"You have been removed from the blacklist.\nYou can now create tickets again.",
|
||||||
"clearLog":"{0} tickets have been deleted by {1}!",
|
"clearLog":"{0} ticket(s) have been deleted by {1}.",
|
||||||
|
|
||||||
"transferLog":"The ownership of this ticket has been transferred from {0} to {1} by {2}!",
|
"transferLog":"Ticket ownership 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!",
|
"transferDm":"Ownership of your ticket has been transferred from {0} to {1}.",
|
||||||
"prioritySetLog":"The priority of this ticket has been changed to {0} by {1}!",
|
"prioritySetLog":"The priority of this ticket has been set to {0} by {1}.",
|
||||||
"prioritySetDm":"The priority of your ticket has been changed to {0} in our server!",
|
"prioritySetDm":"The priority of your ticket has been set to {0}.",
|
||||||
"roleUpdateLog":"{0} has updated their roles!",
|
"roleUpdateLog":"{0} has modified their roles.",
|
||||||
"roleUpdateDm":"Your roles in our server have been updated!"
|
"roleUpdateDm":"Your roles have been modified."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transcripts":{
|
"transcripts":{
|
||||||
"success":{
|
"success":{
|
||||||
"visit":"Visit Transcript",
|
"visit":"Visit Transcript",
|
||||||
"ready":"Transcript Created",
|
"ready":"Transcript Created",
|
||||||
"textFileDescription":"This is the text transcript of a deleted ticket!",
|
"textFileDescription":"This is a text transcript of a deleted ticket.",
|
||||||
"htmlProgress":"Please wait while this html transcript is getting processed...",
|
"htmlProgress":"Please wait while the HTML transcript is being generated...",
|
||||||
|
|
||||||
"createdChannel":"A new {0} transcript has been created in the server!",
|
"createdChannel":"A new {0} transcript has been created in the server.",
|
||||||
"createdCreator":"A new {0} transcript has been created for one of your tickets!",
|
"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!",
|
"createdParticipant":"A new {0} transcript has been created for a ticket you participated in.",
|
||||||
"createdActiveAdmin":"A new {0} transcript has been created in one of the tickets you participated as admin!",
|
"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 in one of the tickets you were admin in!",
|
"createdEveryAdmin":"A new {0} transcript has been created for a ticket you managed as an admin.",
|
||||||
"createdOther":"A new {0} transcript has been created!"
|
"createdOther":"A new {0} transcript has been created."
|
||||||
},
|
},
|
||||||
"errors":{
|
"errors":{
|
||||||
"retry":"Retry",
|
"retry":"Retry",
|
||||||
"continue":"Delete Without Transcript",
|
"continue":"Delete Without Transcript",
|
||||||
"backup":"Create Backup 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"
|
"title":"Transcript Error"
|
||||||
},
|
},
|
||||||
"text":{
|
"text":{
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
"fileTitle":"FILE",
|
"fileTitle":"FILE",
|
||||||
"fieldsTitle":"FIELDS",
|
"fieldsTitle":"FIELDS",
|
||||||
"reactionsTitle":"REACTIONS",
|
"reactionsTitle":"REACTIONS",
|
||||||
"statsTitle":"STATS",
|
"statsTitle":"STATISTICS",
|
||||||
"emptyContent":"<content is empty>",
|
"emptyContent":"<content is empty>",
|
||||||
"noTitle":"<no-title>",
|
"noTitle":"<no-title>",
|
||||||
"noDesc":"<no-description>"
|
"noDesc":"<no-description>"
|
||||||
@@ -302,68 +302,68 @@
|
|||||||
"permissionError":"Permission Error"
|
"permissionError":"Permission Error"
|
||||||
},
|
},
|
||||||
"descriptions":{
|
"descriptions":{
|
||||||
"askForInfo":"Contact the owner of this bot for more info!",
|
"askForInfo":"Please contact the bot owner for more information.",
|
||||||
"askForInfoResolve":"Contact the bot owner of this bot if this issue doesn't resolve after a few tries.",
|
"askForInfoResolve":"If the issue persists after a few attempts, please contact the bot owner.",
|
||||||
"internalError":"Failed to respond to this {0} due to an internal error!",
|
"internalError":"An internal error occurred while processing this {0}.",
|
||||||
"optionMissing":"A required parameter is missing in this command!",
|
"optionMissing":"A required parameter is missing for this command.",
|
||||||
"optionInvalid":"A parameter in this command is invalid!",
|
"optionInvalid":"One or more parameters provided for this command are invalid.",
|
||||||
"optionInvalidChoose":"Choose between",
|
"optionInvalidChoose":"Please choose between",
|
||||||
"unknownCommand":"Try visiting the help menu for more info!",
|
"unknownCommand":"Please use the help menu for more information.",
|
||||||
"noPermissions":"You are not allowed to use this {0}!",
|
"noPermissions":"You are not permitted to use this {0}.",
|
||||||
"noPermissionsList":"Required Permissions: (one of them)",
|
"noPermissionsList":"Required permissions (one of the following):",
|
||||||
"noPermissionsCooldown":"You are not allowed to use this {0} because you have a cooldown!",
|
"noPermissionsCooldown":"You cannot use this {0} while on cooldown.",
|
||||||
"noPermissionsBlacklist":"You are not allowed to use this {0} because you have been blacklisted!",
|
"noPermissionsBlacklist":"You cannot use this {0} because you are blacklisted.",
|
||||||
"noPermissionsLimitGlobal":"You are not allowed to create a ticket because the server reached the max tickets limit!",
|
"noPermissionsLimitGlobal":"You cannot create a ticket because the server has reached its maximum ticket limit.",
|
||||||
"noPermissionsLimitGlobalUser":"You are not allowed to create a ticket because you reached the max tickets limit!",
|
"noPermissionsLimitGlobalUser":"You cannot create a ticket because you have reached your maximum ticket limit.",
|
||||||
"noPermissionsLimitOption":"You are not allowed to create a ticket because the server reached the max tickets limit for this option!",
|
"noPermissionsLimitOption":"You cannot create a ticket because the server has reached the maximum ticket limit for this option.",
|
||||||
"noPermissionsLimitOptionUser":"You are not allowed to create a ticket because you reached the max tickets limit for this option!",
|
"noPermissionsLimitOptionUser":"You cannot create a ticket because you have reached the maximum ticket limit for this option.",
|
||||||
"unknownTicket":"Try this command again in a valid ticket!",
|
"unknownTicket":"Please run this command inside a valid ticket channel.",
|
||||||
"deprecatedTicket":"The current channel is not a valid ticket! It might have been a ticket from an old Open Ticket version!",
|
"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} doesn't work in DM! Please try it again in a server!",
|
"notInGuild":"This {0} cannot be used in direct messages. Please use it 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.",
|
"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":"The source of this error is: {0}",
|
"channelRenameSource":"Error source: {0}",
|
||||||
"busy":"Unable to use this {0}!\nThe ticket is currently being processed by the bot.\n\nPlease try again in a few seconds!",
|
"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/deleted before a message has been sent by a user.",
|
"closeBeforeMessage":"This ticket cannot be closed or deleted before a user has sent a message.",
|
||||||
"closeBeforeAdminMessage":"This ticket cannot be closed/deleted before a message has been sent by a ticket admin or support member.",
|
"closeBeforeAdminMessage":"This ticket cannot be closed or deleted before a support member or admin has sent a message.",
|
||||||
"unableToCreateTicket":"You are unable to create a ticket."
|
"unableToCreateTicket":"You are currently unable to create a ticket."
|
||||||
},
|
},
|
||||||
"optionInvalidReasons":{
|
"optionInvalidReasons":{
|
||||||
"stringRegex":"Value doesn't match pattern!",
|
"stringRegex":"The value does not match the required pattern.",
|
||||||
"stringMinLength":"Value needs to be at least {0} characters!",
|
"stringMinLength":"The value must be at least {0} characters long.",
|
||||||
"stringMaxLength":"Value needs to be at most {0} characters!",
|
"stringMaxLength":"The value must be at most {0} characters long.",
|
||||||
"numberInvalid":"Invalid number!",
|
"numberInvalid":"Invalid number provided.",
|
||||||
"numberMin":"Number needs to be at least {0}!",
|
"numberMin":"The number must be at least {0}.",
|
||||||
"numberMax":"Number needs to be at most {0}!",
|
"numberMax":"The number must be at most {0}.",
|
||||||
"numberDecimal":"Number is not allowed to be a decimal!",
|
"numberDecimal":"Decimals are not allowed.",
|
||||||
"numberNegative":"Number is not allowed to be negative!",
|
"numberNegative":"Negative numbers are not allowed.",
|
||||||
"numberPositive":"Number is not allowed to be positive!",
|
"numberPositive":"Positive numbers are not allowed.",
|
||||||
"numberZero":"Number is not allowed to be zero!",
|
"numberZero":"Zero is not allowed.",
|
||||||
"channelNotFound":"Unable to find channel!",
|
"channelNotFound":"Channel not found.",
|
||||||
"userNotFound":"Unable to find user!",
|
"userNotFound":"User not found.",
|
||||||
"roleNotFound":"Unable to find role!",
|
"roleNotFound":"Role not found.",
|
||||||
"memberNotFound":"Unable to find user!",
|
"memberNotFound":"Member not found.",
|
||||||
"mentionableNotFound":"Unable to find user or role!",
|
"mentionableNotFound":"User or role not found.",
|
||||||
"channelType":"Invalid channel type!",
|
"channelType":"Invalid channel type.",
|
||||||
"notInGuild":"This option requires you to be in a server!"
|
"notInGuild":"This option can only be used in a server."
|
||||||
},
|
},
|
||||||
"permissions":{
|
"permissions":{
|
||||||
"developer":"You need to be the developer of the bot.",
|
"developer":"This action is restricted to the bot developer.",
|
||||||
"owner":"You need to be the server owner.",
|
"owner":"You must be the server owner to use this.",
|
||||||
"admin":"You need to be a server admin.",
|
"admin":"You must have administrator permissions to use this.",
|
||||||
"moderator":"You need to be a moderator.",
|
"moderator":"You must be a moderator to use this.",
|
||||||
"support":"You need to be in the support team.",
|
"support":"You must be part of the support team to use this.",
|
||||||
"member":"You need to be a member.",
|
"member":"You must be a server member to use this.",
|
||||||
"discord-administrator":"You need to have the `ADMINISTRATOR` permission."
|
"discord-administrator":"You must have the `ADMINISTRATOR` permission."
|
||||||
},
|
},
|
||||||
"actionInvalid":{
|
"actionInvalid":{
|
||||||
"close":"Ticket is already closed!",
|
"close":"This ticket is already closed.",
|
||||||
"reopen":"Ticket is not closed yet!",
|
"reopen":"This ticket is not closed.",
|
||||||
"claim":"Ticket is already claimed!",
|
"claim":"This ticket is already claimed.",
|
||||||
"unclaim":"Ticket is not claimed yet!",
|
"unclaim":"This ticket is not claimed.",
|
||||||
"pin":"Ticket is already pinned!",
|
"pin":"This ticket is already pinned.",
|
||||||
"unpin":"Ticket is not pinned yet!",
|
"unpin":"This ticket is not pinned.",
|
||||||
"add":"This user is already able to access the ticket!",
|
"add":"This user already has access to this ticket.",
|
||||||
"remove":"Unable to remove this user from the ticket!"
|
"remove":"This user does not have access to this ticket."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params":{
|
"params":{
|
||||||
@@ -432,107 +432,107 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands":{
|
"commands":{
|
||||||
"reason":"Specify an optional reason that will be visible in logs.",
|
"reason":"Optional reason shown in logs.",
|
||||||
"help":"Get a list of all the available commands.",
|
"help":"Display all available commands.",
|
||||||
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
|
"panel":"Create a ticket panel (buttons or dropdown).",
|
||||||
"panelId":"The identifier of the panel that you want to spawn.",
|
"panelId":"ID of the panel to spawn.",
|
||||||
"panelAutoUpdate":"Do you want this panel to automatically update when edited?",
|
"panelAutoUpdate":"Automatically update this panel when edited.",
|
||||||
"ticket":"Instantly create a ticket.",
|
"ticket":"Create a ticket instantly.",
|
||||||
"ticketId":"The identifier of the ticket that you want to create.",
|
"ticketId":"ID of the ticket to create.",
|
||||||
"close":"Close a ticket.",
|
"close":"Close this ticket.",
|
||||||
"delete":"Delete a ticket.",
|
"delete":"Delete this ticket.",
|
||||||
"deleteNoTranscript":"Delete this ticket without creating a transcript.",
|
"deleteNoTranscript":"Delete ticket without saving a transcript.",
|
||||||
"reopen":"Reopen a ticket.",
|
"reopen":"Reopen a closed ticket.",
|
||||||
"claim":"Claim a ticket.",
|
"claim":"Claim this ticket.",
|
||||||
"claimUser":"Claim this ticket to someone else instead of yourself.",
|
"claimUser":"Claim the ticket for another user.",
|
||||||
"unclaim":"Unclaim a ticket.",
|
"unclaim":"Unclaim this ticket.",
|
||||||
"pin":"Pin a ticket.",
|
"pin":"Pin this ticket.",
|
||||||
"unpin":"Unpin a ticket.",
|
"unpin":"Unpin this ticket.",
|
||||||
|
|
||||||
"move":"Move a ticket.",
|
"move":"Move ticket to another option.",
|
||||||
"moveId":"The identifier of the option that you want to move to.",
|
"moveId":"Target option ID.",
|
||||||
"rename":"Rename a ticket.",
|
"rename":"Rename this ticket.",
|
||||||
"renameName":"The new name for this ticket.",
|
"renameName":"New name for the ticket.",
|
||||||
"add":"Add a user to a ticket.",
|
"add":"Add a user to this ticket.",
|
||||||
"addUser":"The user to add.",
|
"addUser":"User to add.",
|
||||||
"remove":"Remove a user from a ticket.",
|
"remove":"Remove a user from this ticket.",
|
||||||
"removeUser":"The user to remove.",
|
"removeUser":"User to remove.",
|
||||||
|
|
||||||
"blacklist":"Manage the ticket blacklist.",
|
"blacklist":"Manage the blacklist.",
|
||||||
"blacklistView":"View a list of the current blacklist.",
|
"blacklistView":"View all blacklisted users.",
|
||||||
"blacklistAdd":"Add a user to the blacklist.",
|
"blacklistAdd":"Add a user to the blacklist.",
|
||||||
"blacklistRemove":"Remove a user from the blacklist.",
|
"blacklistRemove":"Remove a user from the blacklist.",
|
||||||
"blacklistGet":"Get the details from a blacklisted user.",
|
"blacklistGet":"View blacklist entry details.",
|
||||||
"blacklistGetUser":"The user to get details from.",
|
"blacklistGetUser":"User to look up.",
|
||||||
"stats":"View statistics from the bot, a member or a ticket.",
|
"stats":"View bot, user or ticket statistics.",
|
||||||
"statsReset":"Reset all the stats of the bot (and start counting from zero).",
|
"statsReset":"Reset all bot statistics.",
|
||||||
"statsGlobal":"View the global stats.",
|
"statsGlobal":"View global bot statistics.",
|
||||||
"statsUser":"View the stats from a user in the server.",
|
"statsUser":"View a user's statistics.",
|
||||||
"statsUserUser":"The user to view.",
|
"statsUserUser":"User to view.",
|
||||||
"statsTicket":"View the stats of a ticket in the server.",
|
"statsTicket":"View ticket statistics.",
|
||||||
"statsTicketTicket":"The ticket to view.",
|
"statsTicketTicket":"Ticket to view.",
|
||||||
|
|
||||||
"clear":"Delete multiple tickets at the same time.",
|
"clear":"Delete multiple tickets at once.",
|
||||||
"clearFilter":"The filter for clearing tickets.",
|
"clearFilter":"Filter used when clearing tickets.",
|
||||||
"clearFilters":{
|
"clearFilters":{
|
||||||
"all":"All",
|
"all":"All tickets",
|
||||||
"open":"Open",
|
"open":"Open tickets",
|
||||||
"close":"Closed",
|
"close":"Closed tickets",
|
||||||
"claim":"Claimed",
|
"claim":"Claimed tickets",
|
||||||
"unclaim":"Unclaimed",
|
"unclaim":"Unclaimed tickets",
|
||||||
"pin":"Pinned",
|
"pin":"Pinned tickets",
|
||||||
"unpin":"Unpinned",
|
"unpin":"Unpinned tickets",
|
||||||
"autoclose":"Autoclosed"
|
"autoclose":"Autoclosed tickets"
|
||||||
},
|
},
|
||||||
|
|
||||||
"autoclose":"Manage autoclose in a ticket.",
|
"autoclose":"Manage ticket autoclose.",
|
||||||
"autocloseDisable":"Disable autoclose in this ticket.",
|
"autocloseDisable":"Disable autoclose.",
|
||||||
"autocloseEnable":"Enable autoclose in this ticket.",
|
"autocloseEnable":"Enable autoclose.",
|
||||||
"autocloseEnableTime":"The amount of hours this ticket needs to be inactive to close it.",
|
"autocloseEnableTime":"Hours of inactivity before closing.",
|
||||||
"autodelete":"Manage autodelete in a ticket.",
|
"autodelete":"Manage ticket autodelete.",
|
||||||
"autodeleteDisable":"Disable autodelete in this ticket.",
|
"autodeleteDisable":"Disable autodelete.",
|
||||||
"autodeleteEnable":"Enable autodelete in this ticket.",
|
"autodeleteEnable":"Enable autodelete.",
|
||||||
"autodeleteEnableTime":"The amount of days this ticket needs to be inactive to delete it.",
|
"autodeleteEnableTime":"Days of inactivity before deletion.",
|
||||||
|
|
||||||
"topic":"Manage the topic of the ticket channel.",
|
"topic":"Manage ticket channel topic.",
|
||||||
"topicSet":"Set the topic of the ticket channel.",
|
"topicSet":"Set the ticket channel topic.",
|
||||||
"topicValue":"The new topic of the channel.",
|
"topicValue":"New channel topic text.",
|
||||||
"topicList":"Get a list of all tickets with their topic and stats.",
|
"topicList":"List all ticket channel topics.",
|
||||||
"priority":"Manage the priority of the ticket.",
|
"priority":"Manage ticket priority.",
|
||||||
"prioritySet":"Set the priority of the ticket.",
|
"prioritySet":"Set ticket priority.",
|
||||||
"priorityValue":"The priority of the channel.",
|
"priorityValue":"Priority level.",
|
||||||
"priorityGet":"Get the priority of the ticket.",
|
"priorityGet":"View ticket priority.",
|
||||||
"priorityList":"Get a list of all tickets with their priority status.",
|
"priorityList":"List all ticket priorities.",
|
||||||
"transfer":"Transfer the ticket ownership from one user to another.",
|
"transfer":"Transfer ticket ownership.",
|
||||||
"transferUser":"The user to transfer to."
|
"transferUser":"User to transfer to."
|
||||||
},
|
},
|
||||||
"helpMenu":{
|
"helpMenu":{
|
||||||
"help":"Get a list of all the available commands.",
|
"help":"View all available commands.",
|
||||||
"ticket":"Instantly create a ticket.",
|
"ticket":"Create a ticket instantly.",
|
||||||
"close":"Close a ticket, this disables writing in this channel.",
|
"close":"Close this ticket and disable messaging in the channel.",
|
||||||
"delete":"Delete a ticket, this creates a transcript when enabled.",
|
"delete":"Delete this ticket (creates a transcript if enabled).",
|
||||||
"reopen":"Reopen a ticket, this enables writing in this channel again.",
|
"reopen":"Reopen a closed ticket and restore messaging.",
|
||||||
"pin":"Pin a ticket. This will move the ticket to the top and will add a '📌' emoij to the name.",
|
"pin":"Pin this ticket and move it to the top with '📌'.",
|
||||||
"unpin":"Unpin a ticket. The ticket will stay on it's position but will lose the '📌' emoij.",
|
"unpin":"Unpin this ticket and remove the '📌' emoji.",
|
||||||
"move":"Move a ticket. This will change the type of this ticket.",
|
"move":"Move this ticket to a different option or ticket type.",
|
||||||
"rename":"Rename a ticket. This will change the channel name of this ticket.",
|
"rename":"Rename this ticket channel.",
|
||||||
"claim":"Claim a ticket. With this, you can let your team know you are handling this ticket.",
|
"claim":"Claim this ticket to show you are handling it.",
|
||||||
"unclaim":"Unclaim a ticket. With this, you can let your team know that this ticket is free again.",
|
"unclaim":"Unclaim this ticket to mark it as available.",
|
||||||
"add":"Add a user to a ticket. This will allow the user to read & write in this ticket.",
|
"add":"Add a user to this ticket.",
|
||||||
"remove":"Remove a user from a ticket. This will remove the ability to read & write for a user in this ticket.",
|
"remove":"Remove a user's access from this ticket.",
|
||||||
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
|
"panel":"Create a ticket panel with buttons or a dropdown.",
|
||||||
"blacklistView":"View a list of the current blacklist.",
|
"blacklistView":"View all blacklisted users.",
|
||||||
"blacklistAdd":"Add a user to the blacklist.",
|
"blacklistAdd":"Add a user to the blacklist.",
|
||||||
"blacklistRemove":"Remove a user from the blacklist.",
|
"blacklistRemove":"Remove a user from the blacklist.",
|
||||||
"blacklistGet":"Get the details from a blacklisted user.",
|
"blacklistGet":"View details of a blacklisted user.",
|
||||||
"statsGlobal":"View the global stats.",
|
"statsGlobal":"View global bot statistics.",
|
||||||
"statsTicket":"View the stats of a ticket in the server.",
|
"statsTicket":"View statistics for a ticket.",
|
||||||
"statsUser":"View the stats from a user in the server.",
|
"statsUser":"View statistics for a user.",
|
||||||
"statsReset":"Reset all the stats of the bot (and start counting from zero).",
|
"statsReset":"Reset all bot statistics.",
|
||||||
"autocloseDisable":"Disable autoclose in this ticket.",
|
"autocloseDisable":"Disable autoclose for this ticket.",
|
||||||
"autocloseEnable":"Enable autoclose in this ticket.",
|
"autocloseEnable":"Enable autoclose for this ticket.",
|
||||||
"autodeleteDisable":"Disable autodelete in this ticket.",
|
"autodeleteDisable":"Disable autodelete for this ticket.",
|
||||||
"autodeleteEnable":"Enable autodelete in this ticket.",
|
"autodeleteEnable":"Enable autodelete for this ticket.",
|
||||||
"categories":{
|
"categories":{
|
||||||
"general":"General Commands",
|
"general":"General Commands",
|
||||||
"basicTicket":"Basic Ticket Commands",
|
"basicTicket":"Basic Ticket Commands",
|
||||||
@@ -545,10 +545,10 @@
|
|||||||
},
|
},
|
||||||
"stats":{
|
"stats":{
|
||||||
"scopes":{
|
"scopes":{
|
||||||
"global":"Global Stats",
|
"global":"Global Statistics",
|
||||||
"system":"System Stats",
|
"system":"System Statistics",
|
||||||
"user":"User Stats",
|
"user":"User Statistics",
|
||||||
"ticket":"Ticket Stats",
|
"ticket":"Ticket Statistics",
|
||||||
"participants":"Participants",
|
"participants":"Participants",
|
||||||
"messages":"Messages"
|
"messages":"Messages"
|
||||||
},
|
},
|
||||||
@@ -592,9 +592,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"panel":{
|
"panel":{
|
||||||
"selectTicket":"Select your ticket",
|
"selectTicket":"Select a ticket",
|
||||||
"selectRole":"Select your role",
|
"selectRole":"Select a role",
|
||||||
"selectOption":"Select your option"
|
"selectOption":"Select an option"
|
||||||
},
|
},
|
||||||
"priorities":{
|
"priorities":{
|
||||||
"urgent":"Urgent",
|
"urgent":"Urgent",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["spyeye_"],
|
"translators":["spyeye_"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Czech",
|
"language":"Czech",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["the_gamer"],
|
"translators":["the_gamer"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Danish",
|
"language":"Danish",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["DJj123dj"],
|
"translators":["DJj123dj"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Dutch",
|
"language":"Dutch",
|
||||||
|
|||||||
+318
-318
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["DJj123dj"],
|
"translators":["DJj123dj"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"English",
|
"language":"English",
|
||||||
@@ -13,94 +13,94 @@
|
|||||||
"typeWarning":"[WARNING]",
|
"typeWarning":"[WARNING]",
|
||||||
"typeInfo":"[INFO]",
|
"typeInfo":"[INFO]",
|
||||||
"headerConfigChecker":"CONFIG CHECKER",
|
"headerConfigChecker":"CONFIG CHECKER",
|
||||||
"headerDescription":"check for errors in your config files!",
|
"headerDescription":"Validating config files...",
|
||||||
"footerError":"the bot won't start until all {0}'s are fixed!",
|
"footerError":"The bot will not start until all {0}'s are resolved.",
|
||||||
"footerWarning":"it's recommended to fix all {0}'s before starting!",
|
"footerWarning":"The bot may behave unexpectedly until all {0}'s are resolved.",
|
||||||
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
|
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
|
||||||
"compactInformation":"use {0} for more information!",
|
"compactInformation":"Use {0} for a detailed config report.",
|
||||||
"dataPath":"path",
|
"dataPath":"path",
|
||||||
"dataDocs":"docs",
|
"dataDocs":"docs",
|
||||||
"dataMessages":"message"
|
"dataMessages":"message"
|
||||||
},
|
},
|
||||||
"messages":{
|
"messages":{
|
||||||
"stringTooShort":"This string can't be shorter than {0} characters!",
|
"stringTooShort":"Text must be at least {0} characters long",
|
||||||
"stringTooLong":"This string can't be longer than {0} characters!",
|
"stringTooLong":"Text must be no longer than {0} characters",
|
||||||
"stringLengthInvalid":"This string needs to be {0} characters long!",
|
"stringLengthInvalid":"Text must be exactly {0} characters long",
|
||||||
"stringStartsWith":"This string needs to start with {0}!",
|
"stringStartsWith":"Text must start with {0}",
|
||||||
"stringEndsWith":"This string needs to end with {0}!",
|
"stringEndsWith":"Text must end with {0}",
|
||||||
"stringContains":"This string needs to contain {0}!",
|
"stringContains":"Text must contain {0}",
|
||||||
"stringChoices":"This string can only be one of the following values: {0}!",
|
"stringChoices":"Text must be one of the following: {0}",
|
||||||
"stringRegex":"This string is invalid!",
|
"stringRegex":"Text does not match the required format",
|
||||||
"stringInvertedContains":"This string is not allowed to contain {0}!",
|
"stringInvertedContains":"Text must not contain {0}",
|
||||||
"stringLowercase":"This string must be written in lowercase only!",
|
"stringLowercase":"Text must be entirely lowercase",
|
||||||
"stringUppercase":"This string must be written in uppercase only!",
|
"stringUppercase":"Text must be entirely uppercase",
|
||||||
"stringSpecialCharacters":"This string is not allowed to contain any special characters! (a-z, 0-9 & space only)",
|
"stringSpecialCharacters":"Text must only contain letters (a–z), numbers (0–9), and spaces",
|
||||||
"stringNoSpaces":"This string is not allowed to contain spaces!",
|
"stringNoSpaces":"Text must not contain spaces",
|
||||||
"stringCapitalWord":"It's recommended that each word in this string starts with a capital letter!",
|
"stringCapitalWord":"Each word in this value should start with a capital letter",
|
||||||
"stringCapitalSentence":"It looks like some sentences in this string don't start with a capital letter!",
|
"stringCapitalSentence":"One or more sentences in this value do not start with a capital letter",
|
||||||
"stringPunctuation":"It looks like the sentence in this string doesn't end with a punctuation mark!",
|
"stringPunctuation":"The sentence in this value does not end with a punctuation mark",
|
||||||
|
|
||||||
"numberTooShort":"This number can't be shorter than {0} characters!",
|
"numberTooShort":"Number must be at least {0} digits long",
|
||||||
"numberTooLong":"This number can't be longer than {0} characters!",
|
"numberTooLong":"Number must be no longer than {0} digits",
|
||||||
"numberLengthInvalid":"This number needs to be {0} characters long!",
|
"numberLengthInvalid":"Number must be exactly {0} digits long",
|
||||||
"numberTooSmall":"This number needs to be at least {0}!",
|
"numberTooSmall":"Number must be at least {0}",
|
||||||
"numberTooLarge":"This number needs to be at most {0}!",
|
"numberTooLarge":"Number must be at most {0}",
|
||||||
"numberNotEqual":"This number needs to be {0}!",
|
"numberNotEqual":"Number must be exactly {0}",
|
||||||
"numberStep":"This number needs to be a multiple of {0}!",
|
"numberStep":"Number must be a multiple of {0}",
|
||||||
"numberStepOffset":"This number needs to be a multiple of {0} starting with {1}!",
|
"numberStepOffset":"Number must be a multiple of {0}, starting from {1}",
|
||||||
"numberStartsWith":"This number needs to start with {0}!",
|
"numberStartsWith":"Number must start with {0}",
|
||||||
"numberEndsWith":"This number needs to end with {0}!",
|
"numberEndsWith":"Number must end with {0}",
|
||||||
"numberContains":"This number needs to contain {0}!",
|
"numberContains":"Number must contain {0}",
|
||||||
"numberChoices":"This number can only be one of the following values: {0}!",
|
"numberChoices":"Number must be one of the following: {0}",
|
||||||
"numberFloat":"This number can't be a decimal!",
|
"numberFloat":"Number must be a whole number",
|
||||||
"numberNegative":"This number can't be negative!",
|
"numberNegative":"Number must be a positive number",
|
||||||
"numberPositive":"This number can't be positive!",
|
"numberPositive":"Number must be a negative number",
|
||||||
"numberZero":"This number can't be zero!",
|
"numberZero":"Number must not be zero",
|
||||||
"numberNan":"This number can't be NaN (Not A Number)!",
|
"numberNan":"Number must be a valid number",
|
||||||
"numberInvertedContains":"This number is not allowed to contain {0}!",
|
"numberInvertedContains":"Number must not contain {0}",
|
||||||
|
|
||||||
"booleanTrue":"This boolean can't be true!",
|
"booleanTrue":"Boolean must be false",
|
||||||
"booleanFalse":"This boolean can't be false!",
|
"booleanFalse":"Boolean must be true",
|
||||||
|
|
||||||
"arrayEmptyDisabled":"This array isn't allowed to be empty!",
|
"arrayEmptyDisabled":"List must not be empty",
|
||||||
"arrayEmptyRequired":"This array is required to be empty!",
|
"arrayEmptyRequired":"List must be empty",
|
||||||
"arrayTooShort":"This array needs to have a length of at least {0}!",
|
"arrayTooShort":"List must have at least {0} items",
|
||||||
"arrayTooLong":"This array needs to have a length of at most {0}!",
|
"arrayTooLong":"List must have at most {0} items",
|
||||||
"arrayLengthInvalid":"This array needs to have a length of {0}!",
|
"arrayLengthInvalid":"List must have exactly {0} items",
|
||||||
"arrayInvalidTypes":"This array can only contain the following types: {0}!",
|
"arrayInvalidTypes":"List may only contain the following types: {0}",
|
||||||
"arrayDouble":"This array doesn't allow the same value twice!",
|
"arrayDouble":"List must not contain duplicate values",
|
||||||
|
|
||||||
"discordInvalidId":"This is an invalid discord {0} id!",
|
"discordInvalidId":"Invalid Discord {0} ID",
|
||||||
"discordInvalidIdOptions":"This is an invalid discord {0} id! You can also use one of these: {1}!",
|
"discordInvalidIdOptions":"Invalid Discord {0} ID. Alternatively, use one of the following: {1}",
|
||||||
"discordInvalidToken":"This is an invalid discord token (syntactically)!",
|
"discordInvalidToken":"Invalid Discord token",
|
||||||
"colorInvalid":"This is an invalid hex color!",
|
"colorInvalid":"Invalid hex color",
|
||||||
"emojiTooShort":"This string needs to have at least {0} emoji's!",
|
"emojiTooShort":"Value must contain at least {0} emoji",
|
||||||
"emojiTooLong":"This string needs to have at most {0} emoji's!",
|
"emojiTooLong":"Value must contain at most {0} emoji",
|
||||||
"emojiCustom":"This emoji can't be a custom discord emoji!",
|
"emojiCustom":"Custom Discord emojis are not allowed here",
|
||||||
"emojiInvalid":"This is an invalid emoji!",
|
"emojiInvalid":"Invalid emoji",
|
||||||
"urlInvalid":"This url is invalid!",
|
"urlInvalid":"Invalid URL",
|
||||||
"urlInvalidHttp":"This url can only use the https:// protocol!",
|
"urlInvalidHttp":"URL must use the https:// protocol",
|
||||||
"urlInvalidProtocol":"This url can only use the http:// & https:// protocols!",
|
"urlInvalidProtocol":"URL must use the http:// or https:// protocol",
|
||||||
"urlInvalidHostname":"This url has a disallowed hostname!",
|
"urlInvalidHostname":"URL hostname is not allowed",
|
||||||
"urlInvalidExtension":"This url has an invalid extension! Choose between: {0}!",
|
"urlInvalidExtension":"Invalid URL extension. Allowed extensions: {0}",
|
||||||
"urlInvalidPath":"This url has an invalid path!",
|
"urlInvalidPath":"Invalid URL path",
|
||||||
"idNotUnique":"This id isn't unique, use another id instead!",
|
"idNotUnique":"This ID is already in use. Please choose a unique ID",
|
||||||
"idNonExistent":"The id {0} doesn't exist!",
|
"idNonExistent":"ID {0} does not exist",
|
||||||
|
|
||||||
"invalidType":"This property needs to be the type: {0}!",
|
"invalidType":"Property must be of type: {0}",
|
||||||
"propertyMissing":"The property {0} is missing from this object!",
|
"propertyMissing":"Required property {0} is missing from the object",
|
||||||
"propertyOptional":"The property {0} is optional in this object!",
|
"propertyOptional":"Property {0} is optional in the object",
|
||||||
"objectDisabled":"This object is disabled, enable it using {0}!",
|
"objectDisabled":"This object is disabled. Enable it using {0}",
|
||||||
"nullInvalid":"This property can't be null!",
|
"nullInvalid":"Property must not be null",
|
||||||
"switchInvalidType":"This needs to be one of the following types: {0}!",
|
"switchInvalidType":"Value must be one of the following types: {0}",
|
||||||
"objectSwitchInvalid":"This object needs to be one of the following types: {0}!",
|
"objectSwitchInvalid":"Object must be one of the following types: {0}",
|
||||||
|
|
||||||
"invalidLanguage":"This is an invalid language!",
|
"invalidLanguage":"Invalid language",
|
||||||
"invalidButton":"This button needs to have at least an {0} or {1}!",
|
"invalidButton":"Button must have at least an {0} or {1}",
|
||||||
"unusedOption":"The option {0} isn't used anywhere!",
|
"unusedOption":"Option {0} is not used anywhere",
|
||||||
"unusedQuestion":"The question {0} isn't used anywhere!",
|
"unusedQuestion":"Question {0} is not used anywhere",
|
||||||
"dropdownOption":"A panel with dropdown enabled can only contain options of the 'ticket' type!",
|
"dropdownOption":"Panels with dropdown enabled may 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!"
|
"customInvalidVersion":"Config version mismatch. Make sure to update your config to the latest version"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actions":{
|
"actions":{
|
||||||
@@ -159,118 +159,118 @@
|
|||||||
"transfer":"Ticket Transferred"
|
"transfer":"Ticket Transferred"
|
||||||
},
|
},
|
||||||
"descriptions":{
|
"descriptions":{
|
||||||
"create":"Your ticket has been created. Click the button below to access it!",
|
"create":"Your ticket is ready. Click the button below to view and continue.",
|
||||||
"close":"The ticket has been closed successfully!",
|
"close":"The ticket has been closed.",
|
||||||
"delete":"The ticket has been deleted successfully!",
|
"delete":"The ticket has been deleted.",
|
||||||
"reopen":"The ticket has been reopened successfully!",
|
"reopen":"The ticket has been reopened.",
|
||||||
"claim":"The ticket has been claimed successfully!",
|
"claim":"The ticket has been claimed.",
|
||||||
"unclaim":"The ticket has been unclaimed successfully!",
|
"unclaim":"The ticket has been unclaimed.",
|
||||||
"pin":"The ticket has been pinned successfully!",
|
"pin":"The ticket has been pinned.",
|
||||||
"unpin":"The ticket has been unpinned successfully!",
|
"unpin":"The ticket has been unpinned.",
|
||||||
"rename":"The ticket has been renamed to {0} successfully!",
|
"rename":"The ticket has been renamed to {0}.",
|
||||||
"move":"The ticket has been moved to {0} successfully!",
|
"move":"The ticket has been moved to {0}.",
|
||||||
"add":"{0} has been added to the ticket successfully!",
|
"add":"{0} has been added to the ticket.",
|
||||||
"remove":"{0} has been removed from the ticket successfully!",
|
"remove":"{0} has been removed from the ticket.",
|
||||||
|
|
||||||
"helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter",
|
"helpExplanation":"`<name>` => required parameter\n`[name]` => optional parameter",
|
||||||
"statsReset":"The bot stats have been reset successfully!",
|
"statsReset":"The bot statistics have been reset.",
|
||||||
"statsError":"Unable to view ticket stats!\n{0} is not a ticket!",
|
"statsError":"Unable to retrieve ticket statistics.\n{0} is not a valid ticket.",
|
||||||
"blacklistAdd":"{0} has been blacklisted successfully!",
|
"blacklistAdd":"{0} has been blacklisted.",
|
||||||
"blacklistRemove":"{0} has been released successfully!",
|
"blacklistRemove":"{0} has been released.",
|
||||||
"blacklistGetSuccess":"{0} is currently blacklisted!",
|
"blacklistGetSuccess":"{0} is blacklisted!",
|
||||||
"blacklistGetEmpty":"{0} is currently not blacklisted!",
|
"blacklistGetEmpty":"{0} is not blacklisted!",
|
||||||
"blacklistViewEmpty":"No-one has been blacklisted yet!",
|
"blacklistViewEmpty":"No users have been blacklisted yet.",
|
||||||
"blacklistViewTip":"Use \"/blacklist add\" to blacklist a user!",
|
"blacklistViewTip":"Use \"/blacklist add\" to add a user to the blacklist.",
|
||||||
"clearVerify":"Are you sure you want to delete multiple tickets?\nThis action can't be undone!",
|
"clearVerify":"Are you sure you want to delete multiple tickets?\nThis action cannot be undone.",
|
||||||
"clearReady":"{0} tickets have been deleted successfully!",
|
"clearReady":"{0} ticket(s) have been deleted.",
|
||||||
"rolesEmpty":"No roles have been updated!",
|
"rolesEmpty":"No roles were modified.",
|
||||||
|
|
||||||
"autocloseLeave":"This ticket has been autoclosed because the creator left the server!",
|
"autocloseLeave":"This ticket was automatically closed because its creator left the server.",
|
||||||
"autocloseTimeout":"This ticket has been autoclosed because it has been inactive for more than `{0}h`!",
|
"autocloseTimeout":"This ticket was automatically closed due to inactivity exceeding `{0}h`.",
|
||||||
"autodeleteLeave":"This ticket has been autodeleted because the creator left the server!",
|
"autodeleteLeave":"This ticket was automatically deleted because its creator left the server.",
|
||||||
"autodeleteTimeout":"This ticket has been autodeleted because it has been inactive for more than `{0} days`!",
|
"autodeleteTimeout":"This ticket was automatically deleted due to inactivity exceeding `{0} days`.",
|
||||||
"autocloseEnabled":"Autoclose has been enabled in this ticket!\nIt will be closed when it is inactive for more than `{0}h`!",
|
"autocloseEnabled":"Autoclose has been enabled for this ticket.\nIt will close after `{0}h` of inactivity.",
|
||||||
"autocloseDisabled":"Autoclose has been disabled in this ticket!\nIt won't be closed automatically anymore!",
|
"autocloseDisabled":"Autoclose has been disabled for this ticket.\nThis ticket will no longer close automatically.",
|
||||||
"autodeleteEnabled":"Autodelete has been enabled in this ticket!\nIt will be deleted when it is inactive for more than `{0} days`!",
|
"autodeleteEnabled":"Autodelete has been enabled for this ticket.\nIt will be deleted after `{0} days` of inactivity.",
|
||||||
"autodeleteDisabled":"Autodelete has been disabled in this ticket!\nIt won't be deleted automatically anymore!",
|
"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!",
|
"ticketMessageLimit":"You can only have {0} active ticket(s) at a time.",
|
||||||
"ticketMessageAutoclose":"This ticket will be autoclosed when inactive for {0}h!",
|
"ticketMessageAutoclose":"This ticket will automatically close after `{0}h` of inactivity.",
|
||||||
"ticketMessageAutodelete":"This ticket will be autodeleted when inactive for {0} days!",
|
"ticketMessageAutodelete":"This ticket will automatically be deleted after `{0} days` of inactivity.",
|
||||||
"panelReady":"The panel is available in the followup message!\nThis message can now be deleted!",
|
"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!",
|
"topicSet":"The channel topic has been changed by {0}.",
|
||||||
"prioritySet":"The ticket priority has been changed to {0} by {1} successfully!",
|
"prioritySet":"The ticket priority has been changed to {0} by {1}.",
|
||||||
"priorityGet":"The current priority of this ticket is {0}.",
|
"priorityGet":"The priority of this ticket is {0}.",
|
||||||
"transfer":"The ticket ownership has been transferred from {0} to {1} by {2} successfully!"
|
"transfer":"The ticket ownership has been transferred from {0} to {1} by {2}."
|
||||||
},
|
},
|
||||||
"modal":{
|
"modal":{
|
||||||
"closePlaceholder":"Why did you close this ticket?",
|
"closePlaceholder":"Why would you like to close this ticket?",
|
||||||
"deletePlaceholder":"Why did you delete this ticket?",
|
"deletePlaceholder":"Why would you like to delete this ticket?",
|
||||||
"reopenPlaceholder":"Why did you reopen this ticket?",
|
"reopenPlaceholder":"Why would you like to reopen this ticket?",
|
||||||
"claimPlaceholder":"Why did you claim this ticket?",
|
"claimPlaceholder":"Why would you like to claim this ticket?",
|
||||||
"unclaimPlaceholder":"Why did you unclaim this ticket?",
|
"unclaimPlaceholder":"Why would you like to unclaim this ticket?",
|
||||||
"pinPlaceholder":"Why did you pin this ticket?",
|
"pinPlaceholder":"Why would you like to pin this ticket?",
|
||||||
"unpinPlaceholder":"Why did you unpin this ticket?"
|
"unpinPlaceholder":"Why would you like to unpin this ticket?"
|
||||||
},
|
},
|
||||||
"logs":{
|
"logs":{
|
||||||
"createLog":"A new ticket got created by {0}!",
|
"createLog":"A new ticket got created by {0}.",
|
||||||
"closeLog":"This ticket has been closed by {0}!",
|
"closeLog":"This ticket has been closed by {0}.",
|
||||||
"closeDm":"Your ticket has been closed in our server!",
|
"closeDm":"Your ticket has been closed.",
|
||||||
"deleteLog":"This ticket has been deleted by {0}!",
|
"deleteLog":"This ticket has been deleted by {0}.",
|
||||||
"deleteDm":"Your ticket has been deleted in our server!",
|
"deleteDm":"Your ticket has been deleted.",
|
||||||
"reopenLog":"This ticket has been reopened by {0}!",
|
"reopenLog":"This ticket has been reopened by {0}.",
|
||||||
"reopenDm":"Your ticket has been reopened in our server!",
|
"reopenDm":"Your ticket has been reopened.",
|
||||||
"claimLog":"This ticket has been claimed by {0}!",
|
"claimLog":"This ticket has been claimed by {0}.",
|
||||||
"claimDm":"Your ticket has been claimed in our server!",
|
"claimDm":"Your ticket has been claimed.",
|
||||||
"unclaimLog":"This ticket has been unclaimed by {0}!",
|
"unclaimLog":"This ticket has been unclaimed by {0}.",
|
||||||
"unclaimDm":"Your ticket has been unclaimed in our server!",
|
"unclaimDm":"Your ticket has been unclaimed.",
|
||||||
"pinLog":"This ticket has been pinned by {0}!",
|
"pinLog":"This ticket has been pinned by {0}.",
|
||||||
"pinDm":"Your ticket has been pinned in our server!",
|
"pinDm":"Your ticket has been pinned.",
|
||||||
"unpinLog":"This ticket has been unpinned by {0}!",
|
"unpinLog":"This ticket has been unpinned by {0}.",
|
||||||
"unpinDm":"Your ticket has been unpinned in our server!",
|
"unpinDm":"Your ticket has been unpinned.",
|
||||||
"renameLog":"This ticket has been renamed to {0} by {1}!",
|
"renameLog":"This ticket has been renamed to {0} by {1}.",
|
||||||
"renameDm":"Your ticket has been renamed to {0} in our server!",
|
"renameDm":"Your ticket has been renamed to {0}.",
|
||||||
"moveLog":"This ticket has been moved to {0} by {1}!",
|
"moveLog":"This ticket has been moved to {0} by {1}.",
|
||||||
"moveDm":"Your ticket has been moved to {0} in our server!",
|
"moveDm":"Your ticket has been moved to {0}.",
|
||||||
"addLog":"{0} has been added to this ticket by {1}!",
|
"addLog":"{0} has been added to this ticket by {1}.",
|
||||||
"addDm":"{0} has been added to your ticket in our server!",
|
"addDm":"{0} has been added to your ticket.",
|
||||||
"removeLog":"{0} has been removed from this ticket by {1}!",
|
"removeLog":"{0} has been removed from this ticket by {1}.",
|
||||||
"removeDm":"{0} has been removed from your ticket in our server!",
|
"removeDm":"{0} has been removed from your ticket.",
|
||||||
|
|
||||||
"blacklistAddLog":"{0} was blacklisted by {1}!",
|
"blacklistAddLog":"{0} has been blacklisted by {1}.",
|
||||||
"blacklistRemoveLog":"{0} was removed from the blacklist by {1}!",
|
"blacklistRemoveLog":"{0} has been removed from the blacklist by {1}.",
|
||||||
"blacklistAddDm":"You have been blacklisted in our server!\nFrom now on, you are unable to create a ticket!",
|
"blacklistAddDm":"You have been blacklisted from this server.\nYou are no longer able to create tickets.",
|
||||||
"blacklistRemoveDm":"You have been removed from the blacklist in our server!\nNow you can create tickets again!",
|
"blacklistRemoveDm":"You have been removed from the blacklist.\nYou can now create tickets again.",
|
||||||
"clearLog":"{0} tickets have been deleted by {1}!",
|
"clearLog":"{0} ticket(s) have been deleted by {1}.",
|
||||||
|
|
||||||
"transferLog":"The ownership of this ticket has been transferred from {0} to {1} by {2}!",
|
"transferLog":"Ticket ownership 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!",
|
"transferDm":"Ownership of your ticket has been transferred from {0} to {1}.",
|
||||||
"prioritySetLog":"The priority of this ticket has been changed to {0} by {1}!",
|
"prioritySetLog":"The priority of this ticket has been set to {0} by {1}.",
|
||||||
"prioritySetDm":"The priority of your ticket has been changed to {0} in our server!",
|
"prioritySetDm":"The priority of your ticket has been set to {0}.",
|
||||||
"roleUpdateLog":"{0} has updated their roles!",
|
"roleUpdateLog":"{0} has modified their roles.",
|
||||||
"roleUpdateDm":"Your roles in our server have been updated!"
|
"roleUpdateDm":"Your roles have been modified."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"transcripts":{
|
"transcripts":{
|
||||||
"success":{
|
"success":{
|
||||||
"visit":"Visit Transcript",
|
"visit":"Visit Transcript",
|
||||||
"ready":"Transcript Created",
|
"ready":"Transcript Created",
|
||||||
"textFileDescription":"This is the text transcript of a deleted ticket!",
|
"textFileDescription":"This is a text transcript of a deleted ticket.",
|
||||||
"htmlProgress":"Please wait while this html transcript is getting processed...",
|
"htmlProgress":"Please wait while the HTML transcript is being generated...",
|
||||||
|
|
||||||
"createdChannel":"A new {0} transcript has been created in the server!",
|
"createdChannel":"A new {0} transcript has been created in the server.",
|
||||||
"createdCreator":"A new {0} transcript has been created for one of your tickets!",
|
"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!",
|
"createdParticipant":"A new {0} transcript has been created for a ticket you participated in.",
|
||||||
"createdActiveAdmin":"A new {0} transcript has been created in one of the tickets you participated as admin!",
|
"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 in one of the tickets you were admin in!",
|
"createdEveryAdmin":"A new {0} transcript has been created for a ticket you managed as an admin.",
|
||||||
"createdOther":"A new {0} transcript has been created!"
|
"createdOther":"A new {0} transcript has been created."
|
||||||
},
|
},
|
||||||
"errors":{
|
"errors":{
|
||||||
"retry":"Retry",
|
"retry":"Retry",
|
||||||
"continue":"Delete Without Transcript",
|
"continue":"Delete Without Transcript",
|
||||||
"backup":"Create Backup 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"
|
"title":"Transcript Error"
|
||||||
},
|
},
|
||||||
"text":{
|
"text":{
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
"fileTitle":"FILE",
|
"fileTitle":"FILE",
|
||||||
"fieldsTitle":"FIELDS",
|
"fieldsTitle":"FIELDS",
|
||||||
"reactionsTitle":"REACTIONS",
|
"reactionsTitle":"REACTIONS",
|
||||||
"statsTitle":"STATS",
|
"statsTitle":"STATISTICS",
|
||||||
"emptyContent":"<content is empty>",
|
"emptyContent":"<content is empty>",
|
||||||
"noTitle":"<no-title>",
|
"noTitle":"<no-title>",
|
||||||
"noDesc":"<no-description>"
|
"noDesc":"<no-description>"
|
||||||
@@ -302,68 +302,68 @@
|
|||||||
"permissionError":"Permission Error"
|
"permissionError":"Permission Error"
|
||||||
},
|
},
|
||||||
"descriptions":{
|
"descriptions":{
|
||||||
"askForInfo":"Contact the owner of this bot for more info!",
|
"askForInfo":"Please contact the bot owner for more information.",
|
||||||
"askForInfoResolve":"Contact the bot owner of this bot if this issue doesn't resolve after a few tries.",
|
"askForInfoResolve":"If the issue persists after a few attempts, please contact the bot owner.",
|
||||||
"internalError":"Failed to respond to this {0} due to an internal error!",
|
"internalError":"An internal error occurred while processing this {0}.",
|
||||||
"optionMissing":"A required parameter is missing in this command!",
|
"optionMissing":"A required parameter is missing for this command.",
|
||||||
"optionInvalid":"A parameter in this command is invalid!",
|
"optionInvalid":"One or more parameters provided for this command are invalid.",
|
||||||
"optionInvalidChoose":"Choose between",
|
"optionInvalidChoose":"Please choose between",
|
||||||
"unknownCommand":"Try visiting the help menu for more info!",
|
"unknownCommand":"Please use the help menu for more information.",
|
||||||
"noPermissions":"You are not allowed to use this {0}!",
|
"noPermissions":"You are not permitted to use this {0}.",
|
||||||
"noPermissionsList":"Required Permissions: (one of them)",
|
"noPermissionsList":"Required permissions (one of the following):",
|
||||||
"noPermissionsCooldown":"You are not allowed to use this {0} because you have a cooldown!",
|
"noPermissionsCooldown":"You cannot use this {0} while on cooldown.",
|
||||||
"noPermissionsBlacklist":"You are not allowed to use this {0} because you have been blacklisted!",
|
"noPermissionsBlacklist":"You cannot use this {0} because you are blacklisted.",
|
||||||
"noPermissionsLimitGlobal":"You are not allowed to create a ticket because the server reached the max tickets limit!",
|
"noPermissionsLimitGlobal":"You cannot create a ticket because the server has reached its maximum ticket limit.",
|
||||||
"noPermissionsLimitGlobalUser":"You are not allowed to create a ticket because you reached the max tickets limit!",
|
"noPermissionsLimitGlobalUser":"You cannot create a ticket because you have reached your maximum ticket limit.",
|
||||||
"noPermissionsLimitOption":"You are not allowed to create a ticket because the server reached the max tickets limit for this option!",
|
"noPermissionsLimitOption":"You cannot create a ticket because the server has reached the maximum ticket limit for this option.",
|
||||||
"noPermissionsLimitOptionUser":"You are not allowed to create a ticket because you reached the max tickets limit for this option!",
|
"noPermissionsLimitOptionUser":"You cannot create a ticket because you have reached the maximum ticket limit for this option.",
|
||||||
"unknownTicket":"Try this command again in a valid ticket!",
|
"unknownTicket":"Please run this command inside a valid ticket channel.",
|
||||||
"deprecatedTicket":"The current channel is not a valid ticket! It might have been a ticket from an old Open Ticket version!",
|
"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} doesn't work in DM! Please try it again in a server!",
|
"notInGuild":"This {0} cannot be used in direct messages. Please use it 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.",
|
"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":"The source of this error is: {0}",
|
"channelRenameSource":"Error source: {0}",
|
||||||
"busy":"Unable to use this {0}!\nThe ticket is currently being processed by the bot.\n\nPlease try again in a few seconds!",
|
"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/deleted before a message has been sent by a user.",
|
"closeBeforeMessage":"This ticket cannot be closed or deleted before a user has sent a message.",
|
||||||
"closeBeforeAdminMessage":"This ticket cannot be closed/deleted before a message has been sent by a ticket admin or support member.",
|
"closeBeforeAdminMessage":"This ticket cannot be closed or deleted before a support member or admin has sent a message.",
|
||||||
"unableToCreateTicket":"You are unable to create a ticket."
|
"unableToCreateTicket":"You are currently unable to create a ticket."
|
||||||
},
|
},
|
||||||
"optionInvalidReasons":{
|
"optionInvalidReasons":{
|
||||||
"stringRegex":"Value doesn't match pattern!",
|
"stringRegex":"The value does not match the required pattern.",
|
||||||
"stringMinLength":"Value needs to be at least {0} characters!",
|
"stringMinLength":"The value must be at least {0} characters long.",
|
||||||
"stringMaxLength":"Value needs to be at most {0} characters!",
|
"stringMaxLength":"The value must be at most {0} characters long.",
|
||||||
"numberInvalid":"Invalid number!",
|
"numberInvalid":"Invalid number provided.",
|
||||||
"numberMin":"Number needs to be at least {0}!",
|
"numberMin":"The number must be at least {0}.",
|
||||||
"numberMax":"Number needs to be at most {0}!",
|
"numberMax":"The number must be at most {0}.",
|
||||||
"numberDecimal":"Number is not allowed to be a decimal!",
|
"numberDecimal":"Decimals are not allowed.",
|
||||||
"numberNegative":"Number is not allowed to be negative!",
|
"numberNegative":"Negative numbers are not allowed.",
|
||||||
"numberPositive":"Number is not allowed to be positive!",
|
"numberPositive":"Positive numbers are not allowed.",
|
||||||
"numberZero":"Number is not allowed to be zero!",
|
"numberZero":"Zero is not allowed.",
|
||||||
"channelNotFound":"Unable to find channel!",
|
"channelNotFound":"Channel not found.",
|
||||||
"userNotFound":"Unable to find user!",
|
"userNotFound":"User not found.",
|
||||||
"roleNotFound":"Unable to find role!",
|
"roleNotFound":"Role not found.",
|
||||||
"memberNotFound":"Unable to find user!",
|
"memberNotFound":"Member not found.",
|
||||||
"mentionableNotFound":"Unable to find user or role!",
|
"mentionableNotFound":"User or role not found.",
|
||||||
"channelType":"Invalid channel type!",
|
"channelType":"Invalid channel type.",
|
||||||
"notInGuild":"This option requires you to be in a server!"
|
"notInGuild":"This option can only be used in a server."
|
||||||
},
|
},
|
||||||
"permissions":{
|
"permissions":{
|
||||||
"developer":"You need to be the developer of the bot.",
|
"developer":"This action is restricted to the bot developer.",
|
||||||
"owner":"You need to be the server owner.",
|
"owner":"You must be the server owner to use this.",
|
||||||
"admin":"You need to be a server admin.",
|
"admin":"You must have administrator permissions to use this.",
|
||||||
"moderator":"You need to be a moderator.",
|
"moderator":"You must be a moderator to use this.",
|
||||||
"support":"You need to be in the support team.",
|
"support":"You must be part of the support team to use this.",
|
||||||
"member":"You need to be a member.",
|
"member":"You must be a server member to use this.",
|
||||||
"discord-administrator":"You need to have the `ADMINISTRATOR` permission."
|
"discord-administrator":"You must have the `ADMINISTRATOR` permission."
|
||||||
},
|
},
|
||||||
"actionInvalid":{
|
"actionInvalid":{
|
||||||
"close":"Ticket is already closed!",
|
"close":"This ticket is already closed.",
|
||||||
"reopen":"Ticket is not closed yet!",
|
"reopen":"This ticket is not closed.",
|
||||||
"claim":"Ticket is already claimed!",
|
"claim":"This ticket is already claimed.",
|
||||||
"unclaim":"Ticket is not claimed yet!",
|
"unclaim":"This ticket is not claimed.",
|
||||||
"pin":"Ticket is already pinned!",
|
"pin":"This ticket is already pinned.",
|
||||||
"unpin":"Ticket is not pinned yet!",
|
"unpin":"This ticket is not pinned.",
|
||||||
"add":"This user is already able to access the ticket!",
|
"add":"This user already has access to this ticket.",
|
||||||
"remove":"Unable to remove this user from the ticket!"
|
"remove":"This user does not have access to this ticket."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"params":{
|
"params":{
|
||||||
@@ -432,107 +432,107 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"commands":{
|
"commands":{
|
||||||
"reason":"Specify an optional reason that will be visible in logs.",
|
"reason":"Optional reason shown in logs.",
|
||||||
"help":"Get a list of all the available commands.",
|
"help":"Display all available commands.",
|
||||||
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
|
"panel":"Create a ticket panel (buttons or dropdown).",
|
||||||
"panelId":"The identifier of the panel that you want to spawn.",
|
"panelId":"ID of the panel to spawn.",
|
||||||
"panelAutoUpdate":"Do you want this panel to automatically update when edited?",
|
"panelAutoUpdate":"Automatically update this panel when edited.",
|
||||||
"ticket":"Instantly create a ticket.",
|
"ticket":"Create a ticket instantly.",
|
||||||
"ticketId":"The identifier of the ticket that you want to create.",
|
"ticketId":"ID of the ticket to create.",
|
||||||
"close":"Close a ticket.",
|
"close":"Close this ticket.",
|
||||||
"delete":"Delete a ticket.",
|
"delete":"Delete this ticket.",
|
||||||
"deleteNoTranscript":"Delete this ticket without creating a transcript.",
|
"deleteNoTranscript":"Delete ticket without saving a transcript.",
|
||||||
"reopen":"Reopen a ticket.",
|
"reopen":"Reopen a closed ticket.",
|
||||||
"claim":"Claim a ticket.",
|
"claim":"Claim this ticket.",
|
||||||
"claimUser":"Claim this ticket to someone else instead of yourself.",
|
"claimUser":"Claim the ticket for another user.",
|
||||||
"unclaim":"Unclaim a ticket.",
|
"unclaim":"Unclaim this ticket.",
|
||||||
"pin":"Pin a ticket.",
|
"pin":"Pin this ticket.",
|
||||||
"unpin":"Unpin a ticket.",
|
"unpin":"Unpin this ticket.",
|
||||||
|
|
||||||
"move":"Move a ticket.",
|
"move":"Move ticket to another option.",
|
||||||
"moveId":"The identifier of the option that you want to move to.",
|
"moveId":"Target option ID.",
|
||||||
"rename":"Rename a ticket.",
|
"rename":"Rename this ticket.",
|
||||||
"renameName":"The new name for this ticket.",
|
"renameName":"New name for the ticket.",
|
||||||
"add":"Add a user to a ticket.",
|
"add":"Add a user to this ticket.",
|
||||||
"addUser":"The user to add.",
|
"addUser":"User to add.",
|
||||||
"remove":"Remove a user from a ticket.",
|
"remove":"Remove a user from this ticket.",
|
||||||
"removeUser":"The user to remove.",
|
"removeUser":"User to remove.",
|
||||||
|
|
||||||
"blacklist":"Manage the ticket blacklist.",
|
"blacklist":"Manage the blacklist.",
|
||||||
"blacklistView":"View a list of the current blacklist.",
|
"blacklistView":"View all blacklisted users.",
|
||||||
"blacklistAdd":"Add a user to the blacklist.",
|
"blacklistAdd":"Add a user to the blacklist.",
|
||||||
"blacklistRemove":"Remove a user from the blacklist.",
|
"blacklistRemove":"Remove a user from the blacklist.",
|
||||||
"blacklistGet":"Get the details from a blacklisted user.",
|
"blacklistGet":"View blacklist entry details.",
|
||||||
"blacklistGetUser":"The user to get details from.",
|
"blacklistGetUser":"User to look up.",
|
||||||
"stats":"View statistics from the bot, a member or a ticket.",
|
"stats":"View bot, user or ticket statistics.",
|
||||||
"statsReset":"Reset all the stats of the bot (and start counting from zero).",
|
"statsReset":"Reset all bot statistics.",
|
||||||
"statsGlobal":"View the global stats.",
|
"statsGlobal":"View global bot statistics.",
|
||||||
"statsUser":"View the stats from a user in the server.",
|
"statsUser":"View a user's statistics.",
|
||||||
"statsUserUser":"The user to view.",
|
"statsUserUser":"User to view.",
|
||||||
"statsTicket":"View the stats of a ticket in the server.",
|
"statsTicket":"View ticket statistics.",
|
||||||
"statsTicketTicket":"The ticket to view.",
|
"statsTicketTicket":"Ticket to view.",
|
||||||
|
|
||||||
"clear":"Delete multiple tickets at the same time.",
|
"clear":"Delete multiple tickets at once.",
|
||||||
"clearFilter":"The filter for clearing tickets.",
|
"clearFilter":"Filter used when clearing tickets.",
|
||||||
"clearFilters":{
|
"clearFilters":{
|
||||||
"all":"All",
|
"all":"All tickets",
|
||||||
"open":"Open",
|
"open":"Open tickets",
|
||||||
"close":"Closed",
|
"close":"Closed tickets",
|
||||||
"claim":"Claimed",
|
"claim":"Claimed tickets",
|
||||||
"unclaim":"Unclaimed",
|
"unclaim":"Unclaimed tickets",
|
||||||
"pin":"Pinned",
|
"pin":"Pinned tickets",
|
||||||
"unpin":"Unpinned",
|
"unpin":"Unpinned tickets",
|
||||||
"autoclose":"Autoclosed"
|
"autoclose":"Autoclosed tickets"
|
||||||
},
|
},
|
||||||
|
|
||||||
"autoclose":"Manage autoclose in a ticket.",
|
"autoclose":"Manage ticket autoclose.",
|
||||||
"autocloseDisable":"Disable autoclose in this ticket.",
|
"autocloseDisable":"Disable autoclose.",
|
||||||
"autocloseEnable":"Enable autoclose in this ticket.",
|
"autocloseEnable":"Enable autoclose.",
|
||||||
"autocloseEnableTime":"The amount of hours this ticket needs to be inactive to close it.",
|
"autocloseEnableTime":"Hours of inactivity before closing.",
|
||||||
"autodelete":"Manage autodelete in a ticket.",
|
"autodelete":"Manage ticket autodelete.",
|
||||||
"autodeleteDisable":"Disable autodelete in this ticket.",
|
"autodeleteDisable":"Disable autodelete.",
|
||||||
"autodeleteEnable":"Enable autodelete in this ticket.",
|
"autodeleteEnable":"Enable autodelete.",
|
||||||
"autodeleteEnableTime":"The amount of days this ticket needs to be inactive to delete it.",
|
"autodeleteEnableTime":"Days of inactivity before deletion.",
|
||||||
|
|
||||||
"topic":"Manage the topic of the ticket channel.",
|
"topic":"Manage ticket channel topic.",
|
||||||
"topicSet":"Set the topic of the ticket channel.",
|
"topicSet":"Set the ticket channel topic.",
|
||||||
"topicValue":"The new topic of the channel.",
|
"topicValue":"New channel topic text.",
|
||||||
"topicList":"Get a list of all tickets with their topic and stats.",
|
"topicList":"List all ticket channel topics.",
|
||||||
"priority":"Manage the priority of the ticket.",
|
"priority":"Manage ticket priority.",
|
||||||
"prioritySet":"Set the priority of the ticket.",
|
"prioritySet":"Set ticket priority.",
|
||||||
"priorityValue":"The priority of the channel.",
|
"priorityValue":"Priority level.",
|
||||||
"priorityGet":"Get the priority of the ticket.",
|
"priorityGet":"View ticket priority.",
|
||||||
"priorityList":"Get a list of all tickets with their priority status.",
|
"priorityList":"List all ticket priorities.",
|
||||||
"transfer":"Transfer the ticket ownership from one user to another.",
|
"transfer":"Transfer ticket ownership.",
|
||||||
"transferUser":"The user to transfer to."
|
"transferUser":"User to transfer to."
|
||||||
},
|
},
|
||||||
"helpMenu":{
|
"helpMenu":{
|
||||||
"help":"Get a list of all the available commands.",
|
"help":"View all available commands.",
|
||||||
"ticket":"Instantly create a ticket.",
|
"ticket":"Create a ticket instantly.",
|
||||||
"close":"Close a ticket, this disables writing in this channel.",
|
"close":"Close this ticket and disable messaging in the channel.",
|
||||||
"delete":"Delete a ticket, this creates a transcript when enabled.",
|
"delete":"Delete this ticket (creates a transcript if enabled).",
|
||||||
"reopen":"Reopen a ticket, this enables writing in this channel again.",
|
"reopen":"Reopen a closed ticket and restore messaging.",
|
||||||
"pin":"Pin a ticket. This will move the ticket to the top and will add a '📌' emoij to the name.",
|
"pin":"Pin this ticket and move it to the top with '📌'.",
|
||||||
"unpin":"Unpin a ticket. The ticket will stay on it's position but will lose the '📌' emoij.",
|
"unpin":"Unpin this ticket and remove the '📌' emoji.",
|
||||||
"move":"Move a ticket. This will change the type of this ticket.",
|
"move":"Move this ticket to a different option or ticket type.",
|
||||||
"rename":"Rename a ticket. This will change the channel name of this ticket.",
|
"rename":"Rename this ticket channel.",
|
||||||
"claim":"Claim a ticket. With this, you can let your team know you are handling this ticket.",
|
"claim":"Claim this ticket to show you are handling it.",
|
||||||
"unclaim":"Unclaim a ticket. With this, you can let your team know that this ticket is free again.",
|
"unclaim":"Unclaim this ticket to mark it as available.",
|
||||||
"add":"Add a user to a ticket. This will allow the user to read & write in this ticket.",
|
"add":"Add a user to this ticket.",
|
||||||
"remove":"Remove a user from a ticket. This will remove the ability to read & write for a user in this ticket.",
|
"remove":"Remove a user's access from this ticket.",
|
||||||
"panel":"Spawn a message with a dropdown or buttons (for ticket creation).",
|
"panel":"Create a ticket panel with buttons or a dropdown.",
|
||||||
"blacklistView":"View a list of the current blacklist.",
|
"blacklistView":"View all blacklisted users.",
|
||||||
"blacklistAdd":"Add a user to the blacklist.",
|
"blacklistAdd":"Add a user to the blacklist.",
|
||||||
"blacklistRemove":"Remove a user from the blacklist.",
|
"blacklistRemove":"Remove a user from the blacklist.",
|
||||||
"blacklistGet":"Get the details from a blacklisted user.",
|
"blacklistGet":"View details of a blacklisted user.",
|
||||||
"statsGlobal":"View the global stats.",
|
"statsGlobal":"View global bot statistics.",
|
||||||
"statsTicket":"View the stats of a ticket in the server.",
|
"statsTicket":"View statistics for a ticket.",
|
||||||
"statsUser":"View the stats from a user in the server.",
|
"statsUser":"View statistics for a user.",
|
||||||
"statsReset":"Reset all the stats of the bot (and start counting from zero).",
|
"statsReset":"Reset all bot statistics.",
|
||||||
"autocloseDisable":"Disable autoclose in this ticket.",
|
"autocloseDisable":"Disable autoclose for this ticket.",
|
||||||
"autocloseEnable":"Enable autoclose in this ticket.",
|
"autocloseEnable":"Enable autoclose for this ticket.",
|
||||||
"autodeleteDisable":"Disable autodelete in this ticket.",
|
"autodeleteDisable":"Disable autodelete for this ticket.",
|
||||||
"autodeleteEnable":"Enable autodelete in this ticket.",
|
"autodeleteEnable":"Enable autodelete for this ticket.",
|
||||||
"categories":{
|
"categories":{
|
||||||
"general":"General Commands",
|
"general":"General Commands",
|
||||||
"basicTicket":"Basic Ticket Commands",
|
"basicTicket":"Basic Ticket Commands",
|
||||||
@@ -545,10 +545,10 @@
|
|||||||
},
|
},
|
||||||
"stats":{
|
"stats":{
|
||||||
"scopes":{
|
"scopes":{
|
||||||
"global":"Global Stats",
|
"global":"Global Statistics",
|
||||||
"system":"System Stats",
|
"system":"System Statistics",
|
||||||
"user":"User Stats",
|
"user":"User Statistics",
|
||||||
"ticket":"Ticket Stats",
|
"ticket":"Ticket Statistics",
|
||||||
"participants":"Participants",
|
"participants":"Participants",
|
||||||
"messages":"Messages"
|
"messages":"Messages"
|
||||||
},
|
},
|
||||||
@@ -592,9 +592,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"panel":{
|
"panel":{
|
||||||
"selectTicket":"Select your ticket",
|
"selectTicket":"Select a ticket",
|
||||||
"selectRole":"Select your role",
|
"selectRole":"Select a role",
|
||||||
"selectOption":"Select your option"
|
"selectOption":"Select an option"
|
||||||
},
|
},
|
||||||
"priorities":{
|
"priorities":{
|
||||||
"urgent":"Urgent",
|
"urgent":"Urgent",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["iamnotmega","ChatGPT"],
|
"translators":["iamnotmega","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Estonian",
|
"language":"Estonian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["iamnotmega","ChatGPT"],
|
"translators":["iamnotmega","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Finnish",
|
"language":"Finnish",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["guillee3"],
|
"translators":["guillee3"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"French",
|
"language":"French",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["benzorich"],
|
"translators":["benzorich"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"German",
|
"language":"German",
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
"typeInfo":"[INFO]",
|
"typeInfo":"[INFO]",
|
||||||
"headerConfigChecker":"CONFIG CHECKER",
|
"headerConfigChecker":"CONFIG CHECKER",
|
||||||
"headerDescription":"Prüfen Sie auf Fehler in Ihrer Konfigurationsdateien!",
|
"headerDescription":"Prüfen Sie auf Fehler in Ihrer Konfigurationsdateien!",
|
||||||
"footerError":"Der Bot wird nicht starten, bis alle {0}'s repariert sind!",
|
"footerError":"Der Bot wird nicht starten, bis alle {0}en repariert sind!",
|
||||||
"footerWarning":"Es wird empfohlen, vor dem Start alle {0}'s zu korrigieren!",
|
"footerWarning":"Es wird empfohlen, vor dem Start alle {0}en zu korrigieren!",
|
||||||
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
|
"footerSupport":"SUPPORT: {0} - DOCS: {1}",
|
||||||
"compactInformation":"Verwenden Sie {0} für weitere Informationen!",
|
"compactInformation":"Verwenden Sie {0} für weitere Informationen!",
|
||||||
"dataPath":"Pfad",
|
"dataPath":"Pfad",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Greek",
|
"language":"Greek",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["challenger_nova"],
|
"translators":["challenger_nova"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Hindi",
|
"language":"Hindi",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["Kornel0706"],
|
"translators":["Kornel0706"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Hungarian",
|
"language":"Hungarian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["erxg"],
|
"translators":["erxg"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Indonesian",
|
"language":"Indonesian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["fraden1mvp.","imperatorix_17"],
|
"translators":["fraden1mvp.","imperatorix_17"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Italian",
|
"language":"Italian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Japanese",
|
"language":"Japanese",
|
||||||
|
|||||||
@@ -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":"`<name>` => ប៉ារ៉ាម៉ែត្រចាំបាច់\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":"គ្មាន"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Korean",
|
"language":"Korean",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Kurdish",
|
"language":"Kurdish",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["NoOneNook"],
|
"translators":["NoOneNook"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Latvian",
|
"language":"Latvian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["TsgIndrius"],
|
"translators":["TsgIndrius"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Lithuanian",
|
"language":"Lithuanian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["NoOneNook"],
|
"translators":["NoOneNook"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Norwegian",
|
"language":"Norwegian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["dysashop","zhavis"],
|
"translators":["dysashop","zhavis"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Persian",
|
"language":"Persian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["DanoGlez"],
|
"translators":["DanoGlez"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Polish",
|
"language":"Polish",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["quiradon"],
|
"translators":["quiradon"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Portuguese",
|
"language":"Portuguese",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["SankeDev"],
|
"translators":["SankeDev"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Romanian",
|
"language":"Romanian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["NoOneNook"],
|
"translators":["NoOneNook"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Russian",
|
"language":"Russian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Simplified Chainese",
|
"language":"Simplified Chainese",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Solvenian",
|
"language":"Solvenian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["Redactado","Josuens"],
|
"translators":["Redactado","Josuens"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Spanish",
|
"language":"Spanish",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["NoOneNook"],
|
"translators":["NoOneNook"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Svenska",
|
"language":"Svenska",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["HanumeshGupta","ChatGPT"],
|
"translators":["HanumeshGupta","ChatGPT"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Tamil",
|
"language":"Tamil",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["modshd"],
|
"translators":["modshd"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Thai",
|
"language":"Thai",
|
||||||
|
|||||||
@@ -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":"無"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["palestinian"],
|
"translators":["palestinian"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Turkish",
|
"language":"Turkish",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["Anderskiy"],
|
"translators":["Anderskiy"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Ukrainian",
|
"language":"Ukrainian",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_TRANSLATION":{
|
"_TRANSLATION":{
|
||||||
"otversion":"v4.1.3",
|
"otversion":"v4.2.0",
|
||||||
"translators":["ngocdiep2006"],
|
"translators":["ngocdiep2006"],
|
||||||
"lastedited":"16/02/2026",
|
"lastedited":"16/02/2026",
|
||||||
"language":"Vietnamese",
|
"language":"Vietnamese",
|
||||||
|
|||||||
+11
-9
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "open-ticket",
|
"name": "open-ticket",
|
||||||
"author": "DJdj Development",
|
"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! ",
|
"description": "The most advanced open-source discord ticket bot with HTML transcripts, plugins, questions, claiming, pinning & more! Using discord.js v14 & JSON database! ",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"ticket-bot",
|
"ticket-bot",
|
||||||
@@ -19,20 +19,22 @@
|
|||||||
"test": "node index.js --dev-config --dev-database --soft-plugins",
|
"test": "node index.js --dev-config --dev-database --soft-plugins",
|
||||||
"testsetup": "node index.js --cli --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",
|
"testnc": "node index.js --no-compile --dev-config --dev-database --soft-plugins",
|
||||||
"docs": "npx typedoc --options .docs/typedoc-config.json && node .docs/createDocs.js",
|
"tools:mergelang": "bun run .tools/mergeTranslations.js",
|
||||||
"mergelang": "node .docs/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",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/rest": "^2.6.0",
|
"@discordjs/rest": "^2.6.1",
|
||||||
|
"@open-discord-bots/framework": "^0.5.2",
|
||||||
"@types/node": "^22.5.0",
|
"@types/node": "^22.5.0",
|
||||||
"@types/terminal-kit": "^2.5.7",
|
"@types/terminal-kit": "^2.5.7",
|
||||||
"ansis": "^4.2.0",
|
"ansis": "^4.2.0",
|
||||||
"discord.js": "^14.24.2",
|
"discord.js": "^14.26.4",
|
||||||
"formatted-json-stringify": "^1.2.1",
|
"formatted-json-stringify": "^1.3.2",
|
||||||
"terminal-kit": "^3.1.2",
|
"terminal-kit": "^3.1.2",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^6.0.3"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -45,7 +47,7 @@
|
|||||||
"homepage": "https://openticket.dj-dj.be",
|
"homepage": "https://openticket.dj-dj.be",
|
||||||
"imports": {
|
"imports": {
|
||||||
"#opendiscord": "./dist/src/index.js",
|
"#opendiscord": "./dist/src/index.js",
|
||||||
"#opendiscord-types": "./dist/src/core/api/api.js"
|
"#opendiscord-types": "./dist/src/core/api.js"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
|
|||||||
@@ -6,15 +6,15 @@ import * as discord from "discord.js"
|
|||||||
//// Enable it in the plugin.json file! ////
|
//// 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!!!)
|
//Add Typescript autocomplete support for plugin data. (!!!OPTIONAL!!!)
|
||||||
declare module "#opendiscord-types" {
|
declare module "#opendiscord-types" {
|
||||||
export interface ODPluginManagerIds_Default {
|
export interface ODPluginManagerIdMappings {
|
||||||
"example-plugin":api.ODPlugin
|
"example-plugin":api.ODPlugin
|
||||||
}
|
}
|
||||||
export interface ODConfigManagerIds_Default {
|
export interface ODConfigManagerIdMappings {
|
||||||
"example-plugin:config":api.ODJsonConfig
|
"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!
|
//Let's also log it to the console to let us know it worked!
|
||||||
const ourConfig = configManager.get("example-plugin:config")
|
const ourConfig = configManager.get("example-plugin:config")
|
||||||
opendiscord.log("The example config loaded successfully!","plugin",[
|
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-2",value:ourConfig.data.testVariable2.toString()},
|
||||||
{key:"var-3",value:ourConfig.data.testVariable3.toString()}
|
{key:"var-3",value:ourConfig.data.testVariable3.toString()}
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET ADD USER SYSTEM
|
//TICKET ADD USER SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:add-ticket-user"))
|
||||||
opendiscord.actions.get("opendiscord:add-ticket-user").workers.add([
|
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
|
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!")
|
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")
|
opendiscord.log("Failed to add channel permission overwrites on add-ticket-user","error")
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketUserAdded").emit([ticket,user,data,channel,reason])
|
await opendiscord.events.get("afterTicketUserAdded").emit([ticket,user,data,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason,data} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket,data} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" added "+data.displayName+" to a ticket!","info",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}
|
||||||
+38
-218
@@ -1,15 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET CLAIMING SYSTEM
|
//TICKET CLAIMING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:claim-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:claim-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to claim ticket! Open Ticket doesn't support threads!")
|
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
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-claimed",1,"increase")
|
await opendiscord.statistics.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:user").setStat("opendiscord:tickets-claimed",user.id,1,"increase")
|
||||||
|
|
||||||
//update category
|
//calculate & update category
|
||||||
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
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 categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("claim-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
|
||||||
const claimCategory = (rawClaimCategory) ? rawClaimCategory.category : null
|
if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
|
||||||
if (claimCategory){
|
const originalCategoryName = channel.parent?.name ?? "<unknown>"
|
||||||
|
const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
|
||||||
try{
|
try{
|
||||||
channel.setParent(claimCategory,{lockPermissions:false})
|
await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
|
||||||
ticket.get("opendiscord:category-mode").value = "claimed"
|
process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
|
||||||
ticket.get("opendiscord:category").value = claimCategory
|
})
|
||||||
}catch(e){
|
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
|
||||||
opendiscord.log("Unable to move ticket to 'claimed category'!","error",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{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
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketClaimed").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketClaimed").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" claimed a ticket!","info",[
|
opendiscord.log(user.displayName+" claimed a ticket!","info",[
|
||||||
@@ -91,7 +91,7 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
@@ -100,183 +100,3 @@ export const registerActions = async () => {
|
|||||||
params.ticket.get("opendiscord:busy").value = false
|
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}))
|
|
||||||
})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//CLEAR TICKETS SYSTEM
|
//CLEAR TICKETS SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:clear-tickets"))
|
||||||
opendiscord.actions.get("opendiscord:clear-tickets").workers.add([
|
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
|
const {guild,channel,user,filter,list} = params
|
||||||
|
|
||||||
await opendiscord.events.get("onTicketsClear").emit([list,user,channel,filter])
|
await opendiscord.events.get("onTicketsClear").emit([list,user,channel,filter])
|
||||||
@@ -43,21 +43,21 @@ export const registerActions = async () => {
|
|||||||
instance.list = nameList
|
instance.list = nameList
|
||||||
await opendiscord.events.get("afterTicketsCleared").emit([list,user,channel,filter])
|
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
|
const {guild,channel,user,filter,list} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
const {guild,user,filter,list} = params
|
||||||
opendiscord.log(user.displayName+" cleared "+list.length+" tickets!","info",[
|
opendiscord.log(user.displayName+" cleared "+list.length+" tickets!","info",[
|
||||||
{key:"user",value:user.username},
|
{key:"user",value:user.username},
|
||||||
{key:"userid",value:user.id,hidden:true},
|
{key:"userid",value:user.id,hidden:true},
|
||||||
{key:"method",value:source},
|
{key:"method",value:origin},
|
||||||
{key:"filter",value:filter}
|
{key:"filter",value:filter}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|||||||
+59
-207
@@ -1,16 +1,17 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET CLOSING SYSTEM
|
//TICKET CLOSING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
const lang = opendiscord.languages
|
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.add(new api.ODAction("opendiscord:close-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:close-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to close ticket! Open Ticket doesn't support threads!")
|
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-by").value = null
|
||||||
ticket.get("opendiscord:reopened-on").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:open").value = false
|
||||||
ticket.get("opendiscord:busy").value = true
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-closed",1,"increase")
|
await opendiscord.statistics.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:user").setStat("opendiscord:tickets-closed",user.id,1,"increase")
|
||||||
|
|
||||||
//update category
|
//calculate & update category
|
||||||
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
||||||
const closeCategory = ticket.option.get("opendiscord:channel-category-closed").value
|
const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("close-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
|
||||||
if (closeCategory !== ""){
|
if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
|
||||||
|
const originalCategoryName = channel.parent?.name ?? "<unknown>"
|
||||||
|
const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
|
||||||
try{
|
try{
|
||||||
channel.setParent(closeCategory,{lockPermissions:false})
|
await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
|
||||||
ticket.get("opendiscord:category-mode").value = "closed"
|
process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
|
||||||
ticket.get("opendiscord:category").value = closeCategory
|
})
|
||||||
}catch(e){
|
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
|
||||||
opendiscord.log("Unable to move ticket to 'closed category'!","error",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{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)
|
//update permissions (non-staff => readonly)
|
||||||
const permissions: discord.OverwriteResolvable[] = [{
|
const permissions: discord.OverwriteResolvable[] = [{
|
||||||
type:discord.OverwriteType.Role,
|
type:discord.OverwriteType.Role,
|
||||||
@@ -93,7 +118,7 @@ export const registerActions = async () => {
|
|||||||
ticket.get("opendiscord:participants").value.forEach((participant) => {
|
ticket.get("opendiscord:participants").value.forEach((participant) => {
|
||||||
//all participants that aren't roles/admins => readonly (OR non-viewable when enabled)
|
//all participants that aren't roles/admins => readonly (OR non-viewable when enabled)
|
||||||
if (participant.type == "user"){
|
if (participant.type == "user"){
|
||||||
if (generalConfig.data.system.removeParticipantsOnClose) permissions.push({
|
if (generalConfig.data.ticketSystem.removeParticipantsOnClose) permissions.push({
|
||||||
type:discord.OverwriteType.Member,
|
type:discord.OverwriteType.Member,
|
||||||
id:participant.id,
|
id:participant.id,
|
||||||
allow:[],
|
allow:[],
|
||||||
@@ -109,44 +134,39 @@ export const registerActions = async () => {
|
|||||||
})
|
})
|
||||||
channel.permissionOverwrites.set(permissions)
|
channel.permissionOverwrites.set(permissions)
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketClosed").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketClosed").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" closed a ticket!","info",[
|
opendiscord.log(user.displayName+" closed a ticket!","info",[
|
||||||
@@ -155,7 +175,7 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
@@ -164,171 +184,3 @@ export const registerActions = async () => {
|
|||||||
params.ticket.get("opendiscord:busy").value = false
|
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}))
|
|
||||||
})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
+50
-68
@@ -1,63 +1,36 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET CREATION SYSTEM
|
//TICKET CREATION SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
const lang = opendiscord.languages
|
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.add(new api.ODAction("opendiscord:create-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:create-ticket").workers.add([
|
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
|
const {guild,user,answers,option} = params
|
||||||
|
|
||||||
await opendiscord.events.get("onTicketCreate").emit([user])
|
await opendiscord.events.get("onTicketCreate").emit([user])
|
||||||
await opendiscord.events.get("onTicketChannelCreation").emit([option,user])
|
await opendiscord.events.get("onTicketChannelCreation").emit([option,user])
|
||||||
|
|
||||||
//get channel properties
|
//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 channelTopicText = option.get("opendiscord:channel-topic").value
|
||||||
const channelSuffix = await opendiscord.options.suffix.getSuffixFromOption(option,user,guild)
|
|
||||||
const channelName = channelPrefix+channelSuffix
|
|
||||||
|
|
||||||
//handle category
|
//calculate channel name
|
||||||
let category: string|null = null
|
const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("create-ticket",{guild,user,option,channel:null,ticket:null,currentChannelName:null})
|
||||||
let categoryMode: "backup"|"normal"|null = null
|
if (!channelNameResult) return opendiscord.log("Ticket Creation Error: Unable to calculate ticket name.","error")
|
||||||
if (channelCategory != ""){
|
const channelName = (channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined") ? channelNameResult.newChannelName : "ot-unnamed-ticket"
|
||||||
//category enabled
|
const channelSuffix = (typeof channelNameResult.newChannelSuffix !== "undefined") ? channelNameResult.newChannelSuffix : "unknown"
|
||||||
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
|
|
||||||
if (!normalCategory){
|
//calculate category
|
||||||
//default category was not found
|
const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("create-ticket",{guild,user,option,channel:null,ticket:null,currentCategoryId:null})
|
||||||
opendiscord.log("Ticket Creation Error: Unable to find category! #1","error",[
|
if (!categoryResult) return opendiscord.log("Ticket Creation Error: Unable to calculate ticket category.","error")
|
||||||
{key:"categoryid",value:channelCategory},
|
const ticketCategoryId = (categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined") ? categoryResult.newCategoryId : undefined
|
||||||
{key:"backup",value:"false"}
|
const ticketCategoryMode = (categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryMode !== "undefined") ? categoryResult.newCategoryMode : undefined
|
||||||
])
|
|
||||||
}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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//handle permissions
|
//handle permissions
|
||||||
const permissions: discord.OverwriteResolvable[] = [{
|
const permissions: discord.OverwriteResolvable[] = [{
|
||||||
@@ -118,15 +91,15 @@ export const registerActions = async () => {
|
|||||||
|
|
||||||
//handle channel topic
|
//handle channel topic
|
||||||
const channelTopics: string[] = []
|
const channelTopics: string[] = []
|
||||||
if (generalConfig.data.system.channelTopic.showOptionName) channelTopics.push(option.get("opendiscord:name").value)
|
if (generalConfig.data.ticketSystem.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.ticketSystem.channelTopic.showOptionDescription) channelTopics.push(option.get("opendiscord:description").value)
|
||||||
if (generalConfig.data.system.channelTopic.showOptionTopic) channelTopics.push(channelTopicText)
|
if (generalConfig.data.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.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
|
//create channel
|
||||||
const channel = await guild.channels.create({
|
const channel = await guild.channels.create({
|
||||||
@@ -134,7 +107,7 @@ export const registerActions = async () => {
|
|||||||
name:channelName,
|
name:channelName,
|
||||||
nsfw:false,
|
nsfw:false,
|
||||||
topic:(channelTopics.length > 0) ? channelTopics.join(" • ") : undefined,
|
topic:(channelTopics.length > 0) ? channelTopics.join(" • ") : undefined,
|
||||||
parent:category,
|
parent:ticketCategoryId,
|
||||||
reason:"Ticket Created By "+user.displayName,
|
reason:"Ticket Created By "+user.displayName,
|
||||||
permissionOverwrites:permissions,
|
permissionOverwrites:permissions,
|
||||||
rateLimitPerUser:slowMode
|
rateLimitPerUser:slowMode
|
||||||
@@ -148,6 +121,7 @@ export const registerActions = async () => {
|
|||||||
new api.ODTicketData("opendiscord:ticket-message",null),
|
new api.ODTicketData("opendiscord:ticket-message",null),
|
||||||
new api.ODTicketData("opendiscord:participants",participants),
|
new api.ODTicketData("opendiscord:participants",participants),
|
||||||
new api.ODTicketData("opendiscord:channel-suffix",channelSuffix),
|
new api.ODTicketData("opendiscord:channel-suffix",channelSuffix),
|
||||||
|
new api.ODTicketData("opendiscord:channel-renamed",null),
|
||||||
new api.ODTicketData("opendiscord:previous-creators",[]),
|
new api.ODTicketData("opendiscord:previous-creators",[]),
|
||||||
|
|
||||||
new api.ODTicketData("opendiscord:open",true),
|
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:pinned-on",null),
|
||||||
new api.ODTicketData("opendiscord:for-deletion",false),
|
new api.ODTicketData("opendiscord:for-deletion",false),
|
||||||
|
|
||||||
new api.ODTicketData("opendiscord:category",category),
|
new api.ODTicketData("opendiscord:category",ticketCategoryId ?? null),
|
||||||
new api.ODTicketData("opendiscord:category-mode",categoryMode),
|
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-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)),
|
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
|
//manage stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-created",1,"increase")
|
await opendiscord.statistics.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:user").setStat("opendiscord:tickets-created",user.id,1,"increase")
|
||||||
|
|
||||||
//manage bot permissions
|
//manage bot permissions
|
||||||
await opendiscord.events.get("onTicketPermissionsCreated").emit([option,opendiscord.permissions,channel,user])
|
await opendiscord.events.get("onTicketPermissionsCreated").emit([option,opendiscord.permissions,channel,user])
|
||||||
@@ -197,7 +171,7 @@ export const registerActions = async () => {
|
|||||||
instance.ticket = ticket
|
instance.ticket = ticket
|
||||||
opendiscord.tickets.add(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 {guild,user,answers,option} = params
|
||||||
const {ticket,channel} = instance
|
const {ticket,channel} = instance
|
||||||
|
|
||||||
@@ -207,17 +181,23 @@ export const registerActions = async () => {
|
|||||||
//check if ticket message is enabled
|
//check if ticket message is enabled
|
||||||
if (!option.get("opendiscord:ticket-message-enabled").value) return
|
if (!option.get("opendiscord:ticket-message-enabled").value) return
|
||||||
try {
|
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)
|
//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
|
//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){
|
}catch(err){
|
||||||
process.emit("uncaughtException",err)
|
process.emit("uncaughtException",err)
|
||||||
//something went wrong while sending the ticket message
|
//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])
|
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 {guild,user,answers,option} = params
|
||||||
const {ticket,channel} = instance
|
const {ticket,channel} = instance
|
||||||
|
|
||||||
|
if (!ticket || !channel) return opendiscord.log("Ticket Creation Error: Unable to send ticket message. Previous worker failed!","error")
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//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 {guild,user,answers,option} = params
|
||||||
const {ticket,channel} = instance
|
const {ticket,channel} = instance
|
||||||
|
|
||||||
@@ -249,7 +231,7 @@ export const registerActions = async () => {
|
|||||||
{key:"userid",value:user.id,hidden:true},
|
{key:"userid",value:user.id,hidden:true},
|
||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"method",value:source},
|
{key:"method",value:origin},
|
||||||
{key:"option",value:option.id.value}
|
{key:"option",value:option.id.value}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET CREATION SYSTEM
|
//TICKET CREATION SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.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.add(new api.ODAction("opendiscord:create-ticket-permissions"))
|
||||||
opendiscord.actions.get("opendiscord:create-ticket-permissions").workers.add([
|
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)){
|
if (!params.option.get("opendiscord:allow-blacklisted-users").value && opendiscord.blacklist.exists(params.user.id)){
|
||||||
instance.valid = false
|
instance.valid = false
|
||||||
instance.reason = "blacklist"
|
instance.reason = "blacklist"
|
||||||
@@ -19,7 +19,7 @@ export const registerActions = async () => {
|
|||||||
return cancel()
|
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)
|
const cooldown = opendiscord.cooldowns.get("opendiscord:option-cooldown_"+params.option.id.value)
|
||||||
if (cooldown && cooldown instanceof api.ODTimeoutCooldown && cooldown.use(params.user.id)){
|
if (cooldown && cooldown instanceof api.ODTimeoutCooldown && cooldown.use(params.user.id)){
|
||||||
instance.valid = false
|
instance.valid = false
|
||||||
@@ -36,16 +36,16 @@ export const registerActions = async () => {
|
|||||||
return cancel()
|
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")
|
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 allTickets = opendiscord.tickets.getAll()
|
||||||
const globalTicketCount = allTickets.length
|
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 userTickets = opendiscord.tickets.getFiltered((ticket) => ticket.exists("opendiscord:opened-by") && (ticket.get("opendiscord:opened-by").value == params.user.id))
|
||||||
const userTicketCount = userTickets.length
|
const userTicketCount = userTickets.length
|
||||||
|
|
||||||
if (globalTicketCount >= generalConfig.data.system.limits.globalMaximum){
|
if (globalTicketCount >= generalConfig.data.ticketSystem.limits.globalMaximum){
|
||||||
instance.valid = false
|
instance.valid = false
|
||||||
instance.reason = "global-limit"
|
instance.reason = "global-limit"
|
||||||
opendiscord.log(params.user.displayName+" tried to create a ticket but reached the limit!","info",[
|
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"}
|
{key:"limit",value:"global"}
|
||||||
])
|
])
|
||||||
return cancel()
|
return cancel()
|
||||||
}else if (userTicketCount >= generalConfig.data.system.limits.userMaximum){
|
}else if (userTicketCount >= generalConfig.data.ticketSystem.limits.userMaximum){
|
||||||
instance.valid = false
|
instance.valid = false
|
||||||
instance.reason = "global-user-limit"
|
instance.reason = "global-user-limit"
|
||||||
opendiscord.log(params.user.displayName+" tried to create a ticket, but reached the limit!","info",[
|
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()
|
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
|
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)
|
const allTickets = opendiscord.tickets.getFiltered((ticket) => ticket.option.id.value == params.option.id.value)
|
||||||
@@ -97,7 +97,7 @@ export const registerActions = async () => {
|
|||||||
return cancel()
|
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.valid = true
|
||||||
instance.reason = null
|
instance.reason = null
|
||||||
cancel()
|
cancel()
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TRANSCRIPT CREATION SYSTEM
|
//TRANSCRIPT CREATION SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const transcriptConfig = opendiscord.configs.get("opendiscord:transcripts")
|
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.add(new api.ODAction("opendiscord:create-transcript"))
|
||||||
opendiscord.actions.get("opendiscord:create-transcript").workers.add([
|
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
|
const {channel,user,ticket} = params
|
||||||
if (channel.type != discord.ChannelType.GuildText) return cancel()
|
if (channel.type != discord.ChannelType.GuildText) return cancel()
|
||||||
if (!transcriptConfig.data.general.enabled) 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")
|
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")
|
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
|
const {channel,user,ticket} = params
|
||||||
if (channel.type != discord.ChannelType.GuildText) return cancel()
|
if (channel.type != discord.ChannelType.GuildText) return cancel()
|
||||||
if (!transcriptConfig.data.general.enabled) 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()
|
//run transcript compiler init()
|
||||||
await opendiscord.events.get("onTranscriptInit").emit([opendiscord.transcripts,ticket,channel,user])
|
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])
|
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
|
const {channel,user,ticket} = params
|
||||||
if (channel.type != discord.ChannelType.GuildText) return cancel()
|
if (channel.type != discord.ChannelType.GuildText) return cancel()
|
||||||
if (!instance.compiler){
|
if (!instance.compiler){
|
||||||
@@ -71,6 +76,11 @@ export const registerActions = async () => {
|
|||||||
cancel()
|
cancel()
|
||||||
throw new api.ODSystemError("ODAction(ot:create-transcript):ODWorker(ot:compile-transcript) => Instance is missing transcript compiler!")
|
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()
|
//run transcript compiler compile()
|
||||||
await opendiscord.events.get("onTranscriptCompile").emit([opendiscord.transcripts,ticket,channel,user])
|
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])
|
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){
|
if (!instance.result){
|
||||||
instance.success = false
|
instance.success = false
|
||||||
cancel()
|
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()
|
//run transcript compiler ready()
|
||||||
utilities.runAsync(async () => {
|
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])
|
await opendiscord.events.get("onTranscriptReady").emit([opendiscord.transcripts,instance.result.ticket,instance.result.channel,instance.result.user])
|
||||||
if (instance.compiler.ready){
|
if (instance.compiler.ready){
|
||||||
try{
|
try{
|
||||||
@@ -109,9 +135,9 @@ export const registerActions = async () => {
|
|||||||
|
|
||||||
//send channel message
|
//send channel message
|
||||||
if (transcriptConfig.data.general.enableChannel && channelMessage){
|
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
|
//edit "pending" message to be the "ready" message
|
||||||
instance.pendingMessage.message.edit(channelMessage.message)
|
instance.pendingMessage.message.edit(utilities.getMessageFromBuildResult(channelMessage,"message"))
|
||||||
}else{
|
}else{
|
||||||
//send ready message to channel
|
//send ready message to channel
|
||||||
const post = opendiscord.posts.get("opendiscord:transcripts")
|
const post = opendiscord.posts.get("opendiscord:transcripts")
|
||||||
@@ -149,11 +175,11 @@ export const registerActions = async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:transcripts-created",1,"increase")
|
await opendiscord.statistics.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: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])
|
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
|
const {user,channel,ticket} = params
|
||||||
opendiscord.log(user.displayName+" created a transcript!","info",[
|
opendiscord.log(user.displayName+" created a transcript!","info",[
|
||||||
{key:"user",value:user.username},
|
{key:"user",value:user.username},
|
||||||
@@ -161,8 +187,8 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"option",value:ticket.option.id.value},
|
{key:"option",value:ticket.option.id.value},
|
||||||
{key:"method",value:source,hidden:true},
|
{key:"method",value:origin,hidden:true},
|
||||||
{key:"compiler",value:instance.compiler.id.value},
|
{key:"compiler",value:instance.compiler?.id.value ?? "<unknown-compiler>"},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
+17
-383
@@ -1,16 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET DELETION SYSTEM
|
//TICKET DELETION SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
const lang = opendiscord.languages
|
const lang = opendiscord.languages
|
||||||
|
|
||||||
export const registerActions = async () => {
|
export async function registerActions(){
|
||||||
opendiscord.actions.add(new api.ODAction("opendiscord:delete-ticket"))
|
opendiscord.actions.add(new api.ODAction("opendiscord:delete-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:delete-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to delete ticket! Open Ticket doesn't support threads!")
|
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:for-deletion").value = true
|
||||||
ticket.get("opendiscord:busy").value = true
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
//create transcript
|
||||||
if (!params.withoutTranscript){
|
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
|
//transcript failure
|
||||||
if (typeof transcriptRes.success == "boolean" && !transcriptRes.success && transcriptRes.compiler){
|
if (typeof transcriptRes.success == "boolean" && !transcriptRes.success && transcriptRes.compiler){
|
||||||
const {compiler} = transcriptRes
|
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}]))
|
.catch((reason) => opendiscord.log("Unable to send transcript failure to ticket channel!","error",[{key:"id",value:channel.id}]))
|
||||||
|
|
||||||
//undo deletion
|
//undo deletion
|
||||||
@@ -59,8 +46,8 @@ export const registerActions = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-deleted",1,"increase")
|
await opendiscord.statistics.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:user").setStat("opendiscord:tickets-deleted",user.id,1,"increase")
|
||||||
|
|
||||||
//delete ticket from manager
|
//delete ticket from manager
|
||||||
opendiscord.tickets.remove(ticket.id)
|
opendiscord.tickets.remove(ticket.id)
|
||||||
@@ -68,21 +55,21 @@ export const registerActions = async () => {
|
|||||||
//delete permissions from manager
|
//delete permissions from manager
|
||||||
await (await import("../data/framework/permissionLoader.js")).removeTicketPermissions(ticket)
|
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
|
//logs before channel deletion => channel might still be used in log embeds
|
||||||
const {guild,channel,user,ticket,reason} = params
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
//delete channel & events
|
//delete channel & events
|
||||||
await opendiscord.events.get("onTicketChannelDeletion").emit([ticket,channel,user])
|
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])
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" deleted a ticket!","info",[
|
opendiscord.log(user.displayName+" deleted a ticket!","info",[
|
||||||
@@ -103,7 +90,7 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source},
|
{key:"method",value:origin},
|
||||||
{key:"transcript",value:(!params.withoutTranscript).toString()},
|
{key:"transcript",value:(!params.withoutTranscript).toString()},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@@ -114,356 +101,3 @@ export const registerActions = async () => {
|
|||||||
params.ticket.get("opendiscord:for-deletion").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}))
|
|
||||||
})
|
|
||||||
])
|
|
||||||
}
|
|
||||||
@@ -1,76 +1,43 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TRANSCRIPT ERROR SYSTEM
|
//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")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
|
|
||||||
export const registerButtonResponders = async () => {
|
export async function registerButtonResponders(){
|
||||||
//TRANSCRIPT ERROR RETRY
|
//TRANSCRIPT ERROR RETRY
|
||||||
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-retry",/^od: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([
|
opendiscord.responders.buttons.get("opendiscord:transcript-error-retry").workers.add([
|
||||||
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
|
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,cancel) => {
|
||||||
const permissionMode = generalConfig.data.system.permissions.delete
|
const {guild,channel,user,member} = instance
|
||||||
|
|
||||||
if (permissionMode == "none"){
|
//responder checks
|
||||||
//no permissions
|
const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
|
||||||
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]}))
|
if (!hasPerms) return cancel()
|
||||||
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"]
|
|
||||||
|
|
||||||
if (!guild){
|
const isInGuild = await openticketUtils.replyIsInGuild(instance,origin)
|
||||||
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
|
if (!isInGuild || !guild || channel.isDMBased()) return cancel()
|
||||||
return cancel()
|
|
||||||
}
|
const ticket = await openticketUtils.replyIsTicket(instance,origin)
|
||||||
const ticket = opendiscord.tickets.get(channel.id)
|
if (!ticket) return cancel()
|
||||||
if (!ticket || channel.isDMBased()){
|
|
||||||
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user}))
|
const isAvailable = await openticketUtils.replyTicketIsAvailable(instance,origin,ticket)
|
||||||
return cancel()
|
if (!isAvailable) return cancel()
|
||||||
}
|
|
||||||
//return when busy
|
//fetch data
|
||||||
if (ticket.get("opendiscord:busy").value){
|
const originalOrigin = instance.interaction.customId.split("_")[1] as api.ODActionManagerIdMappings["opendiscord:delete-ticket"]["origin"]
|
||||||
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user}))
|
|
||||||
return cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
//start deleting ticket (without reason)
|
//start deleting ticket (without reason)
|
||||||
await instance.defer("update",false)
|
await instance.defer("update",false)
|
||||||
//don't await DELETE action => else it will update the message after the channel has been deleted
|
//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})
|
opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{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
|
|
||||||
await instance.update(await opendiscord.builders.messages.getSafe("opendiscord:delete-message").build("other",{guild,channel,user,ticket,reason:"Transcript Error (Retried)"}))
|
|
||||||
|
|
||||||
|
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
|
const {user,channel} = instance
|
||||||
if (channel.isDMBased()) return
|
if (channel.isDMBased()) return
|
||||||
opendiscord.log(user.displayName+" retried deleting a ticket with transcript!","info",[
|
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:"userid",value:user.id,hidden:true},
|
||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{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
|
//TRANSCRIPT ERROR CONTINUE
|
||||||
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:transcript-error-continue",/^od: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([
|
opendiscord.responders.buttons.get("opendiscord:transcript-error-continue").workers.add([
|
||||||
new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => {
|
new api.ODWorker("opendiscord:delete-ticket",0,async (instance,params,origin,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 {guild,channel,user} = instance
|
||||||
const originalSource = instance.interaction.customId.split("_")[1] as api.ODActionManagerIds_Default["opendiscord:delete-ticket"]["source"]
|
|
||||||
|
|
||||||
if (!guild){
|
//responder checks
|
||||||
instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user}))
|
const hasPerms = await openticketUtils.replyHasPermissions(instance,origin,"delete")
|
||||||
return cancel()
|
if (!hasPerms) 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
//start deleting ticket (without reason)
|
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 & without transcript)
|
||||||
await instance.defer("update",false)
|
await instance.defer("update",false)
|
||||||
//don't await DELETE action => else it will update the message after the channel has been deleted
|
//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})
|
opendiscord.actions.get("opendiscord:delete-ticket").run(originalOrigin,{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
|
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)"}))
|
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
|
const {user,channel} = instance
|
||||||
if (channel.isDMBased()) return
|
if (channel.isDMBased()) return
|
||||||
opendiscord.log(user.displayName+" continued deleting a ticket without transcript!","info",[
|
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:"userid",value:user.id,hidden:true},
|
||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -1,32 +1,22 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//VERIFYBAR SYSTEM
|
//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 () => {
|
export async function registerButtonResponders(){
|
||||||
//VERIFYBAR SUCCESS
|
//HANDLE VERIFYBAR BUTTON
|
||||||
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-success",/^od:verifybar-success_([^_]+)/))
|
opendiscord.responders.buttons.add(new api.ODButtonResponder("opendiscord:verifybar-button",/^od:verifybar\|([^|]+)\|([^|]+)/))
|
||||||
opendiscord.responders.buttons.get("opendiscord:verifybar-success").workers.add(
|
opendiscord.responders.buttons.get("opendiscord:verifybar-button").workers.add(
|
||||||
new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,source,cancel) => {
|
new api.ODWorker("opendiscord:handle-verifybar",0,async (instance,params,origin,cancel) => {
|
||||||
const id = instance.interaction.customId.split("_")[1]
|
const match = /^od:verifybar\|([^|]+)\|([^|]+)/.exec(instance.interaction.customId)
|
||||||
const customData = instance.interaction.customId.split("_")[2] as string|undefined
|
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) return
|
||||||
if (verifybar.success) await verifybar.success.executeWorkers(instance,"verifybar",{data:customData ?? null,verifybarMessage:instance.message})
|
await verifybar.activate(instance,verifyButtonId)
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
//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})
|
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+40
-95
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET MOVING SYSTEM
|
//TICKET MOVING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:move-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:move-ticket").workers.add([
|
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
|
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!")
|
if (channel.isThread()) throw new api.ODSystemError("Unable to move ticket! Open Ticket doesn't support threads!")
|
||||||
|
|
||||||
@@ -17,76 +17,29 @@ export const registerActions = async () => {
|
|||||||
ticket.option = data
|
ticket.option = data
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-moved",1,"increase")
|
await opendiscord.statistics.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: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"}
|
|
||||||
])
|
|
||||||
}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"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
//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 ?? "<unknown>"
|
||||||
|
const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
|
||||||
try{
|
try{
|
||||||
//only move category when not the same.
|
await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
|
||||||
if (channel.parentId != category) await utilities.timedAwait(channel.setParent(category,{lockPermissions:false}),2500,(err) => {
|
process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
|
||||||
opendiscord.log("Failed to change channel category on ticket move","error")
|
|
||||||
})
|
})
|
||||||
ticket.get("opendiscord:category-mode").value = categoryMode
|
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
|
||||||
ticket.get("opendiscord:category").value = category
|
ticket.get("opendiscord:category").value = categoryResult.newCategoryId
|
||||||
}catch(e){
|
}catch(err){
|
||||||
opendiscord.log("Unable to move ticket to 'moved category'!","error",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"categoryid",value:category ?? "/"}
|
{key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
|
||||||
])
|
])
|
||||||
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//handle permissions
|
//handle permissions
|
||||||
@@ -153,58 +106,50 @@ export const registerActions = async () => {
|
|||||||
ticket.get("opendiscord:participants").value = participants
|
ticket.get("opendiscord:participants").value = participants
|
||||||
ticket.get("opendiscord:participants").refreshDatabase()
|
ticket.get("opendiscord:participants").refreshDatabase()
|
||||||
|
|
||||||
//rename channel (and give error when crashed)
|
//calculate channel name
|
||||||
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
|
const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("move-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
|
||||||
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
|
if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
|
||||||
|
|
||||||
const originalName = channel.name
|
const originalName = channel.name
|
||||||
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channelPrefix+channelSuffix)
|
const newName = channelNameResult.newChannelName
|
||||||
try{
|
try{
|
||||||
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
||||||
opendiscord.log("Failed to rename channel on ticket move","error")
|
opendiscord.log("Failed to rename channel on ticket move","error")
|
||||||
})
|
})
|
||||||
}catch(err){
|
}catch(err){
|
||||||
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-move",{guild,channel,user,originalName,newName:newName})).message)
|
opendiscord.log("Unable to rename channel while moving 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-move",{guild,channel,user,originalName,newName})).message)
|
||||||
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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 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}
|
|
||||||
])
|
|
||||||
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketMoved").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketMoved").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason,data} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" moved a ticket!","info",[
|
opendiscord.log(user.displayName+" moved a ticket!","info",[
|
||||||
@@ -213,7 +158,7 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
+34
-217
@@ -1,15 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET PINNING SYSTEM
|
//TICKET PINNING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:pin-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:pin-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to pin ticket! Open Ticket doesn't support threads!")
|
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
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-pinned",1,"increase")
|
await opendiscord.statistics.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:user").setStat("opendiscord:tickets-pinned",user.id,1,"increase")
|
||||||
|
|
||||||
//move to top of category
|
//move to top of category
|
||||||
if (channel.parent){
|
if (channel.parent){
|
||||||
await channel.setPosition(0,{reason:"Ticket Pinned!"})
|
await channel.setPosition(0,{reason:"Ticket Pinned!"})
|
||||||
}
|
}
|
||||||
|
|
||||||
//rename channel (and give error when crashed)
|
//calculate channel name
|
||||||
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
|
const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("pin-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
|
||||||
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
|
if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
|
||||||
|
|
||||||
const originalName = channel.name
|
const originalName = channel.name
|
||||||
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
|
const newName = channelNameResult.newChannelName
|
||||||
try{
|
try{
|
||||||
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
||||||
opendiscord.log("Failed to rename channel on ticket pin","error")
|
opendiscord.log("Failed to rename channel on ticket pin","error")
|
||||||
})
|
})
|
||||||
}catch(err){
|
}catch(err){
|
||||||
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-pin",{guild,channel,user,originalName,newName})).message)
|
opendiscord.log("Unable to rename channel while pinning 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-pin",{guild,channel,user,originalName,newName})).message)
|
||||||
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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 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}
|
|
||||||
])
|
|
||||||
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketPinned").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketPinned").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" pinned a ticket!","info",[
|
opendiscord.log(user.displayName+" pinned a ticket!","info",[
|
||||||
@@ -90,192 +91,8 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//REACTION ROLE SYSTEM
|
//REACTION ROLE SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:reaction-role"))
|
||||||
opendiscord.actions.get("opendiscord:reaction-role").workers.add([
|
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 {guild,user,option,overwriteMode} = params
|
||||||
const role = opendiscord.roles.get(option.id)
|
const role = opendiscord.roles.get(option.id)
|
||||||
if (!role) throw new api.ODSystemError("ODAction(ot:reaction-role) => Unknown reaction role (ODRole)")
|
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
|
instance.result = result
|
||||||
await opendiscord.events.get("afterRolesUpdated").emit([user,role])
|
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
|
const {guild,user,option,overwriteMode} = params
|
||||||
if (!instance.role || !instance.result) return
|
if (!instance.role || !instance.result) return
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//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
|
const {guild,user,option} = params
|
||||||
opendiscord.log(user.displayName+" updated his roles!","info",[
|
opendiscord.log(user.displayName+" updated his roles!","info",[
|
||||||
{key:"user",value:user.username},
|
{key:"user",value:user.username},
|
||||||
{key:"userid",value:user.id,hidden:true},
|
{key:"userid",value:user.id,hidden:true},
|
||||||
{key:"method",value:source},
|
{key:"method",value:origin},
|
||||||
{key:"option",value:option.id.value}
|
{key:"option",value:option.id.value}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET REMOVE USER SYSTEM
|
//TICKET REMOVE USER SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:remove-ticket-user"))
|
||||||
opendiscord.actions.get("opendiscord:remove-ticket-user").workers.add([
|
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
|
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!")
|
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")
|
opendiscord.log("Failed to remove channel permission overwrites on remove-ticket-user","error")
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketUserRemoved").emit([ticket,user,data,channel,reason])
|
await opendiscord.events.get("afterTicketUserRemoved").emit([ticket,user,data,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason,data} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket,data} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" removed "+data.displayName+" from a ticket!","info",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
+25
-30
@@ -1,72 +1,67 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET RENAMING SYSTEM
|
//TICKET RENAMING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:rename-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:rename-ticket").workers.add([
|
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
|
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!")
|
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])
|
await opendiscord.events.get("onTicketRename").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//rename channel (and give error when crashed)
|
//update ticket
|
||||||
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
|
ticket.get("opendiscord:channel-renamed").value = data
|
||||||
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
|
|
||||||
|
|
||||||
|
//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 originalName = channel.name
|
||||||
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(data)
|
const newName = channelNameResult.newChannelName
|
||||||
try{
|
try{
|
||||||
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
||||||
opendiscord.log("Failed to rename channel on ticket rename","error")
|
opendiscord.log("Failed to rename channel on ticket rename","error")
|
||||||
})
|
})
|
||||||
}catch(err){
|
}catch(err){
|
||||||
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-rename",{guild,channel,user,originalName,newName:data})).message)
|
opendiscord.log("Unable to rename channel while renaming 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-rename",{guild,channel,user,originalName,newName})).message)
|
||||||
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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 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}
|
|
||||||
])
|
|
||||||
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketRenamed").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketRenamed").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason,data} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" renamed a ticket!","info",[
|
opendiscord.log(user.displayName+" renamed a ticket!","info",[
|
||||||
@@ -75,7 +70,7 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
+58
-343
@@ -1,15 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET REOPENING SYSTEM
|
//TICKET REOPENING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:reopen-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:reopen-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to reopen ticket! Open Ticket doesn't support threads!")
|
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:open").value = true
|
||||||
ticket.get("opendiscord:busy").value = true
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
if (generalConfig.data.system.disableAutocloseAfterReopen){
|
if (generalConfig.data.ticketSystem.disableAutocloseAfterReopen){
|
||||||
//disable autoclose after reopen
|
//disable autoclose after reopen
|
||||||
ticket.get("opendiscord:autoclose-enabled").value = false
|
ticket.get("opendiscord:autoclose-enabled").value = false
|
||||||
ticket.get("opendiscord:autoclose-hours").value = 0
|
ticket.get("opendiscord:autoclose-hours").value = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
//update stats
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-reopened",1,"increase")
|
await opendiscord.statistics.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:user").setStat("opendiscord:tickets-reopened",user.id,1,"increase")
|
||||||
|
|
||||||
//update category
|
//calculate & update category
|
||||||
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
||||||
const channelCategory = ticket.option.get("opendiscord:channel-category").value
|
const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("reopen-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
|
||||||
const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value
|
if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
|
||||||
if (channelCategory !== ""){
|
const originalCategoryName = channel.parent?.name ?? "<unknown>"
|
||||||
//category enabled
|
const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
|
||||||
try{
|
try{
|
||||||
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
|
await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
|
||||||
if (!normalCategory){
|
process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
|
||||||
//default category was not found
|
})
|
||||||
opendiscord.log("Ticket Reopening Error: Unable to find category! #1","error",[
|
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
|
||||||
{key:"categoryid",value:channelCategory},
|
ticket.get("opendiscord:category").value = categoryResult.newCategoryId
|
||||||
{key:"backup",value:"false"}
|
}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)
|
||||||
}else{
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
//default category was found
|
opendiscord.log("Unable to move ticket to reopened category.","error",[
|
||||||
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",[
|
|
||||||
{key:"channel",value:"#"+channel.name},
|
{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
|
//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)
|
channel.permissionOverwrites.set(permissions)
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketReopened").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketReopened").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" reopened a ticket!","info",[
|
opendiscord.log(user.displayName+" reopened a ticket!","info",[
|
||||||
@@ -186,280 +173,8 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET TRANSFER SYSTEM
|
//TICKET TRANSFER SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:transfer-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:transfer-ticket").workers.add([
|
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
|
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!")
|
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
|
//update stats
|
||||||
await opendiscord.stats.get("opendiscord:global").setStat("opendiscord:tickets-transferred",1,"increase")
|
await opendiscord.statistics.get("opendiscord:global").setStat("opendiscord:tickets-transferred",1,"increase")
|
||||||
await opendiscord.stats.get("opendiscord:user").setStat("opendiscord:tickets-transferred",user.id,1,"increase")
|
await opendiscord.statistics.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
|
|
||||||
|
|
||||||
//handle permissions
|
//handle permissions
|
||||||
const permissions: discord.OverwriteResolvable[] = [{
|
const permissions: discord.OverwriteResolvable[] = [{
|
||||||
@@ -93,48 +89,40 @@ export const registerActions = async () => {
|
|||||||
opendiscord.log("Failed to reset channel permissions on ticket transfer!","error")
|
opendiscord.log("Failed to reset channel permissions on ticket transfer!","error")
|
||||||
}
|
}
|
||||||
|
|
||||||
//rename channel (and give error when crashed)
|
//calculate channel name
|
||||||
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
|
const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("transfer-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
|
||||||
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
|
if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
|
||||||
|
|
||||||
const originalName = channel.name
|
const originalName = channel.name
|
||||||
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channelPrefix+channelSuffix)
|
const newName = channelNameResult.newChannelName
|
||||||
try{
|
try{
|
||||||
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
||||||
opendiscord.log("Failed to rename channel on ticket transfer","error")
|
opendiscord.log("Failed to rename channel on ticket transfer","error")
|
||||||
})
|
})
|
||||||
}catch(err){
|
}catch(err){
|
||||||
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-transfer",{guild,channel,user,originalName,newName:newName})).message)
|
opendiscord.log("Unable to rename channel while transferring 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-transfer",{guild,channel,user,originalName,newName})).message)
|
||||||
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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 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}
|
|
||||||
])
|
|
||||||
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketTransferred").emit([ticket,user,channel,oldCreator,newCreator,reason])
|
await opendiscord.events.get("afterTicketTransferred").emit([ticket,user,channel,oldCreator,newCreator,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
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
|
const {guild,channel,user,ticket,newCreator} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" transferred a ticket to '"+newCreator.displayName+"'!","info",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{key:"reason",value:params.reason ?? "/"},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
+38
-255
@@ -1,15 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET UNCLAIMING SYSTEM
|
//TICKET UNCLAIMING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:unclaim-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:unclaim-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to unclaim ticket! Open Ticket doesn't support threads!")
|
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:claimed-on").value = null
|
||||||
ticket.get("opendiscord:busy").value = true
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
//update category
|
//calculate & update category
|
||||||
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
if (typeof params.allowCategoryChange == "boolean" ? params.allowCategoryChange : true){
|
||||||
const channelCategory = ticket.option.get("opendiscord:channel-category").value
|
const categoryResult = await opendiscord.actions.get("opendiscord:calculate-ticket-category").run("unclaim-ticket",{guild,user,option:ticket.option,channel,ticket,currentCategoryId:channel.parentId})
|
||||||
const channelBackupCategory = ticket.option.get("opendiscord:channel-category-backup").value
|
if (categoryResult && categoryResult.shouldChangeCategory && typeof categoryResult.newCategoryId !== "undefined" && typeof categoryResult.newCategoryMode !== "undefined" && typeof categoryResult.newCategory !== "undefined"){
|
||||||
if (channelCategory !== ""){
|
const originalCategoryName = channel.parent?.name ?? "<unknown>"
|
||||||
//category enabled
|
const newCategoryName = categoryResult.newCategory?.name ?? "<unknown>"
|
||||||
try{
|
try{
|
||||||
const normalCategory = await opendiscord.client.fetchGuildCategoryChannel(guild,channelCategory)
|
await utilities.timedAwait(channel.setParent(categoryResult.newCategoryId,{lockPermissions:false}),3000,(err) => {
|
||||||
if (!normalCategory){
|
process.emit("uncaughtException",new Error("Error: Unable to change channel parent: "+err))
|
||||||
//default category was not found
|
})
|
||||||
opendiscord.log("Ticket Unclaiming Error: Unable to find category! #1","error",[
|
ticket.get("opendiscord:category-mode").value = categoryResult.newCategoryMode
|
||||||
{key:"categoryid",value:channelCategory},
|
ticket.get("opendiscord:category").value = categoryResult.newCategoryId
|
||||||
{key:"backup",value:"false"}
|
}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)
|
||||||
}else{
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
//default category was found
|
opendiscord.log("Unable to move ticket to unclaimed category.","error",[
|
||||||
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",[
|
|
||||||
{key:"channel",value:"#"+channel.name},
|
|
||||||
{key:"channelid",value:channel.id,hidden:true}
|
|
||||||
])
|
|
||||||
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"messageid",value:ticketMessage.id},
|
{key:"categoryid",value:categoryResult.newCategoryId ?? "/"}
|
||||||
{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
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketUnclaimed").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketUnclaimed").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" unclaimed a ticket!","info",[
|
opendiscord.log(user.displayName+" unclaimed a ticket!","info",[
|
||||||
@@ -120,192 +87,8 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
+32
-215
@@ -1,15 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET UNPINNING SYSTEM
|
//TICKET UNPINNING SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:unpin-ticket"))
|
||||||
opendiscord.actions.get("opendiscord:unpin-ticket").workers.add([
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
if (channel.isThread()) throw new api.ODSystemError("Unable to unpin ticket! Open Ticket doesn't support threads!")
|
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:pinned-on").value = null
|
||||||
ticket.get("opendiscord:busy").value = true
|
ticket.get("opendiscord:busy").value = true
|
||||||
|
|
||||||
//rename channel (and give error when crashed)
|
//calculate channel name
|
||||||
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
|
const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("unpin-ticket",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
|
||||||
const priorityEmoji = opendiscord.priorities.getFromPriorityLevel(ticket.get("opendiscord:priority").value).channelEmoji ?? ""
|
if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
|
||||||
|
|
||||||
const originalName = channel.name
|
const originalName = channel.name
|
||||||
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
|
const newName = channelNameResult.newChannelName
|
||||||
try{
|
try{
|
||||||
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
||||||
opendiscord.log("Failed to rename channel on ticket unpin","error")
|
opendiscord.log("Failed to rename channel on ticket unpin","error")
|
||||||
})
|
})
|
||||||
}catch(err){
|
}catch(err){
|
||||||
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-unpin",{guild,channel,user,originalName,newName})).message)
|
opendiscord.log("Unable to rename channel while unpinning 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-unpin",{guild,channel,user,originalName,newName})).message)
|
||||||
|
setTimeout(() => {if (sentMsg.deletable) sentMsg.delete()},7000) //autodelete error message
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update ticket message
|
//update ticket message (no await)
|
||||||
const ticketMessage = await opendiscord.tickets.getTicketMessage(ticket)
|
openticketUtils.updateTicketMessage(guild,channel,user,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 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}
|
|
||||||
])
|
|
||||||
opendiscord.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketUnpinned").emit([ticket,user,channel,reason])
|
await opendiscord.events.get("afterTicketUnpinned").emit([ticket,user,channel,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
const {guild,channel,user,ticket,reason} = params
|
||||||
|
|
||||||
//to logs
|
//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")
|
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
|
//to dm
|
||||||
const creator = await opendiscord.tickets.getTicketUser(ticket,"creator")
|
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
|
const {guild,channel,user,ticket} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" unpinned a ticket!","info",[
|
opendiscord.log(user.displayName+" unpinned a ticket!","info",[
|
||||||
@@ -81,192 +82,8 @@ export const registerActions = async () => {
|
|||||||
{key:"channel",value:"#"+channel.name},
|
{key:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"reason",value:params.reason ?? "/"},
|
{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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET TOPIC SYSTEM
|
//TICKET TOPIC SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
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.add(new api.ODAction("opendiscord:update-ticket-priority"))
|
||||||
opendiscord.actions.get("opendiscord:update-ticket-priority").workers.add([
|
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
|
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!")
|
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
|
ticket.get("opendiscord:busy").value = true
|
||||||
if (newPriority) ticket.get("opendiscord:priority").value = newPriority.priority
|
if (newPriority) ticket.get("opendiscord:priority").value = newPriority.priority
|
||||||
|
|
||||||
//rename channel (and give error when crashed)
|
//calculate channel name
|
||||||
const pinEmoji = ticket.get("opendiscord:pinned").value ? generalConfig.data.system.pinEmoji : ""
|
const channelNameResult = await opendiscord.actions.get("opendiscord:calculate-ticket-name").run("priority-change",{guild,user,option:ticket.option,channel,ticket,currentChannelName:channel.name})
|
||||||
const priorityEmoji = newPriority.channelEmoji ?? ""
|
if (channelNameResult && channelNameResult.shouldChangeName && typeof channelNameResult.newChannelName !== "undefined"){
|
||||||
|
|
||||||
const originalName = channel.name
|
const originalName = channel.name
|
||||||
const newName = pinEmoji+priorityEmoji+utilities.trimEmojis(channel.name)
|
const newName = channelNameResult.newChannelName
|
||||||
try{
|
try{
|
||||||
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
await utilities.timedAwait(channel.setName(newName),2500,(err) => {
|
||||||
opendiscord.log("Failed to rename channel on ticket priority update","error")
|
opendiscord.log("Failed to rename channel on priority change","error")
|
||||||
})
|
})
|
||||||
}catch(err){
|
}catch(err){
|
||||||
await channel.send((await opendiscord.builders.messages.getSafe("opendiscord:error-channel-rename").build("ticket-priority",{guild,channel,user,originalName,newName})).message)
|
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
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
await opendiscord.events.get("afterTicketPriorityChanged").emit([ticket,user,channel,oldPriority,newPriority,reason])
|
await opendiscord.events.get("afterTicketPriorityChanged").emit([ticket,user,channel,oldPriority,newPriority,reason])
|
||||||
|
|
||||||
//update channel topic
|
//update channel topic
|
||||||
await opendiscord.actions.get("opendiscord:update-ticket-topic").run("ticket-action",{guild,channel,user,ticket,sendMessage:false,newTopic:null})
|
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
|
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
|
const {guild,channel,user,ticket,newPriority} = params
|
||||||
|
|
||||||
opendiscord.log(user.displayName+" changed the priority of a ticket!","info",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"priority",value:newPriority.id.value},
|
{key:"priority",value:newPriority.id.value},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
//TICKET TOPIC SYSTEM
|
//TICKET TOPIC SYSTEM
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
import {opendiscord, api, utilities} from "../index"
|
import {opendiscord, api, utilities, openticketUtils} from "../index.js"
|
||||||
import * as discord from "discord.js"
|
import * as discord from "discord.js"
|
||||||
|
|
||||||
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
const generalConfig = opendiscord.configs.get("opendiscord:general")
|
||||||
const lang = opendiscord.languages
|
const lang = opendiscord.languages
|
||||||
|
|
||||||
export const registerActions = async () => {
|
export async function registerActions(){
|
||||||
opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-topic"))
|
opendiscord.actions.add(new api.ODAction("opendiscord:update-ticket-topic"))
|
||||||
opendiscord.actions.get("opendiscord:update-ticket-topic").workers.add([
|
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
|
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!")
|
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
|
//handle channel topic
|
||||||
const channelTopics: string[] = []
|
const channelTopics: string[] = []
|
||||||
if (generalConfig.data.system.channelTopic.showOptionName) channelTopics.push(ticket.option.get("opendiscord:name").value)
|
if (generalConfig.data.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.ticketSystem.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.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
|
//update channel
|
||||||
channel.setTopic(channelTopics.join(" • "),"Topic Changed")
|
channel.setTopic(channelTopics.join(" • "),"Topic Changed")
|
||||||
|
|
||||||
//reply with new message
|
//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
|
ticket.get("opendiscord:busy").value = false
|
||||||
if (newTopic) await opendiscord.events.get("afterTicketTopicChanged").emit([ticket,user,channel,oldTopic,newTopic])
|
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
|
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
|
const {guild,channel,user,ticket,newTopic} = params
|
||||||
|
|
||||||
if (newTopic) opendiscord.log(user.displayName+" changed the topic of a ticket!","info",[
|
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:"channel",value:"#"+channel.name},
|
||||||
{key:"channelid",value:channel.id,hidden:true},
|
{key:"channelid",value:channel.id,hidden:true},
|
||||||
{key:"topic",value:newTopic},
|
{key:"topic",value:newTopic},
|
||||||
{key:"method",value:source}
|
{key:"method",value:origin}
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user