112 lines
10 KiB
Markdown
112 lines
10 KiB
Markdown
# 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 эти правки могут потребовать переноса или проверки совместимости.*
|