Commit daaf4fdcb352bc56e95949765d4700fb36faa971

Multiple experiments on current sweet store

  - Add Persona login, logout APIs and verfication with Persona code.
  - Added a small stats part to show the total number of sweets
  - Changed template styles to have a better UI
  - Initial version of opening each sweet in a relevant app.
The /where part of displayed sweet is a hyperlink to a relevant swtr app
(defined by the context) with the corresponding sweet as the argument.
  
44h1 { border-bottom: 2px solid #eee; }
55h2 { font-size: 1.2em; }
66
7.page { margin: 2em auto; width: 35em; border: 5px solid #ccc;
7.page { margin: 2em auto; width: 45em; border: 5px solid #ccc;
88 padding: 0.8em; background: white; }
9.entries li { margin: 0.8em 1.2em; word-wrap: break-word; }
9.entries li { margin: 0.8em 1.2em; word-wrap: break-word;
10 border: 1px solid #CCC; padding: 10px;
11 border-radius: 3px; }
1012.add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; }
1113.add-entry dl { font-weight: bold; }
1214.metanav { text-align: right; font-size: 0.8em; padding: 0.3em;
1616.flash { background: #CEE5F5; padding: 0.5em;
1717 border: 1px solid #AACBE2; }
1818.error { background: #F0D6D6; padding: 0.5em; }
19small { font-size: 0.9em; }
swtr.py
(87 / 13)
  
1616from urllib import unquote_plus
1717import json
1818import conf
19import requests
1920
2021# TODO:
2122# restify
2929# classes!
3030# sqlAlchemy
3131# Postgres
32# Persona, Auth in API endpoints
3233
3334# TODO: move this in a config file
3435# configuration
35DATABASE = 'alipiBlog'
36
37DATABASE = 'sweets_production'
3638COLLECTION_NAME = 'posts'
3739DEBUG = True
3840SECRET_KEY = conf.SECRET_KEY
4242PASSWORD = 'default'
4343DB_PORT = 27017
4444DB_HOST = 'localhost'
45URL = "http://localhost:5001"
45URL = 'http://localhost:5001'
46MOZ_PERSONA_VERIFIER = 'https://verifier.login.persona.org/verify'
47MOZ_PERSONA_AUDIENCE = 'http://localhost:5000'
4648
49appURL_map = {'img-anno': 'http://localhost:5000/?where=',
50 're-narration': 'http://y.a11y.in/web?foruri=',
51 'idh-mowl': 'http://app.swtr.us/?where=',
52 'testFromAPI': 'http://app.swtr.us/?where='}
53
4754# create our little application :)
4855# ^ ... It's going to be big now :P
4956app = Flask(__name__)
7373 return False
7474 return True
7575
76
7677def getUsers():
7778 db = g.connection[app.config['DATABASE']]
7879 coll = db['sweet_users']
8282 users.append(i['user'])
8383 return users
8484
85def gatherStats(coll):
86 stats = {}
87 stats['total_sweets'] = coll.count()
88 return stats
89
8590@app.before_request
8691def init_db():
8792 g.connection = Connection(app.config['DB_HOST'], app.config['DB_PORT'])
8893 db = g.connection[app.config['DATABASE']]
8994 g.collection = db[app.config["COLLECTION_NAME"]]
95 g.stats = gatherStats(g.collection)
9096
9197
9298@app.teardown_request
111111
112112@app.route('/')
113113def show_entries():
114 print 'request:'
115 print request.method
116 res = g.collection.find().sort('_id',direction=-1)
114 res = g.collection.find().sort('_id',direction=-1).limit(100)
117115 entries = make_list(res)
118 return render_template('show_entries.html', entries=entries)
116 return render_template('show_entries.html', entries=entries,
117 appURL_map=appURL_map, stats=g.stats)
119118
120119
121120# TODO: understand if we really need the OPTIONS
126126 if request.method == 'OPTIONS':
127127 response = make_response()
128128 response.status_code = 200
129 response.headers['Access-Control-Allow-Origin'] = '*'
129 response.headers['Access-Control-Allow-Origin'] =\
130 'http://localhost:5000'
130131 response.headers['Access-Control-Max-Age'] = '20days'
131132 response.headers['Access-Control-Allow-Headers'] = 'Origin,\
132133 X-Requested-With, Content-Type, Accept'
133134 return response
134135
135136 response = make_response()
136 response.headers['Access-Control-Allow-Origin'] = '*'
137 response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000'
137138 response.headers['Access-Control-Allow-Headers'] = 'Origin,\
138139 X-Requested-With, Content-Type, Accept'
139140 data = {}
140141 data_list = []
142
143 if 'email' in session:
144 print 'identifed user'
145 print session['email']
146 else:
147 print 'unidentified user'
148
141149 # TODO: find a better way of handling reqeust sweets
142150 try:
143151 payload = json.loads(request.form['data'])
200200def searchSweets():
201201 response = make_response()
202202 response.status_code = 200
203 response.headers['Access-Control-Allow-Origin'] = '*'
203 response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000'
204204 response.headers['Access-Control-Max-Age'] = '20days'
205205 response.headers['Access-Control-Allow-Headers'] = 'Origin,\
206206 X-Requested-With, Content-Type, Accept'
211211 reponse.status_code = 400
212212 return response
213213
214 if args['where'] is None:
215 reponse.status_code = 400
216 return response
214 #if args['where'] is None:
215 # reponse.status_code = 400
216 # return response
217217
218218 params = {}
219219
220 params['where'] = args.get('where')
220 if args.get('where'):
221 params['where'] = args.get('where')
221222 if args.get('who'):
222223 params['who'] = args.get('who')
223224 if args.get('what'):
226226 if args.get('how'):
227227 params['how'] = args.get('how')
228228
229
230 print params
229231 res = g.collection.find(params)
230232
231233 if res.count() < 1:
360360 elif request.method == "GET":
361361 return app.send_static_file("sweet-authenticate.js")
362362
363@app.route('/auth/login', methods=['POST'])
364def authLogin():
365 response = make_response()
366 response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000'
367 response.headers['Access-Control-Allow-Credentials'] = 'true'
368 response.headers['Access-Control-Max-Age'] = '20days'
369 response.headers['Access-Control-Allow-Headers'] = 'Origin,\
370 X-Requested-With, Content-Type, Accept'
371
372 if 'assertion' not in request.form:
373 response.status_code = 400
374 return response
375
376 data = {'assertion': request.form['assertion'], 'audience':
377 MOZ_PERSONA_AUDIENCE}
378 resp = requests.post(MOZ_PERSONA_VERIFIER, data=data, verify=True)
379 print resp.status_code
380 print resp.json()
381
382 if resp.ok:
383 verified_data = json.loads(resp.content)
384 if verified_data['status'] == 'okay':
385 #session.update({'email': verified_data['email']})
386 session['email'] = verified_data['email']
387 response.status_code = 200
388 response.data = {'email': verified_data['email']}
389 return response
390
391 response.status_code = 500
392 return response
393
394@app.route('/auth/logout', methods=['POST'])
395def authLogout():
396 response = make_response()
397 response.headers['Access-Control-Allow-Origin'] = 'http://localhost:5000'
398 response.headers['Access-Control-Allow-Credentials'] = 'true'
399 response.headers['Access-Control-Max-Age'] = '20days'
400 response.headers['Access-Control-Allow-Headers'] = 'Origin,\
401 X-Requested-With, Content-Type, Accept'
402
403 if 'email' in session:
404 print 'logging out '
405 print session['email']
406 session.pop('email')
407
408 response.status_code = 200
409 return response
363410
364411def make_list(res):
365412 entries = []
  
22<html>
33 <head>
44 <title>SWeeT Store</title>
5 <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
65 <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/bootstrap.min.css') }}">
6 <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
77 {% block head %}{% endblock %}
88 </head>
99 <body>
2121 {% endif %}
2222 </div>
2323 {% for message in get_flashed_messages() %}
24 <div class="flash">{{ message }}</div>
24 <div class="flash">{{ message }}</div>
2525 {% endfor %}
2626 {% block body %}{% endblock %}
2727 </div>
  
11{% extends "layout.html" %}
22{% block body %}
3 <div id="store-stats">
4 <span><b>Total Sweets:</b> {{ stats.total_sweets }}</span>
5 </div>
36 <ul class="entries unstyled">
47 {% if entries|len > 0 %}
58 {% for entry in entries %}
1616 <b>@{{ entry.who }}</b>
1717 {% endif %}
1818
19 <b>#{{ entry.what }}</b> /{{ entry.where }} {{ entry.how|safe }}
19 <b>#{{ entry.what }}</b>
20 <a href="{{ appURL_map[entry.what] + entry.where }}" target="tab">
21 {{ entry.where }}
22 </a>
23 <p></p>
24 <p> {{ entry.how|safe }} </p>
2025 {% if entry.created|len > 0 %}
21 <small>created: {{entry.created }} UTC</small>
26 <small><i> created: {{entry.created }} UTC </i></small>
2227 {% endif %}
2328 <a class="pull-right" href={{ "/posts/" + entry.id }}>
2429 <i class="icon-share-alt"></i>