Files
ACORE/apps/tasks/attachments.py
T
lokses 03019898b0 reports: КЕП-подпись PDF отчётов; задачи: загрузка вложений.
Добавлена офлайн/EndUser-подпись «ознакомлен и принял в работу» для документов отчётов и файловые вложения к задачам через Nextcloud.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-06 21:13:28 +03:00

49 lines
1.8 KiB
Python

"""Вложения задач: путь в Nextcloud и уникальные имена файлов."""
from apps.nextcloud_connector.access import safe_filename
from apps.tasks.models import TaskAttachment
TASKS_DAV_ROOT = '07_Задачи'
def attachment_relpath(attachment: TaskAttachment) -> str:
return f'{TASKS_DAV_ROOT}/{attachment.task_id}/{attachment.stored_name}'
def unique_stored_name(task_id: int, original_name: str) -> str | None:
"""Исходное имя; при коллизии в рамках задачи — суффикс -2, -3…"""
name = safe_filename(original_name)
if not name:
return None
if '.' in name:
stem, ext = name.rsplit('.', 1)
candidate = safe_filename(f'{stem}.{ext}') or name
if not TaskAttachment.objects.filter(task_id=task_id, stored_name=candidate).exists():
return candidate
n = 2
while True:
cand = safe_filename(f'{stem}-{n}.{ext}') or f'file-{n}.{ext}'
if not TaskAttachment.objects.filter(task_id=task_id, stored_name=cand).exists():
return cand
n += 1
if not TaskAttachment.objects.filter(task_id=task_id, stored_name=name).exists():
return name
n = 2
while True:
cand = safe_filename(f'{name}-{n}') or f'file-{n}'
if not TaskAttachment.objects.filter(task_id=task_id, stored_name=cand).exists():
return cand
n += 1
def can_delete_attachment(user, attachment: TaskAttachment) -> bool:
"""Удалить может загрузивший, автор задачи или staff."""
if not user or not user.is_authenticated:
return False
if user.is_staff:
return True
if attachment.uploaded_by_id == user.pk:
return True
if attachment.task.creator_id == user.pk:
return True
return False