feat(chat): личный чат тьютор ↔ админ с вложениями
Диалоги 1:1 (один тред на тьютора), отдельный SSE-канал whatido:chat вместо общей ленты notifications, вложения с белым списком расширений и вставкой из буфера (Ctrl+V), очистка по chat_retention_days. Таблицы в бэкап, chat_attachments добавлен в sweepOrphanedUploads.
This commit is contained in:
@@ -70,6 +70,30 @@ ok('notification_reads нормализуются', nt.notification_reads[0].not
|
||||
ok('audit_log нормализуется', nt.audit_log[0].action === 'backup.download' && nt.audit_log[0].target === '{"size":5}', nt.audit_log[0]);
|
||||
ok('banned_ips нормализуются', nt.banned_ips[0].ip === '203.0.113.7');
|
||||
|
||||
const ch = normalizeRestoreData({
|
||||
...base,
|
||||
chat_threads: [{ id: 3, tutor_id: 1, last_message_text: 'привет', tutor_unread: 2, admin_unread: 1 }],
|
||||
chat_messages: [{ id: 9, thread_id: 3, sender_id: 1, body: 'привет' }],
|
||||
chat_attachments: [{ id: 4, message_id: 9, token: 'a'.repeat(32), path: '/uploads/1700000000000-abc123.png', name: 'photo.png', size: 1234 }],
|
||||
});
|
||||
ok('chat_threads нормализуются', ch.chat_threads[0].tutor_id === 1 && ch.chat_threads[0].tutor_unread === 2, ch.chat_threads[0]);
|
||||
ok('chat_messages нормализуются', ch.chat_messages[0].thread_id === 3 && ch.chat_messages[0].body === 'привет', ch.chat_messages[0]);
|
||||
ok('chat_attachments нормализуются', ch.chat_attachments[0].name === 'photo.png' && ch.chat_attachments[0].size === 1234, ch.chat_attachments[0]);
|
||||
let chatBad = false;
|
||||
try {
|
||||
normalizeRestoreData({ ...base, chat_messages: [{ id: 1, thread_id: 3, sender_id: 1, body: 'x'.repeat(5001) }] });
|
||||
} catch (e) {
|
||||
chatBad = true;
|
||||
}
|
||||
ok('слишком длинный текст сообщения отклоняется', chatBad);
|
||||
let chatPathBad = false;
|
||||
try {
|
||||
normalizeRestoreData({ ...base, chat_attachments: [{ id: 1, message_id: 1, token: 'b'.repeat(32), path: '/etc/passwd', name: 'x' }] });
|
||||
} catch (e) {
|
||||
chatPathBad = true;
|
||||
}
|
||||
ok('путь вложения вне uploads отклоняется', chatPathBad);
|
||||
|
||||
const badLevel = normalizeRestoreData({ ...base, notifications: [{ id: 1, type: 'x', level: 'drop-table', title: 'T' }] });
|
||||
ok('неизвестный level уведомления -> info', badLevel.notifications[0].level === 'info', badLevel.notifications[0]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user