# 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`. Этапы 6–7 учтены в текущей реализации; при необходимости доработки по праву «только просмотр» или граничным случаям — отдельные записи. ### Этап 4–5 — навигация: группировка по владельцу и локализация - **`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 эти правки могут потребовать переноса или проверки совместимости.*