-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
404 lines (358 loc) · 10.1 KB
/
Copy pathapp.py
File metadata and controls
404 lines (358 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
import os
import datetime
from flask import Flask, request, abort, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
from models import setup_db, Actor, Gender, Movie
from auth import AuthError, requires_auth
def create_app():
# create and configure the app
#print(__name__)
app = Flask(__name__)
CORS(app)
#setup_db(app, os.getenv('SQLALCHEMY_DATABASE_URI'))
#setup_db(app, os.getenv('DATABASE_URI'))
#setup_db(app, os.environ['DATABASE_URL'])
#if __name__ == '__main__':
setup_db(app, os.environ['DATABASE_URL'])
return app
#APP = create_app()
#APP = create_app(os.environ['DATABASE_URL'], test=False)
APP = create_app()
@APP.route('/', methods=['GET'])
def check_health():
#
# base endpoint without authentication for check app health
#
return jsonify({
'success': True,
'healthy': True,
'db': os.environ['DATABASE_URL']
#'path': os.environ['DATABASE_URL']
})
@APP.route('/actors', methods=['GET'])
@requires_auth('get:actors')
def get_actors(payload):
#
# Endpoint to get the list of actors, requires get:actors permission
#
try:
ans = Actor.query.all()
formatted_ans = []
for i in ans:
formatted_ans.append(i.format())
except:
abort(422)
return jsonify({
'actors': formatted_ans,
'total_actors': len(formatted_ans),
'success': True,
})
@APP.route('/movies', methods=['GET'])
@requires_auth('get:movies')
def get_movies(payload):
#
# Endpoint to get the list of movies, requires get:movies permission
#
try:
ans = Movie.query.all()
formatted_ans = []
for i in ans:
formatted_ans.append(i.format())
except:
abort(422)
return jsonify({
'movies': formatted_ans,
'total_movies': len(formatted_ans),
'success': True,
})
@APP.route('/actors/<int:actor_id>', methods=['DELETE'])
@requires_auth('delete:actor')
def delete_actor(payload, actor_id):
#
# Endpoint for delete actor by providing the actor id, requires delete:actor permission
#
try:
actor = Actor.query.filter(Actor.id == actor_id).one_or_none()
except:
# processing error
abort(422)
if actor:
#print('if')
try:
actor.delete()
except:
# processing error
abort(422)
else:
# actor not found
#print('else')
abort(404)
return jsonify({
'actor_id': actor_id,
'success': True,
})
@APP.route('/movies/<int:movie_id>', methods=['DELETE'])
@requires_auth('delete:movie')
def delete_movie(payload, movie_id):
#
# Endpoint to delete movie by providing the movie id, requires delete:movie permission
#
try:
movie = Movie.query.filter(Movie.id == movie_id).one_or_none()
except:
# processing error
abort(422)
if movie:
#print('if')
try:
movie.delete()
except:
# processing error
abort(422)
else:
# movie not found
#print('else')
abort(404)
return jsonify({
'movie_id': movie_id,
'success': True,
})
def check_movies_exist(movies_id):
#
# Called by add_actor enpoint, check the list of movies provided. Return the Movies objects if all exists,
# otherwise return None
#
movies = Movie.query.filter(Movie.id.in_(movies_id)).all()
#print(movies_id)
#print(movies)
if len(movies) == len(movies_id):
return movies
else:
return None
@APP.route('/actors', methods=['POST'])
@requires_auth('post:actor')
def add_actor(payload):
#
# Endpoint to add actor. name, age, gender must be provided. movies_id is optional,
# if provided, endpoint will check the existence of them. Actor can only be added
# if all the movies_id exist
#
body = request.get_json()
if not body:
abort(400)
else:
name = body.get('name')
age = body.get('age')
gender = body.get('gender')
movies_id = list(set(body.get('movies_id', [])))
if name is None or age is None or gender is None:
abort(400)
else:
# determine all the movies exist
movies = check_movies_exist(movies_id)
#print(movies)
if movies is not None or movies_id == []:
try:
#print(f'{name} {age} {gender} {movies}')
actor = Actor(name=name, age=age, gender=Gender(gender))
actor.movies = movies
actor.insert()
except:
# processing error
abort(422)
else:
# input error, some or all movies do not exist
abort(404)
return jsonify({
'success': True,
'actor_id': actor.id,
})
def check_actors_exist(actors_id):
#
# Call by add_movie endpoint, it checks for the existence of the list actors_id,
# return Actor objects if all exist, otherwise return None
#
actors = Actor.query.filter(Actor.id.in_(actors_id)).all()
if len(actors) == len(actors_id):
return actors
else:
return None
@APP.route('/movies', methods=['POST'])
@requires_auth('post:movie')
def add_movie(payload):
#
# Endpoint to add movie. Must provide title, date_release and actors_id,
# endpoint will check the existence of the actors_id provided, movie can be
# added if all actors_id exist
#
body = request.get_json()
if not body:
abort(400)
else:
title = body.get('title')
date_release = body.get('date_release')
actors_id = list(set(body.get('actors_id', [])))
if title is None or date_release is None or actors_id == []:
abort(400)
else:
# determine all the actors exist
actors = check_actors_exist(actors_id)
if actors:
try:
date_release = datetime.datetime.strptime(date_release, '%Y%m%d').date()
#print(f'{title} {date_release} {actors_id} {actors}')
movie = Movie(title=title, date_release=date_release, actors=actors)
movie.insert()
except:
# processing error
abort(422)
else:
# input error, some or all actors do not exist
abort(404)
return jsonify({
'success': True,
'movie_id': movie.id,
})
@APP.route('/actors/<int:actor_id>', methods=['PATCH'])
@requires_auth('patch:actor')
def update_actor(payload, actor_id):
#
# Endpoint to update actor. name, age, gender must be provided. movies_id is optional,
# if provided, endpoint will check the existence of them. Actor can only be updated
# if all the movies_id exist
#
body = request.get_json()
if not body:
abort(400)
else:
name = body.get('name')
age = body.get('age')
gender = body.get('gender')
movies_id = list(set(body.get('movies_id', [])))
if name is None or age is None or gender is None:
abort(400)
else:
# determine all the movies exist
movies = check_movies_exist(movies_id)
#print(movies)
if movies is not None or movies_id == []:
#print(f'{name} {age} {gender} {movies}')
try:
actor = Actor.query.filter(Actor.id == actor_id).one_or_none()
except:
abort(422)
if actor:
try:
actor.name = name
actor.age = age
actor.gender = Gender(gender)
actor.movies = movies
actor.update()
except:
abort(422)
else:
#print('1')
# The actor that going to be modified does not exist
abort(404)
else:
#print('2')
# Some or all movies_id do not exist
abort(404)
return jsonify({
'success': True,
'actor_id': actor.id,
})
@APP.route('/movies/<int:movie_id>', methods=['PATCH'])
@requires_auth('patch:movie')
def update_movie(payload, movie_id):
#
# Endpoint to update movie. Must provide title, date_release and actors_id,
# endpoint will check the existence of the actors_id provided, movie can be
# updated if all actors_id exist
#
body = request.get_json()
if not body:
abort(400)
else:
title = body.get('title')
date_release = body.get('date_release')
actors_id = list(set(body.get('actors_id', [])))
if title is None or date_release is None or actors_id == []:
abort(400)
else:
# determine all the actors exist
actors = check_actors_exist(actors_id)
if actors:
try:
movie = Movie.query.filter(Movie.id == movie_id).one_or_none()
except:
abort(422)
if movie:
try:
movie.title = title
movie.date_release = datetime.datetime.strptime(date_release, '%Y%m%d').date()
movie.actors = actors
movie.update()
except:
abort(422)
else:
#print('1')
# The movie going to be modified does not exist
abort(404)
else:
#print('2')
# Some or all actors_id do not exist
abort(404)
return jsonify({
'success': True,
'movie_id': movie.id,
})
#
# Error handler to format error as JSON object
#
@APP.errorhandler(400)
def bad_request(error):
return jsonify({
"success": False,
"error": 400,
"message": "bad request"
}), 400
@APP.errorhandler(404)
def resouce_not_found(error):
return jsonify({
"success": False,
"error": 404,
"message": "resource not found"
}), 404
@APP.errorhandler(405)
def method_not_allow(error):
return jsonify({
"success": False,
"error": 405,
"message": "method not allow"
}), 405
@APP.errorhandler(422)
def unprocessable(error):
return jsonify({
"success": False,
"error": 422,
"message": "unprocessable"
}), 422
@APP.errorhandler(500)
def internal_server_error(error):
return jsonify({
"success": False,
"error": 500,
"message": "internal server error"
}), 500
@APP.errorhandler(AuthError)
def auth_error(error):
return jsonify({
"success": False,
"error": error.status_code,
"message": error.error['description']
}), error.status_code
if __name__ == '__main__':
# APP = create_app(os.environ['DATABASE_URL'])
APP.run(host='0.0.0.0', port=8080, debug=True)