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
This commit is contained in:
parent
8efcabf530
commit
eaedea1403
@ -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",
|
||||
]
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -1 +0,0 @@
|
||||
default_app_config = 'hikcentral.apps.HikcentralConfig'
|
||||
@ -1,3 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@ -1,10 +0,0 @@
|
||||
# hikcentral/apps.py
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class HikcentralConfig(AppConfig):
|
||||
name = 'hikcentral'
|
||||
|
||||
def ready(self):
|
||||
import hikcentral.signals
|
||||
@ -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,
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -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}"
|
||||
@ -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()
|
||||
@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@ -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
|
||||
@ -1,3 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
Loading…
x
Reference in New Issue
Block a user