Skip to content
Draft
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
19 changes: 11 additions & 8 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 Down Expand Up @@ -764,12 +765,9 @@
"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.",
"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 cancelled.",
"field-quick-history": "Quick history view (Last %w weeks)",
"field-quick-desc": "Pings history amount: %p\nModeration actions amount: %m",
Expand All @@ -781,15 +779,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
48 changes: 46 additions & 2 deletions modules/ping-protection/configs/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,10 @@
"humanName": "AutoMod Log Channel",
"description": "Channel where AutoMod alerts are sent. It is recommended to keep these in a private channel.",
"type": "channelID",
"default": "",
"channelTypes": [
"content": [
"GUILD_TEXT"
],
"default": "",
"dependsOn": "enableAutomod"
},
{
Expand Down Expand Up @@ -178,6 +178,50 @@
"image": "https://scnx-cdn.scootkit.net/1769198862209-rJfCVKzAuo6uQLhPUe9o2P6ArJkDBSVUCEyUQM6bqt5WFKWK.gif",
"color": "#ed4245"
}
},
{
"name": "kickPunishmentMessage",
"category": "messages",
"humanName": "Warning Message",
"description": "The message that gets sent to the user's DM's when they are kicked for meeting a moderation action's treshold.'",
"type": "string",
"allowEmbed": true,
"params": [
{
"name": "reason",
"description": "The reason why the user was kicked."
},
{
"name": "pings",
"description": "The amount of pings that triggered the moderation action."
},
{
"name": "timeframe",
"description": "The time frame in which the pings occurred."
},
{
"name": "guild-name",
"description": "The name of the server."
}
],
"default": "You have been kicked from **%guild-name%** for pinging protected users/roles %pings% times within %timeframe% days."
},
{
"name": "autoDeleteWarningMessage",
"category": "messages",
"humanName": "Automatically delete warning message",
"description": "If enabled, you can set a custom time after which the warning message will automatically be deleted to keep the channel clean.",
"type": "boolean",
"default": true
},
{
"name": "deleteWarningMessageTime",
"category": "messages",
"humanName": "Automatic message deletion time",
"description": "The amount of time after which the warning message will automatically be deleted, in seconds.",
"type": "integer",
"default": 30,
"minValue": "1"
}
]
}
22 changes: 17 additions & 5 deletions modules/ping-protection/configs/moderation.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@
"type": "integer",
"default": 10
},
{
"name": "pingsType",
"humanName": "Type of ping",
"description": "The type of pings tht will trigger this moderation action",
"type": "select",
"content": [
"Mentions",
"Reply pings",
"Both"
],
"default": "Both"
},
{
"name": "enableRolePingThresholds",
"humanName": "Enable role-based ping thresholds",
Expand Down Expand Up @@ -42,11 +54,11 @@
"default": false
},
{
"name": "timeframeDays",
"humanName": "Timeframe (Days)",
"description": "In how many days must these pings occur?",
"type": "integer",
"default": 7,
"name": "customTimeFrame",
"humanName": "Custom timeframe",
"description": "In how much time must these pings occur? (use formats like 10s for 10 seconds, 1h for 1 hour or 1d for 1 day)",
"type": "string",
"default": "7d",
"dependsOn": "useCustomTimeframe"
},
{
Expand Down
8 changes: 4 additions & 4 deletions modules/ping-protection/configs/storage.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"name": "enablePingHistory",
"category": "pings",
"humanName": "Enable Ping History",
"description": "If enabled, the bot will keep a history of pings to enforce moderation actions.",
"description": "If enabled, the bot will keep a history of pings to enforce moderation actions. THIS IS REQUIRED TO USE MODERATION ACTIONS!",
"type": "boolean",
"default": true
},
Expand Down Expand Up @@ -69,11 +69,11 @@
"name": "leaverRetention",
"category": "leavers",
"humanName": "Leaver Data Retention (Days)",
"description": "How long to keep data after a user leaves (1-7 Days).",
"description": "How long to keep data after a user left the server (1-60 Days).",
"type": "integer",
"default": 1,
"default": 7,
"minValue": "1",
"maxValue": "7",
"maxValue": "60",
"dependsOn": "enableLeaverDataRetention"
}
]
Expand Down
27 changes: 6 additions & 21 deletions modules/ping-protection/events/interactionCreate.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,21 +103,9 @@ module.exports.run = async function (client, interaction) {
});
}

// Checks to ensure modal content fits Discord limits
let modalTitle = localize('ping-protection', 'modal-title');
if (modalTitle.length > 45) {
modalTitle = localize('ping-protection', 'fallback-modal-title');
}

let modalLabel = localize('ping-protection', 'modal-label');
if (modalLabel.length > 45) {
modalLabel = localize('ping-protection', 'fallback-modal-label');
}

let confirmationPhrase = localize('ping-protection', 'modal-phrase');
if (confirmationPhrase.length > 100) {
confirmationPhrase = localize('ping-protection', 'fallback-modal-phrase');
}
let modalTitle = localize('ping-protection', 'del-modal-title');
let modalLabel = localize('ping-protection', 'del-modal-label');
let confirmationPhrase = localize('ping-protection', 'del-conf-phrase');

const modal = new ModalBuilder()
.setCustomId(`ping-protection_del-confirm_${targetId}_${selection}`)
Expand Down Expand Up @@ -149,10 +137,7 @@ module.exports.run = async function (client, interaction) {
const targetId = parts[2];
const selection = parts.slice(3).join('_');

let confirmPhrase = localize('ping-protection', 'modal-phrase');
if (confirmPhrase.length > 100) {
confirmPhrase = localize('ping-protection', 'fallback-modal-phrase');
}
let confirmPhrase = localize('ping-protection', 'del-conf-phrase');

if (interaction.fields.getTextInputValue('confirm').trim() !== confirmPhrase) {
return interaction.reply({
Expand Down Expand Up @@ -242,8 +227,8 @@ module.exports.run = async function (client, interaction) {
}

if (btnInt.customId.includes('confirm')) {
await executeDataDeletion(client, targetId, 'del_all');
const blockedUntil = await setDeletionCooldown(client, targetId, 'del_all', btnInt.user.id);
await executeDataDeletion(client, targetId, selection);
const blockedUntil = await setDeletionCooldown(client, targetId, selection, btnInt.user.id);

client.logger.info(localize('ping-protection', 'log-del-all', {
target: targetId,
Expand Down
8 changes: 6 additions & 2 deletions modules/ping-protection/events/messageCreate.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const {
processPing,
sendPingWarning,
isWhitelistedChannel
isWhitelistedChannel,
determinePingType
} = require('../ping-protection');
const {localize} = require('../../../src/functions/localize');
const {randomElementFromArray} = require('../../../src/functions/helpers');
Expand Down Expand Up @@ -126,13 +127,16 @@ module.exports.run = async function (client, message) {
}
}

const pingType = determinePingType(message, target.id, isRole);

await processPing(
client,
message.author.id,
target.id,
isRole,
message.url,
message.channel,
memberToPunish
message.member,
pingType
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const {DataTypes} = require('sequelize');

const TABLE = 'ping_protection_history';

module.exports = {
tables: [TABLE],
up: async ({
context: {
queryInterface,
sequelize
}
}) => {
await sequelize.transaction(async (transaction) => {
const description = await queryInterface.describeTable(TABLE).catch(() => ({}));

if (!description.pingType) {
await queryInterface.addColumn(TABLE, 'pingType', {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null
}, {transaction});
}
});
},
down: async ({
context: {
queryInterface,
sequelize
}
}) => {
await sequelize.transaction(async (transaction) => {
const description = await queryInterface.describeTable(TABLE).catch(() => ({}));
if (description.pingType) {
await queryInterface.removeColumn(TABLE, 'pingType', {transaction});
}
});
}
};
5 changes: 5 additions & 0 deletions modules/ping-protection/models/PingHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ module.exports = class PingProtectionPingHistory extends Model {
isRole: {
type: DataTypes.BOOLEAN,
defaultValue: false
},
pingType: {
type: DataTypes.STRING,
allowNull: true,
defaultValue: null
}
}, {
tableName: 'ping_protection_history',
Expand Down
30 changes: 30 additions & 0 deletions modules/ping-protection/models/UserPingPreference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const {
DataTypes,
Model
} = require('sequelize');

module.exports = class PingProtectionUserPingPreference extends Model {
static init(sequelize) {
return super.init({
userId: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
disabledUntil: {
type: DataTypes.DATE,
allowNull: true,
defaultValue: null
}
}, {
tableName: 'ping_protection_user_preferences',
timestamps: true,
sequelize
});
}
};

module.exports.config = {
name: 'UserPingPreference',
module: 'ping-protection'
};
6 changes: 3 additions & 3 deletions modules/ping-protection/module.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@
"tags": [
"moderation"
],
"fa-icon": "fa-duotone fa-clock-alarm",
"fa-icon": "fa-duotone fa-solid fa-message-dot",
"humanReadableName": "Ping-Protection",
"description": "Powerful and highly customizable ping-protection module to protect members/roles from unwanted mentions with moderation capabilities.",
"description": "A powerful and highly customizable module to protect members and roles from unwanted mentions with moderation capabilities.",
"intents": [
"GuildMembers",
"GuildMessages",
Expand All @@ -31,7 +31,7 @@
"MessageContent"
],
"intentReasons": {
"GuildMembers": "Enumerates the holders of protected roles to detect unwanted mentions.",
"GuildMembers": "Checks members to see if they are protected from pings and if they are allowed to ping such users.",
"MessageContent": "Scans message content and mentions to catch pings of protected roles and users."
}
}
Loading
Loading