15 Commits

Author SHA1 Message Date
lizerk
0217bc1a38 refactor: migrate comments to unified communications system
- Delete legacy Comment models (feed.Comment, documents.DocumentComment, requests_app.RequestComment)
- Create migration scripts to move data to communications.Message
- Add comments_helpers.py for unified comment operations
- Update API endpoints: /api/v1/posts/{id}/comments/, /api/v1/requests/{id}/comments/
- Fix notifications.0010_drop_old_tables migration with SeparateDatabaseAndState
- Implement real-time comments_count via GenericForeignKey annotations
- Update frontend API client to use new endpoints
- Update JavaScript files for new comment API routes
- Remove deprecated API endpoints and serializers
- Clean up signal handlers and admin registrations

Deployment tested: all migrations apply successfully on fresh database
2026-03-11 23:56:41 +03:00
lizerk
dd4f99c244 refactor(documents): удаление FSM workflow и упрощение моделей
- Удалены поля document_type, status, published_at из модели Document
- Упрощены разрешения и правила доступа
- Удалены endpoint'ы для работы со статусами
- Удалены тесты FSM workflow
- Обновлены serializers для новой структуры модели
2026-03-06 12:21:11 +03:00
41e4238a84 feat: add document related, comments, tags, versions components and notifications integration 2026-03-02 12:37:55 +03:00
58e341e295 feat: Add DocumentComment model and related documents support
- Added related_documents ManyToMany field to Document model
- Created DocumentComment model with threading support (parent/replies)
- Created DocumentCommentViewSet with CRUD and permission checks
- Added endpoints for related documents:
  * GET /documents/{id}/related/ - list related documents
  * POST /documents/{id}/add_related/ - add related document
  * POST /documents/{id}/remove_related/ - remove related document
- DocumentComment features:
  * Threading support via parent field
  * Edit tracking (is_edited flag)
  * Author-only deletion (or staff)
  * Depth calculation for nested comments
- Created migration 0010 for new fields and model
- Registered DocumentCommentViewSet in router

All medium-priority features complete!
2026-02-28 14:38:59 +03:00
7739e7520e feat: Add django-reversion API endpoints for document versions
- Added RevisionMiddleware to settings for automatic user tracking
- Created VersionSerializer and ActivityItemSerializer for version history
- Implemented GET /documents/{id}/versions/ endpoint
- Implemented GET /documents/{id}/activity/ endpoint (versions + audit + acknowledgements)
- Implemented POST /documents/{id}/revert/ endpoint for version rollback
- Activity timeline combines data from reversion, audit log, and acknowledgements
- All endpoints properly serialize user data with avatar support

This unblocks the Activity and Versions tabs in DocumentDetailModal.
2026-02-28 14:29:54 +03:00
11acea9ad0 feat: Extend DocumentUploadForm with full enterprise features
PROBLEM:
- Upload form was minimal, not using full backend capabilities
- Missing: recipients, departments, acknowledgement requirement
- No folder indication when uploading to specific folder

SOLUTION - BACKEND:
- Added 'acknowledgement_required' field to DocumentWriteSerializer
- Now accepts: sent_to_all, department_ids, recipient_ids, acknowledgement_required

SOLUTION - FRONTEND:
Extended DocumentUploadForm with enterprise-grade features:

NEW FIELDS:
1. Sent to All Toggle
   - Checkbox to send document to all employees
   - When checked, hides recipients/departments selection

2. Recipients Section (when sent_to_all = false)
   - Multi-select for departments (with Building2 icon)
   - Multi-select for specific employees (with Users icon)
   - Live loading from API
   - Validation: requires at least one department OR recipient
   - Helper text for Ctrl/Cmd multi-select

3. Acknowledgement Required
   - Checkbox to require recipients to acknowledge reading
   - Clear explanation of what it means

UX IMPROVEMENTS:
- Folder indicator: shows when uploading to specific folder
- Visual sections with dividers and headers
- Icons for each field type
- Warning when no recipients selected (amber alert)
- Better validation messages
- Reset all new fields on successful upload

API CLIENT:
- Updated createDocument signature to include acknowledgement_required
- Properly serializes checkbox values as strings

DATA LOADING:
- useEffect loads departments and employees on mount
- Loading states during fetch
- Handles empty lists gracefully

VALIDATION:
- Requires file and title (unchanged)
- NEW: When sent_to_all=false, requires departments OR recipients
- Shows user-friendly error messages

BENEFITS:
- Full feature parity with backend capabilities
- Professional document management workflow
- Granular control over document distribution
- Acknowledgement tracking from upload stage
- Better UX with progressive disclosure
2026-02-28 14:04:27 +03:00
6def6d2d43 feat: Improve folders UI with breadcrumbs and document counts
Backend improvements:
- Add document_count annotation to FolderViewSet queryset
- Add document_count field to FolderSerializer

Frontend improvements:
- Add folder_path display in document cards with folder icon
- Add document count badges in folder tree
- Add breadcrumbs navigation showing current folder path
- Improve folder selector button to show selected folder name
- Add clear filter button (X) to folder selector
- Add highlighted style for selected folder in selector
- Update Document interface to include folder and folder_path fields

UI enhancements:
- Folder path shown in sky-blue color with FolderOpen icon in cards
- Document count displayed in gray badge next to folder names
- Breadcrumbs allow quick navigation back to root
- Selected folder highlighted with sky-blue background
- Visual feedback for folder selection state
2026-02-28 13:15:06 +03:00
f4b5b75c01 feat: Implement folder-document integration and acknowledgements UI
Backend changes:
- Add acknowledgement_required field to Document model (migration 0009)
- Add FolderViewSet with CRUD endpoints for folder management
- Add folder_id filtering support in DocumentViewSet.get_queryset()
- Register folders endpoint in API router

Frontend changes:
- Add DocumentAcknowledgementsReport component for viewing acknowledgement status
- Add folder_id parameter to getDocuments API method
- Add currentFolderId prop to DocumentUploadForm
- Update document creation to save to selected folder
- Add folder filtering in documents list view
- Fix PDF worker loading (use local worker instead of CDN)
- Lock pdfjs-dist version to 5.4.296 to prevent conflicts
- Add postinstall script to copy PDF worker to public/

Features:
- Hierarchical folder structure with parent-child relationships
- Filter documents by selected folder
- Upload documents to specific folders
- View acknowledgement statistics with search and export
- Local PDF worker for reliable document preview
2026-02-28 13:06:41 +03:00
a315ce4f33 feat(documents): Integrate client-side processing into upload form
- Updated DocumentUploadForm to use processDocument utility
- Added real-time progress tracking with visual feedback
- Display extracted text in editable textarea
- Support compressed file upload
- Added extracted_text field to API client and backend serializer
- Auto-process PDFs, DOCX, and images on file selection
2026-02-28 09:36:17 +03:00
ab07a6ff9a feat(documents): Phase 1 - Backend Foundation Complete
- Добавлены расширенные модели для Mayan-level DMS:
  * DocumentType - типы документов с JSON schema
  * DocumentTag - теги для категоризации
  * Cabinet - виртуальные коллекции
  * DocumentMetadata - динамические key-value метаданные
  * DocumentAuditLog - полный аудит действий

- Расширена модель Document:
  * extracted_text - для полнотекстового поиска
  * document_type - FK к типу
  * modified_by, modified_at - audit trail

- Интегрирован django-watson для full-text search:
  * Регистрация с extracted_text
  * Кастомный adapter с URL
  * Обновлен индекс (22 документа)

- API Serializers:
  * DocumentTypeSerializer
  * DocumentTagSerializer
  * CabinetSerializer
  * FolderSerializer расширен
  * DocumentReadSerializer обновлен с новыми полями

Следующий этап: Phase 2 Frontend Foundation
2026-02-28 09:26:23 +03:00
abed82ed6c feat(documents): Добавлен django-fsm для workflow управления
Установлен и настроен django-fsm==3.0.1 для управления жизненным циклом документов.

Изменения в модели (documents/models.py):
- Добавлено FSM поле 'status' с 6 состояниями:
  * draft (черновик) - по умолчанию
  * in_review (на рассмотрении)
  * approved (одобрен)
  * published (опубликован)
  * archived (архивирован)
  * rejected (отклонен)

- Созданы transitions (переходы между состояниями):
  * submit_for_review(): draft → in_review
  * approve(): in_review → approved
  * reject(): in_review → rejected
  * publish(): approved → published (с отправкой уведомлений)
  * return_to_draft(): draft/in_review → draft
  * archive(): published → archived
  * unarchive(): archived → published

Изменения в админке (documents/admin.py):
- Добавлен status_badge() с цветовыми индикаторами статусов
- Добавлен available_transitions() - список доступных переходов
- Поле status добавлено в list_display и fieldsets
- Фильтрация по статусам в list_filter

Изменения в API (api/v1/documents/):
- Добавлены поля status и status_code в DocumentReadSerializer
- Созданы actions для всех FSM transitions:
  * POST /api/v1/documents/{id}/submit-for-review/
  * POST /api/v1/documents/{id}/approve/
  * POST /api/v1/documents/{id}/reject/
  * POST /api/v1/documents/{id}/publish/
  * POST /api/v1/documents/{id}/return-to-draft/
  * POST /api/v1/documents/{id}/archive/
  * POST /api/v1/documents/{id}/unarchive/

Миграция:
- Создана 0006_add_fsm_status.py
- Применена успешно
- Все 16 юнит-тестов проходят

Зависимости:
- Добавлен django-fsm==3.0.1 в requirements.txt
2026-02-28 01:33:23 +03:00
f138358862 feat(api): Адаптация API documents для django-filer
- Создан FilerFileField для сериализации filer.File объектов
- При чтении: возвращает URL файла через filer.url
- При записи: создает filer.File из UploadedFile с валидацией размера
- Обновлены serializers для работы с FilerFileField
- Обновлены тесты API: _filer_file() helper, mak_document() использует filer
- Удален устаревший mock documents.notification
- Удален validate_file() (валидация перенесена в FilerFileField)

WIP: Некоторые тесты не проходят, требуется отладка permissions
2026-02-28 01:26:23 +03:00
35f365a1b0 feat: Add department-based document distribution with department picker in UI
- Added departments ManyToMany field to Document model
- Implemented department selection in document create/edit modals
- Added automatic notification creation for all department employees
- Fixed document filtering to include uploaded documents in 'My Documents'
- Fixed acknowledgements API to include department recipients
- Added bulk notification support with configurable threshold
- Removed acknowledge button, added visual highlighting for unread documents
- Implemented server-side acknowledgment flow with redirect to file
- Fixed mobile responsive layout for document actions
- Removed temporary test files and documentation
2025-11-21 12:46:43 +03:00
25ae9a40b8 **feat(documents, calendar): привести API к спецификации и починить тесты**
### Основное

* Политика доступа для документов:

  * **CRUD** — только `is_staff` или обладатели модельных прав (`add/change/delete_document`).
  * **Чтение/скачивание/ACK** — любой **аутентифицированный**, но **только** свои документы (получатель активен) или если `sent_to_all=True`.
* Для календаря: `GET /api/v1/calendar/events/` (компания) доступен авторизованным пользователям.

### permissions / views

* Введён `DocumentReadOrModelPerms` на базе `DjangoModelPermissions`:

  * `GET/HEAD/OPTIONS` не требуют model-perms (только `IsAuthenticated`).
  * Объектно: staff/любой model-perm → доступ; иначе только `sent_to_all` или пользователь в `recipients(is_active=True)`.
  * Небезопасные методы требуют `add/change/delete_document` (или staff); **не требуем** дополнительно `view_document`.
* `DocumentViewSet.get_queryset()` фильтрует **list** для пользователей без `view_document`: только `sent_to_all` и документы, где текущий пользователь — активный получатель.
* Экшен `acknowledge` больше не переопределяет `permission_classes`; вызывается `self.get_object()` → срабатывает объектная проверка доступа.
* (dev) Раздача медиа: убедились, что подключён `urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)` — скачивание по `file_url` отдаёт `200`.

### serializers

* Добавлен `RecipientIDsField`: принимает `recipient_ids` в форматах **repeat-params / JSON-строка / CSV**, корректно читает `QueryDict.getlist()`.
* `DocumentWriteSerializer`:

  * `file` теперь **необязателен** на PUT/PATCH, обязателен на POST (проверяется в `validate()`).
  * Валидация `sent_to_all`/`recipient_ids` учитывает текущее состояние при апдейте; пустой список при `sent_to_all=False` запрещён.
  * `_set_recipients()` назначает **только активных** пользователей и очищает список при `sent_to_all=True`.
  * `validate_file()` — отказ по лимиту размера (`DATA_UPLOAD_MAX_MEMORY_SIZE`) с 400.
* `DocumentReadSerializer` — `file_url` через `FileField(source="file")`, `is_acknowledged` рассчитывается корректно.

### create response

* В `DocumentViewSet.create()` рассчитываем `recipient_count` из **нормализованных входных ID** (до `save()`), считая только активных; при `sent_to_all=True` возвращаем `0`.

### employees

* `EmployeeBriefSerializer` дополнен полем `full_name` (для тестов сериализации документов).

### Исправленные тесты/регрессии

* `TestCreate::test_create_sent_to_all_false_with_recipients_variants` — теперь `recipient_count` корректен для repeat/JSON/CSV.
* `TestUpdate::*` (PUT/PATCH) — больше не требуют `file`, возвращают `200`.
* `TestDelete::test_delete_and_cascade_acknowledgements` — `delete_document` достаточно, `403` устранён.
* `TestAcknowledge::test_ack_forbidden_if_not_recipient_and_not_sent_to_all` — теперь **403** для чужих документов с `sent_to_all=False`.
* `TestSerialization::test_file_url_downloadable_in_dev` — `200` при скачивании `file_url` в dev.
* `TestSecurityAndPolicy::test_policy_without_perms_list_is_200_detail_and_ack_require_access` — `list` даёт `200`, `detail/ack` чужого документа с `sent_to_all=False` дают `403`.
* `calendar_app`: `TestAuthAndPermissions.test_company_get_ok_regular_user` — `GET` по компании даёт `200`.

### Затронутые файлы (основные)

* `backend/api/v1/documents/permissions.py` (+ `DocumentReadOrModelPerms`)
* `backend/api/v1/documents/serializers.py` (+ `RecipientIDsField`, правки `DocumentWriteSerializer`, `DocumentReadSerializer`)
* `backend/api/v1/documents/views.py` (фильтрация `get_queryset()`, логика `create()`, `acknowledge`)
* `backend/api/v1/employees/serializers.py` (+ `full_name`)
* `eusrr_backend/urls.py` (проверка `static()` для MEDIA)
* *(календарь)* `backend/api/v1/calendar/views.py` (`get_permissions()` для company list)

---

**BREAKING**: ACK для документов с `sent_to_all=False` теперь доступен **только получателям** (или при наличии модельных прав/staff).
2025-09-12 17:04:47 +03:00
9529b3f268 **feat(feed, perms, tests): новая политика доступа для фида + полный набор автотестов**
Ключевые изменения

* Перевели доступ к объектам отдела (посты) на **ролевую модель внутри отдела**:

  * Используются `DepartmentRole.scoped_permissions` (M2M к `DepartmentPermission`).
  * Проверка прав идёт по **коду** из `DeptPerm` (`CREATE_POST`/`MANAGE_FEED`), а не по `auth.Permission`.
* **Company-посты** теперь контролируются **модельными правами** (`add_post`, `change_post`, `delete_post`) или статусом staff/superuser.
* Убраны остатки старой логики `publish_company_post` / `publish_department_post` (как глобальные права).

Пермишены / утилиты

* `user_has_dept_perm(user, dept, code)`:

  * true для staff/superuser и для руководителя отдела;
  * иначе проверка активной связи `EmployeeDepartment(is_active=True)` и наличия `role__scoped_permissions__code=...`.
  * ВАЖНО: используем поле **`code`**, не `codename`.
* `has_dept_perm(user, department_id, code)`:

  * те же правила, оптимизирован поиск (select\_related для роли).
* `AdminOrDeptAllowed`:

  * Корректно извлекает `department_id` из `kwargs`/`data`/`query_params` и из объекта (`obj.department_id/department.id`).
  * Если код не задан — SAFE-методы разрешены (чтение), небезопасные запрещены.
* `AdminOrActionOrModelPerms`:

  * staff/superuser — полный доступ;
  * поддержка явного `required_perm_code`/`required_perms_by_action`;
  * SAFE-методы требуют `view_<model>`, небезопасные — стандартная карта DjangoModelPermissions.
* `IsSelfOrStaff`/`IsSelfOrStaffOrModelPerms`:

  * Владелец объекта (по `author_id`/`author` и др.) или staff/superuser может изменять/удалять;
  * SAFE-методы — для авторизованных.

API: PostViewSet

* Обновлён `get_permissions()`:

  * `list/retrieve/create/like/unlike` → `IsAuthenticated`;
  * `update/partial_update/destroy` → `AdminOrDeptAllowed` с `required_code_map`:

    * `update/partial_update/destroy` → `DeptPerm.MANAGE_FEED`.
* Бизнес-проверки:

  * `perform_create`:

    * `type=department` → разрешено staff/superuser, head отдела, либо роль с `DeptPerm.CREATE_POST`;
    * `type=company` → нужны модельные права `add_post` (или staff).
    * `author` проставляется на `request.user`.
  * `perform_update/perform_destroy`:

    * dept-посты: staff/superuser, head, либо роль с `DeptPerm.MANAGE_FEED`;
    * company-посты: модельные права `change_post`/`delete_post` (или staff).
* Производительность:

  * Аннотация `is_liked` (через `Exists`).
  * Аннотация `last_comment_id` + батч-подтягивание последнего комментария в `list()`.
* Лайки:

  * `like/unlike` — идемпотентные; счётчик корректируется атомарно.

API: CommentViewSet

* `permission_classes = [IsAuthenticated, (IsSelfOrStaff | AdminOrActionOrModelPerms)]`.
* `perform_create` всегда ставит `author=request.user`.
* Фильтры `?post=`/`?author=` и сортировка `created_at ASC`.
* Обновлён `IsSelfOrStaff` для чтения настроек владельца с вью (например, `owner_id_attrs=("author_id",)`).

Тесты

* Добавлен/переписан комплект для новой модели доступа (фид):

  * **Аноним**: все эндпоинты → 401.
  * **Обычный пользователь**:

    * `GET posts/comments` → 200;
    * `POST comment`, `like/unlike` → 201/200;
    * `POST/PUT/PATCH/DELETE dept-post` → 403 (без роли/прав).
  * **Роль отдела**:

    * С `DeptPerm.CREATE_POST` — может создать пост **в своём отделе**; **в чужом** → 403.
    * С `DeptPerm.MANAGE_FEED` — может редактировать/удалять **в своём отделе**.
  * **Head отдела** — полный доступ к постам своего отдела.
  * **Staff/superuser** — полный доступ; `pin/unpin` только staff/superuser.
  * **Глобальные модельные права на company**:

    * `add_post`/`change_post`/`delete_post` → CRUD **только** для company-постов; dept-посты по-прежнему 403.
  * **Комментарии**:

    * Создание — любой аутентифицированный;
    * Изменение/удаление — автор или staff/superuser.
  * **Лайки**:

    * Идемпотентность `like/unlike`, корректная синхронизация `is_liked`.
  * **Валидация**:

    * `type=department` требует `department`;
    * роль в одном отделе не даёт создавать в другом → 403.
* Тестовые хелперы:

  * `_ensure_permission(model, codename, name)` — создаёт/возвращает `auth.Permission` для company-кейсов;
  * `_ensure_dept_permission(code)` и `_give_dept_role_with_perms(...)` — для департаментных прав (через `DepartmentPermission`/`DepartmentRole.scoped_permissions`).

Fixed / багфиксы

* `FieldError: Unsupported lookup 'codename'…` — заменён на фильтр по `scoped_permissions__code`.
* `IntegrityError: NOT NULL constraint failed: feed_post.author_id` — в `perform_create` постов/комментариев author задаётся принудительно.
* Несоответствие тестам по правам чтения/изменения комментариев — исправлено через корректный пермишен владельца.

Файлы (основные)

* `api/v1/permissions.py`: `AdminOrDeptAllowed`, `AdminOrActionOrModelPerms`, `IsSelfOrStaff`(+вариант `IsSelfOrStaffOrModelPerms`), `user_has_dept_perm`, `has_dept_perm`.
* `api/v1/feed/views.py`: `PostViewSet`, `CommentViewSet` (правки прав, `perform_*`, аннотации, like/unlike).
* `tests/api/v1/feed/test_posts.py`, `tests/api/v1/feed/test_comments.py` (и/или `test_feed_api.py`): полный набор сценариев под новую политику.
* Хелперы тестов: функции создания отделов, прав и ролей, генераторы payload.

Итог

* Политика доступа фида приведена к спецификации: **dept-права — через роли внутри отдела**, **company — через модельные права**.
* Исправлены ошибки в проверках прав и авторстве, покрыто автотестами (CRUD, лайки, комменты, валидация, пермишены).
* Производительность чтения ленты улучшена (аннотации `is_liked`, `last_comment_id` без N+1).
2025-09-11 17:56:33 +03:00