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 | 52 | from result import ResultAPI |
| 53 | 53 | from pybossa.core import project_repo, task_repo |
| 54 | 54 | from pybossa.contributions_guard import ContributionsGuard |
| 55 | +from pybossa.cache import users as cached_users | |
| 55 | 56 | |
| 56 | 57 | blueprint = Blueprint('api', __name__) |
| 57 | 58 | |
| ... | ... | @@ -182,3 +183,13 @@ def user_progress(project_id=None, short_name=None): |
| 182 | 183 | return abort(404) |
| 183 | 184 | else: # pragma: no cover |
| 184 | 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 | 62 | top_users.append(user) |
| 63 | 63 | if (user_id is not None): |
| 64 | 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 | 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 | 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 | 164 | @memoize(timeout=timeouts.get('USER_TIMEOUT')) |
| 106 | 165 | def get_user_summary(name): | ... | ... |
pybossa/core.py
| ... | ... | @@ -573,6 +573,7 @@ def setup_cache_timeouts(app): |
| 573 | 573 | timeouts['USER_TIMEOUT'] = app.config['USER_TIMEOUT'] |
| 574 | 574 | timeouts['USER_TOP_TIMEOUT'] = app.config['USER_TOP_TIMEOUT'] |
| 575 | 575 | timeouts['USER_TOTAL_TIMEOUT'] = app.config['USER_TOTAL_TIMEOUT'] |
| 576 | + timeouts['LEADERBOARD_TIMEOUT'] = app.config['LEADERBOARD_TIMEOUT'] | |
| 576 | 577 | |
| 577 | 578 | |
| 578 | 579 | def setup_scheduled_jobs(app): # pragma: no cover | ... | ... |
pybossa/default_settings.py
| ... | ... | @@ -81,6 +81,7 @@ CATEGORY_TIMEOUT = 24 * 60 * 60 |
| 81 | 81 | USER_TIMEOUT = 15 * 60 |
| 82 | 82 | USER_TOP_TIMEOUT = 24 * 60 * 60 |
| 83 | 83 | USER_TOTAL_TIMEOUT = 24 * 60 * 60 |
| 84 | +LEADERBOARD_TIMEOUT = 5 * 60 | |
| 84 | 85 | |
| 85 | 86 | # Project Presenters |
| 86 | 87 | PRESENTERS = ["basic", "image", "sound", "video", "map", "pdf"] | ... | ... |