# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
import json
from channels import Group
from django.conf import settings
from django.db.models.signals import post_save
from django.utils.encoding import force_text
from django.utils.translation import get_language, ugettext_lazy as _
from .signals import notify_items # NOQA
[docs]class KnockerModel(object):
_knocker_data = {
'title': 'get_knocker_title',
'message': 'get_knocker_message',
'icon': 'get_knocker_icon',
'url': 'get_absolute_url',
'language': 'get_knocker_language',
}
def __new__(cls, *args, **kwargs):
new_cls = object.__new__(cls)
new_cls._connect()
return new_cls
@classmethod
def _connect(cls):
"""
Connect signal to current model
"""
post_save.connect(
notify_items, sender=cls,
dispatch_uid='knocker_{0}'.format(cls.__name__)
)
@classmethod
def _disconnect(cls):
"""
Disconnect signal from current model
"""
post_save.disconnect(
notify_items, sender=cls,
dispatch_uid='knocker_{0}'.format(cls.__name__)
)
[docs] def get_knocker_icon(self):
"""
Generic function to return the knock icon
Defaults to the value of settings.KNOCKER_ICON_URL
"""
return getattr(settings, 'KNOCKER_ICON_URL', '')
[docs] def get_knocker_title(self):
"""
Generic function to return the knock title.
Defaults to 'new `model_verbose_name`'
"""
return force_text(_('new {0}'.format(self._meta.verbose_name)))
[docs] def get_knocker_message(self):
"""
Generic function to return the knock message.
Defaults to calling ``self.get_title``
"""
return self.get_title()
[docs] def get_knocker_language(self):
"""
Returns the current language.
This will call ``selg.get_current_language`` if available or the Django
``django.utils.translation.get_language()`` otherwise
"""
if hasattr(self, 'get_current_language'):
return self.get_current_language()
else:
return get_language()
[docs] def should_knock(self, created=False):
"""
Generic function to tell whether a knock should be emitted.
Override this to avoid emitting knocks under specific circumstances (e.g.: if the object
has just been created or update)
:param created: True if the object has been created
"""
return True
def as_knock(self, created=False):
"""
Returns a dictionary with the knock data built from _knocker_data
"""
knock = {}
if self.should_knock(created):
for field, data in self._retrieve_data(None, self._knocker_data):
knock[field] = data
return knock
def send_knock(self, created=False):
"""
Send the knock in the associated channels Group
"""
knock = self.as_knock(created)
if knock:
gr = Group('knocker-{0}'.format(knock['language']))
gr.send({'text': json.dumps(knock)})