annotate accounts/stats.py @ 887:9a15f7c27526

Actually save model object upon change. This commit was tested on the comments model. Additional logging added. Added check for Markdown image references. Added TODOs after observing behavior on comments.
author Brian Neal <bgneal@gmail.com>
date Tue, 03 Feb 2015 21:09:44 -0600
parents ee87ea74d46b
children
rev   line source
bgneal@520 1 """
bgneal@520 2 This module performs user account related statistics.
bgneal@520 3
bgneal@520 4 """
bgneal@520 5 import logging
bgneal@520 6
bgneal@520 7 from django.db.models.signals import post_save
bgneal@520 8 from django.contrib.auth.models import User
bgneal@520 9
bgneal@520 10 from core.services import get_redis_connection
bgneal@520 11
bgneal@520 12
bgneal@520 13 # Redis key names
bgneal@520 14 USER_COUNT_KEY = "accounts:user_count"
bgneal@520 15 NEW_USERS_KEY = "accounts:new_users"
bgneal@520 16
bgneal@520 17
bgneal@520 18 logger = logging.getLogger(__name__)
bgneal@520 19
bgneal@520 20
bgneal@520 21 def on_user_save(sender, **kwargs):
bgneal@520 22 """
bgneal@520 23 This function is our signal handler for when a User object is saved.
bgneal@520 24
bgneal@520 25 """
bgneal@520 26 from accounts.tasks import user_stats_task
bgneal@520 27
bgneal@520 28 if kwargs['created']:
bgneal@520 29 user = kwargs['instance']
bgneal@520 30
bgneal@520 31 # kick off a task to update user stats
bgneal@520 32
bgneal@520 33 user_stats_task.delay(user.id)
bgneal@520 34
bgneal@520 35
bgneal@520 36 def update_user_stats(user_id):
bgneal@520 37 """
bgneal@520 38 This function is given a new user id and is responsible for updating various
bgneal@520 39 user account statistics.
bgneal@520 40
bgneal@520 41 """
bgneal@520 42 try:
bgneal@520 43 user = User.objects.get(pk=user_id)
bgneal@520 44 except User.DoesNotExist:
bgneal@520 45 logger.warning("update_user_stats: user id %d doesn't exist", user_id)
bgneal@520 46 return
bgneal@520 47
bgneal@520 48 redis = get_redis_connection()
bgneal@520 49
bgneal@520 50 # update the count of registered users
bgneal@520 51
bgneal@520 52 count = redis.incr(USER_COUNT_KEY)
bgneal@520 53 if count == 1:
bgneal@520 54 # it is likely redis got wiped out; update it now
bgneal@520 55 count = User.objects.all().count()
bgneal@520 56 redis.set(USER_COUNT_KEY, count)
bgneal@520 57
bgneal@520 58 # update the list of new users
bgneal@520 59
bgneal@520 60 pipeline = redis.pipeline()
bgneal@520 61 pipeline.lpush(NEW_USERS_KEY, user.username)
bgneal@520 62 pipeline.ltrim(NEW_USERS_KEY, 0, 9)
bgneal@520 63 pipeline.execute()
bgneal@520 64
bgneal@520 65
bgneal@520 66 def get_user_count(redis=None):
bgneal@520 67 """
bgneal@520 68 This function returns the current count of users.
bgneal@520 69
bgneal@520 70 """
bgneal@520 71 if redis is None:
bgneal@520 72 redis = get_redis_connection()
bgneal@520 73 return redis.get(USER_COUNT_KEY)
bgneal@520 74
bgneal@520 75
bgneal@520 76 def get_new_users(redis=None):
bgneal@520 77 """
bgneal@520 78 This function returns a list of new usernames.
bgneal@520 79
bgneal@520 80 """
bgneal@520 81 if redis is None:
bgneal@520 82 redis = get_redis_connection()
bgneal@520 83 return redis.lrange(NEW_USERS_KEY, 0, -1)
bgneal@520 84
bgneal@520 85
bgneal@520 86 def get_user_stats(redis=None):
bgneal@520 87 """
bgneal@520 88 This function returns a tuple of the user stats. Element 0 is the user count
bgneal@520 89 and element 1 is the list of new users.
bgneal@520 90
bgneal@520 91 """
bgneal@520 92 if redis is None:
bgneal@520 93 redis = get_redis_connection()
bgneal@520 94 return get_user_count(redis), get_new_users(redis)
bgneal@520 95
bgneal@520 96
bgneal@520 97 post_save.connect(on_user_save, sender=User, dispatch_uid='accounts.stats')