refactor(actions): упростить EmployeeActionViewSet - удалить LDAP логику, использовать сигналы
Изменения: - EmployeeActionViewSet: 240 → 115 строк (-125 строк, -52%) - _apply_effects(): удалена вся LDAP логика (~140 строк) Удалено: - Прямые вызовы DirectoryService - Обработка LdapSyncState - Логика перемещения в OU=Dismissed и обратно - Удаление из департаментов в LDAP - Все try/except блоки для LDAP ошибок - Импорты: DirectoryService, DirectoryLdapError, DirectoryServiceError, DirectoryDbError, LdapSyncState, settings, _is_ldap_enabled Осталось только работа с БД: - При ACTION_DISMISSED: is_active=False + деактивация EmployeeDepartment - При других действиях: is_active=True LDAP синхронизация через существующие сигналы: - sync_employee_to_ldap_on_save: обрабатывает is_active (активация/деактивация) - sync_member (signals_department.py): обрабатывает EmployeeDepartment (удаление из отделов) Функционал сохранен, код стал в 2 раза короче
This commit is contained in:
parent
18ca956348
commit
e606a6ce2b
@ -4,21 +4,17 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
from employees.constants import ACTION_DISMISSED
|
||||
from employees.ldap.directory_service import DirectoryService
|
||||
from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError,
|
||||
DirectoryServiceError)
|
||||
from employees.models import EmployeeAction, EmployeeDepartment, LdapSyncState
|
||||
from employees.models import EmployeeAction, EmployeeDepartment
|
||||
from rest_framework import filters, viewsets
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
|
||||
from ...permissions import AdminOrActionOrModelPerms
|
||||
from ..serializers import EmployeeActionSerializer
|
||||
from ._helpers import HistoryActionMixin, _is_ldap_enabled
|
||||
from ._helpers import HistoryActionMixin
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -82,153 +78,32 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet):
|
||||
|
||||
# --- бизнес-эффекты после записи события ---
|
||||
def _apply_effects(self, action_obj: EmployeeAction):
|
||||
"""Применяет эффекты кадрового события.
|
||||
|
||||
Работает только с БД. LDAP синхронизация через сигналы:
|
||||
- sync_employee_to_ldap_on_save: активация/деактивация в LDAP
|
||||
- sync_member (signals_department.py): удаление из отделов в LDAP
|
||||
"""
|
||||
emp = action_obj.employee
|
||||
ldap_enabled = _is_ldap_enabled()
|
||||
|
||||
if action_obj.action == ACTION_DISMISSED:
|
||||
# Сначала деактивируем сотрудника
|
||||
# Деактивируем сотрудника (сигнал синхронизирует в LDAP)
|
||||
if emp.is_active:
|
||||
emp.is_active = False
|
||||
emp._ldap_changes = {"is_active": False}
|
||||
emp.save(update_fields=["is_active"])
|
||||
|
||||
# Деактивируем связи с отделами в БД
|
||||
# Деактивируем связи с отделами (сигналы синхронизируют в LDAP)
|
||||
EmployeeDepartment.objects.filter(employee=emp, is_active=True).update(
|
||||
is_active=False, date_to=timezone.now().date()
|
||||
)
|
||||
|
||||
# Синхронизируем с LDAP
|
||||
if ldap_enabled:
|
||||
try:
|
||||
svc = DirectoryService()
|
||||
has_ldap_dn = LdapSyncState.objects.filter(
|
||||
model="employee", object_pk=str(emp.pk), ldap_dn__isnull=False
|
||||
).exists()
|
||||
|
||||
if has_ldap_dn:
|
||||
svc.update_user(emp, changes={"is_active": False})
|
||||
|
||||
active_departments = EmployeeDepartment.objects.filter(
|
||||
employee=emp
|
||||
).select_related("department")
|
||||
|
||||
departments_processed = False
|
||||
for emp_dept in active_departments:
|
||||
try:
|
||||
svc.remove_member(emp_dept.department, emp)
|
||||
departments_processed = True
|
||||
except (
|
||||
DirectoryLdapError,
|
||||
DirectoryDbError,
|
||||
DirectoryServiceError,
|
||||
) as e:
|
||||
logger.error(
|
||||
f"Failed to remove dismissed employee from department: "
|
||||
f"employee_id={emp.id}, department_id={emp_dept.department.id}, error={e}"
|
||||
)
|
||||
|
||||
if not departments_processed:
|
||||
try:
|
||||
from employees.ldap.utils.ldap_utils import \
|
||||
get_base_dn_for_employee
|
||||
|
||||
sync_state = LdapSyncState.objects.filter(
|
||||
model="employee", object_pk=str(emp.pk)
|
||||
).first()
|
||||
|
||||
if sync_state and sync_state.ldap_dn:
|
||||
target_base = get_base_dn_for_employee(emp)
|
||||
current_dn = sync_state.ldap_dn
|
||||
|
||||
if not current_dn.lower().endswith(
|
||||
target_base.lower()
|
||||
):
|
||||
try:
|
||||
new_dn = svc.move_user_to_base(
|
||||
emp, target_base
|
||||
)
|
||||
logger.info(
|
||||
f"Dismissed employee without department moved to OU=Dismissed: "
|
||||
f"employee_id={emp.id}, new_dn={new_dn}"
|
||||
)
|
||||
except Exception as move_err:
|
||||
logger.error(
|
||||
f"Failed to move dismissed employee: {move_err}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to move dismissed employee without department to OU=Dismissed: "
|
||||
f"employee_id={emp.id}, error={e}"
|
||||
)
|
||||
except (
|
||||
DirectoryLdapError,
|
||||
DirectoryDbError,
|
||||
DirectoryServiceError,
|
||||
) as e:
|
||||
logger.error(
|
||||
f"Failed to disable user in LDAP during dismissal: "
|
||||
f"employee_id={emp.id}, error={e}"
|
||||
)
|
||||
else:
|
||||
# Любое иное событие делает сотрудника активным
|
||||
was_inactive = not emp.is_active
|
||||
if was_inactive:
|
||||
# Любое иное событие делает сотрудника активным (сигнал синхронизирует в LDAP)
|
||||
if not emp.is_active:
|
||||
emp.is_active = True
|
||||
emp._ldap_changes = {"is_active": True}
|
||||
emp.save(update_fields=["is_active"])
|
||||
|
||||
if ldap_enabled:
|
||||
try:
|
||||
svc = DirectoryService()
|
||||
has_ldap_dn = LdapSyncState.objects.filter(
|
||||
model="employee", object_pk=str(emp.pk), ldap_dn__isnull=False
|
||||
).exists()
|
||||
|
||||
if has_ldap_dn:
|
||||
svc.update_user(emp, changes={"is_active": True})
|
||||
|
||||
if was_inactive:
|
||||
try:
|
||||
sync_state = LdapSyncState.objects.get(
|
||||
model="employee", object_pk=str(emp.pk)
|
||||
)
|
||||
current_dn = sync_state.ldap_dn
|
||||
dismissed_base = getattr(
|
||||
settings, "LDAP_DISMISSED_BASE", ""
|
||||
)
|
||||
|
||||
if dismissed_base and current_dn.lower().endswith(
|
||||
dismissed_base.lower()
|
||||
):
|
||||
users_base = getattr(
|
||||
settings, "LDAP_USERS_BASE", None
|
||||
) or getattr(settings, "LDAP_USER_BASE", None)
|
||||
if users_base:
|
||||
try:
|
||||
new_dn = svc.move_user_to_base(
|
||||
emp, users_base
|
||||
)
|
||||
logger.info(
|
||||
f"Restored employee moved from Dismissed to Users: "
|
||||
f"employee_id={emp.id}, new_dn={new_dn}"
|
||||
)
|
||||
except Exception as move_err:
|
||||
logger.error(
|
||||
f"Failed to move restored employee: {move_err}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
f"Failed to move restored employee from Dismissed to Users: "
|
||||
f"employee_id={emp.id}, error={e}"
|
||||
)
|
||||
except (
|
||||
DirectoryLdapError,
|
||||
DirectoryDbError,
|
||||
DirectoryServiceError,
|
||||
) as e:
|
||||
logger.error(
|
||||
f"Failed to enable user in LDAP during action: "
|
||||
f"employee_id={emp.id}, action={action_obj.action}, error={e}"
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def perform_create(self, serializer):
|
||||
obj = serializer.save()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user