From fe41bfdd88d08ddeeff24d2db2495517133b964f Mon Sep 17 00:00:00 2001 From: Pepe44DEV Date: Thu, 2 Jul 2026 22:49:28 +0200 Subject: [PATCH] overhaul automod: fix dead toggles, expose hidden settings, add new filters Link-filter and spam-filter toggles in the dashboard wrote to config keys the backend never read, so both filters always ran regardless of the switch. Fixed by reading the same field names on both sides. Also surfaces backend features that already existed but had no UI: caps filter, a custom bad-word list, a role whitelist (members with these roles are ignored entirely), and tunable spam thresholds/window/timeout. Each filter now shows its relevant settings inline instead of hiding them in a separate generic panel. Adds two new detections: an invite-link filter separate from the general link filter, and mass-mention/raid protection with a configurable limit. Co-Authored-By: Claude Sonnet 5 --- frontend/src/pages/Automod.tsx | 199 ++++++++++++++++++++++++++++----- src/services/automodService.ts | 58 ++++++++-- 2 files changed, 219 insertions(+), 38 deletions(-) diff --git a/frontend/src/pages/Automod.tsx b/frontend/src/pages/Automod.tsx index 51e7aab..76b947a 100644 --- a/frontend/src/pages/Automod.tsx +++ b/frontend/src/pages/Automod.tsx @@ -1,8 +1,10 @@ -import { Card, CardContent, CardHeader, TextArea, Button, Separator, TextField, Label } from '@heroui/react'; -import { Shield, Link, Ban, AlertTriangle, Save, Info } from 'lucide-react'; +import { useState } from 'react'; +import { Card, CardContent, CardHeader, Input, TextArea, Button, Separator, TextField, Label } from '@heroui/react'; +import { Shield, Link2, Ban, AlertTriangle, Save, Info, MailWarning, AtSign, CaseUpper, X, UserPlus } from 'lucide-react'; import { useApp } from '../context/AppContext'; import { SectionCard } from '../components/shared/SectionCard'; import { ChannelSelect } from '../components/shared/ChannelSelect'; +import { RoleSelect } from '../components/shared/RoleSelect'; import { AppSwitch } from '../components/shared/AppSwitch'; import { useGuildResources } from '../hooks/useGuildResources'; @@ -15,9 +17,27 @@ const FILTERS = [ }, { key: 'linkFilter' as const, - icon: , + icon: , title: 'Link-Filter', - description: 'Blockiert bekannte schädliche Domains und nicht-whitelistete Links.', + description: 'Blockiert Links, die nicht auf der Whitelist stehen.', + }, + { + key: 'inviteFilter' as const, + icon: , + title: 'Einladungslink-Filter', + description: 'Blockiert Discord-Invites unabhängig vom Link-Filter.', + }, + { + key: 'mentionSpamFilter' as const, + icon: , + title: 'Mass-Mention-Schutz', + description: 'Verhindert Raid-artiges Massen-Pingen von Usern/Rollen.', + }, + { + key: 'capsFilter' as const, + icon: , + title: 'Caps-Filter', + description: 'Entfernt Nachrichten mit überwiegend GROSSBUCHSTABEN.', }, { key: 'spamFilter' as const, @@ -27,9 +47,26 @@ const FILTERS = [ }, ]; +function toList(value?: string) { + return (value || '').split(',').map((x) => x.trim()).filter(Boolean); +} + export function Automod() { const { settings, setSettings, saveSettingsPayload, currentGuildId } = useApp(); - const { channels } = useGuildResources(currentGuildId); + const { channels, roles } = useGuildResources(currentGuildId); + const [roleDraft, setRoleDraft] = useState(''); + + const cfg = settings.automodConfig || {}; + const whitelistRoles: string[] = cfg.whitelistRoles || []; + + const patchConfig = (patch: Record) => + setSettings((s) => ({ ...s, automodConfig: { ...(s.automodConfig || {}), ...patch } })); + + const addWhitelistRole = () => { + if (!roleDraft || whitelistRoles.includes(roleDraft)) return; + patchConfig({ whitelistRoles: [...whitelistRoles, roleDraft] }); + setRoleDraft(''); + }; return ( @@ -56,19 +93,80 @@ export function Automod() {
{FILTERS.map((f) => ( -
-
- {f.icon} +
+
+
+ {f.icon} +
+
+
{f.title}
+
{f.description}
+
+ patchConfig({ [f.key]: v })} + />
-
-
{f.title}
-
{f.description}
-
- setSettings((s) => ({ ...s, automodConfig: { ...(s.automodConfig || {}), [f.key]: v } }))} - /> + + {f.key === 'linkFilter' && (cfg.linkFilter ?? true) && ( +
+ + +