bgneal@520: """
bgneal@520: This module performs user account related statistics.
bgneal@520: 
bgneal@520: """
bgneal@520: import logging
bgneal@520: 
bgneal@520: from django.db.models.signals import post_save
bgneal@520: from django.contrib.auth.models import User
bgneal@520: 
bgneal@520: from core.services import get_redis_connection
bgneal@520: 
bgneal@520: 
bgneal@520: # Redis key names
bgneal@520: USER_COUNT_KEY = "accounts:user_count"
bgneal@520: NEW_USERS_KEY = "accounts:new_users"
bgneal@520: 
bgneal@520: 
bgneal@520: logger = logging.getLogger(__name__)
bgneal@520: 
bgneal@520: 
bgneal@520: def on_user_save(sender, **kwargs):
bgneal@520:     """
bgneal@520:     This function is our signal handler for when a User object is saved.
bgneal@520: 
bgneal@520:     """
bgneal@520:     from accounts.tasks import user_stats_task
bgneal@520: 
bgneal@520:     if kwargs['created']:
bgneal@520:         user = kwargs['instance']
bgneal@520: 
bgneal@520:         # kick off a task to update user stats
bgneal@520: 
bgneal@520:         user_stats_task.delay(user.id)
bgneal@520: 
bgneal@520: 
bgneal@520: def update_user_stats(user_id):
bgneal@520:     """
bgneal@520:     This function is given a new user id and is responsible for updating various
bgneal@520:     user account statistics.
bgneal@520: 
bgneal@520:     """
bgneal@520:     try:
bgneal@520:         user = User.objects.get(pk=user_id)
bgneal@520:     except User.DoesNotExist:
bgneal@520:         logger.warning("update_user_stats: user id %d doesn't exist", user_id)
bgneal@520:         return
bgneal@520: 
bgneal@520:     redis = get_redis_connection()
bgneal@520: 
bgneal@520:     # update the count of registered users
bgneal@520: 
bgneal@520:     count = redis.incr(USER_COUNT_KEY)
bgneal@520:     if count == 1:
bgneal@520:         # it is likely redis got wiped out; update it now
bgneal@520:         count = User.objects.all().count()
bgneal@520:         redis.set(USER_COUNT_KEY, count)
bgneal@520: 
bgneal@520:     # update the list of new users
bgneal@520: 
bgneal@520:     pipeline = redis.pipeline()
bgneal@520:     pipeline.lpush(NEW_USERS_KEY, user.username)
bgneal@520:     pipeline.ltrim(NEW_USERS_KEY, 0, 9)
bgneal@520:     pipeline.execute()
bgneal@520: 
bgneal@520: 
bgneal@520: def get_user_count(redis=None):
bgneal@520:     """
bgneal@520:     This function returns the current count of users.
bgneal@520: 
bgneal@520:     """
bgneal@520:     if redis is None:
bgneal@520:         redis = get_redis_connection()
bgneal@520:     return redis.get(USER_COUNT_KEY)
bgneal@520: 
bgneal@520: 
bgneal@520: def get_new_users(redis=None):
bgneal@520:     """
bgneal@520:     This function returns a list of new usernames.
bgneal@520: 
bgneal@520:     """
bgneal@520:     if redis is None:
bgneal@520:         redis = get_redis_connection()
bgneal@520:     return redis.lrange(NEW_USERS_KEY, 0, -1)
bgneal@520: 
bgneal@520: 
bgneal@520: def get_user_stats(redis=None):
bgneal@520:     """
bgneal@520:     This function returns a tuple of the user stats. Element 0 is the user count
bgneal@520:     and element 1 is the list of new users.
bgneal@520: 
bgneal@520:     """
bgneal@520:     if redis is None:
bgneal@520:         redis = get_redis_connection()
bgneal@520:     return get_user_count(redis), get_new_users(redis)
bgneal@520: 
bgneal@520: 
bgneal@520: post_save.connect(on_user_save, sender=User, dispatch_uid='accounts.stats')