Commit 8fe0bbcd381cb883f9c885dff889481b10ab1e73
- Diff rendering mode:
- inline
- side by side
runserver.py
(1 / 1)
  | |||
19 | 19 | # Run the server if this script is directly executed | |
20 | 20 | # Presumably, this is development mode | |
21 | 21 | if __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
(19 / 2)
  | |||
5 | 5 | ||
6 | 6 | from flask import Flask, request, jsonify, render_template, make_response, g | |
7 | 7 | import os | |
8 | import logging | ||
8 | 9 | ||
9 | 10 | from classes.database import db | |
10 | 11 | from config import DefaultConfig | |
… | … | ||
22 | 22 | (views.api, '/api'), | |
23 | 23 | (views.user, '/users'), | |
24 | 24 | (views.context, '/contexts'), | |
25 | (views.sweet, '/sweets'), | ||
25 | 26 | (views.app, '/apps'), | |
26 | 27 | (views.Oauth, '/oauth') | |
27 | 28 | ) | |
… | … | ||
150 | 150 | ||
151 | 151 | ||
152 | 152 | def 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) |
  | |||
5 | 5 | ||
6 | 6 | class AlreadyExistsError(Exception, DontWrapMixin): | |
7 | 7 | pass | |
8 | |||
9 | class InvalidPayload(Exception, DontWrapMixin): | ||
10 | pass |
  | |||
3 | 3 | # class:: Client | |
4 | 4 | ||
5 | 5 | from datetime import datetime, timedelta | |
6 | from flask import current_app | ||
6 | 7 | ||
7 | 8 | from swtstore.classes.database import db | |
8 | 9 | from swtstore.classes.models.um import User | |
… | … | ||
157 | 157 | ||
158 | 158 | @oauth.clientgetter | |
159 | 159 | def loadClient(client_id): | |
160 | print '@oauth.clientgetter' | ||
160 | current_app.logger.debug('@oauth.clientgetter') | ||
161 | 161 | #return Client.query.filter_by(id=client_id).first() | |
162 | 162 | return Client.query.get(client_id) | |
163 | 163 | ||
164 | 164 | @oauth.grantgetter | |
165 | 165 | def loadGrant(client_id, code): | |
166 | print '@oauth.grantgetter' | ||
166 | current_app.logger.debug('@oauth.grantgetter') | ||
167 | 167 | return Grant.query.filter_by(client_id=client_id, code=code).first() | |
168 | 168 | ||
169 | 169 | @oauth.grantsetter | |
170 | 170 | def saveGrant(client_id, code, request, *args, **kwargs): | |
171 | print '@oauth.grantsetter' | ||
171 | current_app.logger.debug('@oauth.grantsetter') | ||
172 | 172 | expires = datetime.utcnow() + timedelta(seconds=100) | |
173 | 173 | grant = Grant( | |
174 | 174 | client_id = client_id, | |
… | … | ||
184 | 184 | ||
185 | 185 | @oauth.tokengetter | |
186 | 186 | def loadToken(access_token=None, refresh_token=None): | |
187 | print '@oauth.tokengetter' | ||
187 | current_app.logger.debug('@oauth.tokengetter') | ||
188 | 188 | if access_token: | |
189 | 189 | return Token.query.filter_by(access_token=access_token).first() | |
190 | 190 | elif refresh_token: | |
… | … | ||
192 | 192 | ||
193 | 193 | @oauth.tokensetter | |
194 | 194 | def saveToken(token, request, *args, **kwargs): | |
195 | print '@oauth.tokensetter' | ||
195 | current_app.logger.debug('@oauth.tokensetter') | ||
196 | 196 | ||
197 | 197 | toks = Token.query.filter_by(client_id=request.client.id, | |
198 | 198 | user_id=request.user.id) |
  | |||
58 | 58 | ||
59 | 59 | # return a context instance given a name | |
60 | 60 | @staticmethod | |
61 | def getContextByName(name): | ||
61 | def getByName(name): | ||
62 | 62 | return Context.query.filter_by(name=name).first() | |
63 | 63 | ||
64 | 64 | @staticmethod |
swtstore/classes/models/sweet.py
(73 / 2)
  | |||
2 | 2 | # classes/sweet.py | |
3 | 3 | # class:: Sweet | |
4 | 4 | ||
5 | from flask import current_app | ||
5 | 6 | from datetime import datetime | |
6 | 7 | ||
7 | 8 | from swtstore.classes.database import db | |
8 | 9 | # custom SQLAlchemy type JSONType | |
9 | 10 | from swtstore.classes.models.types import JSONType | |
10 | 11 | from swtstore.classes.utils import urlnorm # normalize URLs | |
12 | from swtstore.classes.models import Context | ||
13 | from swtstore.classes.models.um import User | ||
11 | 14 | ||
12 | 15 | class Sweet(db.Model): | |
13 | 16 | """ customary docstring """ | |
… | … | ||
33 | 33 | ||
34 | 34 | ||
35 | 35 | def __init__(self, who, what, where, how): | |
36 | print 'initing sweet..' | ||
36 | current_app.logger.info('initing sweet..') | ||
37 | 37 | self.who = who | |
38 | 38 | self.what = what | |
39 | 39 | self.where = urlnorm(where) | |
… | … | ||
48 | 48 | return '[Sweet Object: <%s : @%s: #%s : %s>]' % (self.id, self.who, | |
49 | 49 | self.what, self.where) | |
50 | 50 | ||
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 | 119 | # return a dictionary of data members | |
52 | 120 | def to_dict(self): | |
53 | print self.created | ||
54 | 121 | return { | |
55 | 122 | 'id': self.id, | |
56 | 123 | 'who': self.who.username, | |
… | … | ||
133 | 133 | # create and persist the sweet to the database | |
134 | 134 | def persist(self): | |
135 | 135 | ||
136 | current_app.logger.debug('Commiting sweet %s to db', self) | ||
136 | 137 | db.session.add(self) | |
137 | 138 | db.session.commit() |
  | |||
3 | 3 | __init__.py | |
4 | 4 | """ | |
5 | 5 | from urlnorm import urlnorm | |
6 | from httputils import makeCORSHeaders |
  | |||
1 | # HTTP utilities | ||
2 | from flask import current_app | ||
1 | 3 | ||
2 | |||
3 | def make_cross_origin_headers(response, host_url): | ||
4 | print 'client\'s host_url: %s' % host_url | ||
4 | def makeCORSHeaders(response, host_url): | ||
5 | current_app.logger.debug('makeCORSHeaders(): client\'s host_url: %s', | ||
6 | host_url) | ||
5 | 7 | response.headers['Access-Control-Allow-Origin'] = host_url | |
6 | 8 | response.headers['Access-Control-Max-Age'] = '3600' | |
7 | 9 | response.headers['Access-Control-Allow-Credentials'] = 'true' | |
8 | 10 | response.headers['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept' | |
9 | 11 | ||
10 | print 'Updated headers' | ||
11 | print response.headers | ||
12 | current_app.logger.debug('Updated headers %s', response.headers) | ||
12 | 13 | ||
13 | 14 | return response | |
15 | |||
16 | from datetime import timedelta | ||
17 | from flask import make_response, request, current_app | ||
18 | from functools import update_wrapper | ||
19 | |||
20 | """ | ||
21 | def 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 | """ |
  | |||
2 | 2 | from .api import api | |
3 | 3 | from .user import user | |
4 | 4 | from .context import context | |
5 | from .sweet import sweet | ||
5 | 6 | from .app import app | |
6 | 7 | from .oauth import Oauth |
swtstore/classes/views/api.py
(69 / 85)
  | |||
1 | from flask import Module, jsonify, request, make_response, abort, g, json | ||
2 | #import json | ||
3 | from sqlalchemy.exc import IntegrityError | ||
1 | from flask import Module, jsonify, request, make_response, abort, g, json,\ | ||
2 | current_app | ||
4 | 3 | ||
5 | 4 | from swtstore.classes.models import Context | |
6 | 5 | from swtstore.classes.models import Sweet | |
7 | from swtstore.classes.exceptions import AlreadyExistsError | ||
6 | from swtstore.classes.exceptions import AlreadyExistsError, InvalidPayload | ||
8 | 7 | from swtstore.classes.utils import urlnorm # normalize URLs | |
9 | from swtstore.classes.utils.httputils import make_cross_origin_headers | ||
8 | from swtstore.classes.utils.httputils import makeCORSHeaders | ||
10 | 9 | from swtstore.classes import oauth | |
11 | 10 | ||
12 | 11 | ||
… | … | ||
13 | 13 | ||
14 | 14 | ||
15 | 15 | # 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']) | ||
17 | 18 | def getSweetById(id): | |
18 | try: | ||
19 | |||
20 | # Get a specific sweet | ||
21 | if request.method == 'GET': | ||
19 | 22 | sweet = Sweet.query.get(id) | |
20 | except: | ||
21 | abort(404) | ||
22 | 23 | ||
23 | if sweet is None: | ||
24 | abort(404) | ||
24 | if sweet is None: | ||
25 | abort(404) | ||
25 | 26 | ||
26 | print sweet | ||
27 | return jsonify(sweet.to_dict()) | ||
27 | current_app.logger.debug('getSweetById: %s', sweet) | ||
28 | return jsonify(sweet.to_dict()) | ||
28 | 29 | ||
30 | # Update a specific sweet | ||
31 | elif request.method == 'PUT': | ||
32 | payload = request.json | ||
33 | if payload is None: | ||
34 | abort(400) | ||
29 | 35 | ||
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 | 51 | # Post a sweet to the sweet store | |
31 | 52 | @api.route('/sweets', methods=['OPTIONS', 'POST']) | |
32 | 53 | @oauth.require_oauth('email', 'sweet') | |
… | … | ||
57 | 57 | ||
58 | 58 | client = oauth_request.client | |
59 | 59 | ||
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) | ||
62 | 62 | ||
63 | 63 | if request.method == 'OPTIONS': | |
64 | 64 | response.status_code = 200 | |
65 | 65 | return response | |
66 | 66 | ||
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 | 70 | g.error= 'data not found in payload!' | |
74 | 71 | abort(400) | |
75 | 72 | ||
76 | print 'new sweet payload recvd..' | ||
77 | print payload | ||
73 | current_app.logger.debug('new sweet payload recvd.. %s', payload) | ||
78 | 74 | ||
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 | ||
83 | 78 | ||
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) | ||
86 | 84 | ||
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 | 85 | 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 | 88 | return response | |
120 | 89 | ||
121 | 90 | ||
122 | 91 | # The Sweet query API: /sweets/q?who=<>&what=<>&where=<> | |
123 | 92 | # args: who, what, where | |
124 | 93 | @api.route('/sweets/q', methods=['GET', 'OPTIONS']) | |
125 | @oauth.require_oauth('sweet') | ||
126 | def querySweets(oauth_request): | ||
94 | #@oauth.require_oauth('sweet') | ||
95 | def querySweets(): | ||
127 | 96 | ||
128 | 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) | ||
131 | 100 | ||
132 | 101 | if request.method == 'OPTIONS': | |
133 | 102 | reponse.status_code = 200 | |
… | … | ||
112 | 112 | if args.get('who'): | |
113 | 113 | params['who'] = args.get('who') | |
114 | 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 | 116 | if args.get('where'): | |
118 | 117 | params['where'] = urlnorm(args.get('where')) | |
119 | 118 | ||
… | … | ||
120 | 120 | if len(params) == 0: | |
121 | 121 | abort(400) | |
122 | 122 | ||
123 | print 'recvd params' | ||
124 | print params | ||
123 | current_app.logger.debug('recvd params: %s', params) | ||
125 | 124 | ||
125 | sweets = Sweet.queryByAll(params) | ||
126 | 126 | ||
127 | sweets = Sweet.query.filter_by(**params).all() | ||
128 | |||
129 | 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 | 129 | abort(404) | |
132 | 130 | ||
133 | 131 | swts = [i.to_dict() for i in sweets] | |
… | … | ||
139 | 139 | @api.route('/contexts/<name>', methods=['GET']) | |
140 | 140 | def getContextByName(name): | |
141 | 141 | ||
142 | context = Context.query.filter_by(name=name).first() | ||
142 | context = Context.getByName(name) | ||
143 | 143 | if context is None: | |
144 | 144 | abort(404) | |
145 | 145 | ||
146 | print context | ||
146 | current_app.logger.debug('getContextByName : %s', context) | ||
147 | 147 | return jsonify(context.to_dict()) | |
148 | 148 | ||
149 | 149 | # Get a specific context with its definition; based on id | |
… | … | ||
154 | 154 | if context is None: | |
155 | 155 | abort(404) | |
156 | 156 | ||
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 | 160 | return jsonify(context.to_dict()) | |
162 | 161 | ||
163 | 162 | ||
… | … | ||
176 | 176 | # if not found send back a 400 | |
177 | 177 | abort(400) | |
178 | 178 | ||
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) | ||
182 | 180 | ||
183 | 181 | # if data is invalid send back 400 | |
184 | 182 | if 'name' not in payload and 'definition' not in payload: | |
… | … | ||
187 | 187 | ||
188 | 188 | except AlreadyExistsError: | |
189 | 189 | # context with same name exists; send back 400? | |
190 | print 'Already Exists Error' | ||
190 | current_app.logger.info('Context Already Exists Error') | ||
191 | 191 | abort(400) | |
192 | 192 | ||
193 | print 'new context' | ||
194 | print new_context | ||
193 | current_app.logger.debug('new context created: %s', new_context) | ||
194 | |||
195 | 195 | # all ok. save the new context | |
196 | 196 | res = new_context.persist() | |
197 | 197 | ||
… | … | ||
204 | 204 | @oauth.require_oauth('email') | |
205 | 205 | def getCurrentUser(oauth_request): | |
206 | 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 | 208 | response.status_code = 200 | |
210 | 209 | ||
211 | 210 | if request.method == 'OPTIONS': | |
212 | 211 | return response | |
213 | 212 | ||
213 | response.headers['Content-type'] = 'application/json' | ||
214 | # We have the user object along with the oauth request. Just return it back | ||
214 | 215 | response.data = json.dumps(oauth_request.user.to_dict()) | |
215 | 216 | return response |
swtstore/classes/views/app.py
(2 / 19)
  | |||
1 | |||
2 | 1 | # -*- coding utf-8 -*- | |
3 | 2 | # classes/views/apps.py | |
4 | 3 | ||
5 | |||
6 | 4 | from flask import Module, jsonify, request, render_template, redirect,\ | |
7 | 5 | url_for, flash, abort | |
8 | 6 | ||
… | … | ||
14 | 14 | ||
15 | 15 | app = Module(__name__) | |
16 | 16 | ||
17 | @app.route('/', methods=['GET']) | ||
18 | # list apps owned by current user | ||
19 | def list(): | ||
20 | current_user = User.getCurrentUser() | ||
21 | if current_user is None: | ||
22 | return redirect(url_for('frontend.index')) | ||
23 | 17 | ||
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 | 18 | @app.route('/register', methods=['GET', 'POST']) | |
32 | 19 | def register(): | |
33 | 20 | current_user = User.getCurrentUser() | |
34 | 21 | if current_user is None: | |
35 | 22 | return redirect(url_for('frontend.index')) | |
36 | 23 | ||
37 | user = current_user.to_dict() | ||
38 | |||
39 | 24 | if request.method == 'GET': | |
40 | return render_template('register_app.html', user=user) | ||
25 | return render_template('register_app.html') | ||
41 | 26 | ||
42 | 27 | elif request.method == 'POST': | |
43 | 28 | req_fields = ['name', 'host_url', 'redirect_uris', 'scopes'] | |
… | … | ||
43 | 43 | ) | |
44 | 44 | new_app.persist() | |
45 | 45 | ||
46 | return redirect(url_for('list')) | ||
46 | return redirect(url_for('user.myApps')) |
  | |||
1 | |||
2 | 1 | # -*- coding utf-8 -*- | |
3 | 2 | # classes/views/context.py | |
4 | 3 | ||
4 | from flask import Module, jsonify, request, render_template, redirect,\ | ||
5 | url_for, json, current_app | ||
5 | 6 | ||
6 | from flask import Module, jsonify, request, render_template, redirect, url_for | ||
7 | import json | ||
8 | |||
9 | 7 | from swtstore.classes.models import Context | |
10 | 8 | from swtstore.classes.models.um import User | |
11 | 9 | ||
12 | 10 | ||
13 | 11 | context = Module(__name__) | |
14 | 12 | ||
15 | @context.route('/', methods=['GET']) | ||
16 | # list apps owned by current user | ||
17 | def 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 | 13 | @context.route('/register', methods=['GET', 'POST']) | |
31 | 14 | def register(): | |
32 | 15 | current_user = User.getCurrentUser() | |
33 | 16 | if current_user is None: | |
34 | return redirect(url_for('index')) | ||
17 | return redirect(url_for('frontend.index')) | ||
35 | 18 | ||
36 | user = current_user.to_dict() | ||
37 | |||
38 | 19 | if request.method == 'GET': | |
39 | return render_template('register_context.html', user=user) | ||
20 | return render_template('register_context.html') | ||
40 | 21 | ||
41 | 22 | if request.method == 'POST': | |
42 | 23 | if not request.form.get('name') or not request.form.get('defn'): | |
43 | 24 | abort(400) | |
44 | 25 | ||
45 | print request.form.get('defn') | ||
26 | current_app.logger.debug('New Context: defn: %s ', | ||
27 | request.form.get('defn')) | ||
46 | 28 | json_ld = json.loads(request.form.get('defn')) | |
47 | print json_ld | ||
29 | current_app.logger.debug('Resulting json_ld %s', json_ld) | ||
48 | 30 | ||
49 | 31 | new_context = Context( | |
50 | 32 | name = request.form.get('name'), | |
51 | 33 | definition = json_ld, | |
52 | 34 | user_id = current_user.id | |
53 | 35 | ) | |
54 | print new_context | ||
36 | current_app.logger.debug('New Context created: %s', new_context) | ||
55 | 37 | new_context.persist() | |
56 | 38 | ||
57 | return redirect(url_for('list')) | ||
39 | return redirect(url_for('user.myContexts')) |
  | |||
2 | 2 | # classes/views/frontend.py | |
3 | 3 | ||
4 | 4 | ||
5 | from flask import Module, jsonify, request, render_template, redirect, url_for | ||
5 | from flask import Module, jsonify, request, render_template, redirect,\ | ||
6 | url_for, g, current_app | ||
6 | 7 | ||
8 | from sqlalchemy import desc | ||
9 | |||
7 | 10 | from swtstore.classes.models import Sweet | |
8 | 11 | from swtstore.classes.models.um import User | |
9 | 12 | ||
… | … | ||
15 | 15 | ||
16 | 16 | @frontend.route('/', methods=['GET']) | |
17 | 17 | def index(): | |
18 | # sweets = Sweet.query.somethingToGetRelevant() | ||
19 | sweets = Sweet.query.all() | ||
18 | sweets = Sweet.getFrontendSwts() | ||
20 | 19 | ||
21 | 20 | user = User.getCurrentUser() | |
22 | if user is not None: | ||
23 | user = user.to_dict() | ||
24 | 21 | ||
25 | return render_template('index.html', sweets=sweets, user=user) | ||
22 | return render_template('index.html', sweets=sweets) | ||
26 | 23 | ||
27 | 24 | ||
28 | 25 | # Create a new sweet context |
  | |||
1 | 1 | # -*- coding utf-8 -*- | |
2 | 2 | # classes/views/oauth.py | |
3 | 3 | ||
4 | from flask import Module, jsonify, request, render_template, redirect, url_for | ||
5 | import json | ||
4 | from flask import Module, jsonify, request, render_template, redirect,\ | ||
5 | url_for, current_app | ||
6 | 6 | ||
7 | 7 | from swtstore.classes import oauth | |
8 | 8 | from swtstore.classes.models.um import User | |
… | … | ||
21 | 21 | if request.method == 'GET': | |
22 | 22 | client_id = kwargs.get('client_id') | |
23 | 23 | client = Client.query.get(client_id) | |
24 | print '/authorize: ' | ||
25 | print client | ||
24 | current_app.logger.debug('In /authorize: client: %s', client) | ||
26 | 25 | kwargs['client'] = client | |
27 | 26 | kwargs['user'] = current_user | |
28 | print kwargs | ||
27 | current_app.logger.debug('kwargs %s', kwargs) | ||
29 | 28 | return render_template('authorize.html', **kwargs) | |
30 | 29 | ||
31 | 30 | confirm = request.form.get('confirm', 'no') | |
32 | print confirm | ||
31 | current_app.logger.debug('confirm authorize from user: %s', confirm) | ||
33 | 32 | return confirm == 'yes' | |
34 | 33 | ||
35 | 34 | @Oauth.route('/token', methods=['GET', 'POST']) | |
36 | 35 | @oauth.token_handler | |
37 | 36 | def access_token(): | |
38 | 37 | #print request.form | |
39 | print 'access token touched..' | ||
38 | current_app.logger.debug('access token touched..') | ||
40 | 39 | return None | |
41 | 40 | ||
42 | 41 | @Oauth.route('/errors') |
swtstore/classes/views/sweet.py
(28 / 0)
  | |||
1 | # -*- coding utf-8 -*- | ||
2 | # classes/views/sweet.py | ||
3 | |||
4 | |||
5 | from flask import Module, jsonify, request, render_template, redirect,\ | ||
6 | url_for, abort, json | ||
7 | |||
8 | from swtstore.classes.models import Context | ||
9 | from swtstore.classes.models import Sweet | ||
10 | from swtstore.classes.models.um import User | ||
11 | |||
12 | |||
13 | sweet = Module(__name__) | ||
14 | |||
15 | @sweet.route('/<id>', methods=['GET']) | ||
16 | def 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
(58 / 14)
  | |||
3 | 3 | ||
4 | 4 | import requests | |
5 | 5 | ||
6 | # flask imports | ||
6 | 7 | from flask import Module, jsonify, request, render_template, session,\ | |
7 | make_response, url_for, redirect | ||
8 | import json | ||
8 | make_response, url_for, redirect, json, current_app | ||
9 | 9 | ||
10 | # swtstore imports | ||
10 | 11 | from swtstore.classes.models.um import User | |
12 | from swtstore.classes.models import Sweet, Context, Client | ||
11 | 13 | ||
12 | from swtstore.classes.utils.httputils import make_cross_origin_headers | ||
14 | from swtstore.classes.utils.httputils import makeCORSHeaders | ||
13 | 15 | from swtstore.config import DefaultConfig | |
14 | 16 | ||
15 | 17 | ||
… | … | ||
23 | 23 | def login(): | |
24 | 24 | ||
25 | 25 | response = make_response() | |
26 | #response = make_cross_origin_headers(response) | ||
26 | #response = makeCORSHeaders(response) | ||
27 | 27 | ||
28 | 28 | if 'assertion' not in request.form: | |
29 | 29 | response.status_code = 400 | |
30 | 30 | return response | |
31 | 31 | ||
32 | print request.remote_addr | ||
32 | current_app.logger.debug('remote address of request for user login %s', | ||
33 | request.remote_addr) | ||
34 | |||
33 | 35 | data = {'assertion': request.form['assertion'], 'audience': | |
34 | 36 | config.SWTSTORE_URL} | |
35 | 37 | ||
36 | 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()) | ||
39 | 42 | ||
40 | 43 | if resp.ok: | |
41 | 44 | verified_data = json.loads(resp.content) | |
… | … | ||
48 | 48 | current_user = User.query.filter_by(email=user_email).first() | |
49 | 49 | # user doesn't exist; create her | |
50 | 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 | 55 | new_user = User('', user_email) | |
54 | 56 | new_user.persist() | |
55 | 57 | current_user = new_user | |
56 | 58 | ||
57 | 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 | 62 | session['email'] = current_user.email | |
60 | 63 | ||
61 | 64 | response.status_code = 200 | |
… | … | ||
72 | 72 | def logout(): | |
73 | 73 | ||
74 | 74 | response = make_response() | |
75 | #response = make_cross_origin_headers(response) | ||
75 | #response = makeCORSHeaders(response) | ||
76 | 76 | ||
77 | 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 | 79 | session.pop('email') | |
81 | 80 | ||
82 | 81 | response.status_code = 200 | |
… | … | ||
92 | 92 | return render_template('me.html', user=current_user) | |
93 | 93 | ||
94 | 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 | 99 | current_user.update(username=username) | |
97 | 100 | ||
98 | 101 | return redirect(url_for('profile')) | |
102 | |||
103 | |||
104 | @user.route('/me/sweets', methods=['GET']) | ||
105 | def 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']) | ||
116 | def 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']) | ||
127 | def 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
(64 / 0)
  | |||
5 | 5 | this.attachLogout(); | |
6 | 6 | this.initPersona(); | |
7 | 7 | this.activeNav(); | |
8 | $('.edit-sweet').click(ss.editSweet); | ||
8 | 9 | }; | |
9 | 10 | ||
10 | 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 | }; | |
73 | 136 | ||
74 | 137 | })(ss); |
  | |||
28 | 28 | <small><i>created: {{sweet.created }}</i></small> | |
29 | 29 | ||
30 | 30 | <span class="pull-right permalink"> | |
31 | <a href="#"> | ||
31 | <a href="{{ url_for('sweet.showSweet', id=sweet.id) }}"> | ||
32 | 32 | <i class="glyphicon glyphicon-share"></i> | |
33 | 33 | </a> | |
34 | 34 | </li> |
swtstore/templates/layout.html
(9 / 17)
  | |||
17 | 17 | <li> | |
18 | 18 | <a href="{{ url_for('frontend.index') }}"> Home </a> | |
19 | 19 | </li> | |
20 | {% if not user %} | ||
20 | {% if not session.email %} | ||
21 | 21 | <li> | |
22 | 22 | <a id="login" href="#"> Login </a> | |
23 | 23 | </li> | |
24 | 24 | {% else %} | |
25 | <!-- swts list --> | ||
26 | <li> | ||
27 | <a href="{{ url_for('user.mySweets') }}"> My Sweets </a> | ||
28 | </li> | ||
25 | 29 | <!-- the cog menu --> | |
26 | 30 | <li class="dropdown user-menu"> | |
27 | 31 | <a class="dropdown-toggle" data-toggle="dropdown" href="#"> | |
… | … | ||
33 | 33 | </a> | |
34 | 34 | <ul class="dropdown-menu" role="menu"> | |
35 | 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 | 37 | <li class="divider"></li> | |
38 | 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 | 40 | </ul> | |
41 | 41 | </li> | |
42 | 42 | <!-- the user menu --> | |
… | … | ||
48 | 48 | <ul class="dropdown-menu" role="menu"> | |
49 | 49 | <li> | |
50 | 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 | 52 | </small></a> | |
57 | 53 | </li> | |
58 | 54 | <li class="divider"></li> | |
… | … | ||
85 | 85 | ss.loginURL = function() { return "{{ url_for('user.login') }}"; }; | |
86 | 86 | ss.logoutURL = function() { return "{{ url_for('user.logout') }}"; }; | |
87 | 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 | 90 | window.onload = function() { | |
99 | 91 | ss.init(); |
swtstore/templates/my_apps.html
(25 / 0)
  | |||
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 %} |
  | |||
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 %} |
  | |||
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">×</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 %} |
  | |||
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 %} |