5 Commits

Author SHA1 Message Date
lizerk
95ff0dc0af refactor(ldap): заменить ldap3 CRUD на django-ldapdb ORM
- user_service.py: read_attrs/modify_user_attrs → LdapUser ORM,
  sync_user_groups_by_cns → ORM, delete_user без _ldap() контекста
- group_service.py: _wrapped методы через LdapGroup ORM
- department_service.py: _set_ou_description/_delete_department_ou → ORM
- views.py, employees.py: ldap_info через LdapUser ORM
- sync_employee_ids_to_ldap: полная замена на LdapUser ORM
- __init__.py: ORM реэкспорты, обёртки import_*/export_*
- orm_models.py: compatibility shim для django-ldapdb + Django 5.x
- Создан group_utils_orm.py (ORM замена group_utils)
- Удалён deprecated sync_service.py (352 строки)

TODO(ldap-orm) помечены: _set_password, _enable_user, _unique_logins,
_create_user_in_ldap, _move_user_to_base, rename (modify_dn),
sync_catalog (paged search), _set_ou_managed_by
2026-03-18 14:25:53 +03:00
026bc46816 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
b3ee4f1960 feat(ldap): separate dismissed employees to OU=Dismissed
Implemented automatic movement of dismissed employees to dedicated OU.

Core Changes:
- Configuration: Added LDAP_DISMISSED_BASE setting for dismissed employees OU
- Utility: Created get_base_dn_for_employee() to determine target OU by is_active status
- Service Layer: Modified DepartmentService.remove_member() to use status-based OU selection
- View Logic: Updated EmployeeActionViewSet._apply_effects() to:
  * Deactivate employee BEFORE removing from departments (critical for correct OU routing)
  * Loop through all departments and call remove_member() for each
  * Handle restoration: move from OU=Dismissed back to OU=Users on activation

Infrastructure:
- Management Command: ensure_dismissed_ou.py to create OU=Dismissed in AD
  * Checks OU existence before creation
  * Supports --force flag for recreation
  * Configurable description

Testing:
- test_dismissal_moves_to_dismissed_ou: Verifies dismissal → OU=Dismissed movement
- test_restoration_moves_from_dismissed_to_users: Verifies activation → OU=Users movement

Edge Cases Handled:
- Repeat dismissal: Idempotent (already inactive employees stay in OU=Dismissed)
- Restoration: Automatic move from OU=Dismissed to OU=Users on any activating action
- Missing OU: ensure_container_exists() creates OU=Dismissed if missing (fallback to OU=Users on error)
- LDAP errors: Graceful logging without blocking database operations

Technical Details:
- OU=Dismissed: OU=Dismissed,OU=company,DC=robotail,DC=local
- Dismissal flow: is_active=False → deactivate EmployeeDepartment → update LDAP UAC → remove from all departments
- Restoration flow: is_active=True → update LDAP UAC → check current OU → move if in OU=Dismissed
- Backward compatible: Works with existing dismissals (they will move to OU=Dismissed on next department change)

Files Changed:
- backend/.env: Added LDAP_DISMISSED_BASE configuration
- backend/eusrr_backend/settings.py: Registered LDAP_DISMISSED_BASE setting
- backend/employees/ldap/utils/ldap_utils.py: New get_base_dn_for_employee() utility
- backend/employees/ldap/services/department_service.py: Modified remove_member() logic
- backend/api/v1/employees/views.py: Enhanced dismissal and restoration logic
- backend/employees/management/commands/ensure_dismissed_ou.py: New management command
- backend/tests/api/v1/employees/test_employee_actions.py: Added tests for new behavior
2025-12-18 11:56:51 +03:00
992dc6a13f feat: maximize LDAP avatar quality (384px, progressive JPEG, 4:4:4)
- Увеличено разрешение: 120px -> 384px (+900% пикселей)
- Повышено качество JPEG: 50-95 -> 75-98
- Добавлен progressive JPEG для лучшего сжатия
- Включён subsampling 4:4:4 (без потери цветности)
- Добавлена обработка EXIF ориентации
- Добавлено сохранение пропорций (thumbnail вместо resize)
- Обработка прозрачности PNG

Улучшения в:
- employees/ldap/utils/image_utils.py
- employees/ldap/services/user_service.py
- employees/ldap/sync_service.py

Добавлены тестовые скрипты:
- test_ldap_simple.py (быстрый тест)
- test_avatar_simple.py (тест системного сжатия)
- TEST_IMAGE_SCRIPTS.md (документация)
2025-12-16 14:55:58 +03:00
4d04aafdb9 refactor: Replace inline CSS with components (Phase 3)
- Replaced feed-* inline styles in base.html with feed-cards.css component (~60 lines)
- Replaced ios-search inline styles in 3 templates with ios-search.css component
  * employees/employees_list.html
  * search/results.html
  * employees/department_list.html
- Eliminated ~150 lines of duplicate CSS across templates
- All 17 tests passing
2025-10-28 08:54:38 +03:00