# План: шаринг папок почты (доступ к папкам других пользователей) Документ описывает планируемый функционал и возможность реализации **без внесения изменений в код**. После согласования можно переходить к реализации по этапам. --- ## 1. Требуемый функционал (кратко) 1. **Меню папки (три точки)** В выпадающем меню, которое открывается по нажатию на три точки справа от папки, — пункт **«Поделиться»** с возможностью выбрать пользователей и/или группы и выдать доступ к папке. 2. **Два уровня прав** - **Только просмотр** — чтение писем в папке, без изменений. - **Полный доступ** — чтение, добавление/изменение/удаление писем, создание подпапок и управление ими. 3. **Блок «Папки других пользователей»** В боковой панели (список ящиков/папок) — отдельная секция **«Папки других пользователей»**, где отображаются: - аккаунт (пользователь), который предоставил доступ; - список расшаренных папок с подпапками. --- ## 2. Оценка возможности реализации **Вывод: реализуемо.** Приложение уже опирается на понятия «аккаунт» и «папка (mailbox)», есть пример шаринга (TextBlockShare), контекстное меню папок и навигация по папкам. Нужно добавить слой «шаринга папок» и продумать, как при открытии папки и работе с письмами учитывать «режим shared» и права. Ниже — что уже есть и что нужно добавить. --- ## 3. Текущая архитектура (релевантные части) - **Папки (mailbox):** сущность `Mailbox` привязана к `account_id`. Список папок загружается по аккаунту (`MailboxesController::index(accountId)`), маршрут вида `/box/{mailboxId}`. - **Письма:** доступ через `MessagesController` по `mailboxId`; везде проверяется принадлежность папки текущему пользователю через `getMailbox(currentUserId, mailboxId)`. - **Навигация:** `Navigation.vue` строит список из аккаунтов и их папок; каждая папка — `NavigationMailbox.vue` с контекстным меню (слот `#actions`). - **Шаринг в приложении:** уже есть модель «объект + с кем поделились» — `TextBlockShare` (тип, shareWith, id объекта). Аналогичная таблица для папок — естественный следующий шаг. Ограничение: папки и письма жёстко привязаны к владельцу аккаунта. Чтобы «открыть чужую папку», бэкенд должен: - знать, что эта папка расшарена текущему пользователю (или группе, в которой он состоит); - при запросах писем/действий использовать аккаунт **владельца** папки, но проверять права **текущего** пользователя по таблице шаринга. --- ## 4. Предлагаемая архитектура ### 4.1. Модель данных (бэкенд) - **Новая таблица** (например, `oc_mail_mailbox_shares`): - `id` - `owner_user_id` — владелец папки (кто шарит) - `account_id` — id почтового аккаунта владельца - `mailbox_id` — id папки в БД (у владельца) - `share_type` — `user` | `group` - `share_with` — uid пользователя или gid группы - `permission` — `read` | `read_write` - `created_at` (опционально) - **Подпапки:** При шаринге папки доступ предоставляется и на **все подпапки** с тем же уровнем прав (логика «папка + дерево вниз»). В блоке «Папки других пользователей» отображаются расшаренная папка и её подпапки; подпапки доступны по тому же shareId (для корневой расшаренной папки) или по правилу «дочерняя папка владельца, чья родительская папка расшарена» — при открытии подпапки бэкенд проверяет, что её родитель (или сама папка) фигурирует в шаринге для текущего пользователя. ### 4.2. Бэкенд: новые/изменённые API | Назначение | Метод/маршрут | Описание | |------------|----------------|----------| | Создать шаринг | `POST /api/mailboxes/{id}/share` | Тело: `shareWith`, `shareType` (user/group), `permission` (read/read_write). Проверка: папка принадлежит текущему пользователю. | | Удалить шаринг | `DELETE /api/mailbox-shares/{shareId}` | Только владелец. | | Список «кому расшарено» | `GET /api/mailboxes/{id}/shares` | Для владельца папки — кто имеет доступ. | | Список «расшарено мне» | `GET /api/mailbox-shares` (или `shared-with-me`) | Для текущего пользователя: список шарингов (владелец, папка, подпапки, право). Используется для блока «Папки других пользователей». | - **Чтение писем в расшаренной папке:** Варианты: - Ввести «виртуальный» идентификатор расшаренной папки для текущего пользователя (например, `shareId`). Маршрут вида `/box/shared/{shareId}`. - Или передавать в существующий API писем пару `mailboxId` + `sharedByUserId` (или `shareId`). В обоих случаях бэкенд: по `shareId` (или паре) находит запись в `oc_mail_mailbox_shares`, проверяет, что shareWith — текущий пользователь (или он в группе), и что permission не ниже read; затем загружает письма через владельца: `getMailbox(owner_user_id, mailbox_id)` и существующую логику выборки писем. - **Действия с письмами (перемещение, удаление, флаги и т.д.):** Те же контроллеры, но при вызове с контекстом «расшаренная папка» дополнительно проверять `permission === read_write`. При `read` — возвращать 403 на изменение. - **Создание подпапок в расшаренной папке:** Разрешать только при `read_write`. Создание подпапки на IMAP/бэкенде выполнять от имени владельца аккаунта (как сейчас делается для «своих» папок), но инициировать действие может только пользователь с правом «полный доступ». ### 4.3. Фронтенд - **Меню папки (`NavigationMailbox.vue`, выпадающее по нажатию на три точки справа от папки):** - Добавить пункт **«Поделиться»** (иконка «Share»). - Условие показа: только для «своих» папок (не для элементов из блока «Папки других пользователей»), при необходимости — исключить системные папки (Входящие/Корзина и т.д.) по тем же правилам, что и для «Переместить папку». - **Модальное окно «Поделиться папкой»:** - Выбор получателя: пользователь и/или группа (автодополнение как в «Поделиться» в Файлах или как при выборе получателей в письме). - Выбор права: «Только просмотр» / «Полный доступ». - Список уже имеющих доступ (при открытии из «Управление доступом» или повторном открытии «Поделиться») и возможность забрать доступ. - **Блок «Папки других пользователей» в `Navigation.vue`:** - Отдельная секция под списком своих аккаунтов. - Заголовок: «Папки других пользователей». - Данные: результат `GET /api/mailbox-shares` (или аналог). - Группировка по владельцу: под каждым владельцем — список папок (и при варианте B — подпапок). - Каждая папка ведёт на маршрут вида `/box/shared/{shareId}` (или эквивалент с `sharedBy` + `mailboxId`). - **Роут и представление «расшаренная папка»:** - Новый маршрут, например `/box/shared/:shareId`. - В `Home.vue` / хранилище: при таком маршруте не искать папку в своих аккаунтах, а подставлять «виртуальную» папку из ответа API shared-with-me (название, владелец, право). - Загрузка писем и превью — через существующие API, но с параметром `shareId` (или аналог), чтобы бэкенд работал в режиме «расшаренная папка». - **Ограничение UI по праву «только просмотр»:** - Скрыть или отключить: перемещение писем, удаление, создание подпапок, «Очистить папку» и т.п. - Кнопки «Ответить»/«Переслать» — по желанию оставить (это не изменение папки владельца). --- ## 5. Открытые вопросы и риски 1. **Группы:** при `share_type = group` проверка доступа: текущий пользователь входит в группу (через `IGroupManager`). Удаление/изменение шаринга — только владелец папки. 2. **Кэш и синхронизация:** письма в расшаренной папке читаются из кэша/IMAP владельца. Нужно понимать, что синхронизация папки выполняется для аккаунта владельца; при первом открытии расшаренной папки кэш владельца может быть пустым — тогда нужна явная синхронизация (как для своих папок) или отложенная подгрузка. 3. **Производительность:** при большом числе шарингов запрос «расшарено мне» может быть тяжёлым; имеет смысл отдавать только метаданные (владелец, папка, право), без полного дерева подпапок в первом запросе. 4. **Подпапки при шаринге:** реализуются с самого начала: при шаринге папки доступ даётся на неё и на все подпапки; в API «расшарено мне» возвращается дерево (папка + подпапки); при открытии подпапки проверяется, что она является потомком расшаренной папки владельца. --- ## 6. Этапы реализации (предварительно) | Этап | Содержание | |------|------------| | 1 | Таблица и сущность `MailboxShare`, маппер, миграция. | | 2 | Сервис/контроллер шаринга: создание/удаление/список по папке, список «расшарено мне». | | 3 | Изменение логики доступа к папке/письмам: при наличии `shareId` (или контекста shared) разрешать доступ с проверкой прав и от имени владельца. | | 4 | Фронтенд: пункт «Поделиться» в контекстном меню, модальное окно выбора пользователей/групп и прав. | | 5 | Фронтенд: секция «Папки других пользователей», маршрут `/box/shared/:shareId`, подстановка данных в навигации и в представлении папки. | | 6 | Ограничение действий в UI и в API по праву «только просмотр». | | 7 | Тесты и доработки (подпапки, группы, граничные случаи). | --- ## 7. Итог - Функционал **реализуем** в рамках текущей архитектуры Mail. - Основная работа: новый слой шаринга (БД + API + проверки прав) и доработка навигации/контекстного меню/маршрутизации на фронтенде. - Риски управляемые; открытые моменты (подпапки, кэш, производительность) можно зафиксировать в конфиге или упростить в первой версии. После согласования плана можно приступать к реализации по этапам без активных изменений в текущем коде до начала этапа 1.