# HG changeset patch # User Brian Neal # Date 1278385340 0 # Node ID 423c39ee44e05910bc12188cd528e8866f870f70 # Parent 405468b8e3b9acedb34da8c990ddc8180fb5248c Rework the who's online middleware and template tag for #87. diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/core/functions.py --- a/gpp/core/functions.py Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/core/functions.py Tue Jul 06 03:02:20 2010 +0000 @@ -1,5 +1,6 @@ """This file houses various core utility functions for GPP""" import datetime +import re import django.core.mail from django.contrib.sites.models import Site @@ -65,3 +66,17 @@ year_range = "%d - %d" % (BASE_YEAR, curr_year) return 'Copyright (C) %s, SurfGuitar101.com' % year_range + + +IP_PAT = re.compile('(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})') + +def get_ip(request): + """Returns the IP from the request or None if it cannot be retrieved.""" + ip = request.META.get('HTTP_X_FORWARDED_FOR', + request.META.get('REMOTE_ADDR')) + + if ip: + match = IP_PAT.match(ip) + ip = match.group(1) if match else None + + return ip diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/core/middleware.py --- a/gpp/core/middleware.py Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/core/middleware.py Tue Jul 06 03:02:20 2010 +0000 @@ -1,5 +1,13 @@ """Common middleware for the entire project.""" +import datetime + from django.contrib.auth import logout +from django.conf import settings + +from core.models import UserLastVisit +from core.models import AnonLastVisit +from core.functions import get_ip + class InactiveUserMiddleware(object): """ @@ -10,7 +18,59 @@ Idea taken from: http://djangosnippets.org/snippets/1105/ """ - def process_request(self, request): + def process_view(self, request, view_func, view_args, view_kwargs): if request.user.is_authenticated() and not request.user.is_active: logout(request) + +ONLINE_COOKIE = 'sg101_online' # online cookie name +ONLINE_TIMEOUT = 10 * 60 # online cookie lifetime in seconds + +class WhosOnline(object): + """ + This middleware class keeps track of which registered users have + been seen recently, and the number of unique unregistered users. + This middleware should come after the authentication middleware, + as we count on the user attribute being attached to the request. + """ + + def process_response(self, request, response): + """ + Keep track of who is online. + """ + if request.is_ajax(): + return + + if request.user.is_authenticated(): + if request.COOKIES.get(ONLINE_COOKIE) is None: + # update the last seen timestamp + try: + ulv = UserLastVisit.objects.get(user=request.user) + except UserLastVisit.DoesNotExist: + ulv = UserLastVisit(user=request.user) + + ulv.last_visit = datetime.datetime.now() + ulv.save() + + # set a cookie to expire in 10 minutes or so + response.set_cookie(ONLINE_COOKIE, '1', max_age=ONLINE_TIMEOUT) + else: + if request.COOKIES.get(settings.CSRF_COOKIE_NAME) is not None: + # We have a non-authenticated user that has cookies enabled. This + # means we can track them. + if request.COOKIES.get(ONLINE_COOKIE) is None: + # update the timestamp for this anonymous visitor + ip = get_ip(request) + if ip: + try: + alv = AnonLastVisit.objects.get(ip=ip) + except AnonLastVisit.DoesNotExist: + alv = AnonLastVisit(ip=ip) + + alv.last_visit = datetime.datetime.now() + alv.save() + + # set a cookie to expire in 10 minutes or so + response.set_cookie(ONLINE_COOKIE, '1', max_age=ONLINE_TIMEOUT) + + return response diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/core/models.py --- a/gpp/core/models.py Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/core/models.py Tue Jul 06 03:02:20 2010 +0000 @@ -1,5 +1,24 @@ """ This file contains the core Models used in gpp -(None at this time). """ +from django.db import models +from django.contrib import auth + +class UserLastVisit(models.Model): + """ + This model represents timestamps indicating a user's last visit to the + site. + """ + user = models.ForeignKey(auth.models.User, unique=True) + last_visit = models.DateTimeField(db_index=True) + + +class AnonLastVisit(models.Model): + """ + This model represents timestamps for the last visit from non-authenticated + users. + """ + ip = models.CharField(max_length=16, db_index=True, unique=True) + last_visit = models.DateTimeField(db_index=True) + diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/core/templatetags/core_tags.py --- a/gpp/core/templatetags/core_tags.py Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/core/templatetags/core_tags.py Tue Jul 06 03:02:20 2010 +0000 @@ -1,8 +1,14 @@ """ Miscellaneous/utility template tags. """ +import datetime + from django import template from django.conf import settings +from django.core.cache import cache + +from core.models import UserLastVisit, AnonLastVisit + register = template.Library() @@ -21,3 +27,30 @@ @register.inclusion_tag('core/comment_dialogs.html') def comment_dialogs(): return {'MEDIA_URL': settings.MEDIA_URL} + + +@register.inclusion_tag('core/whos_online_tag.html') +def whos_online(): + """ + Displays a list of who is online. + """ + info = cache.get('whos_online') + if info: + return info + + now = datetime.datetime.now() + cutoff = now - datetime.timedelta(minutes=10, seconds=5) + + info = {} + users = UserLastVisit.objects.filter( + last_visit__gte=cutoff).values_list('user__username', flat=True) + num_users = len(users) + info['num_users'] = num_users + info['users'] = sorted(users) + + num_guests = AnonLastVisit.objects.filter(last_visit__gte=cutoff).count() + info['num_guests'] = num_guests + info['total'] = num_users + num_guests + + cache.set('whos_online', info, 300) + return info diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/forums/middleware.py --- a/gpp/forums/middleware.py Thu Jun 10 03:31:57 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -""" -Middleware for the forums application. -""" -import datetime - -from django.core.cache import cache -from django.conf import settings - - -USER_ONLINE_TIMEOUT = datetime.timedelta(minutes=15) -USERS_ONLINE_KEY = 'users_online' -GUESTS_ONLINE_KEY = 'guests_online' -USERS_CACHE_TIMEOUT = 60 * 60 * 24 # units are seconds - - -class WhosOnline(object): - """ - This middleware class keeps track of which registered users have - been seen recently, and the number of unique unregistered users. - We use the Django cache system to store this information. - This middleware should come after the authentication middleware, - as we count on the user attribute being attached to the request. - """ - - def process_request(self, request): - """ - Keep track of who is online. - """ - now = datetime.datetime.now() - cutoff = now - USER_ONLINE_TIMEOUT - users_online = cache.get(USERS_ONLINE_KEY, {}) - guests_online = cache.get(GUESTS_ONLINE_KEY, {}) - - # update timestamp for user - if request.user.is_authenticated(): - users_online[request.user.username] = now - else: - sid = request.COOKIES.get(settings.SESSION_COOKIE_NAME, '') - guests_online[sid] = now - - # expire old records - for username, timestamp in users_online.items(): - if timestamp < cutoff: - del users_online[username] - - for sid, timestamp in guests_online.items(): - if timestamp < cutoff: - del guests_online[sid] - - cache.set(USERS_ONLINE_KEY, users_online, USERS_CACHE_TIMEOUT) - cache.set(GUESTS_ONLINE_KEY, guests_online, USERS_CACHE_TIMEOUT) diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/forums/templatetags/forum_tags.py --- a/gpp/forums/templatetags/forum_tags.py Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/forums/templatetags/forum_tags.py Tue Jul 06 03:02:20 2010 +0000 @@ -128,26 +128,6 @@ } -@register.inclusion_tag('forums/whos_online_tag.html') -def whos_online(): - """ - Displays a list of who is online. - """ - users_online = cache.get('users_online', {}) - guests_online = cache.get('guests_online', {}) - num_users = len(users_online) - num_guests = len(guests_online) - total = num_users + num_guests - users = sorted(users_online.keys()) - - return { - 'num_users': num_users, - 'num_guests': num_guests, - 'total': total, - 'users': users, - } - - @register.inclusion_tag('forums/forum_stats_tag.html') def forum_stats(): """ diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/settings.py --- a/gpp/settings.py Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/settings.py Tue Jul 06 03:02:20 2010 +0000 @@ -82,7 +82,7 @@ 'debug_toolbar.middleware.DebugToolbarMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'gpp.core.middleware.InactiveUserMiddleware', - 'gpp.forums.middleware.WhosOnline', + 'gpp.core.middleware.WhosOnline', 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware', ) else: @@ -93,7 +93,7 @@ 'django.contrib.messages.middleware.MessageMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'gpp.core.middleware.InactiveUserMiddleware', - 'gpp.forums.middleware.WhosOnline', + 'gpp.core.middleware.WhosOnline', 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware', ) diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/templates/core/whos_online_tag.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/core/whos_online_tag.html Tue Jul 06 03:02:20 2010 +0000 @@ -0,0 +1,11 @@ +
+There {{ total|pluralize:"is,are"}} {{ total }} user{{ total|pluralize }} online: {{ num_users }} registered user{{ num_users|pluralize }} and {{ num_guests }} guest{{ num_guests|pluralize }}. +{% if num_users %} +Registered users: + +{% endif %} +
diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/templates/forums/index.html --- a/gpp/templates/forums/index.html Thu Jun 10 03:31:57 2010 +0000 +++ b/gpp/templates/forums/index.html Tue Jul 06 03:02:20 2010 +0000 @@ -1,6 +1,7 @@ {% extends 'base.html' %} {% load cache %} {% load forum_tags %} +{% load core_tags %} {% block custom_head %} {% for feed in feeds %} diff -r 405468b8e3b9 -r 423c39ee44e0 gpp/templates/forums/whos_online_tag.html --- a/gpp/templates/forums/whos_online_tag.html Thu Jun 10 03:31:57 2010 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -
-There {{ total|pluralize:"is,are"}} {{ total }} user{{ total|pluralize }} online: {{ num_users }} registered user{{ num_users|pluralize }} and {{ num_guests }} guest{{ num_guests|pluralize }}. -{% if num_users %} -Registered users: - -{% endif %} -