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

142 lines
15 KiB
Markdown
Raw 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.

# План: шаринг папок почты (доступ к папкам других пользователей)
Документ описывает планируемый функционал и возможность реализации **без внесения изменений в код**. После согласования можно переходить к реализации по этапам.
---
## 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.