Files
ACORE/apps/nextcloud_connector/signals.py
T
lokses 19bc2874aa Nextcloud connector: скелет провижининга Group Folders (Фаза 2)
- ConnectorConfig: тип 'nextcloud' (host/username/token, шифруется)
- NextcloudService: OCS-клиент Group Folders (create/ACL/quota, идемпотентный ensure_folder)
- NextcloudSyncService: отделы → 03_Отделы/* ↔ nc-dept-<код>; аптеки → 02_Аптеки/* ↔ nc-svc
- Сигналы Directory/Pharmacy с гейтом на включённый коннектор (по умолч. no-op)
- Celery-задачи + команда nextcloud_sync (dry-run по умолчанию, --apply)
- NextcloudSyncLog + admin; тесты (пути, гейт, идемпотентность ensure_folder)

Членство юзеров идёт через AD/LDAP, коннектор ведёт только папки+ACL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 11:09:49 +03:00

51 lines
2.0 KiB
Python

"""Сигналы провижининга Group Folders.
Гейт безопасности: если коннектор Nextcloud не настроен или отключён
(ConnectorConfig.get_for('nextcloud') is None) — сигналы полностью no-op, ни
одного обращения к внешнему API. Так прод не дёргается, пока коннектор явно
не включат. Сама задача ставится в Celery, недоступный брокер не роняет save.
"""
import logging
from django.db.models.signals import post_save
from django.dispatch import receiver
from core.models import Directory, ConnectorConfig
from apps.locations.models import Pharmacy
from apps.nextcloud_connector.tasks import (
sync_department_folder_task, sync_pharmacy_folder_task,
)
logger = logging.getLogger(__name__)
def _connector_enabled() -> bool:
return ConnectorConfig.get_for('nextcloud') is not None
def _queue(task, obj_id, label: str) -> None:
try:
task.delay(obj_id)
logger.info(f'Nextcloud: поставлена задача {label} (id={obj_id})')
except Exception as e:
logger.error(f'Nextcloud: не удалось поставить задачу {label} (id={obj_id}): {e}')
@receiver(post_save, sender=Directory)
def provision_department_folder(sender, instance, created, **kwargs):
if not _connector_enabled():
return
# Group Folder заводим только под отделы, не под прочие справочники.
if getattr(instance.directory_type, 'code', None) != 'department':
return
if not instance.is_active:
return
_queue(sync_department_folder_task, instance.pk, f'отдел {instance.code}')
@receiver(post_save, sender=Pharmacy)
def provision_pharmacy_folder(sender, instance, created, **kwargs):
if not _connector_enabled():
return
_queue(sync_pharmacy_folder_task, instance.pk, f'аптека {instance.pharmacy_number}')