- Add birth_date, created_at/updated_at to Employee; remove username field - Introduce EmployeeAction for tracking HR events and is_actually_active/status properties - Create BotSubscriber model (OneToOne relation) for TG/WA binding - Implement Aiogram-based Telegram bot: • request contact to bind by phone or @username • department selection keyboard from DEPARTMENTS dict • async ORM via sync_to_async, custom filters for bound & active employees - Update profile view & template: • show “Bind Telegram/WhatsApp” button only when not already bound • preview avatar on upload - Remove registration tokens in favor of contact-based auth - Clean up templates, forms and add avatar validation mixin
51 lines
1.6 KiB
Python
51 lines
1.6 KiB
Python
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
|