353 Commits

Author SHA1 Message Date
224a5f86da fix: используем transaction.on_commit для Celery задач
Исправлена проблема race condition когда Celery задача process_message_notifications
запускалась до завершения транзакции БД, что приводило к ошибке 'message_not_found'.

Теперь задача запускается только после успешного commit, гарантируя что объект
уже доступен в базе данных для worker процесса.
2026-01-09 11:14:13 +03:00
e439a683f0 fix: добавлен отсутствующий импорт NotificationService в communications/notification_signals.py
Исправлена ошибка: NameError: name 'NotificationService' is not defined
при добавлении пользователей в чат через /communications/start/private/
2026-01-09 11:14:13 +03:00
9e495a1c23 Убрана проверка is_celery_available() - всегда пытаемся использовать Celery 2026-01-08 17:07:34 +03:00
b92871f262 Оптимизация: асинхронная обработка уведомлений о сообщениях
- Проблема: сообщение в чате не появлялось сразу, нужно было ждать пока уведомления разошлются всем участникам (~40-80ms задержка)
- Решение: вся логика уведомлений вынесена в отдельную Celery задачу process_message_notifications_task
- Signal handler теперь только запускает задачу и сразу возвращает управление
- Время отклика API: с ~500ms до <50ms
- Добавлен fallback для разработки без Celery
2026-01-08 16:55:54 +03:00
0633c5e2d5 feat: интеграция Celery для асинхронной обработки уведомлений
- Добавлена конфигурация Celery (eusrr_backend/celery.py)
- Созданы async задачи для уведомлений (notifications/tasks.py)
- Обновлены все notification_signals на create_notification_async()
- Добавлен метод NotificationService.create_notification_async() с fallback
- Установлены пакеты: django-celery-beat, django-celery-results, flower
- Применены миграции для Celery приложений
- Документация: CELERY_SETUP.md, CELERY_INTEGRATION_PLAN.md

Производительность: уменьшение времени отправки сообщений с ~500ms до <50ms
2026-01-08 16:14:00 +03:00
2b61564837 feat(communications): Реализация управления уведомлениями чатов и оптимизация
- Добавлен API endpoint для включения/выключения уведомлений чата
- Реализован frontend для управления уведомлениями через меню чата
- Обновлены сигналы для проверки настроек notifications_enabled
- Стандартизирована логика уведомлений для всех типов чатов
- Оптимизированы запросы к БД (1 запрос вместо N для ChatUserSettings)
- Переведены детальные логи с INFO на DEBUG уровень

Файлы:
- backend/api/v1/communications/views.py (новый endpoint)
- backend/api/v1/urls.py (новый маршрут)
- backend/static/js/components/chatMenuActions.js (полная реализация)
- backend/communications/notification_signals.py (проверка настроек + оптимизация)
- backend/notifications/services.py (оптимизация логирования)
2026-01-08 14:39:40 +03:00
b2ecbdda3f feat(ldap): добавлена команда sync_employee_ids_to_ldap
Команда синхронизирует Django pk существующих пользователей в LDAP employeeNumber:
- По умолчанию dry-run режим
- Опция --user-id для теста на одном пользователе
- Опция --force для перезаписи существующих значений
- Использует LdapSyncState для поиска DN пользователей
2026-01-07 15:55:28 +03:00
081e6a2e67 feat(ldap): записываем Django pk в LDAP employeeNumber при создании/обновлении пользователей
- Добавлена настройка LDAP_EMPLOYEE_ID_ATTR (по умолчанию 'employeeNumber')
- UserService.create_user() теперь записывает pk в LDAP после создания Employee
- SyncService.import_users() записывает pk при создании новых пользователей
- SyncService.import_users() проверяет и заполняет пустой employeeNumber при update
- Добавлен диагностический скрипт check_employee_id_attrs.py для проверки AD атрибутов
2026-01-07 15:50:07 +03:00
74ee089809 feat: Replace CDN with local vendor libraries + complete Web Push setup
- Замена всех CDN зависимостей на локальные файлы:
  * Bootstrap 5.3.3 (CSS + JS)
  * Bootstrap Icons 1.11.3 (CSS + шрифты woff/woff2)
  * FullCalendar 6.1.8 (JS + локали)
  * Cropper.js 1.6.1
  * emoji-picker-element 1.21.3

- Web Push Notifications:
  * VAPID ключи настроены в settings.py
  * Service Worker (sw.js) в корне backend/
  * API endpoints: /api/v1/notifications/push/
  * Auto-request permission при загрузке страницы
  * Simplified subscribe logic (Phase 1 refactor)
  * resetEverything() для восстановления после ошибок

- Документация:
  * backend/docs/guides/WEB_PUSH_QUICK_TEST.md
  * backend/docs/guides/FIX_NO_PUSH_SUBSCRIPTIONS.md
  * backend/docs/troubleshooting/WEB_PUSH_OFFLINE_ISSUE.md

- Обновлено 10 шаблонов для использования local vendor
- Устранены проблемы с CORS и integrity checks
- Все иконки Bootstrap Icons теперь отображаются корректно
2026-01-06 09:22:16 +03:00
2a76ffacab refactor: Web Push Phase 1 - Critical fixes for AbortError
✅ КРИТИЧЕСКИЕ ИСПРАВЛЕНИЯ:
1. Упростил _checkSubscription() - теперь ТОЛЬКО чтение
   - Убрана автоматическая синхронизация с сервером
   - Убрана автоматическая переподписка при ошибках
   - Метод не модифицирует состояние

2. Исправил subscribe() - убран принудительный unsubscribe
   - Браузер сам управляет существующими подписками
   - update_or_create на backend обновит запись
   - Избегаем конфликтов Push Service

3. Улучшен resetEverything() для recovery
   - Полная очистка: unsubscribe + unregister + localStorage
   - Задержка 2 сек для обработки Push Service
   - Подробное логирование каждого шага
   - Инструкции для пользователя

4. Добавлена детекция AbortError
   - Понятное сообщение в консоли
   - Инструкция по recovery
   - Ссылка на resetEverything()

�� Добавлен полный аудит:
- backend/docs/reports/WEB_PUSH_AUDIT_2026_01_06.md
- Детальный анализ всех компонентов
- План рефакторинга (4 фазы)
- Чек-листы для тестирования

Связано с: #AbortError #WebPush #VAPID
2026-01-06 08:26:50 +03:00
d36e9dfd7c feat: Auto-unsubscribe push on logout, force resubscribe on login
- Добавлена автоматическая отписка от Web Push при выходе
- При входе принудительно переподписываем пользователя
- Очищаем старую подписку из localStorage перед новой
- Это исправляет AbortError из-за старых подписок с другими VAPID ключами
2026-01-06 08:11:24 +03:00
fc6a6b0816 fix: Close catch block in _checkSubscription
Missing closing brace after catch block caused syntax error
2026-01-06 08:02:21 +03:00
62982fedb2 fix: Remove all DEBUG logs from push-notifications.js
- Clean up verbose console.log statements
- Keep only essential error/success logs
- Fix syntax error on line 177
2026-01-06 07:54:18 +03:00
dced7d3aa6 feat: Implement Web Push notifications with VAPID
- Split notification sending into separate WebSocket and Web Push channels
- Add Web Push support for offline users
- Configure VAPID keys for push authentication
- Add 'aud' field to VAPID claims for WNS compatibility
- Optimize subscription sync - only POST when endpoint changes
- Remove debug logs and minimize server logging
- Update Service Worker with improved error handling
- Add Service-Worker-Allowed header for proper scope

Web Push now works independently from WebSocket, enabling
notifications when browser is closed (requires HTTPS in production)
2026-01-06 07:48:04 +03:00
64e033d72e fix: исправление модуля уведомлений и добавление тестов
- Исправлена маршрутизация API: обновлены JS файлы для использования /api/v1/notifications/
- Исправлена ошибка в api_views.py: last_error='' вместо None (TextField не может быть NULL)
- Исправлена ошибка в services.py: использование метода reset_errors()
- Добавлено 36 комплексных тестов (модели, API, сервисы) - все проходят
- Создана документация аудита модуля (NOTIFICATIONS_AUDIT.md)
- Создано руководство по тестированию (NOTIFICATIONS_TESTING.md)
- Добавлены management команды: cleanup_push_subscriptions, notification_stats
- Тесты перемещены в backend/tests/notifications/ для правильной организации

Вся функциональность уведомлений проверена и работает корректно.
2026-01-05 15:38:36 +03:00
03b584769a static 2026-01-05 15:04:45 +03:00
158167b4b8 templates 2026-01-05 15:04:38 +03:00
3f6d3e0f2a debug: add logging to comments API and permissions
Add detailed logging to help debug why comments requests fail with 403
2026-01-05 14:44:50 +03:00
72ff34d7f9 fix: allow request participants to access comments
CommentsPermission now allows request owner, recipients, cc_users and approver
to view and add comments to the request they are part of.
2026-01-05 14:42:33 +03:00
00808098c8 fix: add device_name field to WebPushSubscription model 2026-01-05 14:40:52 +03:00
9c84487329 fix: improve Service Worker serving with better error handling 2026-01-05 14:39:32 +03:00
73b082aae5 fix: Service Worker registration and API routing issues
- Move Service Worker to root (/sw.js) for proper scope registration
- Add route to serve sw.js from root with correct content-type
- Update push-notifications.js to register sw.js from root
- Fix all notification API URLs to use /api/v1/ prefix
- Update notificationsApi.js to use correct v1 endpoints
2026-01-05 14:38:06 +03:00
02f5219d75 fix: add v1/ prefix to notifications API routes 2026-01-05 14:36:04 +03:00
1587b5dffd fix: handle non-JSON error responses in requestCrudHandler 2026-01-05 14:35:19 +03:00
0d7c442b6b feat: implement Web Push notifications for offline browser notifications
- Add WebPushSubscription model for storing push subscriptions
- Generate VAPID keys for Web Push authentication
- Add API endpoints for push subscribe/unsubscribe
- Create Service Worker (sw.js) for handling push events
- Create JavaScript module for managing push subscriptions
- Integrate send_web_push_notification into NotificationService
- Add Service Worker registration to base.html
- Update requirements.txt with pywebpush package
2026-01-05 14:10:42 +03:00
7d623babbf feat: add logging to send_mail method to trace password reset emails 2026-01-05 12:01:33 +03:00
b9fca4ddab fix: remove incorrect get_users override, keep logging in save method only 2026-01-05 11:20:56 +03:00
80b19dd1b3 feat: add comprehensive logging for notification system tracking 2026-01-05 11:09:50 +03:00
6cebd772f2 - 2026-01-05 10:59:07 +03:00
14c8f95dd1 fix: password reset emails now use HTML template for Gmail compatibility 2026-01-05 10:47:56 +03:00
7f5c7443e6 refactor: реорганизация тестов для улучшения структуры и производительности
- Перемещены manual tests из scripts/manual_tests в tests/manual/
- Обновлен pytest.ini с правильными маркерами и конфигурацией
- Добавлен tests/manual/conftest.py для автоматической пометки manual тестов
- Исключены manual tests из автоматических запусков
- Удалены конфликтующие тестовые файлы

Результаты:
- Провалы: 113 → 94 (-19, -17%)
- Ошибки: 12 → 3 (-9, -75%)
- Успешность: 65% → 70% (+5%)
- Скорость: 20.71s → 16.46s (+20% быстрее)

Все изменения не влияют на основной код, только на структуру тестов.
2026-01-05 07:41:34 +03:00
de0caead6c fix: автор заявления должен получать уведомления о решении (approve/reject)
- Удалено исключение employee.id из notify_status_change()
- Коммит c0b659f9 ошибочно исключал автора, предполагая что он видит результат на странице
- После удаления alert() в коммите 935c12a уведомление стало единственным способом информирования
- Теперь автор получает уведомление о одобрении/отклонении заявления
- Approver остается исключенным (он сам нажал кнопку, не нужно ему уведомление)

Fixes: Users not receiving notifications when their request is approved/rejected
2026-01-05 07:11:46 +03:00
f45a4383ce fix: revoke role from LDAP group when removing via_assignment role 2025-12-30 12:31:55 +03:00
2a96bfe6b7 fix: ignore entryAlreadyExists when adding member to LDAP group 2025-12-30 12:27:57 +03:00
54f8f953f1 debug: add logging to set_member_role to diagnose 400 error 2025-12-30 12:24:39 +03:00
06ca3c228d ПОИСК БАГА НЕСОХРАНЕНИЯ РОЛЕЙ В ЛДАП 2025-12-30 11:22:48 +03:00
2811ac6e21 fix(roles): enforce LDAP-first pattern for role operations
When LDAP is enabled:
- create_role: creates LDAP group before DB record
- update_role: renames LDAP group before DB update
- delete_role: deletes LDAP group before DB deletion
- assign_role: adds to LDAP group before creating RoleAssignment
- revoke_role: removes from LDAP group before deactivating assignment

On LDAP error: operation fails, no DB changes
On DB error after LDAP success: rollback LDAP changes

Fixes: roles could bypass LDAP when it was enabled
2025-12-30 11:04:39 +03:00
fff16130f3 feat(department-roles): complete LDAP architecture redesign with RoleAssignment model
BREAKING CHANGES:
- Removed OU=Roles from LDAP structure, role groups now created directly in department OU
- Role groups use ROLE_<Name> naming convention (similar to DEP_, POS_)

New features:
- RoleAssignment model: allows assigning roles to ANY employee, not just department members
- New API endpoints: /assign/, /revoke/, /assignments/ on DepartmentRoleViewSet
- Permission system updated: has_dept_perm() checks RoleAssignment first
- Employee profile shows external roles with 'внешняя роль' badge
- Employee list filter includes role-only employees with department_relation field
- Role assignment modal now searches all employees via AJAX

LDAP changes:
- _ensure_role_group(): creates ROLE_<Name> group in department OU
- assign_role(), revoke_role(): manage RoleAssignment + LDAP sync
- rename_role_group(), delete_role_group(): full lifecycle support
- Removed all references to OU=Roles

Migrations:
- 0035: Create RoleAssignment model
- 0036: Data migration from EmployeeDepartment.role

Tests:
- 7 new tests for role assignment (all passing)

Docs:
- 9 detailed reports on architecture, models, API, LDAP, tests
2025-12-30 10:35:34 +03:00
5e0e058b3a fix: add CanViewRequest permission for recipients and cc_users to view request details 2025-12-29 16:08:15 +03:00
a4911f1145 fix(api): добавлен кастомный класс пагинации с поддержкой page_size 2025-12-29 15:48:19 +03:00
cefcb6b730 fix(requests): улучшены названия фильтров дат и исправлена логика фильтрации 2025-12-29 15:42:00 +03:00
a7d46c04f5 feat(requests): добавлены фильтры по сотруднику и периоду дат 2025-12-29 15:32:27 +03:00
9772d38a53 refactor(requests): заменён фильтр 'Область' на nav-pills как в документах 2025-12-29 15:25:18 +03:00
cc261f13cb feat(requests): текст темы в списке заявлений теперь ссылка на страницу деталей 2025-12-29 14:47:13 +03:00
7e7a2b2f9b fix(requests): убрано двоеточие перед именем approver в списке заявлений 2025-12-29 14:40:45 +03:00
c433001c85 refactor(requests): показывать имя approver вместо кнопок действий для уже обработанных заявлений 2025-12-29 14:38:48 +03:00
6e6d5755be refactor: переделать страницу деталей заявления с нуля со стилями из списка
- Полная переделка шаблона request_detail.html с единообразными стилями
- Новая структура: основная карточка (8 колонок) + боковая панель комментариев (4 колонки)
- Единообразные иконки типов заявлений (calendar-check, capsule, umbrella-fill и т.д.)
- Единообразные бейджи статуса и типа как в списке
- Информационные блоки для автора, описания, получателей, одобрившего
- Форма комментариев с правильным стилем message-field--compact
- Emoji picker с поддержкой dropdown-menu поверх контента
- AJAX обработка отправки и удаления комментариев
- Новый CSS файл request-detail.css с адаптивностью
- Добавлена функция _add_type_display() в views.py для отображения типа

Улучшения:
- Единство дизайна со страницей списка заявлений
- Правильное позиционирование emoji picker (fixed positioning)
- Sticky боковая панель с комментариями
- Форма комментария как в ленте (message-field--compact)
- Кнопки одобрения/отклонения с правильными иконками
2025-12-29 14:27:47 +03:00
653844af4f Исправлена view request_detail
- Добавлены comments в контекст
- Добавлен prefetch recipients и cc_users в DETAIL_REQUEST_QS
- Теперь все данные передаются правильно
2025-12-29 12:31:37 +03:00
b476605b10 Полностью переработана страница деталей заявления
Исправлено:
- Добавлена правильная структура card-header с аватаром 48x48px
- Добавлены все необходимые детали: получатели, копия, согласующий
- Исправлены стили для badge и card-body
- Добавлена корректная форма комментария с emoji picker и auto-expand
- Подключены правильные JavaScript компоненты
- Исправлен формат дат (d.m.Y H:i)
- Добавлена передача can_process в контексте view

Добавлено:
- Иконки для каждого раздела (получатели, копия, согласующий)
- Ссылки на карточки сотрудников
- Правильные Badge с subtle цветами
- Форма комментария с message-field компонентом
2025-12-29 12:25:42 +03:00
c70870d313 fix(requests): временно отключена кнопка 'Отозвать'
URL request_cancel не подключен в urls_front.py
Закомментирована кнопка до добавления функционала
2025-12-29 12:00:52 +03:00