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
127 changes: 66 additions & 61 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -930,66 +930,71 @@
"nickname-error": "An error occurred while trying to change the nickname of %u: %e"
},
"ping-protection": {
"log-not-a-member": "[Ping Protection] Punishment failed: The pinger is not a member.",
"log-punish-role-error": "[Ping Protection] Punishment failed: I cannot punish %tag because their role is higher than or equal to my highest role.",
"log-mute-error": "[Ping Protection] Punishment failed: I cannot mute %tag: %e",
"log-kick-error": "[Ping Protection] Punishment failed: I cannot kick %tag: %e",
"log-action-log-failed": "[Ping Protection] Punishment logging failed: %e",
"log-manual-delete": "All data for <@%u> (%u) has been deleted successfully.",
"log-manual-delete-logs": "[Ping Protection] All data for user with ID %u has been deleted successfully.",
"log-automod-keyword-limit": "[Ping Protection] Automod keywords exceed 1000 characters limit. Keywords were truncated.",
"punish-log-failed-title": "Punishment failed for user %u",
"punish-log-failed-desc": "An error occured while trying to punish the user %m. Please check the bot's permissions and role hierarchy. See the message below for the error.",
"punish-log-error": "Error: ```%e```",
"punish-role-error": "I cannot punish %tag because their role is higher than or equal to my highest role.",
"reason-basic": "User reached %c pings in the last %w weeks.",
"reason-advanced": "User reached %c pings in the last %d days (Custom timeframe).",
"cmd-desc-module": "Ping protection related commands",
"cmd-desc-group-user": "Every command related to the users",
"cmd-desc-history": "View the ping history of a user",
"cmd-opt-user": "The user to check",
"cmd-desc-actions": "View the moderation action history of a user",
"cmd-desc-panel": "Admin: Open the user management panel",
"cmd-desc-group-list": "Lists protected or whitelisted entities",
"cmd-desc-list-protected": "List all protected users and roles",
"cmd-desc-list-wl": "List all whitelisted roles and channels",
"embed-history-title": "Ping history of %u",
"embed-leaver-warning": "This user left the server at %t. These logs will stay until automatic deletion.",
"no-data-found": "No logs found for this user.",
"embed-actions-title": "Moderation history of %u",
"label-reason": "Reason",
"actions-retention-note": "Note: Moderation actions are retained for 1 - 12 months based on the configuration.",
"no-permission": "You don't have sufficient permissions to use this command.",
"panel-title": "User Panel: %u",
"panel-description": "Manage and view data for %u (%i). View a quick recap of their ping and moderation history, or delete all data stored for this user (Risky).",
"btn-history": "Ping history",
"btn-actions": "Actions history",
"btn-delete": "Delete all data (Risky)",
"list-protected-title": "Protected Users and Roles",
"list-protected-desc": "View all protected users and roles here. When someone pings one of these protected user(s)/role(s), a warning will be sent. Exceptions are whitelisted roles, and when sent in a whitelisted channel.",
"field-prot-users": "Protected Users",
"field-prot-roles": "Protected Roles",
"list-whitelist-title": "Whitelisted Roles and Channels",
"list-whitelist-desc": "View all whitelisted roles and channels here. Whitelisted roles will not get a warning for pinging a protected entity, and pings will be ignored in whitelisted channels.",
"field-wl-roles": "Whitelisted Roles",
"field-wl-channels": "Whitelisted Channels",
"list-none": "None are configured.",
"modal-title": "Confirm data deletion for this user",
"modal-label": "Confirm data deletion by typing this phrase:",
"modal-phrase": "I understand that all data of this user will be deleted and that this action cannot be undone.",
"modal-failed": "The phrase you entered is incorrect. Data deletion cancelled.",
"field-quick-history": "Quick history view (Last %w weeks)",
"field-quick-desc": "Pings history amount: %p\nModeration actions amount: %m",
"history-disabled": "History logging has been disabled by a bot-configurator.\nAre you (one of) the bot-configurators? You can enable history logging in the \"storage\" tab in the 'ping-protection' module ^^",
"leaver-warning-long": "User left at %d. These logs will stay until automatic deletion.",
"leaver-warning-short": "User left at %d.",
"meme-why": "😐 [Why are you the way that you are?](<https://www.youtube.com/watch?v=NY9UZI1OUMI>) - You just pinged yourself..",
"meme-played": "🔑 [Congratulations, you played yourself.](<https://www.youtube.com/watch?v=Lr7CKWxqhtw>)",
"meme-spider": "🕷️ [Is this you?](<https://i.kym-cdn.com/entries/icons/original/000/023/397/C-658VsXoAo3ovC.jpg>) - You just pinged yourself.",
"meme-rick": "🎵 [Never gonna give you up, never gonna let you down...](<https://www.youtube.com/watch?v=dQw4w9WgXcQ>) You just Rick Rolled yourself. Also congrats you unlocked the secret easter egg that only has a 1% chance of appearing!!1!1!!",
"meme-grind": "Why are you even pinging yourself 5 times in a row? Anyways continue some more to possibly get the secret meme\n-# (good luck grinding, only a 1% chance of getting it and during testing I had it once after 83 pings)",
"label-jump": "Jump to Message",
"no-message-link": "This ping was blocked by AutoMod",
"list-entry-text": "%index. **Pinged %target** at %time\n%link"
"log-not-a-member": "[Ping Protection] Punishment failed: The pinger is not a member.",
"log-punish-role-error": "[Ping Protection] Punishment failed: I cannot punish %tag because their role is higher than or equal to my highest role.",
"log-mute-error": "[Ping Protection] Punishment failed: I cannot mute %tag: %e",
"log-kick-error": "[Ping Protection] Punishment failed: I cannot kick %tag: %e",
"log-action-log-failed": "[Ping Protection] Punishment logging failed: %e",
"log-manual-delete": "All data for <@%u> (%u) has been deleted successfully.",
"log-manual-delete-logs": "[Ping Protection] All data for user with ID %u has been deleted successfully.",
"log-automod-keyword-limit": "[Ping Protection] Automod keywords exceed 1000 characters limit. Keywords were truncated.",
"punish-log-failed-title": "Punishment failed for user %u",
"punish-log-failed-desc": "An error occured while trying to punish the user %m. Please check the bot's permissions and role hierarchy. See the message below for the error.",
"punish-log-error": "Error: ```%e```",
"punish-role-error": "I cannot punish %tag because their role is higher than or equal to my highest role.",
"reason-basic": "User reached %c pings in the last %w weeks.",
"reason-advanced": "User reached %c pings in the last %d days (Custom timeframe).",
"cmd-desc-module": "Ping protection related commands",
"cmd-desc-group-user": "Every command related to the users",
"cmd-desc-history": "View the ping history of a user",
"cmd-opt-user": "The user to check",
"cmd-desc-actions": "View the moderation action history of a user",
"cmd-desc-panel": "Admin: Open the user management panel",
"cmd-desc-group-list": "Lists protected or whitelisted entities",
"cmd-desc-list-protected": "List all protected users and roles",
"cmd-desc-list-wl": "List all whitelisted roles and channels",
"embed-history-title": "Ping history of %u",
"embed-leaver-warning": "This user left the server at %t. These logs will stay until automatic deletion.",
"no-data-found": "No logs found for this user.",
"embed-actions-title": "Moderation history of %u",
"label-reason": "Reason",
"actions-retention-note": "Note: Moderation actions are retained for 1 - 12 months based on the configuration.",
"no-permission": "You don't have sufficient permissions to use this command.",
"panel-title": "User Panel: %u",
"panel-description": "Manage and view data for %u (%i). View a quick recap of their ping and moderation history, or delete all data stored for this user (Risky).",
"btn-history": "Ping history",
"btn-actions": "Actions history",
"btn-delete": "Delete all data (Risky)",
"list-protected-title": "Protected Users and Roles",
"list-protected-desc": "View all protected users and roles here. When someone pings one of these protected user(s)/role(s), a warning will be sent. Exceptions are whitelisted roles, and when sent in a whitelisted channel.",
"field-prot-users": "Protected Users",
"field-prot-roles": "Protected Roles",
"list-whitelist-title": "Whitelisted Roles and Channels",
"list-whitelist-desc": "View all whitelisted roles and channels here. Whitelisted roles will not get a warning for pinging a protected entity, and pings will be ignored in whitelisted channels.",
"field-wl-roles": "Whitelisted Roles",
"field-wl-channels": "Whitelisted Channels",
"list-none": "None are configured.",
"modal-title": "Confirm data deletion for this user",
"modal-label": "Confirm data deletion by typing this phrase:",
"modal-phrase": "I understand that all data of this user will be deleted and that this action cannot be undone.",
"modal-failed": "The phrase you entered is incorrect. Data deletion cancelled.",
"field-quick-history": "Quick history view (Last %w weeks)",
"field-quick-desc": "Pings history amount: %p\nModeration actions amount: %m",
"history-disabled": "History logging has been disabled by a bot-configurator.\nAre you (one of) the bot-configurators? You can enable history logging in the \"storage\" tab in the 'ping-protection' module ^^",
"leaver-warning-long": "User left at %d. These logs will stay until automatic deletion.",
"leaver-warning-short": "User left at %d.",
"meme-why": "😐 [Why are you the way that you are?](<https://www.youtube.com/watch?v=NY9UZI1OUMI>) - You just pinged yourself..",
"meme-played": "🔑 [Congratulations, you played yourself.](<https://www.youtube.com/watch?v=Lr7CKWxqhtw>)",
"meme-spider": "🕷️ [Is this you?](<https://i.kym-cdn.com/entries/icons/original/000/023/397/C-658VsXoAo3ovC.jpg>) - You just pinged yourself.",
"meme-rick": "🎵 [Never gonna give you up, never gonna let you down...](<https://www.youtube.com/watch?v=dQw4w9WgXcQ>) You just Rick Rolled yourself. Also congrats you unlocked the secret easter egg that only has a 1% chance of appearing!!1!1!!",
"meme-grind": "Why are you even pinging yourself 5 times in a row? Anyways continue some more to possibly get the secret meme\n-# (good luck grinding, only a 1% chance of getting it and during testing I had it once after 83 pings)",
"label-jump": "Jump to Message",
"no-message-link": "This ping was blocked by AutoMod",
"list-entry-text": "%index. **Pinged %target** at %time\n%link"
},
"name-list-cleaner": {
"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",
"nickname-reset": "The nickname of %u has been reset, as it started with a blacklisted character."
}
}
90 changes: 90 additions & 0 deletions modules/name-list-cleaner/configs/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"description": {
"en": "Configure the function of the module here",
"de": "Stelle hier die Funktionen des Modules ein"
},
"humanName": {
"en": "Configuration",
"de": "Konfiguration"
},
"filename": "config.json",
"content": [
{
"name": "keepNickname",
"humanName": {
"en": "Keep nickname",
"de": "Nickname behalten"
},
"default": {
"en": true
},
"description": {
"en": "If yes: special characters will be removed from nicknames; if no: the nickname will be removed and the username will be shown instead.",
"de": "Wenn ja: Sonderzeichen werden aus den Nicknames entfernt; wenn nein: der Nickname wird entfernt und stattdessen der Benutzername angezeigt."
},
"type": "boolean"
},
{
"name": "symbolWhitelist",
"humanName": {
"en": "Character Whitelist/Blacklist",
"de": "Zeichen Whitelist/Blacklist"
},
"default": {
"en": []
},
"description": {
"en": "A list of characters that should be allowed (whitelist) or blocked (blacklist) at the start of usernames. If the list is empty, all non-alphanumeric characters will be removed.",
"de": "Eine Liste von Zeichen, die am Anfang von Benutzernamen erlaubt (Whitelist) oder blockiert (Blacklist) werden sollen. Wenn die Liste leer ist, werden alle nicht-alphanumerischen Zeichen entfernt."
},
"type": "array",
"content": "string"
},
{
"name": "isBlacklist",
"humanName": {
"en": "Use blacklist instead of whitelist",
"de": "Blacklist statt Whitelist verwenden"
},
"default": {
"en": false
},
"description": {
"en": "If yes: the list of characters will be treated as a blacklist (characters in the list will be blocked); if no: the list will be treated as a whitelist (only characters in the list and alphanumeric characters will be allowed).",
"de": "Wenn ja: die Liste der Zeichen wird als Blacklist behandelt (Zeichen in der Liste werden blockiert); wenn nein: die Liste wird als Whitelist behandelt (nur Zeichen in der Liste und alphanumerische Zeichen werden erlaubt)."
},
"type": "boolean"
},
{
"name": "userWhitelist",
"humanName": {
"en": "User Whitelist",
"de": "Benutzer-Whitelist"
},
"default": {
"en": []
},
"description": {
"en": "A list of user IDs that should be exempt from the username check. Usernames of these users will not be modified.",
"de": "Eine Liste von Benutzer-IDs, die von der Benutzernamenprüfung ausgenommen werden sollen. Die Benutzernamen dieser Benutzer werden nicht geändert."
},
"type": "array",
"content": "userID"
},
{
"name": "alsoCheckUsernames",
"humanName": {
"en": "Also check usernames",
"de": "Auch Benutzernamen überprüfen"
},
"default": {
"en": false
},
"description": {
"en": "If yes: not only nicknames but also usernames will be checked for special characters and modified accordingly. If no: only nicknames will be checked and modified, usernames will be left unchanged.",
"de": "Wenn ja: nicht nur Nicknames, sondern auch Benutzernamen werden auf Sonderzeichen überprüft und entsprechend geändert. Wenn nein: nur Nicknames werden überprüft und geändert, Benutzernamen bleiben unverändert."
},
"type": "boolean"
}
]
}
7 changes: 7 additions & 0 deletions modules/name-list-cleaner/events/botReady.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const {renameMember} = require('../renameMember');

module.exports.run = async function (client) {
for (const member of client.guild.members.cache.values()) {
await renameMember(client, member);
}
}
9 changes: 9 additions & 0 deletions modules/name-list-cleaner/events/guildMemberUpdate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const {renameMember} = require("../renameMember");
module.exports.run = async function (client, oldGuildMember, newGuildMember) {

if (!client.botReadyAt) return;
if (newGuildMember.guild.id !== client.guild.id) return;
if (oldGuildMember.nickname === newGuildMember.nickname && oldGuildMember.user.username === newGuildMember.user.username) return;
await renameMember(client, newGuildMember);
}

24 changes: 24 additions & 0 deletions modules/name-list-cleaner/module.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "name-list-cleaner",
"humanReadableName": {
"en": "Name List Cleaner",
"de": "Namenslisten Cleaner"
},
"author": {
"name": "hfgd",
"link": "https://github.com/hfgd123",
"scnxOrgID": "2"
},
"openSourceURL": "https://github.com/hfgd123/CustomDCBot/tree/main/modules/username-check",
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

openSourceURL points to modules/username-check, which doesn’t match this module’s name/path (modules/name-list-cleaner). Update it to the correct repository URL so metadata consumers can find the module’s source.

Suggested change
"openSourceURL": "https://github.com/hfgd123/CustomDCBot/tree/main/modules/username-check",
"openSourceURL": "https://github.com/hfgd123/CustomDCBot/tree/main/modules/name-list-cleaner",

Copilot uses AI. Check for mistakes.
"config-example-files": [
"configs/config.json"
],
"events-dir": "/events",
"tags": [
"tools"
],
"description": {
"en": "Remove special characters from the beginning of usernames",
"de": "Entferne Sonderzeichen vom Anfang von Benutzernamen"
}
}
52 changes: 52 additions & 0 deletions modules/name-list-cleaner/renameMember.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
const {localize} = require("../../src/functions/localize");
renameMember = async function (client, guildMember) {
let newName;
const moduleConf = client.configurations['name-list-cleaner']['config'];
if (moduleConf.userWhitelist.includes(guildMember.user.id)) return;


if (guildMember.nickname !== null) {
newName = await checkUsername(client, guildMember.nickname);
if (newName === guildMember.nickname) return;
} else if (moduleConf.alsoCheckUsername) {
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

moduleConf.alsoCheckUsername does not match the configuration key defined in this module's config schema (alsoCheckUsernames), so the username-check path will never run. Rename one side so the code reads the actual configured flag (and keep naming consistent across config + implementation).

Suggested change
} else if (moduleConf.alsoCheckUsername) {
} else if (moduleConf.alsoCheckUsernames) {

Copilot uses AI. Check for mistakes.
newName = await checkUsername(client, guildMember.user.username);
if (newName === guildMember.user.username) return;
} else return;
if (guildMember.guild.ownerId === guildMember.id) {
client.logger.error('[nicknames] ' + localize('name-list-cleaner', 'owner-cannot-be-renamed', {u: guildMember.user.username}))
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

The log prefix here is [nicknames] but the message is for the name-list-cleaner module. This makes operational debugging harder; switch the prefix/tag to [name-list-cleaner] for consistency with the rest of this file’s logging.

Suggested change
client.logger.error('[nicknames] ' + localize('name-list-cleaner', 'owner-cannot-be-renamed', {u: guildMember.user.username}))
client.logger.error('[name-list-cleaner] ' + localize('name-list-cleaner', 'owner-cannot-be-renamed', {u: guildMember.user.username}))

Copilot uses AI. Check for mistakes.
return;
}
if (moduleConf.keepNickname) {
try {
await guildMember.setNickname(newName);
} catch (e) {
client.logger.error('[name-list-cleaner] ' + localize('name-list-cleaner', 'nickname-error', {u: guildMember.user.username, e: e}))
}
} else {
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

If alsoCheckUsernames is enabled and keepNickname is false, this code will attempt setNickname(null, ...) even when the member already has no nickname (no-op but still an API call + audit log entry). Consider short-circuiting when guildMember.nickname === null in this branch to avoid unnecessary requests.

Suggested change
} else {
} else {
if (guildMember.nickname === null) {
return;
}

Copilot uses AI. Check for mistakes.
await guildMember.setNickname(null, localize('name-list-cleaner', 'nickname-reset', {u: guildMember.user.username}));
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

In the keepNickname === false branch, setNickname(null, ...) is awaited without error handling. Other nickname-changing code in this repo wraps setNickname in try/catch (or .catch) to avoid unhandled rejections when the bot lacks permissions / role hierarchy is too low; apply the same handling here.

Suggested change
await guildMember.setNickname(null, localize('name-list-cleaner', 'nickname-reset', {u: guildMember.user.username}));
try {
await guildMember.setNickname(null, localize('name-list-cleaner', 'nickname-reset', {u: guildMember.user.username}));
} catch (e) {
client.logger.error('[name-list-cleaner] ' + localize('name-list-cleaner', 'nickname-error', {u: guildMember.user.username, e: e}))
}

Copilot uses AI. Check for mistakes.
}
}

module.exports.renameMember = renameMember;

async function checkUsername(client, name) {
const moduleConf = client.configurations['name-list-cleaner']['config'];
if (name.length === 0) return 'INVALID NAME';
if (moduleConf.symbolWhitelist === []) {
Comment on lines +34 to +35
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

When the input name consists entirely of stripped characters, this returns the hard-coded string 'INVALID NAME', which would then be applied as a nickname. Consider returning null/'' and handling that in renameMember (e.g., reset nickname or skip) so the bot never sets a literal "INVALID NAME" nickname.

Suggested change
if (name.length === 0) return 'INVALID NAME';
if (moduleConf.symbolWhitelist === []) {
if (name.length === 0) return null;
if (!Array.isArray(moduleConf.symbolWhitelist) || moduleConf.symbolWhitelist.length === 0) {

Copilot uses AI. Check for mistakes.
if (name.charAt(0).match(/^[a-zA-Z0-9]$/)) {
return name;
} else {
return await checkUsername(client, name.substring(1));
}
} else if (!moduleConf.symbolWhitelist.includes(name.charAt(0)) && !moduleConf.isBlacklist) {
Comment on lines +34 to +41
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

moduleConf.symbolWhitelist === [] will always be false in JS (array reference comparison). This breaks the intended “empty list” behavior (especially when isBlacklist is true). Use an emptiness check like Array.isArray(...) && symbolWhitelist.length === 0 (and ensure the empty-list behavior matches the config description).

Copilot uses AI. Check for mistakes.
if (name.charAt(0).match(/^[a-zA-Z0-9]$/)) {
return name;
} else {
return await checkUsername(client, name.substring(1));
}
} else if (moduleConf.symbolWhitelist.includes(name.charAt(0)) && moduleConf.isBlacklist) {
return await checkUsername(client, name.substring(1));
} else {
return name;
}
}