From eaedea14031a324f060eda7b9b675c21dbd987a0 Mon Sep 17 00:00:00 2001 From: igor_nadein Date: Mon, 16 Feb 2026 16:21:45 +0300 Subject: [PATCH] refactor(employees): remove permissions.py shim, fix relative imports - Replaced ..permissions with ...permissions in all 7 view modules - Deleted backend/api/v1/employees/permissions.py (duplicate re-export) - Views now import directly from api.v1.permissions (3 dots up) manage.py check: System check identified no issues --- backend/api/v1/employees/permissions.py | 20 ----- backend/api/v1/employees/views/actions.py | 2 +- backend/api/v1/employees/views/departments.py | 2 +- backend/api/v1/employees/views/employees.py | 2 +- backend/api/v1/employees/views/groups.py | 2 +- backend/api/v1/employees/views/positions.py | 2 +- backend/api/v1/employees/views/roles.py | 2 +- backend/api/v1/employees/views/skills.py | 2 +- backend/eusrr_backend/settings.py | 12 +-- backend/hikcentral/__init__.py | 1 - backend/hikcentral/admin.py | 3 - backend/hikcentral/apps.py | 10 --- backend/hikcentral/migrations/0001_initial.py | 65 ---------------- backend/hikcentral/migrations/__init__.py | 0 backend/hikcentral/models.py | 68 ---------------- backend/hikcentral/signals.py | 77 ------------------- backend/hikcentral/tests.py | 3 - backend/hikcentral/utils.py | 50 ------------ backend/hikcentral/views.py | 3 - 19 files changed, 9 insertions(+), 317 deletions(-) delete mode 100644 backend/api/v1/employees/permissions.py delete mode 100644 backend/hikcentral/__init__.py delete mode 100644 backend/hikcentral/admin.py delete mode 100644 backend/hikcentral/apps.py delete mode 100644 backend/hikcentral/migrations/0001_initial.py delete mode 100644 backend/hikcentral/migrations/__init__.py delete mode 100644 backend/hikcentral/models.py delete mode 100644 backend/hikcentral/signals.py delete mode 100644 backend/hikcentral/tests.py delete mode 100644 backend/hikcentral/utils.py delete mode 100644 backend/hikcentral/views.py diff --git a/backend/api/v1/employees/permissions.py b/backend/api/v1/employees/permissions.py deleted file mode 100644 index cb89508d..00000000 --- a/backend/api/v1/employees/permissions.py +++ /dev/null @@ -1,20 +0,0 @@ -# flake8: noqa: F401 -"""Реэкспорт permissions из api.v1.permissions для обратной совместимости. - -Модуль views/ стал пакетом, и относительный импорт ``..permissions`` -из его подмодулей резолвится сюда (api.v1.employees.permissions). -""" - -from api.v1.permissions import ( - AdminOrActionOrModelPerms, - AdminOrDeptAllowed, - IsSelfOrStaff, - has_dept_perm, -) - -__all__ = [ - "AdminOrActionOrModelPerms", - "AdminOrDeptAllowed", - "IsSelfOrStaff", - "has_dept_perm", -] diff --git a/backend/api/v1/employees/views/actions.py b/backend/api/v1/employees/views/actions.py index 84af3d8d..3ecc825e 100644 --- a/backend/api/v1/employees/views/actions.py +++ b/backend/api/v1/employees/views/actions.py @@ -23,7 +23,7 @@ from rest_framework import filters, viewsets from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import AdminOrActionOrModelPerms +from ...permissions import AdminOrActionOrModelPerms from ..serializers import EmployeeActionSerializer from ._helpers import HistoryActionMixin, _is_ldap_enabled diff --git a/backend/api/v1/employees/views/departments.py b/backend/api/v1/employees/views/departments.py index 498aabfd..acd01287 100644 --- a/backend/api/v1/employees/views/departments.py +++ b/backend/api/v1/employees/views/departments.py @@ -49,7 +49,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import ( +from ...permissions import ( AdminOrActionOrModelPerms, AdminOrDeptAllowed, has_dept_perm, diff --git a/backend/api/v1/employees/views/employees.py b/backend/api/v1/employees/views/employees.py index fc06a3c5..74b8f4c0 100644 --- a/backend/api/v1/employees/views/employees.py +++ b/backend/api/v1/employees/views/employees.py @@ -42,7 +42,7 @@ from rest_framework.exceptions import ValidationError from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import AdminOrActionOrModelPerms, IsSelfOrStaff +from ...permissions import AdminOrActionOrModelPerms, IsSelfOrStaff from ..serializers import ( EmployeeListSerializer, EmployeeSerializer, diff --git a/backend/api/v1/employees/views/groups.py b/backend/api/v1/employees/views/groups.py index dca3165b..7313fd15 100644 --- a/backend/api/v1/employees/views/groups.py +++ b/backend/api/v1/employees/views/groups.py @@ -16,7 +16,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import AdminOrActionOrModelPerms +from ...permissions import AdminOrActionOrModelPerms from ..serializers import GroupSerializer from ._helpers import Employee, _is_ldap_enabled diff --git a/backend/api/v1/employees/views/positions.py b/backend/api/v1/employees/views/positions.py index 0cdd4c90..63d81ab0 100644 --- a/backend/api/v1/employees/views/positions.py +++ b/backend/api/v1/employees/views/positions.py @@ -10,7 +10,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import AdminOrActionOrModelPerms +from ...permissions import AdminOrActionOrModelPerms from ..serializers import PositionSerializer from ._helpers import HistoryActionMixin, _is_ldap_enabled, _ldap_try diff --git a/backend/api/v1/employees/views/roles.py b/backend/api/v1/employees/views/roles.py index 368c0358..725b7e54 100644 --- a/backend/api/v1/employees/views/roles.py +++ b/backend/api/v1/employees/views/roles.py @@ -22,7 +22,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import AdminOrDeptAllowed +from ...permissions import AdminOrDeptAllowed from ..serializers import DepartmentRoleSerializer from ._helpers import Employee, _is_ldap_enabled diff --git a/backend/api/v1/employees/views/skills.py b/backend/api/v1/employees/views/skills.py index 7b599a6f..d41b62be 100644 --- a/backend/api/v1/employees/views/skills.py +++ b/backend/api/v1/employees/views/skills.py @@ -8,7 +8,7 @@ from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response -from ..permissions import AdminOrActionOrModelPerms +from ...permissions import AdminOrActionOrModelPerms from ..serializers import SkillSerializer from ._helpers import Employee diff --git a/backend/eusrr_backend/settings.py b/backend/eusrr_backend/settings.py index ce189d60..6182e10e 100644 --- a/backend/eusrr_backend/settings.py +++ b/backend/eusrr_backend/settings.py @@ -41,7 +41,7 @@ INSTALLED_APPS = [ # Основные приложения "employees.apps.EmployeesConfig", "api.apps.ApiConfig", - "hikcentral.apps.HikcentralConfig", + "calendar_app.apps.CalendarAppConfig", "documents.apps.DocumentsConfig", "requests_app.apps.RequestsAppConfig", @@ -100,15 +100,7 @@ USE_SQLITE = os.getenv("USE_SQLITE", "false").lower() == "true" DATABASES = { "default": {}, - "hikcentral": { - "ENGINE": "django.db.backends.postgresql", - "NAME": "cms", - "USER": "postgres", - "PASSWORD": None, - "HOST": "127.0.0.1", - "PORT": "5432", - "OPTIONS": {"options": "-c search_path=platform"}, - }, + } if USE_SQLITE: diff --git a/backend/hikcentral/__init__.py b/backend/hikcentral/__init__.py deleted file mode 100644 index 5e0902da..00000000 --- a/backend/hikcentral/__init__.py +++ /dev/null @@ -1 +0,0 @@ -default_app_config = 'hikcentral.apps.HikcentralConfig' diff --git a/backend/hikcentral/admin.py b/backend/hikcentral/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/backend/hikcentral/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/backend/hikcentral/apps.py b/backend/hikcentral/apps.py deleted file mode 100644 index 5f724df6..00000000 --- a/backend/hikcentral/apps.py +++ /dev/null @@ -1,10 +0,0 @@ -# hikcentral/apps.py - -from django.apps import AppConfig - - -class HikcentralConfig(AppConfig): - name = 'hikcentral' - - def ready(self): - import hikcentral.signals diff --git a/backend/hikcentral/migrations/0001_initial.py b/backend/hikcentral/migrations/0001_initial.py deleted file mode 100644 index 53a47632..00000000 --- a/backend/hikcentral/migrations/0001_initial.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by Django 5.2.4 on 2025-07-24 09:24 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='HikPerson', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('person_group_id', models.IntegerField(blank=True, null=True)), - ('person_type', models.IntegerField(blank=True, null=True)), - ('person_code', models.CharField(max_length=16, unique=True)), - ('given_name', models.CharField(blank=True, max_length=255, null=True)), - ('family_name', models.CharField(blank=True, max_length=255, null=True)), - ('full_name', models.CharField(blank=True, max_length=255, null=True)), - ('gender', models.IntegerField(blank=True, null=True)), - ('email', models.EmailField(blank=True, max_length=254, null=True)), - ('phone_number', models.CharField(blank=True, max_length=32, null=True)), - ('photo_url', models.CharField(blank=True, max_length=512, null=True)), - ('photo_index', models.IntegerField(blank=True, null=True)), - ('small_photo_url', models.CharField(blank=True, max_length=512, null=True)), - ('start_valid_date', models.DateTimeField(blank=True, null=True)), - ('end_valid_date', models.DateTimeField(blank=True, null=True)), - ('remark', models.TextField(blank=True, null=True)), - ('update_time', models.DateTimeField(blank=True, null=True)), - ('create_time', models.DateTimeField(blank=True, null=True)), - ('is_deleted', models.IntegerField(default=0)), - ('object_guid', models.CharField(blank=True, max_length=64, null=True)), - ('person_from', models.IntegerField(blank=True, null=True)), - ('rdn', models.CharField(blank=True, max_length=255, null=True)), - ('dn', models.CharField(blank=True, max_length=255, null=True)), - ('usn_changed', models.BigIntegerField(blank=True, null=True)), - ('start_time_differ', models.IntegerField(blank=True, null=True)), - ('end_time_differ', models.IntegerField(blank=True, null=True)), - ], - options={ - 'db_table': 'person', - 'managed': False, - }, - ), - migrations.CreateModel( - name='HikPersonHeadPic', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('standard_head_portrait', models.TextField(blank=True, null=True)), - ('thumbnail_head_portrait', models.TextField(blank=True, null=True)), - ('deepmode_head_portrait', models.TextField(blank=True, null=True)), - ('identi_photo', models.TextField(blank=True, null=True)), - ('create_time', models.DateTimeField(blank=True, null=True)), - ('update_time', models.DateTimeField(blank=True, null=True)), - ], - options={ - 'db_table': 'person_head_pic', - 'managed': False, - }, - ), - ] diff --git a/backend/hikcentral/migrations/__init__.py b/backend/hikcentral/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/backend/hikcentral/models.py b/backend/hikcentral/models.py deleted file mode 100644 index f870a399..00000000 --- a/backend/hikcentral/models.py +++ /dev/null @@ -1,68 +0,0 @@ -# hikcentral/models.py - -from django.db import models - - -class HikPerson(models.Model): - id = models.AutoField(primary_key=True) - person_group_id = models.IntegerField(blank=True, null=True) - person_type = models.IntegerField(blank=True, null=True) - # важно! Уникальный ID от 1 до 16 символов (цифры/буквы) - person_code = models.CharField(max_length=16, unique=True) - given_name = models.CharField(max_length=255, blank=True, null=True) - family_name = models.CharField(max_length=255, blank=True, null=True) - full_name = models.CharField(max_length=255, blank=True, null=True) - gender = models.IntegerField(blank=True, null=True) - email = models.EmailField(blank=True, null=True) - phone_number = models.CharField(max_length=32, blank=True, null=True) - photo_url = models.CharField( - max_length=512, blank=True, null=True, default="") - photo_index = models.IntegerField(blank=True, null=True) - small_photo_url = models.CharField(max_length=512, blank=True, null=True) - start_valid_date = models.DateTimeField(blank=True, null=True) - end_valid_date = models.DateTimeField(blank=True, null=True) - remark = models.TextField(blank=True, null=True) - update_time = models.DateTimeField(blank=True, null=True) - create_time = models.DateTimeField(blank=True, null=True) - is_deleted = models.IntegerField(default=0) - object_guid = models.CharField(max_length=64, blank=True, null=True) - person_from = models.IntegerField(blank=True, null=True) - rdn = models.CharField(max_length=255, blank=True, null=True) - dn = models.CharField(max_length=255, blank=True, null=True) - usn_changed = models.BigIntegerField(blank=True, null=True) - start_time_differ = models.IntegerField(blank=True, null=True) - end_time_differ = models.IntegerField(blank=True, null=True) - - class Meta: - db_table = 'person' - app_label = 'hikcentral' - managed = False # очень важно! — Django не управляет этой таблицей - - def __str__(self): - return self.full_name or self.person_code - - -class HikPersonHeadPic(models.Model): - id = models.AutoField(primary_key=True) - person = models.ForeignKey( - HikPerson, - db_column='person_id', - on_delete=models.CASCADE, - related_name='head_pics' - ) - standard_head_portrait = models.TextField( - blank=True, null=True) # основное фото (base64-строка) - thumbnail_head_portrait = models.TextField( - blank=True, null=True) # миниатюра (base64) - deepmode_head_portrait = models.TextField(blank=True, null=True) - identi_photo = models.TextField(blank=True, null=True) - create_time = models.DateTimeField(blank=True, null=True) - update_time = models.DateTimeField(blank=True, null=True) - - class Meta: - db_table = 'person_head_pic' - app_label = 'hikcentral' - managed = False - - def __str__(self): - return f"Photo for person_id={self.person_id}" diff --git a/backend/hikcentral/signals.py b/backend/hikcentral/signals.py deleted file mode 100644 index b9bd3f7e..00000000 --- a/backend/hikcentral/signals.py +++ /dev/null @@ -1,77 +0,0 @@ -# # backend/hikcentral/signals.py - -# from django.db.models.signals import post_save, post_delete -# from django.dispatch import receiver -# from users.models import Employee -# from .models import HikPerson, HikPersonHeadPic -# from django.utils import timezone -# from .utils import gen_person_code, compress_image_to_base64 - - -# @receiver(post_save, sender=Employee) -# def sync_employee_to_hikcentral(sender, instance, created, **kwargs): -# db = 'hikcentral' - -# # Определяем person_code (уникальный) -# person_code = gen_person_code(instance) - -# # Проставим даты -# now = timezone.now() -# start_valid = now -# end_valid = now.replace(year=now.year+10) - -# # 1. Создаём/обновляем запись в person -# person_values = dict( -# person_group_id=1, -# person_type=0, -# person_code=person_code, -# given_name=instance.first_name, -# family_name=instance.last_name, -# full_name=f"{instance.first_name} {instance.last_name}", -# gender=0, # по аналогии: 0 - не указан, 1 - муж, 2 - жен -# email=instance.email, -# phone_number=str( -# instance.phone_number) if instance.phone_number else "", -# photo_url=instance.avatar.url if instance.avatar else "", -# photo_index=0, -# small_photo_url=instance.avatar.url if instance.avatar else "", -# start_valid_date=start_valid, -# end_valid_date=end_valid, -# remark='', -# update_time=now, -# create_time=now, -# is_deleted=0, -# person_from=0, -# usn_changed=0, -# start_time_differ=10800, -# end_time_differ=10800, -# ) - -# # Сохраняем сотрудника в HikCentral -# person = HikPerson.objects.using(db).create(**person_values) - -# # 2. Картинка (photo/avatar) -# if instance.avatar: -# img_b64 = compress_image_to_base64(instance.avatar) -# HikPersonHeadPic.objects.using(db).create( -# person_id=person.id, -# standard_head_portrait=img_b64, -# thumbnail_head_portrait='', -# deepmode_head_portrait='', -# identi_photo='', -# create_time=now, -# update_time=now, -# ) - - -# @receiver(post_delete, sender=Employee) -# def delete_employee_from_hikcentral(sender, instance, **kwargs): -# db = 'hikcentral' -# # Найдём всех по имени и почте — или храни person_code в Employee -# HikPerson.objects.using(db).filter( -# email=instance.email, -# full_name=f"{instance.first_name} {instance.last_name}", -# ).delete() -# # Не забудь удалить фото -# # person_ids = list(...) -# # HikPersonHeadPic.objects.using(db).filter(person_id__in=person_ids).delete() diff --git a/backend/hikcentral/tests.py b/backend/hikcentral/tests.py deleted file mode 100644 index 7ce503c2..00000000 --- a/backend/hikcentral/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/backend/hikcentral/utils.py b/backend/hikcentral/utils.py deleted file mode 100644 index f2186f6b..00000000 --- a/backend/hikcentral/utils.py +++ /dev/null @@ -1,50 +0,0 @@ -import base64 -from PIL import Image -from io import BytesIO -import random -import string - - -def gen_person_code(instance): - import re - base = str(instance.phone_number or instance.email or instance.pk) - code = re.sub(r'\W+', '', base)[:16] - - # Проверяем уникальность, если не уникален — добавляем символы в конец - from .models import HikPerson - existing = ( - HikPerson.objects.using('hikcentral') - .filter(person_code=code) - .exists() - ) - orig_code = code - while existing: - # Укорачиваем до 12 символов и дописываем случайные 4 символа - code = ( - orig_code[:12] + ''.join(random.choices(string.ascii_letters + string.digits, k=4)))[:16] - existing = ( - HikPerson.objects.using('hikcentral') - .filter(person_code=code) - .exists() - ) - return code - - -def compress_image_to_base64(image_field, target_size_kb=200): - """Сжимает изображение до размера (примерно) target_size_kb и возвращает base64-строку.""" - if not image_field: - return '' - image = Image.open(image_field) - output = BytesIO() - quality = 90 - # Сжимать до ~200КБ - while True: - output.seek(0) - image.save(output, format='JPEG', quality=quality) - size_kb = output.tell() / 1024 - if size_kb <= target_size_kb or quality <= 20: - break - quality -= 10 - output.seek(0) - img_b64 = base64.b64encode(output.read()).decode('utf-8') - return img_b64 diff --git a/backend/hikcentral/views.py b/backend/hikcentral/views.py deleted file mode 100644 index 91ea44a2..00000000 --- a/backend/hikcentral/views.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.shortcuts import render - -# Create your views here.