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')