Commit Graph
7 Commits
Author SHA1 Message Date
dev a3169648f3 style(chat): цитата ответа как в телеграме — квадрат слева, текст справа
Миниатюра вложения в цитате больше не растягивается на всю ширину:
фиксированный квадрат 44x44 слева, автор и текст в колонке справа.
Обёртка .msg-reply-body даёт им flex:1, поэтому длинный текст
обрезается многоточием по месту, а не растягивает цитату.
2026-10-06 00:35:25 +03:00
dev 3ac54f57b4 feat(chat): ответы на сообщения с цитатой и переходом к оригиналу
Кнопка «Ответить» у каждого сообщения: цитата показывается в новом
сообщении и в поле ввода, отмена — ✕ или Escape, переключение треда
сбрасывает ответ. Клик по цитате прокручивает ленту к исходному
сообщению и подсвечивает его.

Цитата повторяет вложение оригинала: имя файла с иконкой, для
картинок — миниатюра WebP через существующий /api/chat/files/:token.

- chat_messages.reply_to_id: FK на саму таблицу с ON DELETE SET NULL,
  миграция и ensureChatTables, индекс
- POST .../messages принимает reply_to_id и проверяет, что родитель
  в этом же треде и не удалён; вложения при ошибке подчищаются
- цитата едет в списке, при отправке и в SSE правки/удаления, так что
  у собеседника она обновляется по живому каналу
- бэкап: reply_to_id в normalizeRestoreData, при restore ссылка
  принимается только если родитель восстановился, иначе NULL
- shorts: скрывать поле «Резидент» при добавлении без разбора строк
2026-10-06 00:33:17 +03:00
dev 62239a35a4 fix(chat): валидная разметка карточки диалога и доступ с клавиатуры
Карточка треда была вложенными <button>, поэтому кнопки действий внутри
неё ломали HTML-структуру. Заменена на <div role="button" tabindex="0">
с обработкой Enter/Space; классы действий переименованы в
chat-thread-act / chat-thread-act-danger, чтобы не путаться с .chat-act.

Также ужата шапка списка диалогов: заголовок не сжимается, кнопки
не переносятся, подпись у кнопки скрытых заменена на бейдж.
2026-10-05 20:02:03 +03:00
dev 7d282d4f3d feat(chat): скрытие и плановое удаление диалогов
Админ может скрыть диалог тьютора (мягкое удаление), снять скрытие,
отменить плановое удаление или удалить диалог физически через TTL
общей настройки корзины.

- chat_threads: deleted_at, purge_at (init.sql, migration.sql, ensureChatTables)
- маршруты hide / restore / unschedule / permanent под requireAdmin + аудит
- purgeScheduledDeletions() + hardDeleteChatThread() с safeUnlink по вложениям
- скрытые диалоги видны тьютору как обычно; новое сообщение тьютора
  авто-возвращает диалог в список (thread_update по SSE)
- UI: кнопка «Скрытые» с бейджем и действия в карточке треда
- бэкап: deleted_at/purge_at в normalizeRestoreData
2026-10-05 19:32:56 +03:00
dev 1740c341a0 feat(chat): правка и удаление сообщений
- PUT/DELETE /api/chat/threads/:id/messages/:messageId под requireAuth+chatLimiter,
  доступ через chatMessageFor (тред + принадлежность сообщения)
- править может только автор (админу чужое сообщение 403), удалять — автор или админ
- мягкое удаление: body='', вложения каскадом из БД + safeUnlink по path,
  счётчик непрочитанных уменьшается на 1 у своей стороны (GREATEST(col-1,0))
- refreshChatThreadPreview() пересчитывает превью треда по последнему живому сообщению
- SSE: publishChat с type, список типов валидируется через CHAT_EVENTS; новые
  message_update/message_delete подписаны в connectChatStream (admin.js)
- аудит chat.message.update с textDiff и chat.message.delete без текста
- колонки edited_at/deleted_at в db/init.sql, db/migration.sql, ensureChatTables()
  и в normalizeRestoreData + restore-INSERT — удалённые сообщения не воскресают
- фронтенд: кнопки правки/удаления по наведению, модалка правки (Ctrl+Enter),
  метка «изменено», плейсхолдер «Сообщение удалено», обновление по SSE
- покрытие в api.smoketest.js (правка/удаление/403/400/404) и backup.selftest.js
2026-10-05 18:32:58 +03:00
dev 7e4b1a1324 fix(chat): просмотр фото вложений в модалке, доступ тьюторов к уведомлениям
- изображения во вложениях чата открываются в общей модалке #imgModal
  (data-img + общий обработчик в admin.js) вместо новой вкладки
- Escape и клик по фону закрывают модалку изображения
- .chat-side[hidden] скрывается — раньше правило display:none его не покрывало
- страница уведомлений открывается любому авторизованному пользователю
  (checkAuth вместо requireAdminPage), пункт меню виден всем
2026-10-05 17:51:37 +03:00
dev 235fd43af4 feat(chat): личный чат тьютор ↔ админ с вложениями
Диалоги 1:1 (один тред на тьютора), отдельный SSE-канал whatido:chat
вместо общей ленты notifications, вложения с белым списком расширений
и вставкой из буфера (Ctrl+V), очистка по chat_retention_days.
Таблицы в бэкап, chat_attachments добавлен в sweepOrphanedUploads.
2026-10-05 17:30:26 +03:00