feat(web): разделы «Баны» и «Журнал аудита» в настройках сервера

Фаза 4 (AGENT.md 7.17, 7.18): модерация из интерфейса.

- `api/moderation.ts`: список банов, бан, разбан, тайм-аут, кик и журнал
  аудита с фильтрами;
- «Баны»: причина и автор каждого бана, снятие бана и пресеты тайм-аута
  (1/5/10/60/1440 минут) прямо из списка; ответ сервера обновляет кэш, поэтому
  строка исчезает без перезагрузки;
- «Журнал аудита»: фильтры по действию, автору и цели уходят в запрос,
  кнопки «Показать» и «Сбросить»;
- секции видны только с правами BAN_MEMBERS и VIEW_AUDIT_LOG
  (`canBanMembers`, `canViewAuditLog`);
- тесты: список с причиной и автором, снятие бана с обновлением списка,
  тайм-аут с проверкой времени, скрытие секций без прав, фильтры в запросе.
This commit is contained in:
2026-09-20 22:43:56 +03:00
parent 4fb3509128
commit 8613989b21
7 changed files with 764 additions and 3 deletions
+24 -1
View File
@@ -7,7 +7,14 @@ import { fetchMyGuilds, myGuildsQueryKey } from '@/api/users';
import { ErrorNotice } from '@/components/ui/ErrorNotice';
import { Card } from '@/components/ui/primitives';
import { SkeletonLines } from '@/components/ui/Skeleton';
import { canAdministerGuild, canManageEmojis, canManageSounds } from '@/lib/identity';
import { GuildAuditSection, GuildBansSection } from '@/pages/settings/GuildModerationSections';
import {
canAdministerGuild,
canBanMembers,
canManageEmojis,
canManageSounds,
canViewAuditLog,
} from '@/lib/identity';
import { useCurrentUser } from '@/lib/hooks';
import { useSessionStore } from '@/stores/session';
import { GuildDangerSection } from '@/pages/settings/GuildDangerSection';
@@ -151,6 +158,20 @@ function GuildSettingsBody({ guilds }: { guilds: { id: string }[] }) {
currentUser.data?.is_instance_admin === true,
);
// «Баны» и журнал аудита (AGENT.md 7.17, 7.18).
const canBan = canBanMembers(
guild.my_permissions,
guild.owner_id,
currentUser.data?.id,
currentUser.data?.is_instance_admin === true,
);
const canViewAudit = canViewAuditLog(
guild.my_permissions,
guild.owner_id,
currentUser.data?.id,
currentUser.data?.is_instance_admin === true,
);
// «Звуки» (AGENT.md 7.13) — та же логика для права MANAGE_SOUNDS.
const canManageSoundSet = canManageSounds(
guild.my_permissions,
@@ -175,6 +196,8 @@ function GuildSettingsBody({ guilds }: { guilds: { id: string }[] }) {
{canManageSoundSet ? (
<GuildSoundsSection key={`${guild.id}-sounds`} guildId={guild.id} />
) : null}
<GuildBansSection key={`${guild.id}-bans`} guildId={guild.id} canBan={canBan} />
<GuildAuditSection key={`${guild.id}-audit`} guildId={guild.id} canView={canViewAudit} />
<GuildDangerSection
key={`${guild.id}-danger`}
guildId={guild.id}