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
82 changes: 75 additions & 7 deletions locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,36 @@
"edit-modal-username-placeholder": "Username of the user",
"user-not-found": "User not found"
},
"guess-the-number": {
"command-description": "Manage your guess-the-number-games",
"status-command-description": "Shows the current status of a guess-the-number-game in this channel",
"create-command-description": "Create a new guess-the-number-game in this channel",
"create-min-description": "Minimal value users can guess",
"create-max-description": "Maximal value users can guess",
"create-number-description": "Number users should guess to win",
"end-command-description": "Ends the current game",
"session-already-running": "There is a session already running in this channel. Please end it with /guess-the-number end",
"session-not-running": "There is currently no session running.",
"gamechannel-modus": "You can't use this command in a gamechannel. To end a game, disable the gamechannel modus and try using the end command.",
"session-ended-successfully": "Ended session successfully. Locked channel successfully.",
"current-session": "Current session",
"number": "Number",
"min-val": "Min-Value",
"max-val": "Max-Value",
"owner": "Owner",
"guess-count": "Count of guesses",
"min-max-discrepancy": "`min` can't be bigger or equal to `max`",
"max-discrepancy": "`number` can't be bigger than `max`.",
"min-discrepancy": "`number` can't be smaller than `min`.",
"emoji-guide-button": "What does the reaction under my guess mean?",
"guide-wrong-guess": "Your guess was wrong (but your entry was valid)",
"guide-win": "You guessed correctly - you win :tada:",
"guide-admin-guess": "Your guess was invalid, because you are an admin - admins can't participate because they can see the correct number",
"guide-invalid-guess": "Your guess was invalid (e.g. below the minimal / over the maximal number, not a number, …)",
"created-successfully": "Created game successfully. Users can now start guessing in this channel. The winning number is **%n**. You can always check the status by running `/guess-the-number-status`. Note that you as an admin can not guess.",
"game-ended": "Game ended",
"game-started": "Game started"
},
"massrole": {
"command-description": "Manage roles for all members",
"add-subcommand-description": "Add a role to all members",
Expand Down Expand Up @@ -961,10 +991,7 @@
"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)",
"panel-description": "Manage and view data for %u (%i). You can see the user's ping history, moderation actions, quick recap of both, and view data deletion options for this user.",
"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 when pinged by someone with a whitelisted role/as a whitelisted user or when it's sent in a whitelisted channel.",
"field-protected-users": "Protected Users",
Expand All @@ -977,9 +1004,8 @@
"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-phrase": "I understand that the 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.",
"modal-success-data-deletion": "All data for the user <@%u> (%u) has been deleted successfully",
"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 @@ -992,6 +1018,48 @@
"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"
"list-entry-text": "%index. **Pinged %target** at %time\n%link",
"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-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",
"log-punish-log-send-failed": "[Ping Protection] Failed to send the punishment failure message: %e",
"log-modlog-create-failed": "[Ping Protection] Failed to store the moderation log for user %u: %e",
"log-ping-history-create-failed": "[Ping Protection] Failed to store ping history for user %u: %e",
"log-recent-mod-check-failed": "[Ping Protection] Failed to check recent moderation actions for user %u: %e",
"panel-ph": "Select an option",
"panel-opt-over": "Overview",
"panel-opt-hist": "Ping History",
"panel-opt-actions": "Moderation History",
"panel-opt-delete": "Data Deletion",
"panel-deletion-title": "Data Deletion: %u",
"panel-deletion-desc": "⚠️ DANGEROUS AREA ⚠️\nYou are now entering a dangerous zone. At this place, you are able to delete specific or all data for the selected user. These actions ***CANNOT BE UNDONE*** and should only be used if you are absolutely sure about what you are doing.\nIf you are unsure, click 'Go Back' from the dropdown now.\nUse the dropdown below to choose which data you want to delete or delete all data. Choose wisely and gracefully.",
"panel-deletion-placeholder": "Select a deletion option",
"panel-opt-back": "Go back",
"panel-opt-del-pings": "Ping History Deletion",
"panel-opt-del-actions": "Moderation History Deletion",
"panel-opt-del-all": "Delete All Data",
"panel-deletion-cooldown-active": "Data deletion is currently blocked for this user because of a recent %type deletion. Deletion will be available again at %time.",
"del-type-pings": "ping history",
"del-type-actions": "moderation history",
"del-type-all": "full data",
"del-type-unknown": "data",
"del-all-admin-only": "Only users with Administrator permissions can delete all stored data for a user.",
"err-del-cooldown": "Data deletion for this user is currently on cooldown because of a recent %time deletion. You can delete data again at %until.",
"del-all-title": "Confirm full data deletion",
"del-all-desc": "You are about to delete ALL data for this user. Reminder that this ***cannot be undone***. This is the last chance to back out. If you are sure, click the button below.\nThis action will automatically cancel in 30 seconds.",
"btn-conf-del": "Confirm deletion",
"btn-cancel": "Cancel",
"succ-del-canc": "Data deletion cancelled.",
"err-del-time": "⏳ Data deletion timed out and was cancelled. Please try again if you still want to delete data for this user.",
"succ-del-tgt": "The selected %type data was deleted successfully. Deletion for this user is now on cooldown until %until.",
"succ-del-all": "All stored Ping Protection data for this user was deleted successfully. Deletion for this user is now on cooldown until %until.",
"log-del-type": "[Ping Protection] Deleted %type data for user %target by %admin.",
"log-del-all": "[Ping Protection] Deleted all stored data for user %target by %admin."
}
}
53 changes: 6 additions & 47 deletions modules/ping-protection/commands/ping-protection.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const {
fetchModHistory,
getPingCountInWindow,
generateHistoryResponse,
generateActionsResponse
generateActionsResponse,
generateUserPanel
} = require('../ping-protection');
const { localize } = require('../../../src/functions/localize');
const { truncate } = require('../../../src/functions/helpers');
const { ActionRowBuilder, ButtonBuilder, EmbedBuilder, ButtonStyle, MessageFlags } = require('discord.js');
const { EmbedBuilder, MessageFlags } = require('discord.js');

module.exports.run = async function (interaction) {
const group = interaction.options.getSubcommandGroup(false);
Expand All @@ -33,50 +32,10 @@ module.exports.subcommands = {
},
'panel': async function (interaction) {
const user = interaction.options.getUser('user');
const pingerId = user.id;
const storageConfig = interaction.client.configurations['ping-protection']['storage'];
const retentionWeeks = (storageConfig && storageConfig.pingHistoryRetention)
? storageConfig.pingHistoryRetention
: 12;
const timeframeDays = retentionWeeks * 7;

const pingCount = await getPingCountInWindow(interaction.client, pingerId, timeframeDays);
const modData = await fetchModHistory(interaction.client, pingerId, 1, 1000);
const payload = await generateUserPanel(interaction.client, user);

const row = new ActionRowBuilder().addComponents(
new ButtonBuilder()
.setCustomId(`ping-protection_history_${user.id}`)
.setLabel(localize('ping-protection', 'btn-history'))
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId(`ping-protection_actions_${user.id}`)
.setLabel(localize('ping-protection', 'btn-actions'))
.setStyle(ButtonStyle.Secondary),
new ButtonBuilder()
.setCustomId(`ping-protection_delete_${user.id}`)
.setLabel(localize('ping-protection', 'btn-delete'))
.setStyle(ButtonStyle.Danger)
);

const embed = new EmbedBuilder()
.setTitle(localize('ping-protection', 'panel-title', { u: user.tag }))
.setDescription(localize('ping-protection', 'panel-description', { u: user.toString(), i: user.id }))
.setColor('Blue')
.setThumbnail(user.displayAvatarURL({ dynamic: true }))
.addFields([{
name: localize('ping-protection', 'field-quick-history', { w: retentionWeeks }),
value: localize('ping-protection', 'field-quick-desc', { p: pingCount, m: modData.total }),
inline: false
}])
.setFooter({
text: interaction.client.strings.footer,
iconURL: interaction.client.strings.footerImgUrl
});
if (!interaction.client.strings.disableFooterTimestamp) embed.setTimestamp();

await interaction.reply({
embeds: [embed.toJSON()],
components: [row.toJSON()],
await interaction.reply({
...payload,
flags: MessageFlags.Ephemeral
});
}
Expand Down
13 changes: 9 additions & 4 deletions modules/ping-protection/configs/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,12 @@
"content": "channelID",
"default": {
"en": []
}
},
"channelTypes": [
"GUILD_TEXT",
"GUILD_NEWS",
"GUILD_CATEGORY"
]
},
{
"name": "ignoredUsers",
Expand Down Expand Up @@ -179,10 +184,10 @@
"name": "enableAutomod",
"category": "automod",
"humanName": {
"en": "Enable automod"
"en": "Enable AutoMod"
},
"description": {
"en": "If enabled, the bot will utilise Discord's native AutoMod to block the message with a ping of a protected user/role."
"en": "If enabled, the bot will utilise Discord's native AutoMod to block the message with a ping of a protected user/role. Warning: AutoMod does not support whitelisted categories due to limitations in Discord's AutoMod system - instead, it will still block the message but not log it in the history."
},
"type": "boolean",
"default": {
Expand All @@ -196,7 +201,7 @@
"en": "AutoMod Log Channel"
},
"description": {
"en": "Channel where AutoMod alerts are sent."
"en": "Channel where AutoMod alerts are sent. It is recommended to keep these in a private channel."
},
"type": "channelID",
"default": {
Expand Down
32 changes: 32 additions & 0 deletions modules/ping-protection/configs/moderation.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,37 @@
"en": 10
}
},
{
"name": "enableRolePingThresholds",
"humanName": {
"en": "Enable role-based ping thresholds"
},
"description": {
"en": "If enabled, specific roles can have custom ping thresholds for this moderation action. This also allows specific roles to be exempted from this specific action."
},
"type": "boolean",
"default": {
"en": false
}
},
{
"name": "rolePingThresholds",
"humanName": {
"en": "Role-based ping thresholds"
},
"description": {
"en": "Set custom ping thresholds per role for this moderation action. If a user has multiple configured roles, the value of their highest configured role is used. Setting a role to 0 exempts that role from this action - exempted roles also override any other role's threshold."
},
"type": "keyed",
"content": {
"key": "roleID",
"value": "integer"
},
"default": {
"en": {}
},
"dependsOn": "enableRolePingThresholds"
},
{
"name": "useCustomTimeframe",
"humanName": {
Expand Down Expand Up @@ -106,6 +137,7 @@
"en": "The message that will be sent when a user is punished for pinging protected users/roles."
},
"type": "string",
"dependsOn": "enableActionLogging",
"allowEmbed": true,
"params": [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { processPing } = require('../ping-protection');
const { processPing, isWhitelistedChannel } = require('../ping-protection');

// Handles auto mod actions
module.exports.run = async function (client, execution) {
Expand All @@ -16,6 +16,8 @@ module.exports.run = async function (client, execution) {
if (!originChannel && execution.channelId) {
originChannel = await execution.guild.channels.fetch(execution.channelId).catch(() => null);
}
if (isWhitelistedChannel(config, originChannel)) return;

const memberToPunish = await execution.guild.members.fetch(execution.userId).catch(() => null);

if (!isProtected && config.protectAllUsersWithProtectedRole) {
Expand Down
Loading