Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

models.py 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. import json
  2. from django.conf import settings
  3. from django.contrib.admin.utils import quote
  4. from django.contrib.contenttypes.models import ContentType
  5. from django.db import models
  6. from django.urls import NoReverseMatch, reverse
  7. from django.utils import timezone
  8. from django.utils.text import get_text_list
  9. from django.utils.translation import gettext, gettext_lazy as _
  10. ADDITION = 1
  11. CHANGE = 2
  12. DELETION = 3
  13. ACTION_FLAG_CHOICES = (
  14. (ADDITION, _('Addition')),
  15. (CHANGE, _('Change')),
  16. (DELETION, _('Deletion')),
  17. )
  18. class LogEntryManager(models.Manager):
  19. use_in_migrations = True
  20. def log_action(self, user_id, content_type_id, object_id, object_repr, action_flag, change_message=''):
  21. if isinstance(change_message, list):
  22. change_message = json.dumps(change_message)
  23. return self.model.objects.create(
  24. user_id=user_id,
  25. content_type_id=content_type_id,
  26. object_id=str(object_id),
  27. object_repr=object_repr[:200],
  28. action_flag=action_flag,
  29. change_message=change_message,
  30. )
  31. class LogEntry(models.Model):
  32. action_time = models.DateTimeField(
  33. _('action time'),
  34. default=timezone.now,
  35. editable=False,
  36. )
  37. user = models.ForeignKey(
  38. settings.AUTH_USER_MODEL,
  39. models.CASCADE,
  40. verbose_name=_('user'),
  41. )
  42. content_type = models.ForeignKey(
  43. ContentType,
  44. models.SET_NULL,
  45. verbose_name=_('content type'),
  46. blank=True, null=True,
  47. )
  48. object_id = models.TextField(_('object id'), blank=True, null=True)
  49. # Translators: 'repr' means representation (https://docs.python.org/library/functions.html#repr)
  50. object_repr = models.CharField(_('object repr'), max_length=200)
  51. action_flag = models.PositiveSmallIntegerField(_('action flag'), choices=ACTION_FLAG_CHOICES)
  52. # change_message is either a string or a JSON structure
  53. change_message = models.TextField(_('change message'), blank=True)
  54. objects = LogEntryManager()
  55. class Meta:
  56. verbose_name = _('log entry')
  57. verbose_name_plural = _('log entries')
  58. db_table = 'django_admin_log'
  59. ordering = ('-action_time',)
  60. def __repr__(self):
  61. return str(self.action_time)
  62. def __str__(self):
  63. if self.is_addition():
  64. return gettext('Added "%(object)s".') % {'object': self.object_repr}
  65. elif self.is_change():
  66. return gettext('Changed "%(object)s" - %(changes)s') % {
  67. 'object': self.object_repr,
  68. 'changes': self.get_change_message(),
  69. }
  70. elif self.is_deletion():
  71. return gettext('Deleted "%(object)s."') % {'object': self.object_repr}
  72. return gettext('LogEntry Object')
  73. def is_addition(self):
  74. return self.action_flag == ADDITION
  75. def is_change(self):
  76. return self.action_flag == CHANGE
  77. def is_deletion(self):
  78. return self.action_flag == DELETION
  79. def get_change_message(self):
  80. """
  81. If self.change_message is a JSON structure, interpret it as a change
  82. string, properly translated.
  83. """
  84. if self.change_message and self.change_message[0] == '[':
  85. try:
  86. change_message = json.loads(self.change_message)
  87. except json.JSONDecodeError:
  88. return self.change_message
  89. messages = []
  90. for sub_message in change_message:
  91. if 'added' in sub_message:
  92. if sub_message['added']:
  93. sub_message['added']['name'] = gettext(sub_message['added']['name'])
  94. messages.append(gettext('Added {name} "{object}".').format(**sub_message['added']))
  95. else:
  96. messages.append(gettext('Added.'))
  97. elif 'changed' in sub_message:
  98. sub_message['changed']['fields'] = get_text_list(
  99. sub_message['changed']['fields'], gettext('and')
  100. )
  101. if 'name' in sub_message['changed']:
  102. sub_message['changed']['name'] = gettext(sub_message['changed']['name'])
  103. messages.append(gettext('Changed {fields} for {name} "{object}".').format(
  104. **sub_message['changed']
  105. ))
  106. else:
  107. messages.append(gettext('Changed {fields}.').format(**sub_message['changed']))
  108. elif 'deleted' in sub_message:
  109. sub_message['deleted']['name'] = gettext(sub_message['deleted']['name'])
  110. messages.append(gettext('Deleted {name} "{object}".').format(**sub_message['deleted']))
  111. change_message = ' '.join(msg[0].upper() + msg[1:] for msg in messages)
  112. return change_message or gettext('No fields changed.')
  113. else:
  114. return self.change_message
  115. def get_edited_object(self):
  116. """Return the edited object represented by this log entry."""
  117. return self.content_type.get_object_for_this_type(pk=self.object_id)
  118. def get_admin_url(self):
  119. """
  120. Return the admin URL to edit the object represented by this log entry.
  121. """
  122. if self.content_type and self.object_id:
  123. url_name = 'admin:%s_%s_change' % (self.content_type.app_label, self.content_type.model)
  124. try:
  125. return reverse(url_name, args=(quote(self.object_id),))
  126. except NoReverseMatch:
  127. pass
  128. return None