Skip to content
Draft
37 changes: 27 additions & 10 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@
"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-kick-dm-failed": "[Ping Protection] Failed to send kick DM to user %u: %e",
"log-action-log-failed": "[Ping Protection] Punishment logging failed: %e",
"log-data-deletion": "[Ping Protection] All data for the user with ID %u has been deleted successfully.",
"log-automod-keyword-limit": "[Ping Protection] Automod keywords exceed 1000 characters limit. Keywords were truncated.",
Expand All @@ -744,6 +745,7 @@
"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-toggle": "Temporarily toggle your ping protection on or off.",
"cmd-desc-list-protected": "List of all the protected users and roles",
"cmd-desc-list-wl": "List of all the whitelisted roles, channels and users",
"embed-history-title": "Ping history of %u",
Expand All @@ -764,13 +766,14 @@
"field-wl-channels": "Whitelisted Channels",
"field-wl-users": "Whitelisted Users",
"list-none": "None are configured.",
"modal-title": "Confirm data deletion for this user",
"fallback-modal-title": "Confirm data deletion",
"modal-label": "Confirm data deletion by typing this phrase:",
"fallback-modal-label": "Confirm by typing this phrase:",
"modal-phrase": "I understand that the data of this user will be deleted and that this action cannot be undone.",
"fallback-modal-phrase": "I confirm the data deletion of this user with risks.",
"modal-failed": "The phrase you entered is incorrect. Data deletion cancelled.",
"list-user-paused": "temporarily paused",
"del-modal-title": "Confirm data deletion",
"del-modal-label": "Confirm by typing this phrase:",
"del-conf-phrase": "I confirm the data deletion for this user.",
"modal-failed": "The phrase you entered is incorrect. Data deletion has been cancelled.",
"del-modal-timeframe-label": "Only delete data older than (Optional)",
"del-modal-timeframe-ph": "E.g. 7d to delete data older than 7 days. (Leave empty to delete all)",
"del-err-invalid-timeframe": "The timeframe you provided is invalid. Use a positive number of days (e.g. 7) or a format like 7d, 2w, or 24h.",
"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 \"Data Storage\" tab in the 'ping-protection' module ^^",
Expand All @@ -781,15 +784,20 @@
"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",
"label-jump": "Jump to message",
"ping-mention": "Mention",
"ping-reply": "Reply",
"ping-unknown": "Unknown",
"label-type": "Type of ping",
"no-message-link": "This ping was blocked by AutoMod",
"list-entry-text": "%index. **Pinged %target** at %time\n%link",
"list-entry-text": "%index. **Pinged %target** at %time\n%type",
"punish-log-docs-title": "Troubleshooting",
"punish-log-docs-desc": "This issue is documented in the documentation - you can see how to fix this issue [in the documentation](https://docs.scnx.xyz/docs/custom-bot/modules/moderation/ping-protection/#troubleshooting). Please try the steps mentioned there before contacting support as it's very likely the steps mentioned will fix your issue ^^",
"log-fetch-mod-history-failed": "[Ping Protection] Failed to fetch moderation history for user %u: %e",
"log-warning-build-failed": "[Ping Protection] Failed to build the warning message: %e",
"log-warning-reply-failed": "[Ping Protection] Failed to send the warning message as a reply: %e",
"log-warning-send-failed": "[Ping Protection] Failed to send the fallback warning message in channel %c: %e",
"log-warning-delete-failed": "[Ping Protection] Failed to automatically delete the warning message: %e",
"log-automod-channel-fetch-failed": "[Ping Protection] Failed to refresh the guild channel cache while syncing AutoMod: %e",
"log-automod-rule-delete-failed": "[Ping Protection] Failed to delete the native AutoMod rule: %e",
"log-automod-sync-failed": "[Ping Protection] AutoMod sync failed: %e",
Expand Down Expand Up @@ -829,7 +837,16 @@
"view-moderation-history-description": "View this user's moderation history",
"view-ping-history-description": "View this user's ping history",
"log-automod-role-protection-skipped": "[Ping Protection] Skipped adding role-based protected users to the native AutoMod rule because the GuildMembers intent is not granted. Only explicitly configured protected users are included until GuildMembers is enabled.",
"no-reason": "No reason provided"
"no-reason": "No reason provided",
"toggle-disabled-by-admin": "Toggling your ping protection status is currently disabled by a bot administrator. Please contact them if you want to change your protection status.",
"toggle-err-not-protected": ":x: You are not a protected member, so you cannot toggle your protection status :/",
"toggle-err-failed": "An error occurred while updating your protection status. Please try again later or contact the bot's administrator.",
"toggle-succ-disabled": "Your ping protection is now paused until %time (24 hours). Members can mention you without triggering notices. You can reactivate it anytime using `/ping-protection toggle`.",
"toggle-succ-enabled": "Your ping protection has been reactivated. You are now protected from pings.",
"log-check-preference-failed": "[Ping Protection] Failed to find ping preference for user %u: %e",
"log-toggle-preference-failed": "[Ping Protection] Failed to toggle ping preference for user %u: %e",
"toggle-pref-failed": "An error occurred while toggling your ping protection preference. Please try again later or contact the bot's administrator.",
"toggle-not-protected": "You are not a protected member, so you cannot toggle your ping protection preference."
},
"polls": {
"what-have-i-votet": "What have I voted?",
Expand Down
201 changes: 138 additions & 63 deletions modules/ping-protection/commands/ping-protection.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,22 @@ const {
generateHistoryResponse,
generateActionsResponse,
generateUserPanel
} = require('../ping-protection');
} = require('../core/panels');
const {
toggleUserProtection,
isProtectionToggledOff
} = require('../core/toggle');
const {localize} = require('../../../src/functions/localize');
const {truncate, safeSetFooter} = require('../../../src/functions/helpers');
const {
truncate,
safeSetFooter,
dateToDiscordTimestamp
} = require('../../../src/functions/helpers');
const {
EmbedBuilder,
MessageFlags
} = require('discord.js');

module.exports.run = async function (interaction) {
const group = interaction.options.getSubcommandGroup(false);
const sub = interaction.options.getSubcommand(false);

if (group) {
return module.exports.subcommands[group][sub](interaction);
}
return module.exports.subcommands[sub](interaction);
};

// Handles subcommands
module.exports.subcommands = {
'user': {
Expand All @@ -40,6 +38,13 @@ module.exports.subcommands = {
});
},
'panel': async function (interaction) {
const isManager = interaction.member?.permissions.has('Administrator') || interaction.member?.permissions.has('ManageGuild');
if (!isManager) {
return interaction.reply({
content: localize('ping-protection', 'no-permission'),
flags: MessageFlags.Ephemeral
})
}
const user = interaction.options.getUser('user');
const payload = await generateUserPanel(interaction.client, user);
await interaction.reply({
Expand All @@ -48,6 +53,45 @@ module.exports.subcommands = {
});
}
},
'toggle': async function (interaction) {
const generalConfig = interaction.client.configurations['ping-protection']?.['configuration'] || {};
if (!generalConfig.allowProtectionToggle) {
return interaction.reply({
content: localize('ping-protection', 'toggle-disabled-by-admin'),
flags: MessageFlags.Ephemeral
});
}

const targetMember = interaction.member || interaction.user;
const result = await toggleUserProtection(interaction.client, targetMember);

if (!result.success) {
if (result.reason === 'not-protected') {
return interaction.reply({
content: localize('ping-protection', 'toggle-err-not-protected'),
flags: MessageFlags.Ephemeral
});
}
return interaction.reply({
content: localize('ping-protection', 'toggle-err-failed'),
flags: MessageFlags.Ephemeral
});
}

if (result.state === 'disabled') {
return interaction.reply({
content: localize('ping-protection', 'toggle-succ-disabled', {
time: dateToDiscordTimestamp(result.disabledUntil, 'R')
}),
flags: MessageFlags.Ephemeral
});
}

return interaction.reply({
content: localize('ping-protection', 'toggle-succ-enabled'),
flags: MessageFlags.Ephemeral
});
},
'list': {
'protected': async function (interaction) {
await listHandler(interaction, 'protected');
Expand All @@ -58,6 +102,7 @@ module.exports.subcommands = {
}
};

// Handles list subcommands
// Handles list subcommands
async function listHandler(interaction, type) {
const config = interaction.client.configurations['ping-protection']['configuration'];
Expand All @@ -72,11 +117,23 @@ async function listHandler(interaction, type) {
embed.setTitle(localize('ping-protection', 'list-protected-title'));
embed.setDescription(localize('ping-protection', 'list-protected-desc'));

const usersList = config.protectedUsers.length > 0
? config.protectedUsers.map(id => `<@${id}>`).join('\n')
: localize('ping-protection', 'list-none');
let usersList = localize('ping-protection', 'list-none');
if (Array.isArray(config.protectedUsers) && config.protectedUsers.length > 0) {
const formattedUsers = await Promise.all(config.protectedUsers.map(async (id) => {
const isOff = config.allowProtectionToggle
? await isProtectionToggledOff(interaction.client, id)
: false;

if (isOff) {
return `<@${id}> *(${localize('ping-protection', 'list-user-paused')})*`;
}
return `<@${id}>`;
}));

const rolesList = config.protectedRoles.length > 0
usersList = formattedUsers.join('\n');
}

const rolesList = Array.isArray(config.protectedRoles) && config.protectedRoles.length > 0
? config.protectedRoles.map(id => `<@&${id}>`).join('\n')
: localize('ping-protection', 'list-none');

Expand All @@ -97,15 +154,15 @@ async function listHandler(interaction, type) {
embed.setTitle(localize('ping-protection', 'list-whitelist-title'));
embed.setDescription(localize('ping-protection', 'list-whitelist-desc'));

const rolesList = config.ignoredRoles.length > 0
const rolesList = Array.isArray(config.ignoredRoles) && config.ignoredRoles.length > 0
? config.ignoredRoles.map(id => `<@&${id}>`).join('\n')
: localize('ping-protection', 'list-none');

const channelsList = config.ignoredChannels.length > 0
const channelsList = Array.isArray(config.ignoredChannels) && config.ignoredChannels.length > 0
? config.ignoredChannels.map(id => `<#${id}>`).join('\n')
: localize('ping-protection', 'list-none');

const usersList = config.ignoredUsers.length > 0
const usersList = Array.isArray(config.ignoredUsers) && config.ignoredUsers.length > 0
? config.ignoredUsers.map(id => `<@${id}>`).join('\n')
: localize('ping-protection', 'list-none');

Expand Down Expand Up @@ -140,48 +197,64 @@ module.exports.config = {
usage: '/ping-protection',
type: 'slash',
defaultPermission: false,
options: [
{
type: 'SUB_COMMAND_GROUP',
name: 'user',
description: localize('ping-protection', 'cmd-desc-group-user'),
options: [
{
type: 'SUB_COMMAND',
name: 'history',
description: localize('ping-protection', 'cmd-desc-history'),
options: [{
type: 'USER',
name: 'user',
description: localize('ping-protection', 'cmd-opt-user'),
required: true
}]
},
{
type: 'SUB_COMMAND',
name: 'actions-history',
description: localize('ping-protection', 'cmd-desc-actions'),
options: [{
type: 'USER',
name: 'user',
description: localize('ping-protection', 'cmd-opt-user'),
required: true
}]
},
{
type: 'SUB_COMMAND',
name: 'panel',
description: localize('ping-protection', 'cmd-desc-panel'),
options: [{
type: 'USER',
name: 'user',
description: localize('ping-protection', 'cmd-opt-user'),
required: true
}]
}
]
},
{
options: function (client) {
const array = [];

const storageConfig = client.configurations['ping-protection']['storage'] || {};
const generalConfig = client.configurations['ping-protection']['configuration'] || {};

if (storageConfig.enablePingHistory) {
array.push({
type: 'SUB_COMMAND_GROUP',
name: 'user',
description: localize('ping-protection', 'cmd-desc-group-user'),
options: [
{
type: 'SUB_COMMAND',
name: 'history',
description: localize('ping-protection', 'cmd-desc-history'),
options: [{
type: 'USER',
name: 'user',
description: localize('ping-protection', 'cmd-opt-user'),
required: true
}]
},
{
type: 'SUB_COMMAND',
name: 'actions-history',
description: localize('ping-protection', 'cmd-desc-actions'),
options: [{
type: 'USER',
name: 'user',
description: localize('ping-protection', 'cmd-opt-user'),
required: true
}]
},
{
type: 'SUB_COMMAND',
name: 'panel',
description: localize('ping-protection', 'cmd-desc-panel'),
options: [{
type: 'USER',
name: 'user',
description: localize('ping-protection', 'cmd-opt-user'),
required: true
}]
}
]
});
}

if (generalConfig.allowProtectionToggle) {
array.push({
type: 'SUB_COMMAND',
name: 'toggle',
description: localize('ping-protection', 'cmd-desc-toggle')
});
}

array.push({
type: 'SUB_COMMAND_GROUP',
name: 'list',
description: localize('ping-protection', 'cmd-desc-group-list'),
Expand All @@ -197,6 +270,8 @@ module.exports.config = {
description: localize('ping-protection', 'cmd-desc-list-wl')
}
]
}
]
});

return array;
}
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const {localize} = require('../../../src/functions/localize');
const {generateActionsResponse} = require('../ping-protection');
const {generateActionsResponse} = require('../core/panels');
const {MessageFlags} = require('discord.js');

module.exports.config = {
Expand Down
2 changes: 1 addition & 1 deletion modules/ping-protection/commands/view-ping-history.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const {localize} = require('../../../src/functions/localize');
const {generateHistoryResponse} = require('../ping-protection');
const {generateHistoryResponse} = require('../core/panels');
const {MessageFlags} = require('discord.js');

module.exports.config = {
Expand Down
Loading
Loading