Команда синхронизирует Django pk существующих пользователей в LDAP employeeNumber:
- По умолчанию dry-run режим
- Опция --user-id для теста на одном пользователе
- Опция --force для перезаписи существующих значений
- Использует LdapSyncState для поиска DN пользователей
- Добавлена настройка 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 атрибутов
✅ КРИТИЧЕСКИЕ ИСПРАВЛЕНИЯ:
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
- Добавлена автоматическая отписка от Web Push при выходе
- При входе принудительно переподписываем пользователя
- Очищаем старую подписку из localStorage перед новой
- Это исправляет AbortError из-за старых подписок с другими 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)
- Исправлена маршрутизация 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/ для правильной организации
Вся функциональность уведомлений проверена и работает корректно.
- 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
- 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
- Удалено исключение employee.id из notify_status_change()
- Коммит c0b659f9 ошибочно исключал автора, предполагая что он видит результат на странице
- После удаления alert() в коммите 935c12a уведомление стало единственным способом информирования
- Теперь автор получает уведомление о одобрении/отклонении заявления
- Approver остается исключенным (он сам нажал кнопку, не нужно ему уведомление)
Fixes: Users not receiving notifications when their request is approved/rejected
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
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
- Полная переделка шаблона 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)
- Кнопки одобрения/отклонения с правильными иконками
Исправлено:
- Добавлена правильная структура card-header с аватаром 48x48px
- Добавлены все необходимые детали: получатели, копия, согласующий
- Исправлены стили для badge и card-body
- Добавлена корректная форма комментария с emoji picker и auto-expand
- Подключены правильные JavaScript компоненты
- Исправлен формат дат (d.m.Y H:i)
- Добавлена передача can_process в контексте view
Добавлено:
- Иконки для каждого раздела (получатели, копия, согласующий)
- Ссылки на карточки сотрудников
- Правильные Badge с subtle цветами
- Форма комментария с message-field компонентом
ПРОБЛЕМА: Уведомления не отправлялись при создании нового заявления
ПРИЧИНА: Сигнал post_save срабатывал ДО установки ManyToMany связей (recipients, cc_users)
РЕШЕНИЕ:
- Добавлен сигнал m2m_changed для отслеживания установки recipients/cc_users
- При создании заявления оно помечается как ожидающее отправки уведомлений
- После установки recipients через .set() срабатывает m2m_changed и отправляет уведомления
- Используется глобальный set _pending_new_requests для отслеживания
УЛУЧШЕНИЯ:
- Добавлено подробное логирование процесса создания и отправки уведомлений
- Разные эмодзи-иконки для разных типов получателей (� адресовано, � в копии, ✅ на согласование)
- Все типы используют notification_type='request_new' (существующий в БД)
Файлы:
- notification_signals.py: добавлены сигналы m2m_changed
- serializers.py: добавлено логирование создания и установки recipients
Добавлено подробное логирование для диагностики проблемы с уведомлениями:
- Логируется срабатывание сигнала create_request_notifications
- Логируется статус заявления при создании
- Логируется каждый добавленный получатель
- Логируется итоговый список получателей
- Логируется роль каждого получателя при отправке уведомления
- Исправлена терминология: 'заявка' → 'заявление' во всех уведомлениях
- Добавлены эмодзи-иконки для визуального различия типов уведомлений
- Разделены типы уведомлений для основных получателей и cc_users:
* request_new_primary - � адресовано непосредственно
* request_new_cc - � в копии (информирование)
* request_new_approver - ✅ на согласование
* request_new_dept - � в отделе
- Добавлены детали в уведомления:
* Имя автора заявления
* Тип заявления
* Превью комментария (до 150 символов)
* Имя approver в уведомлениях о решении
- Улучшены заголовки с указанием типа заявления
- В metadata добавлены employee_name и approver_name
- requestCrudHandler.js: заменены alert+reload на закрытие модального окна + событие
- requestList.js: добавлен обработчик события request:updated с отложенной перезагрузкой (500ms)
- Улучшен UX: модальное окно плавно закрывается, затем обновляется список
- Системное уведомление больше не появляется
- Approver (тот кто принял решение) не получает уведомление о своем действии
- Исключены employee.id и approver_id из recipients при approve/reject
- Упрощен signal create_request_notifications (убран лишний запрос в БД)
- Теперь передается актуальный request_obj с установленным approver_id