feat(social): блокировка пользователей

- PUT/DELETE /users/@me/blocks/{id}: блокировка снимает дружбу и заявки в обе
  стороны, разблокировка возвращает возможность писать (AGENT.md 7.2)
- блокировка запрещает личные сообщения (ошибка dm.blocked), открытие беседы и
  заявки в друзья с любой стороны
- клиент: раздел «Заблокированные» в друзьях со снятием блокировки, действие
  «Заблокировать» в меню строки друга и в меню модерации участника
- тесты: Go (блокировка, заявки, беседа, сообщение) и Vitest (список, снятие,
  блокировка из меню)
This commit is contained in:
2026-09-21 19:21:00 +03:00
parent afcdf9c1c4
commit ed98c78c9e
11 changed files with 461 additions and 5 deletions
+61
View File
@@ -15,6 +15,7 @@ import {
messagesRoutes,
recordedRequests,
renderApp,
waitForPage,
type FetchRoute,
} from './helpers';
@@ -891,3 +892,63 @@ describe('события шлюза о друзьях', () => {
});
});
});
describe('блокировка пользователей', () => {
it('показывает заблокированных и снимает блокировку', async () => {
const blocked = relationship({
user_id: 'user-7',
username: 'spammer',
display_name: 'Spammer',
relationship: 'blocked',
});
const fetchMock = installFetch(
baseRoutes({ friends: [], incoming: [], outgoing: [], blocked: [blocked] }, [
{
match: '/api/v1/users/@me/blocks/user-7',
method: 'DELETE',
response: () => json({ ok: true }),
},
]),
);
renderApp('/app/friends');
await waitForPage('Друзья');
const section = await screen.findByTestId('friends-blocked');
expect(within(section).getByText('Spammer')).toBeVisible();
await userEvent.click(screen.getByTestId('blocked-unblock-user-7'));
await waitFor(() => {
expect(
recordedRequests(fetchMock).some(
(request) => request.method === 'DELETE' && request.url.includes('/blocks/user-7'),
),
).toBe(true);
});
});
it('блокирует друга из меню строки', async () => {
const fetchMock = installFetch(
baseRoutes({ friends: [bob], incoming: [], outgoing: [], blocked: [] }, [
{
match: '/api/v1/users/@me/blocks/user-2',
method: 'PUT',
response: () => json({ ok: true }),
},
]),
);
renderApp('/app/friends');
await waitForPage('Друзья');
await userEvent.click(await screen.findByTestId('friends-list-toggle'));
await userEvent.click(await screen.findByLabelText('Действия: Боб'));
await userEvent.click(await screen.findByTestId('friend-block-user-2'));
await waitFor(() => {
expect(
recordedRequests(fetchMock).some(
(request) => request.method === 'PUT' && request.url.includes('/blocks/user-2'),
),
).toBe(true);
});
});
});