# HG changeset patch # User Brian Neal # Date 1324163955 0 # Node ID e945706756641534dea504407ac1362f79749346 # Parent f72ace06658a9fa1b21f667fdfd2ec7b06679b35 Created stats for users (number of users and list of newest users). Better separated the forums, who's online, and user stats. Use a Celery task to execute the new user stats processing. This addresses #194 and #238. diff -r f72ace06658a -r e94570675664 gpp/accounts/stats.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/accounts/stats.py Sat Dec 17 23:19:15 2011 +0000 @@ -0,0 +1,97 @@ +""" +This module performs user account related statistics. + +""" +import logging + +from django.db.models.signals import post_save +from django.contrib.auth.models import User + +from core.services import get_redis_connection + + +# Redis key names +USER_COUNT_KEY = "accounts:user_count" +NEW_USERS_KEY = "accounts:new_users" + + +logger = logging.getLogger(__name__) + + +def on_user_save(sender, **kwargs): + """ + This function is our signal handler for when a User object is saved. + + """ + from accounts.tasks import user_stats_task + + if kwargs['created']: + user = kwargs['instance'] + + # kick off a task to update user stats + + user_stats_task.delay(user.id) + + +def update_user_stats(user_id): + """ + This function is given a new user id and is responsible for updating various + user account statistics. + + """ + try: + user = User.objects.get(pk=user_id) + except User.DoesNotExist: + logger.warning("update_user_stats: user id %d doesn't exist", user_id) + return + + redis = get_redis_connection() + + # update the count of registered users + + count = redis.incr(USER_COUNT_KEY) + if count == 1: + # it is likely redis got wiped out; update it now + count = User.objects.all().count() + redis.set(USER_COUNT_KEY, count) + + # update the list of new users + + pipeline = redis.pipeline() + pipeline.lpush(NEW_USERS_KEY, user.username) + pipeline.ltrim(NEW_USERS_KEY, 0, 9) + pipeline.execute() + + +def get_user_count(redis=None): + """ + This function returns the current count of users. + + """ + if redis is None: + redis = get_redis_connection() + return redis.get(USER_COUNT_KEY) + + +def get_new_users(redis=None): + """ + This function returns a list of new usernames. + + """ + if redis is None: + redis = get_redis_connection() + return redis.lrange(NEW_USERS_KEY, 0, -1) + + +def get_user_stats(redis=None): + """ + This function returns a tuple of the user stats. Element 0 is the user count + and element 1 is the list of new users. + + """ + if redis is None: + redis = get_redis_connection() + return get_user_count(redis), get_new_users(redis) + + +post_save.connect(on_user_save, sender=User, dispatch_uid='accounts.stats') diff -r f72ace06658a -r e94570675664 gpp/accounts/tasks.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/accounts/tasks.py Sat Dec 17 23:19:15 2011 +0000 @@ -0,0 +1,16 @@ +""" +Celery tasks for the accounts application. + +""" +from celery.task import task + +from accounts.stats import update_user_stats + + +@task +def user_stats_task(user_id): + """ + Run the update_user_stats() function on a new task. + + """ + update_user_stats(user_id) diff -r f72ace06658a -r e94570675664 gpp/accounts/templatetags/accounts_tags.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/accounts/templatetags/accounts_tags.py Sat Dec 17 23:19:15 2011 +0000 @@ -0,0 +1,20 @@ +""" +Template tags for the accounts applications. + +""" +from django import template + +from accounts.stats import get_user_stats + + +register = template.Library() + + +@register.inclusion_tag('accounts/user_stats_tag.html') +def user_stats(): + """ + This tag renders the total number of site users and a list of new users. + + """ + num_users, new_users = get_user_stats() + return {'num_users': num_users, 'new_users': new_users} diff -r f72ace06658a -r e94570675664 gpp/core/templatetags/core_tags.py --- a/gpp/core/templatetags/core_tags.py Sat Dec 17 19:29:24 2011 +0000 +++ b/gpp/core/templatetags/core_tags.py Sat Dec 17 23:19:15 2011 +0000 @@ -13,7 +13,7 @@ import repoze.timeago -from core.whos_online import get_users_online, get_visitors_online +from core.whos_online import get_users_online, get_visitors_online, get_stats from bio.models import UserProfile @@ -36,10 +36,21 @@ return {'STATIC_URL': settings.STATIC_URL} +@register.inclusion_tag('core/max_users_tag.html') +def max_users(): + """ + Displays max users online information. + + """ + return { + 'stats': get_stats(), + } + @register.inclusion_tag('core/whos_online_tag.html') def whos_online(): """ Displays a list of who is online. + """ users = get_users_online() visitors = get_visitors_online() diff -r f72ace06658a -r e94570675664 gpp/forums/stats.py --- a/gpp/forums/stats.py Sat Dec 17 19:29:24 2011 +0000 +++ b/gpp/forums/stats.py Sat Dec 17 23:19:15 2011 +0000 @@ -3,31 +3,22 @@ """ from django.core.cache import cache -from django.contrib.auth.models import User from forums.models import Post -CACHE_KEY = 'forums-stats' +CACHE_KEY = 'forums-stats-2' CACHE_TIMEOUT = 4 * 60 * 60 # seconds def calc_stats(): """ This function is responsible for computing the forum statistics. - A tuple is returned: (forums post count, active user count, latest username) + The forums post count is returned. """ post_count = Post.objects.all().count() - user_count = User.objects.all().count() - - if user_count > 0: - latest_user = User.objects.filter(is_active=True).values_list( - 'username', flat=True).order_by('-date_joined')[0] - else: - latest_user = None - - return post_count, user_count, latest_user + return post_count def update_stats(): diff -r f72ace06658a -r e94570675664 gpp/forums/templatetags/forum_tags.py --- a/gpp/forums/templatetags/forum_tags.py Sat Dec 17 19:29:24 2011 +0000 +++ b/gpp/forums/templatetags/forum_tags.py Sat Dec 17 23:19:15 2011 +0000 @@ -14,7 +14,6 @@ from forums.models import Post from forums.models import Category from forums.stats import retrieve_stats -from core.whos_online import get_stats as get_core_stats register = template.Library() @@ -154,13 +153,10 @@ """ Displays forum statistics. """ - post_count, user_count, latest_user = retrieve_stats() + post_count = retrieve_stats() return { - 'stats': get_core_stats(), 'post_count': post_count, - 'user_count': user_count, - 'latest_user': latest_user, } diff -r f72ace06658a -r e94570675664 gpp/templates/accounts/user_stats_tag.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/accounts/user_stats_tag.html Sat Dec 17 23:19:15 2011 +0000 @@ -0,0 +1,16 @@ +{% load url from future %} +{% load bio_tags %} +{% load humanize %} +
+{% if num_users %} +Our site has {{ num_users|intcomma }} members. +{% endif %} +{% if new_users %} +Please welcome our newest members: + +{% endif %} +
diff -r f72ace06658a -r e94570675664 gpp/templates/core/max_users_tag.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/core/max_users_tag.html Sat Dec 17 23:19:15 2011 +0000 @@ -0,0 +1,5 @@ +
+{% if stats %} +The most users ever online was {{ stats.max_users }} on {{ stats.max_users_date|date:"P l, N d, Y" }}.
+{% endif %} +
diff -r f72ace06658a -r e94570675664 gpp/templates/core/whos_online_tag.html --- a/gpp/templates/core/whos_online_tag.html Sat Dec 17 19:29:24 2011 +0000 +++ b/gpp/templates/core/whos_online_tag.html Sat Dec 17 23:19:15 2011 +0000 @@ -1,4 +1,3 @@ -{% load url from future %} {% load bio_tags %}
There {{ total|pluralize:"is,are"}} {{ total }} user{{ total|pluralize }} online: {{ num_users }} registered user{{ num_users|pluralize }} and {{ num_guests }} guest{{ num_guests|pluralize }}. diff -r f72ace06658a -r e94570675664 gpp/templates/forums/forum_stats_tag.html --- a/gpp/templates/forums/forum_stats_tag.html Sat Dec 17 19:29:24 2011 +0000 +++ b/gpp/templates/forums/forum_stats_tag.html Sat Dec 17 23:19:15 2011 +0000 @@ -1,11 +1,5 @@ {% load url from future %} -{% load bio_tags %} {% load humanize %}
-Our {{ user_count|intcomma }} users have posted a total of {{ post_count|intcomma }} posts.
-Our newest registered user is {% profile_link latest_user '.' %} -{% if stats %} -
-The most users ever online was {{ stats.max_users }} on {{ stats.max_users_date|date:"P l, N d, Y" }}. -{% endif %} +Our users have posted a total of {{ post_count|intcomma }} posts.
diff -r f72ace06658a -r e94570675664 gpp/templates/forums/index.html --- a/gpp/templates/forums/index.html Sat Dec 17 19:29:24 2011 +0000 +++ b/gpp/templates/forums/index.html Sat Dec 17 23:19:15 2011 +0000 @@ -1,5 +1,6 @@ {% extends 'base.html' %} {% load url from future %} +{% load accounts_tags %} {% load cache %} {% load forum_tags %} {% load core_tags %} @@ -49,8 +50,12 @@
+{% user_stats %} {% cache 900 forum-stats-block %} -{% forum_stats %} + {% forum_stats %} +{% endcache %} +{% cache 900 max-users-block %} + {% max_users %} {% endcache %} {% whos_online %}

{% current_forum_time user %}