Commit 8fe0bbcd381cb883f9c885dff889481b10ab1e73

Lots of refactor, editing sweet and few more functionality

  - Refactor views to abstract a lot of logic to models
  - API for editing sweet
  - Permalink(non-API) to see a specific sweet
  - Frontend async code to edit sweets. (It would be better, IMO, if we can
    make the frontend of swtstore a separate app).
  - Change few APIs to be better. (Like previously to list a user's apps or
    contexts; one would go to /apps or /contexts; now it is /users/me/apps and
/users/me/contexts, also added /users/me/sweets).
  - Move a lot of debug print statements to a logger component.
  • Diff rendering mode:
  • inline
  • side by side

runserver.py

19# Run the server if this script is directly executed19# Run the server if this script is directly executed
20# Presumably, this is development mode20# Presumably, this is development mode
21if __name__ == '__main__':21if __name__ == '__main__':
22 app.run(debug=True, host='0.0.0.0', port=5001)
22 app.run(host='0.0.0.0', port=5001)

swtstore/application.py

55
6from flask import Flask, request, jsonify, render_template, make_response, g6from flask import Flask, request, jsonify, render_template, make_response, g
7import os7import os
8import logging
89
9from classes.database import db10from classes.database import db
10from config import DefaultConfig11from config import DefaultConfig
22 (views.api, '/api'),22 (views.api, '/api'),
23 (views.user, '/users'),23 (views.user, '/users'),
24 (views.context, '/contexts'),24 (views.context, '/contexts'),
25 (views.sweet, '/sweets'),
25 (views.app, '/apps'),26 (views.app, '/apps'),
26 (views.Oauth, '/oauth')27 (views.Oauth, '/oauth')
27)28)
150150
151151
152def configure_logging(app):152def configure_logging(app):
153 #TODO: implement
154 pass
153
154 formatter = logging.Formatter('%(asctime)s %(levelname)s: %(message)s '
155 '[in %(pathname)s:%(lineno)d]')
156
157 # TODO: maybe we can use a RotatingFileHandler?
158 # Also error can be sent out via email. So we can also have a SMTPHandler?
159 log_handler = logging.StreamHandler()
160
161 if app.config.has_key('LOG_LEVEL'):
162 log_level = app.config['LOG_LEVEL'] or 'ERROR'
163 else:
164 log_level = 'ERROR'
165
166 log_handler.setLevel(log_level)
167 log_handler.setFormatter(formatter)
168
169 app.logger.addHandler(log_handler)

swtstore/classes/exceptions.py

55
6class AlreadyExistsError(Exception, DontWrapMixin):6class AlreadyExistsError(Exception, DontWrapMixin):
7 pass7 pass
8
9class InvalidPayload(Exception, DontWrapMixin):
10 pass

swtstore/classes/models/client.py

3# class:: Client3# class:: Client
44
5from datetime import datetime, timedelta5from datetime import datetime, timedelta
6from flask import current_app
67
7from swtstore.classes.database import db8from swtstore.classes.database import db
8from swtstore.classes.models.um import User9from swtstore.classes.models.um import User
157157
158@oauth.clientgetter158@oauth.clientgetter
159def loadClient(client_id):159def loadClient(client_id):
160 print '@oauth.clientgetter'
160 current_app.logger.debug('@oauth.clientgetter')
161 #return Client.query.filter_by(id=client_id).first()161 #return Client.query.filter_by(id=client_id).first()
162 return Client.query.get(client_id)162 return Client.query.get(client_id)
163163
164@oauth.grantgetter164@oauth.grantgetter
165def loadGrant(client_id, code):165def loadGrant(client_id, code):
166 print '@oauth.grantgetter'
166 current_app.logger.debug('@oauth.grantgetter')
167 return Grant.query.filter_by(client_id=client_id, code=code).first()167 return Grant.query.filter_by(client_id=client_id, code=code).first()
168168
169@oauth.grantsetter169@oauth.grantsetter
170def saveGrant(client_id, code, request, *args, **kwargs):170def saveGrant(client_id, code, request, *args, **kwargs):
171 print '@oauth.grantsetter'
171 current_app.logger.debug('@oauth.grantsetter')
172 expires = datetime.utcnow() + timedelta(seconds=100)172 expires = datetime.utcnow() + timedelta(seconds=100)
173 grant = Grant(173 grant = Grant(
174 client_id = client_id,174 client_id = client_id,
184184
185@oauth.tokengetter185@oauth.tokengetter
186def loadToken(access_token=None, refresh_token=None):186def loadToken(access_token=None, refresh_token=None):
187 print '@oauth.tokengetter'
187 current_app.logger.debug('@oauth.tokengetter')
188 if access_token:188 if access_token:
189 return Token.query.filter_by(access_token=access_token).first()189 return Token.query.filter_by(access_token=access_token).first()
190 elif refresh_token:190 elif refresh_token:
192192
193@oauth.tokensetter193@oauth.tokensetter
194def saveToken(token, request, *args, **kwargs):194def saveToken(token, request, *args, **kwargs):
195 print '@oauth.tokensetter'
195 current_app.logger.debug('@oauth.tokensetter')
196196
197 toks = Token.query.filter_by(client_id=request.client.id,197 toks = Token.query.filter_by(client_id=request.client.id,
198 user_id=request.user.id)198 user_id=request.user.id)

swtstore/classes/models/context.py

5858
59 # return a context instance given a name59 # return a context instance given a name
60 @staticmethod60 @staticmethod
61 def getContextByName(name):
61 def getByName(name):
62 return Context.query.filter_by(name=name).first()62 return Context.query.filter_by(name=name).first()
6363
64 @staticmethod64 @staticmethod

swtstore/classes/models/sweet.py

2# classes/sweet.py2# classes/sweet.py
3# class:: Sweet3# class:: Sweet
44
5from flask import current_app
5from datetime import datetime6from datetime import datetime
67
7from swtstore.classes.database import db8from swtstore.classes.database import db
8# custom SQLAlchemy type JSONType9# custom SQLAlchemy type JSONType
9from swtstore.classes.models.types import JSONType10from swtstore.classes.models.types import JSONType
10from swtstore.classes.utils import urlnorm # normalize URLs11from swtstore.classes.utils import urlnorm # normalize URLs
12from swtstore.classes.models import Context
13from swtstore.classes.models.um import User
1114
12class Sweet(db.Model):15class Sweet(db.Model):
13 """ customary docstring """16 """ customary docstring """
3333
3434
35 def __init__(self, who, what, where, how):35 def __init__(self, who, what, where, how):
36 print 'initing sweet..'
36 current_app.logger.info('initing sweet..')
37 self.who = who37 self.who = who
38 self.what = what38 self.what = what
39 self.where = urlnorm(where)39 self.where = urlnorm(where)
48 return '[Sweet Object: <%s : @%s: #%s : %s>]' % (self.id, self.who,48 return '[Sweet Object: <%s : @%s: #%s : %s>]' % (self.id, self.who,
49 self.what, self.where)49 self.what, self.where)
5050
51 # Update the sweet - only 'how' and 'where' fields can be updated
52 def update(self, **kwargs):
53 if kwargs.get('how'):
54 self.how = kwargs.get('how')
55 self.persist()
56 if kwargs.get('where'):
57 self.where = kwargs.get('where')
58 self.persist()
59
60 return None
61
62
63 # create multiple sweets from a list of JSON
64 @staticmethod
65 def createSweets(who, payload):
66 # the payload has to be a list; a list of swts
67 for each in payload:
68 if 'what' not in each and 'where' not in\
69 each and 'how' not in each:
70
71 raise InvalidPayload('Invalid payload %s \n for creating\
72 mutiple sweets' % (each))
73 return None
74
75 # all ok. create swts from the list now
76 swts = []
77 for each in payload:
78
79 what = Context.getByName(each['what'])
80
81 if what is None:
82 current_app.logger.info('Context "%s" do not exist. Aborting',
83 what)
84 g.error = 'Context do not exist'
85 abort(400) # this context doesn't exist!
86
87 current_app.logger.debug('SWEET PAYLOAD\n---\n%s\n%s\n%s\n%s\n----',
88 who, what, each['where'], each['how'])
89
90 new_sweet = Sweet(who, what, each['where'], each['how'])
91
92 new_sweet.persist()
93 current_app.logger.debug('New Sweet %s', new_sweet)
94 swts.append(new_sweet)
95
96 return swts
97
98 # get Sweets for frontend
99 @staticmethod
100 def getFrontendSwts():
101 return Sweet.query.order_by(Sweet.created.desc()).all()
102
103 # get sweets all sweets authored by a particular user
104 @staticmethod
105 def getByCreator(user):
106 return Sweet.query.filter_by(who=user).\
107 order_by(Sweet.created.desc()).all()
108
109 # allow to query all sweets based on "who", "what" and "where" params
110 @staticmethod
111 def queryByAll(params):
112 if params.get('who'):
113 params['who'] = User.getByName(params['who'])
114 if params.get('what'):
115 params['what'] = Context.getByName(params['what'])
116
117 return Sweet.query.filter_by(**params).all()
118
51 # return a dictionary of data members119 # return a dictionary of data members
52 def to_dict(self):120 def to_dict(self):
53 print self.created
54 return {121 return {
55 'id': self.id,122 'id': self.id,
56 'who': self.who.username,123 'who': self.who.username,
133 # create and persist the sweet to the database133 # create and persist the sweet to the database
134 def persist(self):134 def persist(self):
135135
136 current_app.logger.debug('Commiting sweet %s to db', self)
136 db.session.add(self)137 db.session.add(self)
137 db.session.commit()138 db.session.commit()

swtstore/classes/utils/__init__.py

3 __init__.py3 __init__.py
4"""4"""
5from urlnorm import urlnorm5from urlnorm import urlnorm
6from httputils import makeCORSHeaders

swtstore/classes/utils/httputils.py

1# HTTP utilities
2from flask import current_app
13
2
3def make_cross_origin_headers(response, host_url):
4 print 'client\'s host_url: %s' % host_url
4def makeCORSHeaders(response, host_url):
5 current_app.logger.debug('makeCORSHeaders(): client\'s host_url: %s',
6 host_url)
5 response.headers['Access-Control-Allow-Origin'] = host_url7 response.headers['Access-Control-Allow-Origin'] = host_url
6 response.headers['Access-Control-Max-Age'] = '3600'8 response.headers['Access-Control-Max-Age'] = '3600'
7 response.headers['Access-Control-Allow-Credentials'] = 'true'9 response.headers['Access-Control-Allow-Credentials'] = 'true'
8 response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'10 response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept'
911
10 print 'Updated headers'
11 print response.headers
12 current_app.logger.debug('Updated headers %s', response.headers)
1213
13 return response14 return response
15
16from datetime import timedelta
17from flask import make_response, request, current_app
18from functools import update_wrapper
19
20"""
21def crossdomain(origin=None, methods=None, headers=None, max_age=3600,
22 attach_to_all=True, automatic_options=True):
23
24 if methods is not None:
25 methods = ', '.join(sorted(i.upper() for i in methods))
26 if headers in not None and not isinstance(headers, basestring):
27 headers = ', '.join(i.upper() for i in headers)
28 if not isinstance(origin, basestring):
29 origin = ', '.join(origin)
30 if isinstance(max_age, timedelta):
31 max_age = max_age.total_seconds()
32
33 def get_methods():
34 if methods is not None:
35 return methods
36
37 options_resp = current
38
39"""

swtstore/classes/views/__init__.py

2from .api import api2from .api import api
3from .user import user3from .user import user
4from .context import context4from .context import context
5from .sweet import sweet
5from .app import app6from .app import app
6from .oauth import Oauth7from .oauth import Oauth

swtstore/classes/views/api.py

1from flask import Module, jsonify, request, make_response, abort, g, json
2#import json
3from sqlalchemy.exc import IntegrityError
1from flask import Module, jsonify, request, make_response, abort, g, json,\
2 current_app
43
5from swtstore.classes.models import Context4from swtstore.classes.models import Context
6from swtstore.classes.models import Sweet5from swtstore.classes.models import Sweet
7from swtstore.classes.exceptions import AlreadyExistsError
6from swtstore.classes.exceptions import AlreadyExistsError, InvalidPayload
8from swtstore.classes.utils import urlnorm # normalize URLs7from swtstore.classes.utils import urlnorm # normalize URLs
9from swtstore.classes.utils.httputils import make_cross_origin_headers
8from swtstore.classes.utils.httputils import makeCORSHeaders
10from swtstore.classes import oauth9from swtstore.classes import oauth
1110
1211
1313
1414
15# Get a specific sweet15# Get a specific sweet
16@api.route('/sweets/<int:id>', methods=['GET'])
16# Update a specific sweet
17@api.route('/sweets/<int:id>', methods=['GET', 'PUT'])
17def getSweetById(id):18def getSweetById(id):
18 try:
19
20 # Get a specific sweet
21 if request.method == 'GET':
19 sweet = Sweet.query.get(id)22 sweet = Sweet.query.get(id)
20 except:
21 abort(404)
2223
23 if sweet is None:
24 abort(404)
24 if sweet is None:
25 abort(404)
2526
26 print sweet
27 return jsonify(sweet.to_dict())
27 current_app.logger.debug('getSweetById: %s', sweet)
28 return jsonify(sweet.to_dict())
2829
30 # Update a specific sweet
31 elif request.method == 'PUT':
32 payload = request.json
33 if payload is None:
34 abort(400)
2935
36 current_app.logger.debug('Update Sweet: recvd payload: %s', payload)
37
38 sweet = Sweet.query.get(id)
39
40 if sweet is None:
41 abort(404)
42
43 current_app.logger.debug('Updating sweet %s with new how: %s ',
44 sweet.id, payload)
45
46 sweet.update(how=payload)
47
48 return jsonify(sweet.to_dict())
49
50
30# Post a sweet to the sweet store51# Post a sweet to the sweet store
31@api.route('/sweets', methods=['OPTIONS', 'POST'])52@api.route('/sweets', methods=['OPTIONS', 'POST'])
32@oauth.require_oauth('email', 'sweet')53@oauth.require_oauth('email', 'sweet')
5757
58 client = oauth_request.client58 client = oauth_request.client
5959
60 #TODO: check if response is coming from a registered client
61 response = make_cross_origin_headers(response, client.host_url)
60 #TODO: make a decorator of CORS request
61 response = makeCORSHeaders(response, client.host_url)
6262
63 if request.method == 'OPTIONS':63 if request.method == 'OPTIONS':
64 response.status_code = 20064 response.status_code = 200
65 return response65 return response
6666
67 if request.json:
68 payload = request.json
69 if request.data:
70 payload = json.loads(request.data)
71 else:
72 print 'data not found in payload!'
67 payload = request.json or request.data
68 if not payload:
69 current_app.logger.error('data not found in payload!')
73 g.error= 'data not found in payload!'70 g.error= 'data not found in payload!'
74 abort(400)71 abort(400)
7572
76 print 'new sweet payload recvd..'
77 print payload
73 current_app.logger.debug('new sweet payload recvd.. %s', payload)
7874
79 # the payload has to be a list; a list of swts
80 for each in payload:
81 if 'what' not in each and 'where' not in\
82 each and 'how' not in each:
75 # Get the authenticated user from the oauth request object.
76 # Older swtr clients sending `who` in string will be ignored.
77 who = oauth_request.user
8378
84 print 'Invalid Request..'
85 abort(400)
79 try:
80 swts = Sweet.createSweets(who, payload)
81 except InvalidPayload(msg):
82 current_app.logger.error('Invalid Payload in request')
83 abort(400)
8684
87 # all ok. create swts from the list now
88
89 swts = []
90 for each in payload:
91
92 what = Context.query.filter_by(name=each['what']).first()
93
94 if what is None:
95 print 'Context doesn\'t exist'
96 g.error = 'Context doesn\'t exist'
97 abort(400) # this context doesn't exist!
98
99 # Get the authenticated user from the oauth request object.
100 # Older swtr clients sending `who` in string will be ignored.
101 who = oauth_request.user
102
103 print 'SWEET DATA'
104 print '------------'
105 print who
106 print what
107 print each['where']
108 print each['how']
109 print '-------------'
110
111 new_sweet = Sweet(who, what, each['where'], each['how'])
112
113 new_sweet.persist()
114 print new_sweet
115 swts.append(new_sweet.id)
116
117 response.status_code = 20085 response.status_code = 200
118 response.data = json.dumps(swts)
86 response.headers['Content-type'] = 'application/json'
87 response.data = json.dumps([i.to_dict() for i in swts])
119 return response88 return response
12089
12190
122# The Sweet query API: /sweets/q?who=<>&what=<>&where=<>91# The Sweet query API: /sweets/q?who=<>&what=<>&where=<>
123# args: who, what, where92# args: who, what, where
124@api.route('/sweets/q', methods=['GET', 'OPTIONS'])93@api.route('/sweets/q', methods=['GET', 'OPTIONS'])
125@oauth.require_oauth('sweet')
126def querySweets(oauth_request):
94#@oauth.require_oauth('sweet')
95def querySweets():
12796
128 response = make_response()97 response = make_response()
129 response = make_cross_origin_headers(response,
130 oauth_request.client.host_url)
98 origin = request.headers.get('Origin', '*')
99 response = makeCORSHeaders(response, origin)
131100
132 if request.method == 'OPTIONS':101 if request.method == 'OPTIONS':
133 reponse.status_code = 200102 reponse.status_code = 200
112 if args.get('who'):112 if args.get('who'):
113 params['who'] = args.get('who')113 params['who'] = args.get('who')
114 if args.get('what'):114 if args.get('what'):
115 what = Context.query.filter_by(name=args.get('what')).first()
116 params['what'] = what
115 params['what'] = args.get('what')
117 if args.get('where'):116 if args.get('where'):
118 params['where'] = urlnorm(args.get('where'))117 params['where'] = urlnorm(args.get('where'))
119118
120 if len(params) == 0:120 if len(params) == 0:
121 abort(400)121 abort(400)
122122
123 print 'recvd params'
124 print params
123 current_app.logger.debug('recvd params: %s', params)
125124
125 sweets = Sweet.queryByAll(params)
126126
127 sweets = Sweet.query.filter_by(**params).all()
128
129 if len(sweets) == 0:127 if len(sweets) == 0:
130 print 'No sweets found to satisfy query..'
128 current_app.logger.info('No sweets found to satisfy query..')
131 abort(404)129 abort(404)
132130
133 swts = [i.to_dict() for i in sweets]131 swts = [i.to_dict() for i in sweets]
139@api.route('/contexts/<name>', methods=['GET'])139@api.route('/contexts/<name>', methods=['GET'])
140def getContextByName(name):140def getContextByName(name):
141141
142 context = Context.query.filter_by(name=name).first()
142 context = Context.getByName(name)
143 if context is None:143 if context is None:
144 abort(404)144 abort(404)
145145
146 print context
146 current_app.logger.debug('getContextByName : %s', context)
147 return jsonify(context.to_dict())147 return jsonify(context.to_dict())
148148
149# Get a specific context with its definition; based on id149# Get a specific context with its definition; based on id
154 if context is None:154 if context is None:
155 abort(404)155 abort(404)
156156
157 print context
158 print context.created
159 print context.to_dict()
160 print jsonify(context.to_dict()).data
157 current_app.logger.debug('getContextById response: %s',
158 jsonify(context.to_dict()).data)
159
161 return jsonify(context.to_dict())160 return jsonify(context.to_dict())
162161
163162
176 # if not found send back a 400176 # if not found send back a 400
177 abort(400)177 abort(400)
178178
179 #TODO: change it to logger component
180 print 'new context payload recvd..'
181 print payload
179 current_app.logger.debug('new context payload recvd.. %s', payload)
182180
183 # if data is invalid send back 400181 # if data is invalid send back 400
184 if 'name' not in payload and 'definition' not in payload:182 if 'name' not in payload and 'definition' not in payload:
187187
188 except AlreadyExistsError:188 except AlreadyExistsError:
189 # context with same name exists; send back 400?189 # context with same name exists; send back 400?
190 print 'Already Exists Error'
190 current_app.logger.info('Context Already Exists Error')
191 abort(400)191 abort(400)
192192
193 print 'new context'
194 print new_context
193 current_app.logger.debug('new context created: %s', new_context)
194
195 # all ok. save the new context195 # all ok. save the new context
196 res = new_context.persist()196 res = new_context.persist()
197197
204@oauth.require_oauth('email')204@oauth.require_oauth('email')
205def getCurrentUser(oauth_request):205def getCurrentUser(oauth_request):
206 response = make_response()206 response = make_response()
207 response = make_cross_origin_headers(response,
208 oauth_request.client.host_url)
207 response = makeCORSHeaders(response, oauth_request.client.host_url)
209 response.status_code = 200208 response.status_code = 200
210209
211 if request.method == 'OPTIONS':210 if request.method == 'OPTIONS':
212 return response211 return response
213212
213 response.headers['Content-type'] = 'application/json'
214 # We have the user object along with the oauth request. Just return it back
214 response.data = json.dumps(oauth_request.user.to_dict())215 response.data = json.dumps(oauth_request.user.to_dict())
215 return response216 return response

swtstore/classes/views/app.py

1
2# -*- coding utf-8 -*-1# -*- coding utf-8 -*-
3# classes/views/apps.py2# classes/views/apps.py
43
5
6from flask import Module, jsonify, request, render_template, redirect,\4from flask import Module, jsonify, request, render_template, redirect,\
7 url_for, flash, abort5 url_for, flash, abort
86
1414
15app = Module(__name__)15app = Module(__name__)
1616
17@app.route('/', methods=['GET'])
18# list apps owned by current user
19def list():
20 current_user = User.getCurrentUser()
21 if current_user is None:
22 return redirect(url_for('frontend.index'))
2317
24 her_apps = Client.getClientsByCreator(current_user.id)
25 print 'her_apps'
26 print her_apps
27 return render_template('list_apps.html', apps=her_apps,
28 user=current_user.to_dict())
29
30
31@app.route('/register', methods=['GET', 'POST'])18@app.route('/register', methods=['GET', 'POST'])
32def register():19def register():
33 current_user = User.getCurrentUser()20 current_user = User.getCurrentUser()
34 if current_user is None:21 if current_user is None:
35 return redirect(url_for('frontend.index'))22 return redirect(url_for('frontend.index'))
3623
37 user = current_user.to_dict()
38
39 if request.method == 'GET':24 if request.method == 'GET':
40 return render_template('register_app.html', user=user)
25 return render_template('register_app.html')
4126
42 elif request.method == 'POST':27 elif request.method == 'POST':
43 req_fields = ['name', 'host_url', 'redirect_uris', 'scopes']28 req_fields = ['name', 'host_url', 'redirect_uris', 'scopes']
43 )43 )
44 new_app.persist()44 new_app.persist()
4545
46 return redirect(url_for('list'))
46 return redirect(url_for('user.myApps'))

swtstore/classes/views/context.py

1
2# -*- coding utf-8 -*-1# -*- coding utf-8 -*-
3# classes/views/context.py2# classes/views/context.py
43
4from flask import Module, jsonify, request, render_template, redirect,\
5 url_for, json, current_app
56
6from flask import Module, jsonify, request, render_template, redirect, url_for
7import json
8
9from swtstore.classes.models import Context7from swtstore.classes.models import Context
10from swtstore.classes.models.um import User8from swtstore.classes.models.um import User
119
1210
13context = Module(__name__)11context = Module(__name__)
1412
15@context.route('/', methods=['GET'])
16# list apps owned by current user
17def list():
18 current_user = User.getCurrentUser()
19 if current_user is None:
20 return redirect(url_for('index'))
21
22 her_contexts = Context.getByCreator(current_user.id)
23 print 'her_apps'
24 print her_contexts
25
26 return render_template('list_contexts.html', contexts=her_contexts,
27 user=current_user.to_dict())
28
29
30@context.route('/register', methods=['GET', 'POST'])13@context.route('/register', methods=['GET', 'POST'])
31def register():14def register():
32 current_user = User.getCurrentUser()15 current_user = User.getCurrentUser()
33 if current_user is None:16 if current_user is None:
34 return redirect(url_for('index'))
17 return redirect(url_for('frontend.index'))
3518
36 user = current_user.to_dict()
37
38 if request.method == 'GET':19 if request.method == 'GET':
39 return render_template('register_context.html', user=user)
20 return render_template('register_context.html')
4021
41 if request.method == 'POST':22 if request.method == 'POST':
42 if not request.form.get('name') or not request.form.get('defn'):23 if not request.form.get('name') or not request.form.get('defn'):
43 abort(400)24 abort(400)
4425
45 print request.form.get('defn')
26 current_app.logger.debug('New Context: defn: %s ',
27 request.form.get('defn'))
46 json_ld = json.loads(request.form.get('defn'))28 json_ld = json.loads(request.form.get('defn'))
47 print json_ld
29 current_app.logger.debug('Resulting json_ld %s', json_ld)
4830
49 new_context = Context(31 new_context = Context(
50 name = request.form.get('name'),32 name = request.form.get('name'),
51 definition = json_ld,33 definition = json_ld,
52 user_id = current_user.id34 user_id = current_user.id
53 )35 )
54 print new_context
36 current_app.logger.debug('New Context created: %s', new_context)
55 new_context.persist()37 new_context.persist()
5638
57 return redirect(url_for('list'))
39 return redirect(url_for('user.myContexts'))

swtstore/classes/views/frontend.py

2# classes/views/frontend.py2# classes/views/frontend.py
33
44
5from flask import Module, jsonify, request, render_template, redirect, url_for
5from flask import Module, jsonify, request, render_template, redirect,\
6 url_for, g, current_app
67
8from sqlalchemy import desc
9
7from swtstore.classes.models import Sweet10from swtstore.classes.models import Sweet
8from swtstore.classes.models.um import User11from swtstore.classes.models.um import User
912
1515
16@frontend.route('/', methods=['GET'])16@frontend.route('/', methods=['GET'])
17def index():17def index():
18 # sweets = Sweet.query.somethingToGetRelevant()
19 sweets = Sweet.query.all()
18 sweets = Sweet.getFrontendSwts()
2019
21 user = User.getCurrentUser()20 user = User.getCurrentUser()
22 if user is not None:
23 user = user.to_dict()
2421
25 return render_template('index.html', sweets=sweets, user=user)
22 return render_template('index.html', sweets=sweets)
2623
2724
28# Create a new sweet context25# Create a new sweet context

swtstore/classes/views/oauth.py

1# -*- coding utf-8 -*-1# -*- coding utf-8 -*-
2# classes/views/oauth.py2# classes/views/oauth.py
33
4from flask import Module, jsonify, request, render_template, redirect, url_for
5import json
4from flask import Module, jsonify, request, render_template, redirect,\
5 url_for, current_app
66
7from swtstore.classes import oauth7from swtstore.classes import oauth
8from swtstore.classes.models.um import User8from swtstore.classes.models.um import User
21 if request.method == 'GET':21 if request.method == 'GET':
22 client_id = kwargs.get('client_id')22 client_id = kwargs.get('client_id')
23 client = Client.query.get(client_id)23 client = Client.query.get(client_id)
24 print '/authorize: '
25 print client
24 current_app.logger.debug('In /authorize: client: %s', client)
26 kwargs['client'] = client25 kwargs['client'] = client
27 kwargs['user'] = current_user26 kwargs['user'] = current_user
28 print kwargs
27 current_app.logger.debug('kwargs %s', kwargs)
29 return render_template('authorize.html', **kwargs)28 return render_template('authorize.html', **kwargs)
3029
31 confirm = request.form.get('confirm', 'no')30 confirm = request.form.get('confirm', 'no')
32 print confirm
31 current_app.logger.debug('confirm authorize from user: %s', confirm)
33 return confirm == 'yes'32 return confirm == 'yes'
3433
35@Oauth.route('/token', methods=['GET', 'POST'])34@Oauth.route('/token', methods=['GET', 'POST'])
36@oauth.token_handler35@oauth.token_handler
37def access_token():36def access_token():
38 #print request.form37 #print request.form
39 print 'access token touched..'
38 current_app.logger.debug('access token touched..')
40 return None39 return None
4140
42@Oauth.route('/errors')41@Oauth.route('/errors')

swtstore/classes/views/sweet.py

1# -*- coding utf-8 -*-
2# classes/views/sweet.py
3
4
5from flask import Module, jsonify, request, render_template, redirect,\
6 url_for, abort, json
7
8from swtstore.classes.models import Context
9from swtstore.classes.models import Sweet
10from swtstore.classes.models.um import User
11
12
13sweet = Module(__name__)
14
15@sweet.route('/<id>', methods=['GET'])
16def showSweet(id):
17 #current_user = User.getCurrentUser()
18 #if current_user is None:
19 # return redirect(url_for('index'))
20
21 #user = current_user.to_dict()
22 print "recvd sweet id: %s" % (id)
23 sweet = Sweet.query.get(id)
24 if sweet:
25 print "sweet found " + str(sweet)
26 return render_template('specific_sweet.html', sweet=sweet)
27 else:
28 abort(404)

swtstore/classes/views/user.py

33
4import requests4import requests
55
6# flask imports
6from flask import Module, jsonify, request, render_template, session,\7from flask import Module, jsonify, request, render_template, session,\
7 make_response, url_for, redirect
8import json
8 make_response, url_for, redirect, json, current_app
99
10# swtstore imports
10from swtstore.classes.models.um import User11from swtstore.classes.models.um import User
12from swtstore.classes.models import Sweet, Context, Client
1113
12from swtstore.classes.utils.httputils import make_cross_origin_headers
14from swtstore.classes.utils.httputils import makeCORSHeaders
13from swtstore.config import DefaultConfig15from swtstore.config import DefaultConfig
1416
1517
23def login():23def login():
2424
25 response = make_response()25 response = make_response()
26 #response = make_cross_origin_headers(response)
26 #response = makeCORSHeaders(response)
2727
28 if 'assertion' not in request.form:28 if 'assertion' not in request.form:
29 response.status_code = 40029 response.status_code = 400
30 return response30 return response
3131
32 print request.remote_addr
32 current_app.logger.debug('remote address of request for user login %s',
33 request.remote_addr)
34
33 data = {'assertion': request.form['assertion'], 'audience':35 data = {'assertion': request.form['assertion'], 'audience':
34 config.SWTSTORE_URL}36 config.SWTSTORE_URL}
3537
36 resp = requests.post(config.MOZ_PERSONA_VERIFIER, data=data, verify=True)38 resp = requests.post(config.MOZ_PERSONA_VERIFIER, data=data, verify=True)
37 print resp.status_code
38 print resp.json()
39 current_app.logger.debug('Response code from MOZ_PERSONA_VERIFIER %s',
40 resp.status_code)
41 current_app.logger.debug('Response body: %s', resp.json())
3942
40 if resp.ok:43 if resp.ok:
41 verified_data = json.loads(resp.content)44 verified_data = json.loads(resp.content)
48 current_user = User.query.filter_by(email=user_email).first()48 current_user = User.query.filter_by(email=user_email).first()
49 # user doesn't exist; create her49 # user doesn't exist; create her
50 if current_user is None:50 if current_user is None:
51 print 'user with email ' + user_email + ' doesn\'t exist;'
52 print 'creating new user:' + user_email
51 current_app.logger.info('user with email %s doesn\'t exist',
52 user_email)
53 current_app.logger.info('creating new user: %s', user_email)
54
53 new_user = User('', user_email)55 new_user = User('', user_email)
54 new_user.persist()56 new_user.persist()
55 current_user = new_user57 current_user = new_user
5658
57 #session.update({'email': verified_data['email']})59 #session.update({'email': verified_data['email']})
58 print 'logging in user with email' + user_email
60 current_app.logger.info('logging in user with email %s',
61 user_email)
59 session['email'] = current_user.email62 session['email'] = current_user.email
6063
61 response.status_code = 20064 response.status_code = 200
72def logout():72def logout():
7373
74 response = make_response()74 response = make_response()
75 #response = make_cross_origin_headers(response)
75 #response = makeCORSHeaders(response)
7676
77 if 'email' in session:77 if 'email' in session:
78 print 'logging out '
79 print session['email']
78 current_app.logger.info('logging out user %s', session['email'])
80 session.pop('email')79 session.pop('email')
8180
82 response.status_code = 20081 response.status_code = 200
92 return render_template('me.html', user=current_user)92 return render_template('me.html', user=current_user)
9393
94 username = request.form.get('username')94 username = request.form.get('username')
95 print username
95
96 current_app.logger.debug('Updating username of %s to %s',
97 current_user.username, username)
98
96 current_user.update(username=username)99 current_user.update(username=username)
97100
98 return redirect(url_for('profile'))101 return redirect(url_for('profile'))
102
103
104@user.route('/me/sweets', methods=['GET'])
105def mySweets():
106
107 user = User.getCurrentUser()
108 if user is None:
109 return redirect(url_for('frontend.index'))
110
111 swts = Sweet.getByCreator(user)
112 return render_template('my_sweets.html', sweets=swts)
113
114
115@user.route('/me/contexts', methods=['GET'])
116def myContexts():
117
118 user = User.getCurrentUser()
119 if user is None:
120 return redirect(url_for('frontend.index'))
121
122 contexts = Context.getByCreator(user.id)
123 return render_template('my_contexts.html', contexts=contexts)
124
125
126@user.route('/me/apps', methods=['GET'])
127def myApps():
128
129 # make a decorator out of this repetative code
130 user = User.getCurrentUser()
131 if user is None:
132 return redirect(url_for('frontend.index'))
133
134 apps = Client.getClientsByCreator(user.id)
135 return render_template('my_apps.html', apps=apps)

swtstore/static/js/main.js

5 this.attachLogout();5 this.attachLogout();
6 this.initPersona();6 this.initPersona();
7 this.activeNav();7 this.activeNav();
8 $('.edit-sweet').click(ss.editSweet);
8 };9 };
910
10 ss.activeNav = function() {11 ss.activeNav = function() {
69 });69 });
70 }70 }
71 });71 });
72 };
73
74 ss.editSweet = function(event) {
75 var target = $(event.currentTarget).attr('for');
76 var how = JSON.parse($(event.currentTarget).siblings('.how').html());
77 //console.log(how);
78 // update sweet function
79 function updateSweet(event) {
80 var changed = false;
81 for(var field in how) {
82 var data = $('#edit-sweet-modal .modal-body textarea[name="'+field+'"]').val();
83 var item = (typeof how[field] === 'object') ? JSON.stringify(how[field]) :
84 how[field];
85 if(data !== item) {
86 changed = true;
87 how[field] = data;
88 console.log('Updated '+ field + ' with data: ', data);
89 }
90 }
91 if(changed) {
92 $('#save-edited-sweet').text('Saving Changes');
93
94 $.ajax({
95 type: 'PUT',
96 url: 'http://localhost:5001/api/sweets/'+target,
97 contentType: 'application/json',
98 data: JSON.stringify(how),
99 success: function(data) {
100 console.log('Updated swt from the server ', data);
101 $('#save-edited-sweet').text('Save Changes');
102 $('#edit-sweet-modal').modal('hide');
103 },
104 error: function() {
105 $('#save-edited-sweet').text('Save Changes');
106 }
107 });
108 }
109 else {
110 return;
111 }
112 }
113 // prepare the edit view
114 $('#edit-sweet-modal .modal-body').html('');
115 for(var field in how) {
116 var item = (typeof how[field] === 'object') ? JSON.stringify(how[field]) :
117 how[field];
118
119 $('#edit-sweet-modal .modal-body').append('<div class="form-group"> <b>'+
120 field+'</b>');
121 /*$('<input>',
122 {name: field, value: item, class: 'form-control', type: 'text'}).
123 appendTo('#edit-sweet-modal .modal-body');*/
124 $('#edit-sweet-modal .modal-body').append('<textarea name="'+field+'" class="form-control">'+item+'</textarea>');
125
126 $('#edit-sweet-modal').append('</div>');
127 }
128 // launch the modal
129 $('#edit-sweet-modal').modal();
130
131 // attach event handlers
132 $('#save-edited-sweet').off('click');
133 $('#save-edited-sweet').on('click', updateSweet);
134
72 };135 };
73136
74})(ss);137})(ss);

swtstore/templates/index.html

28 <small><i>created: {{sweet.created }}</i></small>28 <small><i>created: {{sweet.created }}</i></small>
2929
30 <span class="pull-right permalink">30 <span class="pull-right permalink">
31 <a href="#">
31 <a href="{{ url_for('sweet.showSweet', id=sweet.id) }}">
32 <i class="glyphicon glyphicon-share"></i>32 <i class="glyphicon glyphicon-share"></i>
33 </a>33 </a>
34 </li>34 </li>

swtstore/templates/layout.html

17 <li>17 <li>
18 <a href="{{ url_for('frontend.index') }}"> Home </a>18 <a href="{{ url_for('frontend.index') }}"> Home </a>
19 </li>19 </li>
20 {% if not user %}
20 {% if not session.email %}
21 <li>21 <li>
22 <a id="login" href="#"> Login </a>22 <a id="login" href="#"> Login </a>
23 </li>23 </li>
24 {% else %}24 {% else %}
25 <!-- swts list -->
26 <li>
27 <a href="{{ url_for('user.mySweets') }}"> My Sweets </a>
28 </li>
25 <!-- the cog menu -->29 <!-- the cog menu -->
26 <li class="dropdown user-menu">30 <li class="dropdown user-menu">
27 <a class="dropdown-toggle" data-toggle="dropdown" href="#">31 <a class="dropdown-toggle" data-toggle="dropdown" href="#">
33 </a>33 </a>
34 <ul class="dropdown-menu" role="menu">34 <ul class="dropdown-menu" role="menu">
35 <li> <a href="{{ url_for('app.register') }}">Register New App</a> </li>35 <li> <a href="{{ url_for('app.register') }}">Register New App</a> </li>
36 <li> <a href="{{ url_for('app.list') }}">Registered Apps</a> </li>
36 <li> <a href="{{ url_for('user.myApps') }}">Registered Apps</a> </li>
37 <li class="divider"></li>37 <li class="divider"></li>
38 <li> <a href="{{ url_for('context.register') }}">Register New Context</a> </li>38 <li> <a href="{{ url_for('context.register') }}">Register New Context</a> </li>
39 <li> <a href="{{ url_for('context.list') }}">Registered Contexts</a> </li>
39 <li> <a href="{{ url_for('user.myContexts') }}">Registered Contexts</a> </li>
40 </ul>40 </ul>
41 </li>41 </li>
42 <!-- the user menu -->42 <!-- the user menu -->
48 <ul class="dropdown-menu" role="menu">48 <ul class="dropdown-menu" role="menu">
49 <li>49 <li>
50 <a href="{{ url_for('user.profile') }}"><small>50 <a href="{{ url_for('user.profile') }}"><small>
51 {% if user.username %}
52 {{ user.username }}
53 {% else %}
54 {{ user.email }}
55 {% endif %}
51 {{ session.email }}
56 </small></a>52 </small></a>
57 </li>53 </li>
58 <li class="divider"></li>54 <li class="divider"></li>
85 ss.loginURL = function() { return "{{ url_for('user.login') }}"; };85 ss.loginURL = function() { return "{{ url_for('user.login') }}"; };
86 ss.logoutURL = function() { return "{{ url_for('user.logout') }}"; };86 ss.logoutURL = function() { return "{{ url_for('user.logout') }}"; };
87 ss.loggedInUser = function() {87 ss.loggedInUser = function() {
88 {% if not user %}
89 var user = '';
90 {% else %}
91 var user = "{{ user.email }}";
92 {% endif %}
93 if(user) {
94 return user;
95 }
96 return null;
88 return ("{{ session.email }}") ? "{{ session.email }}" : null;
97 };89 };
98 window.onload = function() {90 window.onload = function() {
99 ss.init();91 ss.init();

swtstore/templates/my_apps.html

1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if apps|length > 0 %}
5 <ul>
6 {% for app in apps %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div><h4> {{ app.name }} </h4></div>
12 <div><h5> {{ app.description }} </h5></div>
13 <div>APP ID: {{ app.id }} </div>
14 <div> APP Secret: {{ app.client_secret }} </div>
15 <div>Host URL: {{ app.host_url }} </div>
16 <div>Redirect URL: {{ app.redirect_uris|join(', ') }} </div>
17 <div>Scopes: {{ app.default_scopes|join(', ') }} </div>
18 </div>
19 {% endfor %}
20 </ul>
21 {% else %}
22 <em> You haven't registered any apps yet! </em>
23 {% endif %}
24</div>
25{% endblock %}

swtstore/templates/my_contexts.html

1{% extends "layout.html" %}
2{% block body %}
3<div>
4 {% if contexts|length > 0 %}
5 <ul>
6 {% for context in contexts %}
7 <div class="well">
8 <div class="pull-right">
9 <span class="glyphicon glyphicon-trash"></span>
10 </div>
11 <div> {{ context.name }} </div>
12 <div> {{ context.definition }} </div>
13 </div>
14 {% endfor %}
15 </ul>
16 {% else %}
17 <em> You haven't registered any contexts yet! </em>
18 {% endif %}
19</div>
20{% endblock %}

swtstore/templates/my_sweets.html

1{% extends "layout.html" %}
2
3{% block body %}
4
5 {% if sweets|length > 0 %}
6
7 <ul class="entries unstyled">
8 {% for sweet in sweets %}
9 <li>
10 <span class="who">
11 <a href="#">
12 @{{ sweet.who.username }}
13 </a>
14 </span>
15 <span class="what">
16 <b> #{{ sweet.what.name }} </b>
17 </span>
18 <span class="where">
19 {{ sweet.where }}
20 </span>
21 <p></p>
22 <span class="how">
23 {{ sweet.how|tojson }}
24 </span>
25
26 <small><i>created: {{sweet.created }}</i></small>
27
28 <span class="pull-right permalink">
29 <a href="#">
30 <i class="glyphicon glyphicon-share"></i>
31 </a>
32 </span>
33 <span class="pull-right edit-sweet" for="{{ sweet.id }}">
34 <a href="#">
35 <i class="glyphicon glyphicon-edit"></i>
36 </a>
37 </span>
38 </li>
39 {% endfor %}
40 </ul>
41
42 {% else %}
43 <div class="row">
44 <div class="col-md-5">
45 <h4><em>Unbelievable! No sweets yet!!</em></h4>
46 </div>
47 </div>
48 {% endif %}
49
50 <div class="modal fade" id="edit-sweet-modal">
51 <div class="modal-dialog">
52 <div class="modal-content">
53 <div class="modal-header">
54 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
55 <h4 class="modal-title">Edit Sweet </h4>
56 </div>
57 <div class="modal-body"></div>
58 <div
59 class="modal-footer">
60 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
61 <button type="button" class="btn btn-primary" id="save-edited-sweet">Save changes</button>
62 </div>
63 </div><!-- /.modal-content -->
64 </div><!-- /.modal-dialog -->
65 </div><!-- /.modal -->
66
67{% endblock %}

swtstore/templates/specific_sweet.html

1{% extends "layout.html" %}
2
3{% block body %}
4
5<ul class="entries unstyled">
6 <li>
7 <span class="who">
8 <a href="#">
9 @{{ sweet.who.username }}
10 </a>
11 </span>
12 <span class="what">
13 <b> #{{ sweet.what.name }} </b>
14 </span>
15 <span class="where">
16 {{ sweet.where }}
17 </span>
18 <p></p>
19 <span class="how">
20 {{ sweet.how|escape|safe }}
21 </span>
22
23 <small><i>created: {{sweet.created }}</i></small>
24 </li>
25</ul>
26
27{% endblock %}