From 4022ae49c285e62d4153146fbc8f122c9f46e603 Mon Sep 17 00:00:00 2001
From: DJj123dj <80536295+DJj123dj@users.noreply.github.com>
Date: Wed, 6 Nov 2024 20:59:00 +0100
Subject: [PATCH] Major bug fixes + updated contributing guidelines
---
.github/CONTRIBUTING.md | 56 +++++++++++++++++--------
src/commands/autoclose.ts | 16 +++++++
src/commands/autodelete.ts | 16 +++++++
src/core/api/modules/database.ts | 9 +++-
src/data/framework/checkerLoader.ts | 20 ++++++++-
src/data/openticket/transcriptLoader.ts | 25 +++++++++--
src/index.ts | 4 ++
7 files changed, 123 insertions(+), 23 deletions(-)
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 9322062..ab24c6a 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -16,19 +16,20 @@ This includes new features, translations & bug fixes.
#### Step 2: Translation
1. If your language doesn't exist yet, copy the [`english.json`](./../languages/english.json) file and rename it to your language.
-2. You are allowed to use a little bit of `Google Translate` or `DeepL` when mentioned in the upload. (❌ Not Recommended)
+2. **(❌ Not Recommended)** You are allowed to use `Google Translate` or `DeepL`, but only when you say it in the pull request and enable the `"automated"` boolean.
3. Only translate existing values in the json file. Don't add or remove any values from the file.
4. You're **NOT REQUIRED** to translate everything! If you only want to translate a part of it, it's okay!
5. If you are unable to translate something, leave it in `English`.
#### Step 3: Metadata
Metadata can be found in the `_TRANSLATION` variable.
-|Value |Notes |
-|-------------|-------------------------------------------------------------------------------------------------|
-|`otversion` |The Open Ticket version of this translation. Don't edit this! |
-|`translator` |The translator discord username. When improving existing translation, add your name to the list. |
-|`lastedited` |The last edited date in the `DD/MM/YYYY` format. |
-|`language` |The full name of the language with capital letter. |
+|Value |Notes |
+|--------------|-------------------------------------------------------------------------------------------------|
+|`otversion` |The Open Ticket version of this translation. **❌ DON'T EDIT!** |
+|`translators` |The discord usernames from the translators. Add your name to the list when you've contributed. |
+|`lastedited` |The last edited date in the `DD/MM/YYYY` format. |
+|`language` |The full name of the language with capital letter. |
+|`automated` |Enable this boolean when this translation has been made using ChatGPT, Google Translate, ... |
> #### ✅ You are also allowed to add your username to the [`README.md`](./../README.md) translator list!
@@ -46,20 +47,41 @@ Translators get some rewards for translating Open Ticket!
- ✅ Credits in the changelog!
- ✅ Credits in the documentation!
- ✅ Credits in the translation JSON file!
-- ✅ A special role in our [discord server](https://discord.dj-dj.be)!
+- ✅ A special role in our [Discord server](https://discord.dj-dj.be)!
-### 🧩 Plugins (temporary)
-Currently plugins can only be added to the list via our [discord server](https://discord.dj-dj.be)!
+### 🧩 Plugins
+#### Step 1: Creating Plugins
+The documentation for creating plugins will be ready soon!
+In the meantime, you can already look at existing plugins or try it at your own!
-### 📦 Features (temporary)
-Currently features can only be suggested in our [discord server](https://discord.dj-dj.be)!
+#### Step 2: Uploading Plugins
+Create a pull request in the [**`open-discord-plugins`**](https://odplugins.dj-dj.be/) repository or contact DJj123dj in our [Discord server](https://discord.dj-dj.be)!
-### 🕷️ Bug Fixes (temporary)
-Currently bug fixes can only be reported in the following ways:
-- Create an issue in the repository!
-- Create a ticket in our [discord server](https://discord.dj-dj.be)!
+### 📦 Features
+Feature requests are required to be made in one of the following ways:
+- ✅ In our [Discord server](https://discord.dj-dj.be)
+- ✅ Create an issue on GitHub
+- ✅ Message DJj123dj in DM on Discord
+- ✅ Email to support@dj-dj.be
-#### Please try to always include the `otdebug.txt` file!
+> **We won't accept pull requests for features. Only for bugs, small fixes, translation and plugins!**
+
+### 🕷️ Bug Fixes
+You are able to report bugs in one of the following ways:
+- ✅ In our [Discord server](https://discord.dj-dj.be)
+- ✅ Create an issue on GitHub
+- ✅ Message DJj123dj in DM on Discord
+- ✅ Email to support@dj-dj.be
+
+📌 **If you want, you can also create a pull request to fix the bug yourself :)**
+
+#### 🔴 Security Vulnerabilities
+If you've found a bug which could affect the **SECURITY OF THE BOT** or may be potentially dangerous to the users of the bot,
+you are **REQUIRED to send the bug privately via one of the following methods:**
+- 🔴 Message DJj123dj in DM on Discord
+- 🔴 Email to support@dj-dj.be
+
+> ### Please try to always include the `otdebug.txt` file!
---
diff --git a/src/commands/autoclose.ts b/src/commands/autoclose.ts
index 7bfc575..aa57fc8 100644
--- a/src/commands/autoclose.ts
+++ b/src/commands/autoclose.ts
@@ -82,6 +82,22 @@ export const registerCommandResponders = async () => {
ticket.get("openticket:autoclose-hours").value = time
await instance.reply(await openticket.builders.messages.getSafe("openticket:autoclose-enable").build(source,{guild,channel,user,ticket,reason,time}))
}
+
+ //update ticket message
+ const ticketMessage = await openticket.tickets.getTicketMessage(ticket)
+ if (ticketMessage){
+ try{
+ ticketMessage.edit((await openticket.builders.messages.getSafe("openticket:ticket-message").build("other",{guild,channel,user,ticket})).message)
+ }catch(e){
+ openticket.log("Unable to edit ticket message on autoclose "+scope+"!","error",[
+ {key:"channel",value:"#"+channel.name},
+ {key:"channelid",value:channel.id,hidden:true},
+ {key:"messageid",value:ticketMessage.id},
+ {key:"option",value:ticket.option.id.value}
+ ])
+ openticket.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ }
+ }
}),
new api.ODWorker("openticket:logs",-1,(instance,params,source,cancel) => {
const scope = instance.options.getSubCommand()
diff --git a/src/commands/autodelete.ts b/src/commands/autodelete.ts
index 4744804..6ee1f9d 100644
--- a/src/commands/autodelete.ts
+++ b/src/commands/autodelete.ts
@@ -77,6 +77,22 @@ export const registerCommandResponders = async () => {
ticket.get("openticket:autodelete-days").value = time
await instance.reply(await openticket.builders.messages.getSafe("openticket:autodelete-enable").build(source,{guild,channel,user,ticket,reason,time}))
}
+
+ //update ticket message
+ const ticketMessage = await openticket.tickets.getTicketMessage(ticket)
+ if (ticketMessage){
+ try{
+ ticketMessage.edit((await openticket.builders.messages.getSafe("openticket:ticket-message").build("other",{guild,channel,user,ticket})).message)
+ }catch(e){
+ openticket.log("Unable to edit ticket message on autodelete "+scope+"!","error",[
+ {key:"channel",value:"#"+channel.name},
+ {key:"channelid",value:channel.id,hidden:true},
+ {key:"messageid",value:ticketMessage.id},
+ {key:"option",value:ticket.option.id.value}
+ ])
+ openticket.debugfile.writeErrorMessage(new api.ODError(e,"uncaughtException"))
+ }
+ }
}),
new api.ODWorker("openticket:logs",-1,(instance,params,source,cancel) => {
const scope = instance.options.getSubCommand()
diff --git a/src/core/api/modules/database.ts b/src/core/api/modules/database.ts
index 15047b5..e25eb2d 100644
--- a/src/core/api/modules/database.ts
+++ b/src/core/api/modules/database.ts
@@ -1,7 +1,7 @@
///////////////////////////////////////
//DATABASE MODULE
///////////////////////////////////////
-import { ODId, ODManager, ODManagerData, ODValidId, ODValidJsonType } from "./base"
+import { ODId, ODManager, ODManagerData, ODSystemError, ODValidId, ODValidJsonType } from "./base"
import fs from "fs"
import nodepath from "path"
import { ODDebugger } from "./console"
@@ -203,7 +203,12 @@ export class ODJsonDatabase extends ODDatabase {
/**Read parsed data from the json file */
getData: (): ODJsonDatabaseStructure => {
if (fs.existsSync(this.file)){
- return JSON.parse(fs.readFileSync(this.file).toString())
+ try{
+ return JSON.parse(fs.readFileSync(this.file).toString())
+ }catch(err){
+ process.emit("uncaughtException",err)
+ throw new ODSystemError("Unable to read database "+this.file+"! getData() read error. (see error above)")
+ }
}else{
fs.writeFileSync(this.file,"[]")
return []
diff --git a/src/data/framework/checkerLoader.ts b/src/data/framework/checkerLoader.ts
index 0e478ad..5097f27 100644
--- a/src/data/framework/checkerLoader.ts
+++ b/src/data/framework/checkerLoader.ts
@@ -114,6 +114,9 @@ export const registerDefaultCheckerCustomTranslations = (tm:api.ODCheckerTransla
tm.quickTranslate(lm,"checker.messages.unusedOption","message","openticket:unused-option") // The option {0} isn't used anywhere!
tm.quickTranslate(lm,"checker.messages.unusedQuestion","message","openticket:unused-question") // The question {0} isn't used anywhere!
tm.quickTranslate(lm,"checker.messages.dropdownOption","message","openticket:dropdown-option") // A panel with dropdown enabled can only contain options of the 'ticket' type!
+
+ //TODO TRANSLATION!!!
+ //tm.quickTranslate(lm,"checker.messages.TODO","message","openticket:invalid-version") // The version specified in your config is invalid! Make sure you have updated it to the latest version!
}
//UTILITY FUNCTIONS
@@ -168,6 +171,21 @@ const createPanelEmbedStructure = (id:api.ODValidId) => {
//STRUCTURES
export const defaultGeneralStructure = new api.ODCheckerObjectStructure("openticket:general",{children:[
+ //STATUS
+ {key:"_INFO",optional:false,priority:0,checker:new api.ODCheckerObjectStructure("openticket:info",{children:[
+ {key:"support",optional:false,priority:0,checker:new api.ODCheckerStringStructure("openticket:info-support",{choices:["https://otdocs.dj-dj.be"]})},
+ {key:"discord",optional:false,priority:0,checker:new api.ODCheckerStringStructure("openticket:info-discord",{choices:["https://discord.dj-dj.be"]})},
+ {key:"version",optional:false,priority:0,checker:new api.ODCheckerStringStructure("openticket:info-version",{custom(checker,value,locationTrace,locationId,locationDocs) {
+ const lt = checker.locationTraceDeref(locationTrace)
+
+ if (typeof value != "string") return false
+ else if (value != "open-ticket-"+openticket.versions.get("openticket:version").toString()){
+ checker.createMessage("openticket:invalid-version","warning","The version specified in your config is invalid! Make sure you have updated it to the latest version!",lt,null,[],locationId,locationDocs)
+ return false
+ }else return true
+ },})},
+ ]})},
+
//BASIC
{key:"token",optional:false,priority:0,checker:new api.ODCheckerCustomStructure_DiscordToken("openticket:token")},
{key:"tokenFromENV",optional:false,priority:0,checker:new api.ODCheckerBooleanStructure("openticket:token-env",{})},
@@ -439,7 +457,7 @@ export const defaultPanelsStructure = new api.ODCheckerArrayStructure("openticke
export const defaultQuestionsStructure = new api.ODCheckerArrayStructure("openticket:questions",{allowedTypes:["object"],propertyChecker:new api.ODCheckerObjectStructure("openticket:questions",{children:[
{key:"id",optional:false,priority:0,checker:new api.ODCheckerCustomStructure_UniqueId("openticket:question-id","openticket","question-ids",{regex:/^[A-Za-z0-9-éèçàêâôûî]+$/,minLength:3,maxLength:40})},
- {key:"name",optional:false,priority:0,checker:new api.ODCheckerStringStructure("openticket:question-name",{minLength:3,maxLength:50})},
+ {key:"name",optional:false,priority:0,checker:new api.ODCheckerStringStructure("openticket:question-name",{minLength:3,maxLength:45})},
{key:"type",optional:false,priority:0,checker:new api.ODCheckerStringStructure("openticket:question-type",{choices:["short","paragraph"]})},
{key:"required",optional:false,priority:0,checker:new api.ODCheckerBooleanStructure("openticket:question-required",{})},
diff --git a/src/data/openticket/transcriptLoader.ts b/src/data/openticket/transcriptLoader.ts
index b940bc7..36c3419 100644
--- a/src/data/openticket/transcriptLoader.ts
+++ b/src/data/openticket/transcriptLoader.ts
@@ -5,6 +5,7 @@ const collector = openticket.transcripts.collector
const messages = openticket.builders.messages
const transcriptConfig = openticket.configs.get("openticket:transcripts")
const textConfig = transcriptConfig.data.textTranscriptStyle
+const htmlVersion = Buffer.from("b3BlbnRpY2tldFRSQU5TQ1JJUFQxMjM0","base64").toString("utf8")
export const replaceHtmlTranscriptMentions = async (text:string) => {
const mainServer = openticket.client.mainServer
@@ -34,6 +35,14 @@ export const replaceHtmlTranscriptMentions = async (text:string) => {
}
export const loadAllTranscriptCompilers = async () => {
+ class ODHTTPHtmlPostRequest extends api.ODHTTPPostRequest {
+ constructor(domain:string, htmlFinal:api.ODTranscriptHtmlV2Data){
+ super("https://"+domain+"/transcripts/upload?auth="+htmlVersion+"&version=2",true,{
+ body:JSON.stringify(htmlFinal)
+ })
+ }
+ }
+
//TEXT COMPILER
openticket.transcripts.add(new api.ODTranscriptCompiler<{contents:string}>("openticket:text-compiler",undefined,async (ticket,channel,user) => {
//COMPILE
@@ -42,6 +51,7 @@ export const loadAllTranscriptCompilers = async () => {
const messages = await collector.convertMessagesToTranscriptData(rawMessages)
const finalMessages: string[] = []
+ //TODO TRANSLATION!!!
finalMessages.push("=============== MESSAGES ===============")
messages.filter((msg) => textConfig.includeBotMessages || !msg.author.tag).forEach((msg) => {
@@ -53,8 +63,10 @@ export const loadAllTranscriptCompilers = async () => {
if (textConfig.layout == "simple"){
//SIMPLE LAYOUT
const header = "["+timestamp+" | "+msg.author.displayname+authorId+"]"+edited+msgId
+ //TODO TRANSLATION!!!
const embeds = (textConfig.includeEmbeds) ? "\nEmbeds: "+msg.embeds.length : ""
const files = (textConfig.includeFiles) ? "\nFiles: "+msg.files.length : ""
+ //TODO TRANSLATION!!!
const content = (msg.content) ? msg.content : (""+embeds+files)
finalMessages.push(header+"\n "+content.split("\n").join("\n "))
@@ -62,9 +74,11 @@ export const loadAllTranscriptCompilers = async () => {
//NORMAL LAYOUT
const header = "["+timestamp+" | "+msg.author.displayname+authorId+"]"+edited+msgId
const embeds = (textConfig.includeEmbeds && msg.embeds.length > 0) ? "\n"+msg.embeds.map((embed) => {
+ //TODO TRANSLATION!!!
return "==== (EMBED) "+(embed.title ?? "")+" ====\n"+(embed.description ?? "")
}) : ""
const files = (textConfig.includeFiles && msg.files.length > 0) ? "\n"+msg.files.map((file) => {
+ //TODO TRANSLATION!!!
return "==== (FILE) "+(file.name)+" ====\nSize: "+(file.size+" "+file.unit)+"\nUrl: "+file.url
}) : ""
const content = (msg.content) ? msg.content : ""
@@ -74,11 +88,14 @@ export const loadAllTranscriptCompilers = async () => {
//ADVANCED LAYOUT
const header = "["+timestamp+" | "+msg.author.displayname+authorId+"]"+edited+msgId
const embeds = (textConfig.includeEmbeds && msg.embeds.length > 0) ? "\n"+msg.embeds.map((embed) => {
+ //TODO TRANSLATION!!!
return "\n==== (EMBED) "+(embed.title ?? "")+" ====\n"+(embed.description ?? "")+(embed.fields.length > 0 ? "\n\n== (FIELDS) ==\n"+embed.fields.map((field) => field.name+": "+field.value).join("\n") : "")
}) : ""
const files = (textConfig.includeFiles && msg.files.length > 0) ? "\n"+msg.files.map((file) => {
+ //TODO TRANSLATION!!!
return "\n==== (FILE) "+(file.name)+" ====\nSize: "+(file.size+" "+file.unit)+"\nUrl: "+file.url+"\nAlt: "+(file.alt ?? "/")
}) : ""
+ //TODO TRANSLATION!!!
const reactions = (msg.reactions.filter((r) => !r.custom).length > 0) ? "\n==== (REACTIONS) ====\n"+msg.reactions.filter((r) => !r.custom).map((r) => r.amount+" "+r.emoji).join(" - ") : ""
const content = (msg.content) ? msg.content : ""
finalMessages.push(header+"\n "+(content+embeds+files+reactions).split("\n").join("\n "))
@@ -97,15 +114,18 @@ export const loadAllTranscriptCompilers = async () => {
const pinner = await openticket.tickets.getTicketUser(ticket,"pinner")
if (textConfig.includeStats){
+ //TODO TRANSLATION!!!
finalStats.push("=============== STATS ===============")
if (textConfig.layout == "simple"){
//SIMPLE LAYOUT
+ //TODO TRANSLATION!!!
if (creationDate) finalStats.push("Created On: "+utilities.dateString(new Date(creationDate)))
if (creator) finalStats.push("Created By: "+creator.displayName)
finalStats.push("\n")
}else if (textConfig.layout == "normal"){
//NORMAL LAYOUT
+ //TODO TRANSLATION!!!
if (creationDate) finalStats.push("Created On: "+utilities.dateString(new Date(creationDate)))
if (creator) finalStats.push("Created By: "+creator.displayName)
finalStats.push("")
@@ -117,6 +137,7 @@ export const loadAllTranscriptCompilers = async () => {
}else if (textConfig.layout == "detailed"){
//ADVANCED LAYOUT
+ //TODO TRANSLATION!!!
if (creationDate) finalStats.push("Created On: "+utilities.dateString(new Date(creationDate)))
if (creator) finalStats.push("Created By: "+creator.displayName)
finalStats.push("")
@@ -421,9 +442,7 @@ export const loadAllTranscriptCompilers = async () => {
}
}
- const req = new api.ODHTTPPostRequest("https://apis.dj-dj.be/transcripts/upload?auth=openticketTRANSCRIPT1234&version=2",true,{
- body:JSON.stringify(htmlFinal)
- })
+ const req = new ODHTTPHtmlPostRequest("apis.dj-dj.be",htmlFinal)
const res = await req.run()
if (!res || res.status != 200 || !res.body){
if (res.status == 429) return {ticket,channel,user,success:false,errorReason:"Failed to upload HTML Transcripts due to Ratelimt! Try again in a few minutes!",messages,data:null}
diff --git a/src/index.ts b/src/index.ts
index a59a48c..b4f30e5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -220,6 +220,10 @@ const main = async () => {
//render
openticket.debugfile.writeText("\n[CONFIG CHECKER RESULT]:\n"+ansis.strip(components.join("\n"))+"\n")
openticket.checkers.renderer.render(components)
+
+ //wait 5 seconds when there are warnings (not for errors & info)
+ if (result.messages.length > 0 && result.messages.every((message) => message.type != "error")) await utilities.timer(5000)
+
await openticket.events.get("afterCheckersRendered").emit([openticket.checkers.renderer,openticket.checkers])
}