111 lines
4.3 KiB
Python
111 lines
4.3 KiB
Python
# users/signals.py
|
||
import os
|
||
from django.core.files.base import ContentFile
|
||
from django.db.models.signals import post_save, pre_save
|
||
from django.dispatch import receiver
|
||
from django.utils import timezone
|
||
from .constants import ACTION_HIRED
|
||
|
||
from .models import Employee, EmployeeAction
|
||
from bots.models import BotSubscriber
|
||
|
||
|
||
if False: # pragma: no cover - временно отключаем сигнал для тестирования
|
||
@receiver(pre_save, sender=Employee)
|
||
def compress_and_cleanup_avatar(sender, instance: Employee, **kwargs):
|
||
"""Сжимает новый аватар и удаляет старый файл при замене."""
|
||
# Импортируем здесь, чтобы избежать циклических импортов
|
||
from common.image_utils import compress_avatar
|
||
|
||
avatar_field = instance.avatar
|
||
avatar_name = getattr(avatar_field, "name", "")
|
||
if avatar_field and avatar_name:
|
||
storage = avatar_field.storage
|
||
if storage.exists(avatar_name):
|
||
try:
|
||
avatar_field.open("rb")
|
||
avatar_field.seek(0)
|
||
original_data = avatar_field.read()
|
||
|
||
compressed_data = compress_avatar(original_data)
|
||
|
||
if len(compressed_data) < len(original_data):
|
||
filename = avatar_name.split("/")[-1]
|
||
if not filename.lower().endswith(".jpg"):
|
||
filename = filename.rsplit(".", 1)[0] + ".jpg"
|
||
|
||
avatar_field.save(
|
||
filename,
|
||
ContentFile(compressed_data),
|
||
save=False,
|
||
)
|
||
except FileNotFoundError:
|
||
print(
|
||
"Avatar file missing during compression: "
|
||
f"{avatar_name}"
|
||
)
|
||
except Exception as e:
|
||
# Логируем ошибку, но не прерываем сохранение
|
||
print(f"Error compressing avatar: {e}")
|
||
|
||
# Удаляем старый файл если он был заменен
|
||
if instance.pk is None:
|
||
return
|
||
|
||
try:
|
||
old = sender.objects.get(pk=instance.pk)
|
||
except sender.DoesNotExist:
|
||
return
|
||
|
||
# Если аватар изменился или удален
|
||
if old.avatar and old.avatar != instance.avatar:
|
||
# Удаляем старый файл с диска
|
||
if os.path.isfile(old.avatar.path):
|
||
try:
|
||
os.remove(old.avatar.path)
|
||
except Exception as e:
|
||
print(f"Error deleting old avatar: {e}")
|
||
|
||
|
||
@receiver(pre_save, sender=Employee)
|
||
def unbind_bot_subscriber_on_contact_change(
|
||
sender, instance: Employee, **kwargs
|
||
):
|
||
# Игнорируем новых пользователей
|
||
if instance.pk is None:
|
||
return
|
||
|
||
old = sender.objects.get(pk=instance.pk)
|
||
try:
|
||
sub = old.bot_subscription
|
||
except BotSubscriber.DoesNotExist:
|
||
return
|
||
|
||
# Если очистили или изменили telegram в профиле — сбросим telegram_id
|
||
if old.telegram and old.telegram != (instance.telegram or "").strip():
|
||
sub.telegram_id = None
|
||
sub.save(update_fields=["telegram_id"])
|
||
|
||
# Аналогично для whatsapp
|
||
if old.whatsapp and old.whatsapp != instance.whatsapp:
|
||
sub.whatsapp_id = None
|
||
sub.save(update_fields=["whatsapp_id"])
|
||
|
||
if old.wechat and old.wechat != instance.wechat:
|
||
sub.wechat_id = None
|
||
sub.save(update_fields=["wechat_id"])
|
||
|
||
|
||
@receiver(post_save, sender=Employee)
|
||
def create_hired_action(sender, instance: Employee, created, **kwargs):
|
||
"""
|
||
При первом сохранении нового сотрудника создаём событие «Принят».
|
||
"""
|
||
if created:
|
||
EmployeeAction.objects.create(
|
||
employee=instance,
|
||
action=ACTION_HIRED,
|
||
date=instance.created_at or timezone.now(),
|
||
comment="Автоматически: принят при регистрации",
|
||
)
|