def setup_app(): app = Bottle() app.config.update(config.APP_CONFIG) setup_routing(app) setup_db(app) bottle.app.push(app) app = SessionMiddleware(app, config.SESSION_OPTS) return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) cors = CORS(app) @app.route('/') # @requires_auth() def greeting(): """Routes user to a welcome page.""" return render_template('home.html') # return 'Welcome to Magic: The Gathering API' @app.route('/contact') def contact_page(): """Routes user to contact info page.""" return render_template('contact.html') # @app.route('/decks') # @requires_auth('get:decks') # def get_decks(): # """ # Displays all the decks. # An mtg_browser or mtg_publisher role is needed. # """ # decks = Deck.query.all() # decks_readable = [ # f'{deck.title} by {deck.creator}' for deck in decks] # return jsonify(decks_readable) # @app.route('/cards') # @requires_auth('get:cards') # def get_cards(): # """ # Displays all the cards. # An mtg_browser or mtg_publisher role is needed. # """ # cards = Card.query.all() # cards_readable = [ # f'{card.name}' for card in cards] # return jsonify(cards_readable) # @app.route('/cards', methods=['post']) # @requires_auth('post:cards') # def post_card(): # """ # Allows a user to post a new card to the database. # The user must supply a JSON body in their post request as well as a # valid JWT in the header. The JSON body must contain "name" and # "type", and it can optionally contain "colors" and "cmc". # An mtg_publisher role is needed. # """ # data = json.loads(request.data) # name = data.get('name') # type = data.get('type') # colors = data.get('colors') # cmc = data.get('cmc') # try: # new_card = Card(name, type, colors, cmc) # new_card.insert() # except Exception as e: # print('There was an exception:') # print(e) # abort(422) # return jsonify('posted card successfully') # @app.route('/cards/<int:id>', methods=['patch']) # @requires_auth('patch:cards') # def update_card(id): # """ # Allows a user to patch an existing card in the database. # The user must indicate which card they want to edit by providing an id. # They must also supply a JSON body in their patch request as well as a # valid JWT in the header. The JSON body should contain key:value pairs # for the card attribtutes the user would like to update. # An mtg_publisher role is needed. # """ # try: # working_card = Card.query.get(id) # test = working_card.id # except Exception as e: # print(f'There was an exception:\n{e}') # abort(404) # try: # data = json.loads(request.data) # name = data.get('name') # type = data.get('type') # colors = data.get('colors') # cmc = data.get('cmc') # except Exception as e: # print(f'There was an exception:\n{e}') # abort(400) # try: # if name: # working_card.name = name # if type: # working_card.type = type # if colors: # working_card.colors = colors # if cmc: # working_card.cmc = cmc # working_card.update() # except Exception as e: # print(f'There was an exception:\n{e}') # abort(422) # return f""" # updated card successfully: {working_card.name} - # {working_card.type} - {working_card.colors} - # {working_card.cmc} # """ # @app.route('/cards/<int:id>', methods=['delete']) # @requires_auth('delete:cards') # def delete_card(id): # """ # Allows a user to delete a card from the database. # The user must indicate which card they want to delete by providing # an id. They must also supply a valid JWT in the header. # An mtg_publisher role is needed. # """ # try: # working_card = Card.query.get(id) # test = working_card.id # except Exception as e: # print(f'There was an exception:\n{e}') # abort(404) # try: # working_card.delete() # except Exception as e: # print(f'There was an exception:\n{e}') # abort(422) # return f""" # deleted card successfully: # {working_card.id} - {working_card.name} # """ # # Error Handling # @app.errorhandler(400) # def bad_request(error): # return jsonify({ # "success": False, # "error": 400, # "message": "the client sent a bad request" # }), 400 # @app.errorhandler(401) # def unauthorized(error): # return jsonify({ # "success": False, # "error": 401, # "message": "user is not authorized to access this resource" # }), 401 # @app.errorhandler(404) # def resource_not_found(error): # return jsonify({ # "success": False, # "error": 404, # "message": "resource not found" # }), 404 # @app.errorhandler(405) # def method_not_allowed(error): # return jsonify({ # "success": False, # "error": 405, # "message": "the request method is not allowed on this resource" # }), 405 # @app.errorhandler(422) # def unprocessable(error): # return jsonify({ # "success": False, # "error": 422, # "message": "the request was unprocessable" # }), 422 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) CORS(app, resources={r"/*": {'origins': '*'}}) @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization, true') response.headers.add('Access-Control-Allow-Headers', 'GET, PATCH, POST, DELETE, OPTIONS') return response @app.route('/') def index(): return redirect(LOGIN_URI, 302) @app.route('/welcome') def welcome(): return jsonify({ 'success': True, 'message': 'Login was successful, welcome!' }) ############################### # trainers related end-points # ############################### @app.route('/trainers', methods=['GET']) @requires_auth('get:trainers') def get_trainers(): if request.get_json(): abort(405) try: trainers = Trainer.query.all() if trainers is None: raise AuthError( { 'code': 'no_trainers', 'description': 'There are no trainers on system yet.' }, 404) except AuthError as e: abort(e.status_code, e.error) trainers_formatted = [] for trainer in trainers: trainers_formatted.append(trainer.format()) return jsonify({'success': True, 'trainers': trainers_formatted}) @app.route('/trainers', methods=['POST']) @requires_auth('post:trainers') def add_trainer(): request_data = request.get_json() try: if len(request_data) > 3: raise AuthError( { 'description': 'Please include only the name, gender, and age of trainer.' }, 400) if not request_data['name']: raise AuthError({'description': 'Trainer name is missing.'}, 400) if not request_data['gender']: raise AuthError({'description': 'Trainer gender is missing.'}, 400) if not request_data['age']: raise AuthError({'description': 'Trainer age is missing.'}, 400) except AuthError as e: abort(e.status_code, e.error) new_trainer = Trainer() new_trainer.name = request_data['name'] new_trainer.gender = request_data['gender'] new_trainer.age = request_data['age'] new_trainer.insert() return jsonify({'success': True, 'new_trainer': new_trainer.format()}) @app.route('/trainers/<id>', methods=['DELETE']) @requires_auth('delete:trainers') def delete_trainer(id): try: target_trainer = Trainer.query.filter_by(id=id).first() if target_trainer is None: raise AuthError( { 'code': 'trainer_not_found', 'description': 'There is no trainer with the reuqested id to delete.' }, 404) except AuthError as e: abort(e.status_code, e.error) target_trainer.delete() return jsonify({ 'success': True, 'deleted_trainer': target_trainer.format() }) @app.route('/trainers/<id>', methods=['PATCH']) @requires_auth('patch:trainers') def patch_trainer(id): request_data = request.get_json() try: target_trainer = Trainer.query.filter_by(id=id).first() if target_trainer is None: raise AuthError( { 'code': 'trainer_not_found', 'description': 'There is no trainer with the reuqested id to modify.' }, 404) except AuthError as e: abort(e.status_code, e.error) if 'name' in request_data: target_trainer.name = request_data['name'] if 'gender' in request_data: target_trainer.gender = request_data['gender'] if 'age' in request_data: target_trainer.age = request_data['age'] target_trainer.update() return jsonify({ 'success': True, 'modified_trainer': target_trainer.format() }) ############################## # clients related end-points # ############################## @app.route('/clients', methods=['GET']) @requires_auth('get:clients') def get_clients(): if request.get_json(): abort(405) try: clients = Client.query.all() if clients is None: raise AuthError( { 'code': 'no_clients', 'description': 'There are no clients on system yet.' }, 404) except AuthError as e: abort(e.status_code, e.error) clients_formatted = [] for client in clients: clients_formatted.append(client.format()) return jsonify({'success': True, 'clients': clients_formatted}) @app.route('/clients', methods=['POST']) @requires_auth('post:clients') def add_client(): request_data = request.get_json() try: if len(request_data) > 3: raise AuthError( { 'description': 'Please include only the name, gender, and age of client.' }, 400) if not request_data['name']: raise AuthError({'description': 'Client name is missing.'}, 400) if not request_data['gender']: raise AuthError({'description': 'Client gender is missing.'}, 400) if not request_data['age']: raise AuthError({'description': 'Client age is missing.'}, 400) except AuthError as e: abort(e.status_code, e.error) new_client = Client() new_client.name = request_data['name'] new_client.gender = request_data['gender'] new_client.age = request_data['age'] new_client.insert() return jsonify({'success': True, 'new_client': new_client.format()}) @app.route('/clients/<id>', methods=['DELETE']) @requires_auth('delete:clients') def delete_client(id): try: target_client = Client.query.filter_by(id=id).first() if target_client is None: raise AuthError( { 'code': 'client_not_found', 'description': 'There is no client with the reuqested id to delete.' }, 404) except AuthError as e: abort(e.status_code, e.error) target_client.delete() return jsonify({ 'success': True, 'deleted_client': target_client.format() }) @app.route('/clients/<id>', methods=['PATCH']) @requires_auth('patch:clients') def patch_client(id): request_data = request.get_json() try: target_client = Client.query.filter_by(id=id).first() if target_client is None: raise AuthError( { 'code': 'client_not_found', 'description': 'There is no client with the reuqested id to modify.' }, 404) except AuthError as e: abort(e.status_code, e.error) if 'name' in request_data: target_client.name = request_data['name'] if 'gender' in request_data: target_client.gender = request_data['gender'] if 'age' in request_data: target_client.age = request_data['age'] target_client.update() return jsonify({ 'success': True, 'modified_client': target_client.format() }) ############################### # sessions related end-points # ############################### @app.route('/sessions', methods=['GET']) @requires_auth('get:sessions') def get_sessions(): if request.get_json(): abort(405) try: sessions = Session.query.all() if sessions is None: raise AuthError( { 'code': 'no_sessions', 'description': 'There are no sessions on system yet.' }, 404) except AuthError as e: abort(e.status_code, e.error) sessions_formatted = [] for session in sessions: sessions_formatted.append(session.format()) return jsonify({'success': True, 'sessions': sessions_formatted}) @app.route('/sessions', methods=['POST']) @requires_auth('post:sessions') def add_session(): request_data = request.get_json() try: if len(request_data) > 3: raise AuthError( { 'description': 'Please include only the name, trainer_id, and client_id of the session.' }, 400) if not request_data['name']: raise AuthError({'description': 'Session name is missing.'}, 400) if not request_data['trainer_id']: raise AuthError( {'description': 'Session trainer id is missing.'}, 400) if not request_data['client_id']: raise AuthError( {'description': 'Session client id is missing.'}, 400) except AuthError as e: abort(e.status_code, e.error) new_session = Session() new_session.name = request_data['name'] new_session.trainer_id = request_data['trainer_id'] new_session.client_id = request_data['client_id'] new_session.insert() return jsonify({'success': True, 'new_session': new_session.format()}) @app.route('/sessions/<id>', methods=['DELETE']) @requires_auth('delete:sessions') def delete_session(id): try: target_session = Session.query.filter_by(id=id).first() if target_session is None: raise AuthError( { 'code': 'session_not_found', 'description': 'There is no session with the reuqested id to delete.' }, 404) except AuthError as e: abort(e.status_code, e.error) target_session.delete() return jsonify({ 'success': True, 'deleted_session': target_session.format() }) @app.route('/sessions/<id>', methods=['PATCH']) @requires_auth('patch:sessions') def patch_session(id): request_data = request.get_json() try: target_session = Session.query.filter_by(id=id).first() if target_session is None: raise AuthError( { 'code': 'session_not_found', 'description': 'There is no session with the reuqested id to modify.' }, 404) except AuthError as e: abort(e.status_code, e.error) if 'name' in request_data: target_session.name = request_data['name'] if 'trainer_id' in request_data: target_session.trainer_id = request_data['trainer_id'] if 'client_id' in request_data: target_session.client_id = request_data['client_id'] target_session.update() return jsonify({ 'success': True, 'modified_session': target_session.format() }) ################## # error handling # ################## @app.errorhandler(400) def authError_bad_request(error): return jsonify({ "success": False, "error": 400, "message": error.description }), 400 @app.errorhandler(401) def authError_unauthorized(error): return jsonify({ "success": False, "error": 401, "message": error.description }), 401 @app.errorhandler(404) def authError_not_found(error): return jsonify({ "success": False, "error": 404, "message": error.description }), 404 @app.errorhandler(405) def method_not_allowed(error): return jsonify({ "success": False, "error": 405, "message": "method not allowed" }), 405 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) CORS(app, resources={r"/api/*": {"origins": "*"}}) @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,POST,DELETE,OPTIONS,PUT') return response @app.route('/categories', methods=['GET']) def get_categories(): categories = Category.query.all() formatted_categories = [category.format() for category in categories] return jsonify({ 'success': True, 'categories': formatted_categories, 'total_categories': len(categories) }) @app.route('/questions', methods=['GET']) def get_questions(): page = request.args.get('page', 1, type=int) start = (page - 1) * QUESTIONS_PER_PAGE end = start + QUESTIONS_PER_PAGE questions = Question.query.all() formatted_questions = [question.format() for question in questions] categories = Category.query.all() formatted_categories = [category.format() for category in categories] return jsonify({ 'success': True, 'questions': formatted_questions[start:end], 'total_questions': len(questions), 'categories': formatted_categories }) @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): question = Question.query.filter( Question.id == question_id).one_or_none() if question is None: abort(404) question.delete() questions = Question.query.all() return jsonify({ 'success': True, 'deleted': question_id, 'questions': [question.format() for question in questions] }) @app.route('/questions', methods=['POST']) def create_question(): body = request.get_json() if (body.get("searchTerm")): search_term = body.get("searchTerm") temp = Question.query.filter( Question.question.ilike(f'%{search_term}%')).all() questions = [t.format() for t in temp] if (len(temp) == 0): abort(404) return jsonify({ 'success': True, 'questions': questions, 'total_questions': len(temp), 'current_category': 1 }) else: new_question = body.get("question", None) new_category = body.get("category", None) new_answer = body.get("answer", None) new_difficulty = body.get("difficulty", None) try: question = Question(question=new_question, answer=new_answer, category=new_category, difficulty=new_difficulty) question.insert() except: abort(422) questions = Question.query.all() formatted_questions = [qst.format() for qst in questions] return jsonify({ 'success': True, 'questions': formatted_questions, 'total_questions': len(questions) }) @app.route('/categories/<int:category_id>/questions', methods=['GET']) def get_questions_by_category(category_id): category = Category.query.filter( Category.id == category_id).one_or_none() if (category is None): abort(404) questions = Question.query.filter( Question.category == category.id).all() formatted_questions = [question.format() for question in questions] return jsonify({ 'success': True, 'category': category.id, 'questions': formatted_questions, 'total_questions': len(questions) }) @app.route('/quizzes', methods=['POST']) def play_quiz(): body = request.get_json() previous_question = body.get('previous_questions') category = body.get('quiz_category') if ((category is None) or (previous_question is None)): abort(404) if (category["type"] == "click"): questions = Question.query.all() else: category_id = int(category["id"]) + 1 questions = Question.query.filter( Question.category == category_id).all() random_question = random.choice(questions) def is_used(question): used = False if question.id in previous_question: used = True return used if (len(previous_question) == len(questions)): return jsonify({ 'success': True, 'question': None, 'previous_questions': previous_question }) while (is_used(random_question)): random_question = random.choice(questions) return jsonify({ 'success': True, 'question': random_question.format(), 'previous_questions': previous_question }) @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "Bad Request" }), 400 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @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": "500 Internal Server Error” " }), 500 @app.route('/') def hello(): return jsonify({'success': True}) return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' #124 Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs ''' cors = CORS(app) ''' Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization, true') response.headers.add('Access-Control-Methods', 'GET,PATCH,POST,DELETE,OPTIONS') return response ''' Create an endpoint to handle GET requests for all available categories. ''' @app.route('/categories', methods=['GET']) def retrieve_categories(): categories = Category.query.order_by(Category.type).all() if len(categories) == 0: abort(404) return jsonify({ 'success': True, 'categories': {category.id: category.type for category in categories} }) ''' Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' @app.route('/questions', methods=['GET']) def retrieve_questions(): selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) categories = Category.query.order_by(Category.type).all() if len(current_questions) == 0: abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(Question.query.all()), 'categories': {category.id: category.type for category in categories}, 'current_category': None }) ''' Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' @app.route('/delete/<int:question_id>', methods=['DELETE']) def delete_question(question_id): try: question = Question.query.filter( Question.id == question_id).one_or_none() if question is None: abort(404) question.delete() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'deleted': question_id, #'questions': current_questions, #'total_questions': len(current_questions) }) except (): abort(422) ''' Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' @app.route('/questions', methods=['POST']) def add_question(): body = request.get_json() new_question = body.get('question', None) new_answer = body.get('answer', None) new_difficulty = body.get('difficulty', None) new_category = body.get('category', None) try: question = Question(question=new_question, answer=new_answer, difficulty=new_difficulty, category=new_category) question.insert() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'added': question.id, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) except (): print(sys.exc_info()) abort(422) ''' Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' @app.route('/questions/search', methods=['POST']) def search_question(): body = request.get_json() search_term = body.get('searchTerm', None) search = '%{}%'.format(search_term) search_result = Question.query.filter( Question.question.ilike(search)).all() if (search_result is None): abort(404) formatted_questions = [result.format() for result in search_result] return jsonify({ 'success': True, 'questions': formatted_questions, 'total_questions': len(formatted_questions) }) ''' Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route('/categories/<int:category_id>/questions/', methods=['GET']) def get_questions_by_categories(category_id): selection = Question.query.filter( Question.category == category_id).all() current_questions = paginate_questions(request, selection) if len(current_questions) == 0: abort(404) return jsonify({ 'success': True, 'current_category': category_id, 'questions': current_questions, }) ''' Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' @app.route('/quiz', methods=['POST']) def get_random_quiz_questions(): try: body = request.get_json() quiz_category = body.get('quiz_category') previous_questions = body.get('previous_questions') if ((quiz_category is None) or (previous_questions is None)): abort(400) category_id = quiz_category['id'] if (category_id == 0): questions = Question.query.filter( Question.id.notin_(previous_questions)).all() else: questions = Question.query.filter( Question.category == category_id).filter( Question.id.notin_(previous_questions)).all() if len(questions) > 0: next_question = random.choice(questions).format() return jsonify({'success': True, 'question': next_question}) else: return jsonify({'question': None}) except: abort(422) ''' Create error handlers for all expected errors including 404 and 422. ''' @app.errorhandler(404) def not_found(error): return jsonify({ 'success': False, 'error': 404, 'message': 'Resource not found' }), 404 @app.errorhandler(400) def bad_request(error): return jsonify({ 'success': False, 'error': 400, 'message': 'Bad Request' }), 400 @app.errorhandler(422) def unprocessable(error): return jsonify({ 'success': False, 'error': 422, 'message': 'Unprocessable entity' }), 422 @app.errorhandler(500) def server_error(error): return jsonify({ 'success': False, 'error': 500, 'message': 'Internal server error' }), 500 return app
def create_app(): """ @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs """ app = Flask(__name__) setup_db(app) CORS(app, resources={r'/*': {'origins': '*'}}) @app.after_request def set_headers(response): """ @TODO: Use the after_request decorator to set Access-Control-Allow """ response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization, true') response.headers.add('Access-Control-Allow-Methods', 'GET, PATCH, POST, DELETE, OPTIONS') return response @app.route('/categories', methods=['GET']) def get_all_categories(): """ Create an endpoint to handle GET requests for all available categories. """ categories = {} for category in Category.query.all(): categories[category.id] = category.type return jsonify({'categories': categories}) # Get Questions - working # ---------------------------------------------------------------- @app.route('/questions', methods=['GET']) def get_questions(): categories = {} for category in Category.query.all(): categories[category.id] = category.type questions = [question.format() for question in Question.query.all()] page = int(request.args.get('page', '0')) upper_limit = page * 10 lower_limit = upper_limit - 10 return jsonify({ 'questions': questions[lower_limit:upper_limit] if page else questions, 'total_questions': len(questions), 'categories': categories }) # Delete Questions - working # ---------------------------------------------------------------- @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): question = Question.query.get(question_id) if not question: return abort(404, f'No question found with id: {question_id}') question.delete() return jsonify({'deleted': question_id}) # Submit Question - working # ---------------------------------------------------------------- @app.route('/questions', methods=['POST']) def post_question(): question = request.json.get('question') answer = request.json.get('answer') category = request.json.get('category') difficulty = request.json.get('difficulty') if not (question and answer and category and difficulty): return abort( 400, 'Required question object keys missing from request ' 'body') question_entry = Question(question, answer, category, difficulty) question_entry.insert() return jsonify({'question': question_entry.format()}) # Search Questions - not working # ---------------------------------------------------------------- @app.route("/search", methods=['POST']) def search_questions(): if request.data: page = 1 if request.args.get('page'): page = int(request.args.get('page')) search_data = json.loads(request.data.decode('utf-8')) if 'searchTerm' in search_data: questions_query = Question.query.filter( Question.question.like('%' + search_data['searchTerm'] + '%')).paginate( page, QUESTIONS_PER_PAGE, False) questions = list(map(Question.format, questions_query.items)) if len(questions) > 0: result = { "success": True, "questions": questions, "total_questions": questions_query.total, "current_category": None, } return jsonify(result) abort(404) abort(422) # Filter questions via category - working # ---------------------------------------------------------------- @app.route('/categories/<int:category_id>/questions', methods=['GET']) def get_questions_by_category(category_id): if not category_id: return abort(400) questions = [ question.format() for question in Question.query.filter( Question.category == category_id) ] return jsonify({ 'questions': questions, 'total_questions': len(questions), 'current_category': category_id }) # Play game - render questions with optional category - working # ---------------------------------------------------------------- @app.route("/quizzes", methods=['POST']) def get_question_for_quiz(): body = request.get_json() previous_questions = body.get('previous_questions', []) quiz_category = body.get('quiz_category', None) try: if quiz_category: if quiz_category['id'] == 0: selections = Question.query.all() else: selections = Question.query.filter_by( category=quiz_category['id']).all() options = [ question.format() for question in selections if question.id not in previous_questions ] if len(options) == 0: return jsonify({'question': False}) result = random.choice(options) return jsonify({'question': result}) except: abort(500) # Error Handlers # ---------------------------------------------------------------- @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "Unprocessable" }), 422 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "Resource not found" }), 404 @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "Bad Request" }), 400 @app.errorhandler(500) def server_error(error): return jsonify({ "success": False, "error": 500, "message": "Server error" }), 500 return app
def create_app(test_config=None): app = Flask(__name__) setup_db(app) CORS(app) oauth = OAuth(app) secret = secrets.token_urlsafe(32) app.secret_key = secret auth0 = oauth.register( 'auth0', client_id=os.environ.get('CLIENT_ID'), client_secret=os.environ.get('CLIENT_SECRET'), api_base_url=os.environ.get('API_BASE_URL'), access_token_url=os.environ.get('ACCESS_TOKEN_URL'), authorize_url=os.environ.get('AUTHORIZE_URL'), client_kwargs={ 'scope': 'openid profile email', }, ) AUTH0_URL = os.environ.get('AUTH0_LOGIN_URL') CORS(app, resources={r"/api/*": {"origins": "*"}}) # ROUTES @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') return response # main page @app.route('/') def index(): return 'Hello, friend !' # login page @app.route('/login') def login(): return render_template('login.html', AUTH0_AUTHORIZE_URL=AUTH0_URL) # logout @app.route('/logout') def logout(): # Clear session stored data session.clear() # Redirect user to logout endpoint params = {'returnTo': url_for( 'index', _external=True), 'client_id': '5FmE550Gvrv7iLRl1WxYleKWZx44su3a'} return redirect(auth0.api_base_url + '/v2/logout?' + urlencode(params)) # GET endpoints ################################################################## # retrieves all the actors @app.route('/actors', methods=['GET']) @requires_auth('get:actors') def show_actors(jwt): actors = Actor.query.all() if actors is None: abort(404) actors_list = [] for actor in actors: actors_list.append({ 'actor_id': actor.id, 'actor_name': actor.name, 'actor_age': actor.age, 'actor_gender': actor.gender }) return jsonify({ 'success': True, 'actors': actors_list }) # retrieves all the movies @app.route('/movies', methods=['GET']) @requires_auth('get:movies') def show_movies(jwt): movies = Movie.query.all() if movies is None: abort(404) movies_list = [] for movie in movies: movies_list.append({ 'movie_id': movie.id, 'movie_title': movie.title, 'movie_release_date': movie.release_date }) return jsonify({ 'success': True, 'movies': movies_list }) # retrieves a certain actor @app.route('/actors/<int:actor_id>', methods=['GET']) @requires_auth('get:actor') def show_actor(jwt, actor_id): actor = Actor.query.filter(Actor.id == actor_id).one_or_none() if actor is None: abort(404) return jsonify({ 'success': True, 'name': actor.name, 'age': actor.age, 'gender': actor.gender }) # retrieves a certain movie @app.route('/movies/<int:movie_id>', methods=['GET']) @requires_auth('get:movie') def show_movie(jwt, movie_id): movie = Movie.query.filter(Movie.id == movie_id).one_or_none() if movie is None: abort(404) return jsonify({ 'success': True, 'title': movie.title, 'release_date': movie.release_date }) # Delete endpoints ################################################################## # deletes a certain actor @app.route('/actors/<int:actor_id>', methods=['DELETE']) @requires_auth('delete:actor') def delete_actor(jwt, actor_id): try: actor = Actor.query.filter(Actor.id == actor_id).one_or_none() if actor is None: abort(404) actor.delete() return jsonify({ "success": True, "deleted": actor_id }) except Exception: abort(422) # retrieves a certain movie @app.route('/movies/<int:movie_id>', methods=['DELETE']) @requires_auth('delete:movie') def delete_movie(jwt, movie_id): try: movie = Movie.query.filter(Movie.id == movie_id).one_or_none() if movie is None: abort(404) movie.delete() return jsonify({ "success": True, "deleted": movie_id }) except Exception: abort(422) # POST endpoints ################################################################## # adds a new actor @app.route('/actors', methods=['POST']) @requires_auth('post:actor') def add_actor(jwt): body = request.get_json() if body is None: abort(400) new_name = body.get('name', None) new_age = body.get('age', None) new_gender = body.get('gender', None) try: if new_name and new_age and new_gender: new_actor = Actor( name=new_name, age=new_age, gender=new_gender ) new_actor.insert() return jsonify({ 'success': True, 'created_id': new_actor.id, 'actors': [actor.format() for actor in Actor.query.all()] }) else: abort(422) except Exception: abort(422) # adds a new movie @app.route('/movies', methods=['POST']) @requires_auth('post:movie') def add_movie(jwt): body = request.get_json() if body is None: abort(400) new_title = body.get('title', None) release_date_str = body.get('release_date', None) y, m, d = release_date_str.split('-') new_release_date = datetime(int(y), int(m), int(d)).date() try: if new_title and release_date_str: new_movie = Movie( title=new_title, release_date=new_release_date) new_movie.insert() return jsonify({ 'success': True, 'created_id': new_movie.id, 'movies': [movie.format() for movie in Movie.query.all()] }) else: abort(422) except Exception: abort(422) # PATCH endpoints ################################################################## # updates an existing actor @app.route('/actors/<int:actor_id>', methods=['PATCH']) @requires_auth('patch:actor') def update_actor(jwt, actor_id): actor = Actor.query.filter(Actor.id == actor_id).one_or_none() if actor is None: abort(404) body = request.get_json() if body is None: abort(400) new_name = body.get('name', None) new_age = body.get('age', None) new_gender = body.get('gender', None) try: if new_name: actor.name = new_name if new_age: actor.age = new_age if new_gender: actor.gender = new_gender actor.update() return jsonify({ "success": True, "actor": [actor.format() for actor in Actor.query.all()] }) except Exception: abort(422) # updates an existing movie @app.route('/movies/<int:movie_id>', methods=['PATCH']) @requires_auth('patch:movie') def update_movie(jwt, movie_id): movie = Movie.query.filter(Movie.id == movie_id).one_or_none() if movie is None: abort(404) body = request.get_json() if body is None: abort(400) new_title = body.get('title', None) new_release_date_str = body.get('release_date', None) try: if new_title: movie.title = new_title if new_release_date_str: y, m, d = new_release_date_str.split('-') new_release_date = datetime(int(y), int(m), int(d)).date() movie.release_date = new_release_date movie.update() return jsonify({ "success": True, "movies": [movie.format() for movie in Movie.query.all()] }) except Exception: abort(422) # Error Handling @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(AuthError) def authentication_error(error): return jsonify({ "success": False, "error": 401, "message": "AuthError" }), 401 @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": 'bad request' }), 400 return app
def initialize_app(): app = Flask(__name__) setup_db(app) CORS(app) return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) app.config.from_object('config') CORS(app) setup_db(app) db = SQLAlchemy(app) Migrate(app, db) @app.route('/') def index(): return ("hello word") @app.route('/actors', methods=["GET"]) @requires_auth('get:actors') def get_actors(payload): actors = Actor.query.all() return jsonify({ "actors": [actor.format() for actor in actors], "success": True }) @app.route('/actors', methods=["POST"]) @requires_auth('post:actors') def create_actor(payload): body = request.get_json() name = body.get("name") age = body.get("age") gender = body.get("gender") if not name or not age or not gender: abort(400) actor = Actor(name=name, age=age, gender=gender) actor.insert() return jsonify({"actor": actor.format(), "success": True}) @app.route('/actors/<actor_id>', methods=["PATCH"]) @requires_auth('patch:actors') def update_actor(payload, actor_id): body = request.get_json() name = body.get("name", None) age = body.get("age", None) gender = body.get("gender", None) actor = Actor.query.filter_by(id=actor_id).first_or_404() if name: actor.name = name if age: actor.age = age if gender: actor.gender = gender actor.update() return jsonify({"actor": actor.format(), "success": True}) @app.route('/actors/<actor_id>', methods=["DELETE"]) @requires_auth('delete:actors') def delete_actor(payload, actor_id): actor = Actor.query.filter_by(id=actor_id).first_or_404() actor.delete() return jsonify({"success": True}) @app.route('/movies', methods=["GET"]) @requires_auth('get:movies') def get_movies(payload): movies = Movie.query.all() return jsonify({ "movies": [movie.format() for movie in movies], "success": True }) @app.route('/movies', methods=["POST"]) @requires_auth('post:movies') def create_movie(payload): body = request.get_json() title = body.get("title") release_date = body.get("release_date") if not title or not release_date: abort(400) movie = Movie(title=title, release_date=release_date) movie.insert() return jsonify({"movie": movie.format(), "success": True}) @app.route('/movies/<movie_id>', methods=["PATCH"]) @requires_auth('patch:movies') def update_movie(payload, movie_id): body = request.get_json() movie = Movie.query.filter_by(id=movie_id).first_or_404() movie.title = body.get("title") movie.release_date = body.get("release_date") movie.update() return jsonify({"movie": movie.format(), "success": True}) @app.route('/movies/<movie_id>', methods=["DELETE"]) @requires_auth('delete:movies') def delete_movie(payload, movie_id): movie = Movie.query.filter_by(id=movie_id).first_or_404() movie.delete() return jsonify({"success": True}) @app.errorhandler(404) def not_found(error): return jsonify({ 'success': False, 'error': 404, 'message': "Not found" }), 404 @app.errorhandler(422) def unprocessible(error): return jsonify({ 'success': False, 'error': 422, 'message': "Unprocessible" }), 422 @app.errorhandler(400) def bad_request(error): return jsonify({ 'success': False, 'error': 400, 'message': "Bad Request" }), 400 @app.errorhandler(405) def bad_request(error): return jsonify({ 'success': False, 'error': 405, 'message': "Method not found" }), 405 @app.errorhandler(401) def unauthenticated(error): return jsonify({ "success": False, "error": 401, "message": "unauthenticated" }), 401 @app.errorhandler(AuthError) def auth_error(ex): return jsonify({ "success": False, "error": ex.status_code, "message": ex.error['description'] }), ex.status_code return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs ''' CORS(app) ''' @TODO: Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET, POST, DELETE') return response ''' @TODO: Create an endpoint to handle GET requests for all available categories. ''' @app.route('/categories') def get_categories(): categories = Category.query.order_by(Category.id).all() if not len(categories): abort(404) formatted_categories = { category.id: category.type for category in categories } return jsonify({'success': True, 'categories': formatted_categories}) ''' @TODO: Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' @app.route('/questions') def get_questions(): page = request.args.get('page', 1, type=int) start = (page - 1) * QUESTIONS_PER_PAGE end = start + QUESTIONS_PER_PAGE questions = Question.query.all() formatted_questions = [question.format() for question in questions] if not len(formatted_questions[start:end]): abort(404) categories = Category.query.order_by(Category.type).all() formatted_categories = { category.id: category.type for category in categories } return jsonify({ 'success': True, 'questions': formatted_questions[start:end], 'total_questions': len(formatted_questions), 'categories': formatted_categories }) ''' @TODO: Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): question = Question.query.filter_by(id=question_id).one_or_none() if question is None: abort(404) else: question.delete() return jsonify({'success': True, 'question_id': question_id}) ''' @TODO: Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' @app.route('/questions', methods=['POST']) def add_question(): body = request.get_json() if body.get('searchTerm'): return search_question() try: q = Question(body['question'], body['answer'], body['category'], body['difficulty']) q.insert() return jsonify({'success': True, 'id': q.id}) except: abort(422) ''' @TODO: Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' @app.route('/questions', methods=['POST']) def search_question(): body = request.get_json() searchTerm = body['searchTerm'].lower() try: questions = Question.query.filter( Question.question.ilike("%{}%".format(searchTerm))).all() questions = [q.format() for q in questions] return jsonify({ 'success': True, 'questions': questions, 'total_questions': len(questions) }) except: abort(422) ''' @TODO: Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route('/categories/<int:category_id>/questions') def get_questions_by_category_id(category_id): category_questions = Question.query.filter_by( category=category_id).all() if not category_questions: abort(404) else: category_questions = [q.format() for q in category_questions] return jsonify({ 'success': True, 'questions': category_questions, 'total_questions': len(category_questions) }) ''' @TODO: Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' @app.route('/quizzes', methods=['POST']) def play_quiz(): category_id = request.get_json()['quiz_category']['id'] previous_questions = request.get_json()['previous_questions'] if category_id == 0: questions_to_ask = Question.query.filter( ~Question.id.in_(previous_questions)).all() else: questions_to_ask = Question.query.filter_by(category=category_id). \ filter(~Question.id.in_(previous_questions)).all() if not questions_to_ask: return jsonify({ 'previousQuestions': previous_questions, 'question': None }) currentQuestion = random.choice(questions_to_ask).format() return jsonify({ 'previousQuestions': currentQuestion['id'], 'question': currentQuestion }) ''' @TODO: Create error handlers for all expected errors including 404 and 422. ''' @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "Bad request" }), 400 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "Not found" }), 404 @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": "It's not you, it's us" }), 500 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) CORS(app, resources={r"/*": {"origins": '*'}}) @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET, POST, DELETE, OPTIONS') return response @app.route('/categories', methods=['GET']) def get_categories(): categories_query = Category.query.all() categories = {} for category in categories_query: categories[category.id] = category.type if categories_query is None: abort(404) else: return jsonify({ 'success': True, 'categories': categories }) @app.route('/questions', methods=['GET']) def get_paginated_questions(): # get all questions query_questions = Question.query.all() page = request.args.get('page', 1, type=int) begin_index = (page - 1) * QUESTIONS_PER_PAGE end_index = begin_index + QUESTIONS_PER_PAGE questions = [question.format() for question in query_questions] totalQuestions = len(questions) # get all categories (from Category model) categories_query = Category.query.all() categories = {} for category in categories_query: categories[category.id] = category.type currentCategory = None # I had a problem to understand where should I take it from, and what is it used for, I took the solution from https://knowledge.udacity.com/questions/82424 if query_questions is None or categories_query is None: abort(404) else: return jsonify({ 'success': True, 'questions': questions[begin_index:end_index], 'totalQuestions': totalQuestions, 'currentCategory': currentCategory, 'categories': categories }) @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): try: question_to_be_deleted = Question.query.get(question_id) question_to_be_deleted.delete() except: db.session.rollback() if question_to_be_deleted is None: abort(404) else: abort(422) finally: db.session.close() return jsonify({ 'success': True, 'deleted': question_id }) @app.route('/questions', methods=['POST']) def create_question(): try: if request.method == 'PUT': abort(405) else: body = request.get_json() question = body.get('question') answer = body.get('answer') category = body.get('category') difficulty = body.get('difficulty') question_to_be_created = Question(question=question, answer=answer, category=category, difficulty=difficulty) question_to_be_created.insert() except: db.session.rollback() abort(422) finally: db.session.close() return jsonify({ 'success': True }) @app.route('/questions/search', methods=['POST']) def get_question_based_on_search(): body = request.get_json() search_term = body.get('searchTerm', '') search_result = Question.query.filter(Question.question.ilike(f'%{search_term}%')).all() questions = [question.format() for question in search_result] if search_term is None: abort(404) else: return jsonify({ 'success': True, 'questions': questions }) @app.route('/categories/<int:category_id>/questions', methods=['GET']) def get_question_for_category(category_id): requested_category = Category.query.get(category_id) questions_query = Question.query.filter(Question.category == requested_category).all() questions = [question.format() for question in questions_query] if requested_category is None: abort(404) else: return jsonify({ 'success': True, 'questions': questions, 'totalQuestions': len(questions), 'currentCategory': requested_category.type }) @app.route('/quizzes', methods=['POST']) def get_questions(): try: body = request.get_json() category = body.get('quiz_category') previous_question = body.get('previous_questions') query_questions = Question.query.filter(Question.category == category).filter(Question.id not in previous_question).all() if query_questions is None: abort(404) else: questions = [question.format() for question in query_questions] random_index = random.randint(1, len(questions)) except: abort(422) return jsonify({ 'success': True, 'questions': questions[random_index] }) @app.errorhandler(404) def not_found(error): return jsonify({ 'success': False, 'error': 404, 'message': 'resource not found' }), 404 @app.errorhandler(405) def method_not_allowed(error): return jsonify({ 'success': False, 'error': 405, 'message': 'method not allowed' }), 405 @app.errorhandler(422) def unprocessable_request(error): return jsonify({ 'success': False, 'error': 422, 'message': 'unprocessable' }), 422 return app
def create_app(test_config=None): # configure app app = Flask(__name__) CORS(app) setup_db(app) Migrate(app, db) @app.route('/') def index(): return "API tests for Casting Agency project" @app.after_request def after_request(response): header = response.headers header['Access-Control-Allow-Origin'] = '*' return response @app.route('/actors', methods=['GET']) @requires_auth(permission='get:actors') def actors(): """ Returns a list of actors """ try: actors_list = [ actor.actor_information_format() for actor in Actor.query.order_by(Actor.id).all() ] return jsonify({'success': True, 'actors': actors_list}) except Exception as e: print(e) abort(422) @app.route('/actors', methods=['POST']) @requires_auth(permission='post:actors') def post_actors(): """ Posts actors and movie played by the actors """ name = request.get_json()['name'] age = request.get_json()['age'] gender = request.get_json()['gender'] actor = Actor(name=name, age=age, gender=gender) actor.insert() return jsonify({ "success": True, "status_code": 200, "actor": actor.actor_information_format() }) @app.route('/assign_movie_to_actor/', methods=['POST']) @requires_auth(permission='post:actors') def post_actors_movie(): """ post actors with assigned movies or movies with assigned_actors """ try: assigned_movie = helper_table.insert().values( actor_id=request.get_json()['actor_id'], movie_id=request.get_json()['movie_id']) db.session.execute(assigned_movie) db.session.commit() return jsonify({ "success": True, "status_code": 200, "message": 'OK' }) except: abort(404) @app.route('/actors/<int:actor_id>', methods=['PATCH']) @requires_auth(permission='patch:actors') def update_actors(actor_id): """ Updates actors data """ name = request.get_json()['name'] age = request.get_json()['age'] gender = request.get_json()['gender'] played_in_movies = request.json.get("movies", None) actor = Actor.query.filter(Actor.id == actor_id).one_or_none() if actor is None: abort(404) if played_in_movies: actor.movies = [] actor.update() for movie in played_in_movies: actor.movies.append(Movie.query.get(movie)) if name: actor.name = name if age: actor.age = age if gender: actor.gender = gender actor.update() return jsonify({ "success": True, "status_code": 200, "actor": actor.actor_information_format() }) @app.route('/actors/<int:actor_id>', methods=['DELETE']) @requires_auth(permission='delete:actors') def delete_actors(actor_id): """ deletes actors data """ actor = Actor.query.filter(Actor.id == actor_id).one_or_none() if actor is None: abort(404) actor.delete() return jsonify({ "success": True, "status_code": 200, "status_message": 'OK', "id_deleted": actor_id }) # Movie Routes @app.route('/movies', methods=["GET"]) @requires_auth(permission='get:movies') def movies(): """ Returns a list of movies """ try: movies_list = [ movie.movie_information_format() for movie in Movie.query.order_by(Movie.id).all() ] return jsonify({ "success": True, "status_code": 200, "status_message": 'OK', "movies": movies_list }) except Exception: abort(422) @app.route('/movies', methods=['POST']) @requires_auth(permission='post:movies') def post_movies(): """ Posts movies and actors that play in the movies """ title = request.get_json()['title'] release_date = request.get_json()['release_date'] if title is None: abort(422) movie = Movie(title=title, release_date=release_date) movie.insert() return jsonify({ "success": True, "status_code": 200, "status_message": 'OK', "movie": movie.movie_information_format() }) @app.route('/movies/<int:movie_id>', methods=['GET', 'PATCH']) @requires_auth(permission='patch:movies') def update_movies(movie_id): """ Updates movies data """ title = request.get_json()['title'] release_date = request.get_json()['release_date'] cast = request.get_json()['cast'] movie = Movie.query.filter(Movie.id == movie_id).one_or_none() if movie is None: abort(404) if cast: movie.actors = [] movie.update() for person in cast: movie.actors.append(Actor.query.get(person)) if title: movie.title = title if release_date: movie.release_date = release_date movie.update() return jsonify({ "success": True, "status_code": 200, "status_message": 'OK', "movie": movie.movie_information_format() }) @app.route('/movies/<int:movie_id>', methods=['DELETE']) @requires_auth(permission='delete:movies') def delete_movies(movie_id): """ deletes movies data """ movie = Movie.query.filter(Movie.id == movie_id).one_or_none() if movie is None: abort(404) movie.delete() return jsonify({ "success": True, "status_code": 200, "status_message": 'OK', "id_deleted": movie_id }) # Error Handeling @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "status_message": "unprocessable" }), 422 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "status_message": "resource Not found" }), 404 @app.errorhandler(AuthError) def auth_error(error): return jsonify(error.error), error.status_code return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs. ''' CORS(app) ''' @TODO: Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Origin', '*') response.headers.add('Access-Control-Allow-Hearders', 'Content-Type,Autorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PATCH,POST,DELETE,OPTIONS') return response ''' @TODO: Create an endpoint to handle GET requests for all available categories. ''' @app.route('/categories') def get_categories(): try: categories = Category.query.order_by(Category.id).all() except Exception as e: print(e) abort(422) list_categories = [category.format() for category in categories] dict_categories = {} if len(list_categories) == 0: abort(404) else: for cat in list_categories: dict_categories[cat["id"]] = cat["type"] return jsonify({ 'success': True, 'categories': dict_categories, 'number_categories': len(list_categories) }) ''' @TODO: Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' def paginate_questions(request, selection): page = request.args.get('page', 1, type=int) start = (page - 1) * QUESTIONS_PER_PAGE end = start + QUESTIONS_PER_PAGE list_questions = [question.format() for question in selection] current_list = list_questions[start:end] return current_list @app.route('/questions') def get_questions(): try: questions = Question.query.order_by(Question.id).all() categories = Category.query.order_by(Category.id).all() except Exception as e: print(e) abort(422) current_list_questions = paginate_questions(request, questions) list_categories = [category.format() for category in categories] if len(current_list_questions) == 0: abort(404) dict_categories = {} for cat in list_categories: dict_categories[cat['id']] = cat['type'] return jsonify({ 'success': True, 'questions': current_list_questions, 'page': request.args.get('page', 1, type=int), 'total_questions': len(questions), 'categories': dict_categories, 'current_category': None }) ''' @TODO: Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): try: question_to_delete = Question.query. \ filter(Question.id == question_id). \ one_or_none() except Exception as e: print(e) abort(422) if question_to_delete is None: abort(404) question_to_delete.delete() return jsonify({ 'success': True, 'deleted': question_id, 'total_number_questions': len(Question.query.all()) }) ''' @TODO: Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' @app.route('/questions', methods=['POST']) def add_question(): body = request.get_json() if body is None: abort(400) new_question = body.get('question', None) new_answer = body.get('answer', None) new_category = body.get('category', None) new_difficulty = body.get('difficulty', None) if all(v is not None for v in [new_question, new_answer, new_category, new_difficulty]): try: question_to_add = Question(question=new_question, answer=new_answer, category=new_category, difficulty=new_difficulty) question_to_add.insert() return jsonify({ 'success': True, 'created': question_to_add.id, 'total_number_questions': len(Question.query.all()) }) except Exception as e: print(e) abort(422) else: abort(422) ''' @TODO: Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' @app.route('/questions/search', methods=['POST']) def search_questions(): data = request.get_json() if data is None: abort(400) search_terms = data.get('searchTerm', None) if search_terms: try: list_questions = Question.query.order_by(Question.id). \ filter(Question.question. ilike(f'%{search_terms}%')) except Exception as e: print(e) abort(422) formatted_list_questions = [question.format() for question in list_questions] if formatted_list_questions: return jsonify({ 'success': True, 'search_terms': search_terms, 'questions': formatted_list_questions, 'total_questions': list_questions.count(), 'current_category': None }) else: abort(404) else: abort(400) ''' @TODO: Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route('/categories/<int:category_id>/questions') def get_question_by_cat(category_id): # models.py is only what the python application can see and know. # foreign key is defined in trivia.psql try: list_questions = Question.query.order_by(Question.id). \ filter(Question.category == str(category_id)). \ all() except Exception as e: print(e) abort(422) if len(list_questions) == 0: abort(404) formatted_list_questions = [question.format() for question in list_questions] return jsonify({ 'questions': formatted_list_questions, 'current_category': category_id, 'success': True, 'total_questions': len(formatted_list_questions) }) ''' @TODO: Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' @app.route('/quizzes', methods=['POST']) def get_random_question(): data = request.get_json() # if no json object is passed, the request is invalid. if data is None: abort(400) category = data.get('quiz_category', None) previous_questions = data.get('previous_questions', []) # if there are no value associated to 'quiz_category' if category is None: abort(400) try: if category['id'] != 0: list_questions = Question.query. \ filter(Question.category == category['id']). \ all() else: list_questions = Question.query.all() except Exception as e: print(e) abort(404) # In case the list of question is empty. if not list_questions: abort(404) # To randomize our list. # Not required since the order of results # returned change for every query. # But this adds a level of randomness. random.shuffle(list_questions) for q in list_questions: if q.id not in previous_questions: # the front end is taking care of # updating the previous_questions array. return jsonify({ 'question': q.format(), 'quiz_category': q.category, 'success': True }) # return None if all the questions of the category have been sent out. return jsonify({ 'question': None, 'quiz_category': category['id'], 'success': True }) ''' @TODO: Create error handlers for all expected errors including 404 and 422. ''' @app.errorhandler(400) def invalide_request(error): return jsonify({ 'success': False, 'error': 400, 'message': 'invalid request' }), 400 @app.errorhandler(404) def not_found(error): return jsonify({ 'error': 404, 'success': False, 'message': 'resource not found' }), 404 @app.errorhandler(422) def cant_process(error): return jsonify({ 'success': False, 'error': 422, 'message': 'unable to be processed' }), 422 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) # CORS setup allowing '*' for origins. cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) # CORS Headers @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,POST,DELETE,OPTIONS') return response # endpoint to handle GET requests for all available categories. @app.route('/categories') def retrieve_categories(): try: selection = Category.query.order_by(Category.id).all() categories = [category.format() for category in selection] if len(categories) == 0: abort(404) return jsonify({ 'success': True, 'categories': categories, # this returns categories as a list 'categoriesasdict': get_category_list() # this returns categories as a dictionary }) except: abort(422) # Endpoint to handle GET requests for questions, including pagination @app.route('/questions') def retrieve_questions(): try: selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) if len(current_questions) == 0: abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(Question.query.all()), 'categories': get_category_list(), 'current_category': None }) except: abort(422) # Endpoint to DELETE question using a question ID. @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): try: question = Question.query.filter( Question.id == question_id).one_or_none() if question is None: abort(404) question.delete() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'deleted': question_id, 'questions': current_questions, 'total_questions': len(Question.query.all()), 'categories': get_category_list(), 'current_category': None }) except: abort(422) # Endpoint to create an endpoint to POST a new question, with the question and answer text, category, and difficulty score. @app.route('/questions', methods=['POST']) def create_question(): body = request.get_json() new_question = body.get('question', None) new_answer = body.get('answer', None) new_difficulty = body.get('difficulty', None) new_category = body.get('category', None) try: question = Question(question=new_question, answer=new_answer, difficulty=new_difficulty, category=new_category) question.insert() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'created': question.id, 'questions': current_questions, 'total_questions': len(Question.query.all()), 'categories': get_category_list(), 'current_category': None }) except: abort(422) # Endpoint to search questions based on a search term @app.route('/questions/search', methods=['POST']) def search_questions(): try: searchresults = request.get_json() searchterm = searchresults.get('searchTerm') selection = Question.query.filter( Question.question.ilike('%' + searchterm + '%')).all() current_questions = [question.format() for question in selection] # CURRENT ISSUE 1: If I am on page 1, and search results are 14, all 14 will be shown on page 1 # and clicking on page 2 will show result of GET /questions?page=2 # CURRENT ISSUE 2: if I am on page 2, and there is only 1 result, then it will show link to page 1 # but will not navigate there directly. return jsonify({ "questions": current_questions, "total_questions": len(selection), "current_category": None }) except: abort(422) ''' @TODO: Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route('/categories/<int:category_id>/questions') def get_questions_per_category(category_id): try: selection = Question.query.filter( Question.category == category_id).order_by(Question.id).all() current_questions = paginate_questions(request, selection) if len(current_questions) == 0: abort(404) # CURRENT ISSUE 1: If I am on page 1, and search results are 14, first 10 will be shown on page 1 # and clicking on page 2 will show result of GET /questions?page=2 # CURRENT ISSUE 2: if I am on page 2, and there is only 1 result, then it will show link to page 1 # but will not navigate there directly. return jsonify({ 'questions': current_questions, 'total_questions': len(current_questions), 'current_category': (Category.query.filter( Category.id == category_id).first()).type }) except: abort(422) # POST endpoint to play the quiz. @app.route('/quizzes', methods=['POST']) def quiz_questions(): try: body = request.get_json() current_category = body.get('quiz_category') previous_questions = body.get('previous_questions', None) # if 'ALL' is selected in the category selection criteria if current_category['id'] == 0: questions = Question.query.filter( Question.id.notin_((previous_questions))).all() else: # for a particular category questions = Question.query.filter( Question.category == current_category['id']).filter( Question.id.notin_((previous_questions))).all() if questions: current_question = random.choice(questions) return jsonify({ 'success': True, 'question': current_question.format() }) else: # once questions finish, this message will be shown return jsonify({ 'success': True, 'question': { 'id': 1000, 'question': 'No more Questions :)', 'answer': 'No more Answers', 'category': 1, 'difficulty': 1 } }) except: abort(422) # Error handlers for Errors in this code @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) CORS(app) ''' @TODO: Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PATCH,POST,DELETE,OPTIONS') return response @app.route('/categories') def get_categories(): categories = [c.format() for c in Category.query.all()] return jsonify({'categories': categories}) @app.route('/questions') def get_questions(): page = request.args.get('page', 1, type=int) questions = [q.format() for q in Question.query.all()] start = (page - 1) * 10 end = start + 10 if len(questions) == 0: abort(404) categories = [c.format() for c in Category.query.all()] return jsonify({ 'questions': questions[start:end], 'total_questions': len(questions), 'categories': categories, 'current_category': None }) @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): question = Question.query.get(question_id) question.delete() return jsonify({'success': True}) @app.route('/questions', methods=['POST']) def add_question(): try: data = request.get_json() question = Question(data['question'], data['answer'], data['category'], data['difficulty']) question.insert() return jsonify(question.format()) except: abort(422) @app.route('/search', methods=['POST']) def search(): page = request.args.get('page', 1, type=int) start = (page - 1) * 10 end = start + 10 data = request.get_json() questions = Question.query.filter( Question.question.ilike('%{}%'.format(data['searchTerm']))) formattedQuestions = [q.format() for q in questions] categories = [c.format() for c in Category.query.all()] return jsonify({ 'questions': formattedQuestions[start:end], 'total_questions': len(formattedQuestions), 'categories': categories }) @app.route('/categories/<int:id>/questions') def get_categories_questions(id): page = request.args.get('page', 1, type=int) start = (page - 1) * 10 end = start + 10 questions = Question.query.filter_by(category=id + 1) formattedQuestions = [q.format() for q in questions] categories = [c.format() for c in Category.query.all()] return jsonify({ 'questions': formattedQuestions[start:end], 'total_questions': len(formattedQuestions), 'categories': categories, 'current_category': None }) @app.route('/quizzes', methods=['POST']) def quiz(): data = request.get_json() category = data['quiz_category']['id'] if category == 0: questions = Question.query.all() else: questions = Question.query.filter_by(category=category).all() questions = list( filter(lambda x: x not in data['previous_questions'], questions)) if len(questions) == 0: abort(404) question = random.choice(questions) return jsonify({ 'question': question.format(), 'previousQuestions': data['previous_questions'].append(question.id) }) @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 return app
order=data['order']) todo = models.get_todo(todo_id) return todo, 200, {'Access-Control-Allow-Origin': '*'} class TodoList(restful.Resource): def get(self): todos = models.get_todos() return sorted(todos, key=lambda t: t['order']) def post(self): data = json.loads(request.data) todo_schema.validate(data) todo = models.add_todo( text=data['text'], complete=data['complete'], ) return todo, 201 api.add_resource(TodoList, '/todos') api.add_resource(Todo, '/todos/<int:todo_id>') if __name__ == '__main__': models.setup_db() app.run(debug = True)
def create_app(test_config=None): app = Flask(__name__) setup_db(app) CORS(app) # CORS(app, resources={r"*/api/*": {origins: '*'}}) @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE, OPTIONS ') return response #--# removed in FlaskII lesson #--# # @app.route('/') # # @cross_origin # def hello(): # return jsonify({'message': 'Hello?'}) @app.route('/books', methods=['GET']) def get_books(): books = Book.query.all() pagination = paginate_books(books) # zweite Seite aufrufbar mit: http://127.0.0.1:5000/books?page=2 if len(pagination) == 0: abort(404) return jsonify({ 'success': True, 'books': pagination, 'total_books': len(books) }) @app.route('/books/<int:book_id>') def get_specific_book(book_id): book = Book.query.filter(Book.id == book_id).one_or_none() if book is None: abort(404) else: return jsonify({ 'success': True, 'book': book.format() }) @app.route('/books/<int:book_id>', methods=['PATCH']) def update_book(book_id): body = request.get_json() try: book = Book.query.filter(Book.id == book_id).one_or_none() if book is None: abort(404) # nur rating kann geupdated werden if 'rating' in body: book.rating = int(body.get('rating')) book.update() return jsonify({ 'success': True, 'id': book.id }) except: abort(400) # for testing PATCH: curl http://127.0.0.1:5000/books/10 -X PATCH -H "Content-Type: application/json" -d '{"rating":"9"}' @app.route('/books/<int:book_id>', methods=['DELETE']) def delete_book(book_id): try: book = Book.query.filter(Book.id == book_id).one_or_none() if book is None: abort(404) book.delete() books = Book.query.all() pagination = paginate_books(books) return jsonify({ 'success': True, 'deleted': book.id, 'books': pagination, 'total_books': len(books) }) except: abort(422) # for testing DELETE: curl -X DELETE http://127.0.0.1:5000/books/10 @app.route('/books', methods=['POST']) def create_book(): body = request.get_json() new_title = body.get('title', None) new_author = body.get('author', None) new_rating = body.get('rating', None) try: book = Book(title=new_title, author=new_author, rating=new_rating) book.insert() books = Book.query.all() pagination = paginate_books(books) return jsonify({ 'success': True, 'created': book.id, 'books': pagination, 'total_books': len(books) }) except: abort(405) # for testing POST: curl -X POST -H "Content-Type: application/json" -d '{"title":"Harry Potter", "author":"Joanne K. Rowling", "rating":"8"}' http://127.0.0.1:5000/books @app.route('/books/search', methods=['POST']) def search_book_title(): body = request.get_json() search_term = body.get('search_term') try: suggestions = Book.query.filter( Book.title.ilike(f'%{search_term}%')).all() if not suggestions: abort(404) return jsonify({ 'success': True, 'suggestions': paginate_books(suggestions), 'total_books': len(suggestions) }) except: abort(404) # for testing: curl -X POST -H "Content-Type: application/json" -d '{"search_term":"an"}' http://127.0.0.1:5000/books/search @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "bad request" }), 400 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(405) def not_found(error): return jsonify({ "success": False, "error": 405, "message": "method not allowed" }), 405 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 return app
import os from flask import Flask, request, abort, jsonify from flask_sqlalchemy import SQLAlchemy from flask_cors import CORS import random import json from models import setup_db, Question, Category,db QUESTIONS_PER_PAGE = 10 app = Flask(__name__) # create and configure the app cors=CORS(app) setup_db(app) @app.route("/questions",methods=["GET"]) def questions_get(): pagenum=dict(request.args)["page"] questions=[] categores={} for q in list(db.session.query(Question).all()): questions.append({"id":q.id, "question":q.question, "answer":q.answer, "category":q.category, "difficulty":q.difficulty}) for c in db.session.query(Category).all(): categores[c.id]=c.type
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' @DONE: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs ''' cors = CORS(app, resources={r"/*": {"origins": "*"}}) ''' @DONE: Use the after_request decorator to set Access-Control-Allow ''' # CORS Headers @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') return response ''' @DONE: Create an endpoint to handle GET requests for all available categories. ''' @app.route('/categories') def retrieve_categories(): categories = Category.query.order_by(Category.id).all() category_list = {category.id: category.type for category in categories} if len(categories) == 0: abort(404) return jsonify({ 'success': True, 'categories': category_list, 'total_categories': len(Category.query.all()), }) ''' @DONE: Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' @app.route('/questions') def retrieve_questions(): questions = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, questions) categories = Category.query.all() category_list = {category.id: category.type for category in categories} if len(current_questions) == 0: abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(Question.query.all()), 'categories': category_list }) ''' @DONE: Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): try: question = Question.query.filter( Question.id == question_id).one_or_none() if question is None: abort(404) question.delete() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'deleted': question_id, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) except: abort(422) ''' @DONE: Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' '''&''' ''' @DONE: Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' @app.route('/questions', methods=['POST']) def create_question(): body = request.get_json() question = body.get('question', None) answer = body.get('answer', None) category = body.get('category', None) difficulty = body.get('difficulty', None) search = body.get('searchTerm', None) try: # if json body contains no search, a new question will be created if not search: if question is None or answer is None \ or category is None or difficulty is None: abort(422) new_question = Question(question=question, answer=answer, category=category, difficulty=difficulty) new_question.insert() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'created': new_question.id, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) else: # If the json request contains search, a search will be # implemented selection = Question.query.order_by(Question.id).filter( Question.question.ilike(f'%{search}%')) current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(selection.all()) }) except: abort(422) ''' @DONE: Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route('/categories/<int:category_id>/questions') def get_category_questions(category_id): selection = Question.query.order_by( Question.id).filter(Question.category == category_id) current_questions = paginate_questions(request, selection) current_category = Category.query.get(category_id) if len(current_questions) == 0: abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(current_questions), 'current_category': current_category.type }) ''' @DONE: Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' @app.route('/quizzes', methods=['POST']) def retrieve_quizzes(): body = request.get_json() previous_questions = body.get('previous_questions', None) quiz_category = body.get('quiz_category', None) if previous_questions is None or quiz_category is None: abort(422) # Get questions either by category or all if quiz_category['id'] != 0: questions = Question.query \ .filter(Question.category == quiz_category['id']) \ .filter(~Question.id.in_(previous_questions)) else: questions = Question.query \ .filter(~Question.id.in_(previous_questions)) if not questions: abort(404) # Get a list of all the filtered IDs in order to select a random # number from it random_list = [question.id for question in questions] if len(random_list) == 0: return jsonify({'result': True}) random_id = random.choice(random_list) # Select one random question against the random list question = Question.query.get(random_id) return jsonify({ 'success': True, 'question': question.format(), }) ''' @DONE: Create error handlers for all expected errors including 404 and 422. ''' @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "bad request" }), 400 @app.errorhandler(500) def internal_error(error): return jsonify({"success": False, "error": 500, "message": error}), 500 def view(request): raise NotFound() @responder def application(environ, start_response): request = BaseRequest(environ) try: return view(request) except NotFound as e: return not_found(request) except HTTPException as e: return e return app
def create_app(test_config=None): app = Flask(__name__,static_folder='./my-react-app/build', static_url_path='/') setup_db(app) CORS(app) @app.route('/') def index(): return app.send_static_file('index.html') @app.route("/drinks", methods=["GET"]) @cross_origin() def get_all_drinks(): drinks = Drink.query.all() try: return ( json.dumps( {"success": True, "drinks": [drink.title for drink in drinks]} ), 200 ) except: abort(400) @app.route("/post-drinks", methods=["POST"]) @cross_origin() @requires_auth("post:drinks") def drink_post(jwt): body = dict(request.form or request.json or request.data) new_drink_title = body.get("title", None) new_recipe_drink = body.get("recipe", None) if new_drink_title is '': abort(422) try: drink = Drink(title=new_drink_title, recipe=json.dumps([new_recipe_drink])) drink.insert() return( json.dumps({"success": True, "newly_created_drink": drink.long()}), 200) except Exception: abort(422) @app.route("/drinks-detail", methods=["GET"]) @cross_origin() @requires_auth("get:drinks-detail") def drinks_detail(jwt): drinks = Drink.query.all() try: return ( json.dumps( {"success": True, "drinks": [drink.long() for drink in drinks]} ), 200, ) except Exception: abort(400) @app.route("/drinks-update/<int:id>", methods=["PATCH"]) @cross_origin() @requires_auth("patch:drinks") def update_drinks(jwt, id): id = id drink = Drink.query.filter(Drink.id==id).one_or_none() if drink is None: abort(404) try: body = dict(request.form or request.json or request.data) updated_recipe = body.get("recipe", None) updated_title = body.get("title", None) if updated_recipe: drink.recipe = json.dumps(updated_recipe) if updated_title: drink.title = updated_title drink.update() return (json.dumps({"success": True, "drinks": drink.long()}), 200) except Exception: abort(422) @app.route("/drinks-delete/<int:drink_id>", methods=["DELETE"]) @cross_origin() @requires_auth("delete:drinks") def delete_drink(jwt, drink_id): drink = Drink.query.filter(Drink.id ==drink_id).one_or_none() if drink is None: abort(404) else: try: drink.delete() return( json.dumps( { "success": True, "deleted": drink.id, }),200) except Exception: abort(400) ## Error Handling @app.errorhandler(404) def not_found(error): return app.send_static_file('index.html') @app.errorhandler(422) def unprocessable(error): return( json.dumps({"success": False, "error": 422, "message": "unprocessable"}), 422) @app.errorhandler(400) def bad_request(error): return( json.dumps({"success": False, "error": 400, "message": "bad request"}), 400) @app.errorhandler(500) def internal_service_error(error): return( json.dumps( {"success": False, "error": 500, "message": "internal server error"}), 500) @app.errorhandler(401) def unauthorized_error(error): return ( json.dumps( {"success": False, "error": 401, "message": "unauthorized"}), 401) @app.errorhandler(AuthError) def auth_error(error): response = jsonify(error.error) response.status_code = error.status_code return response return app
def create_app(test_config=None): """Create and configure the app.""" app = Flask(__name__) setup_db(app) CORS(app, resources={r"*": {"origins": "*"}}) # CORS Headers @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type:application/json, Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE, OPTIONS') return response def get_error_message(error, default_text): """Get error messages.""" try: return error.description['message'] except: return default_text @app.route('/') def landing_page(): return "Welcome to the Casting Agency!" @app.route('/actors', methods=['GET']) @requires_auth('get:actors') def get_actors(token): """Return a list of actors.""" actors = Actor.query.order_by(Actor.id).all() current_actors = pagination(request, actors) if len(current_actors) == 0: abort(404, {'message': 'No Actors Found In Database'}) result = {'success': True, 'current_actors': current_actors} return jsonify(result) @app.route('/actors', methods=['POST']) @requires_auth('post:actors') def create_actors(token): """Create a new Actor.""" body = request.get_json() if not body: abort(404, {'message', 'Request does not contain a valid JSON body'}) name = body.get('name', None) age = body.get('age', None) gender = body.get('gender', 'Other') if not name: abort(422, {'message': 'No Name Provided'}) if not age: abort(422, {'message': 'No Age Provided'}) new_actor = (Actor(name=name, age=age, gender=gender)) new_actor.insert() return jsonify({'success': True, 'created': new_actor.id}) @app.route('/actors/<int:actor_id>', methods=['PATCH']) @requires_auth('patch:actors') def edit_actors(token, actor_id): """Edit actors.""" body = request.get_json() if not actor_id: abort(400, {'message': 'Please add an actor id to the requested url'}) if not body: abort(400, {'message': 'Request does not contain a vaild JSON body.'}) actor_to_update = Actor.query.filter( Actor.id == actor_id).one_or_none() if not actor_to_update: abort( 404, { 'message': 'Actor with id {} not found in database.'.format(actor_id) }) name = body.get('name', actor_to_update.name) age = body.get('age', actor_to_update.age) gender = body.get('gender', actor_to_update.gender) actor_to_update.name = name actor_to_update.age = age actor_to_update.gender = gender actor_to_update.update() return jsonify({ 'success': True, 'updated': actor_to_update.id, 'actor': [actor_to_update.format()] }) @app.route('/actors/<int:actor_id>', methods=['DELETE']) @requires_auth('delete:actors') def delete_actor(token, actor_id): """Delete a Actor.""" if not actor_id: abort(400, {'message': 'Please add an actor id to the requested url'}) actor_to_delete = Actor.query.filter( Actor.id == actor_id).one_or_none() if not actor_to_delete: abort( 404, { 'message': 'Actor with id {} not found in datebase.'.format(actor_id) }) actor_to_delete.delete() return jsonify({'success': True, 'deleted': actor_id}) @app.route('/movies', methods=['GET']) @requires_auth('get:movies') def get_movies(token): """Get movies route.""" selection = Movie.query.order_by(Movie.id).all() paginated_movies = pagination(request, selection) if len(paginated_movies) == 0: abort(404, {'message': 'No movies found in database.'}) return jsonify({'success': True, 'movies': paginated_movies}) @app.route('/movies', methods=['POST']) @requires_auth('post:movies') def create_movies(token): """Create movies route.""" if request.data: body = request.get_json() if not body: abort( 400, {'message': 'Request does not contain a vaild JSON body'}) title = body.get('title', None) release_date = body.get('release_date', None) if not title: abort(422, {'message': 'No title provided'}) if not release_date: abort(422, {'message': 'No "release_date" provided'}) new_movie = (Movie(title=title, release_date=release_date)) new_movie.insert() return jsonify({'success': True, 'created': new_movie.id}) else: abort(422) @app.route('/movies/<int:movie_id>', methods=['PATCH']) @requires_auth('patch:movies') def edit_movies(token, movie_id): """Edit movies method.""" body = request.get_json() if not movie_id: abort(400, { 'message': 'Please add a valid movie ID to the requested url' }) if not body: abort(400, {'message': 'Request does not contain a vaild JSON body'}) movie_to_update = Movie.query.filter( Movie.id == movie_id).one_or_none() if not movie_to_update: abort( 404, { 'message': 'Movie with id {} not found in database.'.format(movie_id) }) title = body.get('title', movie_to_update.title) release_date = body.get('release_date', movie_to_update.release_date) movie_to_update.title = title movie_to_update.release_date = release_date movie_to_update.update() return jsonify({ 'success': True, 'edited': movie_to_update.id, 'movie': [movie_to_update.format()] }) @app.route('/movies/<int:movie_id>', methods=['DELETE']) @requires_auth('delete:movies') def delete_movies(token, movie_id): """Delete method for movies.""" if not movie_id: abort(400, {'message': 'Please add a movie id to the requested url'}) movie_to_delete = Movie.query.filter( Movie.id == movie_id).one_or_none() if not movie_to_delete: abort( 404, { 'message': 'Movie with id {} not found in database.'.format(movie_id) }) movie_to_delete.delete() return jsonify({'success': True, 'deleted': movie_id}) @app.errorhandler(404) def not_found(error): return jsonify({ 'success': False, 'error': 404, 'message': 'Resource Not Found' }), 404 @app.errorhandler(422) def unprocessable(error): return jsonify({ 'success': False, 'error': 422, 'message': 'unprocessable' }), 422 @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "bad request" }), 400 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs ''' CORS(app, resources={'/': {'origins': '*'}}) ''' @TODO: Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') response.headers.add('Access-Control-Allow-Origin', '*') return response ''' @TODO: Create an endpoint to handle GET requests for all available categories. ''' @app.route("/categories", methods=['GET']) def get_categories(): selection = Category.query.all() if len(selection) == 0: abort(404) categories = {category.id: category.type for category in selection} return jsonify({ 'success': True, 'categories': categories # [category.format() for category in selection], }) ''' @TODO: Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' @app.route("/questions", methods=['GET']) def get_questions(): selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) category_selection = Category.query.all() categories = { category.id: category.type for category in category_selection } if len(current_questions) == 0: abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'totalQuestions': len(Question.query.all()), 'categories': categories }) ''' @TODO: Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' @app.route("/questions/<int:question_id>", methods=['DELETE']) def delete_question(question_id): try: question = Question.query.filter( Question.id == question_id).one_or_none() if question is None: abort(404) question.delete() return jsonify({'success': True, 'question_id': question_id}) except Exception: abort(422) ''' @TODO: Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' @app.route("/questions", methods=['POST']) def create_question(): body = request.get_json() if body.get('question') and body.get('answer') and body.get( 'category') and body.get('difficulty'): new_question_string = body.get('question') new_answer_string = body.get('answer') new_category_string = body.get('category') new_difficulty_string = body.get('difficulty') try: new_question = Question(question=new_question_string, answer=new_answer_string, category=new_category_string, difficulty=new_difficulty_string) new_question.insert() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'created': new_question.id, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) except Exception as error: abort(422) elif body.get('searchTerm'): try: phrase = body.get('searchTerm') search_phrase = "%{0}%".format(phrase) selection = Question.query.filter( Question.question.ilike(search_phrase)).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(selection) }) except Exception as error: abort(422) else: abort(422) ''' @TODO: Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' ''' @TODO: Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route("/categories/<int:category_id>/questions", methods=['GET']) def get_questions_by_category(category_id): selection = Question.query.filter( Question.category == category_id).all() current_questions = paginate_questions(request, selection) if len(selection) == 0: abort(404) return jsonify({ 'success': True, 'category': category_id, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) ''' @TODO: Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' @app.route('/quizzes', methods=['POST']) def get_quiz_question(): try: body = request.get_json() previous_questions = body.get('previous_questions', None) category = body.get('quiz_category', None) if category is None: abort(422) category_id = int(category['id']) if category_id == 0: questions = Question.query.order_by(Question.id).all() else: questions = Question.query.filter( Question.category == int(category_id)).all() if previous_questions is not None: if len(previous_questions) == len(questions): return jsonify({"success": True}) def get_random_question(questions_possible): return questions_possible[random.randint( 0, len(questions) - 1)] if previous_questions == [] or previous_questions is None: question = get_random_question(questions) else: question = get_random_question(questions) while question.id in previous_questions: question = get_random_question(questions) print(question.format()) return jsonify({"success": True, "question": question.format()}) except Exception as error: abort(400) ''' @TODO: Create error handlers for all expected errors including 404 and 422. ''' @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "bad request" }), 400 @app.errorhandler(404) def not_found(error): return jsonify({ 'success': False, 'error': 404, 'message': 'resource not found' }), 404 @app.errorhandler(422) def not_found(error): return jsonify({ 'success': False, 'error': 422, 'message': 'unproccessable' }), 422 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) # DONE: Set up CORS. Allow '*' for origins. Delete the sample route # after completing the TODOs CORS(app, resources={r"/api/*": {"origins": "*"}}) # DONE: Use the after_request decorator to set Access-Control-Allow @app.after_request def after_request(response): response.headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization, true") response.headers.add("Access-Control-Allow-Headers", "GET, PATCH, POST, DELETE, OPTIONS") return response # DONE: Create an endpoint to handle GET requests for all available # categories. @app.route("/api/categories", methods=["GET"]) def retrieve_categories(): try: return jsonify({ "success": True, "categories": format_categories(), }) except Exception: abort(500) # DONE: Create an endpoint to handle GET requests for questions, # including pagination (every 10 questions). # This endpoint should return a list of questions, # number of total questions, current category, categories. # TEST: curl localhost:5000/questions @app.route("/api/questions", methods=["GET"]) def retrieve_questions(): selection = Question.query.all() current_questions = paginate_questions(request, selection) if not current_questions: abort(404) return jsonify({ "success": True, "questions": current_questions, "total_questions": len(selection), "categories": format_categories(), "current_category": None }) # TEST: At this point, when you start the application # you should see questions and categories generated, # ten questions per page and pagination at the bottom of the screen # for three pages. # Clicking on the page numbers should update the questions. # DEBUG route # TEST: curl localhost:5000/questions/4 -X GET @app.route("/api/questions/<int:question_id>", methods=["GET"]) def retrieve_question(question_id): try: question = Question.query.filter( Question.id == question_id).one_or_none() if not question: abort(404) return jsonify({ "success": True, "questions": question.format(), "current_category": None }) except Exception: abort(422) # DONE: Create an endpoint to DELETE question using a question ID. # TEST: curl localhost:5000/questions/5 -X DELETE @app.route("/api/questions/<int:question_id>", methods=["DELETE"]) def delete_question(question_id): try: question = Question.query.filter( Question.id == question_id).one_or_none() if not question: abort(404) question.delete() selection = Question.query.all() current_questions = paginate_questions(request, selection) return jsonify({ "success": True, "questions": current_questions, "total_questions": len(selection), "categories": format_categories(), "current_category": None, "deleted": question_id }) except Exception: abort(404) # TEST: When you click the trash icon next to a question, the question will # be removed. # This removal will persist in the database and when you refresh the page. # DONE: Create an endpoint to POST a new question, # which will require the question and answer text, # category, and difficulty score. # DONE: Create a POST endpoint to get questions based on a search term. # It should return any questions for whom the search term # is a substring of the question. @app.route("/api/questions", methods=["POST"]) def add_question(): form_data = request.json if "searchTerm" in form_data: search_term = form_data["searchTerm"].strip() questions = Question.query.filter( Question.question.ilike(f"%{search_term}%")).all() current_questions = [q.format() for q in questions] return jsonify({"success": True, "questions": current_questions}) else: if (form_data['question'].strip() == "") or (form_data["answer"].strip() == ""): abort(400) try: new_question = Question(question=form_data['question'].strip(), answer=form_data['answer'].strip(), category=form_data['category'], difficulty=form_data['difficulty']) new_question.insert() except Exception: abort(422) return jsonify({"success": True, "added": new_question.id}) # TEST: When you submit a question on the "Add" tab, # the form will clear and the question will appear at the end of the last # page of the questions list in the "List" tab. # TEST: Search by any phrase. The questions list will update to include # only question that include that string within their question. # Try using the word "title" to start. # TODO: Create a GET endpoint to get questions based on category. @app.route('/api/categories/<int:category_id>/questions') def get_category_questions(category_id): questions = Question.query.filter_by(category=str(category_id)).all() current_questions = paginate_questions(request, questions) if not current_questions: abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': len(questions), 'categories': Category.query.get(category_id).format(), 'current_category': category_id }) # TEST: In the "List" tab / main screen, clicking on one of the # categories in the left column will cause only questions of that # category to be shown. # DONE: Create a POST endpoint to get questions to play the quiz. # This endpoint should take category and previous question parameters # and return a random questions within the given category, # if provided, and that is not one of the previous questions. @app.route('/api/quizzes', methods=['POST']) def play(): request_data = request.json try: request_cat = request_data['quiz_category']['id'] except Exception: abort(400) if request_cat == 0: questions = Question.query.all() else: questions = Question.query.filter_by( category=str(request_cat)).all() questions = [x.format() for x in questions] # Remove questions that have been already asked try: previous_questions = request_data['previous_questions'] except Exception: abort(400) fresh_questions = [] for question in questions: if question['id'] not in previous_questions: fresh_questions.append(question) # Make sure not all the questions were asked # If so, return nothing to tell the frontend that the game is over if not fresh_questions: return jsonify({'success': True}) question = random.choice(fresh_questions) return jsonify({'success': True, 'question': question}) # TEST: In the "Play" tab, after a user selects "All" or a category, # one question at a time is displayed, the user is allowed to answer # and shown whether they were correct or not. # DONE: Create error handlers for all expected errors @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "Bad Request" }) @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "Not found" }) @app.errorhandler(422) def unprocessable_entity(error): return jsonify({ "success": False, "error": 422, "message": "Unprocessable Entity" }) @app.errorhandler(500) def server_error(error): return jsonify({ "success": False, "error": 500, "message": "Internal Server Error" }) return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs ''' #Default CORS origin is * CORS(app) ''' @TODO: Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers['Access-Control-Allow'] = '*' return response ''' @TODO: Create an endpoint to handle GET requests for all available categories. ''' @app.route("/categories") def get_categories(): # Query all categories categories = Category.query.all() # Reformat categories into a dictionary # of id: type categories_ids = { category.id: category.type for category in categories } result = jsonify({'success': True, 'categories': categories_ids}) return result ''' @TODO: Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' # Create pagination function called in get_questions def paginate(questions, max_per_page, page): start = (page - 1) * max_per_page end = page * max_per_page questions = questions[start:end] return questions @app.route("/questions") def get_questions(): # Get page number from request page = request.args.get('page', default=1) page = int(page) # Query all questions from database and format questions = Question.query.all() questions = [question.format() for question in questions] # Calculate total length of request to support pagination max_questions = len(questions) # Run paginate custom function questions = paginate(questions, QUESTIONS_PER_PAGE, page) # Get all categories categories = Category.query.all() categories_ids = { category.id: category.type for category in categories } result = { 'success': True, 'questions': questions, 'total_questions': max_questions, 'categories': categories_ids, 'currentCategory': None } return jsonify(result) ''' @TODO: Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' @app.route("/questions/<int:id>", methods=['DELETE']) def delete_question(id): question = Question.query.filter(Question.id == id).first() if question is None: abort(404) try: question.delete() except Exception as e: abort(500) result = jsonify({'success': True}) return result ''' @TODO: Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' @app.route("/questions", methods=['POST']) def create_question(): body = request.get_json() # Make sure all keys are in the request form_keys = ['question', 'answer', 'difficulty', 'category'] if not all(form_key in body for form_key in form_keys): abort(400) try: q = Question(question=body['question'], answer=body['answer'], difficulty=body['difficulty'], category=body['category']) q.insert() except Exception as e: db.session.rollback() print(e) result = jsonify({'success': True}) return result ''' @TODO: Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' @app.route("/questions/search", methods=['POST']) def search_questions(): #Get search term body = request.get_json() search_term = body['searchTerm'] # Find and format questions with the search team, case insensitive questions = Question.query.filter( Question.question.ilike('%{}%'.format(search_term))).all() questions = [question.format() for question in questions] result = { 'success': True, 'questions': questions, 'totalQuestions': len(questions), 'currentCategory': None } return jsonify(result) ''' @TODO: Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' @app.route('/categories/<id>/questions') def question_category(id): category_id = id questions = Question.query.filter( Question.category == category_id).all() questions = [question.format() for question in questions] result = { 'success': True, 'questions': questions, 'totalQuestions': len(questions), 'currentCategory': None } return jsonify(result) ''' @TODO: Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' @app.route('/quizzes', methods=['POST']) def play_quiz(): body = request.get_json() # Category is object with type: string, id: int category = body['quiz_category'] previous_questions = body['previous_questions'] #Get all questions in category questions = Question.query.filter(Question.category == category['id']) # Get full list of question ids in the category question_ids = [] for q in questions: question_ids.append(q.id) # Remove question ids if in previous questions list # Informed by list comprehension in following Stack Overflow answer: # https://stackoverflow.com/questions/4211209/remove-all-the-elements-that-occur-in-one-list-from-another/4211228 potential_question_ids = [ id for id in question_ids if id not in previous_questions ] # Get random question from potential question ids if len(potential_question_ids) > 0: random_question_id = random.choice(potential_question_ids) for q in questions: if q.id == random_question_id: random_question = q.format() else: random_question = None result = {'success': True, 'question': random_question} return jsonify(result) ''' @TODO: Create error handlers for all expected errors including 404 and 422. 400, 404, 422 and 500 ''' @app.errorhandler(405) def method_not_allowed(e): return jsonify({ 'success': False, 'error': 405, 'message': 'Method not allowed' }), 405 @app.errorhandler(500) def server_error(e): return jsonify({ 'success': False, 'error': 500, 'message': 'Internal server error' }), 500 @app.errorhandler(422) def unprocessable_entity(e): return jsonify({ 'success': False, 'error': 422, 'message': 'Request was well formed but included semantic errors' }), 422 @app.errorhandler(404) def not_found(e): return jsonify({ 'success': False, 'error': 404, 'message': 'Page not found' }), 404 @app.errorhandler(400) def bad_request(e): return jsonify({ 'success': False, 'error': 400, 'message': 'Bad request' }), 400 return app
def create_app(test_config=None): app = Flask(__name__) CORS(app) setup_db(app) @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,authorization,True') response.headers.add('Acess-Control-Allow-Methods', 'GET,POST,PATCH,DELETE,OPTIONS') return response @app.route('/') def index(): return 'Congrats' @app.route('/actors') @requires_auth('get:actors') def get_all_actors(payload): try: Actors = Actor.query.all() Actors = [actor.format() for actor in Actors] return (jsonify({'success': True, 'Actors': Actors}), 200) except: abort(401) @app.route('/movies') @requires_auth('get:movies') def get_all_movies(token): movies = Movie.query.all() movies = [movie.format() for movie in movies] return (jsonify({'success': True, 'Movies': movies}), 200) @app.route('/actors/<int:actor_id>', methods=['DELETE']) @requires_auth('delete:actors') def delete_actor(token, actor_id): try: x = Actor.query.filter(Actor.id == actor_id).one_or_none() if x is None: abort(404) x.delete() return (jsonify({'success': True, 'actor_id': actor_id}), 200) except: abort(422) @app.route('/movies/<int:id>', methods=['DELETE']) @requires_auth('delete:movies') def delete_movie(token, id): try: x = Movie.query.filter(Movie.id == id).one_or_none() if x is None: abort(404) x.delete() return (jsonify({'success': True, 'id': id}), 200) except: abort(422) @app.route('/actors', methods=['POST']) @requires_auth('post:actors') def post_actor(token): try: body = request.get_json( ) # fetch the body data from the request body requested_name = body.get('name') requested_age = body.get('age') requested_gender = body.get('gender') if requested_name is None: abort(422) new_actor = Actor( name=requested_name, age=requested_age, gender=requested_gender ) # add the new data to the table as a new record new_actor.insert() if body is None: abort(422) return (jsonify({'success': True, 'id': new_actor.id}), 200) except: abort(422) @app.route('/movies', methods=['POST']) @requires_auth('post:movies') def post_movie(token): try: body = request.get_json() requested_title = body.get('title') requested_release_date = body.get('release_date') requested_actor_id = body.get('actor_id') new_movie = Movie( title=requested_title, release_date=requested_release_date, actor_id=requested_actor_id ) # add the new data to the table as a new record new_movie.insert() if body is None: abort(422) return (jsonify({'success': True, 'movies': new_movie.id}), 200) except: abort(422) @app.route('/actors/<int:id>', methods=['PATCH']) @requires_auth('edit:actors') def edit_actors(token, id): body = request.get_json() # fetch the body data from the request body to_be_updated_row = Actor.query.filter(Actor.id == id).one_or_none( ) # See if we have that id is in our Table ? if to_be_updated_row is None: abort( 404 ) # id is Not found , we do not have that record in our table requested_name = body.get('name') requested_age = body.get('age') requested_gender = body.get('gender') if requested_name is not None: to_be_updated_row.name = requested_name if requested_age is not None: to_be_updated_row.age = requested_age if requested_gender is not None: to_be_updated_row.gender = requested_gender try: to_be_updated_row.update() except: abort(422) actors = Actor.query.filter(Actor.id == id).one_or_none() if actors is None: abort(404) # The Record is not found return (jsonify({'success': True, 'Actor': to_be_updated_row.id}), 200) @app.route('/movies/<int:id>', methods=['PATCH']) @requires_auth('edit:movies') def edit_movies(token, id): body = request.get_json() # fetch the body data from the request body to_be_updated_row_n = Movie.query.filter(Movie.id == id).one_or_none( ) # See if we have that id is in our Table ? if to_be_updated_row_n is None: abort( 404 ) # id is Not found , we do not have that record in our table # add the new data to the table as a new record if body.get('title') is not None: to_be_updated_row_n.title = body.get('title') if body.get('release_date') is not None: to_be_updated_row_n.release_date = body.get('release_date') try: to_be_updated_row_n.update() except: abort(422) return (jsonify({ 'success': True, 'Movies': to_be_updated_row_n.id }), 200) @app.errorhandler(422) def unprocessable(error): return (jsonify({ 'success': False, 'error': 422, 'message': 'unprocessable' }), 422) @app.errorhandler(400) def badrequest(error): return (jsonify({ 'success': False, 'error': 400, 'message': 'bad request' }), 400) @app.errorhandler(404) def not_found(error): return (jsonify({ 'success': False, 'error': 404, 'message': 'resource not found' }), 404) @app.errorhandler(401) def Unauthorized(error): return (jsonify({ 'success': False, 'error': 401, 'message': 'Unauthorized' }), 401) @app.errorhandler(500) def server_error(error): return (jsonify({ 'success': False, 'error': 500, 'message': 'Internal Server Error' }), 500) @app.errorhandler(AuthError) def handle_auth_error(ex): response = jsonify(ex.error) response.status_code = ex.status_code return (jsonify({ 'sucess': False, 'error': response.status_code, 'message': response }), response.status_code) return app
def create_app(test_config=None): app = Flask(__name__) setup_db(app) #@TODO:Set up CORS. Allow '*' for origins, and Delete the sample route after completing the TODOs: CORS(app, resources={'/': {'origins': '*'}}) #Use the after_request decorator to set Access-Control-Allow: @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') return response #Create an endpoint to handle GET requests for all available categories: @app.route('/categories') def get_categories(): categories = Category.query.all() categories_dict = {} for category in categories: categories_dict[category.id] = category.type if (len(categories_dict) == 0): abort(404) return jsonify({ 'success': True, 'categories': categories_dict }) #Create an endpoint to handle GET requests for questions, including pagination (every 10 questions): #This endpoint should return a list of questions,number of total questions, current category, categories: #TEST: At this point, when you start the application #you should see questions and categories generated, #ten questions per page and pagination at the bottom of the screen for three pages. #Clicking on the page numbers should update the questions. @app.route('/questions') def get_questions(): selection = Question.query.all() total_questions = len(selection) current_questions = paginate_questions(request, selection) categories = Category.query.all() categories_dict = {} for category in categories: categories_dict[category.id] = category.type if (len(current_questions) == 0): abort(404) return jsonify({ 'success': True, 'questions': current_questions, 'total_questions': total_questions, 'categories': categories_dict }) #Create an endpoint to DELETE question using a question ID: #TEST: When you click the trash icon next to a question, the question will be removed. #This removal will persist in the database and when you refresh the page. @app.route('/questions/<int:id>', methods=['DELETE']) def delete_question(id): try: question = Question.query.filter_by(id=id).one_or_none() if question is None: abort(404) question.delete() return jsonify({ 'success': True, 'deleted': id }) except: abort(422) #Handles POST requests for creating new questions and searching questions: #Create an endpoint to POST a new question, which will require the question and answer text, #category, and difficulty score. #TEST: When you submit a question on the "Add" tab, #the form will clear and the question will appear at the end of the last page #of the questions list in the "List" tab. #Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term #is a substring of the question. #TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. #Try using the word "title" to start. @app.route('/questions', methods=['POST']) def post_question(): body = request.get_json() if (body.get('searchTerm')): search_term = body.get('searchTerm') selection = Question.query.filter( Question.question.ilike(f'%{search_term}%')).all() if (len(selection) == 0): abort(404) paginated = paginate_questions(request, selection) return jsonify({ 'success': True, 'questions': paginated, 'total_questions': len(Question.query.all()) }) else: new_question = body.get('question') new_answer = body.get('answer') new_difficulty = body.get('difficulty') new_category = body.get('category') if((new_question is None) or (new_answer is None) or (new_difficulty is None) or (new_category is None)): abort(422) try: question = Question(question=new_question, answer=new_answer, difficulty=new_difficulty, category=new_category) question.insert() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'created': question.id, 'question_created': question.question, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) except: abort(422) # Create a GET endpoint to get questions based on category: #TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that #category to be shown. @app.route('/categories/<int:id>/questions') def get_questions_by_category(id): category = Category.query.filter_by(id=id).one_or_none() if (category is None): abort(400) selection = Question.query.filter_by(category=category.id).all() paginated = paginate_questions(request, selection) return jsonify({ 'success': True, 'questions': paginated, 'total_questions': len(Question.query.all()), 'current_category': category.type }) #Create a POST endpoint to get questions to play the quiz. # This endpoint should take category and previous question parameters #and return a random questions within the given category, # if provided, and that is not one of the previous questions. #TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer #and shown whether they were correct or not. @app.route('/quizzes', methods=['POST']) def get_random_quiz_question(): body = request.get_json() previous = body.get('previous_questions') category = body.get('quiz_category') if ((category is None) or (previous is None)): abort(400) if (category['id'] == 0): questions = Question.query.all() else: questions = Question.query.filter_by(category=category['id']).all() total = len(questions) #Picks a random question: def get_random_question(): return questions[random.randrange(0, len(questions), 1)] #Checks to see if question has already been used: def check_if_used(question): used = False for ques in previous: if (ques == question.id): used = True return used question = get_random_question() while (check_if_used(question)): question = get_random_question() if (len(previous) == total): return jsonify({ 'success': True }) return jsonify({ 'success': True, 'question': question.format() }) #Create error handlers for all expected errors: @app.errorhandler(400) def not_found(error): return jsonify({ "success": False, "error": 400, "message": "Bad Request" }), 400 @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "Resource Not Found" }), 404 @app.errorhandler(422) def not_found(error): return jsonify({ "success": False, "error": 422, "message": "Unprocessable" }), 422 return app
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) ''' @TODO: DONE Set up CORS. Allow '*' for origins. @TODO: Delete the sample route after completing the TODOs ''' cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) ''' @TODO: DONE Use the after_request decorator to set Access-Control-Allow ''' @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization, true') response.headers.add('Access-Control-Allow-Methods', 'GET, POST, DELETE') return response ''' @TODO: DONE. Works, imgs working Create an endpoint to handle GET requests for all available categories. ''' #Get categories. FE: FormView #20 Categories @app.route('/categories', methods=['GET']) def get_categories(): categories = Category.query.all() #categories = {category.id: category.type for category in all_categories} formatted_categories = {} #dictionary for category in categories: formatted_categories[category.id] = category.type if len(categories) == 0: abort(404) #resource not found return jsonify({ "success": True, "categories": formatted_categories, "total_categories": len(categories) }) ''' @TODO: Done, Works. Create an endpoint to handle GET requests for questions, including pagination (every 10 questions). This endpoint should return a list of questions, number of total questions, current category, categories. TEST: At this point, when you start the application you should see questions and categories generated, ten questions per page and pagination at the bottom of the screen for three pages. Clicking on the page numbers should update the questions. ''' #Get Questions. FE: QuestionView #24 @app.route('/questions', methods=['GET']) #Qview: /questions?page=${this.state.page} def get_question(): page = request.args.get('page', 1, type=int) start = (page - 1) * 10 end = start + 10 questions = [question.format() for question in Question.query.all()] if len(questions) == 0: abort(404) else: #categories = {category.id: category.type for category in all_categories} categories = Category.query.all() formatted_categories = {} #dictionary for category in categories: formatted_categories[category.id] = category.type return jsonify({ "success": True, "questions": questions[start:end], "total_questions": len(questions), "categories": formatted_categories, "current_category": None }) ''' #@TODO: Done; Works Create an endpoint to DELETE question using a question ID. TEST: When you click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' #Delete question; FE: Qview 105 @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): #question_id = request.json.get('id') #id from QuestionView.js try: question = Question.query.filter( Question.id == question_id).one_or_none() if question is None: abort(404) #resource not found question.delete() selection = Question.query.all() #current_questions = paginate_questions(request, selection) return jsonify({ "success": True, "deleted": question_id, "total_questions": len(selection) }) except Exception as e: print("Exception: ", e) print(sys.exc_info()) abort(422) #unprocessable ''' @TODO: DONE works Create an endpoint to POST a new question, which will require the question and answer text, category, and difficulty score. TEST: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' #Add new question; FE: FormView #37. ToDo: invalidate if info missing @app.route('/questions/add', methods=['POST']) def submit_question(): #From form: question, answer, difficulty, category #body, etc. based on books example data = request.get_json() #replace body w data for consistency new_question = data.get('question') new_answer = data.get('answer') new_difficulty = data.get('difficulty') new_category = data.get('category') #Note: category type or id. id is int, type is string try: add_question = Question(question=new_question, answer=new_answer, category=new_category, difficulty=new_difficulty) add_question.insert() return jsonify({ "success": True, "question": new_question, "answer": new_answer, "difficulty": new_difficulty, "category": new_category }) except Exception as e: print('Exception is >> ', e) print(sys.exc_info()) abort(422) ''' @TODO: DONE *Working on backend & frontend!!! Create a POST endpoint to get questions based on a search term. It should return any questions for whom the search term is a substring of the question. TEST: Search by any phrase. The questions list will update to include only question that include that string within their question. Try using the word "title" to start. ''' #Search questions @app.route('/questions/search', methods=['POST']) def submit_search(): search_term = request.json.get('searchTerm', None) questions = Question.query.filter( Question.question.ilike('%{}%'.format(search_term))).all() formatted_questions = [question.format() for question in questions] if len(questions) == 0: formatted_questions = [] abort(404) return jsonify({ "success": True, "questions": formatted_questions, "total_questions": len(questions), "current_category": None }) ''' @TODO: DONE *works; c.f. questions end point Create a GET endpoint to get questions based on category. TEST: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' #Get questions by category @app.route('/categories/<int:category_id>/questions', methods=['GET']) def get_by_category(category_id): questions = Question.query.filter( Question.category == str(category_id)).all() formatted_questions = [question.format() for question in questions] if len(questions) == 0: abort(404) #resource not found else: return jsonify({ "success": True, "questions": formatted_questions, "total_questions": len(Question.query.all()), "current_category": category_id }) ''' @TODO: DONE, working Create a POST endpoint to get questions to play the quiz. This endpoint should take category and previous question parameters and return a random questions within the given category, if provided, and that is not one of the previous questions. TEST: In the "Play" tab, after a user selects "All" or a category, one question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' #Quiz - questions to play; FE: QuizView #50 @app.route('/quizzes', methods=['POST']) def questions_to_play(): data = request.get_json() category_id = int(data['quiz_category']['id']) category = Category.query.get(category_id) previous_questions = data['previous_questions'] try: #Get questions if category is not selected that have not been played; QuizView #105 if category == None: get_questions = Question.query.filter( Question.id.notin_(previous_questions)).all() #Get questions with selected category that have not been played else: get_questions = (Question.query.filter( Question.category == category_id).filter( Question.id.notin_(previous_questions)).all()) questions = [question.format() for question in get_questions] #Randomize order of questions, deliver 1 at a time if (len(questions) == 0): quest = None else: quest = questions[random.randrange( 0, len(questions) )] #rvu: can also use func.random() in your SQLAlchemy return jsonify({"question": quest, "success": True}) except Exception as e: print("Exception >> ", e) print(sys.exc_info()) abort(422) ''' @TODO: DONE Create error handlers for all expected errors including 404 and 422. ''' @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "bad request" }), 400 @app.errorhandler(404) def resource_not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 @app.errorhandler(500) def not_found(error): return jsonify({ "success": False, "error": 500, "message": "internal server error" }), 500 return app
def setUp(self): """Difine test variables and initialize app.""" self.app = create_app() self.client = self.app.test_client self.database_path = DATABASE_URL setup_db(self.app, self.database_path) # bind the app to the current context with self.app.app_context(): self.db = db self.db.init_app(self.app) # create all tables self.db.create_all() # set up jwts self.user_headers = { 'Authorization': 'Bearer {}'.format(os.environ['USER_JWT']) } self.extra_user_headers = { 'Authorization': 'Bearer {}'.format(os.environ['USER2_JWT']) } self.staff_headers = { 'Authorization': 'Bearer {}'.format(os.environ['STAFF_JWT']) } self.manager_headers = { 'Authorization': 'Bearer {}'.format(os.environ['MANAGER_JWT']) } # set up initial clothes and users # using manager JWT and create clothes and users # ------------------------------ # delete all existing clothes and users # ------------------------------ res = self.client().get('/clothes', headers=self.manager_headers) data = json.loads(res.data) for clothes in data['clothes']: res = self.client().delete('/clothes/{}'.format(clothes['id']), headers=self.manager_headers) res = self.client().get('/users', headers=self.manager_headers) data = json.loads(res.data) for user in data['users']: res = self.client().delete('/users/{}'.format(user['id']), headers=self.manager_headers) # ------------------------------ # create clothes # ------------------------------ clothes = [{ 'type': 'shirt', 'size': '100' }, { 'type': 'pants', 'size': '120' }] response = [] for item_data in clothes: res = self.client().post('/clothes', json=item_data, headers=self.manager_headers) data = json.loads(res.data) response.append(data) # set clothes id for sequencing tests self.clothes_id = response[0]['clothes']['id'] self.extra_clothes_id = response[1]['clothes']['id'] # ------------------------------ # create users # ------------------------------ self.user_auth0_id = "google-oauth2|103606340396848658678" users = [{ "e_mail": "*****@*****.**", "address": "Bunkyo-ku, Tokyo", "auth0_id": self.user_auth0_id, "role": "user" }, { "e_mail": "*****@*****.**", "address": "Shibuya-ku, Tokyo", "auth0_id": "auth0|5fdb49c07567970069085ee9", "role": "user" }] response = [] for item_data in users: res = self.client().post('/users', json=item_data, headers=self.manager_headers) data = json.loads(res.data) response.append(data) staff = { "e_mail": "*****@*****.**", "address": "Shibuya-ku, Tokyo", "auth0_id": "auth0|5fadbe9e64abac00751e7c61", "role": "staff" } res = self.client().post('/users', json=staff, headers=self.manager_headers) manager = { "e_mail": "*****@*****.**", "address": "Shibuya-ku, Tokyo", "auth0_id": "auth0|5f6d247925dd140078ffbefc", "role": "manager" } res = self.client().post('/users', json=manager, headers=self.manager_headers) # set user ids for sequencing tests self.user_id = response[0]['user']['id'] self.extra_user_id = response[1]['user']['id'] # ------------------------------ # make a reservation (with user JWT) # ------------------------------ res = self.client().post( '/clothes/{}/reservations'.format(self.clothes_id), json={"auth0_id": "google-oauth2|103606340396848658678"}, headers=self.user_headers) data = json.loads(res.data) # store reservation information for sequence tests self.reservation = {'clothes': data['clothes'], 'user': data['user']}
def create_app(test_config=None): # create and configure the app app = Flask(__name__) setup_db(app) CORS(app) # CORS Headers @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization,true') response.headers.add('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS') return response @app.route('/books') def retrieve_books(): selection = Book.query.order_by(Book.id).all() current_books = paginate_books(request, selection) if len(current_books) == 0: abort(404) return jsonify({ 'success': True, 'books': current_books, 'total_books': len(Book.query.all()) }) @app.route('/books/<int:book_id>', methods=['PATCH']) def update_book(book_id): body = request.get_json() try: book = Book.query.filter(Book.id == book_id).one_or_none() if book is None: abort(404) if 'rating' in body: book.rating = int(body.get('rating')) book.update() return jsonify({ 'success': True, }) except: abort(400) @app.route('/books/<int:book_id>', methods=['DELETE']) def delete_book(book_id): try: book = Book.query.filter(Book.id == book_id).one_or_none() if book is None: abort(404) book.delete() selection = Book.query.order_by(Book.id).all() current_books = paginate_books(request, selection) return jsonify({ 'success': True, 'deleted': book_id, 'books': current_books, 'total_books': len(Book.query.all()) }) except: abort(422) @app.route('/books', methods=['POST']) def create_book(): body = request.get_json() new_title = body.get('title', None) new_author = body.get('author', None) new_rating = body.get('rating', None) try: book = Book(title=new_title, author=new_author, rating=new_rating) book.insert() selection = Book.query.order_by(Book.id).all() current_books = paginate_books(request, selection) return jsonify({ 'success': True, 'created': book.id, 'books': current_books, 'total_books': len(Book.query.all()) }) except: abort(422) # @TODO: Review the above code for route handlers. # Pay special attention to the status codes used in the aborts since those are relevant for this task! # @TODO: Write error handler decorators to handle AT LEAST status codes 400, 404, and 422. @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "Resource not found" }), 404 @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "Bad Request" }), 400 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 @app.errorhandler(405) def not_allowed(error): return jsonify({ "success": False, "error": 405, "message": "method not allowed" }), 405 return app
def create_app(test_config=None): app = Flask(__name__) setup_db(app) CORS(app, resources={'/': {'origins': '*'}}) @app.route("/") def home(): hiText = "Hi ! I`m Shruti" return str(hiText) @app.route("/actors", methods=["GET"]) @requires_auth('get:actors') def get_actors(token): try: actors = Actor.query.all() return jsonify({"success": True, "actors": [d.format() for d in actors]}), 200 except: abort(404) @app.route("/movies", methods=["GET"]) @requires_auth('get:movies') def get_movies(token): try: movies = Movie.query.all() return jsonify({"success": True, "movies": [d.format() for d in movies]}), 200 except: abort(404) @app.route("/actors/create", methods=["POST"]) @requires_auth('post:actors') def create_actor(token): try: req = request.get_json() act = Actor(name=req['name'], gender=req['gender'], age=req['age']) act.insert() actors = Actor.query.all() return jsonify({"success": True, "actors": [d.format() for d in actors]}), 200 except: abort(404) @app.route("/movies/create", methods=["POST"]) @requires_auth('post:movies') def create_movie(token): try: req = request.get_json() mov = Movie(title=req['title'], release_date=req['release_date']) mov.insert() movies = Movie.query.all() return jsonify({"success": True, "movies": [d.format() for d in movies]}), 200 except: abort(404) @app.route("/actors/<int:id>", methods=["DELETE"]) @requires_auth('delete:actor') def delete_actor(payload, id): try: actor = Actor.query.filter(Actor.id == id).one_or_none() if actor is None: abort(404) else: actor.delete() actors = Actor.query.all() return jsonify({"success": True, "actors": [d.format() for d in actors]}), 200 except: abort(404) @app.route("/movies/<int:id>", methods=["DELETE"]) @requires_auth('delete:movie') def delete_movie(payload, id): try: movie = Movie.query.filter(Movie.id == id).one_or_none() if movie is None: abort(404) else: movie.delete() movies = Movie.query.all() return jsonify({"success": True, "movies": [d.format() for d in movies]}), 200 except: abort(404) @app.route("/actors/<int:id>", methods=["PATCH"]) @requires_auth('patch:actor') def patch_actor(payload, id): try: actor = Actor.query.filter(Actor.id == id).one_or_none() req = request.get_json() if('name' in req): actor.name = req['name'] if('gender' in req): actor.gender = req['gender'] if('age' in req): actor.age = req['age'] actor.update() actors = Actor.query.all() return jsonify({"success": True, "actors": [d.format() for d in actors]}), 200 except: abort(404) @app.route("/movies/<int:id>", methods=["PATCH"]) @requires_auth('patch:movie') def patch_movie(payload, id): try: movie = Movie.query.filter(Movie.id == id).one_or_none() req = request.get_json() if('title' in req): movie.title = req['title'] if('release_date' in req): movie.release_date = req['release_date'] movie.update() movies = Movie.query.all() return jsonify({"success": True, "movies": [d.format() for d in movies]}), 200 except: abort(404) @app.errorhandler(404) def not_found(error): return jsonify({ "success": False, "error": 404, "message": "resourse not found" }), 404 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 @app.errorhandler(405) def method_not_allowed(error): return jsonify({ 'code': 405, 'success': False, 'message': 'method not allowed' }), 405 @app.errorhandler(500) def internal_server_error(error): return jsonify({ 'code': 500, 'success': False, 'message': 'server error' }), 500 @app.errorhandler(AuthError) def internal_auth_error(error): return jsonify({ 'error': error.error, 'success': False, 'message': error.status_code }), error.status_code return app
def create_app(test_config=None): ''' Create and configure the app. ''' app = Flask(__name__, instance_relative_config=True) setup_db(app) ''' Format the categories to fit JS needs. ''' categories_query = Category.query.all() categories = {} for category in categories_query: cat = {} cat[category.id] = category.type categories.update(cat) ''' @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs Sorry, I don't know how to let 'cors' work. ''' #cors = CORS(app, resources={r"*/api/*": {"origins": "*"}}) @app.after_request def after_request(response): ''' Use the after_request decorator to set Access-Control-Allow ''' response.headers.add('Access-Control-Allow-Headers', 'Content-Type, Authorization, True') response.headers.add('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE, OPTIONS') return response @app.route('/categories', methods=['GET']) def get_categories(): ''' Handle GET requests for all available categories. ''' categories = Category.query.all() if len(categories) == 0: abort(404) formatted_categories = [category.format() for category in categories] return jsonify({'success': True, 'categories': formatted_categories}) @app.route('/questions', methods=['GET', 'POST']) def get_search_qustions(): ''' If the request.method is POST, then get questions based on a search term. Return any questions for whom the search term is a substring of the question. And if the request.method is GET, then get all questions in database, including pagination (every 10 questions). PROBLEM! The pagination is not visable although the curl test is right. Please help. Thanks a lot! ''' if request.method == 'POST': body = request.get_json() if 'searchTerm' in body: search_item = '%' + body['searchTerm'] + '%' selection = Question.query.order_by(Question.id).filter( Question.question.ilike(search_item)).all() current_questions = paginate_questions(request, selection) else: abort(404) else: selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'questions': current_questions, 'totalQuestions': len(selection), 'categories': categories }) @app.route('/questions/<int:question_id>', methods=['DELETE']) def delete_question(question_id): ''' DELETE question using a question ID. TESTED: When click the trash icon next to a question, the question will be removed. This removal will persist in the database and when you refresh the page. ''' question = Question.query.filter( Question.id == question_id).one_or_none() if question == None: abort(404) else: question.delete() return jsonify({ 'success': True, 'deleted': question_id, 'totalQuestions': len(Question.query.all()), }) @app.route('/add', methods=['POST']) def create_new_question(): ''' POST a new question which requires the question and answer text, category, and difficulty score. TESTED: When you submit a question on the "Add" tab, the form will clear and the question will appear at the end of the last page of the questions list in the "List" tab. ''' body = request.get_json() if body.get('question') == '' or body.get('answer') == '': abort(422) new_question = body.get('question', None) new_answer = body.get('answer', None) new_category = int(body.get('category', None)) + 1 new_diffidulty = body.get('difficulty', None) try: question = Question(question=new_question, answer=new_answer, category=new_category, difficulty=new_diffidulty) question.insert() selection = Question.query.order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'created': question.id, 'questions': current_questions, 'total_questions': len(Question.query.all()) }) except: abort(422) @app.route('/categories/<int:category_id>', methods=['GET']) def get_category_qustions(category_id): ''' Get questions based on category. TESTED: In the "List" tab / main screen, clicking on one of the categories in the left column will cause only questions of that category to be shown. ''' page = request.args.get('page', 1, type=int) selection = Question.query.filter( Question.category == category_id).order_by(Question.id).all() current_questions = paginate_questions(request, selection) return jsonify({ 'success': True, 'questions': current_questions, 'page': page, 'totalQuestions': len(selection), 'currentCategory': category_id, }) @app.route('/play', methods=['GET']) def choose_category(): ''' GET requests for all available categories. TEST: In the "Play" tab, display categories, after a user selects "All" or a category, turn to question_quiz form. ''' return jsonify({'success': True, 'categories': categories}) @app.route('/play/getnextquestion', methods=['POST']) def get_next_question(): ''' Display a random question within the given category, if provided, and that is not one of the previous questions. TESTED:One question at a time is displayed, the user is allowed to answer and shown whether they were correct or not. ''' body = request.get_json() previous_questions = body.get('previous_questions', None) get_category_id = body.get('quiz_category', None).get('id', None) category_id = int(get_category_id) if category_id == 0: questions = Question.query.filter( ~Question.id.in_(previous_questions)).all() else: questions = Question.query.filter( Question.category == category_id, ~Question.id.in_(previous_questions)).all() formatted_questions = [question.format() for question in questions] total_remained_questions = len(formatted_questions) if total_remained_questions != 0: random_num = random.randint(0, total_remained_questions - 1) question = formatted_questions[random_num] else: question = None return jsonify({ 'success': True, 'question': question, }) @app.errorhandler(400) def unprocessable(error): return jsonify({ "success": False, "error": 400, "message": "bad request" }), 400 @app.errorhandler(404) def resource_not_found(error): return jsonify({ "success": False, "error": 404, "message": "resource not found" }), 404 @app.errorhandler(405) def unprocessable(error): return jsonify({ "success": False, "error": 405, "message": "method not allowed" }), 405 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "unprocessable" }), 422 @app.errorhandler(500) def unprocessable(error): return jsonify({ "success": False, "error": 500, "message": "internal server error" }), 500 return app
size=company_data.get('size'), remote=company_data.get('allows_remote') ) company.techs = [Tech(name=tech_name) for tech_name in company_data.get('stack', [])] company.location = Location( city=company_data['location'].get('city'), country=company_data['location'].get('country'), postcode=company_data['location'].get('postcode') ) session.add(company) session.commit() if __name__ == "__main__": db_url = 'postgresql://*****:*****@localhost/ourstack' companies_path = '../companies' # allows specifying the db url when calling the script directly if len(sys.argv) > 1: db_url = sys.argv[1] session = setup_db(db_url) for company_data in parse_directory(companies_path): load_company(session, company_data) for instance in session.query(Company): print(instance.name)
def create_app(test_config=None): app = Flask(__name__) setup_db(app) db_drop_and_create_all() CORS(app) @app.after_request def after_request(response): response.headers.add('Access-Control-Allow-Headers', 'Content-Type,Authorization') response.headers.add('Access-Control-Allow-Methods', 'GET,PATCH,POST,DELETE,OPTIONS') return response def paginate_results(request, selection): page = request.args.get('page', 1, type=int) start = (page - 1) * ROWS_PER_PAGE end = start + ROWS_PER_PAGE objects = [object.format for object in selection] return objects[start:end] #----------------------------------------------------------------------------# # Endpoint /actors GET/POST/DELETE/PATCH #----------------------------------------------------------------------------# @app.route('/actors') @requires_auth('read:actors') def get_actors(payload): actors = Actor.query.all() actors_paginated = paginate_results(request, actors) if len(actors_paginated) == 0: abort(404) return jsonify({'success': True, 'actors': actors_paginated}) @app.route('/actors', methods=['POST']) @requires_auth('create:actors') def insert_actors(payload): body = request.get_json() if not body: abort(400) name = body.get('name', None) age = body.get('age', None) gender = body.get('gender', 'Other') if not name or not age: abort(422) new_actor = (Actor(name=name, age=age, gender=gender)) new_actor.insert() return jsonify({'success': True, 'created': new_actor.id}) @app.route('/actors/<actor_id>', methods=['PATCH']) @requires_auth('edit:actors') def edit_actors(payload, actor_id): body = request.get_json() if not actor_id or not body: abort(400) actor_to_update = Actor.query.filter( Actor.id == actor_id).one_or_none() if not actor_to_update: abort(404) name = body.get('name', actor_to_update.name) age = body.get('age', actor_to_update.age) gender = body.get('gender', actor_to_update.gender) actor_to_update.name = name actor_to_update.age = age actor_to_update.gender = gender actor_to_update.update() return jsonify({ 'success': True, 'updated': actor_to_update.id, 'actor': [actor_to_update.format] }) @app.route('/actors/<actor_id>', methods=['DELETE']) @requires_auth('delete:actors') def delete_actors(payload, actor_id): if not actor_id: abort(400) actor_to_delete = Actor.query.filter( Actor.id == actor_id).one_or_none() if not actor_to_delete: abort(404) actor_to_delete.delete() return jsonify({'success': True, 'deleted': actor_id}) #----------------------------------------------------------------------------# # Endpoint /movies GET/POST/DELETE/PATCH #----------------------------------------------------------------------------# @app.route('/movies', methods=['GET']) @requires_auth('read:movies') def get_movies(payload): movies = Movie.query.all() movies_paginated = paginate_results(request, movies) if len(movies_paginated) == 0: abort(404) return jsonify({'success': True, 'movies': movies_paginated}) @app.route('/movies', methods=['POST']) @requires_auth('create:movies') def insert_movies(payload): body = request.get_json() if not body: abort(400) title = body.get('title', None) release_date = body.get('release_date', None) if not title or not release_date: abort(422) new_movie = (Movie(title=title, release_date=release_date)) new_movie.insert() return jsonify({'success': True, 'created': new_movie.id}) @app.route('/movies/<movie_id>', methods=['PATCH']) @requires_auth('edit:movies') def edit_movies(payload, movie_id): body = request.get_json() if not movie_id or not body: abort(400) movie_to_update = Movie.query.filter( Movie.id == movie_id).one_or_none() if not movie_to_update: abort(404) title = body.get('title', movie_to_update.title) release_date = body.get('release_date', movie_to_update.release_date) movie_to_update.title = title movie_to_update.release_date = release_date movie_to_update.update() return jsonify({ 'success': True, 'edited': movie_to_update.id, 'movie': [movie_to_update.format] }) @app.route('/movies/<movie_id>', methods=['DELETE']) @requires_auth('delete:movies') def delete_movies(payload, movie_id): if not movie_id: abort(400) movie_to_delete = Movie.query.filter( Movie.id == movie_id).one_or_none() if not movie_to_delete: abort(404) movie_to_delete.delete() return jsonify({'success': True, 'deleted': movie_id}) #----------------------------------------------------------------------------# # Error Handlers #----------------------------------------------------------------------------# @app.errorhandler(500) def unprocessable(error): return jsonify({ "success": False, "error": 500, "message": "Internal server error" }), 500 @app.errorhandler(422) def unprocessable(error): return jsonify({ "success": False, "error": 422, "message": "Unprocessable entity" }), 422 @app.errorhandler(400) def bad_request(error): return jsonify({ "success": False, "error": 400, "message": "Bad request" }), 400 @app.errorhandler(404) def ressource_not_found(error): return jsonify({ "success": False, "error": 404, "message": "Not found" }), 404 @app.errorhandler(AuthError) def authentification_failed(AuthError): return jsonify({ "success": False, "error": AuthError.status_code, "message": AuthError.error['description'] }), AuthError.status_code return app
def main(): models.setup_db() models.reset_db()
def upsert_content(): from models import setup_db setup_db()