Kod źródłowy modułu poradnia.letters.models

import logging
from os.path import basename

from django.conf import settings
from django.contrib.admin.models import ADDITION, LogEntry
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.shortcuts import get_current_site
from django.db import models
from django.db.models import F, Func, IntegerField
from django.forms.models import model_to_dict
from django.urls import reverse
from django.utils.html import mark_safe
from django.utils.translation import gettext_lazy as _
from django_mailbox.models import Message
from model_utils import Choices
from model_utils.fields import MonitorField, StatusField

from poradnia.cases.models import Case
from poradnia.cases.utils import get_users_with_perm
from poradnia.records.models import AbstractRecord, AbstractRecordQuerySet
from poradnia.users.models import User
from poradnia.utils.constants import NAME_MAX_LENGTH
from poradnia.utils.mixins import FormattedDatetimeMixin, UserPrettyNameMixin

from .templatetags.format_text import format_text
from .utils import date_random_path

logger = logging.getLogger(__name__)


[dokumentacja] class LetterQuerySet( FormattedDatetimeMixin, UserPrettyNameMixin, AbstractRecordQuerySet ): def for_user(self, user): qs = super().for_user(user) if not user.is_staff: qs = qs.filter(status=Letter.STATUS.done) return qs def last_staff_send(self): return ( self.filter(status="done", created_by__is_staff=True) .order_by("-created_on", "-id") .all()[0] ) def last_received(self): return ( self.filter(created_by__is_staff=False) .order_by("-created_on", "-id") .all()[0] )
[dokumentacja] def last(self): return self.order_by("-created_on", "-id").all()[0]
def case(self, case): return self.filter(record__case=case) def with_month_year(self): return self.annotate( month=Func(F("created_on"), function="month", output_field=IntegerField()) ).annotate( year=Func(F("created_on"), function="year", output_field=IntegerField()) )
[dokumentacja] class Letter(AbstractRecord): STATUS = Choices(("staff", _("Staff")), ("done", _("Done"))) GENRE = Choices("mail", "comment", "app_message") genre = models.CharField(choices=GENRE, default=GENRE.comment, max_length=20) status = StatusField(db_index=True) status_changed = MonitorField(monitor="status") accept = MonitorField( monitor="status", when=["done"], verbose_name=_("Accepted on") ) name = models.CharField(max_length=NAME_MAX_LENGTH, verbose_name=_("Subject")) text = models.TextField(verbose_name=_("Text")) html = models.TextField(verbose_name=_("Mail formatted HTML"), blank=True) signature = models.TextField(verbose_name=_("Signature"), blank=True, null=True) created_by = models.ForeignKey( to=settings.AUTH_USER_MODEL, related_name="letter_created_by", verbose_name=_("Created by"), on_delete=models.CASCADE, ) created_by_is_staff = models.BooleanField( verbose_name="Created by staff member" ) # redundant to preserve status after member exit created_on = models.DateTimeField(auto_now_add=True, verbose_name=_("Created on")) modified_by = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_("Modified by"), null=True, on_delete=models.CASCADE, related_name="letter_modified_by", ) modified_on = models.DateTimeField( auto_now=True, null=True, blank=True, verbose_name=_("Modified on") ) message = models.ForeignKey( to=Message, null=True, blank=True, on_delete=models.CASCADE ) eml = models.FileField( _("Raw message contents"), null=True, upload_to="messages", help_text=_("Original full content of message"), ) objects = LetterQuerySet.as_manager() def __str__(self): return self.name def get_users(self, force_all=False): users_to_notify = self.get_users_with_perms() if self.status == self.STATUS.staff or force_all: users_to_notify = users_to_notify.filter(is_staff=True) return users_to_notify def get_absolute_url(self): case_url = self.record.case_get_absolute_url() return "{}#letter-{}".format(case_url, self.pk) def render_letter_link(self): url = self.get_absolute_url() label = self.name return mark_safe(f'<a href="{url}">{label}</a>') def render_admin_delete_link(self): url = reverse("admin:letters_letter_delete", args=(self.id,)) label = _("Delete letter") + f" {self.id}" return mark_safe(f'<a href="{url}"><i class="fa fa-trash"></i> {label}</a>') def is_done(self): return ( True if self.status == self.STATUS.done or self.genre == self.GENRE.comment else False ) def is_html(self): return bool(self.html) # TOD0 - fix; long lines are not wrapped properly def render_as_html(self): if self.is_html(): return self.html else: return "<pre>{text}</pre>".format(text=format_text(self.text)) def get_edit_url(self): return reverse("letters:edit", kwargs={"pk": self.pk}) def get_send_url(self): return reverse("letters:send", kwargs={"pk": self.pk}) def set_new_case(self): self.case = Case.objects.create( subject=self.name, created_by=self.created_by, client=self.client ) def send_notification(self, *args, **kwargs): senders = get_users_with_perm(self.case, "can_send_to_client") management = User.objects.filter(notify_unassigned_letter=True).all() user_qs = self.get_users_with_perms() if self.status is not Letter.STATUS.done: user_qs = User.objects.filter(is_staff=True).distinct() & user_qs if senders.count() == 0: user_qs = user_qs | management.distinct() kwargs["user_qs"] = user_qs return super().send_notification(*args, **kwargs) def save_attachments(self, files=[]): content_type = ContentType.objects.get_for_model(Attachment) for file in files: obj = Attachment.objects.create(attachment=file, letter=self) change_dict = model_to_dict(obj) LogEntry.objects.log_action( user_id=self.created_by.id, content_type_id=content_type.id, object_id=obj.id, object_repr=str(obj), action_flag=ADDITION, change_message=f"{change_dict}", ) class Meta: verbose_name = _("Letter") verbose_name_plural = _("Letters") ordering = ["-created_on"]
lrc_cup = "letter__record__case__caseuserobjectpermission"
[dokumentacja] class AttachmentQuerySet(models.QuerySet): def for_user(self, user): qs = self if not user.has_perm("cases.can_view_all"): content_type = ContentType.objects.get_for_model(Case) qs = qs.filter( **{ "{}__permission__codename".format(lrc_cup): "can_view", "{}__permission__content_type".format(lrc_cup): content_type, "{}__user".format(lrc_cup): user, } ) if not user.is_staff: qs = qs.filter(letter__status=Letter.STATUS.done) return qs
[dokumentacja] class Attachment(models.Model): letter = models.ForeignKey(to=Letter, on_delete=models.CASCADE) attachment = models.FileField(upload_to=date_random_path, verbose_name=_("File")) objects = AttachmentQuerySet.as_manager() @property def filename(self): return basename(self.attachment.name) def __str__(self): return "%s" % (self.filename) def get_absolute_url(self): return reverse( "letters:attachment_download", kwargs={ "letter_pk": self.letter_id, "case_pk": self.letter.case_id, "pk": self.pk, }, ) def get_full_url(self): return "".join( ["https://", get_current_site(None).domain, self.get_absolute_url()] ) class Meta: verbose_name = _("Attachment") verbose_name_plural = _("Attachments")