Enhance AutoMod functionality with default word list and improved filtering
- Introduced a default blocked words list for the WORD_FILTER, including common profanity in both English and German. - Updated the word matching logic to utilize Unicode word boundaries, reducing false positives. - Implemented a button in the WebUI to load the default word list, enhancing user experience. - Added functionality to seed default word filters only when necessary, preventing overwriting user-defined lists. - Improved localization for new features related to the word list in both English and German. - Documented changes in phase tracking to reflect the new AutoMod enhancements.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { Redis } from 'ioredis';
|
||||
import {
|
||||
capsRatio,
|
||||
contentMatchesBlockedWord,
|
||||
countEmojis,
|
||||
extractUrls,
|
||||
hasZalgo,
|
||||
@@ -124,15 +125,14 @@ function checkExternalLink(content: string, threshold: AutoModThreshold): Filter
|
||||
}
|
||||
|
||||
function checkWordFilter(content: string, wordList: AutoModWordList): FilterResult | null {
|
||||
const lower = content.toLowerCase();
|
||||
for (const word of wordList.words) {
|
||||
if (word.length > 0 && lower.includes(word.toLowerCase())) {
|
||||
if (contentMatchesBlockedWord(content, word)) {
|
||||
return { matched: true, ruleType: 'WORD_FILTER', reason: 'Blocked word' };
|
||||
}
|
||||
}
|
||||
for (const pattern of wordList.regexPatterns) {
|
||||
try {
|
||||
const regex = new RegExp(pattern, 'i');
|
||||
const regex = new RegExp(pattern, 'iu');
|
||||
if (regex.test(content)) {
|
||||
return { matched: true, ruleType: 'WORD_FILTER', reason: 'Blocked pattern' };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { PrismaClient } from '@prisma/client';
|
||||
import type { Prisma, PrismaClient } from '@prisma/client';
|
||||
import {
|
||||
DEFAULT_AUTOMOD_RULES,
|
||||
defaultAutoModWordList,
|
||||
shouldSeedDefaultBlockedWords,
|
||||
type AutoModExceptions,
|
||||
type AutoModThreshold,
|
||||
type AutoModWordList
|
||||
@@ -16,6 +18,26 @@ export async function getAutoModConfig(prisma: PrismaClient, guildId: string) {
|
||||
return config;
|
||||
}
|
||||
|
||||
async function seedDefaultWordFilterIfNeeded(prisma: PrismaClient, guildId: string) {
|
||||
const rule = await prisma.autoModRule.findUnique({
|
||||
where: { guildId_ruleType: { guildId, ruleType: 'WORD_FILTER' } },
|
||||
select: { id: true, wordList: true }
|
||||
});
|
||||
if (!rule || !shouldSeedDefaultBlockedWords(rule.wordList)) {
|
||||
return;
|
||||
}
|
||||
const existing = parseWordList(rule.wordList);
|
||||
await prisma.autoModRule.update({
|
||||
where: { id: rule.id },
|
||||
data: {
|
||||
wordList: {
|
||||
...defaultAutoModWordList(),
|
||||
regexPatterns: existing.regexPatterns
|
||||
} as Prisma.InputJsonValue
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function ensureDefaultAutoModRules(prisma: PrismaClient, guildId: string) {
|
||||
await ensureGuild(prisma, guildId);
|
||||
const existing = await prisma.autoModRule.findMany({
|
||||
@@ -24,19 +46,19 @@ export async function ensureDefaultAutoModRules(prisma: PrismaClient, guildId: s
|
||||
});
|
||||
const have = new Set(existing.map((row) => row.ruleType));
|
||||
const missing = DEFAULT_AUTOMOD_RULES.filter((rule) => !have.has(rule.ruleType));
|
||||
if (missing.length === 0) {
|
||||
return;
|
||||
if (missing.length > 0) {
|
||||
await prisma.autoModRule.createMany({
|
||||
data: missing.map((rule) => ({
|
||||
guildId,
|
||||
ruleType: rule.ruleType,
|
||||
action: rule.action,
|
||||
threshold: rule.threshold ?? undefined,
|
||||
wordList: rule.wordList ?? undefined,
|
||||
enabled: ['SPAM', 'MASS_MENTION', 'INVITE_LINK', 'PHISHING'].includes(rule.ruleType)
|
||||
}))
|
||||
});
|
||||
}
|
||||
await prisma.autoModRule.createMany({
|
||||
data: missing.map((rule) => ({
|
||||
guildId,
|
||||
ruleType: rule.ruleType,
|
||||
action: rule.action,
|
||||
threshold: rule.threshold ?? undefined,
|
||||
wordList: rule.wordList ?? undefined,
|
||||
enabled: ['SPAM', 'MASS_MENTION', 'INVITE_LINK', 'PHISHING'].includes(rule.ruleType)
|
||||
}))
|
||||
});
|
||||
await seedDefaultWordFilterIfNeeded(prisma, guildId);
|
||||
}
|
||||
|
||||
export async function getEnabledAutoModRules(prisma: PrismaClient, guildId: string) {
|
||||
@@ -71,7 +93,8 @@ export function parseWordList(raw: unknown): AutoModWordList {
|
||||
const obj = raw as Record<string, unknown>;
|
||||
return {
|
||||
words: Array.isArray(obj.words) ? obj.words.map(String) : [],
|
||||
regexPatterns: Array.isArray(obj.regexPatterns) ? obj.regexPatterns.map(String) : []
|
||||
regexPatterns: Array.isArray(obj.regexPatterns) ? obj.regexPatterns.map(String) : [],
|
||||
...(obj.userCleared === true ? { userCleared: true } : {})
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user