19bc2874aa
- 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>
51 lines
2.0 KiB
Python
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}')
|