14 Commits

Author SHA1 Message Date
lizerk
b98a82176c test(ldap): add live integration coverage and fix sync paths 2026-04-12 03:51:52 +03:00
lizerk
6ee32111db chore: configure vscode flake8 and commit lint cleanup 2026-03-31 19:17:56 +03:00
lizerk
2815efe069 chore: finalize backend lint cleanup 2026-03-31 17:53:29 +03:00
lizerk
f88d90230b refactor: clean architecture, align tests to current API contracts, all tests green [deploy-ready] 2026-03-30 04:27:18 +03:00
lizerk
4c5ea98743 админка+ 2026-03-20 14:44:41 +03:00
lizerk
98e98289bf Fix LDAP synchronization issues, improve logging, and resolve binary decoding errors 2026-03-19 23:50:27 +03:00
lizerk
75662ec7ea feat(ldap): Полная миграция на django-ldapdb ORM с миксинами и Django Admin
LDAP ORM модели (orm_models.py):
================================
✅ Применены миксины ModifyDnMixin и LdapSyncStateMixin ко всем моделям
✅ LdapUser - поддержка modify_dn + автоуправление LdapSyncState
✅ LdapGroup - поддержка modify_dn для перемещения групп
✅ LdapOrganizationalUnit - поддержка modify_dn для реорганизации

Миксины (mixins.py) - НОВЫЙ ФАЙЛ:
=================================
✅ ModifyDnMixin - автоматический modify_dn при изменении base_dn
   • Отслеживает изменения base_dn
   • Выполняет LDAP modify_dn с newsuperior
   • Обновляет _saved_dn для корректного последующего save()
   • Использование: user.base_dn = new_dn; user.save()

✅ LdapSyncStateMixin - автоуправление LdapSyncState
   • Автоматически создает/обновляет LdapSyncState при save()
   • Автоматически удаляет LdapSyncState при delete()
   • Настройки: _sync_model_name, _sync_pk_field

Django Admin для LDAP (admin.py) - НОВЫЙ ФАЙЛ:
==============================================
✅ LdapUserAdmin - полноценная админка для LDAP пользователей
   • List display: CN, SAM, email, Django Employee link, sync status
   • Search: по CN, SAM, email, имени, фамилии
   • Filters: по userAccountControl
   • Actions синхронизации:
     - sync_from_ldap_to_django (LDAP → Django)
     - sync_from_django_to_ldap (Django → LDAP)
     - show_sync_diff (сравнение данных)
   • Fieldsets: идентификация, персональные данные, контакты, UAC, группы
   • DN форматирование с подсветкой компонентов
   • Sync status indicators с иконками

Django Admin для Employee (employees/admin.py):
===============================================
✅ Добавлены зеркальные actions синхронизации:
   • sync_from_django_to_ldap - создание/обновление в LDAP
     - Автоматическое создание LDAP пользователя если не существует
     - Генерация временного пароля
     - Установка is_ldap_managed = True
   • sync_from_ldap_to_django - обновление из LDAP
   • show_sync_diff - сравнение Django ↔ LDAP
✅ Импорт django.contrib.messages для уведомлений

Сервисы LDAP (services/):
=========================
✅ UserService - полная миграция на ORM для UPDATE операций
✅ GroupService - использование ORM для модификаций
✅ DepartmentService - ORM для обновления OU
✅ PositionService - ORM для групп позиций

Тесты (tests/unit/):
===================
✅ test_user_service.py - обновлены под ORM
✅ test_group_service.py - обновлены под ORM
✅ test_position_service.py - обновлены под ORM
✅ conftest.py - добавлены фикстуры для ORM моделей

Authentication (auth_backends.py):
=================================
✅ EmailOrPhoneBackend - добавлено подробное debug логирование
   • Логирование email/phone lookup
   • Логирование is_active проверки
   • Логирование password check с hash prefix
✅ SuperuserOnlyBackend - добавлено debug логирование
   • Логирование parent auth результата
   • Логирование is_superuser проверки

API (api/auth/serializers.py):
==============================
✅ PhoneOrEmailTokenObtainPairSerializer - исправлен KeyError
   • Добавлена проверка credentials перед super().validate()
   • Явный AuthenticationFailed при отсутствии учетных данных

Middleware (middleware.py):
===========================
✅ Очистка от устаревшего кода (305 → 102 строки)
   • ❌ Удалена EmailVerificationMiddleware (не используется)
   • ❌ Удалена RegistrationIPRestrictionMiddleware (не используется)
   • ❌ Удалены все ссылки на namespace 'auth_front'
   • ✅ Возврат 403 для неавторизованных вместо редиректа

Settings (settings.py):
=======================
✅ LOGIN_URL изменен с 'auth_front:login' на '/admin/login/'
✅ Добавлено DEBUG логирование для:
   • django.contrib.auth
   • eusrr_backend.auth_backends

Миграции:
=========
✅ Удалены старые миграции LDAP моделей (0042, 0043)
✅ Добавлена миграция LdapSyncQueue (0042_ldapsyncqueue.py)

Документация:
=============
✅ ADMIN_GUIDE.md - руководство по использованию LDAP Admin
✅ docs/guides/ldap-orm-mixins-usage.md - usage guide для миксинов
✅ docs/completed/ldap-orm-create-support.md - документация ORM миграции
✅ docs/in-progress/LDAP_ORM_MIGRATION_PLAN.md - план миграции

Инфраструктура (__init__.py):
=============================
✅ Добавлен импорт admin для авторегистрации
✅ Экспорт ORM моделей (LdapUser, LdapGroup, LdapOrganizationalUnit)

ИТОГО:
======
• Полная миграция с ldap3 на django-ldapdb ORM для UPDATE/MOVE/DELETE
• Унификация: один подход для всех LDAP операций через модели
• Автоматизация: синхронизация состояния и перемещения через миксины
• UI: полноценный Django Admin для управления LDAP объектами
• Отладка: расширенное логирование аутентификации
• Чистота: удален устаревший код middleware и миграций
• Тесты: 29 passed, 0 failed, 18 skipped

Breaking Changes: НЕТ - обратная совместимость сохранена
2026-03-19 22:33:06 +03:00
lizerk
ee920dd365 refactor(employees): реорганизация структуры сигналов
ПРОБЛЕМЫ СТАРОЙ СТРУКТУРЫ:
- 5 файлов сигналов в корне employees/ (захламление)
- Непоследовательность: signals_ldap.py vs signals_department.py
- apps.py импортирует каждый файл явно (5 строк)
- Нет группировки по назначению (LDAP разбросан)

НОВАЯ СТРУКТУРА:
employees/
  signals/
    __init__.py              # единая точка входа
    common.py                # общие сигналы (было signals.py)
    birthday.py              # дни рождений
    ldap/
      __init__.py
      employee.py            # Employee ↔ LDAP
      department.py          # Department ↔ LDAP OU
      group.py               # Group ↔ LDAP Group

ПРЕИМУЩЕСТВА:
- Чёткая иерархия: общие сигналы и LDAP-специфичные
- Единый импорт в apps.py: import employees.signals
- Понятные имена модулей (employee.py вместо signals_ldap.py)
- Масштабируемость: легко добавить signals/email/, signals/webhooks/ и т.д.

ИЗМЕНЕНИЯ:
- Создана структура signals/ и signals/ldap/
- Перемещены и переименованы 5 файлов сигналов
- Обновлены docstrings с новыми путями
- Исправлены относительные импорты в common.py
- apps.py: упрощён с 5 импортов до 1
- Django check: успешно

Git корректно распознал переименования (R), история сохранена.
2026-03-18 19:22:30 +03:00
lizerk
18ca956348 feat(groups): добавить Django сигналы для LDAP синхронизации + упростить GroupViewSet
Создан signals_group.py:
- post_save(Group): создание/обновление LdapGroup (cn, description, scope, security)
- post_delete(Group): удаление LdapGroup
- m2m_changed(Group.user_set): синхронизация участников (add/remove/clear)

Упрощен GroupViewSet (641 → 339 строк, -47%):
- create(): только создание в БД + временные атрибуты для сигнала
- partial_update(): передача _ldap_old_name и _ldap_description в сигнал
- destroy(): базовый ViewSet метод
- list(): удален sync_groups_catalog (должен быть в фоне/cron)
- rename: упрощен до установки _ldap_old_name и save()
- set_description: упрощен до установки _ldap_description и save()
- members: только БД запрос (без LDAP)
- add_members: user_set.add(), сигнал синхронизирует в LDAP
- remove_members: user_set.remove(), сигнал синхронизирует в LDAP
- replace_members: user_set.set(), сигнал синхронизирует в LDAP

Удалено:
- Все if ldap_enabled блоки
- Прямые вызовы DirectoryService в ViewSet
- Rollback логика при ошибках LDAP
- Helper методы: _resolve_group_dn, _members_payload_to_dns, _dns_to_users
- Импорты: DirectoryService, settings, transaction, LdapSyncState, _is_ldap_enabled

Зарегистрирован сигнал в employees/apps.py
2026-03-18 18:11:54 +03:00
lizerk
d0f6eee644 feat(departments): добавить Django сигналы для LDAP синхронизации
- Создан employees/signals_department.py
- post_save(Department): создание/обновление OU в LDAP
  - При created: создает OU, устанавливает description, managedBy
  - При update: синхронизирует name, description, head
- post_delete(Department): удаление OU из LDAP
- post_save(EmployeeDepartment): синхронизация членства
  - При is_active=True: перемещает пользователя в OU отдела + роль
  - При is_active=False: перемещает обратно в Users OU

Подключено в employees/apps.py
2026-03-18 17:14:54 +03:00
lizerk
5585758ede refactor(ldap): replace ExternalSystemSyncMixin with Django signals
- Удалён ExternalSystemSyncMixin из EmployeeViewSet
- ViewSet теперь использует временные атрибуты (_ldap_password, _ldap_avatar, _ldap_changes)
- Создан employees/signals_ldap.py с post_save/post_delete handlers
- Сигналы автоматически синхронизируют Employee с LDAP через DirectoryService
- Убран дублирующий блок required_perms_by_action из EmployeeViewSet
- Упрощены perform_create и perform_update (-170 строк)

Архитектурное улучшение: разделение ответственности ViewSet (HTTP) и signals (синхронизация)
2026-03-18 16:13:20 +03:00
d3b648b438 feat: интеграция django-rules для object-level permissions
- Установлен пакет rules==3.5
- Добавлен ObjectPermissionBackend в AUTHENTICATION_BACKENDS
- Созданы базовые правила для employees:
  * Предикаты: is_hr_staff, is_department_head, is_own_profile и др.
  * Правила: view/change/delete employee, view reports и контакты
- Созданы базовые правила для documents:
  * Предикаты: is_document_owner, has_document_access, can_approve и др.
  * Правила: view/change/delete/approve/publish/share documents
- Правила регистрируются в apps.py (ready() метод)
- Создана подробная документация с примерами использования
  * В views, templates, DRF permissions, Django Admin
  * Сценарии: многоуровневое согласование, временные ограничения
  * Сравнение с django-guardian, отладка, тестирование

Документация: docs/guides/DJANGO_RULES_INTEGRATION.md
2026-02-28 00:07:53 +03:00
8e66ac9b65 feat(employees): переход на Service Layer и перенос birthday логики из calendar_app
- Интегрирован django-service-objects 0.7.1 для Service Layer Pattern
- Перенесена вся логика дней рождения из calendar_app → employees:
  * UpsertBirthdayEventService - создание/обновление событий ДР
  * DeleteBirthdayEventService - удаление событий ДР
  * BulkSyncBirthdaysService - массовая синхронизация
  * signals_birthday.py - автосинхронизация через post_save/post_delete
  * management command sync_birthdays - CLI команда синхронизации
  * тесты (11 tests, 6 passing)

- Обновлена миграция 0013_migrate_to_django_scheduler:
  * Добавлен ШАГ 5: автоматическая синхронизация дней рождения (131 событие)
  * Исключены старые события ДР из миграции (source.endswith(':birthday'))
  * Исправлены имена сотрудников (f'{last_name} {first_name}' вместо get_full_name())
  * Добавлен цвет #FFC107 для событий дней рождения

- Очищен calendar_app от birthday сервисов:
  * Удалены calendar_app/services/birthday_events.py
  * Удалены calendar_app/signals_scheduler.py
  * Удалены calendar_app/management/commands/sync_birthdays.py
  * Удалены calendar_app/tests/test_services.py
  * Обновлен apps.py - удалены ссылки на signals_scheduler

- API улучшения:
  * Добавлен api/v1/schedule/permissions.py (IsCalendarOwnerOrAdmin)
  * Обновлен views.py с правильными permissions

- Документация:
  * DJANGO_SERVICE_OBJECTS_INTEGRATION.md - руководство по Service Layer
  * CALENDAR_MIGRATION_ANALYSIS.md - анализ миграции
  * MODERNIZATION_ANALYSIS.md - анализ модернизации кодовой базы

Цель: подготовка к будущему удалению calendar_app, централизация
логики сотрудников в employees приложении.

Refs: #birthday-refactoring
2026-02-27 23:49:09 +03:00
Игорь Надеин
a42204dda0 0 2025-08-05 15:30:41 +03:00