feat(webhooks): вебхуки комнат — бэкенд, клиент и настройки комнаты
- миграция 00012: таблица webhooks, снимок имени и аватара в messages (AGENT.md 7.11)
- API: список/создание/правка/удаление и пересоздание токена (MANAGE_WEBHOOKS,
step-up при создании, аудит), загрузка аватара отдельной multipart-ручкой
- исполнение POST /webhooks/{id}/{token} без сессии: content, username,
avatar_url, файлы создателя вебхука, лимит 30/мин на вебхук
- клиент: пункт настроек «Комната» со списком вебхуков, копированием ссылки,
пересозданием токена и удалением
- сообщения вебхуков: имя, аватар и значок в ленте вместо «неизвестного автора»
- fix: неполный ответ REST больше не затирает данные READY-снапшота
This commit is contained in:
@@ -2,6 +2,7 @@ import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { act } from '@testing-library/react';
|
||||
|
||||
import { parseGatewaySnapshot } from '@/api/gateway';
|
||||
import type { GuildSummary } from '@/api/types';
|
||||
import { dispatchGatewayEvent, useGatewayStore } from '@/stores/gateway';
|
||||
import { useSessionStore } from '@/stores/session';
|
||||
import { makeReadySnapshot } from './helpers';
|
||||
@@ -63,6 +64,46 @@ describe('session store', () => {
|
||||
expect(useGatewayStore.getState().heartbeatIntervalMs).toBe(45_000);
|
||||
});
|
||||
|
||||
it('не затирает данные снапшота неполной сводкой REST', () => {
|
||||
act(() => {
|
||||
dispatchGatewayEvent({
|
||||
op: 0,
|
||||
t: 'READY',
|
||||
s: 1,
|
||||
d: makeReadySnapshot([
|
||||
{
|
||||
id: 'g-1',
|
||||
name: 'Main',
|
||||
owner_id: 'user-9',
|
||||
is_main: true,
|
||||
my_permissions: ['MANAGE_WEBHOOKS'],
|
||||
channels: [{ id: 'c-1', name: 'general', position: 0 }],
|
||||
},
|
||||
]),
|
||||
});
|
||||
});
|
||||
|
||||
// Ответ REST пришёл без части полей: undefined не должен перетирать снапшот.
|
||||
act(() => {
|
||||
useSessionStore.getState().upsertGuild({
|
||||
id: 'g-1',
|
||||
name: 'Main из REST',
|
||||
owner_id: undefined,
|
||||
is_main: undefined,
|
||||
member_count: undefined,
|
||||
my_role_ids: undefined,
|
||||
my_permissions: undefined,
|
||||
} as unknown as GuildSummary);
|
||||
});
|
||||
|
||||
const guild = useSessionStore.getState().guilds[0];
|
||||
expect(guild?.name).toBe('Main из REST');
|
||||
expect(guild?.owner_id).toBe('user-9');
|
||||
expect(guild?.is_main).toBe(true);
|
||||
expect(guild?.my_permissions).toEqual(['MANAGE_WEBHOOKS']);
|
||||
expect(guild?.channels.map((channel) => channel.id)).toEqual(['c-1']);
|
||||
});
|
||||
|
||||
it('keeps channels with can_send=false (only can_view=false is hidden)', () => {
|
||||
act(() => {
|
||||
dispatchGatewayEvent({
|
||||
|
||||
Reference in New Issue
Block a user