Permalink
Browse files

pluggable-backends: Merged from trunk up to r73. This is a bit rough …

…and will need some more work.

git-svn-id: https://django-notification.googlecode.com/svn/branches/pluggable-backends@76 590c3fc9-4838-0410-bb95-17a0c9b37ca9
  • Loading branch information...
1 parent ef5efc6 commit cb1e271fa4ebfe7c2738133d4d43885bce29450e @brosner brosner committed Jul 8, 2008
@@ -1,8 +1,7 @@
-from notification.models import unseen_count_for
+from notification.models import Notice
def notification(request):
if request.user.is_authenticated():
- return {'notice_unseen_count': unseen_count_for(request.user)}
+ return {'notice_unseen_count': Notice.objects.unseen_count_for(request.user),}
else:
return {}
-
View
@@ -2,12 +2,17 @@
from django.db import models
from django.conf import settings
-from django.db.models import Q
+from django.core.urlresolvers import reverse
+from django.template import Context
+from django.template.loader import render_to_string
-from django.contrib.auth.models import User
+from django.contrib.auth.models import User, SiteProfileNotAvailable
+
+from django.contrib.contenttypes.models import ContentType
+from django.contrib.contenttypes import generic
from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ugettext
+from django.utils.translation import ugettext, get_language, activate
from notification import backends
from notification.message import encode_message
@@ -18,10 +23,10 @@ class NoticeType(models.Model):
label = models.CharField(_('label'), max_length=40)
display = models.CharField(_('display'), max_length=50)
description = models.CharField(_('description'), max_length=100)
-
+
# by default only on for media with sensitivity less than or equal to this number
- default = models.IntegerField(_('default'))
-
+ default = models.IntegerField(_('default'))
+
def __unicode__(self):
return self.label
@@ -31,7 +36,6 @@ class Admin:
class Meta:
verbose_name = _("notice type")
verbose_name_plural = _("notice types")
-
NOTIFICATION_BACKENDS = backends.load_backends()
NOTICE_MEDIA = tuple(
@@ -72,11 +76,31 @@ def get_notification_setting(user, notice_type, medium):
setting.save()
return setting
-
def should_send(user, notice_type, medium):
return get_notification_setting(user, notice_type, medium).send
+class NoticeManager(models.Manager):
+
+ def notices_for(self, user, archived=False):
+ """
+ returns Notice objects for the given user.
+
+ If archived=False, it only include notices not archived.
+ If archived=True, it returns all notices for that user.
+ """
+ if archived:
+ return self.filter(user=user)
+ else:
+ return self.filter(user=user, archived=archived)
+
+ def unseen_count_for(self, user):
+ """
+ returns the number of unseen notices for the given user but does not
+ mark them seen
+ """
+ return self.filter(user=user, unseen=True).count()
+
class Notice(models.Model):
user = models.ForeignKey(User, verbose_name=_('user'))
@@ -86,6 +110,8 @@ class Notice(models.Model):
unseen = models.BooleanField(_('unseen'), default=True)
archived = models.BooleanField(_('archived'), default=False)
+ objects = NoticeManager()
+
def __unicode__(self):
return self.message
@@ -106,9 +132,6 @@ def is_unseen(self):
self.save()
return unseen
- def html_message(self):
- return message_to_html(self.message)
-
class Meta:
ordering = ["-added"]
verbose_name = _("notice")
@@ -117,10 +140,9 @@ class Meta:
class Admin:
list_display = ('message', 'user', 'notice_type', 'added', 'unseen', 'archived')
-
def create_notice_type(label, display, description, default=2):
"""
- create a new NoticeType.
+ Creates a new NoticeType.
This is intended to be used by other apps as a post_syncdb manangement step.
"""
@@ -143,18 +165,80 @@ def create_notice_type(label, display, description, default=2):
NoticeType(label=label, display=display, description=description, default=default).save()
print "Created %s NoticeType" % label
+def get_formatted_messages(formats, label, context):
+ """
+ Returns a dictionary with the format identifier as the key. The values are
+ are fully rendered templates with the given context.
+ """
+ format_templates = {}
+ for format in formats:
+ name = format.split(".")[0]
+ format_templates[name] = render_to_string((
+ 'notification/%s/%s' % (label, format),
+ 'notification/%s' % format), context)
+ return format_templates
-def send(users, notice_type_label, message_template, object_list=None):
+def send(recipient, label, extra_context={}):
"""
- create a new notice.
+ Creates a new notice.
This is intended to be how other apps create new notices.
+
+ notification.send(user, 'friends_invite_sent', {
+ 'spam': 'eggs',
+ 'foo': 'bar',
+ )
"""
- notice_type = NoticeType.objects.get(label=notice_type_label)
- message = encode_message(message_template, object_list)
+ if not isinstance(recipient, (list, tuple)):
+ recipient = (recipient,)
+
+ notice_type = NoticeType.objects.get(label=label)
backend_recipients = {}
+
+ context = Context({
+ "notice": ugettext(notice_type.display),
+ "notices_url": notices_url,
+ "current_site": current_site,
+ })
+ context.update(extra_context)
+
+ recipients = []
+ current_language = get_language()
+
+ formats = (
+ 'short.txt',
+ 'plain.txt',
+ 'teaser.html',
+ 'full.html',
+ ) # TODO make formats configurable
+
+ for user in recipient:
+ # get user profiles if available
+ try:
+ profile = user.get_profile()
+ except SiteProfileNotAvailable:
+ profile = None
+
+ # activate language of user to send message translated
+ if profile is not None:
+ # get language attribute of user profile
+ language = getattr(profile, "language", None)
+ if language is not None:
+ # activate the user's language
+ activate(language)
+
+ # get prerendered format messages
+ messages = get_formatted_messages(formats, label, context)
+
+ # Strip newlines from subject
+ subject = ''.join(render_to_string('notification/email_subject.txt', {
+ 'message': messages['short'],
+ }, context).splitlines())
+
+ body = render_to_string('notification/email_body.txt', {
+ 'message': messages['plain'],
+ }, context)
- for user in users:
notice = Notice(user=user, message=message, notice_type=notice_type)
notice.save()
for key, backend in NOTIFICATION_BACKENDS:
@@ -164,28 +248,92 @@ def send(users, notice_type_label, message_template, object_list=None):
for key, backend in NOTIFICATION_BACKENDS:
backend.deliver(backend_recipients[key], notice_type, message)
+ # reset environment to original language
+ activate(current_language)
+
+class ObservedItemManager(models.Manager):
+
+ def all_for(self, observed, signal):
+ """
+ Returns all ObservedItems for an observed object,
+ to be sent when a signal is emited.
+ """
+ content_type = ContentType.objects.get_for_model(observed)
+ observed_items = self.filter(content_type=content_type, object_id=observed.id, signal=signal)
+ return observed_items
+
+ def get_for(self, observed, observer, signal):
+ content_type = ContentType.objects.get_for_model(observed)
+ observed_item = self.get(content_type=content_type, object_id=observed.id, user=observer, signal=signal)
+ return observed_item
+
+
+class ObservedItem(models.Model):
-def notices_for(user, archived=False):
+ user = models.ForeignKey(User, verbose_name=_('user'))
+
+ content_type = models.ForeignKey(ContentType)
+ object_id = models.PositiveIntegerField()
+ observed_object = generic.GenericForeignKey('content_type', 'object_id')
+
+ notice_type = models.ForeignKey(NoticeType, verbose_name=_('notice type'))
+ message_template = models.TextField(verbose_name=_('message template'))
+
+ added = models.DateTimeField(_('added'), default=datetime.datetime.now)
+
+ # the signal that will be listened to send the notice
+ signal = models.TextField(verbose_name=_('signal'))
+
+ objects = ObservedItemManager()
+
+ class Meta:
+ ordering = ['-added']
+ verbose_name = _('observed item')
+ verbose_name_plural = _('observed items')
+
+ class Admin:
+ pass
+
+ def send_notice(self):
+ send([self.user], self.notice_type.label, self.message_template,
+ [self.observed_object])
+
+
+def observe(observed, observer, notice_type_label, message_template, signal='post_save'):
"""
- returns Notice objects for the given user.
+ Create a new ObservedItem.
- If archived=False, it only include notices not archived.
- If archived=True, it returns all notices for that user.
- Superusers receive all notices.
+ To be used by applications to register a user as an observer for some object.
"""
- if user.is_superuser:
- q = Q()
- else:
- q = Q(user=user)
- if archived:
- return Notice.objects.filter(q)
- else:
- return Notice.objects.filter(q, archived=archived)
+ notice_type = NoticeType.objects.get(label=notice_type_label)
+ observed_item = ObservedItem(user=observer, observed_object=observed, notice_type=notice_type, message_template=message_template, signal=signal)
+ observed_item.save()
+ return observed_item
+def stop_observing(observed, observer, signal='post_save'):
+ """
+ Remove an observed item.
+ """
+ observed_item = ObservedItem.objects.get_for(observed, observer, signal)
+ observed_item.delete()
-def unseen_count_for(user):
+def send_observation_notices_for(observed, signal='post_save'):
"""
- returns the number of unseen notices for the given user but does not
- mark them seen
+ Send a notice for each registered user about an observed object.
"""
- return Notice.objects.filter(user=user, unseen=True).count()
+ observed_items = ObservedItem.objects.all_for(observed, signal)
+ for observed_item in observed_items:
+ observed_item.send_notice()
+ return observed_items
+
+def is_observing(observed, observer, signal='post_save'):
+ try:
+ observed_items = ObservedItem.objects.get_for(observed, observer, signal)
+ return True
+ except ObservedItem.DoesNotExist:
+ return False
+ except ObservedItem.MultipleObjectsReturned:
+ return True
+
+def handle_observations(sender, instance, *args, **kw):
+ send_observation_notices_for(instance)
@@ -0,0 +1,6 @@
+{% load i18n %}{% blocktrans %}You have received the following notice from {{ current_site }}:
+
+{{ message }}
+
+To see other notices or change how you receive notifications, please go to {{ notices_url }}.
+{% endblocktrans %}
@@ -0,0 +1 @@
+{% load i18n %}{% blocktrans %}[{{ current_site }}] {{ message }}{% endblocktrans %}
@@ -1,9 +0,0 @@
-{% load i18n %}{% blocktrans %}You have received the following notice:
-
-{{ message }}
-
-To see other notices or change how you receive notifications,
-please go to {{ notices_url }}
-
-If you have any issues, please don't hesitate to contact {{ contact_email }}
-{% endblocktrans %}
@@ -1 +0,0 @@
-{% load i18n %}{% blocktrans %}{{ display }} Notification{% endblocktrans %}
@@ -0,0 +1 @@
+{% load i18n %}{% blocktrans %}{{ notice }}{% endblocktrans %}
@@ -0,0 +1 @@
+{% load i18n %}{% blocktrans %}{{ notice }}{% endblocktrans %}
@@ -0,0 +1 @@
+{% load i18n %}{% blocktrans %}{{ notice }}{% endblocktrans %}
No changes.
@@ -1,10 +0,0 @@
-from django.template.defaultfilters import stringfilter
-from django.utils.translation import ugettext
-from django import template
-
-register = template.Library()
-
-def do_ugettext(msg):
- """Given a message this returns its gettext translation"""
- return ugettext(msg)
-register.simple_tag('ugettext', do_ugettext)
View
@@ -1,14 +1,14 @@
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
-from django.contrib.auth.decorators import login_required, permission_required
+from django.contrib.auth.decorators import login_required
from notification.models import *
@login_required
def notices(request):
notice_types = NoticeType.objects.all()
- notices = notices_for(request.user)
+ notices = Notice.objects.notices_for(request.user)
settings_table = []
for notice_type in NoticeType.objects.all():
settings_row = []

0 comments on commit cb1e271

Please sign in to comment.