Download apps/cases/models/log.py from jun2024/fc: direct link, hf CLI and curl.
- Browser
- Download file 6.34 kB
-
https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/cases/models/log.py
- Command line
-
hf download hf://spaces/jun2024/fc/apps/cases/models/log.py
-
curl -L -o log.py https://huggingface.co/spaces/jun2024/fc/resolve/main/apps/cases/models/log.py
6.34 kB
| """Module for log.""" | |
| from __future__ import annotations | |
| import logging | |
| from datetime import datetime | |
| from pathlib import Path | |
| from typing import TYPE_CHECKING, Any, ClassVar | |
| from django.core.files.uploadedfile import UploadedFile | |
| from django.db import models | |
| from django.utils.translation import gettext_lazy as _ | |
| from apps.cases.utils import CASE_LOG_ALLOWED_EXTENSIONS, CASE_LOG_MAX_FILE_SIZE | |
| from apps.core.filesystem.storage import KeepOriginalNameStorage | |
| _SENTINEL = object() | |
| from .case import Case | |
| if TYPE_CHECKING: | |
| from django.db.models.fields.related_descriptors import RelatedManager | |
| # 案件日志附件存储 | |
| case_log_storage = KeepOriginalNameStorage() | |
| logger = logging.getLogger(__name__) | |
| def validate_log_attachment(file: UploadedFile) -> None: | |
| """验证日志附件""" | |
| name = str(getattr(file, "name", "")) | |
| size: int = int(getattr(file, "size", 0) or 0) | |
| ext = Path(name).suffix.lower() | |
| if ext not in CASE_LOG_ALLOWED_EXTENSIONS: | |
| from django.core.exceptions import ValidationError | |
| raise ValidationError(_("不支持的文件类型")) | |
| if size and size > CASE_LOG_MAX_FILE_SIZE: | |
| from django.core.exceptions import ValidationError | |
| raise ValidationError(_("文件大小超过50MB限制")) | |
| class CaseLog(models.Model): | |
| id: int | |
| case = models.ForeignKey(Case, on_delete=models.CASCADE, related_name="logs", verbose_name=_("案件")) | |
| content = models.TextField(verbose_name=_("日志内容")) | |
| actor = models.ForeignKey( | |
| "organization.Lawyer", on_delete=models.PROTECT, related_name="case_logs", verbose_name=_("操作人") | |
| ) | |
| created_at = models.DateTimeField(auto_now_add=True, verbose_name=_("创建日期")) | |
| updated_at = models.DateTimeField(auto_now=True, verbose_name=_("修改日期")) | |
| if TYPE_CHECKING: | |
| attachments: RelatedManager[CaseLogAttachment] | |
| versions: RelatedManager[CaseLogVersion] | |
| class Meta: | |
| verbose_name = _("日志") | |
| verbose_name_plural = _("日志") | |
| indexes: ClassVar = [ | |
| models.Index(fields=["case", "-created_at"]), | |
| models.Index(fields=["actor"]), | |
| ] | |
| def __str__(self) -> str: | |
| return f"{self.case_id}-{self.actor_id}-{self.created_at}" | |
| def _exported_reminders(self) -> list[dict[str, Any]]: | |
| cached = getattr(self, "_cached_exported_reminders", _SENTINEL) | |
| if cached is not _SENTINEL: | |
| return cached | |
| if not getattr(self, "id", None): | |
| self._cached_exported_reminders = [] | |
| return [] | |
| reminders: list[dict[str, Any]] | |
| try: | |
| from apps.core.interfaces import ServiceLocator | |
| reminder_service = ServiceLocator.get_reminder_service() | |
| reminders = reminder_service.export_case_log_reminders_internal(case_log_id=int(self.id)) | |
| except Exception: | |
| logger.exception("case_log_export_reminders_failed", extra={"case_log_id": int(self.id)}) | |
| reminders = [] | |
| self._cached_exported_reminders = reminders | |
| return reminders | |
| def reminder_entries(self) -> list[dict[str, Any]]: | |
| return self._exported_reminders() | |
| def has_reminders(self) -> bool: | |
| return bool(self._exported_reminders()) | |
| def reminder_count(self) -> int: | |
| return len(self._exported_reminders()) | |
| def _latest_reminder(self) -> Any | None: | |
| """缓存最近的提醒记录,避免重复查询。""" | |
| cached = getattr(self, "_cached_latest_reminder", _SENTINEL) | |
| if cached is not _SENTINEL: | |
| return cached | |
| if not getattr(self, "id", None): | |
| self._cached_latest_reminder = None | |
| return None | |
| reminder: dict[str, Any] | None = None | |
| try: | |
| from apps.core.interfaces import ServiceLocator | |
| reminder_service = ServiceLocator.get_reminder_service() | |
| reminder = reminder_service.get_latest_case_log_reminder_internal(case_log_id=int(self.id)) | |
| except Exception: | |
| logger.exception("case_log_latest_reminder_failed", extra={"case_log_id": int(self.id)}) | |
| reminders = self._exported_reminders() | |
| reminder = reminders[-1] if reminders else None | |
| self._cached_latest_reminder = reminder | |
| return reminder | |
| def reminder_type(self) -> str | None: | |
| """获取最近的提醒类型。""" | |
| reminder = self._latest_reminder | |
| if reminder is None: | |
| return None | |
| if isinstance(reminder, dict): | |
| return str(reminder.get("reminder_type") or "") | |
| return str(getattr(reminder, "reminder_type", "")) | |
| def reminder_time(self) -> datetime | None: | |
| """获取最近的提醒时间。""" | |
| reminder = self._latest_reminder | |
| if reminder is None: | |
| return None | |
| due_at = reminder.get("due_at") if isinstance(reminder, dict) else getattr(reminder, "due_at", None) | |
| return due_at if isinstance(due_at, datetime) else None | |
| class CaseLogAttachment(models.Model): | |
| id: int | |
| log = models.ForeignKey(CaseLog, on_delete=models.CASCADE, related_name="attachments", verbose_name=_("日志")) | |
| file = models.FileField( | |
| upload_to="case_logs/", | |
| storage=case_log_storage, | |
| validators=[validate_log_attachment], | |
| verbose_name=_("相关文书"), | |
| ) | |
| uploaded_at = models.DateTimeField(auto_now_add=True, verbose_name=_("上传时间")) | |
| class Meta: | |
| verbose_name = _("日志附件") | |
| verbose_name_plural = _("日志附件") | |
| class CaseLogVersion(models.Model): | |
| id: int | |
| log = models.ForeignKey(CaseLog, on_delete=models.CASCADE, related_name="versions", verbose_name=_("日志")) | |
| content = models.TextField(verbose_name=_("历史内容")) | |
| version_at = models.DateTimeField(auto_now_add=True, verbose_name=_("版本时间")) | |
| actor = models.ForeignKey( | |
| "organization.Lawyer", on_delete=models.PROTECT, related_name="case_log_versions", verbose_name=_("操作者") | |
| ) | |
| class Meta: | |
| verbose_name = _("案件日志版本") | |
| verbose_name_plural = _("案件日志版本") | |
| def __str__(self) -> str: | |
| return f"{self.log_id}-{self.version_at}" | |