Commit fef2e2fe232cc5a3fd3b7ad57a664e86f8ef0824
1 parent
3baf5144
Exists in
master
Adicionado um método na API para recuperar os rankings dos projetos.
Showing
4 changed files
with
107 additions
and
35 deletions
Show diff stats
pybossa/api/__init__.py
| @@ -52,6 +52,7 @@ from token import TokenAPI | @@ -52,6 +52,7 @@ from token import TokenAPI | ||
| 52 | from result import ResultAPI | 52 | from result import ResultAPI |
| 53 | from pybossa.core import project_repo, task_repo | 53 | from pybossa.core import project_repo, task_repo |
| 54 | from pybossa.contributions_guard import ContributionsGuard | 54 | from pybossa.contributions_guard import ContributionsGuard |
| 55 | +from pybossa.cache import users as cached_users | ||
| 55 | 56 | ||
| 56 | blueprint = Blueprint('api', __name__) | 57 | blueprint = Blueprint('api', __name__) |
| 57 | 58 | ||
| @@ -182,3 +183,13 @@ def user_progress(project_id=None, short_name=None): | @@ -182,3 +183,13 @@ def user_progress(project_id=None, short_name=None): | ||
| 182 | return abort(404) | 183 | return abort(404) |
| 183 | else: # pragma: no cover | 184 | else: # pragma: no cover |
| 184 | return abort(404) | 185 | return abort(404) |
| 186 | + | ||
| 187 | +@jsonpify | ||
| 188 | +@blueprint.route('/leaderboard') | ||
| 189 | +@crossdomain(origin='*', headers=cors_headers) | ||
| 190 | +@ratelimit(limit=ratelimits.get('LIMIT'), per=ratelimits.get('PER')) | ||
| 191 | +def leaderboard(limit=None): | ||
| 192 | + user_id = None if current_user.is_anonymous() else current_user.id | ||
| 193 | + limit = request.args.get('limit') | ||
| 194 | + data = cached_users.get_complete_leaderboard(n=limit, user_id=user_id) | ||
| 195 | + return Response(json.dumps(data), mimetype="application/json") |
pybossa/cache/users.py
| @@ -62,45 +62,104 @@ def get_leaderboard(n, user_id=None): | @@ -62,45 +62,104 @@ def get_leaderboard(n, user_id=None): | ||
| 62 | top_users.append(user) | 62 | top_users.append(user) |
| 63 | if (user_id is not None): | 63 | if (user_id is not None): |
| 64 | if not user_in_top: | 64 | if not user_in_top: |
| 65 | - sql = text(''' | ||
| 66 | - WITH global_rank AS ( | ||
| 67 | - WITH scores AS ( | ||
| 68 | - SELECT user_id, COUNT(*) AS score FROM task_run | ||
| 69 | - WHERE user_id IS NOT NULL GROUP BY user_id) | ||
| 70 | - SELECT user_id, score, rank() OVER | ||
| 71 | - (ORDER BY score desc) | ||
| 72 | - FROM scores) | ||
| 73 | - SELECT rank, id, name, fullname, email_addr, info, created, | ||
| 74 | - score FROM global_rank | ||
| 75 | - JOIN public."user" on (user_id=public."user".id) | ||
| 76 | - WHERE user_id=:user_id ORDER BY rank; | ||
| 77 | - ''') | ||
| 78 | - user_rank = session.execute(sql, dict(user_id=user_id)) | ||
| 79 | - u = User.query.get(user_id) | ||
| 80 | - # Load by default user data with no rank | ||
| 81 | - user = dict( | ||
| 82 | - rank=-1, | ||
| 83 | - id=u.id, | ||
| 84 | - name=u.name, | ||
| 85 | - fullname=u.fullname, | ||
| 86 | - email_addr=u.email_addr, | ||
| 87 | - info=u.info, | ||
| 88 | - created=u.created, | ||
| 89 | - score=-1) | ||
| 90 | - for row in user_rank: # pragma: no cover | ||
| 91 | - user = dict( | ||
| 92 | - rank=row.rank, | ||
| 93 | - id=row.id, | ||
| 94 | - name=row.name, | ||
| 95 | - fullname=row.fullname, | ||
| 96 | - email_addr=row.email_addr, | ||
| 97 | - info=row.info, | ||
| 98 | - created=row.created, | ||
| 99 | - score=row.score) | 65 | + user = get_user_leaderboard_data(user_id) |
| 100 | top_users.append(user) | 66 | top_users.append(user) |
| 67 | + return top_users | ||
| 101 | 68 | ||
| 69 | +def get_user_leaderboard_data(user_id, project_id=None): | ||
| 70 | + filter_by_project = '' if project_id is None else 'AND task_run.project_id =:project_id' | ||
| 71 | + sql = text(''' | ||
| 72 | + WITH global_rank AS ( | ||
| 73 | + WITH scores AS ( | ||
| 74 | + SELECT user_id, COUNT(*) AS score FROM task_run | ||
| 75 | + WHERE user_id IS NOT NULL %s | ||
| 76 | + GROUP BY user_id) | ||
| 77 | + SELECT user_id, score, rank() OVER | ||
| 78 | + (ORDER BY score desc) | ||
| 79 | + FROM scores) | ||
| 80 | + SELECT rank, id, name, fullname, email_addr, info, created, | ||
| 81 | + score FROM global_rank | ||
| 82 | + JOIN public."user" on (user_id=public."user".id) | ||
| 83 | + WHERE user_id=:user_id ORDER BY rank; | ||
| 84 | + ''' % (filter_by_project)) | ||
| 85 | + | ||
| 86 | + user_rank = session.execute(sql, dict(user_id=user_id, project_id=project_id)) | ||
| 87 | + u = User.query.get(user_id) | ||
| 88 | + # Load by default user data with no rank | ||
| 89 | + user = dict( | ||
| 90 | + rank=0, | ||
| 91 | + id=u.id, | ||
| 92 | + name=u.name, | ||
| 93 | + fullname=u.fullname, | ||
| 94 | + email_addr=u.email_addr, | ||
| 95 | + info=u.info, | ||
| 96 | + created=u.created, | ||
| 97 | + score=0) | ||
| 98 | + for row in user_rank: # pragma: no cover | ||
| 99 | + user = dict( | ||
| 100 | + rank=row.rank, | ||
| 101 | + id=row.id, | ||
| 102 | + name=row.name, | ||
| 103 | + fullname=row.fullname, | ||
| 104 | + email_addr=row.email_addr, | ||
| 105 | + info=row.info, | ||
| 106 | + created=row.created, | ||
| 107 | + score=row.score) | ||
| 108 | + return user | ||
| 109 | + | ||
| 110 | +@memoize(timeout=timeouts.get('LEADERBOARD_TIMEOUT')) | ||
| 111 | +def get_leaderboard_by_project_id(project_id, n=None, user_id=None): | ||
| 112 | + """Return the top n users with their rank.""" | ||
| 113 | + sql = text(''' | ||
| 114 | + WITH global_rank AS ( | ||
| 115 | + WITH scores AS ( | ||
| 116 | + SELECT user_id, COUNT(*) AS score FROM task_run | ||
| 117 | + WHERE user_id IS NOT NULL AND task_run.project_id =:project_id GROUP BY user_id) | ||
| 118 | + SELECT user_id, score, rank() OVER (ORDER BY score desc) | ||
| 119 | + FROM scores) | ||
| 120 | + SELECT rank, id, name, fullname, score FROM global_rank | ||
| 121 | + JOIN public."user" on (user_id=public."user".id) ORDER BY rank | ||
| 122 | + LIMIT :limit; | ||
| 123 | + ''') | ||
| 124 | + results = session.execute(sql, dict(project_id=project_id, limit=n)) | ||
| 125 | + | ||
| 126 | + top_users = [] | ||
| 127 | + user_in_top = False | ||
| 128 | + for row in results: | ||
| 129 | + if (row.id == user_id): | ||
| 130 | + user_in_top = True | ||
| 131 | + user = dict( | ||
| 132 | + rank=row.rank, | ||
| 133 | + name=row.name, | ||
| 134 | + fullname=row.fullname, | ||
| 135 | + score=row.score) | ||
| 136 | + top_users.append(user) | ||
| 137 | + if (user_id is not None and not user_in_top): | ||
| 138 | + user_data = get_user_leaderboard_data(user_id, project_id) | ||
| 139 | + user = dict( | ||
| 140 | + rank=user_data['rank'], | ||
| 141 | + name=user_data['name'], | ||
| 142 | + fullname=user_data['fullname'], | ||
| 143 | + score=user_data['score']) | ||
| 144 | + top_users.append(user) | ||
| 102 | return top_users | 145 | return top_users |
| 103 | 146 | ||
| 147 | +@memoize(timeout=timeouts.get('LEADERBOARD_TIMEOUT')) | ||
| 148 | +def get_complete_leaderboard(n=None, user_id=None): | ||
| 149 | + """Return all projects.""" | ||
| 150 | + sql = text(''' | ||
| 151 | + SELECT id, short_name FROM project | ||
| 152 | + ''') | ||
| 153 | + results = session.execute(sql) | ||
| 154 | + | ||
| 155 | + complete_leaderboard = [] | ||
| 156 | + for row in results: | ||
| 157 | + leaderboard = dict() | ||
| 158 | + leaderboard['project_name'] = row.short_name | ||
| 159 | + leaderboard['leaderboard'] = get_leaderboard_by_project_id(row.id, n, user_id) | ||
| 160 | + complete_leaderboard.append(leaderboard) | ||
| 161 | + return complete_leaderboard | ||
| 162 | + | ||
| 104 | 163 | ||
| 105 | @memoize(timeout=timeouts.get('USER_TIMEOUT')) | 164 | @memoize(timeout=timeouts.get('USER_TIMEOUT')) |
| 106 | def get_user_summary(name): | 165 | def get_user_summary(name): |
pybossa/core.py
| @@ -573,6 +573,7 @@ def setup_cache_timeouts(app): | @@ -573,6 +573,7 @@ def setup_cache_timeouts(app): | ||
| 573 | timeouts['USER_TIMEOUT'] = app.config['USER_TIMEOUT'] | 573 | timeouts['USER_TIMEOUT'] = app.config['USER_TIMEOUT'] |
| 574 | timeouts['USER_TOP_TIMEOUT'] = app.config['USER_TOP_TIMEOUT'] | 574 | timeouts['USER_TOP_TIMEOUT'] = app.config['USER_TOP_TIMEOUT'] |
| 575 | timeouts['USER_TOTAL_TIMEOUT'] = app.config['USER_TOTAL_TIMEOUT'] | 575 | timeouts['USER_TOTAL_TIMEOUT'] = app.config['USER_TOTAL_TIMEOUT'] |
| 576 | + timeouts['LEADERBOARD_TIMEOUT'] = app.config['LEADERBOARD_TIMEOUT'] | ||
| 576 | 577 | ||
| 577 | 578 | ||
| 578 | def setup_scheduled_jobs(app): # pragma: no cover | 579 | def setup_scheduled_jobs(app): # pragma: no cover |
pybossa/default_settings.py
| @@ -81,6 +81,7 @@ CATEGORY_TIMEOUT = 24 * 60 * 60 | @@ -81,6 +81,7 @@ CATEGORY_TIMEOUT = 24 * 60 * 60 | ||
| 81 | USER_TIMEOUT = 15 * 60 | 81 | USER_TIMEOUT = 15 * 60 |
| 82 | USER_TOP_TIMEOUT = 24 * 60 * 60 | 82 | USER_TOP_TIMEOUT = 24 * 60 * 60 |
| 83 | USER_TOTAL_TIMEOUT = 24 * 60 * 60 | 83 | USER_TOTAL_TIMEOUT = 24 * 60 * 60 |
| 84 | +LEADERBOARD_TIMEOUT = 5 * 60 | ||
| 84 | 85 | ||
| 85 | # Project Presenters | 86 | # Project Presenters |
| 86 | PRESENTERS = ["basic", "image", "sound", "video", "map", "pdf"] | 87 | PRESENTERS = ["basic", "image", "sound", "video", "map", "pdf"] |