From 3c8e614d30b57268db544df12831e8a7c537653e Mon Sep 17 00:00:00 2001 From: Ricky Elrod Date: Sat, 10 Aug 2013 12:20:43 -0400 Subject: [PATCH 1/3] add leaderboard json endpoint and make user json generator re-usable. --- tahrir/__init__.py | 2 ++ tahrir/views.py | 88 ++++++++++++++++++++++++++++++---------------- 2 files changed, 59 insertions(+), 31 deletions(-) diff --git a/tahrir/__init__.py b/tahrir/__init__.py index 2b531a6..bb24702 100644 --- a/tahrir/__init__.py +++ b/tahrir/__init__.py @@ -133,6 +133,8 @@ def get_db(request): config.add_route('builder', '/builder') config.add_route('explore', '/explore') config.add_route('leaderboard', '/leaderboard') + config.add_route('leaderboard_json', '/leaderboard/json') + #config.add_route('rank_json', '/leaderboard/{id}/json') config.add_route('tags', '/tags/{tags}/{match}') config.add_route('user', '/user/{id}') config.add_route('user_json', '/user/{id}/json') diff --git a/tahrir/views.py b/tahrir/views.py index fb3282e..6d71ac6 100644 --- a/tahrir/views.py +++ b/tahrir/views.py @@ -343,6 +343,30 @@ def leaderboard(request): competitors=competitors, ) +@view_config(route_name='leaderboard_json', renderer='json') +def leaderboard_json(request): + """ Render a top-users JSON dump. """ + + # Get top persons. + persons_assertions = request.db.get_all_assertions().join(m.Person) + from collections import defaultdict + top_persons = defaultdict(int) # person: assertion count + for item in persons_assertions: + top_persons[item.person] += 1 + + # top_persons and top_persons_sorted contain all persons, ordered + top_persons_sorted = sorted(sorted(top_persons, + key=lambda person: person.id), + key=top_persons.get, + reverse=True) + + # Get total user count. + user_count = len(top_persons) + + return dict( + top_persons_sorted=[_user_json_generator(request, user) for user in top_persons_sorted], + user_count=user_count, + ) @view_config(route_name='explore', renderer='explore.mak') def explore(request): @@ -646,37 +670,7 @@ def user(request): allow_changenick=allow_changenick, ) - -@view_config(route_name='user_json', renderer='json') -def user_json(request): - """Render user info JSON dump.""" - - # So, here they can use their 'id' or their 'nickname'. - # We'll try nickname first since we want to encourage that (or whatever) - # and fall back to id if that fails. If both fail, raise a 404. - user_id = request.matchdict.get('id') - - user = request.db.get_person(nickname=user_id) - - if not user: - try: - # We cast user_id to an integer so that Postgres doesn't - # get upset about comparing what is potentially a string - # to an integer column. - user = request.db.get_person(id=int(user_id)) - except TypeError: - request.response.status = '404 Not Found' - return {"error": "No such user exists."} - - # If we still haven't found anything, just give up. - if not user: - request.response.status = '404 Not Found' - return {"error": "No such user exists."} - - if user.opt_out == True and user.email != authenticated_userid(request): - request.response.status = '404 Not Found' - return {"error": "User has opted out."} - +def _user_json_generator(request, user): awarded_assertions = request.db.get_assertions_by_email(user.email) # Get user badges. @@ -710,6 +704,38 @@ def user_json(request): 'assertions': assertions } +@view_config(route_name='user_json', renderer='json') +def user_json(request): + """Render user info JSON dump.""" + + # So, here they can use their 'id' or their 'nickname'. + # We'll try nickname first since we want to encourage that (or whatever) + # and fall back to id if that fails. If both fail, raise a 404. + user_id = request.matchdict.get('id') + + user = request.db.get_person(nickname=user_id) + + if not user: + try: + # We cast user_id to an integer so that Postgres doesn't + # get upset about comparing what is potentially a string + # to an integer column. + user = request.db.get_person(id=int(user_id)) + except TypeError: + request.response.status = '404 Not Found' + return {"error": "No such user exists."} + + # If we still haven't found anything, just give up. + if not user: + request.response.status = '404 Not Found' + return {"error": "No such user exists."} + + if user.opt_out == True and user.email != authenticated_userid(request): + request.response.status = '404 Not Found' + return {"error": "User has opted out."} + + return _user_json_generator(request, user) + @view_config(route_name='builder', renderer='builder.mak') def builder(request): if authenticated_userid(request): From b951bf3efdf5585c67a31d172464eadd2a7f64d6 Mon Sep 17 00:00:00 2001 From: Ricky Elrod Date: Sat, 10 Aug 2013 12:29:31 -0400 Subject: [PATCH 2/3] respect opt-out in the json endpoint too --- tahrir/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tahrir/views.py b/tahrir/views.py index 20cfba3..61ec09f 100644 --- a/tahrir/views.py +++ b/tahrir/views.py @@ -349,7 +349,8 @@ def leaderboard_json(request): """ Render a top-users JSON dump. """ # Get top persons. - persons_assertions = request.db.get_all_assertions().join(m.Person) + persons_assertions = request.db.get_all_assertions().join(m.Person).filter( + m.Person.opt_out == False) from collections import defaultdict top_persons = defaultdict(int) # person: assertion count for item in persons_assertions: From 752b4d7a66b81b70808a4144fdedfd8e86c40a5d Mon Sep 17 00:00:00 2001 From: Ricky Elrod Date: Sat, 10 Aug 2013 12:32:18 -0400 Subject: [PATCH 3/3] limit the JSON leaderboard endpoint to 25 users, like the main endpoint --- tahrir/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tahrir/views.py b/tahrir/views.py index 61ec09f..8d3b12f 100644 --- a/tahrir/views.py +++ b/tahrir/views.py @@ -350,7 +350,7 @@ def leaderboard_json(request): # Get top persons. persons_assertions = request.db.get_all_assertions().join(m.Person).filter( - m.Person.opt_out == False) + m.Person.opt_out == False)[:25] from collections import defaultdict top_persons = defaultdict(int) # person: assertion count for item in persons_assertions: