nuke old hotfix
This commit is contained in:
parent
0a7105213a
commit
80a53a17fb
2 changed files with 0 additions and 907 deletions
|
@ -1,897 +0,0 @@
|
||||||
import random
|
|
||||||
import transaction
|
|
||||||
import types
|
|
||||||
import sqlalchemy as sa
|
|
||||||
import velruse
|
|
||||||
import json as _json
|
|
||||||
import StringIO
|
|
||||||
import qrcode as qrcode_module
|
|
||||||
import docutils.examples
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from mako.template import Template as t
|
|
||||||
from pyramid.view import (
|
|
||||||
view_config,
|
|
||||||
forbidden_view_config,
|
|
||||||
)
|
|
||||||
|
|
||||||
from pyramid.response import Response
|
|
||||||
from pyramid.httpexceptions import (
|
|
||||||
HTTPFound,
|
|
||||||
HTTPGone,
|
|
||||||
HTTPNotFound,
|
|
||||||
HTTPForbidden,
|
|
||||||
)
|
|
||||||
|
|
||||||
from pyramid.security import (
|
|
||||||
authenticated_userid,
|
|
||||||
effective_principals,
|
|
||||||
remember,
|
|
||||||
forget,
|
|
||||||
)
|
|
||||||
from pyramid.settings import asbool
|
|
||||||
|
|
||||||
from tahrir_api.dbapi import TahrirDatabase
|
|
||||||
import tahrir_api.model as m
|
|
||||||
|
|
||||||
from tahrir.utils import strip_tags, generate_badge_yaml
|
|
||||||
import widgets
|
|
||||||
|
|
||||||
from moksha.wsgi.widgets.api import get_moksha_socket, LiveWidget
|
|
||||||
|
|
||||||
# Optional. Emit messages to the fedmsg bus.
|
|
||||||
fedmsg = None
|
|
||||||
try:
|
|
||||||
import fedmsg
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='admin', renderer='admin.mak', permission='admin')
|
|
||||||
def admin(request):
|
|
||||||
|
|
||||||
settings = request.registry.settings
|
|
||||||
|
|
||||||
# TODO: Check if I even need this anymore... leaving for now.
|
|
||||||
request.session['came_from'] = request.route_url('admin')
|
|
||||||
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# Handle any admin actions. These are done through POSTS via the
|
|
||||||
# HTML forms on the admin panel.
|
|
||||||
if request.POST:
|
|
||||||
if request.POST.get('add-person'):
|
|
||||||
# Email is a required field on the HTML form.
|
|
||||||
# Add a Badge to the DB.
|
|
||||||
request.db.add_person(request.POST.get('person-email'),
|
|
||||||
nickname=request.POST.get(
|
|
||||||
'person-nickname'),
|
|
||||||
website=request.POST.get(
|
|
||||||
'person-website'),
|
|
||||||
bio=request.POST.get(
|
|
||||||
'person-bio'))
|
|
||||||
elif request.POST.get('add-badge'):
|
|
||||||
# Add a Badge to the DB.
|
|
||||||
request.db.add_badge(request.POST.get('badge-name'),
|
|
||||||
request.POST.get('badge-image'),
|
|
||||||
request.POST.get('badge-description'),
|
|
||||||
request.POST.get('badge-criteria'),
|
|
||||||
request.POST.get('badge-issuer'),
|
|
||||||
request.POST.get('badge-tags'))
|
|
||||||
elif request.POST.get('add-invitation'):
|
|
||||||
# Add an Invitation to the DB.
|
|
||||||
try:
|
|
||||||
created_on = datetime.strptime(
|
|
||||||
request.POST.get('invitation-created'),
|
|
||||||
'%Y-%m-%d %H:%M')
|
|
||||||
except ValueError:
|
|
||||||
created_on = None # Will default to datetime.now()
|
|
||||||
|
|
||||||
try:
|
|
||||||
expires_on = datetime.strptime(
|
|
||||||
request.POST.get('invitation-expires'),
|
|
||||||
'%Y-%m-%d %H:%M')
|
|
||||||
except ValueError:
|
|
||||||
expires_on = None # Will default to datettime.now()
|
|
||||||
|
|
||||||
request.db.add_invitation(
|
|
||||||
request.POST.get('invitation-badge-id'),
|
|
||||||
created_on=created_on,
|
|
||||||
expires_on=expires_on,
|
|
||||||
created_by=request.POST.get('invitation-issuer-id'))
|
|
||||||
elif request.POST.get('add-issuer'):
|
|
||||||
# Add an Issuer to the DB.
|
|
||||||
request.db.add_issuer(
|
|
||||||
request.POST.get('issuer-origin'),
|
|
||||||
request.POST.get('issuer-name'),
|
|
||||||
request.POST.get('issuer-org'),
|
|
||||||
request.POST.get('issuer-contact'))
|
|
||||||
elif request.POST.get('add-assertion'):
|
|
||||||
# Add an Assertion to the DB.
|
|
||||||
try:
|
|
||||||
issued_on = datetime.strptime(
|
|
||||||
request.POST.get('assertion-issued-on'),
|
|
||||||
'%Y-%m-%d %H:%M')
|
|
||||||
except ValueError:
|
|
||||||
issued_on = None # Will default to datetime.now()
|
|
||||||
|
|
||||||
request.db.add_assertion(
|
|
||||||
request.POST.get('assertion-badge-id'),
|
|
||||||
request.POST.get('assertion-person-email'),
|
|
||||||
issued_on)
|
|
||||||
|
|
||||||
if fedmsg and settings.get('tahrir.use_fedmsg', False):
|
|
||||||
person = request.db.get_person(
|
|
||||||
person_email=request.POST.get('assertion-person-email'))
|
|
||||||
badge = request.db.get_badge(
|
|
||||||
badge_id=request.POST.get('assertion-badge-id'))
|
|
||||||
|
|
||||||
fedmsg.publish(
|
|
||||||
modname="fedbadges", topic="badge.award",
|
|
||||||
msg=dict(
|
|
||||||
badge=dict(
|
|
||||||
name=badge.name,
|
|
||||||
description=badge.description,
|
|
||||||
image_url=badge.image,
|
|
||||||
),
|
|
||||||
user=dict(
|
|
||||||
username=person.nickname,
|
|
||||||
badges_user_id=person.id
|
|
||||||
),
|
|
||||||
))
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='home', renderer='index.mak')
|
|
||||||
def index(request):
|
|
||||||
|
|
||||||
n = 5 # n is the number of items displayed in each column.
|
|
||||||
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
# set came_from so we can get back home after openid auth.
|
|
||||||
request.session['came_from'] = request.route_url('home')
|
|
||||||
|
|
||||||
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:
|
|
||||||
top_persons[item.person] += 1
|
|
||||||
|
|
||||||
top_persons_sorted = sorted(sorted(top_persons,
|
|
||||||
key=lambda person: person.id),
|
|
||||||
key=top_persons.get,
|
|
||||||
reverse=True)
|
|
||||||
# Limit the sorted top persons to the top 10% and then take
|
|
||||||
# a random sample of 5 persons from that pool.
|
|
||||||
num_users_at_top = max(int(len(top_persons_sorted) * 0.1),
|
|
||||||
min(len(top_persons_sorted), 5))
|
|
||||||
# This is not actually a sample yet, but it's about to be...
|
|
||||||
top_persons_sample = top_persons_sorted[:num_users_at_top]
|
|
||||||
try:
|
|
||||||
top_persons_sample = random.sample(top_persons_sample, 5)
|
|
||||||
except ValueError:
|
|
||||||
# The sample is probably larger than the num of top users,
|
|
||||||
# so let's just take all the users in the top 10%, in a
|
|
||||||
# random order.
|
|
||||||
random.shuffle(top_persons_sample)
|
|
||||||
|
|
||||||
# Get latest awards.
|
|
||||||
latest_awards = persons_assertions.order_by(
|
|
||||||
sa.desc(m.Assertion.issued_on)).limit(n).all()
|
|
||||||
|
|
||||||
# Register our websocket handler callback
|
|
||||||
if asbool(request.registry.settings['tahrir.use_websockets']):
|
|
||||||
socket = make_websocket_handler(request.registry.settings)
|
|
||||||
socket.display()
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
latest_awards=latest_awards,
|
|
||||||
newest_persons=request.db.get_all_persons().filter(
|
|
||||||
m.Person.opt_out == False).order_by(
|
|
||||||
sa.desc(m.Person.created_on)).limit(n).all(),
|
|
||||||
top_persons=top_persons,
|
|
||||||
top_persons_sample=top_persons_sample,
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
moksha_socket=get_moksha_socket(request.registry.settings),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context=types.FunctionType, permission='admin')
|
|
||||||
def action(context, request):
|
|
||||||
|
|
||||||
# Do the action
|
|
||||||
context()
|
|
||||||
|
|
||||||
return HTTPFound(location=request.route_url('home'))
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context=m.Invitation, name='claim')
|
|
||||||
def invitation_claim(request):
|
|
||||||
""" Action that awards a person a badge after scanning a qrcode. """
|
|
||||||
|
|
||||||
settings = request.registry.settings
|
|
||||||
|
|
||||||
if request.context.expires_on < datetime.now():
|
|
||||||
return HTTPGone("That invitation is expired.")
|
|
||||||
|
|
||||||
if not authenticated_userid(request):
|
|
||||||
request.session['came_from'] = request.resource_url(
|
|
||||||
request.context, 'claim')
|
|
||||||
return HTTPFound(location=request.route_url('login'))
|
|
||||||
|
|
||||||
person = request.db.get_person(person_email=authenticated_userid(request))
|
|
||||||
|
|
||||||
# Check to see if the user already has the badge.
|
|
||||||
if request.context.badge in [a.badge for a in person.assertions]:
|
|
||||||
# TODO: Flash a message explaining that they already have the badge
|
|
||||||
return HTTPFound(location=request.route_url('home'))
|
|
||||||
|
|
||||||
result = request.db.add_assertion(request.context.badge_id,
|
|
||||||
person.email,
|
|
||||||
datetime.now())
|
|
||||||
|
|
||||||
if fedmsg and settings.get('tahrir.use_fedmsg', False):
|
|
||||||
badge = request.context.badge
|
|
||||||
fedmsg.publish(
|
|
||||||
modname="fedbadges", topic="badge.award",
|
|
||||||
msg=dict(
|
|
||||||
badge=dict(
|
|
||||||
name=badge.name,
|
|
||||||
description=badge.description,
|
|
||||||
image_url=badge.image,
|
|
||||||
),
|
|
||||||
user=dict(
|
|
||||||
username=person.nickname,
|
|
||||||
badges_user_id=person.id
|
|
||||||
),
|
|
||||||
))
|
|
||||||
|
|
||||||
# TODO -- return them to a page that auto-exports their badges.
|
|
||||||
# TODO -- flash and tell them they got the badge
|
|
||||||
return HTTPFound(location=request.route_url('home'))
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context=m.Invitation, name='qrcode')
|
|
||||||
def invitation_qrcode(request):
|
|
||||||
""" Returns a raw dummy qrcode through to the user. """
|
|
||||||
|
|
||||||
if request.context.expires_on < datetime.now():
|
|
||||||
return HTTPGone("That invitation is expired.")
|
|
||||||
|
|
||||||
target = request.resource_url(request.context, 'claim')
|
|
||||||
img = qrcode_module.make(target)
|
|
||||||
stringstream = StringIO.StringIO()
|
|
||||||
img.save(stringstream)
|
|
||||||
return Response(
|
|
||||||
body=stringstream.getvalue(),
|
|
||||||
content_type='image/png',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='leaderboard', renderer='leaderboard.mak')
|
|
||||||
def leaderboard(request):
|
|
||||||
""" Render a top users view. """
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
if authenticated_userid(request):
|
|
||||||
# Get rank.
|
|
||||||
try:
|
|
||||||
rank = top_persons_sorted.index(request.db.get_person(
|
|
||||||
person_email=authenticated_userid(
|
|
||||||
request))) + 1
|
|
||||||
except ValueError:
|
|
||||||
rank = 0
|
|
||||||
# Get percentile.
|
|
||||||
try:
|
|
||||||
percentile = (float(rank) / float(user_count)) * 100
|
|
||||||
except ZeroDivisionError:
|
|
||||||
percentile = 0
|
|
||||||
|
|
||||||
# Get a list of nearby competetors (5 users above the current
|
|
||||||
# user and 5 users ranked below).
|
|
||||||
competitors = top_persons_sorted[max(rank - 3, 0):\
|
|
||||||
min(rank + 2, len(top_persons_sorted))]
|
|
||||||
|
|
||||||
else:
|
|
||||||
rank = None
|
|
||||||
percentile = None
|
|
||||||
competitors = None
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
top_persons=top_persons,
|
|
||||||
top_persons_sorted=top_persons_sorted,
|
|
||||||
rank=rank,
|
|
||||||
user_count=user_count,
|
|
||||||
percentile=percentile,
|
|
||||||
competitors=competitors,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='explore', renderer='explore.mak')
|
|
||||||
def explore(request):
|
|
||||||
|
|
||||||
# Check if a search has been done, and if so, show
|
|
||||||
# search results.
|
|
||||||
search_results = dict() # name: link
|
|
||||||
if request.POST:
|
|
||||||
if request.POST.get('badge-search'):
|
|
||||||
# badge-query is a required field on the template form.
|
|
||||||
badge_query = request.POST.get('badge-query')
|
|
||||||
matching_results = request.db.get_all_badges().filter(
|
|
||||||
sa.func.lower(m.Badge.name).like('%' + badge_query
|
|
||||||
+ '%') |
|
|
||||||
sa.func.lower(m.Badge.description).like('%' +
|
|
||||||
badge_query +
|
|
||||||
'%') |
|
|
||||||
sa.func.lower(m.Badge.tags).like('%' +
|
|
||||||
badge_query
|
|
||||||
+ '%')).all()
|
|
||||||
for r in matching_results:
|
|
||||||
search_results[r.name] = request.route_url('badge',
|
|
||||||
id=r.name.lower().replace(' ', '-'))
|
|
||||||
elif request.POST.get('person-search'):
|
|
||||||
# person-query is a required field on the template form.
|
|
||||||
person_query = request.POST.get('person-query')
|
|
||||||
matching_results = request.db.get_all_persons().filter(
|
|
||||||
((m.Person.nickname.like('%' + person_query
|
|
||||||
+ '%')) |
|
|
||||||
(m.Person.bio.like('%' + person_query
|
|
||||||
+ '%'))) &
|
|
||||||
(m.Person.opt_out == False)).all()
|
|
||||||
for r in matching_results:
|
|
||||||
search_results[r.nickname] = request.route_url(
|
|
||||||
'user', id=r.nickname)
|
|
||||||
elif request.POST.get('tag-search'):
|
|
||||||
# tag-query is a required field on the template form.
|
|
||||||
tag_query = request.POST.get('tag-query')
|
|
||||||
if request.POST.get('tag-match-all'):
|
|
||||||
return HTTPFound(location=request.route_url(
|
|
||||||
'tags', tags=tag_query, match='all'))
|
|
||||||
else:
|
|
||||||
return HTTPFound(location=request.route_url(
|
|
||||||
'tags', tags=tag_query, match='any'))
|
|
||||||
|
|
||||||
|
|
||||||
# Get awarded assertions.
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# Get some random badges (for discovery).
|
|
||||||
try:
|
|
||||||
random_badges = random.sample(request.db.get_all_badges().all(), 5)
|
|
||||||
except ValueError: # the sample is probably larger than the population
|
|
||||||
random_badges = request.db.get_all_badges().all()
|
|
||||||
|
|
||||||
# Get some random persons (for discovery).
|
|
||||||
try:
|
|
||||||
random_persons = random.sample(request.db.get_all_persons().filter(
|
|
||||||
m.Person.opt_out == False).all(), 5)
|
|
||||||
except ValueError: # the sample is probably larger than the population
|
|
||||||
random_persons = request.db.get_all_persons().filter(
|
|
||||||
m.Person.opt_out == False).all()
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
random_badges=random_badges,
|
|
||||||
random_persons=random_persons,
|
|
||||||
search_results=search_results,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='badge', renderer='badge.mak')
|
|
||||||
def badge(request):
|
|
||||||
"""Render badge info page."""
|
|
||||||
# Get the badge to render info about.
|
|
||||||
badge_id = request.matchdict.get('id')
|
|
||||||
badge = request.db.get_badge(badge_id)
|
|
||||||
|
|
||||||
# if the badge isn't found, raise a 404
|
|
||||||
if not badge:
|
|
||||||
raise HTTPNotFound("No such badge %r" % badge_id)
|
|
||||||
|
|
||||||
# Get awarded assertions.
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# Get badge statistics.
|
|
||||||
# TODO: Perhaps abstract these statistics methods away somewhere?
|
|
||||||
try:
|
|
||||||
times_awarded = len(request.db.get_assertions_by_badge(badge_id))
|
|
||||||
last_awarded = request.db.get_all_assertions().filter(
|
|
||||||
sa.func.lower(m.Assertion.badge_id) == \
|
|
||||||
sa.func.lower(badge_id)).order_by(
|
|
||||||
sa.desc(m.Assertion.issued_on)).limit(1).one()
|
|
||||||
last_awarded_person = request.db.get_person(
|
|
||||||
id=last_awarded.person_id)
|
|
||||||
|
|
||||||
first_awarded = request.db.get_all_assertions().filter(
|
|
||||||
sa.func.lower(m.Assertion.badge_id) == \
|
|
||||||
sa.func.lower(badge_id)).order_by(
|
|
||||||
sa.asc(m.Assertion.issued_on)).limit(1).one()
|
|
||||||
first_awarded_person = request.db.get_person(
|
|
||||||
id=first_awarded.person_id)
|
|
||||||
|
|
||||||
percent_earned = float(times_awarded) / \
|
|
||||||
float(len(request.db.get_all_persons().all()))
|
|
||||||
except sa.orm.exc.NoResultFound: # This badge has never been awarded.
|
|
||||||
times_awarded = 0
|
|
||||||
last_awarded = None
|
|
||||||
last_awarded_person = None
|
|
||||||
first_awarded = None
|
|
||||||
first_awarded_person = None
|
|
||||||
percent_earned = 0
|
|
||||||
# Percent of people who have earned this badge
|
|
||||||
|
|
||||||
# Get badge description HTML from RST.
|
|
||||||
# Note: this html_body function wraps the output
|
|
||||||
# in a <divclass="document">.
|
|
||||||
badge_description_html = docutils.examples.html_body(badge.description)
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
badge=badge,
|
|
||||||
badge_description_html=badge_description_html,
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
times_awarded=times_awarded,
|
|
||||||
last_awarded=last_awarded,
|
|
||||||
last_awarded_person=last_awarded_person,
|
|
||||||
first_awarded=first_awarded,
|
|
||||||
first_awarded_person=first_awarded_person,
|
|
||||||
percent_earned=percent_earned,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _badge_json_generator(request, badge_id, badge):
|
|
||||||
try:
|
|
||||||
times_awarded = len(request.db.get_assertions_by_badge(badge_id))
|
|
||||||
|
|
||||||
last_awarded = request.db.get_all_assertions().filter(
|
|
||||||
sa.func.lower(m.Assertion.badge_id) == \
|
|
||||||
sa.func.lower(badge_id)).order_by(
|
|
||||||
sa.desc(m.Assertion.issued_on)).limit(1).one()
|
|
||||||
|
|
||||||
last_awarded_person = request.db.get_person(
|
|
||||||
id=last_awarded.person_id)
|
|
||||||
|
|
||||||
first_awarded = request.db.get_all_assertions().filter(
|
|
||||||
sa.func.lower(m.Assertion.badge_id) == \
|
|
||||||
sa.func.lower(badge_id)).order_by(
|
|
||||||
sa.asc(m.Assertion.issued_on)).limit(1).one()
|
|
||||||
|
|
||||||
first_awarded_person = request.db.get_person(
|
|
||||||
id=first_awarded.person_id)
|
|
||||||
|
|
||||||
percent_earned = float(times_awarded) / \
|
|
||||||
float(len(request.db.get_all_persons().all()))
|
|
||||||
|
|
||||||
except sa.orm.exc.NoResultFound: # This badge has never been awarded.
|
|
||||||
times_awarded = 0
|
|
||||||
last_awarded = None
|
|
||||||
last_awarded_person = None
|
|
||||||
first_awarded = None
|
|
||||||
first_awarded_person = None
|
|
||||||
percent_earned = 0
|
|
||||||
|
|
||||||
if last_awarded:
|
|
||||||
last_awarded = float(last_awarded.issued_on.strftime('%s'))
|
|
||||||
|
|
||||||
if last_awarded_person:
|
|
||||||
last_awarded_person = last_awarded_person.nickname
|
|
||||||
|
|
||||||
if first_awarded:
|
|
||||||
first_awarded = float(first_awarded.issued_on.strftime('%s'))
|
|
||||||
|
|
||||||
if first_awarded_person:
|
|
||||||
first_awarded_person = first_awarded_person.nickname
|
|
||||||
|
|
||||||
if percent_earned:
|
|
||||||
percent_earned *= 100
|
|
||||||
|
|
||||||
return {
|
|
||||||
'id': badge.id,
|
|
||||||
'name': badge.name,
|
|
||||||
'description': badge.description,
|
|
||||||
'times_awarded': times_awarded,
|
|
||||||
'last_awarded': last_awarded,
|
|
||||||
'last_awarded_person': last_awarded_person,
|
|
||||||
'first_awarded': first_awarded,
|
|
||||||
'first_awarded_person': first_awarded_person,
|
|
||||||
'percent_earned': percent_earned,
|
|
||||||
'image': badge.image
|
|
||||||
}
|
|
||||||
|
|
||||||
@view_config(route_name='badge_json', renderer='json')
|
|
||||||
def badge_json(request):
|
|
||||||
"""Render badge JSON dump."""
|
|
||||||
# Get the badge to render info about.
|
|
||||||
badge_id = request.matchdict.get('id')
|
|
||||||
badge = request.db.get_badge(badge_id)
|
|
||||||
|
|
||||||
# if the badge isn't found, raise a 404
|
|
||||||
if not badge:
|
|
||||||
request.response.status = '404 Not Found'
|
|
||||||
return {"error": "No such badge exists."}
|
|
||||||
|
|
||||||
return _badge_json_generator(request, badge_id, badge)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='user', renderer='user.mak')
|
|
||||||
def user(request):
|
|
||||||
"""Render user info page."""
|
|
||||||
|
|
||||||
# Grab a boolean out of the config
|
|
||||||
settings = request.registry.settings
|
|
||||||
allow_changenick = asbool(settings.get('tahrir.allow_changenick', True))
|
|
||||||
|
|
||||||
# Get awarded assertions.
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# 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:
|
|
||||||
raise HTTPNotFound("No such user %r" % user_id)
|
|
||||||
|
|
||||||
# If we still haven't found anything, just give up.
|
|
||||||
if not user:
|
|
||||||
raise HTTPNotFound("No such user %r" % user_id)
|
|
||||||
|
|
||||||
if user.opt_out == True and user.email != authenticated_userid(request):
|
|
||||||
raise HTTPNotFound("User %r has opted out." % user_id)
|
|
||||||
|
|
||||||
if request.POST:
|
|
||||||
|
|
||||||
# Authz check
|
|
||||||
if authenticated_userid(request) != user.email:
|
|
||||||
raise HTTPForbidden("Unauthorized")
|
|
||||||
|
|
||||||
person = request.db.get_all_persons().filter_by(
|
|
||||||
email=authenticated_userid(request)).one()
|
|
||||||
|
|
||||||
if request.POST.get('change-nickname') and allow_changenick:
|
|
||||||
new_nick = request.POST.get('new-nickname')
|
|
||||||
person.nickname = new_nick
|
|
||||||
|
|
||||||
# The user's nickname has changed, so let's go to the new URL.
|
|
||||||
return HTTPFound(location=request.route_url('user', id=new_nick))
|
|
||||||
elif request.POST.get('deactivate-account'):
|
|
||||||
person.opt_out = True
|
|
||||||
elif request.POST.get('reactivate-account'):
|
|
||||||
person.opt_out = False
|
|
||||||
|
|
||||||
# Get user badges.
|
|
||||||
user_badges = [a.badge for a in user.assertions]
|
|
||||||
|
|
||||||
# Sort user badges by id.
|
|
||||||
user_badges = sorted(user_badges, key=lambda badge: badge.id)
|
|
||||||
|
|
||||||
# Get total number of unique badges in the system.
|
|
||||||
count_total_badges = len(request.db.get_all_badges().all())
|
|
||||||
|
|
||||||
# Get percentage of badges earned.
|
|
||||||
try:
|
|
||||||
percent_earned = (float(len(user_badges)) / \
|
|
||||||
float(count_total_badges)) * 100
|
|
||||||
except ZeroDivisionError:
|
|
||||||
percent_earned = 0
|
|
||||||
|
|
||||||
# Get invitations the user has created.
|
|
||||||
invitations = [i for i in request.db.get_invitations(user.id)\
|
|
||||||
if i.expires_on > datetime.now()]
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
user=user,
|
|
||||||
user_badges=user_badges,
|
|
||||||
invitations=invitations,
|
|
||||||
percent_earned=percent_earned,
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
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."}
|
|
||||||
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(user.email)
|
|
||||||
|
|
||||||
# Get user badges.
|
|
||||||
user_badges = [a.badge for a in user.assertions]
|
|
||||||
|
|
||||||
# Sort user badges by id.
|
|
||||||
user_badges = sorted(user_badges, key=lambda badge: badge.id)
|
|
||||||
|
|
||||||
# Get total number of unique badges in the system.
|
|
||||||
count_total_badges = len(request.db.get_all_badges().all())
|
|
||||||
|
|
||||||
# Get percentage of badges earned.
|
|
||||||
try:
|
|
||||||
percent_earned = (float(len(user_badges)) / \
|
|
||||||
float(count_total_badges)) * 100
|
|
||||||
except ZeroDivisionError:
|
|
||||||
percent_earned = 0
|
|
||||||
|
|
||||||
|
|
||||||
assertions = []
|
|
||||||
for assertion in awarded_assertions:
|
|
||||||
assertions.append(
|
|
||||||
dict(
|
|
||||||
{'issued': float(assertion.issued_on.strftime('%s'))}.items() + \
|
|
||||||
_badge_json_generator(request, assertion.badge.id, assertion.badge).items()))
|
|
||||||
|
|
||||||
return {
|
|
||||||
'user': user.nickname,
|
|
||||||
'avatar': user.avatar_url(int(request.GET.get('size', 100))),
|
|
||||||
'percent_earned': percent_earned,
|
|
||||||
'assertions': assertions
|
|
||||||
}
|
|
||||||
|
|
||||||
@view_config(route_name='builder', renderer='builder.mak')
|
|
||||||
def builder(request):
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# set came_from so we can get back home after openid auth.
|
|
||||||
request.session['came_from'] = request.route_url('builder')
|
|
||||||
|
|
||||||
# get default creator field
|
|
||||||
default_creator = None
|
|
||||||
user = request.db.get_person(person_email=authenticated_userid(request))
|
|
||||||
if user:
|
|
||||||
default_creator = user.nickname or user.email
|
|
||||||
|
|
||||||
badge_yaml = None
|
|
||||||
if request.POST:
|
|
||||||
badge_yaml = generate_badge_yaml(request.POST)
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
default_creator=default_creator,
|
|
||||||
badge_yaml=badge_yaml,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='tags', renderer='tags.mak')
|
|
||||||
def tags(request):
|
|
||||||
"""Render tag page."""
|
|
||||||
|
|
||||||
# Get awarded assertions.
|
|
||||||
if authenticated_userid(request):
|
|
||||||
awarded_assertions = request.db.get_assertions_by_email(
|
|
||||||
authenticated_userid(request))
|
|
||||||
else:
|
|
||||||
awarded_assertions = None
|
|
||||||
|
|
||||||
# Get badges matching tag.
|
|
||||||
tags = [t.strip() for t in request.matchdict.get('tags').split(',')]
|
|
||||||
if request.matchdict.get('match') == 'all':
|
|
||||||
badges = request.db.get_badges_from_tags(tags, match_all=True)
|
|
||||||
else:
|
|
||||||
badges = request.db.get_badges_from_tags(tags, match_all=False)
|
|
||||||
|
|
||||||
return dict(
|
|
||||||
tags=tags,
|
|
||||||
badges=badges,
|
|
||||||
auth_principals=effective_principals(request),
|
|
||||||
awarded_assertions=awarded_assertions,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context=unicode)
|
|
||||||
def html(context, request):
|
|
||||||
return Response(context)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context=m.Assertion, renderer='json')
|
|
||||||
def json(context, request):
|
|
||||||
return context.__json__()
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context='pyramid.httpexceptions.HTTPNotFound', renderer='404.mak')
|
|
||||||
def _404(request):
|
|
||||||
request.response.status = 404
|
|
||||||
return dict()
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context='pyramid.httpexceptions.HTTPServerError',
|
|
||||||
renderer='500.mak')
|
|
||||||
def _500(request):
|
|
||||||
request.response.status = 500
|
|
||||||
return dict()
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='login', renderer='login.mak')
|
|
||||||
@forbidden_view_config(renderer='login.mak')
|
|
||||||
def login(request):
|
|
||||||
settings = request.registry.settings
|
|
||||||
ident = "openid_identifier=" + settings.get('tahrir.openid_identifier')
|
|
||||||
url = velruse.login_url(request, 'openid') + "?" + ident
|
|
||||||
return HTTPFound(location=url)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context='velruse.AuthenticationComplete')
|
|
||||||
def login_complete_view(request):
|
|
||||||
context = request.context
|
|
||||||
settings = request.registry.settings
|
|
||||||
|
|
||||||
nickname = context.profile['preferredUsername']
|
|
||||||
|
|
||||||
if asbool(settings.get('tahrir.use_openid_email')) \
|
|
||||||
and context.profile['emails']:
|
|
||||||
email = context.profile['emails'][0]
|
|
||||||
else:
|
|
||||||
ident = settings.get('tahrir.openid_identifier')
|
|
||||||
domain = '.'.join(ident.split('.')[-2:])
|
|
||||||
if domain.endswith('/'):
|
|
||||||
domain = domain[:-1]
|
|
||||||
email = nickname + "@" + domain
|
|
||||||
|
|
||||||
# Keep adding underscores until we get a default nickname
|
|
||||||
# that isn't already used.
|
|
||||||
while request.db.get_person(nickname=nickname):
|
|
||||||
nickname += '_'
|
|
||||||
|
|
||||||
if not request.db.get_person(person_email=email):
|
|
||||||
request.db.add_person(email=email, nickname=nickname)
|
|
||||||
|
|
||||||
headers = remember(request, email)
|
|
||||||
response = HTTPFound(location=request.session.get('came_from', '/'))
|
|
||||||
response.headerlist.extend(headers)
|
|
||||||
return response
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(context='velruse.AuthenticationDenied', renderer='json')
|
|
||||||
def login_denied_view(request):
|
|
||||||
# HAAACK -- if login fails, just try again.
|
|
||||||
return HTTPFound(location=request.route_url('login'))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='logout')
|
|
||||||
def logout(request):
|
|
||||||
headers = forget(request)
|
|
||||||
return HTTPFound(location=request.resource_url(request.context),
|
|
||||||
headers=headers)
|
|
||||||
|
|
||||||
|
|
||||||
@view_config(route_name='assertion_widget',
|
|
||||||
renderer='assertion_widget.mak')
|
|
||||||
def assertion_widget(request):
|
|
||||||
person_id = request.matchdict.get('person')
|
|
||||||
badge_id = request.matchdict.get('badge')
|
|
||||||
user = request.db.get_person(id=person_id)
|
|
||||||
if not user:
|
|
||||||
raise HTTPNotFound("No such person %r" % person_id)
|
|
||||||
|
|
||||||
def get_assertion():
|
|
||||||
for assertion in user.assertions:
|
|
||||||
if assertion.badge.id == badge_id:
|
|
||||||
return assertion
|
|
||||||
raise HTTPNotFound("User does not have that badge")
|
|
||||||
|
|
||||||
assertion = get_assertion()
|
|
||||||
return dict(assertion=assertion)
|
|
||||||
|
|
||||||
|
|
||||||
def make_websocket_handler(settings):
|
|
||||||
""" Add a js snippet that listens over websockets to fedmsg.
|
|
||||||
|
|
||||||
It animates the "latest awards" pane on the frontpage.
|
|
||||||
"""
|
|
||||||
|
|
||||||
class WebsocketHandler(LiveWidget):
|
|
||||||
topic = settings.get("tahrir.websocket.topic")
|
|
||||||
onmessage = """
|
|
||||||
(function(json){
|
|
||||||
// TODO -- put the DOM manipulation stuff here.
|
|
||||||
var user = json.msg.user.badges_user_id;
|
|
||||||
var badge = json.msg.badge.badge_id;
|
|
||||||
$.ajax({
|
|
||||||
url: "%s/_w/assertion/" + user + "/" + badge,
|
|
||||||
dataType: "html",
|
|
||||||
success: function (html) {
|
|
||||||
$("#latest-awards").prepend(html);
|
|
||||||
$("#latest-awards > div:first-child").hide();
|
|
||||||
$("#latest-awards > div:first-child").slideDown("slow");
|
|
||||||
$("#latest-awards > div:last-child").slideUp('slow', complete=function() {
|
|
||||||
$("#latest-awards > div:last-child").remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})(json);
|
|
||||||
""" % settings['tahrir.base_url']
|
|
||||||
backend = "websocket"
|
|
||||||
|
|
||||||
# Don't actually produce anything when you call .display() on this widget.
|
|
||||||
inline_engine_name = "mako"
|
|
||||||
template = ""
|
|
||||||
|
|
||||||
return WebsocketHandler
|
|
|
@ -43,16 +43,6 @@
|
||||||
notify:
|
notify:
|
||||||
- restart apache
|
- restart apache
|
||||||
|
|
||||||
- name: hotfix - fix badges search 500 error with postgres
|
|
||||||
copy: >
|
|
||||||
src=tahrir/views.py
|
|
||||||
dest=/usr/lib/python2.6/site-packages/tahrir/views.py
|
|
||||||
owner=root group=root mode=0644
|
|
||||||
tags:
|
|
||||||
- hotfix
|
|
||||||
notify:
|
|
||||||
- restart apache
|
|
||||||
|
|
||||||
- name: hotfix - allow velruse to do stateless openid
|
- name: hotfix - allow velruse to do stateless openid
|
||||||
copy: >
|
copy: >
|
||||||
src=openid.py
|
src=openid.py
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue