diff --git a/notification/backends/email.py b/notification/backends/email.py index aa172698..7c52c98c 100644 --- a/notification/backends/email.py +++ b/notification/backends/email.py @@ -5,6 +5,7 @@ from django.utils.translation import ugettext from notification import backends +from notification.message import message_to_text # favour django-mailer but fall back to django.core.mail try: diff --git a/notification/message.py b/notification/message.py new file mode 100644 index 00000000..9eab7ec1 --- /dev/null +++ b/notification/message.py @@ -0,0 +1,109 @@ + +from django.db.models import get_model +from django.utils.translation import ugettext + + +# a notice like "foo and bar are now friends" is stored in the database +# as "{auth.User.5} and {auth.User.7} are now friends". +# +# encode_object takes an object and turns it into "{app.Model.pk}" or +# "{app.Model.pk.msgid}" if named arguments are used in send() +# decode_object takes "{app.Model.pk}" and turns it into the object +# +# encode_message takes either ("%s and %s are now friends", [foo, bar]) or +# ("%(foo)s and %(bar)s are now friends", {'foo':foo, 'bar':bar}) and turns +# it into "{auth.User.5} and {auth.User.7} are now friends". +# +# decode_message takes "{auth.User.5} and {auth.User.7}" and converts it +# into a string using the given decode function to convert the object to +# string representation +# +# message_to_text and message_to_html use decode_message to produce a +# text and html version of the message respectively. + +def encode_object(obj, name=None): + encoded = "%s.%s.%s" % (obj._meta.app_label, obj._meta.object_name, obj.pk) + if name: + encoded = "%s.%s" % (encoded, name) + return "{%s}" % encoded + + +def encode_message(message_template, objects): + if objects is None: + return message_template + if isinstance(objects, list) or isinstance(objects, tuple): + return message_template % tuple(encode_object(obj) for obj in objects) + if type(objects) is dict: + return message_template % dict((name, encode_object(obj, name)) for name, obj in objects.iteritems()) + return '' + + +def decode_object(ref): + decoded = ref.split(".") + if len(decoded) == 4: + app, name, pk, msgid = decoded + return get_model(app, name).objects.get(pk=pk), msgid + app, name, pk = decoded + return get_model(app, name).objects.get(pk=pk), None + + +class FormatException(Exception): + pass + + +def decode_message(message, decoder): + out = [] + objects = [] + mapping = {} + in_field = False + prev = 0 + for index, ch in enumerate(message): + if not in_field: + if ch == '{': + in_field = True + if prev != index: + out.append(message[prev:index]) + prev = index + elif ch == '}': + raise FormatException("unmatched }") + elif in_field: + if ch == '{': + raise FormatException("{ inside {}") + elif ch == '}': + in_field = False + obj, msgid = decoder(message[prev+1:index]) + if msgid is None: + objects.append(obj) + out.append("%s") + else: + mapping[msgid] = obj + out.append("%("+msgid+")s") + prev = index + 1 + if in_field: + raise FormatException("unmatched {") + if prev <= index: + out.append(message[prev:index+1]) + result = "".join(out) + if mapping: + args = mapping + else: + args = tuple(objects) + return ugettext(result) % args + + +def message_to_text(message): + def decoder(ref): + obj, msgid = decode_object(ref) + return unicode(obj), msgid + return decode_message(message, decoder) + + +def message_to_html(message): + def decoder(ref): + obj, msgid = decode_object(ref) + if hasattr(obj, "get_absolute_url"): # don't fail silenty if get_absolute_url hasn't been defined + return u"""%s""" % (obj.get_absolute_url(), unicode(obj)), msgid + else: + return unicode(obj), msgid + return decode_message(message, decoder) + \ No newline at end of file diff --git a/notification/models.py b/notification/models.py index cb3dfcaf..2533b8da 100644 --- a/notification/models.py +++ b/notification/models.py @@ -3,7 +3,6 @@ from django.db import models from django.conf import settings from django.db.models import Q -from django.db.models import get_model from django.contrib.sites.models import Site from django.contrib.auth.models import User @@ -12,6 +11,7 @@ from django.utils.translation import ugettext from notification import backends +from notification.message import encode_message class NoticeType(models.Model): @@ -32,6 +32,7 @@ class Admin: class Meta: verbose_name = _("notice type") verbose_name_plural = _("notice types") + NOTIFICATION_BACKENDS = backends.load_backends() NOTICE_MEDIA = tuple( @@ -62,6 +63,7 @@ class Meta: verbose_name = _("notice setting") verbose_name_plural = _("notice settings") + def get_notification_setting(user, notice_type, medium): try: return NoticeSetting.objects.get(user=user, notice_type=notice_type, medium=medium) @@ -142,104 +144,6 @@ def create_notice_type(label, display, description, default=2): NoticeType(label=label, display=display, description=description, default=default).save() print "Created %s NoticeType" % label -# a notice like "foo and bar are now friends" is stored in the database -# as "{auth.User.5} and {auth.User.7} are now friends". -# -# encode_object takes an object and turns it into "{app.Model.pk}" or -# "{app.Model.pk.msgid}" if named arguments are used in send() -# decode_object takes "{app.Model.pk}" and turns it into the object -# -# encode_message takes either ("%s and %s are now friends", [foo, bar]) or -# ("%(foo)s and %(bar)s are now friends", {'foo':foo, 'bar':bar}) and turns -# it into "{auth.User.5} and {auth.User.7} are now friends". -# -# decode_message takes "{auth.User.5} and {auth.User.7}" and converts it -# into a string using the given decode function to convert the object to -# string representation -# -# message_to_text and message_to_html use decode_message to produce a -# text and html version of the message respectively. - -def encode_object(obj, name=None): - encoded = "%s.%s.%s" % (obj._meta.app_label, obj._meta.object_name, obj.pk) - if name: - encoded = "%s.%s" % (encoded, name) - return "{%s}" % encoded - -def encode_message(message_template, objects): - if objects is None: - return message_template - if isinstance(objects, list) or isinstance(objects, tuple): - return message_template % tuple(encode_object(obj) for obj in objects) - if type(objects) is dict: - return message_template % dict((name, encode_object(obj, name)) for name, obj in objects.iteritems()) - return '' - -def decode_object(ref): - decoded = ref.split(".") - if len(decoded) == 4: - app, name, pk, msgid = decoded - return get_model(app, name).objects.get(pk=pk), msgid - app, name, pk = decoded - return get_model(app, name).objects.get(pk=pk), None - -class FormatException(Exception): - pass - -def decode_message(message, decoder): - out = [] - objects = [] - mapping = {} - in_field = False - prev = 0 - for index, ch in enumerate(message): - if not in_field: - if ch == '{': - in_field = True - if prev != index: - out.append(message[prev:index]) - prev = index - elif ch == '}': - raise FormatException("unmatched }") - elif in_field: - if ch == '{': - raise FormatException("{ inside {}") - elif ch == '}': - in_field = False - obj, msgid = decoder(message[prev+1:index]) - if msgid is None: - objects.append(obj) - out.append("%s") - else: - mapping[msgid] = obj - out.append("%("+msgid+")s") - prev = index + 1 - if in_field: - raise FormatException("unmatched {") - if prev <= index: - out.append(message[prev:index+1]) - result = "".join(out) - if mapping: - args = mapping - else: - args = tuple(objects) - return ugettext(result) % args - -def message_to_text(message): - def decoder(ref): - obj, msgid = decode_object(ref) - return unicode(obj), msgid - return decode_message(message, decoder) - -def message_to_html(message): - def decoder(ref): - obj, msgid = decode_object(ref) - if hasattr(obj, "get_absolute_url"): # don't fail silenty if get_absolute_url hasn't been defined - return u"""%s""" % (obj.get_absolute_url(), unicode(obj)), msgid - else: - return unicode(obj), msgid - return decode_message(message, decoder) - def send(users, notice_type_label, message_template, object_list=None, issue_notice=True): """