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"] |