# -*- coding: utf-8 -*- # pylint: disable=too-many-lines from distutils.version import ( # pylint: disable=no-name-in-module,import-error StrictVersion, ) from django import get_version from django.conf import settings from django.contrib.auth.models import Group from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ImproperlyConfigured from django.db import models from django.db.models import JSONField from django.db.models.query import QuerySet from django.utils import timezone from model_utils import Choices from swapper import load_model from notifications import settings as notifications_settings from notifications.signals import notify from notifications.utils import id2slug if StrictVersion(get_version()) >= StrictVersion("1.8.0"): from django.contrib.contenttypes.fields import GenericForeignKey # noqa else: from django.contrib.contenttypes.generic import GenericForeignKey # noqa EXTRA_DATA = notifications_settings.get_config()["USE_JSONFIELD"] def is_soft_delete(): return notifications_settings.get_config()["SOFT_DELETE"] def assert_soft_delete(): if not is_soft_delete(): # msg = """To use 'deleted' field, please set 'SOFT_DELETE'=True in settings. # Otherwise NotificationQuerySet.unread and NotificationQuerySet.read do NOT filter by 'deleted' field. # """ msg = "REVERTME" raise ImproperlyConfigured(msg) class NotificationQuerySet(models.query.QuerySet): """Notification QuerySet""" def unsent(self): return self.filter(emailed=False) def sent(self): return self.filter(emailed=True) def unread(self, include_deleted=False): """Return only unread items in the current queryset""" if is_soft_delete() and not include_deleted: return self.filter(unread=True, deleted=False) # When SOFT_DELETE=False, developers are supposed NOT to touch 'deleted' field. # In this case, to improve query performance, don't filter by 'deleted' field return self.filter(unread=True) def read(self, include_deleted=False): """Return only read items in the current queryset""" if is_soft_delete() and not include_deleted: return self.filter(unread=False, deleted=False) # When SOFT_DELETE=False, developers are supposed NOT to touch 'deleted' field. # In this case, to improve query performance, don't filter by 'deleted' field return self.filter(unread=False) def mark_all_as_read(self, recipient=None): """Mark as read any unread messages in the current queryset. Optionally, filter these by recipient first. """ # We want to filter out read ones, as later we will store # the time they were marked as read. qset = self.unread(True) if recipient: qset = qset.filter(recipient=recipient) return qset.update(unread=False) def mark_all_as_unread(self, recipient=None): """Mark as unread any read messages in the current queryset. Optionally, filter these by recipient first. """ qset = self.read(True) if recipient: qset = qset.filter(recipient=recipient) return qset.update(unread=True) def deleted(self): """Return only deleted items in the current queryset""" assert_soft_delete() return self.filter(deleted=True) def active(self): """Return only active(un-deleted) items in the current queryset""" assert_soft_delete() return self.filter(deleted=False) def mark_all_as_deleted(self, recipient=None): """Mark current queryset as deleted. Optionally, filter by recipient first. """ assert_soft_delete() qset = self.active() if recipient: qset = qset.filter(recipient=recipient) return qset.update(deleted=True) def mark_all_as_active(self, recipient=None): """Mark current queryset as active(un-deleted). Optionally, filter by recipient first. """ assert_soft_delete() qset = self.deleted() if recipient: qset = qset.filter(recipient=recipient) return qset.update(deleted=False) def mark_as_unsent(self, recipient=None): qset = self.sent() if recipient: qset = qset.filter(recipient=recipient) return qset.update(emailed=False) def mark_as_sent(self, recipient=None): qset = self.unsent() if recipient: qset = qset.filter(recipient=recipient) return qset.update(emailed=True) class AbstractNotification(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::