1 |
from flask import Module, jsonify, request, make_response |
2 |
from flask import abort, g, json, current_app |
3 |
|
4 |
from swtstore.classes.models import Context, Sweet |
5 |
from swtstore.classes.exceptions import AlreadyExistsError, InvalidPayload,\ |
6 |
ContextDoNotExist |
7 |
from swtstore.classes.utils import urlnorm # normalize URLs |
8 |
from swtstore.classes.utils.httputils import makeCORSHeaders |
9 |
from swtstore.classes import oauth |
10 |
|
11 |
|
12 |
api = Module(__name__) |
13 |
|
14 |
|
15 |
# Get a specific sweet |
16 |
# Update a specific sweet |
17 |
@api.route('/sweets/<int:id>', methods=['GET', 'PUT']) |
18 |
def getSweetById(id): |
19 |
|
20 |
# Get a specific sweet |
21 |
if request.method == 'GET': |
22 |
sweet = Sweet.query.get(id) |
23 |
|
24 |
if sweet is None: |
25 |
abort(404) |
26 |
|
27 |
current_app.logger.debug('getSweetById: %s', sweet) |
28 |
return jsonify(sweet.to_dict()) |
29 |
|
30 |
# Update a specific sweet |
31 |
elif request.method == 'PUT': |
32 |
payload = request.json |
33 |
if payload is None: |
34 |
abort(400) |
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 |
|
51 |
# Post a sweet to the sweet store |
52 |
@api.route('/sweets', methods=['OPTIONS', 'POST']) |
53 |
@oauth.require_oauth('email', 'sweet') |
54 |
def createSweet(oauth_request): |
55 |
|
56 |
response = make_response() |
57 |
|
58 |
client = oauth_request.client |
59 |
|
60 |
#TODO: make a decorator of CORS request |
61 |
response = makeCORSHeaders(response, client.host_url) |
62 |
|
63 |
if request.method == 'OPTIONS': |
64 |
response.status_code = 200 |
65 |
return response |
66 |
|
67 |
payload = request.json or request.data |
68 |
if not payload: |
69 |
current_app.logger.error('data not found in payload!') |
70 |
g.error = 'data not found in payload!' |
71 |
abort(400) |
72 |
|
73 |
current_app.logger.debug('new sweet payload recvd.. %s', payload) |
74 |
|
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 |
78 |
|
79 |
try: |
80 |
swts = Sweet.createSweets(who, payload) |
81 |
except (InvalidPayload, ContextDoNotExist) as e: |
82 |
current_app.logger.error('Error creating sweets. Error: %s', e) |
83 |
abort(400) |
84 |
|
85 |
response.status_code = 200 |
86 |
response.headers['Content-type'] = 'application/json' |
87 |
response.data = json.dumps([i.to_dict() for i in swts]) |
88 |
return response |
89 |
|
90 |
|
91 |
# The Sweet query API: /sweets/q?who=<>&what=<>&where=<> |
92 |
# args: who, what, where |
93 |
@api.route('/sweets/q', methods=['GET', 'OPTIONS']) |
94 |
#@oauth.require_oauth('sweet') |
95 |
def querySweets(): |
96 |
|
97 |
response = make_response() |
98 |
origin = request.headers.get('Origin', '*') |
99 |
response = makeCORSHeaders(response, origin) |
100 |
|
101 |
if request.method == 'OPTIONS': |
102 |
response.status_code = 200 |
103 |
return response |
104 |
|
105 |
args = request.args |
106 |
|
107 |
# if no arguments are passed, its an invalid request |
108 |
if args is None: |
109 |
abort(400) |
110 |
|
111 |
params = {} |
112 |
if args.get('who'): |
113 |
params['who'] = args.get('who') |
114 |
if args.get('what'): |
115 |
params['what'] = args.get('what') |
116 |
if args.get('where'): |
117 |
params['where'] = urlnorm(args.get('where')) |
118 |
|
119 |
# if none of the above parameters are present, its an invalid request |
120 |
if len(params) == 0: |
121 |
abort(400) |
122 |
|
123 |
current_app.logger.debug('recvd params: %s', params) |
124 |
|
125 |
sweets = Sweet.queryByAll(params) |
126 |
|
127 |
if len(sweets) == 0: |
128 |
current_app.logger.info('No sweets found to satisfy query..') |
129 |
abort(404) |
130 |
|
131 |
swts = [i.to_dict() for i in sweets] |
132 |
|
133 |
response.data = json.dumps(swts) |
134 |
response.headers['Content-type'] = 'application/json' |
135 |
return response |
136 |
|
137 |
|
138 |
# Get a specific context with its definition; based on name |
139 |
@api.route('/contexts/<name>', methods=['GET']) |
140 |
def getContextByName(name): |
141 |
|
142 |
context = Context.getByName(name) |
143 |
if context is None: |
144 |
abort(404) |
145 |
|
146 |
current_app.logger.debug('getContextByName : %s', context) |
147 |
return jsonify(context.to_dict()) |
148 |
|
149 |
|
150 |
# Get a specific context with its definition; based on id |
151 |
@api.route('/contexts/<int:id>', methods=['GET']) |
152 |
def getContextById(id): |
153 |
|
154 |
context = Context.query.get(id) |
155 |
if context is None: |
156 |
abort(404) |
157 |
|
158 |
current_app.logger.debug('getContextById response: %s', |
159 |
jsonify(context.to_dict()).data) |
160 |
|
161 |
return jsonify(context.to_dict()) |
162 |
|
163 |
|
164 |
# Create a new Sweet Context |
165 |
@oauth.require_oauth('email', 'context') |
166 |
@api.route('/contexts', methods=['POST']) |
167 |
def createContext(): |
168 |
|
169 |
response = make_response() |
170 |
|
171 |
# try our best to get the data from request object |
172 |
if request.json: |
173 |
payload = request.json |
174 |
elif request.data: |
175 |
payload = json.loads(request.data) |
176 |
else: |
177 |
# if not found send back a 400 |
178 |
abort(400) |
179 |
|
180 |
current_app.logger.debug('new context payload recvd.. %s', payload) |
181 |
|
182 |
# if data is invalid send back 400 |
183 |
if 'name' not in payload and 'definition' not in payload: |
184 |
abort(400) |
185 |
|
186 |
try: |
187 |
new_context = Context(payload['name'], payload['definition']) |
188 |
|
189 |
except AlreadyExistsError: |
190 |
# context with same name exists; send back 400? |
191 |
current_app.logger.info('Context Already Exists Error') |
192 |
abort(400) |
193 |
|
194 |
current_app.logger.debug('new context created: %s', new_context) |
195 |
|
196 |
# all ok. save the new context |
197 |
new_context.persist() |
198 |
|
199 |
response.status_code = 200 |
200 |
return response |
201 |
|
202 |
|
203 |
# Send back logged in user data |
204 |
@api.route('/users/me', methods=['GET', 'OPTIONS']) |
205 |
@oauth.require_oauth('email') |
206 |
def getCurrentUser(oauth_request): |
207 |
response = make_response() |
208 |
response = makeCORSHeaders(response, oauth_request.client.host_url) |
209 |
response.status_code = 200 |
210 |
|
211 |
if request.method == 'OPTIONS': |
212 |
return response |
213 |
|
214 |
response.headers['Content-type'] = 'application/json' |
215 |
# We have the user object along with the oauth request. Just return it back |
216 |
response.data = json.dumps(oauth_request.user.to_dict()) |
217 |
return response |