import json
import logging
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.functional import cached_property
from django.utils.html import escape
from django.utils.translation import gettext_lazy as _
from django.utils.translation import ngettext_lazy as _n
from django_scopes import ScopedManager
[docs]
class ActivityLog(models.Model):
"""This model logs actions within an event.
It is **not** designed to provide a complete or reliable audit
trail.
:param is_orga_action: True, if the logged action was performed by a privileged user.
"""
event = models.ForeignKey(
to="event.Event",
on_delete=models.PROTECT,
related_name="log_entries",
null=True,
blank=True,
)
person = models.ForeignKey(
to="person.User",
on_delete=models.PROTECT,
related_name="log_entries",
null=True,
blank=True,
)
content_type = models.ForeignKey(to=ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField(db_index=True)
content_object = GenericForeignKey("content_type", "object_id")
timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
action_type = models.CharField(max_length=200)
data = models.TextField(null=True, blank=True)
is_orga_action = models.BooleanField(default=False)
objects = ScopedManager(event="event")
class Meta:
ordering = ("-timestamp",)
def __str__(self):
"""Custom __str__ to help with debugging."""
event = getattr(self.event, "slug", "None")
person = getattr(self.person, "name", "None")
return f"ActivityLog(event={event}, person={person}, content_object={self.content_object}, action_type={self.action_type})"
@cached_property
def json_data(self):
if self.data:
return json.loads(self.data)
return {}
@cached_property
def display(self):
from pretalx.common.signals import activitylog_display
for _receiver, response in activitylog_display.send(
self.event, activitylog=self
):
if response:
return response
logger = logging.getLogger(__name__)
logger.warning(f'Unknown log action "{self.action_type}".')
return self.action_type
@cached_property
def display_object(self) -> str:
"""Returns an organiser backend URL to the object in question (if any)."""
from pretalx.common.signals import activitylog_object_link
from pretalx.mail.models import MailTemplate, QueuedMail
from pretalx.submission.models import (
Answer,
AnswerOption,
CfP,
Question,
Submission,
SubmissionStates,
)
url = ""
text = ""
link_text = ""
if isinstance(self.content_object, Submission):
url = self.content_object.orga_urls.base
link_text = escape(self.content_object.title)
if self.content_object.state in [
SubmissionStates.ACCEPTED,
SubmissionStates.CONFIRMED,
]:
text = _n("Session", "Sessions", 1)
else:
text = _n("Proposal", "Proposals", 1)
if isinstance(self.content_object, Question):
url = self.content_object.urls.base
link_text = escape(self.content_object.question)
text = _("Question")
if isinstance(self.content_object, AnswerOption):
url = self.content_object.question.urls.base
link_text = escape(self.content_object.question.question)
text = _("Question")
if isinstance(self.content_object, Answer):
if self.content_object.submission:
url = self.content_object.submission.orga_urls.base
else:
url = self.content_object.question.urls.base
link_text = escape(self.content_object.question.question)
text = _("Answer to question")
if isinstance(self.content_object, CfP):
url = self.content_object.urls.text
link_text = _("CfP")
if isinstance(self.content_object, MailTemplate):
url = self.content_object.urls.base
text = _("Mail template")
link_text = escape(self.content_object.subject)
if isinstance(self.content_object, QueuedMail):
url = self.content_object.urls.base
text = _("Email")
link_text = escape(self.content_object.subject)
if url:
if not link_text:
link_text = url
return f'{text} <a href="{url}">{link_text}</a>'
if text or link_text:
return f"{text} {link_text}"
responses = activitylog_object_link.send(sender=self.event, activitylog=self)
if responses:
for _receiver, response in responses:
if response:
return response
return ""