Commit fef2e2fe232cc5a3fd3b7ad57a664e86f8ef0824

Authored by Adabriand Furtado
1 parent 3baf5144
Exists in master

Adicionado um método na API para recuperar os rankings dos projetos.

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