From fef2e2fe232cc5a3fd3b7ad57a664e86f8ef0824 Mon Sep 17 00:00:00 2001 From: Adabriand Furtado Date: Sat, 18 Jun 2016 15:53:54 -0300 Subject: [PATCH] Adicionado um método na API para recuperar os rankings dos projetos. --- pybossa/api/__init__.py | 11 +++++++++++ pybossa/cache/users.py | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------- pybossa/core.py | 1 + pybossa/default_settings.py | 1 + 4 files changed, 107 insertions(+), 35 deletions(-) diff --git a/pybossa/api/__init__.py b/pybossa/api/__init__.py index a14a70b..29738fb 100644 --- a/pybossa/api/__init__.py +++ b/pybossa/api/__init__.py @@ -52,6 +52,7 @@ from token import TokenAPI from result import ResultAPI from pybossa.core import project_repo, task_repo from pybossa.contributions_guard import ContributionsGuard +from pybossa.cache import users as cached_users blueprint = Blueprint('api', __name__) @@ -182,3 +183,13 @@ def user_progress(project_id=None, short_name=None): return abort(404) else: # pragma: no cover return abort(404) + +@jsonpify +@blueprint.route('/leaderboard') +@crossdomain(origin='*', headers=cors_headers) +@ratelimit(limit=ratelimits.get('LIMIT'), per=ratelimits.get('PER')) +def leaderboard(limit=None): + user_id = None if current_user.is_anonymous() else current_user.id + limit = request.args.get('limit') + data = cached_users.get_complete_leaderboard(n=limit, user_id=user_id) + return Response(json.dumps(data), mimetype="application/json") diff --git a/pybossa/cache/users.py b/pybossa/cache/users.py index 78f087f..1b66cfa 100644 --- a/pybossa/cache/users.py +++ b/pybossa/cache/users.py @@ -62,45 +62,104 @@ def get_leaderboard(n, user_id=None): top_users.append(user) if (user_id is not None): if not user_in_top: - sql = text(''' - WITH global_rank AS ( - WITH scores AS ( - SELECT user_id, COUNT(*) AS score FROM task_run - WHERE user_id IS NOT NULL GROUP BY user_id) - SELECT user_id, score, rank() OVER - (ORDER BY score desc) - FROM scores) - SELECT rank, id, name, fullname, email_addr, info, created, - score FROM global_rank - JOIN public."user" on (user_id=public."user".id) - WHERE user_id=:user_id ORDER BY rank; - ''') - user_rank = session.execute(sql, dict(user_id=user_id)) - u = User.query.get(user_id) - # Load by default user data with no rank - user = dict( - rank=-1, - id=u.id, - name=u.name, - fullname=u.fullname, - email_addr=u.email_addr, - info=u.info, - created=u.created, - score=-1) - for row in user_rank: # pragma: no cover - user = dict( - rank=row.rank, - id=row.id, - name=row.name, - fullname=row.fullname, - email_addr=row.email_addr, - info=row.info, - created=row.created, - score=row.score) + user = get_user_leaderboard_data(user_id) top_users.append(user) + return top_users +def get_user_leaderboard_data(user_id, project_id=None): + filter_by_project = '' if project_id is None else 'AND task_run.project_id =:project_id' + sql = text(''' + WITH global_rank AS ( + WITH scores AS ( + SELECT user_id, COUNT(*) AS score FROM task_run + WHERE user_id IS NOT NULL %s + GROUP BY user_id) + SELECT user_id, score, rank() OVER + (ORDER BY score desc) + FROM scores) + SELECT rank, id, name, fullname, email_addr, info, created, + score FROM global_rank + JOIN public."user" on (user_id=public."user".id) + WHERE user_id=:user_id ORDER BY rank; + ''' % (filter_by_project)) + + user_rank = session.execute(sql, dict(user_id=user_id, project_id=project_id)) + u = User.query.get(user_id) + # Load by default user data with no rank + user = dict( + rank=0, + id=u.id, + name=u.name, + fullname=u.fullname, + email_addr=u.email_addr, + info=u.info, + created=u.created, + score=0) + for row in user_rank: # pragma: no cover + user = dict( + rank=row.rank, + id=row.id, + name=row.name, + fullname=row.fullname, + email_addr=row.email_addr, + info=row.info, + created=row.created, + score=row.score) + return user + +@memoize(timeout=timeouts.get('LEADERBOARD_TIMEOUT')) +def get_leaderboard_by_project_id(project_id, n=None, user_id=None): + """Return the top n users with their rank.""" + sql = text(''' + WITH global_rank AS ( + WITH scores AS ( + SELECT user_id, COUNT(*) AS score FROM task_run + WHERE user_id IS NOT NULL AND task_run.project_id =:project_id GROUP BY user_id) + SELECT user_id, score, rank() OVER (ORDER BY score desc) + FROM scores) + SELECT rank, id, name, fullname, score FROM global_rank + JOIN public."user" on (user_id=public."user".id) ORDER BY rank + LIMIT :limit; + ''') + results = session.execute(sql, dict(project_id=project_id, limit=n)) + + top_users = [] + user_in_top = False + for row in results: + if (row.id == user_id): + user_in_top = True + user = dict( + rank=row.rank, + name=row.name, + fullname=row.fullname, + score=row.score) + top_users.append(user) + if (user_id is not None and not user_in_top): + user_data = get_user_leaderboard_data(user_id, project_id) + user = dict( + rank=user_data['rank'], + name=user_data['name'], + fullname=user_data['fullname'], + score=user_data['score']) + top_users.append(user) return top_users +@memoize(timeout=timeouts.get('LEADERBOARD_TIMEOUT')) +def get_complete_leaderboard(n=None, user_id=None): + """Return all projects.""" + sql = text(''' + SELECT id, short_name FROM project + ''') + results = session.execute(sql) + + complete_leaderboard = [] + for row in results: + leaderboard = dict() + leaderboard['project_name'] = row.short_name + leaderboard['leaderboard'] = get_leaderboard_by_project_id(row.id, n, user_id) + complete_leaderboard.append(leaderboard) + return complete_leaderboard + @memoize(timeout=timeouts.get('USER_TIMEOUT')) def get_user_summary(name): diff --git a/pybossa/core.py b/pybossa/core.py index 745216b..6d449f6 100644 --- a/pybossa/core.py +++ b/pybossa/core.py @@ -573,6 +573,7 @@ def setup_cache_timeouts(app): timeouts['USER_TIMEOUT'] = app.config['USER_TIMEOUT'] timeouts['USER_TOP_TIMEOUT'] = app.config['USER_TOP_TIMEOUT'] timeouts['USER_TOTAL_TIMEOUT'] = app.config['USER_TOTAL_TIMEOUT'] + timeouts['LEADERBOARD_TIMEOUT'] = app.config['LEADERBOARD_TIMEOUT'] def setup_scheduled_jobs(app): # pragma: no cover diff --git a/pybossa/default_settings.py b/pybossa/default_settings.py index 41da2d5..b932dd3 100644 --- a/pybossa/default_settings.py +++ b/pybossa/default_settings.py @@ -81,6 +81,7 @@ CATEGORY_TIMEOUT = 24 * 60 * 60 USER_TIMEOUT = 15 * 60 USER_TOP_TIMEOUT = 24 * 60 * 60 USER_TOTAL_TIMEOUT = 24 * 60 * 60 +LEADERBOARD_TIMEOUT = 5 * 60 # Project Presenters PRESENTERS = ["basic", "image", "sound", "video", "map", "pdf"] -- libgit2 0.21.2