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:
@@ -6,8 +6,10 @@ import type {
|
||||
AutomodConfigDashboard,
|
||||
AutomodRuleDashboard
|
||||
} from '@nexumi/shared';
|
||||
import { mergeDefaultBlockedWords } from '@nexumi/shared';
|
||||
import { FieldAnchor } from '@/components/layout/field-anchor';
|
||||
import { useTranslations } from '@/components/locale-provider';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { DiscordChannelMultiSelect } from '@/components/ui/discord-channel-select';
|
||||
import { DiscordRoleMultiSelect } from '@/components/ui/discord-role-select';
|
||||
@@ -25,19 +27,26 @@ async function saveAutomod(guildId: string, value: AutomodConfigDashboard): Prom
|
||||
try {
|
||||
const cleaned: AutomodConfigDashboard = {
|
||||
...value,
|
||||
rules: value.rules.map((rule) => ({
|
||||
...rule,
|
||||
durationMs: rule.action === 'TIMEOUT' ? rule.durationMs ?? 60_000 : null,
|
||||
threshold: {
|
||||
...rule.threshold,
|
||||
linkWhitelist: (rule.threshold.linkWhitelist ?? []).map((s) => s.trim()).filter(Boolean),
|
||||
linkBlacklist: (rule.threshold.linkBlacklist ?? []).map((s) => s.trim()).filter(Boolean)
|
||||
},
|
||||
wordList: {
|
||||
words: (rule.wordList.words ?? []).map((s) => s.trim()).filter(Boolean),
|
||||
regexPatterns: (rule.wordList.regexPatterns ?? []).map((s) => s.trim()).filter(Boolean)
|
||||
}
|
||||
}))
|
||||
rules: value.rules.map((rule) => {
|
||||
const words = (rule.wordList.words ?? []).map((s) => s.trim()).filter(Boolean);
|
||||
const regexPatterns = (rule.wordList.regexPatterns ?? [])
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
return {
|
||||
...rule,
|
||||
durationMs: rule.action === 'TIMEOUT' ? rule.durationMs ?? 60_000 : null,
|
||||
threshold: {
|
||||
...rule.threshold,
|
||||
linkWhitelist: (rule.threshold.linkWhitelist ?? []).map((s) => s.trim()).filter(Boolean),
|
||||
linkBlacklist: (rule.threshold.linkBlacklist ?? []).map((s) => s.trim()).filter(Boolean)
|
||||
},
|
||||
wordList: {
|
||||
words,
|
||||
regexPatterns,
|
||||
...(words.length === 0 ? { userCleared: true as const } : {})
|
||||
}
|
||||
};
|
||||
})
|
||||
};
|
||||
const response = await fetch(`/api/guilds/${guildId}/automod`, {
|
||||
method: 'PATCH',
|
||||
@@ -279,7 +288,24 @@ function RuleCard({
|
||||
{type === 'WORD_FILTER' ? (
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<div className="space-y-2">
|
||||
<Label>{t('modulePages.automod.wordList')}</Label>
|
||||
<div className="flex flex-wrap items-center justify-between gap-2">
|
||||
<Label>{t('modulePages.automod.wordList')}</Label>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
onChange({
|
||||
wordList: {
|
||||
...rule.wordList,
|
||||
words: mergeDefaultBlockedWords(rule.wordList.words ?? [])
|
||||
}
|
||||
})
|
||||
}
|
||||
>
|
||||
{t('modulePages.automod.loadDefaultWords')}
|
||||
</Button>
|
||||
</div>
|
||||
<StringListEditor
|
||||
value={rule.wordList.words}
|
||||
onChange={(words) => onChange({ wordList: { ...rule.wordList, words } })}
|
||||
|
||||
Reference in New Issue
Block a user