Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 71 additions & 1 deletion locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,27 @@
"edit-xp-value-description": "Neue Erfahrungspunktemenge des Nutzers",
"edit-xp-description": "Betrüge deine Community und bearbeite die Erfahrungspunkte eines Nutzers",
"random-messages-enabled-but-non-configured": "Zufällige Nachrichten sind aktiviert, allerdings wurden keine zufälligen Nachrichten festgelegt. Ignoriere Anweisung.",
"granted-rewards-audit-log": "Rollen aktualisiert um sicherzustellen, dass der/die Nutzer:in die benötigten Rollen hat"
"granted-rewards-audit-log": "Rollen aktualisiert um sicherzustellen, dass der/die Nutzer:in die benötigten Rollen hat",
"rewards-command-description": "Level-Belohnungen verwalten",
"rewards-add-description": "Rollen zu einer Level-Belohnung hinzufügen",
"rewards-set-description": "Rollen für eine Level-Belohnung setzen",
"rewards-remove-description": "Eine Rolle aus einer Level-Belohnung entfernen",
"rewards-clear-description": "Alle Belohnungen für ein Level entfernen",
"rewards-list-description": "Konfigurierte Level-Belohnungen anzeigen",
"rewards-level-description": "Level zum Konfigurieren",
"rewards-role-description": "Rolle, die vergeben wird",
"rewards-replace-description": "Ersetzt vorherige ersetzbare Belohnungen",
"rewards-replace-on": "ersetzbar",
"rewards-replace-off": "behalten",
"rewards-none": "keine",
"rewards-added": "Level %l Belohnungen: %roles (%replace)",
"rewards-set": "Level %l Belohnungen gesetzt: %roles (%replace)",
"rewards-removed": "%role aus Level %l Belohnungen entfernt",
"rewards-cleared": "Belohnungen für Level %l entfernt",
"rewards-level-not-found": "Keine Belohnungen für Level %l konfiguriert",
"rewards-list-empty": "Noch keine Level-Belohnungen konfiguriert",
"rewards-list-one": "Level %l: %roles (%replace)",
"rewards-list-line": "Level %l: %roles (%replace)"
},
"partner-list": {
"could-not-give-role": "%u konnte keine Rolle gegeben werden",
Expand Down Expand Up @@ -505,6 +525,7 @@
"moderate-ban-command-description": "Bannt einen Nutzer von deinem Server",
"moderate-reason-description": "Grund für die Aktion",
"moderate-duration-description": "Dauer der Aktion (Standard: Permanent)",
"moderate-only-target-description": "Nur auf den ausgewaehlten Account anwenden (nicht auf verknuepfte Accounts spiegeln)",
"mute-max-duration": "Discord begrenzt die Höchstdauer eines Timeouts auf 28 Tage. Bitte gib einen Wert an, der niedriger oder gleich ist",
"moderate-quarantine-command-description": "Versetzt einen Nurzer auf deinem Server in Quarantäne",
"moderate-unquarantine-command-description": "Entfernt einen Nutzer aus der Quarantäne",
Expand All @@ -526,6 +547,8 @@
"moderate-note-id-description": "ID einer deiner Notizen, die du bearbeiten willst (leer lassen, um neu zu erstellen)",
"moderate-warnid-description": "ID einer Verwarnung (führe /moderate actions aus um diese herauszufinden)",
"moderate-actions-command-description": "Zeigt alle Aktionen gegen einen Nutzer",
"moderate-clear-punishments-command-description": "Alle Moderationsaktionen eines Nutzers loeschen",
"moderate-clear-punishments-confirm-description": "Gib CONFIRM ein, um fortzufahren",
"report-command-description": "Meldet einen Nutzer und sendet einen Ausschnitt des Chats an das Serverteam",
"report-reason-description": "Bitte beschreibe was der Nutzer falsch gemacht hat",
"report-user-description": "Nutzer, den du melden willst",
Expand Down Expand Up @@ -578,10 +601,57 @@
"warning-not-found": "Verwarnung konnte nicht gefunden werden. Bitte stelle sicher, dass du eine VerwarnungsID und keine NutzerID verwendest.",
"can-not-report-mod": "Du kannst Moderatoren nicht melden.",
"action-description-format": "%reason\nvon %u am %t",
"action-reason-line": "> Grund: %r",
"action-by-line": "> Von: %u",
"action-at-line": "> Am: %t",
"action-expires-line": "> Laeuft ab am: %d",
"action-automod-line": "> AutoMod: %a",
"no-actions-title": "Nicht gefunden",
"no-actions-value": "Es wurden keine Aktionen gegen %u gefunden.",
"actions-embed-title": "Mod-Aktionen gegen %u - Seite %i",
"actions-embed-description": "Du kannst jede Aktion gegen %u hier sehen.",
"clear-punishments-disabled": "Strafen loeschen ist in der Konfiguration deaktiviert.",
"clear-punishments-done": "%n Aktionen fuer %u geloescht.",
"clear-punishments-confirm-required": "Bitte CONFIRM eingeben, um den Befehl auszufuehren.",
"clear-punishments-reason": "Alle Strafen geloescht",
"automod-log-line": "%d %a %r",
"moderate-actions-show-notes": "Notizen in der Akte anzeigen",
"actions-channel-not-allowed": "Dieser Befehl ist auf bestimmte Kanaele beschraenkt.",
"dossier-subtitle": "**Dies ist die Akte von %m**",
"dossier-joined": "**Gejoint:** %d",
"dossier-created": "**Account alter:** %d",
"dossier-counts": "%b **ban** %q **quarantaene** %m **mute** %w **warn**",
"dossier-separator": "----------------",
"dossier-notes-title": "**Notizen**",
"dossier-notes-empty": "Keine Notizen vorhanden.",
"dossier-linked-title": "**Verlinkte Zweitaccounts**",
"dossier-actions-title": "**Sanktionen:**",
"dossier-note-alt-inline": "**Alt-Acc %u**",
"dossier-action-alt-prefix": "-# Alt-Acc %u:",
"action-alt-line": "> -# Alt-Acc %u",
"dossier-note-line": "**#%i: %t von %author:**\n> %c%altInfo",
"action-header": "**#%i: %t**",
"action-block": "%a",
"linked-accounts-command-description": "Verknuepfte Accounts verwalten",
"linked-accounts-link-description": "Einen oder mehrere Accounts mit einem Hauptaccount verknuepfen (bis zu 5 pro Befehl)",
"linked-accounts-unlink-description": "Einen Account entkoppeln",
"linked-accounts-clear-description": "Alle Verknuepfungen fuer einen Hauptaccount entfernen",
"linked-accounts-list-description": "Verknuepfte Accounts fuer einen Nutzer anzeigen",
"linked-accounts-main-description": "Hauptaccount",
"linked-accounts-account-description": "Verknuepfter Account",
"linked-accounts-user-description": "Nutzer zum Anzeigen/Entkoppeln",
"linked-accounts-disabled": "Verknuepfte Accounts sind in der Konfiguration deaktiviert.",
"linked-accounts-no-accounts": "Bitte mindestens einen Account zum Verknuepfen angeben.",
"linked-accounts-linked": "Hauptaccount %m verknuepft mit: %a",
"linked-accounts-unlinked": "%u wurde entkoppelt",
"linked-accounts-cleared": "Verknuepfung fuer %m entfernt",
"linked-accounts-none-for-user": "Keine verknuepften Accounts fuer %u gefunden",
"linked-accounts-list": "Hauptaccount: %m | Verknuepft: %a",
"linked-accounts-log-field": "Verknuepfte Accounts",
"automod-log-field": "AutoMod Aktionen",
"linked-accounts-single-reason": "Verknuepft mit Hauptaccount %m",
"linked-accounts-none": "keine",
"unknown": "Unbekannt",
"report-embed-title": "Neue Meldung",
"report-embed-description": "Ein Nutzer hat einen anderen Nutzer gemeldet. Bitte bearbeite den Fall und führe, wenn nötig, Aktionen aus.",
"reported-user": "Gemeldeter Nutzer",
Expand Down
74 changes: 72 additions & 2 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,27 @@
"role-factors-total": "Multiplied together, the user receives **%f times more XP** for every message.",
"edit-level-description": "Betrays your community and edits a user's levels",
"random-messages-enabled-but-non-configured": "You have random messages enabled, but have non configured. Ignoring config.randomMessages configuration.",
"granted-rewards-audit-log": "Updated roles to make sure, they have the level role they need"
"granted-rewards-audit-log": "Updated roles to make sure, they have the level role they need",
"rewards-command-description": "Manage level reward roles",
"rewards-add-description": "Add roles to a level reward",
"rewards-set-description": "Set roles for a level reward",
"rewards-remove-description": "Remove a role from a level reward",
"rewards-clear-description": "Remove all rewards for a level",
"rewards-list-description": "List configured level rewards",
"rewards-level-description": "Level to configure",
"rewards-role-description": "Role to grant",
"rewards-replace-description": "Replace previous replaceable rewards",
"rewards-replace-on": "replaceable",
"rewards-replace-off": "kept",
"rewards-none": "none",
"rewards-added": "Level %l rewards: %roles (%replace)",
"rewards-set": "Level %l rewards set to: %roles (%replace)",
"rewards-removed": "Removed %role from level %l rewards",
"rewards-cleared": "Cleared rewards for level %l",
"rewards-level-not-found": "No rewards configured for level %l",
"rewards-list-empty": "No level rewards configured yet",
"rewards-list-one": "Level %l: %roles (%replace)",
"rewards-list-line": "Level %l: %roles (%replace)"
},
"team-list": {
"channel-not-found": "Could not find channel with ID %c or the channel has a wrong type (only text-channels supported)",
Expand Down Expand Up @@ -560,6 +580,7 @@
"anti-grief-reason": "Too many actions of type \"%type\" in the last %h hours. Maximum amount allowed: %n",
"anti-grief-user-message": "Sorry, but it seems like you are abusing your moderative powers. We've taken actions to prevent this from happening.",
"moderate-duration-description": "Duration of the action (max: 28 days, default: 14 days)",
"moderate-only-target-description": "Apply only to the selected account (do not mirror to linked accounts)",
"mute-max-duration": "Discord limits the maximal duration of a timeout to 28 days. Please enter an amount equal or less than this",
"moderate-quarantine-command-description": "Quarantine a user on your server",
"moderate-unquarantine-command-description": "Removes a user from the quarantine",
Expand All @@ -583,6 +604,8 @@
"moderate-note-id-description": "ID of one of your notes you want to edit (leave blank to create a new one)",
"moderate-warnid-description": "ID of a warn (run /moderate actions to get it)",
"moderate-actions-command-description": "Show all recorded actions against a user",
"moderate-clear-punishments-command-description": "Clear all moderation actions for a user",
"moderate-clear-punishments-confirm-description": "Type CONFIRM to proceed",
"report-command-description": "Reports a user and sends a snapshot of the chat to server staff",
"report-reason-description": "Please describe what the user did wrong",
"report-user-description": "User you want to report",
Expand Down Expand Up @@ -638,10 +661,57 @@
"warning-not-found": "I could not find this warning. Please make sure you are actually using a warning-id and not a userid.",
"can-not-report-mod": "You can not report moderators.",
"action-description-format": "%reason\nby %u on %t",
"action-reason-line": "> Reason: %r",
"action-by-line": "> By: %u",
"action-at-line": "> At: %t",
"action-expires-line": "> Expires: %d",
"action-automod-line": "> AutoMod: %a",
"no-actions-title": "None found",
"no-actions-value": "No actions against %u found.",
"actions-embed-title": "Mod-Actions against %u - Site %i",
"actions-embed-description": "You can find every action against %u here.",
"clear-punishments-disabled": "Clear punishments is disabled in the configuration.",
"clear-punishments-done": "Cleared %n actions for %u.",
"clear-punishments-confirm-required": "Please type CONFIRM to run this command.",
"clear-punishments-reason": "Cleared all punishments",
"automod-log-line": "%d %a %r",
"moderate-actions-show-notes": "Show notes in the dossier",
"actions-channel-not-allowed": "This command is restricted to specific channels.",
"dossier-subtitle": "**This is the dossier of %m**",
"dossier-joined": "**Joined:** %d",
"dossier-created": "**Account age:** %d",
"dossier-counts": "%b **ban** %q **quarantine** %m **mute** %w **warn**",
"dossier-separator": "----------------",
"dossier-notes-title": "**Notes**",
"dossier-notes-empty": "No notes available.",
"dossier-linked-title": "**Linked accounts**",
"dossier-actions-title": "**Sanctions:**",
"dossier-note-alt-inline": "**alt account %u**",
"dossier-action-alt-prefix": "-# Alt acc %u:",
"action-alt-line": "> -# Alt acc %u",
"dossier-note-line": "**#%i: %t from %author:**\n> %c%altInfo",
"action-header": "**#%i: %t**",
"action-block": "%a",
"linked-accounts-command-description": "Manage linked accounts",
"linked-accounts-link-description": "Link one or more accounts to a main account (up to 5 per command)",
"linked-accounts-unlink-description": "Unlink a single account",
"linked-accounts-clear-description": "Clear all links for a main account",
"linked-accounts-list-description": "Show linked accounts for a user",
"linked-accounts-main-description": "Main account",
"linked-accounts-account-description": "Linked account",
"linked-accounts-user-description": "User to check/unlink",
"linked-accounts-disabled": "Linked accounts are disabled in the configuration.",
"linked-accounts-no-accounts": "Please provide at least one account to link.",
"linked-accounts-linked": "Linked main %m with: %a",
"linked-accounts-unlinked": "Unlinked %u",
"linked-accounts-cleared": "Cleared linked accounts for %m",
"linked-accounts-none-for-user": "No linked accounts found for %u",
"linked-accounts-list": "Main: %m | Linked: %a",
"linked-accounts-log-field": "Linked accounts",
"automod-log-field": "AutoMod actions",
"linked-accounts-single-reason": "Linked to main account %m",
"linked-accounts-none": "none",
"unknown": "Unknown",
"report-embed-title": "New report",
"report-embed-description": "A user reported another user. Please review the case and take actions if needed.",
"reported-user": "Reported user",
Expand Down Expand Up @@ -1018,4 +1088,4 @@
"owner-cannot-be-renamed": "The owner of the server (%u) cannot be renamed.",
"nickname-error": "An error occurred while trying to change the nickname of %u: %e"
}
}
}
21 changes: 12 additions & 9 deletions modules/levels/commands/manage-levels.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {registerNeededEdit} = require('../leaderboardChannel');
const {localize} = require('../../../src/functions/localize');
const {formatDiscordUserName} = require('../../../src/functions/helpers');
const {getReplaceableRewardRoleIds, getRewardForLevel} = require('../rewards');

Comment on lines 1 to 5
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions adding /manage-levels rewards ... subcommands, and new locale keys for reward-management commands were added, but manage-levels.js currently only defines reset-xp, edit-xp, and edit-level options (no rewards subcommand group). Either implement and register the rewards subcommands in this PR, or update the PR description/remove unused locale keys to avoid drifting docs/UI text.

Copilot uses AI. Check for mistakes.
async function runXPAction(interaction, newXP) {
const member = interaction.options.getMember('user');
Expand All @@ -26,13 +27,14 @@ async function runXPAction(interaction, newXP) {
const nextLevelXp = user.level * 750 + ((user.level - 1) * 500);
if (nextLevelXp <= user.xp) {
user.level = user.level + 1;
if (interaction.client.configurations.levels.config.reward_roles[user.level.toString()]) {
if (interaction.client.configurations.levels.config.reward_roles[user.level.toString()]) {
for (const role of Object.values(interaction.client.configurations.levels.config.reward_roles)) {
const rewardConfig = getRewardForLevel(interaction.client, user.level);
if (rewardConfig) {
if (rewardConfig.replacePrevious) {
for (const role of getReplaceableRewardRoleIds(interaction.client)) {
if (member.roles.cache.has(role)) member.roles.remove(role, '[levels] ' + localize('levels', 'granted-rewards-audit-log')).catch();
}
}
member.roles.add(interaction.client.configurations.levels.config.reward_roles[user.level.toString()]);
member.roles.add(rewardConfig.roles);
}
Comment on lines +30 to 38
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

member.roles.add(rewardConfig.roles) returns a Promise but isn’t awaited or caught. If adding the role(s) fails (missing permissions/unknown role), this can surface as an unhandled rejection. Please await it and/or attach .catch() (and consider passing an audit-log reason for consistency with message-based leveling).

Copilot uses AI. Check for mistakes.
runXPCheck();
}
Expand Down Expand Up @@ -81,13 +83,14 @@ async function runLevelAction(interaction, newLevel) {
content: '⚠️ ' + localize('levels', 'negative-level')
});
user.xp = (user.level - 1) * 750 + ((user.level - 2) * 500);
if (interaction.client.configurations.levels.config.reward_roles[user.level.toString()]) {
if (interaction.client.configurations.levels.config.reward_roles[user.level.toString()]) {
for (const role of Object.values(interaction.client.configurations.levels.config.reward_roles)) {
const rewardConfig = getRewardForLevel(interaction.client, user.level);
if (rewardConfig) {
if (rewardConfig.replacePrevious) {
for (const role of getReplaceableRewardRoleIds(interaction.client)) {
if (member.roles.cache.has(role)) member.roles.remove(role, '[levels] ' + localize('levels', 'granted-rewards-audit-log')).catch();
}
}
member.roles.add(interaction.client.configurations.levels.config.reward_roles[user.level.toString()]);
member.roles.add(rewardConfig.roles);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

member.roles.add(rewardConfig.roles) returns a Promise but isn’t awaited or caught. If adding the role(s) fails (missing permissions/unknown role), this can surface as an unhandled rejection. Please await it and/or attach .catch() (and consider passing an audit-log reason for consistency with message-based leveling).

Suggested change
member.roles.add(rewardConfig.roles);
await member.roles.add(rewardConfig.roles, '[levels] ' + localize('levels', 'granted-rewards-audit-log')).catch();

Copilot uses AI. Check for mistakes.
}


Expand Down Expand Up @@ -349,4 +352,4 @@ module.exports.config = {
}
return array;
}
};
};
60 changes: 60 additions & 0 deletions modules/levels/configs/reward-roles.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"description": {
"en": "Configure reward roles per level",
"de": "Belohnungsrollen pro Level konfigurieren"
},
"humanName": {
"en": "Reward roles",
"de": "Belohnungsrollen"
},
"filename": "reward-roles.json",
"configElements": true,
"content": [
{
"name": "level",
"humanName": {
"en": "Level",
"de": "Level"
},
"default": {
"en": ""
},
"description": {
"en": "Level at which the reward should be granted",
"de": "Level, bei dem die Belohnung vergeben wird"
},
"type": "integer"
},
{
"name": "roles",
"humanName": {
"en": "Reward roles",
"de": "Belohnungsrollen"
},
"default": {
"en": []
},
"description": {
"en": "Roles that should be granted at this level",
"de": "Rollen, die bei diesem Level vergeben werden"
},
"type": "array",
"content": "roleID"
},
{
"name": "replacePrevious",
"humanName": {
"en": "Replace previous reward roles",
"de": "Vorherige Belohnungsrollen ersetzen"
},
"default": {
"en": false
},
"description": {
"en": "If enabled, previous reward roles will be removed when this reward is granted",
"de": "Wenn aktiviert, werden vorherige Belohnungsrollen entfernt"
},
"type": "boolean"
}
]
}
Loading