f7cloud_client/apps/mail/CHANGELOG-F7CLOUD.md
root 8b6a0139db f7cloud_client
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-17 22:59:26 +00:00

112 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Changelog — доработки F7cloud
Журнал кастомных изменений, внесённых в приложения и ядро F7cloud (на базе F7cloud).
---
## Приложение Mail
### Поиск на русском языке и регистронезависимость
- **`lib/Service/Search/FilterStringParser.php`**
- Для поисковых терминов (в т.ч. с префиксами `from:`, `to:`, `subject:`, `body:`) добавлена передача в запрос варианта с первой заглавной буквой (title-case), чтобы поиск по кириллице работал с `LIKE` в PostgreSQL при локали `C`.
- Добавлены проверки `is_string` и на непустоту для результатов `mb_convert_case` для устойчивости.
- **`lib/Db/MessageMapper.php`**
- Для полей `label`, `email` и `m.subject` заменён `iLike` на `LIKE` с `COALESCE`, чтобы поиск корректно работал при разных локалях БД.
- **`lib/private/DB/SQLiteSessionInit.php`** (ядро)
- Зарегистрирована пользовательская функция `LOWER` для SQLite на базе `mb_strtolower` для корректной работы поиска в SQLite.
### Расширенный поиск — автозаполнение и очистка
- **`src/components/SearchMessages.vue`**
- Удалена логика, которая подставляла значение обычного поиска (`query`) в поля расширенного поиска (Тема, От, Кому, Тело письма).
- Добавлена `watch` на открытие модального окна расширенного поиска: при активном только простом запросе поля расширенного поиска сбрасываются.
- Изменено вычисляемое свойство `searchQuery`: при пустом `query` и отсутствии расширенных фильтров возвращается пустая строка вместо `"match:anyof"`, чтобы избежать ошибки 500 при очистке фильтра.
### Ошибка 500 и «не удалось открыть папку» при поиске
- **`lib/Service/Search/MailSearch.php`**
- Вызов IMAP-поиска (`imapSearchProvider->findMatches`) обёрнут в `try-catch`; при ошибке (в т.ч. из‑за кириллицы на стороне IMAP) используется только поиск по БД (fallback).
### Отображение групп при выборе получателей
- **`lib/Service/GroupsIntegration.php`**
- Для групп из сервиса с namespace `F7cloud` подпись больше не дополняется суффиксом в скобках: показывается только имя группы (например, «all» вместо «all (F7cloud)»).
- Для остальных источников групп (например, контакты) по‑прежнему выводится имя и в скобках источник.
---
## Ядро (lib)
### Отображаемые имена групп
- **`lib/private/Group/Database.php`**
- Добавлен метод `stripInstanceSuffixFromDisplayName()`: убирает суффикс ` (F7cloud)` в конце отображаемого имени группы.
- В `getDisplayName()` и при формировании результата в `getGroupsDetails()` возвращаемое имя группы очищается от этого суффикса (для единообразия в шаринге и других местах).
---
## Приложение Contacts
### Локализация (брендинг F7cloud)
- **`l10n/ru.json`**, **`l10n/ru.js`**
- В русских переводах заменено «F7cloud» на «F7cloud» (название приложения, описания, пункт «Выбрать в F7cloud» и т.п.).
---
## Прочее
### Владелец изменённых файлов
- **`.cursor/rules/file-ownership.mdc`** (в проекте)
- Правило Cursor: для изменённых файлов в `/var/www/f7cloud/` выполнять `chown www-data:www-data`.
---
---
## Шаринг папок почты (завершено)
Реализация по плану `docs/PLAN-FOLDER-SHARING.md` доведена до рабочего состояния; этап 7 (тесты и доработки) считается завершённым — функционал работает и отображается как задумано.
### Этап 1 — модель данных и подпапки с первого дня
- **План:** `docs/PLAN-FOLDER-SHARING.md` — шаринг папок с пользователями/группами, два уровня прав (только просмотр / полный доступ), блок «Папки других пользователей»; **подпапки отображаются и доступны с самого начала**.
- **Миграция** `lib/Migration/Version5007Date20260204120000.php`: создаётся таблица `mail_mailbox_shares` (owner_user_id, account_id, mailbox_id, share_type, share_with, permission, created_at).
- **Сущность** `lib/Db/MailboxShare.php`: константы TYPE_USER, TYPE_GROUP, PERMISSION_READ, PERMISSION_READ_WRITE.
- **Маппер** `lib/Db/MailboxShareMapper.php`: find, findByMailbox, findSharedWith(userOrGroupIds), shareExists, deleteById, deleteByMailbox, findByOwner.
### Этап 2 — сервис и API
- **Сервис** `lib/Service/MailboxShareService.php`: createShare, deleteShare, getSharesForMailbox, getSharedWithMe (владелец, папка, подпапки по префиксу имени), getShareForUser, getShareForMailboxAccess (доступ по шару для текущего пользователя). Используется MailboxMapper для проверки доступа к папке/подпапке.
- **Контроллер** `lib/Controller/MailboxShareController.php`: POST `/api/mailboxes/{id}/share` (shareWith, shareType, permission), DELETE `/api/mailbox-shares/{shareId}`, GET `/api/mailboxes/{id}/shares`, GET `/api/mailbox-shares` (shared with me). Проверка владельца папки/шара, JsonResponse + TrapError.
- **Маршруты** в `appinfo/routes.php`: добавлены четыре маршрута для mailboxShare#create, destroy, index, sharedWithMe.
### Этап 3 — доступ к папкам и письмам по шару
- **Сервис** `lib/Service/MailboxShareService.php`: добавлены `resolveMailboxForAccess(currentUserId, mailboxId, ?shareId)` и `resolveMessageAccess(currentUserId, messageId, ?shareId)` — возвращают mailbox/account (и при shared — share) или null при отсутствии доступа.
- **MessagesController**: во все методы, работающие с папкой или сообщением, добавлен опциональный параметр `?int $shareId = null`. При переданном `shareId` доступ разрешается через резолвер (от имени владельца шаринга). Затронуты: index, show, getFilterHeaders, getBody, getItineraries, getDkim, getThread, move, snooze, unSnooze, mdn, getSource, export, getHtmlBody, downloadAttachment, downloadAttachments, saveAttachment, setFlags, setTag, removeTag, destroy, smartReply, needsTranslation.
- **MailboxesController**: для sync, clearCache, markAllAsRead, stats добавлен `?int $shareId = null` и использование `resolveMailboxForAccess`.
- **ThreadController**: для move, snooze, unSnooze, summarize, generateEventData, delete добавлен `?int $shareId = null` и использование `resolveMessageAccess` / `resolveMailboxForAccess`.
Этапы 67 учтены в текущей реализации; при необходимости доработки по праву «только просмотр» или граничным случаям — отдельные записи.
### Этап 45 — навигация: группировка по владельцу и локализация
- **`src/components/Navigation.vue`**
- Блок расшаренных папок переименован по смыслу: заголовок использует ключ **«Network mail folders»** (см. локализацию ниже), отображается как группа, а не плоский список.
- **Группировка по владельцу:** расшаренные папки сведены в группы по `ownerUserId`. Каждый владелец — одна раскрывающаяся строка (имя + шеврон ▼/▶), внутри — его расшаренные папки (основная + подпапки). Состояние раскрытия хранится в `sharedGroupOpen` (по умолчанию группы открыты).
- Добавлены computed `sharedWithMeGrouped`, методы `toggleSharedGroup` и `isSharedGroupOpen`, импорты иконок `ChevronDown`/`ChevronRight`.
- Заголовок секции уменьшен: класс `mail-navigation__shared-heading--small` (шрифт 0.85rem, font-weight 500). Стили для кнопки-заголовка группы (`.mail-navigation__shared-caption`, `.mail-navigation__shared-chevron`, `.mail-navigation__shared-caption-text`).
- **Локализация**
- **`l10n/ru.json`**: добавлена строка `"Network mail folders" : "Сетевые почтовые папки"`.
- **`l10n/ru.js`**: добавлена строка `"Network mail folders": "Сетевые почтовые папки"` (для корректного отображения перевода на фронтенде).
---
*Документ составлен по результатам доработок под F7cloud. При обновлении приложений или ядра из upstream эти правки могут потребовать переноса или проверки совместимости.*