# -*- coding: utf-8 -*- from django.db import models from django.db.models.fields import FieldDoesNotExist from django.utils.translation import ugettext_lazy as _ import reversion class WatcherMixin(object): NOTIFY_LEVEL_CHOICES = ( ("all_owned_projects", _(u"All events on my projects")), ("only_watching", _(u"Only events for objects i watch")), ("only_assigned", _(u"Only events for objects assigned to me")), ("only_owner", _(u"Only events for objects owned by me")), ("no_events", _(u"No events")), ) notify_level = models.CharField(max_length=32, null=False, blank=False, default="only_watching", choices=NOTIFY_LEVEL_CHOICES, verbose_name=_(u"notify level")) notify_changes_by_me = models.BooleanField(null=False, blank=True, verbose_name=_(u"notify changes made by me")) class Meta: abstract = True def allow_notify_owned(self): return (self.notify_level in [ "only_owner", "only_assigned", "only_watching", "all_owned_projects", ]) def allow_notify_assigned_to(self): return (self.notify_level in [ "only_assigned", "only_watching", "all_owned_projects", ]) def allow_notify_suscribed(self): return (self.notify_level in [ "only_watching", "all_owned_projects", ]) def allow_notify_project(self, project): return self.notify_level == "all_owned_projects" and project.owner.pk == self.pk def allow_notify_by_me(self, changer): return (changer.pk != self.pk) or self.notify_changes_by_me class WatchedMixin(object): class Meta: abstract = True @property def last_version(self): version_list = reversion.get_for_object(self) return version_list and version_list[0] or None def get_changed_fields_dict(self, data_dict): field_dict = {} for field_name, data_value in data_dict.items(): field_dict.update(self._get_changed_field(field_name, data_value)) return field_dict def get_watchers_to_notify(self, changer): watchers_to_notify = set() watchers_by_role = self._get_watchers_by_role() owner = watchers_by_role.get("owner") if (owner and owner.allow_notify_owned() and owner.allow_notify_by_me(changer)): watchers_to_notify.add(owner) assigned_to = watchers_by_role.get("assigned_to") if (assigned_to and assigned_to.allow_notify_assigned_to() and assigned_to.allow_notify_by_me(changer)): watchers_to_notify.add(assigned_to) suscribed_watchers = watchers_by_role.get("suscribed_watchers") if suscribed_watchers: for suscribed_watcher in suscribed_watchers: if (suscribed_watcher and suscribed_watcher.allow_notify_suscribed() and suscribed_watcher.allow_notify_by_me(changer)): watchers_to_notify.add(suscribed_watcher) #(project, project_owner) = watchers_by_role.get("project_owner") #if project_owner \ # and project_owner.allow_notify_project(project) \ # and project_owner.allow_notify_by_me(self._changer): # watchers_to_notify.add(project_owner) return watchers_to_notify def _get_changed_field_verbose_name(self, field_name): try: return self._meta.get_field(field_name).verbose_name except FieldDoesNotExist: return field_name def _get_changed_field_old_value(self, field_name, data_value): return (self.last_version and self.last_version.field_dict.get(field_name, data_value) or None) def _get_changed_field_new_value(self, field_name, data_value): return getattr(self, field_name, data_value) def _get_changed_field(self, field_name, data_value): verbose_name = self._get_changed_field_verbose_name(field_name) old_value = self._get_changed_field_old_value(field_name, data_value) new_value = self._get_changed_field_new_value(field_name, data_value) return {field_name: { "verbose_name": verbose_name, "old_value": old_value, "new_value": new_value, }} def _get_watchers_by_role(self): """ Return the actual instances of watchers of this object, classified by role. For example: return { "owner": self.owner, "assigned_to": self.assigned_to, "suscribed_watchers": self.watchers.all(), "project_owner": (self.project, self.project.owner), } """ raise NotImplementedError("You must subclass WatchedMixin and provide _get_watchers_by_role method")