__copyright__ = "Copyright 2016-2018, Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" from django.db import models from django.core.urlresolvers import reverse from django.conf import settings from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey from .constants import NOTIFICATION_TYPES from .managers import NotificationQuerySet class FakeActors(models.Model): """ This Model acts as a surrogate person that either is unknown, deceased, fake, etc. etc. """ name = models.CharField(max_length=256) def __str__(self): return self.name class Notification(models.Model): """ Action model describing the actor acting out a verb (on an optional target). Nomenclature based on http://activitystrea.ms/specs/atom/1.0/ Generalized Format:: <actor> <verb> <time> <actor> <verb> <target> <time> <actor> <verb> <action_object> <target> <time> Examples:: <justquick> <reached level 60> <1 minute ago> <brosner> <commented on> <pinax/pinax> <2 hours ago> <washingtontimes> <started follow> <justquick> <8 minutes ago> <mitsuhiko> <closed> <issue 70> on <mitsuhiko/flask> <about 2 hours ago> Unicode Representation:: justquick reached level 60 1 minute ago mitsuhiko closed issue 70 on mitsuhiko/flask 3 hours ago """ LEVELS = (('success', 'Success'), ('info', 'Info'), ('warning', 'Warning'), ('error', 'Error')) level = models.CharField(choices=LEVELS, default='info', max_length=20) recipient = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, related_name='notifications') unread = models.BooleanField(default=True) pseudo_unread = models.BooleanField(default=True) # Used to keep notification-bg "active" actor_content_type = models.ForeignKey(ContentType, related_name='notify_actor') actor_object_id = models.CharField(max_length=255) actor = GenericForeignKey('actor_content_type', 'actor_object_id') verb = models.CharField(max_length=255) description = models.TextField(blank=True, null=True) target_content_type = models.ForeignKey(ContentType, related_name='notify_target', blank=True, null=True) target_object_id = models.CharField(max_length=255, blank=True, null=True) target = GenericForeignKey('target_content_type', 'target_object_id') action_object_content_type = models.ForeignKey(ContentType, blank=True, null=True, related_name='notify_action_object') action_object_object_id = models.CharField(max_length=255, blank=True, null=True) action_object = GenericForeignKey('action_object_content_type', 'action_object_object_id') created = models.DateTimeField(auto_now_add=True) url_code = models.CharField(max_length=255) # Fake # This field is for internal use only. It is used to prevent duplicate sending # of notifications. internal_type = models.CharField(max_length=255, blank=True, choices=NOTIFICATION_TYPES) objects = NotificationQuerySet.as_manager() class Meta: ordering = ('-created', ) def __str__(self): ctx = { 'actor': self.actor, 'verb': self.verb, 'action_object': self.action_object, 'target': self.target, 'timesince': self.timesince() } if self.target: if self.action_object: return u'%(actor)s %(verb)s %(action_object)s on %(target)s %(timesince)s ago' % ctx return u'%(actor)s %(verb)s %(target)s %(timesince)s ago' % ctx if self.action_object: return u'%(actor)s %(verb)s %(action_object)s %(timesince)s ago' % ctx return u'%(actor)s %(verb)s %(timesince)s ago' % ctx def get_absolute_url(self): return reverse('notifications:forward', args=(self.slug,)) def timesince(self, now=None): """ Shortcut for the ``django.utils.timesince.timesince`` function of the current timestamp. """ from django.utils.timesince import timesince as timesince_ return timesince_(self.created, now) @property def slug(self): from .utils import id2slug return id2slug(self.id) def mark_toggle(self): if self.pseudo_unread: self.mark_as_read() else: self.mark_as_unread() def mark_as_read(self): if self.unread or self.pseudo_unread: Notification.objects.filter(id=self.id).update(unread=False, pseudo_unread=False) def mark_as_unread(self): if not self.unread or not self.pseudo_unread: Notification.objects.filter(id=self.id).update(unread=True, pseudo_unread=True)