Skip to content

Commit

Permalink
added notice model and increased medium length
Browse files Browse the repository at this point in the history
  • Loading branch information
psychok7 committed Nov 29, 2016
1 parent a2c20e4 commit 32ecab7
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 5 deletions.
10 changes: 9 additions & 1 deletion pinax/notifications/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from django.contrib import admin

from .models import NoticeType, NoticeQueueBatch, NoticeSetting
from .models import NoticeType, NoticeQueueBatch, NoticeSetting, Notice


class NoticeTypeAdmin(admin.ModelAdmin):
Expand All @@ -9,8 +9,16 @@ class NoticeTypeAdmin(admin.ModelAdmin):

class NoticeSettingAdmin(admin.ModelAdmin):
list_display = ["id", "user", "notice_type", "medium", "scoping", "send"]
raw_id_fields = ["user"]


class NoticeAdmin(admin.ModelAdmin):
list_display = [
"message", "recipient", "sender", "notice_type", "added", "unseen",
"archived"]
raw_id_fields = ["recipient", "sender"]

admin.site.register(NoticeQueueBatch)
admin.site.register(NoticeType, NoticeTypeAdmin)
admin.site.register(Notice, NoticeAdmin)
admin.site.register(NoticeSetting, NoticeSettingAdmin)
10 changes: 10 additions & 0 deletions pinax/notifications/backends/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.utils.translation import ugettext

from .base import BaseBackend
from ..utils import get_class_from_path


class EmailBackend(BaseBackend):
Expand Down Expand Up @@ -42,3 +43,12 @@ def deliver(self, recipient, sender, notice_type, extra_context):
body = render_to_string("pinax/notifications/email_body.txt", context)

send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [recipient.email])

Notice = get_class_from_path(path='pinax.notifications.models.Notice')

# Based on http://stackoverflow.com/a/7390947
# This is mostly a log for sent notifications.
Notice.objects.create(
recipient=recipient, message=messages["full.txt"],
notice_type=notice_type, sender=sender
)
44 changes: 44 additions & 0 deletions pinax/notifications/backends/push_notifications.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.translation import ugettext

from .base import BaseBackend


class EmailBackend(BaseBackend):
spam_sensitivity = 2

def can_send(self, user, notice_type, scoping):
can_send = super(EmailBackend, self).can_send(user, notice_type, scoping)
if can_send and user.email:
return True
return False

def deliver(self, recipient, sender, notice_type, extra_context):
# TODO: require this to be passed in extra_context

context = self.default_context()
context.update({
"recipient": recipient,
"sender": sender,
"notice": ugettext(notice_type.display),
})
context.update(extra_context)

messages = self.get_formatted_messages((
"short.txt",
"full.txt"
), notice_type.label, context)

context.update({
"message": messages["short.txt"],
})
subject = "".join(render_to_string("pinax/notifications/email_subject.txt", context).splitlines())

context.update({
"message": messages["full.txt"]
})
body = render_to_string("pinax/notifications/email_body.txt", context)

send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [recipient.email])
44 changes: 44 additions & 0 deletions pinax/notifications/backends/sms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from django.conf import settings
from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils.translation import ugettext

from .base import BaseBackend


class EmailBackend(BaseBackend):
spam_sensitivity = 2

def can_send(self, user, notice_type, scoping):
can_send = super(EmailBackend, self).can_send(user, notice_type, scoping)
if can_send and user.email:
return True
return False

def deliver(self, recipient, sender, notice_type, extra_context):
# TODO: require this to be passed in extra_context

context = self.default_context()
context.update({
"recipient": recipient,
"sender": sender,
"notice": ugettext(notice_type.display),
})
context.update(extra_context)

messages = self.get_formatted_messages((
"short.txt",
"full.txt"
), notice_type.label, context)

context.update({
"message": messages["short.txt"],
})
subject = "".join(render_to_string("pinax/notifications/email_subject.txt", context).splitlines())

context.update({
"message": messages["full.txt"]
})
body = render_to_string("pinax/notifications/email_body.txt", context)

send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [recipient.email])
4 changes: 2 additions & 2 deletions pinax/notifications/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ def configure_backends(self, value):
raise ImproperlyConfigured(
"NOTIFICATION_BACKENDS does not contain enough data."
)
backend_instance = load_path_attr(backend_path)(medium_id, spam_sensitivity)
backends.append(((medium_id, label), backend_instance))
backend_instance = load_path_attr(backend_path)(label, spam_sensitivity)
backends.append(((label, label), backend_instance))
return dict(backends)

def configure_get_language_model(self, value):
Expand Down
40 changes: 40 additions & 0 deletions pinax/notifications/migrations/0002_auto_20161129_1812.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models
import django.utils.timezone
from django.conf import settings


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('pinax_notifications', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Notice',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('message', models.TextField(verbose_name='message')),
('added', models.DateTimeField(default=django.utils.timezone.now, verbose_name='added', db_index=True)),
('unseen', models.BooleanField(default=True, db_index=True, verbose_name='unseen')),
('archived', models.BooleanField(default=False, verbose_name='archived')),
('on_site', models.BooleanField(default=False, verbose_name='on site')),
('notice_type', models.ForeignKey(verbose_name='notice type', to='pinax_notifications.NoticeType')),
('recipient', models.ForeignKey(related_name='received_notices', verbose_name='recipient', to=settings.AUTH_USER_MODEL)),
('sender', models.ForeignKey(related_name='sent_notices', verbose_name='sender', to=settings.AUTH_USER_MODEL, null=True)),
],
options={
'verbose_name': 'notice',
'verbose_name_plural': 'notices',
},
),
migrations.AlterField(
model_name='noticesetting',
name='medium',
field=models.CharField(max_length=100, verbose_name='medium', choices=[(0, 'email')]),
),
]
97 changes: 96 additions & 1 deletion pinax/notifications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@

import base64


from django.utils import timezone
from django.db import models
from django.db.models.query import QuerySet
from django.core.exceptions import ImproperlyConfigured
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import get_language, activate
from django.utils.encoding import python_2_unicode_compatible
from django.utils.six.moves import cPickle as pickle # pylint: disable-msg=F
from django.core.urlresolvers import reverse

from django.contrib.contenttypes.models import ContentType

Expand Down Expand Up @@ -79,7 +82,7 @@ class NoticeSetting(models.Model):

user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_("user"))
notice_type = models.ForeignKey(NoticeType, verbose_name=_("notice type"))
medium = models.CharField(_("medium"), max_length=1, choices=NOTICE_MEDIA)
medium = models.CharField(_("medium"), max_length=100, choices=NOTICE_MEDIA)
send = models.BooleanField(_("send"), default=False)
scoping_content_type = models.ForeignKey(ContentType, null=True, blank=True)
scoping_object_id = models.PositiveIntegerField(null=True, blank=True)
Expand All @@ -100,6 +103,98 @@ class Meta:
unique_together = ("user", "notice_type", "medium", "scoping_content_type", "scoping_object_id")


class NoticeManager(models.Manager):
def notices_for(self, user, archived=False, unseen=None, on_site=None,
sent=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 unseen=None, it includes all notices.
If unseen=True, return only unseen notices.
If unseen=False, return only seen notices.
"""
if sent:
lookup_kwargs = {"sender": user}
else:
lookup_kwargs = {"recipient": user}
qs = self.filter(**lookup_kwargs)
if not archived:
self.filter(archived=archived)
if unseen is not None:
qs = qs.filter(unseen=unseen)
if on_site is not None:
qs = qs.filter(on_site=on_site)
return qs

def unseen_count_for(self, recipient, **kwargs):
"""
returns the number of unseen notices for the given user but does not
mark them seen
"""
return self.notices_for(recipient, unseen=True, **kwargs).count()

def received(self, recipient, **kwargs):
"""
returns notices the given recipient has recieved.
"""
kwargs["sent"] = False
return self.notices_for(recipient, **kwargs)

def sent(self, sender, **kwargs):
"""
returns notices the given sender has sent
"""
kwargs["sent"] = True
return self.notices_for(sender, **kwargs)


class Notice(models.Model):
recipient = models.ForeignKey(
settings.AUTH_USER_MODEL, related_name="received_notices",
verbose_name=_("recipient"))
sender = models.ForeignKey(
settings.AUTH_USER_MODEL, null=True, related_name="sent_notices",
verbose_name=_("sender"))
message = models.TextField(_("message"))
notice_type = models.ForeignKey(NoticeType, verbose_name=_("notice type"))
added = models.DateTimeField(_("added"), db_index=True, default=timezone.now)
unseen = models.BooleanField(_("unseen"), db_index=True, default=True)
archived = models.BooleanField(_("archived"), default=False)
on_site = models.BooleanField(_("on site"), default=False)

objects = NoticeManager()

def __unicode__(self):
return self.message

def archive(self):
self.archived = True
self.save()

def is_unseen(self):
"""
returns value of self.unseen but also changes it to false.
Use this in a template to mark an unseen notice differently the first
time it is shown.
"""
unseen = self.unseen
if unseen:
self.unseen = False
self.save()
return unseen

class Meta:
verbose_name = _("notice")
verbose_name_plural = _("notices")

def get_absolute_url(self):
return reverse("notification_notice", args=[str(self.pk)])


class NoticeQueueBatch(models.Model):
"""
A queued notice.
Expand Down
2 changes: 1 addition & 1 deletion pinax/notifications/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ def get_backend_id(backend_name):
from ..models import NOTICE_MEDIA
for bid, bname in NOTICE_MEDIA:
if bname == backend_name:
return bid
return bname
return None
8 changes: 8 additions & 0 deletions pinax/notifications/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.core.exceptions import ObjectDoesNotExist

from django.contrib.contenttypes.models import ContentType
from django.utils import importlib

from .conf import settings

Expand Down Expand Up @@ -48,3 +49,10 @@ def notice_setting_for_user(user, notice_type, medium, scoping=None):
kwargs.update({"send": default})
setting = user.noticesetting_set.create(**kwargs)
return setting


def get_class_from_path(path):
# This function is helpful to avoid circular imports.
module_name, class_name = path.rsplit(".", 1)
class_ = getattr(importlib.import_module(module_name), class_name)
return class_

1 comment on commit 32ecab7

@psychok7
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the changes that were not merged at the time from pinax#36 and brought back the Notice model from https://github.com/jtauber-archive/django-notification/blob/d50bdfb97a58529662d911fcbeb216083cee8879/notification/models.py that basically works as a log for sent notifications.

Please sign in to comment.