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