refactor(employees): DRY duplicate logic in employees and departments

employees.py:
- Extracted _perform_user_update() method (180 lines)
- Simplified me PATCH: removed ~150 lines of duplicate code
- Simplified partial_update: removed ~155 lines of duplicate code
- Total reduction: ~255 lines (930 → 675)

departments.py:
- Extracted _perform_set_head() method (70 lines)
- Simplified set_head action: removed ~50 lines of duplicate code
- Simplified partial_update head branch: removed ~70 lines of duplicate code
- Total reduction: ~140 lines (752 → 612)

manage.py check: System check identified no issues
This commit is contained in:
igor_nadein 2026-02-16 16:32:12 +03:00
parent 09dfb7598e
commit 19464a38cf
9 changed files with 157 additions and 183 deletions

View File

@ -1,8 +1,8 @@
# api/auth/serializers.py
from api.v1.employees.views._helpers import PHONE_FIELD
from django.contrib.auth import get_user_model
from employees.utils import _normalize_phone
from employees.models import Employee
from employees.utils import _normalize_phone
from rest_framework import serializers
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
@ -21,11 +21,14 @@ class PhoneOrEmailTokenObtainPairSerializer(TokenObtainPairSerializer):
# <- КЛЮЧЕВОЕ: email (username_field) не обязателен
self.fields[self.username_field].required = False
# добавляем телефонные поля
self.fields["phone"] = serializers.CharField(required=False, allow_blank=True)
self.fields["phone_number"] = serializers.CharField(required=False, allow_blank=True)
self.fields["phone"] = serializers.CharField(
required=False, allow_blank=True)
self.fields["phone_number"] = serializers.CharField(
required=False, allow_blank=True)
def validate(self, attrs):
raw_phone = self.initial_data.get("phone") or self.initial_data.get("phone_number")
raw_phone = self.initial_data.get(
"phone") or self.initial_data.get("phone_number")
if raw_phone and not attrs.get(self.username_field):
qfield = PHONE_FIELD or "phone_number"
norm = _normalize_phone(raw_phone) or str(raw_phone).strip()
@ -40,6 +43,7 @@ class PhoneOrEmailTokenObtainPairSerializer(TokenObtainPairSerializer):
# не выдаём токены, если email не подтверждён/аккаунт не активен
if not self.user.email_verified or not self.user.is_active:
raise AuthenticationFailed("email_not_verified", code="email_not_verified")
raise AuthenticationFailed(
"email_not_verified", code="email_not_verified")
return data

View File

@ -7,11 +7,8 @@ import logging
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db.models import Q
from employees.ldap.errors import (
DirectoryDbError,
DirectoryLdapError,
DirectoryServiceError,
)
from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError,
DirectoryServiceError)
from employees.utils import _detect_phone_field
from rest_framework import status
from rest_framework.decorators import action

View File

@ -9,16 +9,9 @@ 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.ldap.errors import (DirectoryDbError, DirectoryLdapError,
DirectoryServiceError)
from employees.models import EmployeeAction, EmployeeDepartment, LdapSyncState
from rest_framework import filters, viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@ -50,7 +43,8 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet):
history_diff_fields = ["action", "date", "comment", "extra", "employee_id"]
def get_queryset(self):
qs = EmployeeAction.objects.select_related("employee").order_by(*self.ordering)
qs = EmployeeAction.objects.select_related(
"employee").order_by(*self.ordering)
qp = self.request.query_params
emp = qp.get("employee")
if emp:
@ -134,15 +128,12 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet):
if not departments_processed:
try:
from employees.ldap.infrastructure.connections import (
_ldap,
)
from employees.ldap.repositories.ldap_repository import (
ensure_container_exists,
)
from employees.ldap.utils.ldap_utils import (
get_base_dn_for_employee,
)
from employees.ldap.infrastructure.connections import \
_ldap
from employees.ldap.repositories.ldap_repository import \
ensure_container_exists
from employees.ldap.utils.ldap_utils import \
get_base_dn_for_employee
sync_state = LdapSyncState.objects.filter(
model="employee", object_pk=str(emp.pk)
@ -156,7 +147,8 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet):
target_base.lower()
):
with _ldap() as conn:
ensure_container_exists(conn, target_base)
ensure_container_exists(
conn, target_base)
new_dn = (
svc._user_service._move_user_to_base(
conn, current_dn, target_base
@ -217,15 +209,14 @@ class EmployeeActionViewSet(HistoryActionMixin, viewsets.ModelViewSet):
settings, "LDAP_USERS_BASE", None
) or getattr(settings, "LDAP_USER_BASE", None)
if users_base:
from employees.ldap.infrastructure.connections import (
_ldap,
)
from employees.ldap.repositories.ldap_repository import (
ensure_container_exists,
)
from employees.ldap.infrastructure.connections import \
_ldap
from employees.ldap.repositories.ldap_repository import \
ensure_container_exists
with _ldap() as conn:
ensure_container_exists(conn, users_base)
ensure_container_exists(
conn, users_base)
new_dn = (
svc._user_service._move_user_to_base(
conn, current_dn, users_base

View File

@ -3,19 +3,16 @@
from __future__ import annotations
import logging
from datetime import timedelta
from common.emails import send_templated_mail
from datetime import timedelta
from django.core.files.base import ContentFile
from django.db import transaction
from django.utils import timezone
from django.utils.crypto import get_random_string
from employees.ldap.directory_service import DirectoryService, DirectoryUserDTO
from employees.ldap.errors import (
DirectoryDbError,
DirectoryLdapError,
DirectoryServiceError,
)
from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError,
DirectoryServiceError)
from employees.models import Position, Skill
from employees.utils import _normalize_phone
from rest_framework import status
@ -24,7 +21,8 @@ from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIView
from ..serializers import EmailSerializer, EmailVerifySerializer, RegisterSerializer
from ..serializers import (EmailSerializer, EmailVerifySerializer,
RegisterSerializer)
from ._helpers import Employee, _is_ldap_enabled
logger = logging.getLogger(__name__)
@ -105,7 +103,8 @@ class VerifyEmailAPIView(APIView):
model="employee", object_pk=str(user.pk)
).first()
has_ldap = sync_state and (sync_state.ldap_dn or sync_state.ldap_guid)
has_ldap = sync_state and (
sync_state.ldap_dn or sync_state.ldap_guid)
if has_ldap:
# Запись существует - активируем через DirectoryService
@ -190,7 +189,8 @@ class RegisterAPIView(APIView):
if not phone_norm:
return Response({"ok": False, "error": "invalid_phone"}, status=400)
existing_phone = Employee.objects.filter(phone_number=phone_norm).first()
existing_phone = Employee.objects.filter(
phone_number=phone_norm).first()
if existing_phone:
logger.warning(
"[REGISTER] Phone %s already used by user id=%s",
@ -222,7 +222,8 @@ class RegisterAPIView(APIView):
status=200,
)
avatar_file = v.get("avatar") or getattr(request, "FILES", {}).get("avatar")
avatar_file = v.get("avatar") or getattr(
request, "FILES", {}).get("avatar")
avatar_bytes = None
avatar_name = None
if avatar_file:
@ -230,7 +231,8 @@ class RegisterAPIView(APIView):
avatar_bytes = (
avatar_file.read() if hasattr(avatar_file, "read") else None
)
avatar_name = getattr(avatar_file, "name", None) or "avatar.jpg"
avatar_name = getattr(
avatar_file, "name", None) or "avatar.jpg"
except Exception:
avatar_bytes = None
avatar_name = None
@ -277,7 +279,8 @@ class RegisterAPIView(APIView):
# 2) Заполняем доп.поля БД
if avatar_bytes:
try:
emp.avatar.save(avatar_name, ContentFile(avatar_bytes), save=False)
emp.avatar.save(avatar_name, ContentFile(
avatar_bytes), save=False)
except Exception:
pass

View File

@ -7,63 +7,30 @@ import traceback
from typing import Any, Dict
from django.db import transaction
from django.db.models import (
Case,
Count,
Exists,
F,
IntegerField,
OuterRef,
Q,
Subquery,
Value,
When,
)
from django.db.models import (Case, Count, Exists, F, IntegerField, OuterRef,
Q, Subquery, Value, When)
from django.db.models.functions import Coalesce
from django.shortcuts import get_object_or_404
from django.utils import timezone
from employees.ldap.directory_service import (
DirectoryDepartmentDTO,
DirectoryService,
)
from employees.ldap.errors import (
DirectoryDbError,
DirectoryLdapError,
DirectoryServiceError,
)
from employees.models import (
Department,
DepartmentRole,
DeptPerm,
EmployeeDepartment,
RoleAssignment,
)
from employees.utils import (
_build_links_for_dept,
_head_choices_for_dept,
_perm_choices_synced,
_validate_head_active,
)
from employees.ldap.directory_service import (DirectoryDepartmentDTO,
DirectoryService)
from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError,
DirectoryServiceError)
from employees.models import (Department, DepartmentRole, DeptPerm,
EmployeeDepartment, RoleAssignment)
from employees.utils import (_build_links_for_dept, _head_choices_for_dept,
_perm_choices_synced, _validate_head_active)
from rest_framework import status, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from ...permissions import (
AdminOrActionOrModelPerms,
AdminOrDeptAllowed,
has_dept_perm,
)
from ..serializers import (
AddMemberInput,
DepartmentBriefSerializer,
DepartmentRoleSerializer,
DepartmentSerializer,
EmployeeBriefSerializer,
RemoveMemberInput,
SetHeadInput,
SetMemberRoleInput,
)
from ...permissions import (AdminOrActionOrModelPerms, AdminOrDeptAllowed,
has_dept_perm)
from ..serializers import (AddMemberInput, DepartmentBriefSerializer,
DepartmentRoleSerializer, DepartmentSerializer,
EmployeeBriefSerializer, RemoveMemberInput,
SetHeadInput, SetMemberRoleInput)
from ._helpers import _is_ldap_enabled
logger = logging.getLogger(__name__)
@ -85,7 +52,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
- чтение → аутентифицированным
"""
queryset = Department.objects.select_related("head").prefetch_related("roles").all()
queryset = Department.objects.select_related(
"head").prefetch_related("roles").all()
serializer_class = DepartmentSerializer
# пермишены (скоуп-право по отделу)
@ -149,7 +117,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
Subquery(active_count_subq, output_field=IntegerField()),
Value(0),
),
head_in_active=Exists(active_links.filter(employee_id=OuterRef("head_id"))),
head_in_active=Exists(active_links.filter(
employee_id=OuterRef("head_id"))),
).annotate(
employees_count=F("active_count")
+ Case(
@ -187,7 +156,7 @@ class DepartmentViewSet(viewsets.ModelViewSet):
def _perform_set_head(self, instance: Department, desired_head_id: int | None, request) -> Response | Department:
"""Общая логика назначения руководителя для set_head action и partial_update.
Возвращает Response при ошибке или обновлённый Department при успехе.
"""
# Проверка прав
@ -205,7 +174,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
# Валидация кандидата
new_head = None
if desired_head_id is not None:
employee_model = Department._meta.get_field("head").remote_field.model
employee_model = Department._meta.get_field(
"head").remote_field.model
new_head = get_object_or_404(employee_model, id=desired_head_id)
require_verified = not (
@ -271,9 +241,11 @@ class DepartmentViewSet(viewsets.ModelViewSet):
desired_head_id = None
else:
try:
desired_head_id = int(raw_desired) if raw_desired is not None else None
desired_head_id = int(
raw_desired) if raw_desired is not None else None
except (TypeError, ValueError):
raise ValueError("head_id должен быть целым числом или null")
raise ValueError(
"head_id должен быть целым числом или null")
except ValueError as e:
return Response(
{"head_id": [str(e)]}, status=status.HTTP_400_BAD_REQUEST
@ -327,7 +299,7 @@ class DepartmentViewSet(viewsets.ModelViewSet):
result = self._perform_set_head(dept, head_id, request)
if isinstance(result, Response):
return result
return Response(self.get_serializer(result).data, status=status.HTTP_200_OK)
@action(detail=True, methods=["post"])
@ -407,7 +379,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
via_assignment = True
if role:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService
@ -415,7 +388,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
try:
group_service = GroupService()
user_service = UserService(group_service)
dept_service = DepartmentService(group_service, user_service)
dept_service = DepartmentService(
group_service, user_service)
dept_service.assign_role(employee, role, request.user)
except Exception as e:
return Response({"detail": str(e)}, status=400)
@ -423,10 +397,12 @@ class DepartmentViewSet(viewsets.ModelViewSet):
RoleAssignment.objects.update_or_create(
employee=employee,
role=role,
defaults={"is_active": True, "assigned_by": request.user},
defaults={"is_active": True,
"assigned_by": request.user},
)
else:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService
@ -438,7 +414,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
try:
group_service = GroupService()
user_service = UserService(group_service)
dept_service = DepartmentService(group_service, user_service)
dept_service = DepartmentService(
group_service, user_service)
for assignment in active_assignments:
dept_service.revoke_role(employee, assignment.role)
except Exception as e:
@ -571,7 +548,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
)
else:
link, created = EmployeeDepartment.objects.get_or_create(
employee_id=emp_id, department_id=dept.id, defaults={"is_active": True}
employee_id=emp_id, department_id=dept.id, defaults={
"is_active": True}
)
if not created and not link.is_active:
link.is_active = True
@ -653,7 +631,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
employee_id=user.id,
is_active=True,
)
user_qs = qs.filter(Q(head_id=user.id) | Exists(active_link_exists)).distinct()
user_qs = qs.filter(Q(head_id=user.id) | Exists(
active_link_exists)).distinct()
user_qs = user_qs.order_by("name", "id")
data = DepartmentBriefSerializer(user_qs, many=True).data
@ -664,9 +643,11 @@ class DepartmentViewSet(viewsets.ModelViewSet):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
head = None
head_id = ser.validated_data.get("head") or ser.validated_data.get("head_id")
head_id = ser.validated_data.get(
"head") or ser.validated_data.get("head_id")
if head_id:
employee_model = Department._meta.get_field("head").remote_field.model
employee_model = Department._meta.get_field(
"head").remote_field.model
head = get_object_or_404(employee_model, id=head_id)
ldap_enabled = _is_ldap_enabled()
@ -681,7 +662,8 @@ class DepartmentViewSet(viewsets.ModelViewSet):
try:
dept = svc.create_department(dto)
return Response(
self.get_serializer(dept).data, status=status.HTTP_201_CREATED
self.get_serializer(
dept).data, status=status.HTTP_201_CREATED
)
except DirectoryLdapError as e:
return Response({"detail": str(e)}, status=502)

View File

@ -9,32 +9,16 @@ from common.emails import send_templated_mail
from django.conf import settings
from django.core.files.base import ContentFile
from django.db import transaction
from django.db.models import (
Exists,
OuterRef,
Prefetch,
Q,
Subquery,
)
from django.db.models import Exists, OuterRef, Prefetch, Q, Subquery
from django.shortcuts import get_object_or_404
from django.utils.crypto import get_random_string
from employees.constants import ACTION_DISMISSED
from employees.ldap.directory_service import DirectoryService, DirectoryUserDTO
from employees.ldap.errors import (
DirectoryDbError,
DirectoryLdapError,
DirectoryServiceError,
)
from employees.ldap.errors import (DirectoryDbError, DirectoryLdapError,
DirectoryServiceError)
from employees.ldap.infrastructure.connections import _conn
from employees.models import (
Department,
EmployeeAction,
EmployeeDepartment,
LdapSyncState,
Position,
RoleAssignment,
Skill,
)
from employees.models import (Department, EmployeeAction, EmployeeDepartment,
LdapSyncState, Position, RoleAssignment, Skill)
from employees.utils import _to_bool
from rest_framework import filters, status, viewsets
from rest_framework.decorators import action
@ -43,11 +27,8 @@ from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from ...permissions import AdminOrActionOrModelPerms, IsSelfOrStaff
from ..serializers import (
EmployeeListSerializer,
EmployeeSerializer,
SkillSerializer,
)
from ..serializers import (EmployeeListSerializer, EmployeeSerializer,
SkillSerializer)
from ._helpers import Employee, _is_ldap_enabled
logger = logging.getLogger(__name__)
@ -69,7 +50,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
serializer_class = EmployeeSerializer
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ["last_name", "first_name", "patronymic", "email", "phone_number"]
search_fields = ["last_name", "first_name",
"patronymic", "email", "phone_number"]
ordering_fields = ["last_name", "first_name", "created_at", "id"]
ordering = ["last_name", "first_name"]
required_perms_by_action = {
@ -80,13 +62,14 @@ class EmployeeViewSet(viewsets.ModelViewSet):
def _perform_user_update(self, instance: Employee, request_data, is_partial=True):
"""Общая логика обновления пользователя для me PATCH и partial_update.
Возвращает Response при ошибке или dict с 'data' и 'instance' при успехе.
"""
old_email = instance.email
# Удаляем пустое поле avatar
data = request_data.copy() if hasattr(request_data, "copy") else dict(request_data)
data = request_data.copy() if hasattr(
request_data, "copy") else dict(request_data)
if hasattr(data, "_mutable") and not data._mutable:
data._mutable = True
avatar_raw = data.get("avatar")
@ -111,13 +94,15 @@ class EmployeeViewSet(viewsets.ModelViewSet):
"phone_number",
"is_active",
}
ldap_changes = {k: vd.pop(k) for k in list(vd.keys()) if k in ldap_keys}
ldap_changes = {k: vd.pop(k)
for k in list(vd.keys()) if k in ldap_keys}
svc_changes = dict(ldap_changes)
pos_key_present = ("position" in data) or ("position_id" in data)
if pos_key_present:
pos_raw = (
data.get("position") if "position" in data else data.get("position_id")
data.get("position") if "position" in data else data.get(
"position_id")
)
svc_changes["position"] = pos_raw
vd.pop("position", None)
@ -160,7 +145,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
) as e:
return Response(
{"detail": str(e)},
status=(502 if isinstance(e, DirectoryLdapError) else 500),
status=(502 if isinstance(
e, DirectoryLdapError) else 500),
)
else:
# Non-LDAP mode
@ -225,14 +211,16 @@ class EmployeeViewSet(viewsets.ModelViewSet):
if email_changed:
instance.email_verified = False
instance.email_activation_code = get_random_string(6, "0123456789")
instance.save(update_fields=["email_verified", "email_activation_code"])
instance.save(
update_fields=["email_verified", "email_activation_code"])
try:
send_templated_mail(
subject="Подтверждение нового email",
to=[instance.email],
template_base="emails/registration_verify_code",
context={"code": instance.email_activation_code, "user": instance},
context={"code": instance.email_activation_code,
"user": instance},
)
except Exception:
pass
@ -295,7 +283,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
member_ids = EmployeeDepartment.objects.filter(
department_id=dep_id
).values("employee_id")
head_ids = Department.objects.filter(id=dep_id).values("head_id")
head_ids = Department.objects.filter(
id=dep_id).values("head_id")
role_assignment_ids = RoleAssignment.objects.filter(
role__department_id=dep_id, is_active=True
).values("employee_id")
@ -315,7 +304,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
)
),
_is_dept_head=Exists(
Department.objects.filter(id=dep_id, head_id=OuterRef("pk"))
Department.objects.filter(
id=dep_id, head_id=OuterRef("pk"))
),
_has_role_assignment=Exists(
RoleAssignment.objects.filter(
@ -435,7 +425,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
"position",
):
if k in vd:
setattr(user, k + ("_id" if k == "position" else ""), vd[k])
setattr(user, k + ("_id" if k ==
"position" else ""), vd[k])
user.save()
if user.position_id:
try:
@ -475,7 +466,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
"gender",
):
if k in vd:
setattr(user, k + ("_id" if k == "position" else ""), vd[k])
setattr(user, k + ("_id" if k ==
"position" else ""), vd[k])
if avatar_bytes:
user.avatar.save(
f"avatar_{user.id}.jpg",
@ -528,7 +520,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
# PATCH — используем общий метод
try:
result = self._perform_user_update(instance, request.data, is_partial=True)
result = self._perform_user_update(
instance, request.data, is_partial=True)
if isinstance(result, Response):
return result
return Response(result["data"], status=200)
@ -584,7 +577,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
from employees.ldap.repositories.ldap_repository import LdapRepository
emp = self.get_object()
force_refresh = request.query_params.get('force_refresh', '').lower() == 'true'
force_refresh = request.query_params.get(
'force_refresh', '').lower() == 'true'
if not force_refresh and emp.username:
return Response(
@ -705,7 +699,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
departments = emp.departments_links.filter(is_active=True)
dept_names = ", ".join(
[
f"{d.department.name}" + (f" ({d.role.name})" if d.role else "")
f"{d.department.name}" +
(f" ({d.role.name})" if d.role else "")
for d in departments
]
)
@ -739,7 +734,8 @@ class EmployeeViewSet(viewsets.ModelViewSet):
emp.position.name if emp.position else "",
dept_names,
emp.birth_date.strftime("%d.%m.%Y") if emp.birth_date else "",
emp.created_at.strftime("%d.%m.%Y %H:%M") if emp.created_at else "",
emp.created_at.strftime(
"%d.%m.%Y %H:%M") if emp.created_at else "",
"Да" if emp.is_active else "Нет",
"Да" if emp.email_verified else "Нет",
skills,

View File

@ -126,14 +126,16 @@ class GroupViewSet(viewsets.ModelViewSet):
dns: list[str] = []
raw_dns = payload.get("member_dns") or []
if isinstance(raw_dns, list):
dns.extend([d.strip() for d in raw_dns if isinstance(d, str) and d.strip()])
dns.extend([d.strip()
for d in raw_dns if isinstance(d, str) and d.strip()])
ids = payload.get("member_ids") or []
if isinstance(ids, list) and ids:
if _is_ldap_enabled():
svc = DirectoryService()
dns.extend(
svc.employee_ids_to_dns([i for i in ids if isinstance(i, int)])
svc.employee_ids_to_dns(
[i for i in ids if isinstance(i, int)])
)
uniq, seen = [], set()
@ -146,7 +148,8 @@ class GroupViewSet(viewsets.ModelViewSet):
return []
if not uniq:
raise ValueError("Не переданы корректные member_dns или member_ids")
raise ValueError(
"Не переданы корректные member_dns или member_ids")
return uniq
def _dns_to_users(self, dns):

View File

@ -4,18 +4,9 @@ from __future__ import annotations
from django.shortcuts import get_object_or_404
from employees.ldap.directory_service import DirectoryService
from employees.ldap.errors import (
DirectoryDbError,
DirectoryLdapError,
)
from employees.models import (
Department,
DepartmentPermission,
DepartmentRole,
DeptPerm,
EmployeeDepartment,
RoleAssignment,
)
from employees.ldap.errors import DirectoryDbError, DirectoryLdapError
from employees.models import (Department, DepartmentPermission, DepartmentRole,
DeptPerm, EmployeeDepartment, RoleAssignment)
from employees.utils import _ensure_department_permissions
from rest_framework import status, viewsets
from rest_framework.decorators import action
@ -98,7 +89,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
ldap_enabled = _is_ldap_enabled()
if ldap_enabled:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService
@ -121,7 +113,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
scoped_permissions=scoped_permissions,
)
return Response(
self.get_serializer(role).data, status=status.HTTP_201_CREATED
self.get_serializer(
role).data, status=status.HTTP_201_CREATED
)
except DirectoryLdapError as e:
return Response(
@ -156,7 +149,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
ldap_enabled = _is_ldap_enabled()
if ldap_enabled:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService
@ -201,7 +195,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
ldap_enabled = _is_ldap_enabled()
if ldap_enabled:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService
@ -317,7 +312,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
if ldap_enabled:
try:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService
@ -325,7 +321,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
user_service = UserService(group_service)
dept_service = DepartmentService(group_service, user_service)
assignment = dept_service.assign_role(employee, role, assigned_by)
assignment = dept_service.assign_role(
employee, role, assigned_by)
return Response(
{
@ -387,7 +384,8 @@ class DepartmentRoleViewSet(viewsets.ModelViewSet):
if ldap_enabled:
try:
from employees.ldap.services.department_service import DepartmentService
from employees.ldap.services.department_service import \
DepartmentService
from employees.ldap.services.group_service import GroupService
from employees.ldap.services.user_service import UserService

View File

@ -3,6 +3,7 @@
from __future__ import annotations
from django.db import transaction
from employees.models import Skill
from rest_framework import filters, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
@ -12,8 +13,6 @@ from ...permissions import AdminOrActionOrModelPerms
from ..serializers import SkillSerializer
from ._helpers import Employee
from employees.models import Skill
class SkillViewSet(viewsets.ModelViewSet):
"""
@ -67,7 +66,8 @@ class SkillViewSet(viewsets.ModelViewSet):
cleaned.append(s)
existing = set(
Skill.objects.filter(name__in=cleaned).values_list("name", flat=True)
Skill.objects.filter(name__in=cleaned).values_list(
"name", flat=True)
)
to_create = [Skill(name=n) for n in cleaned if n not in existing]
Skill.objects.bulk_create(to_create, ignore_conflicts=True)