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