Permalink
Browse files

caching count of inbox

cleanup
bumped version
  • Loading branch information...
1 parent 07491b9 commit 866fa603bdc50f6c9bace43843078e778a4233cb @philippWassibauer philippWassibauer committed Apr 15, 2012
View
@@ -0,0 +1,2 @@
+*.pyc
+dist/
@@ -1,2 +1,2 @@
-VERSION = (0, 1, 28)
+VERSION = (0, 1, 29)
__version__ = '.'.join(map(str, VERSION))
@@ -1,7 +1,8 @@
-from threaded_messages.models import inbox_count_for
+from threaded_messages.models import cached_inbox_count_for
+
def inbox(request):
if request.user.is_authenticated():
- return {'messages_inbox_count': inbox_count_for(request.user)}
+ return {'messages_inbox_count': cached_inbox_count_for(request.user)}
else:
return {}
View
@@ -1,10 +1,7 @@
-import datetime
import settings as sendgrid_settings
from django import forms
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
-from django.utils.translation import ugettext_noop
-from django.contrib.auth.models import User
from .models import *
from .fields import CommaSeparatedUserField
from .utils import reply_to_thread, now
@@ -16,14 +13,15 @@
if "notification" in settings.INSTALLED_APPS:
from notification import models as notification
+
class ComposeForm(forms.Form):
"""
A simple default form for private messages.
"""
recipient = CommaSeparatedUserField(label=_(u"Recipient"))
subject = forms.CharField(label=_(u"Subject"))
body = forms.CharField(label=_(u"Body"),
- widget=forms.Textarea(attrs={'rows': '12', 'cols':'55'}))
+ widget=forms.Textarea(attrs={'rows': '12', 'cols': '55'}))
def __init__(self, *args, **kwargs):
recipient_filter = kwargs.pop('recipient_filter', None)
@@ -50,7 +48,9 @@ def save(self, sender, send=True):
sender_part.replied_at = sender_part.read_at = now()
sender_part.save()
- thread.save() #save this last, since this updates the search index
+ thread.save() # save this last, since this updates the search index
+
+ invalidate_count_cache(new_message)
#send notifications
if send and notification:
@@ -60,8 +60,8 @@ def save(self, sender, send=True):
notification.send(recipients, "received_email",
{"thread": thread,
"message": new_message}, sender=sender,
- from_email= reply_email.get_from_email(),
- headers = {'Reply-To': reply_email.get_reply_to_email()})
+ from_email=reply_email.get_from_email(),
+ headers={'Reply-To': reply_email.get_reply_to_email()})
else:
notification.send(recipients, "received_email",
{"thread": thread,
@@ -1,19 +1,23 @@
-from django.utils.html import strip_tags
-import settings as sendgrid_settings
import logging
+
+from django.utils.html import strip_tags
+
+from . import settings as sendgrid_settings
+
logger = logging.getLogger('threaded_messages')
if sendgrid_settings.THREADED_MESSAGES_USE_SENDGRID:
from sendgrid_parse_api.signals import email_received
else:
email_received = None
+
def signal_received_email(sender, sma, app_id, html, text, from_field, **kwargs):
- from utils import reply_to_thread, strip_mail # circular dependency fix
- logger.debug("Sendgrid signal receive: %s, %s, %s, %s, %s, %s"%(sender, sma, app_id,
- html, repr(text), from_field) )
+ from .utils import reply_to_thread, strip_mail
+ logger.debug("Sendgrid signal receive: %s, %s, %s, %s, %s, %s" % (sender, sma, app_id,
+ html, repr(text), from_field))
if app_id == sendgrid_settings.THREADED_MESSAGES_ID:
- body =''
+ body = ''
if text:
body = text
@@ -27,7 +31,10 @@ def signal_received_email(sender, sma, app_id, html, text, from_field, **kwargs)
thread = sma.content_object
reply_to_thread(thread, sma.user, body)
+
def start_listening():
if email_received:
logger.debug("Sendgrid start listening")
email_received.connect(signal_received_email, dispatch_uid="thm_reply")
+
+
@@ -1,16 +1,15 @@
-import datetime
from django.db import models
-from django.conf import settings
-from django.db.models import signals
-from django.db.models.query import QuerySet
from django.contrib.auth.models import User
+from django.core.cache import cache
from django.utils.translation import ugettext_lazy as _
from django.db.models import F, Q
-from django.db.models import Avg, Max, Min, Count
from .listeners import start_listening
+from .settings import INBOX_COUNT_CACHE, INBOX_COUNT_CACHE_TIME
+
start_listening()
+
class MessageManager(models.Manager):
def inbox_for(self, user, read=None, only_unreplied=None):
@@ -30,12 +29,12 @@ def inbox_for(self, user, read=None, only_unreplied=None):
else:
# unread threads are the ones that either have not been read at all or before the last message arrived
inbox = inbox.filter(Q(read_at__isnull=True)
- |Q(read_at__lt=F("thread__latest_msg__sent_at")))
+ | Q(read_at__lt=F("thread__latest_msg__sent_at")))
if only_unreplied != None:
if only_unreplied == True:
inbox = inbox.filter(Q(replied_at__isnull=True)
- |Q(replied_at__lt=F("thread__latest_msg__sent_at")))
+ | Q(replied_at__lt=F("thread__latest_msg__sent_at")))
return inbox
@@ -153,21 +152,33 @@ def others(self):
def get_next(self):
try:
- participation = Participant.objects.inbox_for(self.user).filter(thread__latest_msg__sent_at__gt=\
- self.thread.latest_msg.sent_at).reverse()[0]
+ participation = Participant.objects.inbox_for(
+ self.user
+ ).filter(
+ thread__latest_msg__sent_at__gt=self.thread.latest_msg.sent_at
+ ).reverse()[0]
return participation
except:
return None
-
def get_previous(self):
try:
- participation = Participant.objects.inbox_for(self.user).filter(thread__latest_msg__sent_at__lt=\
- self.thread.latest_msg.sent_at)[0]
+ participation = Participant.objects.inbox_for(
+ self.user
+ ).filter(
+ thread__latest_msg__sent_at__lt=self.thread.latest_msg.sent_at)[0]
return participation
except:
return None
+ def read_thread(self):
+ """
+ Marks thread as read and invalidates count cache
+ """
+ from .utils import fill_count_cache, now
+ self.read_at = now()
+ fill_count_cache(self.user)
+
def __unicode__(self):
return "%s - %s" % (str(self.user), self.thread.subject)
@@ -177,10 +188,28 @@ class Meta:
verbose_name_plural = _("participants")
-def inbox_count_for(user):
+def cached_inbox_count_for(user):
"""
returns the number of unread messages for the given user but does not
mark them seen
"""
+ count = cache.get(INBOX_COUNT_CACHE % user.pk)
+ if count:
+ return count
+ else:
+ count = inbox_count_for(user)
+ cache.set(INBOX_COUNT_CACHE % user.pk,
+ count,
+ INBOX_COUNT_CACHE_TIME)
+ return count
+
+
+def inbox_count_for(user):
return Participant.objects.inbox_for(user, read=False).count()
+
+def invalidate_count_cache(message):
+ from .utils import fill_count_cache
+ for thread in message.thread.select_related().all():
+ for participant in thread.participants.exclude(user=message.sender):
+ fill_count_cache(participant.user)
@@ -1,4 +1,7 @@
from django.conf import settings
THREADED_MESSAGES_USE_SENDGRID = getattr(settings, 'THREADED_MESSAGES_USE_SENDGRID', False)
-THREADED_MESSAGES_ID = getattr(settings, 'THREADED_MESSAGES_ID', 'm')
+THREADED_MESSAGES_ID = getattr(settings, 'THREADED_MESSAGES_ID', 'm')
+
+INBOX_COUNT_CACHE = "THREADED_MESSAGES_INBOX_COUNT_%s"
+INBOX_COUNT_CACHE_TIME = 60 * 60 * 6
@@ -1,5 +1,6 @@
from django.template import Library, Node, TemplateSyntaxError
-from threaded_messages.models import inbox_count_for
+from threaded_messages.models import cached_inbox_count_for
+
class InboxOutput(Node):
def __init__(self, varname=None):
@@ -8,15 +9,17 @@ def __init__(self, varname=None):
def render(self, context):
try:
user = context['user']
- count = inbox_count_for(user)
+ count = cached_inbox_count_for(user)
except (KeyError, AttributeError):
count = ''
+
if self.varname is not None:
context[self.varname] = count
return ""
else:
return "%s" % (count)
+
def do_print_inbox_count(parser, token):
"""
A templatetag to show the unread-count for a logged in user.
View
@@ -2,18 +2,14 @@
import HTMLParser
import datetime
import re
-from lxml.html.clean import Cleaner
from django.conf import settings
-from django.contrib.sites.models import Site
-from django.utils.encoding import force_unicode
-from django.utils.text import wrap
-from django.utils.translation import ugettext_lazy as _
-from django.template import Context, loader
-from django.template.loader import render_to_string, get_template
+from django.core.cache import cache
+from django.template import Context
+from django.template.loader import get_template
-import settings as tm_settings
-from .models import Message, Participant
+from . import settings as tm_settings
+from .models import Message, Participant, inbox_count_for, invalidate_count_cache
if "notification" in settings.INSTALLED_APPS:
@@ -34,6 +30,11 @@
now = datetime.datetime.now
+def fill_count_cache(user):
+ cache.set(tm_settings.INBOX_COUNT_CACHE % user.pk,
+ inbox_count_for(user), tm_settings.INBOX_COUNT_CACHE_TIME)
+
+
def open_message_thread(recipients, subject, template,
sender, context={}, send=True, message=None):
body = ''
@@ -75,6 +76,8 @@ def reply_to_thread(thread,sender, body):
sender_part.replied_at = sender_part.read_at = now()
sender_part.save()
+ invalidate_count_cache(new_message)
+
if notification:
for r in recipients:
if tm_settings.THREADED_MESSAGES_USE_SENDGRID:
@@ -83,7 +86,7 @@ def reply_to_thread(thread,sender, body):
{"thread": thread,
"message": new_message}, sender=sender,
from_email=reply_email.get_from_email(),
- headers = {'Reply-To': reply_email.get_reply_to_email()})
+ headers={'Reply-To': reply_email.get_reply_to_email()})
else:
notification.send([r], "received_email",
{"thread": thread,
View
@@ -79,6 +79,7 @@ def outbox(request, template_name='django_messages/inbox.html'):
'thread_list': thread_list,
}, context_instance=RequestContext(request))
+
@login_required
def trash(request, template_name='django_messages/trash.html'):
"""
@@ -93,6 +94,7 @@ def trash(request, template_name='django_messages/trash.html'):
'message_list': message_list,
}, context_instance=RequestContext(request))
+
@login_required
def compose(request, recipient=None, form_class=ComposeForm,
template_name='django_messages/compose.html', success_url=None, recipient_filter=None):
@@ -207,7 +209,6 @@ def view(request, thread_id, form_class=ReplyForm,
else:
form = form_class()
- right_now = now()
participant = get_object_or_404(Participant, thread=thread, user=request.user)
message_list = []
# in this view we want the last message last
@@ -216,7 +217,7 @@ def view(request, thread_id, form_class=ReplyForm,
if participant.read_at and message.sent_at <= participant.read_at:
unread = False
message_list.append((message, unread,))
- participant.read_at = right_now
+ participant.read_thread()
participant.save()
return render_to_response(template_name, {
'thread': thread,
@@ -290,9 +291,9 @@ def message_ajax_reply(request, thread_id,
@login_required
def recipient_search(request):
term = request.GET.get("term")
- users = User.objects.filter(Q(first_name__icontains=term)|
- Q(last_name__icontains=term)|
- Q(username__icontains=term)|
+ users = User.objects.filter(Q(first_name__icontains=term) |
+ Q(last_name__icontains=term) |
+ Q(username__icontains=term) |
Q(email__icontains=term))
if request.GET.get("format") == "json":
data = []

0 comments on commit 866fa60

Please sign in to comment.