From c2117a67ed1f269a676de85e489814948d537894 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Wed, 3 Dec 2025 16:20:17 +0100 Subject: [PATCH 1/8] Updated German translation for v4.1 --- languages/catalan.json | 2 +- languages/custom.json | 2 +- languages/dutch.json | 2 +- languages/english.json | 2 +- languages/estonian.json | 2 +- languages/finnish.json | 2 +- languages/german.json | 180 +++++++++++++++++++++++++----- languages/greek.json | 2 +- languages/hindi.json | 2 +- languages/indonesian.json | 2 +- languages/japanese.json | 2 +- languages/korean.json | 2 +- languages/kurdish.json | 2 +- languages/simplified-chinese.json | 2 +- languages/slovenian.json | 2 +- languages/tamil.json | 2 +- languages/thai.json | 2 +- 17 files changed, 171 insertions(+), 41 deletions(-) diff --git a/languages/catalan.json b/languages/catalan.json index 18a26e9..4307d3c 100644 --- a/languages/catalan.json +++ b/languages/catalan.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["guillee3"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Catalan", "automated":false }, diff --git a/languages/custom.json b/languages/custom.json index bfa160c..4756229 100644 --- a/languages/custom.json +++ b/languages/custom.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["DJj123dj"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Custom", "automated":false }, diff --git a/languages/dutch.json b/languages/dutch.json index 982d582..e0e703f 100644 --- a/languages/dutch.json +++ b/languages/dutch.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["DJj123dj"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Dutch", "automated":false }, diff --git a/languages/english.json b/languages/english.json index 1ed67c7..92bf9f3 100644 --- a/languages/english.json +++ b/languages/english.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["DJj123dj"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"English", "automated":false }, diff --git a/languages/estonian.json b/languages/estonian.json index 73ccdb0..53699a5 100644 --- a/languages/estonian.json +++ b/languages/estonian.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["iamnotmega","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Estonian", "automated":true }, diff --git a/languages/finnish.json b/languages/finnish.json index b35da41..1532b79 100644 --- a/languages/finnish.json +++ b/languages/finnish.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["iamnotmega","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Finnish", "automated":true }, diff --git a/languages/german.json b/languages/german.json index 7731b68..0d21093 100644 --- a/languages/german.json +++ b/languages/german.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["benzorich"], - "lastedited":"06/10/2024", + "lastedited":"03/12/2025", "language":"German", "automated":false }, @@ -31,7 +31,15 @@ "stringContains":"Diese Zeichenfolge muss {0} enthalten!", "stringChoices":"Diese Zeichenfolge kann nur einen der folgenden Werte annehmen: {0}!", "stringRegex":"Diese Zeichenfolge ist ungültig!", - + "stringInvertedContains":"Diese Zeichenkette darf {0} nicht enthalten!", + "stringLowercase":"Diese Zeichenkette muss ausschließlich in Kleinbuchstaben geschrieben werden!", + "stringUppercase":"Diese Zeichenkette muss ausschließlich in Großbuchstaben geschrieben werden!", + "stringSpecialCharacters":"Diese Zeichenkette darf keine Sonderzeichen enthalten! (nur a-z, 0-9 & Leerzeichen)", + "stringNoSpaces":"Diese Zeichenkette darf keine Leerzeichen enthalten!", + "stringCapitalWord":"Es wird empfohlen, dass jedes Wort in dieser Zeichenkette mit einem Großbuchstaben beginnt!", + "stringCapitalSentence":"Es sieht so aus, als würden einige Sätze in dieser Zeichenkette nicht mit einem Großbuchstaben beginnen!", + "stringPunctuation":"Es sieht so aus, als würde der Satz in dieser Zeichenkette nicht mit einem Satzzeichen enden!", + "numberTooShort":"Diese Zahl kann nicht kürzer als {0} Zeichen sein!", "numberTooLong":"Diese Nummer darf nicht länger als {0} Zeichen sein!", "numberLengthInvalid":"Diese Nummer muss {0} Zeichen lang sein!", @@ -48,10 +56,12 @@ "numberNegative":"Diese Zahl kann nicht negativ sein!", "numberPositive":"Diese Zahl kann nicht positiv sein!", "numberZero":"Diese Zahl kann nicht Null sein!", - + "numberNan":"Diese Zahl darf nicht NaN (Not A Number) sein!", + "numberInvertedContains":"Diese Zahl darf {0} nicht enthalten!", + "booleanTrue":"Dieser boolean Wert kann nicht wahr sein!", "booleanFalse":"Dieser boolean Wert kann nicht falsch sein!", - + "arrayEmptyDisabled":"Dieses Array darf nicht leer sein!", "arrayEmptyRequired":"Dieses Array muss leer sein!", "arrayTooShort":"Dieses Array muss eine Länge von mindestens {0} haben!", @@ -59,7 +69,7 @@ "arrayLengthInvalid":"Dieses Array muss eine Länge von {0} haben!", "arrayInvalidTypes":"Dieses Array kann nur die folgenden Typen enthalten: {0}!", "arrayDouble":"In diesem Array darf derselbe Wert nicht zweimal vorkommen!", - + "discordInvalidId":"Dies ist eine ungültige Discord {0} id!", "discordInvalidIdOptions":"Dies ist eine ungültige Discord {0} id! Du kannst auch eine der folgenden verwenden: {1}!", "discordInvalidToken":"Das ist ein ungültiger Discord-Token (syntaktisch)!", @@ -76,7 +86,7 @@ "urlInvalidPath":"Diese Url hat einen ungültigen Pfad!", "idNotUnique":"Diese ID ist nicht eindeutig, verwenden Sie stattdessen eine andere ID!", "idNonExistent":"Die ID {0} existiert nicht!", - + "invalidType":"Diese Eigenschaft muss vom Typ sein: {0}!", "propertyMissing":"Die Eigenschaft {0} fehlt in diesem Objekt!", "propertyOptional":"Die Eigenschaft {0} ist in diesem Objekt optional!", @@ -84,12 +94,13 @@ "nullInvalid":"Diese Eigenschaft kann nicht null sein!", "switchInvalidType":"Dies muss einer der folgenden Typen sein: {0}!", "objectSwitchInvalid":"Dieses Objekt muss einer der folgenden Typen sein: {0}!", - + "invalidLanguage":"Dies ist eine ungültige Sprache!", "invalidButton":"Dieser Button muss mindestens eine {0} oder {1} enthalten!", "unusedOption":"Die Option {0} wird nirgends verwendet!", "unusedQuestion":"Die Frage {0} wird nirgends verwendet!", - "dropdownOption":"Ein Panel mit aktiviertem Dropdown kann nur Optionen vom Typ 'Ticket' enthalten!" + "dropdownOption":"Ein Panel mit aktiviertem Dropdown kann nur Optionen vom Typ 'Ticket' enthalten!", + "customInvalidVersion":"Die in deiner Konfiguration angegebene Version stimmt nicht überein! Stelle sicher, dass du die Konfiguration auf die neueste Version aktualisiert hast!" } }, "actions":{ @@ -132,6 +143,7 @@ "blacklistAddDm":"Zur Blacklist hinzugefügt", "blacklistRemoveDm":"Von der Blacklist entfernen", "clear":"Freigegebene Tickets", + "clearTickets":"Tickets Löschen", "roles":"Aktualisierte Rollen", "autoclose":"Ticket automatisch geschlossen", @@ -139,7 +151,12 @@ "autocloseDisabled":"Automatisches schließen Deaktiviert", "autodelete":"Ticket automatisch gelöscht", "autodeleteEnabled":"Automatisches Löschen Aktiviert", - "autodeleteDisabled":"Automatisches Löschen Deaktiviert" + "autodeleteDisabled":"Automatisches Löschen Deaktiviert", + + "topicSet":"Thema Geändert", + "prioritySet":"Priorität Geändert", + "priorityGet":"Ticket-Priorität", + "transfer":"Ticket Übertragen" }, "descriptions":{ "create":"Ihr Ticket wurde bereits erstellt. Klicken Sie auf die Button unten, um es zu öffnen!", @@ -154,7 +171,7 @@ "move":"Das Ticket wurde erfolgreich nach {0} verschoben!", "add":"{0} wurde erfolgreich zum Ticket hinzugefügt!", "remove":"{0} wurde erfolgreich aus dem Ticket entfernt!", - + "helpExplanation":"`` => erforderlicher Parameter\n`[name]` => optionaler Parameter", "statsReset":"Die Bot-Statistiken wurden erfolgreich zurückgesetzt!", "statsError":"Ticketstatistiken können nicht angezeigt werden!\n{0} ist kein Ticket!", @@ -167,7 +184,7 @@ "clearVerify":"Sind Sie sicher, dass Sie mehrere Tickets löschen möchten?\nDiese Aktion kann nicht rückgängig gemacht werden!", "clearReady":"{0} Tickets wurden erfolgreich gelöscht!", "rolesEmpty":"Es wurden keine Rollen aktualisiert!", - + "autocloseLeave":"Dieses Ticket wurde automatisch geschlossen, weil der Ersteller den Server verlassen hat!", "autocloseTimeout":"Dieses Ticket wurde automatisch geschlossen, da es seit mehr als `{0}h` inaktiv ist!", "autodeleteLeave":"Dieses Ticket wurde automatisch gelöscht, weil der Ersteller den Server verlassen hat!", @@ -176,11 +193,16 @@ "autocloseDisabled":"Autoclose wurde für dieses Ticket deaktiviert! Es wird nicht mehr automatisch geschlossen!", "autodeleteEnabled":"Automatisches Löschen wurde für dieses Ticket aktiviert! Es wird gelöscht, wenn es länger als `{0} Tage` inaktiv ist!", "autodeleteDisabled":"Automatisches Löschen wurde bei diesem Ticket deaktiviert! Es wird nicht mehr automatisch gelöscht!", - + "ticketMessageLimit":"Sie können nur {0} Tickets gleichzeitig erstellen!", "ticketMessageAutoclose":"Dieses Ticket wird automatisch geschlossen, wenn es {0}h lang inaktiv war!", "ticketMessageAutodelete":"Dieses Ticket wird automatisch gelöscht, wenn es {0} Tage lang inaktiv war!", - "panelReady":"Sie finden das Panel unten!\nDiese Nachricht kann jetzt gelöscht werden!" + "panelReady":"Das Panel ist in der folgenden Nachricht verfügbar!\nDiese Nachricht kann nun gelöscht werden!", + + "topicSet":"Das Kanalthema wurde erfolgreich von {0} geändert!", + "prioritySet":"Die Ticket-Priorität wurde erfolgreich von {1} auf {0} geändert!", + "priorityGet":"Die aktuelle Priorität dieses Tickets ist {0}.", + "transfer":"Das Ticket wurde erfolgreich von {0} an {1} durch {2} übertragen!" }, "modal":{ "closePlaceholder":"Warum haben Sie dieses Ticket geschlossen?", @@ -215,12 +237,19 @@ "addDm":"{0} wurde zu Ihrem Ticket auf unserem Server hinzugefügt!", "removeLog":"{0} wurde von {1} aus diesem Ticket entfernt!", "removeDm":"{0} wurde von Ihrem Ticket auf unserem Server entfernt!", - + "blacklistAddLog":"{0} wurde von {1} auf die Blacklist gesetzt!", "blacklistRemoveLog":"{0} wurde von {1} von der Blacklist entfernt!", "blacklistAddDm":"Sie wurden in unserem Server auf die Blacklist gesetzt!\nAb sofort können Sie kein Ticket mehr erstellen!", "blacklistRemoveDm":"Sie wurden von der Blacklist unseres Servers entfernt!\n Jetzt können Sie wieder Tickets erstellen!", - "clearLog":"{0} Tickets wurden von {1} gelöscht!" + "clearLog":"{0} Tickets wurden von {1} gelöscht!", + + "transferLog":"Das Ticket wurde von {0} an {1} durch {2} übertragen!", + "transferDm":"Dein Ticket wurde von {0} an {1} auf unserem Server übertragen!", + "prioritySetLog":"Die Priorität dieses Tickets wurde von {1} auf {0} geändert!", + "prioritySetDm":"Die Priorität deines Tickets wurde auf unserem Server auf {0} geändert!", + "roleUpdateLog":"{0} hat seine Rollen aktualisiert!", + "roleUpdateDm":"Deine Rollen auf unserem Server wurden aktualisiert!" } }, "transcripts":{ @@ -229,7 +258,7 @@ "ready":"Transkript erstellt", "textFileDescription":"Dies ist die Textabschrift eines gelöschten Tickets!", "htmlProgress":"Bitte warten Sie, während dieses html-Transkript verarbeitet wird...", - + "createdChannel":"Ein neues {0} Transkript wurde auf dem Server erstellt!", "createdCreator":"Es wurde ein neues {0} Transkript für eines Ihrer Tickets erstellt!", "createdParticipant":"In einem der Tickets, an denen Sie teilgenommen haben, wurde ein neues {0} Transkript erstellt!", @@ -241,7 +270,19 @@ "retry":"Erneut versuchen", "continue":"Löschen ohne Transkript", "backup":"Sicherungstranskript erstellen", - "error":"Beim Versuch, das Transkript zu erstellen, ist etwas schief gelaufen.\nWas möchten Sie tun?\n\nDieses Ticket wird erst gelöscht, wenn Sie auf eine der folgenden Buttons klicken." + "error":"Beim Versuch, das Transkript zu erstellen, ist etwas schief gelaufen.\nWas möchten Sie tun?\n\nDieses Ticket wird erst gelöscht, wenn Sie auf eine der folgenden Buttons klicken.", + "title":"Transkript-Fehler" + }, + "text":{ + "messagesTitle":"NACHRICHTEN", + "embedTitle":"EMBED", + "fileTitle":"DATEI", + "fieldsTitle":"FELDER", + "reactionsTitle":"REAKTIONEN", + "statsTitle":"STATISTIKEN", + "emptyContent":"", + "noTitle":"", + "noDesc":"" } }, "errors":{ @@ -257,7 +298,8 @@ "unknownPanel":"Unbekanntes Panel", "notInGuild":"Nicht auf dem Server", "channelRename":"Kanal kann nicht umbenannt werden", - "busy":"Ticket ist besetzt" + "busy":"Ticket ist besetzt", + "permissionError":"Berechtigungsfehler" }, "descriptions":{ "askForInfo":"Kontaktieren Sie den Besitzer dieses Bots für weitere Informationen!", @@ -280,7 +322,10 @@ "notInGuild":"{0} funktioniert nicht in DM! Bitte versuchen Sie es erneut auf einem Server!", "channelRename":"Aufgrund von Discord-Ratelimits ist es dem Bot derzeit nicht möglich, den Channel umzubenennen. Der Channel wird nach 10 Minuten automatisch umbenannt, wenn der Bot nicht neu gestartet wird.", "channelRenameSource":"Die Quelle dieses Fehlers ist: {0}", - "busy":"{0} kann nicht verwendet werden!\nDas Ticket wird derzeit vom Bot bearbeitet.\n\nBitte versuchen Sie es in ein paar Sekunden erneut!" + "busy":"{0} kann nicht verwendet werden!\nDas Ticket wird derzeit vom Bot bearbeitet.\n\nBitte versuchen Sie es in ein paar Sekunden erneut!", + "closeBeforeMessage":"Dieses Ticket kann nicht geschlossen/gelöscht werden, bevor eine Nachricht von einem Benutzer gesendet wurde.", + "closeBeforeAdminMessage":"Dieses Ticket kann nicht geschlossen/gelöscht werden, bevor eine Nachricht von einem Ticket-Admin oder Support-Mitglied gesendet wurde.", + "unableToCreateTicket":"Du kannst kein Ticket erstellen." }, "optionInvalidReasons":{ "stringRegex":"Wert stimmt nicht mit Muster überein!", @@ -331,7 +376,6 @@ "added":"Hinzugefügt", "removed":"Entfernt", "filter":"Filter", - "claimedBy":"Beansprucht von {0}", "method":"Methode", "type":"Typ", "blacklisted":"Gesperrt", @@ -355,7 +399,27 @@ "status":"Status", "claimed":"Beansprucht", "pinned":"Angepinnt", - "creationDate":"Erstellungsdatum" + "creationDate":"Erstellungsdatum", + + "noone":"Niemand", + "open":"Offen", + "closed":"Geschlossen", + "priority":"Priorität", + "participants":"Teilnehmer", + "yes":"Ja", + "no":"Nein", + "option":"Option", + "topic":"Thema", + "uptime":"System-Laufzeit", + "messages":"Nachrichten", + "embeds":"Embeds", + "files":"Dateien", + "components":"Komponenten", + "cooldown":"Cooldown", + "maxTickets":"Max. Tickets", + "admins":"Admins", + "roles":"Rollen", + "size":"Größe" }, "lowercase":{ "text":"text", @@ -384,6 +448,7 @@ "unclaim":"Beanspruchen Sie ein Ticket zurück.", "pin":"Pinne ein Ticket an.", "unpin":"Pinne ein Ticket ab.", + "move":"Verschieben Sie ein Ticket.", "moveId":"Die Kennung der Option.", "rename":"Ein Ticket umbenennen.", @@ -392,6 +457,7 @@ "addUser":"Der hinzuzufügende Benutzer.", "remove":"Entfernen Sie einen Benutzer aus einem Ticket.", "removeUser":"Der zu entfernende Benutzer.", + "blacklist":"Verwalten Sie die Blacklist für Tickets.", "blacklistView":"Zeigen Sie eine Liste der aktuellen Blacklist an.", "blacklistAdd":"Hinzufügen eines Benutzers zur Blacklist.", @@ -405,6 +471,7 @@ "statsUserUser":"Der zu betrachtende Benutzer.", "statsTicket":"Anzeigen der Statistiken eines Tickets auf dem Server.", "statsTicketTicket":"Das Ticket zur Betrachtung.", + "clear":"Mehrere Tickets gleichzeitig löschen. Optional kann ein Filter angegeben werden.", "clearFilter":"Der Filter zum Löschen von Tickets.", "clearFilters":{ @@ -417,6 +484,7 @@ "unpin":"nicht Angepinnte", "autoclose":"Autoclosed" }, + "autoclose":"Verwalten Sie die automatische Schließung in einem Ticket.", "autocloseDisable":"Deaktivieren Sie das automatische Schließen in diesem Ticket.", "autocloseEnable":"Aktivieren Sie das automatische Schließen in diesem Ticket.", @@ -424,7 +492,19 @@ "autodelete":"Verwalten Sie die automatische Löschung in einem Ticket.", "autodeleteDisable":"Deaktivieren Sie das automatische Löschen in diesem Ticket.", "autodeleteEnable":"Aktivieren Sie das automatische Löschen in diesem Ticket.", - "autodeleteEnableTime":"Die Anzahl der Tage, die das Ticket inaktiv sein muss, um es zu löschen." + "autodeleteEnableTime":"Die Anzahl der Tage, die das Ticket inaktiv sein muss, um es zu löschen.", + + "topic":"Verwalte das Thema des Ticket-Kanals.", + "topicSet":"Setze das Thema des Ticket-Kanals.", + "topicValue":"Das neue Thema des Kanals.", + "topicList":"Zeige eine Liste aller Tickets mit ihrem Thema und Statistiken an.", + "priority":"Verwalte die Priorität des Tickets.", + "prioritySet":"Setze die Priorität des Tickets.", + "priorityValue":"Die Priorität des Kanals.", + "priorityGet":"Zeige die Priorität des Tickets an.", + "priorityList":"Zeige eine Liste aller Tickets mit ihrem Prioritätsstatus an.", + "transfer":"Übertrage das Ticket von einem Benutzer an einen anderen.", + "transferUser":"Der Benutzer, an den übertragen werden soll." }, "helpMenu":{ "help":"Erhalten Sie eine Liste mit allen verfügbaren Befehlen.", @@ -452,7 +532,16 @@ "autocloseDisable":"Deaktivieren Sie das automatische Schließen in diesem Ticket.", "autocloseEnable":"Aktivieren Sie das automatische Schließen in diesem Ticket.", "autodeleteDisable":"Deaktivieren Sie das automatische Löschen in diesem Ticket.", - "autodeleteEnable":"Aktivieren Sie das automatische Löschen in diesem Ticket." + "autodeleteEnable":"Aktivieren Sie das automatische Löschen in diesem Ticket.", + "categories":{ + "general":"Allgemeine Befehle", + "basicTicket":"Basis-Ticket-Befehle", + "advancedTicket":"Erweiterte Ticket-Befehle", + "userTicket":"Benutzer-Ticket-Befehle", + "admin":"Admin-Befehle", + "advanced":"Erweiterte Befehle", + "extra":"Extra-Befehle" + } }, "stats":{ "scopes":{ @@ -460,7 +549,8 @@ "system":"System-Statistiken", "user":"Benutzer-Statistiken", "ticket":"Ticket-Statistiken", - "participants":"Teilnehmer" + "participants":"Teilnehmer", + "messages":"Nachrichten" }, "properties":{ "ticketsCreated":"Tickets erstellt", @@ -472,7 +562,47 @@ "ticketsPinned":"Tickets angepinnt", "ticketsMoved":"Tickets verschoben", "usersBlacklisted":"Nutzer auf der Blacklist", - "transcriptsCreated":"Transcripts erstellt" + "transcriptsCreated":"Transcripts erstellt", + "ticketsAutodeleted":"Automatisch gelöschte Tickets", + "ticketsTransferred":"Übertragene Tickets", + "ticketVolume":"Ticket-Volumen", + "averageTickets":"Durchschnittliche Tickets/Benutzer", + "currentTickets":"Aktuelle Tickets", + "age":"Ticket-Alter", + "responseTime":"Antwortzeit", + "resolutionTime":"Lösungszeit", + "createdOn":"Erstellt am", + "createdBy":"Erstellt von", + "closedOn":"Geschlossen am", + "closedBy":"Geschlossen von", + "claimedOn":"Angenommen am", + "claimedBy":"Angenommen von", + "pinnedOn":"Angepinnt am", + "pinnedBy":"Angepinnt von", + "deletedOn":"Gelöscht am", + "deletedBy":"Gelöscht von" + }, + "roles":{ + "developer":"Entwickler", + "serverOwner":"Server-Besitzer", + "serverAdmin":"Server-Administrator", + "moderator":"Moderatoren-Team", + "support":"Support-Team", + "member":"Mitglied" } + }, + "panel":{ + "selectTicket":"Wähle dein Ticket", + "selectRole":"Wähle deine Rolle", + "selectOption":"Wähle deine Option" + }, + "priorities":{ + "urgent":"Dringend", + "veryHigh":"Sehr Hoch", + "high":"Hoch", + "normal":"Normal", + "low":"Niedrig", + "veryLow":"Sehr Niedrig", + "none":"Keine" } } \ No newline at end of file diff --git a/languages/greek.json b/languages/greek.json index 69c651d..73d5fb8 100644 --- a/languages/greek.json +++ b/languages/greek.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Greek", "automated":true }, diff --git a/languages/hindi.json b/languages/hindi.json index fe5212f..556c9fd 100644 --- a/languages/hindi.json +++ b/languages/hindi.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["challenger_nova"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Hindi", "automated":false }, diff --git a/languages/indonesian.json b/languages/indonesian.json index 38651c4..f02d8ee 100644 --- a/languages/indonesian.json +++ b/languages/indonesian.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["erxg"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Indonesian", "automated":false }, diff --git a/languages/japanese.json b/languages/japanese.json index bd1ff6c..3b8c067 100644 --- a/languages/japanese.json +++ b/languages/japanese.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Japanese", "automated":true }, diff --git a/languages/korean.json b/languages/korean.json index 1d1f9ea..b49fe2f 100644 --- a/languages/korean.json +++ b/languages/korean.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Korean", "automated":true }, diff --git a/languages/kurdish.json b/languages/kurdish.json index c2c8a86..457891f 100644 --- a/languages/kurdish.json +++ b/languages/kurdish.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Kurdish", "automated":false }, diff --git a/languages/simplified-chinese.json b/languages/simplified-chinese.json index 3e7894b..c8b9a00 100644 --- a/languages/simplified-chinese.json +++ b/languages/simplified-chinese.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Simplified Chainese", "automated":true }, diff --git a/languages/slovenian.json b/languages/slovenian.json index a7dae38..53ced9a 100644 --- a/languages/slovenian.json +++ b/languages/slovenian.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Solvenian", "automated":true }, diff --git a/languages/tamil.json b/languages/tamil.json index 1d72cf7..23c308c 100644 --- a/languages/tamil.json +++ b/languages/tamil.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["HanumeshGupta","ChatGPT"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Tamil", "automated":true }, diff --git a/languages/thai.json b/languages/thai.json index 7f47338..c474730 100644 --- a/languages/thai.json +++ b/languages/thai.json @@ -2,7 +2,7 @@ "_TRANSLATION":{ "otversion":"v4.1.1", "translators":["modshd"], - "lastedited":"16/11/2025", + "lastedited":"03/12/2025", "language":"Thai", "automated":false }, From 488b5fce5374723d2ea7ee6eae7793564b759beb Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Sat, 27 Dec 2025 10:42:10 +0100 Subject: [PATCH 2/8] Fixed fetch() errors of unknown guild members --- src/core/api/defaults/permission.ts | 5 +++-- src/core/api/modules/permission.ts | 10 +++++++--- src/core/api/openticket/option.ts | 10 +++++++++- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/core/api/defaults/permission.ts b/src/core/api/defaults/permission.ts index 23b4b02..2a67d3e 100644 --- a/src/core/api/defaults/permission.ts +++ b/src/core/api/defaults/permission.ts @@ -3,6 +3,7 @@ /////////////////////////////////////// import { ODDebugger } from "../modules/console" import { ODPermissionManager } from "../modules/permission" +import { ODClientManager_Default } from "./client" /**## ODPermissionManager_Default `default_class` * This is a special class that adds type definitions & typescript to the ODPermissionManager class. @@ -11,8 +12,8 @@ import { ODPermissionManager } from "../modules/permission" * This default class is made for the global variable `opendiscord.permissions`! */ export class ODPermissionManager_Default extends ODPermissionManager { - constructor(debug:ODDebugger){ - super(debug,true) + constructor(debug:ODDebugger,client:ODClientManager_Default){ + super(debug,client,true) } } diff --git a/src/core/api/modules/permission.ts b/src/core/api/modules/permission.ts index fbfd12b..5ae1d72 100644 --- a/src/core/api/modules/permission.ts +++ b/src/core/api/modules/permission.ts @@ -4,6 +4,7 @@ import { ODId, ODValidId, ODManager, ODSystemError, ODManagerData } from "./base" import * as discord from "discord.js" import { ODDebugger } from "./console" +import { ODClientManager } from "./client" /**## ODPermissionType `type` * All available permission types/levels. Can be used in the `ODPermission` class. @@ -111,6 +112,8 @@ export type ODPermissionCalculationCallback = (user:discord.User, channel?:disco export class ODPermissionManager extends ODManager { /**The function for calculating permissions in this manager. */ #calculation: ODPermissionCalculationCallback|null + /**An alias to the Open Discord client manager. */ + #client: ODClientManager /**The result which is returned when no other permissions match. (`member` by default) */ defaultResult: ODPermissionResult = { level:ODPermissionLevel["member"], @@ -119,9 +122,10 @@ export class ODPermissionManager extends ODManager { source:null } - constructor(debug:ODDebugger, useDefaultCalculation?:boolean){ + constructor(debug:ODDebugger, client:ODClientManager, useDefaultCalculation?:boolean){ super(debug,"permission") this.#calculation = useDefaultCalculation ? this.#defaultCalculation : null + this.#client = client } /**Edit the permission calculation function in this manager. */ @@ -193,7 +197,7 @@ export class ODPermissionManager extends ODManager { //check for global role permissions if (allowGlobalRoleScope){ if (guild){ - const member = await guild.members.fetch(user.id) + const member = await this.#client.fetchGuildMember(guild,user.id) if (member){ const memberRoles = member.roles.cache.map((role) => role.id) const roles = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "global-role" && (permission.value instanceof discord.Role) && memberRoles.includes(permission.value.id) && permission.value.guild.id == guild.id) @@ -256,7 +260,7 @@ export class ODPermissionManager extends ODManager { //check for channel role permissions if (allowChannelRoleScope){ - const member = await guild.members.fetch(user.id) + const member = await this.#client.fetchGuildMember(guild,user.id) if (member){ const memberRoles = member.roles.cache.map((role) => role.id) const roles = this.getFiltered((permission) => (!idRegex || (idRegex && idRegex.test(permission.id.value))) && permission.scope == "channel-role" && permission.channel && (permission.channel.id == channel.id) && (permission.value instanceof discord.Role) && memberRoles.includes(permission.value.id) && permission.value.guild.id == guild.id) diff --git a/src/core/api/openticket/option.ts b/src/core/api/openticket/option.ts index f5351a7..69d2be9 100644 --- a/src/core/api/openticket/option.ts +++ b/src/core/api/openticket/option.ts @@ -357,13 +357,21 @@ export class ODOptionSuffixManager extends ODManager { const suffix = this.getAll().find((suffix) => suffix.option.id.value == option.id.value) if (!suffix) return null try{ - const member = await guild.members.fetch(user.id) + const member = await this.#getMember(guild,user) + if (!member) return null return await suffix.getSuffix(member) }catch(err){ process.emit("uncaughtException",err) return null } } + async #getMember(guild:discord.Guild,user:discord.User){ + try{ + return await guild.members.fetch(user.id) + }catch{ + return null + } + } } /**## ODOptionSuffix `class` From b95b8f239eb39dd5ecf53aecb98df4bebf624feb Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Thu, 1 Jan 2026 23:00:29 +0100 Subject: [PATCH 3/8] Fixed typescript compilation error --- src/core/api/main.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/api/main.ts b/src/core/api/main.ts index 2849516..0019824 100644 --- a/src/core/api/main.ts +++ b/src/core/api/main.ts @@ -157,7 +157,7 @@ export class ODMain { this.responders = new ODResponderManager_Default(this.debug,this.client) this.actions = new ODActionManager_Default(this.debug) this.verifybars = new ODVerifyBarManager_Default(this.debug) - this.permissions = new ODPermissionManager_Default(this.debug) + this.permissions = new ODPermissionManager_Default(this.debug,this.client) this.cooldowns = new ODCooldownManager_Default(this.debug) this.helpmenu = new ODHelpMenuManager_Default(this.debug) this.stats = new ODStatsManager_Default(this.debug) From 24d98aeaebd7ee9983fa8986121f5db3aacd4e19 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Fri, 6 Feb 2026 17:45:31 +0100 Subject: [PATCH 4/8] (v4.1.2) Fixed autocomplete bug with many options --- README.md | 2 +- src/core/api/modules/responder.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0378ef7..979eb8f 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ With the amazing support of our translators, we've been able to translate Open T |🟢 |❓ Catalan |guillee3 | |🟢 |🇮🇩 Indonesian |erxg | |🟢 |🇮🇳 Hindi |challenger_nova | -|🟢⏳ |🇩🇪 German |benzorich | +|🟢 |🇩🇪 German |benzorich | |🟢⏳ |🇪🇸 Spanish |redactado & josuens | |🟢⏳ |🇫🇷 French |guillee.3 | |🟢⏳ |🇵🇹 Portuguese |quiradon | diff --git a/src/core/api/modules/responder.ts b/src/core/api/modules/responder.ts index dbe78ea..ce3bebe 100644 --- a/src/core/api/modules/responder.ts +++ b/src/core/api/modules/responder.ts @@ -1389,7 +1389,7 @@ export class ODAutocompleteResponderInstance { else return raw }) - const filteredChoices = newChoices.filter((choice) => choice.name.startsWith(this.target.value) || choice.value.toString().startsWith(this.target.value)) + const filteredChoices = newChoices.filter((choice) => choice.name.startsWith(this.target.value) || choice.value.toString().startsWith(this.target.value)).slice(0,25) return await this.autocomplete(filteredChoices) } } From 1f402a848e84766d9124c7ba1a9f93bed1e90bd1 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:08:55 +0100 Subject: [PATCH 5/8] (v4.1.2) Massive permission system cleanup --- src/actions/closeTicket.ts | 104 +++++---------- src/actions/deleteTicket.ts | 202 +++++++++-------------------- src/commands/add.ts | 48 ++----- src/commands/autoclose.ts | 51 +++----- src/commands/autodelete.ts | 49 +++---- src/commands/blacklist.ts | 49 ++----- src/commands/claim.ts | 49 +++---- src/commands/clear.ts | 46 ++----- src/commands/close.ts | 57 +++----- src/commands/delete.ts | 51 +++----- src/commands/help.ts | 50 ++----- src/commands/move.ts | 47 ++----- src/commands/panel.ts | 52 ++------ src/commands/pin.ts | 16 ++- src/commands/priority.ts | 49 +++---- src/commands/remove.ts | 48 ++----- src/commands/rename.ts | 48 ++----- src/commands/reopen.ts | 49 +++---- src/commands/role.ts | 5 +- src/commands/stats.ts | 28 +++- src/commands/ticket.ts | 126 ++++++------------ src/commands/topic.ts | 49 +++---- src/commands/transfer.ts | 48 ++----- src/commands/unclaim.ts | 49 +++---- src/commands/unpin.ts | 49 +++---- src/core/api/modules/permission.ts | 47 +++++++ 26 files changed, 504 insertions(+), 962 deletions(-) diff --git a/src/actions/closeTicket.ts b/src/actions/closeTicket.ts index 083a903..e09bb2c 100644 --- a/src/actions/closeTicket.ts +++ b/src/actions/closeTicket.ts @@ -169,62 +169,44 @@ 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:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.close - - 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:close-ticket",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + 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 (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) @@ -268,62 +250,44 @@ export const registerVerifyBars = async () => { //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:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.close - - 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:close-ticket",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + 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 (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) diff --git a/src/actions/deleteTicket.ts b/src/actions/deleteTicket.ts index 07d6996..68b0d16 100644 --- a/src/actions/deleteTicket.ts +++ b/src/actions/deleteTicket.ts @@ -119,8 +119,16 @@ 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:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.delete + 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){ @@ -130,54 +138,27 @@ export const registerVerifyBars = async () => { } } - 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 + //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 (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) @@ -224,8 +205,16 @@ export const registerVerifyBars = async () => { //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:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.delete + 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){ @@ -235,54 +224,27 @@ export const registerVerifyBars = async () => { } } - 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 + //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 (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) @@ -333,8 +295,16 @@ export const registerVerifyBars = async () => { //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:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.delete + 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){ @@ -344,54 +314,26 @@ export const registerVerifyBars = async () => { } } - 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 + //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 (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) @@ -442,8 +384,16 @@ export const registerVerifyBars = async () => { //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:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.delete + 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){ @@ -453,54 +403,26 @@ export const registerVerifyBars = async () => { } } - 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 + //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 (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) diff --git a/src/commands/add.ts b/src/commands/add.ts index ab68104..43d4b89 100644 --- a/src/commands/add.ts +++ b/src/commands/add.ts @@ -10,50 +10,30 @@ export const registerCommandResponders = async () => { //ADD COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:add",generalConfig.data.prefix,"add")) opendiscord.responders.commands.get("opendiscord:add").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.add - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:add",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.add,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check if in guild/Server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/commands/autoclose.ts b/src/commands/autoclose.ts index 6200479..bdf5a8b 100644 --- a/src/commands/autoclose.ts +++ b/src/commands/autoclose.ts @@ -10,62 +10,43 @@ export const registerCommandResponders = async () => { //AUTOCLOSE COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:autoclose",generalConfig.data.prefix,/^autoclose/)) opendiscord.responders.commands.get("opendiscord:autoclose").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.autoclose - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:autoclose",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.autoclose,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ - //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return } + //return when already closed if (ticket.get("opendiscord:closed").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) return cancel() } + //subcommands const scope = instance.options.getSubCommand() if (!scope || (scope != "disable" && scope != "enable")) return diff --git a/src/commands/autodelete.ts b/src/commands/autodelete.ts index acf4941..f912668 100644 --- a/src/commands/autodelete.ts +++ b/src/commands/autodelete.ts @@ -10,57 +10,38 @@ export const registerCommandResponders = async () => { //AUTODELETE COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:autodelete",generalConfig.data.prefix,/^autodelete/)) opendiscord.responders.commands.get("opendiscord:autodelete").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.autodelete - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:autodelete",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.autodelete,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) return cancel() } + //subcommands const scope = instance.options.getSubCommand() if (!scope || (scope != "disable" && scope != "enable")) return diff --git a/src/commands/blacklist.ts b/src/commands/blacklist.ts index b33c3fe..16e8548 100644 --- a/src/commands/blacklist.ts +++ b/src/commands/blacklist.ts @@ -10,49 +10,26 @@ export const registerCommandResponders = async () => { //BLACKLIST COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:blacklist",generalConfig.data.prefix,/^blacklist/)) opendiscord.responders.commands.get("opendiscord:blacklist").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.blacklist - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:blacklist",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.blacklist,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ - //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } + + //subcommands const scope = instance.options.getSubCommand() if (!scope || (scope != "add" && scope != "get" && scope != "remove" && scope != "view")) return - if (scope == "view"){ await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:blacklist-view").build(source,{guild,channel,user})) diff --git a/src/commands/claim.ts b/src/commands/claim.ts index d47aedb..72c2b6c 100644 --- a/src/commands/claim.ts +++ b/src/commands/claim.ts @@ -10,55 +10,36 @@ export const registerCommandResponders = async () => { //CLAIM COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:claim",generalConfig.data.prefix,"claim")) opendiscord.responders.commands.get("opendiscord:claim").workers.add([ - new api.ODWorker("opendiscord: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(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:claim",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.claim,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when already claimed if (ticket.get("opendiscord:claimed").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.claim"),layout:"simple"})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/commands/clear.ts b/src/commands/clear.ts index 3eb7b66..1de6e25 100644 --- a/src/commands/clear.ts +++ b/src/commands/clear.ts @@ -10,42 +10,18 @@ export const registerCommandResponders = async () => { //CLEAR COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:clear",generalConfig.data.prefix,"clear")) opendiscord.responders.commands.get("opendiscord:clear").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.clear - - 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"){ - //only allow global admins (ticket admins aren't allowed to clear tickets) - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild,{allowChannelUserScope:false,allowChannelRoleScope:false}))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:clear",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions (only allow global admins: ticket admins aren't allowed to clear tickets) + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.clear,"support",user,member,channel,guild,{allowChannelUserScope:false,allowChannelRoleScope:false}) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() diff --git a/src/commands/close.ts b/src/commands/close.ts index 8aac86a..8f2c01b 100644 --- a/src/commands/close.ts +++ b/src/commands/close.ts @@ -11,62 +11,44 @@ export const registerCommandResponders = async () => { //CLOSE COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:close",generalConfig.data.prefix,"close")) opendiscord.responders.commands.get("opendiscord:close").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.close - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:close",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.close,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when already closed if (ticket.get("opendiscord:closed").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.close"),layout:"simple"})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) return cancel() } + //return when not allowed because of missing messages - if (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) @@ -77,11 +59,10 @@ export const registerCommandResponders = async () => { return cancel() } } - - const reason = instance.options.getString("reason",false) - + //start closing ticket await instance.defer(false) + const reason = instance.options.getString("reason",false) await opendiscord.actions.get("opendiscord:close-ticket").run(source,{guild,channel,user,ticket,reason,sendMessage:false}) await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:close-message").build(source,{guild,channel,user,ticket,reason})) }), diff --git a/src/commands/delete.ts b/src/commands/delete.ts index 24ea2ec..ebe4c32 100644 --- a/src/commands/delete.ts +++ b/src/commands/delete.ts @@ -11,57 +11,38 @@ export const registerCommandResponders = async () => { //DELETE COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:delete",generalConfig.data.prefix,"delete")) opendiscord.responders.commands.get("opendiscord:delete").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.delete - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:delete",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.delete,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) return cancel() } + //return when not allowed because of missing messages - if (!generalConfig.data.system.allowCloseBeforeMessage || !generalConfig.data.system.allowCloseBeforeAdminMessage){ + 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")})) diff --git a/src/commands/help.ts b/src/commands/help.ts index 3679785..a8eb799 100644 --- a/src/commands/help.ts +++ b/src/commands/help.ts @@ -10,47 +10,21 @@ export const registerCommandResponders = async () => { //HELP COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:help",generalConfig.data.prefix,"help")) opendiscord.responders.commands.get("opendiscord:help").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.help - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:help",0,async (instance,params,source,cancel) => { - const preferSlashOverText = generalConfig.data.system.preferSlashOverText + const {guild,channel,user,member} = instance + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.help,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //calculate slash/text mode for help menu let mode: "slash"|"text" - if (generalConfig.data.slashCommands && generalConfig.data.textCommands){ - mode = (preferSlashOverText) ? "slash" : "text" - - }else if (!generalConfig.data.slashCommands) mode = "text" + if (generalConfig.data.slashCommands && generalConfig.data.textCommands) mode = (generalConfig.data.system.preferSlashOverText) ? "slash" : "text" + else if (!generalConfig.data.slashCommands) mode = "text" else mode = "slash" await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:help-menu").build(source,{mode,page:0})) diff --git a/src/commands/move.ts b/src/commands/move.ts index 3a63498..93ad8ed 100644 --- a/src/commands/move.ts +++ b/src/commands/move.ts @@ -10,45 +10,24 @@ export const registerCommandResponders = async () => { //MOVE COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:move",generalConfig.data.prefix,"move")) opendiscord.responders.commands.get("opendiscord:move").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.move - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:move",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.move,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check if in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) diff --git a/src/commands/panel.ts b/src/commands/panel.ts index 22218db..cb84407 100644 --- a/src/commands/panel.ts +++ b/src/commands/panel.ts @@ -10,56 +10,30 @@ export const registerCommandResponders = async () => { //PANEL COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:panel",generalConfig.data.prefix,/^panel/)) opendiscord.responders.commands.get("opendiscord:panel").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.panel - - //command is disabled - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:panel",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.panel,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild || instance.channel.type == discord.ChannelType.GroupDM){ - //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } + //get panel data const id = instance.options.getString("id",true) const panel = opendiscord.panels.get(id) - if (!panel){ - //invalid panel instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-panel-unknown").build(source,{guild,channel,user})) return cancel() - } + } await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:panel-ready").build(source,{guild,channel,user,panel})) const panelMessage = await instance.channel.send((await opendiscord.builders.messages.getSafe("opendiscord:panel").build(source,{guild,channel,user,panel})).message) diff --git a/src/commands/pin.ts b/src/commands/pin.ts index e58858f..f1a8499 100644 --- a/src/commands/pin.ts +++ b/src/commands/pin.ts @@ -44,21 +44,35 @@ export const registerCommandResponders = async () => { } }), new api.ODWorker("opendiscord:pin",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.pin,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when already pinned if (ticket.get("opendiscord:pinned").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.pin"),layout:"simple"})) return cancel() } + //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})) diff --git a/src/commands/priority.ts b/src/commands/priority.ts index cbf6744..39812ca 100644 --- a/src/commands/priority.ts +++ b/src/commands/priority.ts @@ -10,56 +10,37 @@ export const registerCommandResponders = async () => { //PRIORITY COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:priority",generalConfig.data.prefix,"priority")) opendiscord.responders.commands.get("opendiscord:priority").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.priority - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:priority",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.priority,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) return cancel() } + //subcommands const scope = instance.options.getSubCommand() if (!scope || (scope != "set" && scope != "get")) return diff --git a/src/commands/remove.ts b/src/commands/remove.ts index 6e71533..c6ec472 100644 --- a/src/commands/remove.ts +++ b/src/commands/remove.ts @@ -10,50 +10,30 @@ export const registerCommandResponders = async () => { //REMOVE COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:remove",generalConfig.data.prefix,"remove")) opendiscord.responders.commands.get("opendiscord:remove").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.remove - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:remove",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.remove,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //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})) diff --git a/src/commands/rename.ts b/src/commands/rename.ts index f84740d..7bbee26 100644 --- a/src/commands/rename.ts +++ b/src/commands/rename.ts @@ -10,50 +10,30 @@ export const registerCommandResponders = async () => { //RENAME COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:rename",generalConfig.data.prefix,"rename")) opendiscord.responders.commands.get("opendiscord:rename").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.rename - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:rename",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.rename,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/commands/reopen.ts b/src/commands/reopen.ts index f398aec..fb86a30 100644 --- a/src/commands/reopen.ts +++ b/src/commands/reopen.ts @@ -10,55 +10,36 @@ export const registerCommandResponders = async () => { //REOPEN COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:reopen",generalConfig.data.prefix,"reopen")) opendiscord.responders.commands.get("opendiscord:reopen").workers.add([ - new api.ODWorker("opendiscord: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(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:reopen",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {guild,channel,user,member} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.reopen,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when not closed if (!ticket.get("opendiscord:closed").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.reopen"),layout:"simple"})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/commands/role.ts b/src/commands/role.ts index 0081df6..e9de633 100644 --- a/src/commands/role.ts +++ b/src/commands/role.ts @@ -12,13 +12,14 @@ export const registerButtonResponders = async () => { opendiscord.responders.buttons.get("opendiscord:role-option").workers.add( new api.ODWorker("opendiscord:role-option",0,async (instance,params,source,cancel) => { const {guild,channel,user} = instance + + //check is in guild/server if (!guild){ - //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } - //get option + //get option data const optionId = instance.interaction.customId.split("_")[2] const option = opendiscord.options.get(optionId) if (!option || !(option instanceof api.ODRoleOption)){ diff --git a/src/commands/stats.ts b/src/commands/stats.ts index c308c3f..46be1fb 100644 --- a/src/commands/stats.ts +++ b/src/commands/stats.ts @@ -57,12 +57,36 @@ export const registerCommandResponders = async () => { } }), new api.ODWorker("opendiscord:stats",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + if (generalConfig.data.system.permissions.stats === "none"){ + //command is disabled + instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) + return cancel() + + }else if (instance.options.getSubCommand() === "reset" && !opendiscord.permissions.hasPermissions("owner",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ + //reset --> owner/developer role is required + instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["owner","developer"]})) + return cancel() + + }else{ + //default permissions check + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.stats,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + } + + //check is in guild/server if (!guild){ - //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } + + //subcommands const scope = instance.options.getSubCommand() if (!scope || (scope != "global" && scope != "ticket" && scope != "user" && scope != "reset")) return diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts index 45fcddb..055dc1d 100644 --- a/src/commands/ticket.ts +++ b/src/commands/ticket.ts @@ -7,52 +7,46 @@ import * as discord from "discord.js" const generalConfig = opendiscord.configs.get("opendiscord:general") const lang = opendiscord.languages +async function checkTicketCreationPerms(instance:api.ODButtonResponderInstance|api.ODDropdownResponderInstance|api.ODModalResponderInstance|api.ODCommandResponderInstance,source:api.ODActionManagerIds_Default["opendiscord:create-ticket-permissions"]["source"],guild:discord.Guild,user:discord.User,option:api.ODTicketOption){ + //check ticket permissions + const permsRes = await opendiscord.actions.get("opendiscord:create-ticket-permissions").run(source,{guild,user,option}) + if (!permsRes.valid && instance.channel){ + //error + const newSource = (source === "slash" || source === "text") ? source : "other" + if (permsRes.reason == "blacklist") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-blacklisted").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user})) + else if (permsRes.reason == "cooldown") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-cooldown").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,until:permsRes.cooldownUntil})) + else if (permsRes.reason == "global-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global"})) + else if (permsRes.reason == "global-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global-user"})) + else if (permsRes.reason == "option-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option"})) + else if (permsRes.reason == "option-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option-user"})) + else if (permsRes.reason == "custom") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,layout:"simple",error:permsRes.customReason ?? lang.getTranslation("errors.descriptions.unableToCreateTicket")+" `Unknown invalid_permission_reason => no reason specified by plugin`",customTitle:lang.getTranslation("errors.titles.permissionError")})) + else instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(newSource,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Unknown invalid_permission reason => calculation failed #1",layout:"advanced"})) + return false + }else return true +} + export const registerCommandResponders = async () => { //TICKET COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:ticket",generalConfig.data.prefix,/^ticket/)) opendiscord.responders.commands.get("opendiscord:ticket").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.ticket - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:ticket",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.ticket,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/server if (!guild){ - //error instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build(source,{channel:instance.channel,user:instance.user})) return cancel() } - //get option + //get option data const optionId = instance.options.getString("id",true) const option = opendiscord.options.get(optionId) if (!option || !(option instanceof api.ODTicketOption)){ @@ -61,26 +55,14 @@ export const registerCommandResponders = async () => { return cancel() } - //check ticket permissions - const res = await opendiscord.actions.get("opendiscord:create-ticket-permissions").run(source,{guild,user,option}) - if (!res.valid){ - //error - if (res.reason == "blacklist") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-blacklisted").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user})) - else if (res.reason == "cooldown") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-cooldown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,until:res.cooldownUntil})) - else if (res.reason == "global-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global"})) - else if (res.reason == "global-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global-user"})) - else if (res.reason == "option-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option"})) - else if (res.reason == "option-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option-user"})) - else if (res.reason == "custom") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,layout:"simple",error:res.customReason ?? lang.getTranslation("errors.descriptions.unableToCreateTicket")+" `Unknown invalid_permission_reason => no reason specified by plugin`",customTitle:lang.getTranslation("errors.titles.permissionError")})) - else instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Unknown invalid_permission reason => calculation failed #1",layout:"advanced"})) - return cancel() - } - //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //send modal instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build(source,{guild,channel,user,option})) }else{ + //check ticket permissions + if (!checkTicketCreationPerms(instance,source,guild,user,option)) return cancel() + //create ticket await instance.defer(true) const res = await opendiscord.actions.get("opendiscord:create-ticket").run(source,{guild,user,answers:[],option}) @@ -124,26 +106,14 @@ export const registerButtonResponders = async () => { return cancel() } - //check ticket permissions - const res = await opendiscord.actions.get("opendiscord:create-ticket-permissions").run("panel-button",{guild,user,option}) - if (!res.valid){ - //error - if (res.reason == "blacklist") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-blacklisted").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user})) - else if (res.reason == "cooldown") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-cooldown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,until:res.cooldownUntil})) - else if (res.reason == "global-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global"})) - else if (res.reason == "global-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global-user"})) - else if (res.reason == "option-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option"})) - else if (res.reason == "option-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option-user"})) - else if (res.reason == "custom") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,layout:"simple",error:res.customReason ?? lang.getTranslation("errors.descriptions.unableToCreateTicket")+" `Unknown invalid_permission_reason => no reason specified by plugin`",customTitle:lang.getTranslation("errors.titles.permissionError")})) - else instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Unknown invalid_permission reason => calculation failed #1",layout:"advanced"})) - return cancel() - } - //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //send modal instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option})) }else{ + //check ticket permissions + if (!checkTicketCreationPerms(instance,"panel-button",guild,user,option)) return cancel() + //create ticket await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) @@ -180,26 +150,14 @@ export const registerDropdownResponders = async () => { return cancel() } - //check ticket permissions - const res = await opendiscord.actions.get("opendiscord:create-ticket-permissions").run("panel-dropdown",{guild,user,option}) - if (!res.valid){ - //error - if (res.reason == "blacklist") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-blacklisted").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user})) - else if (res.reason == "cooldown") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-cooldown").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,until:res.cooldownUntil})) - else if (res.reason == "global-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global"})) - else if (res.reason == "global-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"global-user"})) - else if (res.reason == "option-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option"})) - else if (res.reason == "option-user-limit") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions-limits").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,limit:"option-user"})) - else if (res.reason == "custom") instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,layout:"simple",error:res.customReason ?? lang.getTranslation("errors.descriptions.unableToCreateTicket")+" `Unknown invalid_permission_reason => no reason specified by plugin`",customTitle:lang.getTranslation("errors.titles.permissionError")})) - else instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Unknown invalid_permission reason => calculation failed #1",layout:"advanced"})) - return cancel() - } - //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //send modal instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option})) }else{ + //check ticket permissions + if (!checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option)) return cancel() + //create ticket await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) @@ -229,6 +187,7 @@ export const registerModalResponders = async () => { opendiscord.responders.modals.get("opendiscord:ticket-questions").workers.add([ new api.ODWorker("opendiscord:ticket-questions",0,async (instance,params,source,cancel) => { const {guild,channel,user} = instance + await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) if (!channel) throw new api.ODSystemError("The 'Ticket Questions' modal requires a channel for responding!") if (!guild){ //error @@ -247,6 +206,9 @@ export const registerModalResponders = async () => { return cancel() } + //check ticket permissions + if (!checkTicketCreationPerms(instance,originalSource,guild,user,option)) return cancel() + //get answers const answers: {id:string,name:string,type:"short"|"paragraph",value:string|null}[] = [] option.get("opendiscord:questions").value.forEach((id) => { @@ -270,8 +232,6 @@ export const registerModalResponders = async () => { }) //create ticket - await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) - const res = await opendiscord.actions.get("opendiscord:create-ticket").run(originalSource,{guild,user,answers,option}) if (!res.channel || !res.ticket){ //error diff --git a/src/commands/topic.ts b/src/commands/topic.ts index f8423c7..79992c2 100644 --- a/src/commands/topic.ts +++ b/src/commands/topic.ts @@ -10,56 +10,37 @@ export const registerCommandResponders = async () => { //TOPIC COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:topic",generalConfig.data.prefix,"topic")) opendiscord.responders.commands.get("opendiscord:topic").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.topic - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:topic",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.topic,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/Server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) return cancel() } + //subcommands const scope = instance.options.getSubCommand() if (!scope || (scope != "set")) return diff --git a/src/commands/transfer.ts b/src/commands/transfer.ts index 18c8c8b..5aa2298 100644 --- a/src/commands/transfer.ts +++ b/src/commands/transfer.ts @@ -10,50 +10,30 @@ export const registerCommandResponders = async () => { //TRANSFER COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:transfer",generalConfig.data.prefix,"transfer")) opendiscord.responders.commands.get("opendiscord:transfer").workers.add([ - new api.ODWorker("opendiscord:permissions",1,async (instance,params,source,cancel) => { - const permissionMode = generalConfig.data.system.permissions.transfer - - if (permissionMode == "none"){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build("button",{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else if (permissionMode == "everyone") return - else if (permissionMode == "admin"){ - if (!opendiscord.permissions.hasPermissions("support",await opendiscord.permissions.getPermissions(instance.user,instance.channel,instance.guild))){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:transfer",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.transfer,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/Server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/commands/unclaim.ts b/src/commands/unclaim.ts index 0cdec44..73cb608 100644 --- a/src/commands/unclaim.ts +++ b/src/commands/unclaim.ts @@ -10,55 +10,36 @@ export const registerCommandResponders = async () => { //UNCLAIM COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:unclaim",generalConfig.data.prefix,"unclaim")) opendiscord.responders.commands.get("opendiscord:unclaim").workers.add([ - new api.ODWorker("opendiscord: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(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:unclaim",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.unclaim,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/Server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when not claimed if (!ticket.get("opendiscord:claimed").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unclaim"),layout:"simple"})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/commands/unpin.ts b/src/commands/unpin.ts index 06095ca..30a9579 100644 --- a/src/commands/unpin.ts +++ b/src/commands/unpin.ts @@ -10,55 +10,36 @@ export const registerCommandResponders = async () => { //UNPIN COMMAND RESPONDER opendiscord.responders.commands.add(new api.ODCommandResponder("opendiscord:unpin",generalConfig.data.prefix,"unpin")) opendiscord.responders.commands.get("opendiscord:unpin").workers.add([ - new api.ODWorker("opendiscord: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(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:["support"]})) - return cancel() - }else return - }else{ - if (!instance.guild || !instance.member){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #1",layout:"advanced"})) - return cancel() - } - const role = await opendiscord.client.fetchGuildRole(instance.guild,permissionMode) - if (!role){ - //error - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,error:"Permission Error: Not in Server #2",layout:"advanced"})) - return cancel() - } - if (!role.members.has(instance.member.id)){ - //no permissions - instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild:instance.guild,channel:instance.channel,user:instance.user,permissions:[]})) - return cancel() - }else return - } - }), new api.ODWorker("opendiscord:unpin",0,async (instance,params,source,cancel) => { - const {guild,channel,user} = instance + const {user,member,channel,guild} = instance + + //check permissions + const permsResult = await opendiscord.permissions.checkCommandPerms(generalConfig.data.system.permissions.unpin,"support",user,member,channel,guild) + if (!permsResult.hasPerms){ + if (permsResult.reason == "not-in-server") await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) + else await instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-no-permissions").build(source,{guild,channel,user,permissions:["support"]})) + return cancel() + } + + //check is in guild/Server if (!guild){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-not-in-guild").build("button",{channel,user})) return cancel() } + + //check if ticket exists const ticket = opendiscord.tickets.get(channel.id) if (!ticket || channel.isDMBased()){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-unknown").build("button",{guild,channel,user})) return cancel() } + //return when not pinned yet if (!ticket.get("opendiscord:pinned").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error").build("button",{guild,channel,user,error:opendiscord.languages.getTranslation("errors.actionInvalid.unpin"),layout:"simple"})) return cancel() } + //return when busy if (ticket.get("opendiscord:busy").value){ instance.reply(await opendiscord.builders.messages.getSafe("opendiscord:error-ticket-busy").build("button",{guild,channel,user})) diff --git a/src/core/api/modules/permission.ts b/src/core/api/modules/permission.ts index 5ae1d72..4b4f883 100644 --- a/src/core/api/modules/permission.ts +++ b/src/core/api/modules/permission.ts @@ -101,6 +101,20 @@ export interface ODPermissionSettings { */ export type ODPermissionCalculationCallback = (user:discord.User, channel?:discord.Channel|null, guild?:discord.Guild|null, settings?:ODPermissionSettings|null) => Promise +/**## ODPermissionCommandResult `type` + * The result of calculating permissions for a command. + */ +export type ODPermissionCommandResult = { + /**Returns `true` when the user has valid permissions. */ + hasPerms:false, + reason:"no-perms"|"disabled"|"not-in-server" +}|{ + /**Returns `true` when the user has valid permissions. */ + hasPerms:true, + /**Is the user a server admin or a normal member? This does not decide if the user has permissions or not. */ + isAdmin:boolean +} + /**## ODPermissionManager `class` * This is an Open Ticket permission manager. * @@ -110,6 +124,8 @@ export type ODPermissionCalculationCallback = (user:discord.User, channel?:disco * Add new permissions using the `ODPermission` class in your plugin! */ export class ODPermissionManager extends ODManager { + /**Alias for Open Ticket debugger. */ + #debug: ODDebugger /**The function for calculating permissions in this manager. */ #calculation: ODPermissionCalculationCallback|null /**An alias to the Open Discord client manager. */ @@ -124,6 +140,7 @@ export class ODPermissionManager extends ODManager { constructor(debug:ODDebugger, client:ODClientManager, useDefaultCalculation?:boolean){ super(debug,"permission") + this.#debug = debug this.#calculation = useDefaultCalculation ? this.#defaultCalculation : null this.#client = client } @@ -290,4 +307,34 @@ export class ODPermissionManager extends ODManager { //spread result to prevent accidental modification because of referencing return {...this.defaultResult} } + + /**Check the permissions for a certain command of the bot. */ + async checkCommandPerms(permissionMode:string,requiredLevel:ODPermissionType,user:discord.User,member?:discord.GuildMember|null,channel?:discord.Channel|null,guild?:discord.Guild|null,settings?:ODPermissionSettings): Promise { + if (permissionMode === "none"){ + return {hasPerms:false,reason:"disabled"} + + }else if (permissionMode === "everyone"){ + const isAdmin = this.hasPermissions(requiredLevel,await this.getPermissions(user,channel,guild,settings)) + return {hasPerms:true,isAdmin} + + }else if (permissionMode === "admin"){ + const isAdmin = this.hasPermissions(requiredLevel,await this.getPermissions(user,channel,guild,settings)) + if (!isAdmin) return {hasPerms:false,reason:"no-perms"} + else return {hasPerms:true,isAdmin} + }else{ + if (!guild || !member){ + this.#debug.debug("ODPermissionManager.checkCommandPerms(): Permission Error, Not in server! (#1)") + return {hasPerms:false,reason:"not-in-server"} + } + const role = await this.#client.fetchGuildRole(guild,permissionMode) + if (!role){ + this.#debug.debug("ODPermissionManager.checkCommandPerms(): Permission Error, Not in server! (#2)") + return {hasPerms:false,reason:"not-in-server"} + } + if (!role.members.has(member.id)) return {hasPerms:false,reason:"no-perms"} + + const isAdmin = this.hasPermissions(requiredLevel,await this.getPermissions(user,channel,guild,settings)) + return {hasPerms:true,isAdmin} + } + } } \ No newline at end of file From 6a4f40d862889f76f999c3a3d13bbd92bd2a1b50 Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:48:21 +0100 Subject: [PATCH 6/8] (v4.1.2) Readme updates & general improvements --- .docs/mergeTranslations.js | 2 +- .eggs/README.md | 7 +++- .eggs/openticket-egg-v4.1.2.json | 62 +++++++++++++++++++++++++++++++ .github/CONTRIBUTING.md | 4 +- .github/SECURITY.md | 21 ++++++----- LICENSE.md | 2 +- README.md | 14 ++++--- config/general.json | 2 +- config/panels.json | 2 +- index.js | 2 +- languages/arabic.json | 2 +- languages/bengali.json | 2 +- languages/catalan.json | 2 +- languages/custom.json | 2 +- languages/czech.json | 2 +- languages/danish.json | 2 +- languages/dutch.json | 2 +- languages/english.json | 2 +- languages/estonian.json | 2 +- languages/finnish.json | 2 +- languages/french.json | 2 +- languages/german.json | 2 +- languages/greek.json | 2 +- languages/hindi.json | 2 +- languages/hungarian.json | 2 +- languages/indonesian.json | 2 +- languages/italian.json | 2 +- languages/japanese.json | 2 +- languages/korean.json | 2 +- languages/kurdish.json | 2 +- languages/latvian.json | 2 +- languages/lithuanian.json | 2 +- languages/norwegian.json | 2 +- languages/persian.json | 2 +- languages/polish.json | 2 +- languages/portuguese.json | 2 +- languages/romanian.json | 2 +- languages/russian.json | 2 +- languages/simplified-chinese.json | 2 +- languages/slovenian.json | 2 +- languages/spanish.json | 2 +- languages/swedish.json | 2 +- languages/tamil.json | 2 +- languages/thai.json | 2 +- languages/turkish.json | 2 +- languages/ukrainian.json | 2 +- languages/vietnamese.json | 2 +- package.json | 2 +- src/core/api/main.ts | 2 +- src/core/api/modules/base.ts | 8 ++-- src/core/startup/migration.ts | 3 ++ src/index.ts | 2 +- 52 files changed, 141 insertions(+), 68 deletions(-) create mode 100644 .eggs/openticket-egg-v4.1.2.json diff --git a/.docs/mergeTranslations.js b/.docs/mergeTranslations.js index deb9ca8..0854ee2 100644 --- a/.docs/mergeTranslations.js +++ b/.docs/mergeTranslations.js @@ -643,7 +643,7 @@ for (const language of fs.readdirSync(".docs/languages/")){ } } original["_TRANSLATION"]["lastedited"] = new Date().toLocaleDateString("nl-BE",{day:"2-digit",month:"2-digit",year:"numeric"}) - original["_TRANSLATION"]["otversion"] = "v4.1.1" + original["_TRANSLATION"]["otversion"] = "v4.1.2" const finalText = formatter.stringify(original) fs.writeFileSync("./languages/"+language,finalText) } \ No newline at end of file diff --git a/.eggs/README.md b/.eggs/README.md index f35f3f7..79d6bb1 100644 --- a/.eggs/README.md +++ b/.eggs/README.md @@ -2,7 +2,7 @@ Open Ticket Logo [![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) -[![version](https://img.shields.io/badge/version-4.1.1-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.1) +[![version](https://img.shields.io/badge/version-4.1.2-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.2) [![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj) [![Open Ticket supports Pterodactyl Eggs!](https://img.shields.io/badge/pterodactyl-supported-10539F?style=flat-square&logo=pterodactyl)](.eggs/README.md) @@ -20,6 +20,9 @@ It's recommended to provide at least `1GB` of **Memory/RAM** and `5GB` of **disk [**`openticket-egg-main.json` (Recommended)**](openticket-egg-main.json) - This egg will use the `main` branch of Open Ticket. +[**`openticket-egg-v4.1.2.json`**](openticket-egg-v4.1.2.json) +- This egg will always use Open Ticket `v4.1.2`. Open Ticket updates will not have an effect on this egg. + [**`openticket-egg-v4.1.1.json`**](openticket-egg-v4.1.1.json) - This egg will always use Open Ticket `v4.1.1`. Open Ticket updates will not have an effect on this egg. @@ -41,4 +44,4 @@ It's recommended to provide at least `1GB` of **Memory/RAM** and `5GB` of **disk **Pterodactyl Eggs**
[Changelog](https://otgithub.dj-dj.be/releases) - [Documentation](https://otdocs.dj-dj.be) - [Website](https://openticket.dj-dj.be) - [Support Server](https://discord.dj-dj.be) - [License](./LICENSE.md)
-© 2025 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) \ No newline at end of file +© 2021 - 2026 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) \ No newline at end of file diff --git a/.eggs/openticket-egg-v4.1.2.json b/.eggs/openticket-egg-v4.1.2.json new file mode 100644 index 0000000..45d81a3 --- /dev/null +++ b/.eggs/openticket-egg-v4.1.2.json @@ -0,0 +1,62 @@ +{ + "_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO", + "meta": { + "version": "PTDL_v2", + "update_url": null + }, + "exported_at": "2025-03-16T18:10:18+01:00", + "name": "Open Ticket (v4.1.2)", + "author": "support@dj-dj.be", + "description": "This is the official Pterodactyl egg for Open Ticket v4.1.2, 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.1.2)\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.1.2\"\r\n\r\nif [ \"$(ls -A \/mnt\/server)\" ]; then\r\n echo -e \"[OT INSTALLER] \/mnt\/server directory is not empty.\"\r\n if [ -d .git ]; then\r\n echo -e \"[OT INSTALLER] .git directory exists\"\r\n if [ -f .git\/config ]; then\r\n echo -e \"[OT INSTALLER] loading info from git config\"\r\n ORIGIN=$(git config --get remote.origin.url)\r\n else\r\n echo -e \"[OT INSTALLER] files found with no git config\"\r\n echo -e \"[OT INSTALLER] closing out without touching things to not break anything\"\r\n exit 10\r\n fi\r\n fi\r\n\r\n if [ \"${ORIGIN}\" == \"https:\/\/github.com\/open-discord-bots\/open-ticket.git\" ]; then\r\n echo \"pulling latest from github\"\r\n git pull\r\n fi\r\nelse\r\n echo -e \"[OT INSTALLER] \/mnt\/server is empty.\"\r\n echo -e \"[OT INSTALLER] cloning files into repo.\"\r\n if [ -z ${BRANCH} ]; then\r\n echo -e \"[OT INSTALLER] cloning default branch\"\r\n git clone https:\/\/github.com\/open-discord-bots\/open-ticket.git .\r\n else\r\n echo -e \"[OT INSTALLER] cloning ${BRANCH}'\"\r\n git clone --single-branch --branch ${BRANCH} https:\/\/github.com\/open-discord-bots\/open-ticket.git .\r\n fi\r\nfi\r\n\r\necho -e \"[OT INSTALLER] installing Open Ticket node.js packages.\"\r\nif [ -f \/mnt\/server\/package.json ]; then\r\n \/usr\/local\/bin\/npm install --omit=dev\r\nfi\r\n\r\necho -e \"[OT INSTALLER] installing custom node.js packages.\"\r\nif [[ ! -z ${NODE_PACKAGES} ]]; then\r\n \/usr\/local\/bin\/npm install ${NODE_PACKAGES}\r\nfi\r\n\r\necho -e \"[OT INSTALLER] install complete!\"\r\nexit 0", + "container": "node:latest", + "entrypoint": "bash" + } + }, + "variables": [ + { + "name": "Additional Npm Packages", + "description": "Specify additional npm packages used by Open Ticket plugins. Use spaces to separate.", + "env_variable": "NODE_PACKAGES", + "default_value": "", + "user_viewable": false, + "user_editable": true, + "rules": "string|nullable", + "field_type": "text" + }, + { + "name": "Startup Flags", + "description": "Start the bot with additional Open Ticket flags. Separate using spaces.\r\nA full reference list can be found in the documentation.", + "env_variable": "NODE_FLAGS", + "default_value": "", + "user_viewable": false, + "user_editable": true, + "rules": "string|nullable", + "field_type": "text" + }, + { + "name": "Uninstall Npm Packages", + "description": "A list of npm packages to uninstall. Separate by spaces.", + "env_variable": "UNNODE_PACKAGES", + "default_value": "", + "user_viewable": false, + "user_editable": true, + "rules": "string|nullable", + "field_type": "text" + } + ] +} \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e583f05..f385196 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing Guidelines Open Ticket Logo -[![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-4.1.1-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.1) [![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj) +[![discord](https://img.shields.io/badge/discord-support%20server-5865F2.svg?style=flat-square&logo=discord)](https://discord.com/invite/26vT9wt3n3) [![version](https://img.shields.io/badge/version-4.1.2-brightgreen.svg?style=flat-square)](https://github.com/open-discord-bots/open-ticket/releases/tag/v4.1.2) [![Sponsor DJj123dj](https://img.shields.io/badge/sponsor-DJj123dj-ea4aaa?style=flat-square&logo=githubsponsors)](https://github.com/sponsors/DJj123dj) These are the Contributing Guidelines of Open Ticket!
Here you can find everything you need to know about contributing to Open Ticket.
@@ -89,4 +89,4 @@ you are **REQUIRED to send the bug privately via one of the following methods:** **Contributing Guidelines**
[Changelog](https://otgithub.dj-dj.be/releases) - [Documentation](https://otdocs.dj-dj.be) - [Website](https://openticket.dj-dj.be) - [Support Server](https://discord.dj-dj.be) - [License](./LICENSE.md)
-© 2025 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) \ No newline at end of file +© 2021 - 2026 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) \ No newline at end of file diff --git a/.github/SECURITY.md b/.github/SECURITY.md index f9216c0..0d27c2d 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -14,20 +14,21 @@ This list will be updated on every release. - 🟦 In Development **(ideas, bugs, support, html transcripts)** - ✅ Supported **(features, bugs, support, docs, html transcripts)** - 🚧 Maintenance **(support, docs, html transcripts)** -- 🟧 Deprecated **(docs)** +- 🟧 Deprecated **(docs only)** - ❌ Fully Deprecated | Version | Supported | Notes | |------------|-----------|---------------------------------------------------------------| -| 4.2.0 | 🟦 | Transcripts v2.0 will be inaccessible when v4.2 is released. | -| 4.1.2 | 🟦 | | -| 4.1.1 | ✅ | | -| 4.1.0 | ✅ | | -| 4.0.7 | ✅ | Supported Until December 2025 (LTS) | +| 4.2.0 | 🟦 | In Development | +| 4.1.x | 🟦 | In Development | +| 4.1.2 | ✅ | | +| 4.1.1 | ✅ | Supported Until April 2026 (LTS) | +| 4.1.0 | 🚧 | | +| 4.0.7 | 🚧 | | | 4.0.6 | 🚧 | | -| 4.0.5 | 🚧 | | -| 4.0.4 | 🚧 | | -| < 4.0.4 | 🟧 | Deprecated Transcripts v2.0, Documentation Only | +| 4.0.5 | 🟧 | Deprecated | +| 4.0.4 | 🟧 | Deprecated | +| < 4.0.4 | 🟧 | Deprecated, Transcripts v2.0, Documentation Only | | < 4.0.0 | ❌ | | ### 🕷️ Reporting Vulnerabilities @@ -50,4 +51,4 @@ If possible, try to provide screenshots! **Security Policy**
[Changelog](https://otgithub.dj-dj.be/releases) - [Documentation](https://otdocs.dj-dj.be) - [Website](https://openticket.dj-dj.be) - [Support Server](https://discord.dj-dj.be) - [License](./LICENSE.md)
-© 2025 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) \ No newline at end of file +© 2021 - 2026 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md index c40fc44..8d20042 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # Open Ticket (License) -© 2025 - DJj123dj & Contributors +© 2021 - 2026 - DJj123dj & Contributors #### Table Of Contents - [General License](#general-license) diff --git a/README.md b/README.md index 979eb8f..3f57fda 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ -> ### 🎥 Content Creators -> Hey there! We're searching for content creators that would like to create a tutorial or setup guide for Open Ticket!
-> [📌 More Information](.github/CONTENT_CREATORS.md) +> ### 📌 Open Ticket Quick Links +> - [⏱️ Quick Setup](#️-quick-setup-using-cli) +> - [📔 Documentation](https://otdocs.dj-dj.be) +> - [🧩 Available Plugins](#-plugins) +> - [📞 Discord Server](https://discord.dj-dj.be) ---

@@ -8,7 +10,7 @@
Powered By
Open Ticket
Discord Invite Link -Open Ticket Version +Open Ticket Version Open Ticket Documentation Open Ticket License Open Ticket Stars @@ -71,9 +73,11 @@ A big thanks to all our sponsors! Without them, it wouldn't be possible to creat + +
Profile PictureProfile Picture
guillee3yeeetSK
@@ -254,4 +258,4 @@ This will help us grow and reach even more people! **README.md**
[Changelog](https://otgithub.dj-dj.be/releases) - [Documentation](https://otdocs.dj-dj.be) - [Website](https://openticket.dj-dj.be) - [Support Server](https://discord.dj-dj.be) - [License](./LICENSE.md)
-© 2025 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) +© 2021 - 2026 - [DJdj Development](https://www.dj-dj.be) - [Terms](https://www.dj-dj.be/terms) - [Privacy Policy](https://www.dj-dj.be/privacy) - [Support Us](https://github.com/sponsors/DJj123dj) diff --git a/config/general.json b/config/general.json index 1a69e66..5c62a2b 100644 --- a/config/general.json +++ b/config/general.json @@ -2,7 +2,7 @@ "_INFO":{ "support":"https://otdocs.dj-dj.be", "discord":"https://discord.dj-dj.be", - "version":"open-ticket-v4.1.1" + "version":"open-ticket-v4.1.2" }, "token":"insert your bot token here! (or leave empty when using 'tokenFromENV')", diff --git a/config/panels.json b/config/panels.json index 8747aff..f8f8f1b 100644 --- a/config/panels.json +++ b/config/panels.json @@ -17,7 +17,7 @@ "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.1 (or leave empty)", + "footer":"Open Ticket v4.1.2 (or leave empty)", "fields":[ {"name":"field name","value":"field value","inline":false} ], diff --git a/index.js b/index.js index 440a9ef..c3bdea0 100644 --- a/index.js +++ b/index.js @@ -14,7 +14,7 @@ process.argv.push(...flags) ██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██║██║ ██╔═██╗ ██╔══╝ ██║ ╚██████╔╝██║ ███████╗██║ ╚████║ ██║ ██║╚██████╗██║ ██╗███████╗ ██║ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═╝ - v4.1.1 - Made by DJj123dj & Contributors + v4.1.2 - Made by DJj123dj & Contributors Discord: https://discord.dj-dj.be Docs: https://otdocs.dj-dj.be diff --git a/languages/arabic.json b/languages/arabic.json index cd340f6..238fb0f 100644 --- a/languages/arabic.json +++ b/languages/arabic.json @@ -1,6 +1,6 @@ { "_TRANSLATION": { - "otversion": "v4.1.1", + "otversion": "v4.1.2", "translators": ["palestinian"], "lastedited": "06/12/2024", "language": "Arabic", diff --git a/languages/bengali.json b/languages/bengali.json index 2b759c0..32258f0 100644 --- a/languages/bengali.json +++ b/languages/bengali.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta"], "lastedited":"19/06/2025", "language":"Bengali", diff --git a/languages/catalan.json b/languages/catalan.json index 4307d3c..cf8ddba 100644 --- a/languages/catalan.json +++ b/languages/catalan.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["guillee3"], "lastedited":"03/12/2025", "language":"Catalan", diff --git a/languages/custom.json b/languages/custom.json index 4756229..cd615aa 100644 --- a/languages/custom.json +++ b/languages/custom.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["DJj123dj"], "lastedited":"03/12/2025", "language":"Custom", diff --git a/languages/czech.json b/languages/czech.json index 82dcd9f..8c0c68f 100644 --- a/languages/czech.json +++ b/languages/czech.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["spyeye_"], "lastedited":"21/08/2024", "language":"Czech", diff --git a/languages/danish.json b/languages/danish.json index 4febf42..da10044 100644 --- a/languages/danish.json +++ b/languages/danish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["the_gamer"], "lastedited":"26/09/2024", "language":"Danish", diff --git a/languages/dutch.json b/languages/dutch.json index e0e703f..a52c97a 100644 --- a/languages/dutch.json +++ b/languages/dutch.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["DJj123dj"], "lastedited":"03/12/2025", "language":"Dutch", diff --git a/languages/english.json b/languages/english.json index 92bf9f3..7639e07 100644 --- a/languages/english.json +++ b/languages/english.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["DJj123dj"], "lastedited":"03/12/2025", "language":"English", diff --git a/languages/estonian.json b/languages/estonian.json index 53699a5..d339152 100644 --- a/languages/estonian.json +++ b/languages/estonian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["iamnotmega","ChatGPT"], "lastedited":"03/12/2025", "language":"Estonian", diff --git a/languages/finnish.json b/languages/finnish.json index 1532b79..29f3c90 100644 --- a/languages/finnish.json +++ b/languages/finnish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["iamnotmega","ChatGPT"], "lastedited":"03/12/2025", "language":"Finnish", diff --git a/languages/french.json b/languages/french.json index ce0306e..93eebb7 100644 --- a/languages/french.json +++ b/languages/french.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["guillee3"], "lastedited":"04/12/2024", "language":"French", diff --git a/languages/german.json b/languages/german.json index 0d21093..d0bfd55 100644 --- a/languages/german.json +++ b/languages/german.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["benzorich"], "lastedited":"03/12/2025", "language":"German", diff --git a/languages/greek.json b/languages/greek.json index 73d5fb8..cb11870 100644 --- a/languages/greek.json +++ b/languages/greek.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Greek", diff --git a/languages/hindi.json b/languages/hindi.json index 556c9fd..d8e3de0 100644 --- a/languages/hindi.json +++ b/languages/hindi.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["challenger_nova"], "lastedited":"03/12/2025", "language":"Hindi", diff --git a/languages/hungarian.json b/languages/hungarian.json index 3d11c28..ba38be9 100644 --- a/languages/hungarian.json +++ b/languages/hungarian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["Kornel0706"], "lastedited":"22/08/2024", "language":"Hungarian", diff --git a/languages/indonesian.json b/languages/indonesian.json index f02d8ee..8693ee0 100644 --- a/languages/indonesian.json +++ b/languages/indonesian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["erxg"], "lastedited":"03/12/2025", "language":"Indonesian", diff --git a/languages/italian.json b/languages/italian.json index f437372..18500da 100644 --- a/languages/italian.json +++ b/languages/italian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["fraden1mvp."], "lastedited":"08/10/2024", "language":"Italian", diff --git a/languages/japanese.json b/languages/japanese.json index 3b8c067..8a5a047 100644 --- a/languages/japanese.json +++ b/languages/japanese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Japanese", diff --git a/languages/korean.json b/languages/korean.json index b49fe2f..2827074 100644 --- a/languages/korean.json +++ b/languages/korean.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Korean", diff --git a/languages/kurdish.json b/languages/kurdish.json index 457891f..1108685 100644 --- a/languages/kurdish.json +++ b/languages/kurdish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Kurdish", diff --git a/languages/latvian.json b/languages/latvian.json index cc8070d..fc40af4 100644 --- a/languages/latvian.json +++ b/languages/latvian.json @@ -1,6 +1,6 @@ { "_TRANSLATION": { - "otversion": "v4.1.1", + "otversion": "v4.1.2", "translators": ["NoOneNook"], "lastedited": "25/03/2025", "language": "Latvian", diff --git a/languages/lithuanian.json b/languages/lithuanian.json index 016a824..3ceb5a1 100644 --- a/languages/lithuanian.json +++ b/languages/lithuanian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["TsgIndrius"], "lastedited":"26/01/2025", "language":"Lithuanian", diff --git a/languages/norwegian.json b/languages/norwegian.json index 84a72dc..91cfe16 100644 --- a/languages/norwegian.json +++ b/languages/norwegian.json @@ -1,6 +1,6 @@ { "_TRANSLATION": { - "otversion": "v4.1.1", + "otversion": "v4.1.2", "translators": ["NoOneNook"], "lastedited": "25/03/2025", "language": "Norwegian", diff --git a/languages/persian.json b/languages/persian.json index dd24b07..1ee9a45 100644 --- a/languages/persian.json +++ b/languages/persian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["dysashop","zhavis"], "lastedited":"28/05/2025", "language":"Persian", diff --git a/languages/polish.json b/languages/polish.json index bfa3d8e..bbd35dc 100644 --- a/languages/polish.json +++ b/languages/polish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["DanoGlez"], "lastedited":"28/01/2025", "language":"Polish", diff --git a/languages/portuguese.json b/languages/portuguese.json index 208e748..ff76c90 100644 --- a/languages/portuguese.json +++ b/languages/portuguese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["quiradon"], "lastedited":"20/08/2024", "language":"Portuguese", diff --git a/languages/romanian.json b/languages/romanian.json index 82a4bf1..19fb1aa 100644 --- a/languages/romanian.json +++ b/languages/romanian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["SankeDev"], "lastedited":"27/08/2024", "language":"Romanian", diff --git a/languages/russian.json b/languages/russian.json index f14fe96..a0411cd 100644 --- a/languages/russian.json +++ b/languages/russian.json @@ -1,6 +1,6 @@ { "_TRANSLATION": { - "otversion": "v4.1.1", + "otversion": "v4.1.2", "translators": ["NoOneNook"], "lastedited": "25/03/2025", "language": "Russian", diff --git a/languages/simplified-chinese.json b/languages/simplified-chinese.json index c8b9a00..2a5d02c 100644 --- a/languages/simplified-chinese.json +++ b/languages/simplified-chinese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Simplified Chainese", diff --git a/languages/slovenian.json b/languages/slovenian.json index 53ced9a..84b1da6 100644 --- a/languages/slovenian.json +++ b/languages/slovenian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Solvenian", diff --git a/languages/spanish.json b/languages/spanish.json index f9a96a2..34e98ea 100644 --- a/languages/spanish.json +++ b/languages/spanish.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["Redactado","Josuens"], "lastedited":"22/08/2024", "language":"Spanish", diff --git a/languages/swedish.json b/languages/swedish.json index d117fcb..e319ee3 100644 --- a/languages/swedish.json +++ b/languages/swedish.json @@ -1,6 +1,6 @@ { "_TRANSLATION": { - "otversion": "v4.1.1", + "otversion": "v4.1.2", "translators": ["NoOneNook"], "lastedited": "25/03/2025", "language": "Svenska", diff --git a/languages/tamil.json b/languages/tamil.json index 23c308c..97b0ff7 100644 --- a/languages/tamil.json +++ b/languages/tamil.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["HanumeshGupta","ChatGPT"], "lastedited":"03/12/2025", "language":"Tamil", diff --git a/languages/thai.json b/languages/thai.json index c474730..13c120e 100644 --- a/languages/thai.json +++ b/languages/thai.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["modshd"], "lastedited":"03/12/2025", "language":"Thai", diff --git a/languages/turkish.json b/languages/turkish.json index 88e9906..5c286f7 100644 --- a/languages/turkish.json +++ b/languages/turkish.json @@ -1,6 +1,6 @@ { "_TRANSLATION": { - "otversion": "v4.1.1", + "otversion": "v4.1.2", "translators": ["palestinian"], "lastedited": "26/11/2024", "language": "Turkish", diff --git a/languages/ukrainian.json b/languages/ukrainian.json index e946d89..83f7888 100644 --- a/languages/ukrainian.json +++ b/languages/ukrainian.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["Anderskiy"], "lastedited":"31/08/2024", "language":"Ukrainian", diff --git a/languages/vietnamese.json b/languages/vietnamese.json index e038411..71a63dc 100644 --- a/languages/vietnamese.json +++ b/languages/vietnamese.json @@ -1,6 +1,6 @@ { "_TRANSLATION":{ - "otversion":"v4.1.1", + "otversion":"v4.1.2", "translators":["ngocdiep2006"], "lastedited":"07/04/2025", "language":"Vietnamese", diff --git a/package.json b/package.json index 7e6c462..ec4f105 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "open-ticket", "author": "DJdj Development", - "version": "4.1.1", + "version": "4.1.2", "description": "The most advanced open-source discord ticket bot with HTML transcripts, plugins, questions, claiming, pinning & more! Using discord.js v14 & JSON database! ", "keywords": [ "ticket-bot", diff --git a/src/core/api/main.ts b/src/core/api/main.ts index 0019824..8cc2400 100644 --- a/src/core/api/main.ts +++ b/src/core/api/main.ts @@ -133,7 +133,7 @@ export class ODMain { constructor(){ this.versions = new ODVersionManager_Default() - this.versions.add(ODVersion.fromString("opendiscord:version","v4.1.1")) + this.versions.add(ODVersion.fromString("opendiscord:version","v4.1.2")) this.versions.add(ODVersion.fromString("opendiscord:api","v1.0.0")) this.versions.add(ODVersion.fromString("opendiscord:transcripts","v2.1.0")) this.versions.add(ODVersion.fromString("opendiscord:livestatus","v2.0.0")) diff --git a/src/core/api/modules/base.ts b/src/core/api/modules/base.ts index 4275a7e..69e91e3 100644 --- a/src/core/api/modules/base.ts +++ b/src/core/api/modules/base.ts @@ -560,8 +560,8 @@ export class ODHTTPGetRequest { this.throwOnError = throwOnError const newConfig = config ?? {} newConfig.method = "GET" - if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":"OpenDiscordBots-OpenTicket/4.1.1"}) - else newConfig.headers = {"User-Agent":"OpenDiscordBots-OpenTicket/4.1.1"} + if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":"OpenDiscordBots-OpenTicket/4.1.2"}) + else newConfig.headers = {"User-Agent":"OpenDiscordBots-OpenTicket/4.1.2"} this.config = newConfig } @@ -615,8 +615,8 @@ export class ODHTTPPostRequest { this.throwOnError = throwOnError const newConfig = config ?? {} newConfig.method = "POST" - if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":"OpenDiscordBots-OpenTicket/4.1.1"}) - else newConfig.headers = {"User-Agent":"OpenDiscordBots-OpenTicket/4.1.1"} + if (newConfig.headers) Object.assign(newConfig.headers,{"User-Agent":"OpenDiscordBots-OpenTicket/4.1.2"}) + else newConfig.headers = {"User-Agent":"OpenDiscordBots-OpenTicket/4.1.2"} this.config = newConfig } diff --git a/src/core/startup/migration.ts b/src/core/startup/migration.ts index ef25ee8..e127dad 100644 --- a/src/core/startup/migration.ts +++ b/src/core/startup/migration.ts @@ -139,4 +139,7 @@ export const migrations = [ //MIGRATE TO v4.1.1 new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.1"),async () => {},async () => {}), + //MIGRATE TO v4.1.2 + new utilities.ODVersionMigration(api.ODVersion.fromString("opendiscord:version","v4.1.2"),async () => {},async () => {}), + ] \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 95631bf..6d0090f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,7 +20,7 @@ INFORMATION: ============ - Open Ticket v4.1.1 - © DJdj Development + Open Ticket v4.1.2 - © DJdj Development support us: https://github.com/sponsors/DJj123dj discord: https://discord.dj-dj.be From db94f226fb6ad80db1de3bba48207036eba943ef Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Fri, 6 Feb 2026 20:59:36 +0100 Subject: [PATCH 7/8] Fixed: Panel embed was replaced with cooldown error --- src/commands/ticket.ts | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts index 055dc1d..def5c65 100644 --- a/src/commands/ticket.ts +++ b/src/commands/ticket.ts @@ -55,14 +55,14 @@ export const registerCommandResponders = async () => { return cancel() } + //check ticket permissions + if (!checkTicketCreationPerms(instance,source,guild,user,option)) return cancel() + //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //send modal instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build(source,{guild,channel,user,option})) }else{ - //check ticket permissions - if (!checkTicketCreationPerms(instance,source,guild,user,option)) return cancel() - //create ticket await instance.defer(true) const res = await opendiscord.actions.get("opendiscord:create-ticket").run(source,{guild,user,answers:[],option}) @@ -106,14 +106,14 @@ export const registerButtonResponders = async () => { return cancel() } + //check ticket permissions + if (!checkTicketCreationPerms(instance,"panel-button",guild,user,option)) return cancel() + //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //send modal instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-button",{guild,channel,user,option})) }else{ - //check ticket permissions - if (!checkTicketCreationPerms(instance,"panel-button",guild,user,option)) return cancel() - //create ticket await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) @@ -150,14 +150,14 @@ export const registerDropdownResponders = async () => { return cancel() } + //check ticket permissions + if (!checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option)) return cancel() + //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ //send modal instance.modal(await opendiscord.builders.modals.getSafe("opendiscord:ticket-questions").build("panel-dropdown",{guild,channel,user,option})) }else{ - //check ticket permissions - if (!checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option)) return cancel() - //create ticket await instance.defer((generalConfig.data.system.replyOnTicketCreation) ? "reply" : "update",true) @@ -206,9 +206,6 @@ export const registerModalResponders = async () => { return cancel() } - //check ticket permissions - if (!checkTicketCreationPerms(instance,originalSource,guild,user,option)) return cancel() - //get answers const answers: {id:string,name:string,type:"short"|"paragraph",value:string|null}[] = [] option.get("opendiscord:questions").value.forEach((id) => { From b972c9787118baf798ac9548d477dabfa895545a Mon Sep 17 00:00:00 2001 From: DJj123dj <80536295+DJj123dj@users.noreply.github.com> Date: Fri, 6 Feb 2026 21:16:30 +0100 Subject: [PATCH 8/8] Fixed: Unknown interaction when on cooldown --- src/commands/ticket.ts | 6 +++--- src/core/api/modules/responder.ts | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/commands/ticket.ts b/src/commands/ticket.ts index def5c65..65159fb 100644 --- a/src/commands/ticket.ts +++ b/src/commands/ticket.ts @@ -56,7 +56,7 @@ export const registerCommandResponders = async () => { } //check ticket permissions - if (!checkTicketCreationPerms(instance,source,guild,user,option)) return cancel() + if (!(await checkTicketCreationPerms(instance,source,guild,user,option))) return cancel() //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ @@ -107,7 +107,7 @@ export const registerButtonResponders = async () => { } //check ticket permissions - if (!checkTicketCreationPerms(instance,"panel-button",guild,user,option)) return cancel() + if (!(await checkTicketCreationPerms(instance,"panel-button",guild,user,option))) return cancel() //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ @@ -151,7 +151,7 @@ export const registerDropdownResponders = async () => { } //check ticket permissions - if (!checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option)) return cancel() + if (!(await checkTicketCreationPerms(instance,"panel-dropdown",guild,user,option))) return cancel() //start ticket creation if (option.exists("opendiscord:questions") && option.get("opendiscord:questions").value.length > 0){ diff --git a/src/core/api/modules/responder.ts b/src/core/api/modules/responder.ts index ce3bebe..3398ab2 100644 --- a/src/core/api/modules/responder.ts +++ b/src/core/api/modules/responder.ts @@ -426,7 +426,8 @@ export class ODCommandResponderInstance { /**Show a modal as reply to this command. */ async modal(modal:ODModalBuildResult){ if (this.type != "interaction" || !(this.interaction instanceof discord.ChatInputCommandInteraction)) return false - this.interaction.showModal(modal.modal) + if (this.interaction.deferred || this.interaction.replied) return false + await this.interaction.showModal(modal.modal) this.didReply = true return true } @@ -601,7 +602,8 @@ export class ODButtonResponderInstance { } /**Show a modal as reply to this button. */ async modal(modal:ODModalBuildResult){ - this.interaction.showModal(modal.modal) + if (this.interaction.deferred || this.interaction.replied) return false + await this.interaction.showModal(modal.modal) this.didReply = true return true } @@ -889,7 +891,8 @@ export class ODDropdownResponderInstance { } /**Show a modal as reply to this dropdown. */ async modal(modal:ODModalBuildResult){ - this.interaction.showModal(modal.modal) + if (this.interaction.deferred || this.interaction.replied) return false + await this.interaction.showModal(modal.modal) this.didReply = true return true } @@ -1261,7 +1264,8 @@ export class ODContextMenuResponderInstance { } /**Show a modal as reply to this context menu. */ async modal(modal:ODModalBuildResult){ - this.interaction.showModal(modal.modal) + if (this.interaction.deferred || this.interaction.replied) return false + await this.interaction.showModal(modal.modal) this.didReply = true return true }