예제 #1
0
    def setUp(self):
        """Define test variables and initialize app."""
        self.app = create_app()
        self.client = self.app.test_client
        self.database_name = "trivia"
        self.database_path = 'postgresql://*****:*****@localhost:5432/{}'.format(
            self.database_name)

        setup_db(self.app, self.database_path)

        # sample question for use in tests
        self.new_question = {
            'question':
            'Which four states make up the 4 Corners region of the US?',
            'answer': 'Colorado, New Mexico, Arizona, Utah',
            'difficulty': 3,
            'category': '3'
        }

        # binds the app to the current context
        with self.app.app_context():
            self.db = SQLAlchemy()
            self.db.init_app(self.app)
            # create all tables
            self.db.create_all()
예제 #2
0
 def setUp(self):
     """Define test variables and initialize app."""
     self.database_name = "trivia_test"
     self.database_path = "postgresql://*****:*****@localhost:54321/trivia_test"
     self.app = create_app({"SQLALCHEMY_DATABASE_URI": self.database_path})
     self.client = self.app.test_client
     self.app_context = self.app.app_context()
     self.app_context.push()
     setup_db(self.app)
     self.db = db
예제 #3
0
    def setUp(self):
        """Define test variables and initialize app."""
        self.database_name = "trivia_test"
        self.app = create_app()
        self.client = self.app.test_client
        self.database_path = "postgresql://{}/{}".format(
            'localhost:5432', self.database_name)
        setup_db(self.app, self.database_path)

        # binds the app to the current context
        with self.app.app_context():
            self.db = SQLAlchemy()
            self.db.init_app(self.app)
            # create all tables
            self.db.create_all()
예제 #4
0
    def setUp(self):
        """
        Setup db.
        :param self:
        """
        self.app = create_app()
        self.client = self.app.test_client

        setup_db(self.app)

        # binds the app to the current context
        with self.app.app_context():
            self.db = SQLAlchemy()
            self.db.init_app(self.app)
            # create all tables
            self.db.create_all()
예제 #5
0
    def setUp(self):
        """Define test variables and initialize app."""
        self.app = create_app()
        self.client = self.app.test_client
        self.token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik56RTBSa1pDTXpZMk5qWTRRelU0T0RFMFJFUTNORVE0TmpFek9FTkdOVFUxTkRZNU9ETkdOdyJ9.eyJpc3MiOiJodHRwczovL2NhcHN0b25lLWF1dGguYXV0aDAuY29tLyIsInN1YiI6ImF1dGgwfDVkY2M0ZTM2YmMyMDQyMGUyODc4ZGJhNyIsImF1ZCI6ImNhcHN0b25lIiwiaWF0IjoxNTc0MjgwNjQ4LCJleHAiOjE1NzQyODc4NDgsImF6cCI6ImlURlROMXJRMWtvNXdTVHkzU1F1ODdQZTBuTVdlS0YzIiwic2NvcGUiOiIiLCJwZXJtaXNzaW9ucyI6WyJhZGQ6YWN0b3IiLCJhZGQ6bW92aWUiLCJjaGFuZ2U6YWN0b3IiLCJjaGFuZ2U6bW92aWUiLCJkZWxldGU6YWN0b3IiLCJkZWxldGU6bW92aWUiLCJyZWFkOmFjdG9ycyIsInJlYWQ6bW92aWVzIl19.IPpiGLmSGr87MkCSRTzteScV6VdZL1tpmQFD_29ApFKXll2MD_nXzp-_Y6apluBauiYApVSNi9XYVo4o6HiiBXWiVuHEZL57EYHufmvGPxieH4pU5vrhIOcMFjIRXwnj5GxyalL_hHmWtBFjRnorkKBhEj_-rRWQ11GoacfqTXSV0fRcbq7ZXt3feZmW6lZ2SFQgarfK_ZIR4bkvHywaUu9381Hq3AgSuRxz6UAQk-hkOUhs2ppQcMapRcS9PWjUv7axJiLnwvAGdytGg0DshmuF2Qy50I_vnnZ_YM2JCllb027eq9vK7TLgJr5Aazt9zJDvk8bHK57OTeA660VtCw"
        self.database_name = "casting"
        self.database_path = "postgres://{}/{}".format(
            'tomaswingord:tomasw87@localhost:5432',
            self.database_name)
        setup_db(self.app, self.database_path)

        # binds the app to the current context
        with self.app.app_context():
            self.db = SQLAlchemy()
            self.db.init_app(self.app)
            # create all tables
            self.db.create_all()
예제 #6
0
파일: __init__.py 프로젝트: jackthias/FSND
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,PATCH')
        return response

    @app.route('/categories', methods=['GET'])
    def get_categories():
        selection = Category.query.order_by(Category.id).all()
        return jsonify({
            "categories": format_categories(selection),
            "success": True
        })

    @app.route('/questions', methods=['GET'])
    def get_questions():
        if len(search_term := request.args.get('search', '')) > 0:
            return search_questions(search_term)
        all_questions = Question.query.order_by(Question.id).all()
        current_questions = paginate_questions(request, all_questions)

        if len(current_questions) == 0:
            abort(404)

        return jsonify({
            'total_questions':
            len(all_questions),
            'questions':
            current_questions,
            'categories':
            format_categories(Category.query.order_by(Category.id).all()),
            # 'current_category': Category.query.all()[0].format(),
            'success':
            True
        })
예제 #7
0
 def setUp(self):
     """Define test variables and initialize app."""
     self.app = create_app()
     self.client = self.app.test_client
     self.database_name = "trivia_test"
     self.database_path = "postgres://{}/{}".format('localhost:5432',
                                                    self.database_name)
     setup_db(self.app, self.database_path)
     self.question = {
         "question": "Whats the name of California's capitol",
         "answer": "Sacramento",
         "difficulty": 1,
         'category': 2
     }
     # binds the app to the current context
     with self.app.app_context():
         self.db = SQLAlchemy()
         self.db.init_app(self.app)
         # create all tables
         self.db.create_all()
예제 #8
0
    def setUp(self):
        """Define test variables and initialize app."""
        self.app = create_app()
        self.client = self.app.test_client
        self.database_name = "trivia_test"
        self.database_path = "postgres://{}/{}".format('localhost:5432', self.database_name)
        setup_db(self.app, self.database_path)

        self.new_question = {
            'category': '1',
            'question': 'Neil Gaiman',
            'answer': 'aaaaaaa',
            'difficulty': 5
        }
        self.new_category = {
            'id': '1',
            'type': 'test_type',
        }
        # binds the app to the current context
        with self.app.app_context():
            self.db = SQLAlchemy(self.app)
            self.db.init_app(self.app)
            self.db.create_all()


            # # create all tables

            # create all tables
            self.question = Question(difficulty=self.new_question['difficulty'],
                                     question=self.new_question['question'],
                                     answer=self.new_question['answer'], category=self.new_question['category'])
            self.question.insert()

            if Category.query.first() is None:
                category = Category(type=self.new_category['type'])
                category.insert()
예제 #9
0
import sys
from sqlalchemy import exc
# from flask import Flask, request, jsonify, abort
from flask import (Flask, request, jsonify, abort)
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS

from backend.auth import AuthError, requires_auth
# from backend.models import db_drop_and_create_all,
# setup_db, migrate_db, Movie, Actor, Cast
from backend.models import (db_drop_and_create_all, setup_db, migrate_db,
                            Movie, Actor, Cast)

# def create_app(test_config=None):
app = Flask(__name__)
setup_db(app)
CORS(app)

db_drop_and_create_all()


@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('/')
예제 #10
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)
    CORS(app)  # CORS by default allows '*' for all origins.

    @app.errorhandler(400)
    def bad_request(*args):
        return jsonify({
            'success': False,
            'error': 400,
            'message': 'Bad request'
        }), 400

    @app.errorhandler(404)
    def not_found(*args):
        return jsonify({
            'success': False,
            'error': 404,
            'message': 'Not found'
        }), 404

    @app.errorhandler(405)
    def method_not_allowed(*args):
        return jsonify({
            'success': False,
            'error': 405,
            'message': 'Method not allowed'
        }), 405

    @app.errorhandler(422)
    def unprocessable_entity(*args):
        return jsonify({
            'success': False,
            'error': 422,
            'message': 'Unprocessable entity'
        }), 422

    @app.errorhandler(500)
    def internal_server_error(*args):
        return jsonify({
            'success': False,
            'error': 500,
            'message': 'Internal server error'
        }), 500

    @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, PATCH, DELETE, OPTIONS')
        return response

    @app.route('/categories')
    def get_categories():
        try:
            categories = Category.query.order_by(Category.id).all()
            return jsonify({
                'success': True,
                'categories':
                {category.id: category.type
                 for category in categories}
            })
        except:
            abort(500)

    @app.route('/questions')
    def get_questions():
        try:
            page = request.args.get('page', 1, type=int)
            questions = Question.query.order_by(Question.id).all()
            start = (page - 1) * QUESTIONS_PER_PAGE
            end = start + QUESTIONS_PER_PAGE
            questions_list = [question.format()
                              for question in questions][start:end]
            if not questions_list:
                abort(400)
            categories = {
                category.id: category.type
                for category in Category.query.order_by(Category.id).all()
            }
            return jsonify({
                'success': True,
                'questions': questions_list,
                'total_questions': len(questions),
                'categories': categories,
                'current_category': "Science"
                # Since the front end doesn't tell us what category it's on in this request,
            })  # we default to Science.
        except:
            abort(400)

    @app.route('/questions/<question_id>', methods=['DELETE'])
    def delete_question(question_id):
        question = Question.query.filter(
            Question.id == question_id).one_or_none()
        if question:
            question.delete()
            return jsonify({'success': True})
        else:
            abort(404)

    @app.route('/questions', methods=['POST'])
    def create_question():
        try:
            data = json.loads(request.data)
            if 'searchTerm' not in data.keys():
                question = data['question']
                answer = data['answer']
                difficulty = data['difficulty']
                category = data['category']
                if not (question and answer and difficulty and category):
                    abort(400)
                new_question = Question(question, answer, category, difficulty)
                new_question.insert()
                return jsonify({
                    'success': True,
                })
            elif 'searchTerm' in data.keys():
                search_term = data['searchTerm']
                questions = Question.query.filter(
                    Question.question.ilike(f'%{search_term}%')).all()
                return jsonify({
                    'success':
                    True,
                    'questions': [question.format() for question in questions]
                })
        except:
            abort(422)

    @app.route('/categories/<category_id>/questions')
    def get_questions_by_category(category_id):
        category = Category.query.filter(
            Category.id == category_id).one_or_none()
        if not category:
            abort(404)

        questions = Question.query.filter(
            Question.category == category.id).all()
        return jsonify({
            'success':
            True,
            'total_questions':
            len(questions),
            'current_category':
            category.type,
            'questions': [question.format() for question in questions]
        })

    @app.route('/quizzes', methods=['POST'])
    def create_quiz():
        data = json.loads(request.data)
        previous_questions = data[
            'previous_questions']  # will have ids of questions
        quiz_category_id = data['quiz_category']['id']
        questions = Question.query.filter(
            Question.category == quiz_category_id).all()
        unseen_questions = [
            question.format() for question in questions
            if question.id not in previous_questions
        ]
        print('unseen questions are: ', unseen_questions)
        return jsonify({
            'success':
            True,
            'question':
            random.choice(unseen_questions) if unseen_questions else False
        })

    return app
예제 #11
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)
    CORS(app)

    db = SQLAlchemy(app)
    migrate = Migrate(app, db)  # this

    # GET /actors and /movies --> DONE
    @app.route('/actors', methods=['GET'])
    @requires_auth(permission='read:actors')
    def get_actors(payload):
        all_actors = actors.query.all()
        results = []
        for actor in all_actors:
            one_actor = {}
            one_actor["id"] = actor.id
            one_actor["name"] = actor.name
            one_actor["age"] = actor.age
            one_actor["gender"] = actor.gender
            results.append(one_actor)
        if not results:
            abort(404)
        return jsonify({"success": True, "Actors": results})

    @app.route('/movies', methods=['GET'])
    @requires_auth(permission='read:movies')
    def get_movies(payload):
        all_movies = movies.query.all()
        results = []
        for movie in all_movies:
            one_movie = {}
            one_movie["id"] = movie.id
            one_movie["title"] = movie.title
            one_movie["release_date"] = movie.release_date
            results.append(one_movie)
        if not results:
            abort(404)
        return jsonify({"success": True, "Movies": results})

    # DELETE / actors / and / movies/
    @app.route('/actors/<int:id>', methods=['DELETE'])
    @requires_auth(permission='delete:actor')
    def delete_actor(payload, id):
        actor = actors.query.get(id)
        if not actor:
            abort(404)
        try:
            actor.delete()
        except Exception:
            abort(401)
        return jsonify({"success": True, "Deleted": id})

    @app.route('/movies/<int:id>', methods=['DELETE'])
    @requires_auth(permission='delete:movie')
    def delete_movie(payload, id):
        movie = movies.query.get(id)
        if not movie:
            abort(404)
        try:
            movie.delete()
        except Exception:
            abort(401)
        return jsonify({"success": True, "Deleted": id})

    # POST / actors and / movies and
    @app.route('/actors', methods=['POST'])
    @requires_auth(permission='add:actor')
    def post_actor(payload):
        data = request.get_json()
        if not data:
            abort(400)

        new_name = data.get("name")
        new_age = data.get("age")
        new_gender = data.get("gender")

        if not new_name or not new_age or not new_gender:
            abort(400)

        # Create a new actor
        new_actor = actors(name=new_name, age=new_age, gender=new_gender)
        try:
            new_actor.insert()
        except Exception:
            abort(401)

        # Query for new actor
        new_actor_id = new_actor.id
        new_actors = actors.query.get(new_actor_id)
        one_actor = {}
        one_actor["id"] = new_actors.id
        one_actor["name"] = new_actors.name
        one_actor["age"] = new_actors.age
        one_actor["gender"] = new_actors.gender

        return jsonify({"success": True, "Actor": one_actor})

    @app.route('/movies', methods=['POST'])
    @requires_auth(permission='add:movie')
    def post_movie(payload):
        data = request.get_json()
        if not data:
            abort(400)
        new_title = data.get("title")
        new_release_date = data.get("release_date")
        if not new_title or not new_release_date:
            abort(400)
        # Create a new movie
        new_movie = movies(title=new_title, release_date=new_release_date)
        try:
            new_movie.insert()
        except Exception:
            abort(401)
        # Query for new actor
        new_movie_id = new_movie.id
        new_movies = movies.query.get(new_movie_id)
        one_movie = {}
        one_movie["id"] = new_movies.id
        one_movie["title"] = new_movies.title
        one_movie["release_date"] = new_movies.release_date
        return jsonify({"success": True, "Movie": one_movie})

    # PATCH / actors / and / movies/
    @app.route('/actors/<int:id>', methods=['PATCH'])
    @requires_auth(permission='change:actor')
    def patch_actor(payload, id):
        # Get actor to patch
        new_actor = actors.query.get(id)
        if not new_actor:
            abort(404)
        # Check what values are available to patch
        data = request.get_json()
        if 'name' in data:
            new_actor.name = data.get("name")
        if 'age' in data:
            new_actor.age = data.get("age")
        if 'gender' in data:
            new_actor.gender = data.get("gender")
        try:
            new_actor.update()
        except Exception:
            abort(401)
        patched_actor = actors.query.get(new_actor.id)
        one_actor = {}
        one_actor["id"] = patched_actor.id
        one_actor["name"] = patched_actor.name
        one_actor["age"] = patched_actor.age
        one_actor["gender"] = patched_actor.gender
        return jsonify({"success": True, "Actor": one_actor})

    @app.route('/movies/<int:id>', methods=['PATCH'])
    @requires_auth(permission='change:movie')
    def patch_movie(payload, id):
        # Get actor to patch
        new_movie = movies.query.get(id)
        if not new_movie:
            abort(404)
        # Check what values are available to patch
        data = request.get_json()
        if 'title' in data:
            new_movie.title = data.get("title")
        if 'release_date' in data:
            new_movie.release_date = data.get("release_date")
        try:
            new_movie.update()
        except Exception:
            abort(401)
        patched_movie = movies.query.get(new_movie.id)
        one_movie = {}
        one_movie["id"] = new_movie.id
        one_movie["title"] = new_movie.title
        one_movie["release_date"] = new_movie.release_date
        return jsonify({"success": True, "Movie": one_movie})

    # @TODO: Create error handlers for all expected errors \
    #  including 404 and 422. --> DONE

    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            "success": False,
            "error": 404,
            "message": "Not found"
        }), 404

    @app.errorhandler(401)
    def unauthorized(error):
        return jsonify({
            "success": False,
            "error": 401,
            "message": "Unauthorized"
        }), 401

    @app.errorhandler(422)
    def unprocessable(error):
        return jsonify({
            "success": False,
            "error": 422,
            "message": "Unprocessable Entity"
        }), 422

    @app.errorhandler(405)
    def method_not_allowed(error):
        return jsonify({
            "success": False,
            "error": 405,
            "message": "Method not allowed"
        }), 405

    @app.errorhandler(400)
    def bad_request(error):
        return jsonify({
            "success": False,
            "error": 400,
            "message": "Bad Request error"
        }), 400

    @app.errorhandler(500)
    def internal_server_error(error):
        return jsonify({
            "success": False,
            "error": 500,
            "message": "Internal server error"
        }), 500

    return app
예제 #12
0
파일: app.py 프로젝트: AlexPapas/TriviaAPI
def create_app(test_config=None):
    app = Flask(__name__)
    setup_db(app)
    CORS(app)
    """
    @TODO: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs
    # """
    cors = CORS(app)
    app.config["CORS_HEADERS"] = "Content-Type"
    """
    @TODO: 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,PATCH,POST,DELETE,OPTIONS")
        return response

    """
    @TODO: 
    Create an endpoint to handle GET requests 
    for all available categories.
    """

    @app.route("/categories")
    def get_categories():
        categories = db.session.query(Category).all()
        categories_dict = [cat.format() for cat in categories]

        if len(categories) == 0:
            abort(404)

        return jsonify({"success": True, "categories": categories_dict})

    #   """
    #   @TODO- 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.
    @app.route("/questions")
    def get_paginated_questions():
        # selection = Question.query.order_by(Question.id).all()
        selection = Question.query.all()
        questions = paginate_questions(request, selection)

        categories = db.session.query(Category).all()
        # categories = Category.query.all()
        categories_dict = {cat.id: cat.type for cat in categories}

        if len(questions) == 0:
            abort(404)

        return jsonify({
            "success": True,
            "categories": categories_dict,
            "questions": questions,
            "total_questions": len(questions),
            "current_category": None,
        })

    #   """
    # @TODO:
    # Create an endpoint to DELETE question using a question ID.

    @app.route("/questions/<int:id>", methods=["GET", "DELETE"])
    def delete_question(id):
        # might page be out of index
        try:
            question = Question.query.get(id)
        except:
            abort(404)
        question.delete()

        return jsonify({"success": True, "deleted_id": 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("/add", methods=["POST"])
    def add_question():

        body = request.get_json()
        if not all([len(str(value)) > 0 for value in body.values()]):
            abort(422)

        question = Question(
            question=body.get("question"),
            answer=body["answer"],
            category=body["category"],
            difficulty=body["difficulty"],
        )
        try:
            question.insert()
            questions = Question.query.all()
            print("question was added")
            current_questions = paginate_questions(request, questions)

            print(len(questions))
            return jsonify({
                "success": True,
                "created": question.id,
                "questions": current_questions,
            })
        except:
            abort(404)

        #   """

    # @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.
    #   """

    # -- Error Handling --
    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            "success": False,
            "error": 404,
            "message": "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,
        )

    return app
예제 #13
0
def create_app(test_config=None):
    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,PATCH,POST,DELETE,OPTIONS')
        return response

# --------------------------------------- GET CATEGORIES ------------------------------------------------------------- #

    @app.route("/categories")
    def get_categories():
        try:
            categories = Category.query.all()
            categories_dict = {
                category.id: category.type
                for category in categories
            }

            if len(categories) == 0:
                abort(404)

            return jsonify(
                {
                    "success": True,
                    "categories": categories_dict,
                    "total_categories": len(categories),
                }, 200)
        except:
            abort(500)

# ------------------------------------------ GET QUESTIONS ----------------------------------------------------------- #

    @app.route("/questions")
    def get_questions():
        try:
            selection = Question.query.order_by(Question.id).all()
            current_questions = paginate_questions(request, selection)

            if len(current_questions) == 0:
                abort(404)

            categories = Category.query.all()
            categories_dict = {
                category.id: category.type
                for category in categories
            }

            return jsonify(
                {
                    "success": True,
                    "questions": current_questions,
                    "total_questions": len(selection),
                    "current_category": None,
                    "categories": categories_dict,
                }, 200)
        except:
            abort(500)

# --------------------------------------- DELETE QUESTION ------------------------------------------------------------ #

    @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(422)

            question.delete()

            return jsonify(
                {
                    "success": True,
                    "deleted": question_id,
                    "total_questions": len(Question.query.all()),
                }, 200)
        except:
            abort(500)

# ------------------------------------------ ADD QUESTIONS ----------------------------------------------------------- #

    @app.route("/questions", methods=["POST"])
    def add_questions():
        body = request.get_json()

        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 (new_question is None) or (new_answer is None) or (
                new_category is None) or (new_difficulty is None):
            abort(422)

        try:
            add_question = Question(question=new_question,
                                    answer=new_answer,
                                    category=new_category,
                                    difficulty=new_difficulty)

            add_question.insert()

            return jsonify(
                {
                    "success": True,
                    "created": add_question.id,
                    "total_questions": len(Question.query.all()),
                }, 200)
        except:
            abort(500)

# --------------------------------------- SEARCH QUESTIONS ----------------------------------------------------------- #

    @app.route("/questions/search", methods=["POST"])
    def search_questions():
        body = request.get_json()
        search = body.get("search_term", None)

        if not search:
            abort(400)

        try:
            search_results = Question.query.filter(
                Question.question.ilike("%{}%".format(search))).all()

            return jsonify(
                {
                    "success":
                    True,
                    "questions":
                    [questions.format() for questions in search_results],
                    "total_questions":
                    len(search_results),
                }, 200)
        except:
            abort(422)

# ------------------------------------ CATEGORIES FOR EACH QUESTION -------------------------------------------------- #

    @app.route("/categories/<int:category_id>/questions")
    def get_category_questions(category_id):
        try:
            selection = Question.query.filter(
                Question.category == category_id).all()
            questions = paginate_questions(request, selection)

            categories = Category.query.order_by(Category.type).all()

            if len(questions) == 0:
                abort(404)

            return jsonify(
                {
                    "success": True,
                    "questions": questions,
                    "total_questions": len(Question.query.all()),
                    "current_category": category_id,
                    "categories":
                    [category.format() for category in categories],
                }, 200)
        except:
            abort(500)

# --------------------------------------------- Play Quiz ------------------------------------------------------------ #

    @app.route("/quizzes", methods=["POST"])
    def play_quiz():
        body = request.get_json()
        try:
            category = body.get("quiz_category", None)
            previous_questions = body.get("previous_questions", None)

            if (category is None) or (previous_questions is None):
                abort(400)

            if category["id"] == 0:
                available_questions = Question.query.filter(
                    Question.id.notin_((previous_questions))).all()
            else:
                available_questions = Question.query.filter_by(
                    category=category["id"]).filter(
                        Question.id.notin_(previous_questions)).all()

            if len(available_questions) > 0:
                new_question = available_questions[random.randrange(
                    0, len(available_questions))].format()
            else:
                new_question = None

            return jsonify({
                "success": True,
                "question": new_question,
            }, 200)
        except:
            abort(500)
# --------------------------------------------- Error Handlers ------------------------------------------------------- #

    @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 Entity"
        }), 422

    @app.errorhandler(405)
    def bad_request(error):
        return jsonify({
            "success": False,
            "error": 405,
            "message": "Method Not Allowed"
        }), 405

    @app.errorhandler(500)
    def bad_request(error):
        return jsonify({
            "success": False,
            "error": 500,
            "message": "Internal Server Error"
        }), 500

    return app
예제 #14
0
def create_app(test_config=None):  # noqa
    # create and configure the app
    app = Flask(__name__)

    if test_config is None:
        # load the instance config, if it exists, when not testing
        app.config.from_pyfile(Path(__name__).absolute().parent / "config.py")
        setup_db(app)
    else:
        # load the test config if passed in
        app.config.from_mapping(test_config)

    cors = CORS(app, resources={r"/*": {"origins": "*"}})  # noqa

    @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, PATCH, DELETE, OPTIONS")
        return response

    @app.route("/")
    def hello():
        return jsonify(dict(r, message="hello world"))

    @app.route("/categories")
    def get_categories():
        data = Category.query.all()
        return jsonify(dict(r, categories=[cat.format() for cat in data]))

    @app.route("/questions")
    def get_questions():
        q = Question.query
        paged = q.paginate(
            per_page=QUESTIONS_PER_PAGE,
            error_out=True,
            max_per_page=QUESTIONS_PER_PAGE,
        )
        try:
            return jsonify(
                dict(
                    r,
                    categories=[cat.format() for cat in Category.query.all()],
                    total_questions=q.count(),
                    questions=[quest.format() for quest in paged.items],
                    current_category="All",
                ))
        except AttributeError:
            abort(404)

    """
    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/<int:id>", methods=["DELETE"])
    def delete_question(id):
        try:
            question_to_delete = Question.query.get(id)
            question_to_delete.delete()
            return jsonify(
                dict(r, message=f"successfully deleted question with id {id}"))
        except AttributeError:
            abort(404)

    """
    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", methods=["POST"])
    def post_question():
        question = Question(
            question=request.json.get("question"),
            answer=request.json.get("answer"),
            difficulty=request.json.get("difficulty"),
            category=request.json.get("category"),
        )
        question.insert()
        return jsonify(
            dict(
                r,
                message="Successfully added question to database",
                data=question.format(),
            ))

    """
    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/search", methods=["POST"])
    def search_question():
        search_term = request.json.get("searchTerm")
        results = Question.query.filter(
            Question.question.ilike(f"%{search_term}%"))
        return jsonify(
            dict(
                r,
                message="Successfully added question to database",
                questions=[question.format() for question in results.all()],
                total_questions=results.count(),
                current_category="All",
            ))

    """
    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("/categories/<int:id>/questions")
    def category_questions(id):
        q = Question.query
        if id != 0:
            q = q.filter_by(category=str(id))
        paged = q.paginate(
            per_page=QUESTIONS_PER_PAGE,
            error_out=True,
            max_per_page=QUESTIONS_PER_PAGE,
        )
        try:
            category = Category.query.get(id)
            return jsonify(
                dict(
                    r,
                    message=
                    f"Successfully fetched all questions with category id={id}",
                    questions=[quest.format() for quest in paged.items],
                    total_questions=q.count(),
                    current_category=category.format()["type"]
                    if category else "All",
                ))
        except AttributeError:
            abort(404)

    """
    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("/quizzes/<int:id>", methods=["POST"])
    def quiz_questions(id):
        r_json = request.json
        previous_questions = r_json.get("previous_questions")
        cat_questions = category_questions(id).json.get("questions")
        eligible_qs = [
            q for q in cat_questions if q["id"] not in previous_questions
        ]
        question = None
        if eligible_qs:
            question = random.sample(eligible_qs, k=1)[0]
        return jsonify(dict(r, question=question))

    """
    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.errorhandler(400)
    def not_understood(error):
        return (
            jsonify(
                dict(
                    success=False,
                    status_code=400,
                    message=
                    "The request could not be understood by the server due to malformed syntax",
                )),
            400,
        )

    @app.errorhandler(404)
    def not_found(error):
        return (
            jsonify(
                dict(
                    success=False,
                    status_code=404,
                    message="The record you requested was not found",
                )),
            404,
        )

    @app.errorhandler(422)
    def not_processable(error):
        return (
            jsonify(
                dict(
                    success=False,
                    status_code=422,
                    message="Your request is not processable",
                )),
            422,
        )

    @app.errorhandler(500)
    def server_error(error):
        return (
            jsonify(
                dict(
                    success=False,
                    status_code=500,
                    message="The server encountered an unexpected condition "
                    "which prevented it from fulfilling the request",
                )),
            500,
        )

    return app
예제 #15
0
def create_app(test_env: str = None):
    """
    create and configure the app
    @type test_env: str relative path for .env or .env.test from __init__.py
    """

    app = Flask(__name__)
    if test_env is None:
        # load the instance config, from app settings environment variable if not testing
        app.config.from_envvar('APP_SETTINGS')
    else:
        # load the test env file if passed in
        app.config.from_pyfile(test_env)

    # making sure .env file is loaded for db and other modules
    env_path = Path(flaskr_dir_path, test_env or '.env').absolute()
    load_dotenv(env_path)

    db = setup_db(app, {'name': os.getenv('DB_NAME')})

    Migrate(
        app,
        db,
        # to make sure migrations inside backend folder
        directory=Path(flaskr_dir_path.parent, 'migrations').absolute())

    # @DONE: Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs
    cors = CORS(app, resources={
        r"^/api/*": {
            'origin': '*'
        },
    })

    # @DONE: Use the after_request decorator to set Access-Control-Allow
    @app.after_request
    def after_request(response: Response):
        if match(r'^/api/*', request.path
                 ):  # to make sure it's only allowed for api endpoints
            response.headers.add('Access-Control-Allow-Headers',
                                 'Content-Type')
            response.headers.add('Access-Control-Allow-Methods',
                                 'GET, POST, PATCH, DELETE')
        return response

    @app.route('/api/categories')
    def get_all_categories():
        """
        @DONE:
        Create an endpoint to handle GET requests
        for all available categories.
        """
        categories = Category.query.all()

        res = {'categories': {c.id: c.type for c in categories}}

        return jsonify(res)

    @app.route('/api/questions')
    def get_questions():
        """
        @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.
        """

        questions = Question.query.paginate(per_page=QUESTIONS_PER_PAGE)
        categories = Category.query.all()

        data = {
            'questions': [q.format() for q in questions.items],
            'total_questions': questions.total,
            'categories': {c.id: c.type
                           for c in categories},
            'current_category': None,
        }

        return jsonify(data)

    @app.route('/api/questions/<question_id>', methods=['DELETE'])
    def delete_question(question_id):
        """
        @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.
        """

        question = Question.query.get_or_404(question_id)
        try:
            db.session.delete(question)
            db.session.commit()
        except SQLAlchemyError:
            db.session.rollback()
            db.session.close()
            raise InternalServerError

        return '', 204

    @app.route('/api/questions', methods=['POST'])
    def add_question():
        """
        @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.
        """

        data: dict = request.get_json()

        question = data.get('question')
        answer = data.get('answer')
        category = data.get('category')
        difficulty = int(data.get('difficulty', 0))

        # Simple validation
        all_values_exist = all([question, answer, category, difficulty])
        category_exist = db.session.query(
            Category.query.filter_by(id=category).exists()).scalar()
        difficulty_in_range = 1 <= difficulty <= 5

        if not all([all_values_exist, category_exist, difficulty_in_range]):
            message = ""
            if not all_values_exist:
                message = "There is an empty required field. "
            if not category_exist:
                message += "Category doesn't exist. "
            if not difficulty_in_range:
                message += "Difficulty range is between 1 to 5."
            return jsonify({'message': message}), 422

        question_model = Question(question=question,
                                  answer=answer,
                                  category_id=category,
                                  difficulty=difficulty)

        try:
            db.session.add(question_model)
            db.session.commit()
            _id = question_model.id
        except SQLAlchemyError:
            db.session.rollback()
            db.session.close()
            raise InternalServerError

        return jsonify({
            'id': _id,
        }), 201

    @app.route('/api/questions/search', methods=['POST'])
    def search_question():
        """
        @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.
        """
        data = request.get_json()
        q = data.get('q') or ''
        questions = Question.query.filter(
            Question.question.ilike(f"%{q}%")).paginate(
                page=data.get('page') or 1, per_page=QUESTIONS_PER_PAGE)

        data = {
            'questions': [q.format() for q in questions.items],
            'total_questions': questions.total,
            'current_category': None,
        }

        return jsonify(data)

    @app.route('/api/categories/<category_id>/questions')
    def get_questions_by_category(category_id):
        """
        @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.
        """
        category: Category = Category.query.get_or_404(category_id)
        questions = Question.query.filter_by(category_id=category_id).paginate(
            per_page=QUESTIONS_PER_PAGE)
        data = {
            'questions': [q.format() for q in questions.items],
            'total_questions': questions.total,
            'current_category': category_id
        }

        return jsonify(data)

    @app.route('/api/quizzes', methods=['POST'])
    def quizzes_handler():
        """
        @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.
        """
        data: dict = request.get_json()

        quiz_category = data.get('quiz_category')
        previous_questions = data.get('previous_questions') or []

        questions = Question.query
        if quiz_category:
            questions = questions.filter_by(category_id=quiz_category)
        question = questions.filter(
            Question.id.notin_(previous_questions)).order_by(
                func.random()).first()

        data = {'question': question.format() if question else None}

        return jsonify(data)

    '''
    @DONE: 
    Create error handlers for all expected errors 
    including 404 and 422. 
    '''

    # There is no need for this one for me
    @app.errorhandler(400)
    def handle_400(error):
        return jsonify({
            "message": "Bad Request.",
        }), 400

    @app.errorhandler(404)
    def handle_404(error):
        return jsonify({
            "message": "Not found.",
        }), 404

    # There is no need for this one for me
    @app.errorhandler(422)
    def handle_422(error):
        return jsonify({
            "message": "Unprocessable Entity.",
        }), 422

    @app.errorhandler(500)
    def handle_500(error):
        return jsonify({
            "message": "Internal Server Error.",
        }), 500

    return app
예제 #16
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)

    # Set up CORS. Allow '*' for origins.
    CORS(app, resources={r"/api/*": {"origins": "*"}})

    # Use the after_request decorator to set Access-Control-Allow
    @app.after_request
    def after_request(response):
        response.headers.add('Access-Control-Allow-Methods',
                             'GET,PUT,POST,DELETE,OPTIONS')
        response.headers.add('Access-Control-Allow-Headers',
                             'Content-Type,Authorization,true')
        return response

    def paginate_questions(request, selection):
        page = request.args.get('page', 1, type=int)
        start = (page - 1) * QUESTIONS_PER_PAGE
        end = start + QUESTIONS_PER_PAGE

        items = [item.format() for item in selection]
        current_items = items[start:end]

        return current_items

    @app.route('/categories', methods=['GET'])
    def get_categories():
        selection = Category.query.all()
        categories = [category.format() for category in selection]

        if len(categories) == 0:
            abort(404)

        return jsonify({
            'categories': categories,
        }), 200

    @app.route('/questions', methods=['GET'])
    def get_questions():
        selection = Question.query.order_by(Question.id).all()

        questions = paginate_questions(request, selection)
        current_category = [question['category'] for question in questions]
        current_category = list(set(current_category))
        categories = [cat.format() for cat in Category.query.all()]

        if len(questions) == 0:
            abort(404)

        return jsonify({
            'questions': questions,
            'total_questions': len(selection),
            'categories': categories,
            'current_category': current_category,
        }), 200

    @app.route('/questions/<int:question_id>', methods=['DELETE'])
    def delete_question(question_id):
        try:
            question = Question.query.get(question_id)

            if not question:
                abort(404)

            question.delete()

            return jsonify({
                'success': True,
                'deleted': question_id,
            }), 200

        except Exception as e:
            abort(404)

    @app.route('/questions', methods=['POST'])
    def add_question():

        try:
            data = request.json
            to_add = Question(data['question'], data['answer'],
                              data['category'], data['difficulty'])
            to_add.insert()

            return jsonify({'success': True}), 200
        except Exception as e:
            abort(422)

    @app.route('/questions/search', methods=['POST'])
    def search_questions():
        try:
            search_term = request.json['searchTerm']

            selection = Question.query.filter(
                Question.question.ilike('%' + search_term + '%')).all()

            search_results = paginate_questions(request, selection)

            return jsonify({
                'success': True,
                'questions': search_results,
                'total_questions': len(search_results),
                'current_category': None
            }), 200
        except Exception as e:
            abort(404)

    @app.route('/categories/<int:category_id>/questions', methods=['GET'])
    def get_questions_by_category(category_id):
        selection = Question.query.filter_by(category=category_id).all()
        questions = paginate_questions(request, selection)

        if len(questions) == 0:
            abort(404)

        return jsonify({
            'questions': questions,
            'total_questions': len(selection),
            'current_category': category_id,
        })

    @app.route("/quizzes", methods=['POST'])
    def quizzes():
        previous_questions = request.json.get('previous_questions')
        quiz_category = request.json.get('quiz_category')

        if previous_questions is None or quiz_category is None:
            abort(404)

        if quiz_category['id'] == 0:  # all categories
            questions_by_category = Question.query. \
                filter(Question.id.notin_(previous_questions)). \
                all()

        else:  # specific category
            questions_by_category = Question.query. \
                filter_by(category=quiz_category['id']). \
                filter(Question.id.notin_(previous_questions)). \
                all()

        if questions_by_category:
            formatted_questions = \
                [question.format() for question in questions_by_category]
            return jsonify({'question': formatted_questions[0]}), 200
        else:
            return jsonify({'question': False}), 200

    @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
예제 #17
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)

    app.config['SECRET_KEY'] = 'dev'
    app.config['CORS_HEADERS'] = 'Content-Type'
    '''
  Set up CORS. Allow '*' for origins.
  '''
    CORS(app, resources={r"/.*": {"origins": "*"}})
    '''
  Use the after_request decorator to set Access-Control-Allow 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, PUT, PATCH, DELETE, OPTIONS')

        return response

    '''
  Endpoint to GET all available categories.
  '''

    @app.route("/categories")
    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}
        })

    '''
  Endpoint to handle GET requests for questions, 
  including pagination (every 10 questions). 
  This endpoint will return a list of questions, 
  number of total questions, current category, categories. 
  '''

    @app.route('/questions')
    def retrieve_questions():

        questions = Question.query.order_by(Question.id).all()
        current_questions = paginate_questions(request, questions)

        categories = Category.query.order_by(Category.id).all()

        if len(current_questions) == 0:
            abort(404)

        return jsonify({
            "success": True,
            "questions": current_questions,
            "total_questions": len(questions),
            "categories":
            {category.id: category.type
             for category in categories},
            "currentCategory": None
        })

    '''
  Endpoint to DELETE question using a question ID. 
  '''

    @app.route("/questions/<int:question_id>", methods=["DELETE"])
    def delete_question(question_id):

        try:
            question_obj = Question.query.filter(
                Question.id == question_id).one()
            print(question_obj.format())
            question_obj.delete()

            return jsonify({"success": True, "deleted": question_id})
        except:
            abort(422)

    '''
  Endpoint to POST a new question, 
  which will require the question and answer text, 
  category, and difficulty level.
  '''

    @app.route("/questions", methods=["POST"])
    def add_question():

        body = request.get_json()

        if not ('question' in body and 'answer' in body and 'category' in body
                and 'difficulty' in body):
            abort(422)

        question_val = body.get('question')
        answer_val = body.get('answer')
        category_val = body.get('category')
        difficulty_val = body.get('difficulty')

        try:

            question_obj = Question(question_val, answer_val, category_val,
                                    difficulty_val)
            question_obj.insert()

            questions = Question.query.order_by(Question.id).all()
            current_questions = paginate_questions(request, questions)

            return jsonify({
                "success": True,
                "created": question_obj.id,
                "questions": current_questions,
                "total_questions": len(questions)
            })
        except:
            question_obj.rollback()
            abort(422)

    ''' 
  Endpoint to get questions based on a search term sent using POST body. 
  It returns one/more questions that matches the substring of the question.
  '''

    @app.route("/questions/search", methods=["POST"])
    def search_questions():

        body = request.get_json()
        search_term = body.get('searchTerm')

        if search_term:

            questions_obj = Question.query.filter(
                Question.question.ilike("%" + search_term + "%")).all()

            if not questions_obj:
                abort(404)

            current_questions = paginate_questions(request, questions_obj)

            return jsonify({
                "success": True,
                "questions": current_questions,
                "total_questions": len(questions_obj),
                "current_category": None
            })
        else:
            abort(404)

    '''
  GET endpoint to get questions based on category. 
  '''

    @app.route("/categories/<int:category_id>/questions", methods=["GET"])
    def retrieve_questions_by_category(category_id):

        try:

            category_ids = [
                cat.id for cat in Category.query.with_entities(
                    Category.id, Category.type).order_by(Category.id).all()
            ]

            if category_id not in category_ids:
                abort(404)

            questions_obj = Question.query.filter(
                Question.category == str(category_id)).all()
            current_questions = paginate_questions(request, questions_obj)

            return jsonify({
                "success": True,
                "questions": current_questions,
                "total_questions": len(questions_obj),
                "currentCategory": category_id
            })
        except:
            abort(404)

    '''
  POST endpoint to get questions to play the quiz. 
  This endpoint takes category and previous question parameters 
  and returns a random question within the given category, 
  if provided, and that is not one of the previous questions. 
  '''

    @app.route("/quizzes", methods=["POST"])
    def play_quiz():

        try:

            body = request.get_json()

            if not ('previous_questions' in body and 'quiz_category' in body):
                abort(422)

            previous_questions = body.get('previous_questions')
            quiz_category = body.get('quiz_category')

            if quiz_category['type'] == 'click':
                available_questions = Question.query.filter(
                    Question.id.notin_((previous_questions))).all()
            else:
                available_questions = Question.query.filter(
                    Question.category == quiz_category['id']).filter(
                        Question.id.notin_((previous_questions))).all()

            question = available_questions[random.randrange(
                0, len(available_questions))].format(
                ) if len(available_questions) > 0 else None

            return jsonify({'success': True, 'question': question})

        except:
            abort(422)

    '''
  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 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,
            "messgae": "An internal error has occured"
        }), 500

    return app
예제 #18
0
def create_app(test_config=None):
    app = Flask(__name__)
    setup_db(app)
    CORS(app)

    @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('/categories', Methods=['GET'])
    def get_categories():
        categories = Category.query.order_by(Category.id).all()

        categories_list = {}
        for category in categories:
            categories_list[category.id] = category.type

        if (len(categories_list)) == 0:
            abort(404)

        return jsonify({
            'success': True,
            'categories': categories_list
        })

    @app.route('/questions', Methods=['GET'])
    def get_questions():
        selection = Question.query.order_by(Question.id).all()
        current_questions = paginate_questions(request, selection)

        categories = Category.query.order_by(Category.id).all()
        categories_list = {}
        for category in categories:
            categories_list[category.id] = category.type

        if len(current_questions) == 0 or len(categories_list) == 0:
            abort(404)

        return jsonify({
            'success': True,
            'questions': current_questions,
            'total_questions': len(Question.query.all()),
            'categories': categories_list,
        })

    @app.route('/questions/<int:question_id>', Methods=['DELETE'])
    def delete_question(question_id):
        try:
            question = Question.query.filter(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)

            categories = Category.query.order_by(Category.id).all()
            categories_list = {}
            for category in categories:
                categories_list[category.id] = category.type

            return jsonify({
                'success': True,
                'deleted': question_id,
                'questions': current_questions,
                'total_questions': len(Question.query.all()),
                'categories': categories_list
            })

        except:
            abort(422)

    @app.route('/questions', Methods=['POST'])
    def add_question():
        data = request.get_json()

        question = data.get('question', None)
        answer = data.get('answer', None)
        difficulty = data.get('difficulty', None)
        category = data.get('category', None)

        try:
            question = Question(question=question, answer=answer,
                                difficulty=difficulty, category=category)
            question.insert()

            return jsonify({
                'success': True
            })
        except:
            abort(422)

    @app.route('/questions/serach', Methods=['POST'])
    def serach_questions():

        data = request.get_json()
        search_term = data.get('searchTerm', None)
        questions = Question.query.filter(
            Question.question.ilike('%' + search_term + '%')).all()

        if len(questions) == 0:
            abort(404)

        return jsonify({
            'success': True,
            'questions': 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_by(id=category_id).one_or_none()

        if (category is None):
            abort(404)

        selection = Question.query.filter_by(category=Category.id).all()
        current_questions = paginate_questions(request, selection)

        return jsonify({
            'success': True,
            'questions': current_questions,
            'total_questions': len(Question.query.all()),
            'current_category': category.type
        })

    @app.route('/quizzes', Methods=['POST'])
    def quiz():

        data = request.get_json()
        previous_questions = data.get('previous_questions')
        quiz_category = data.get('quiz_category')

        if ((quiz_category is None) or (previous_questions is None)):
            abort(400)

        if (quiz_category['id'] == 0):
            questions = Question.query.all()
        else:
            questions = Question.query.filter_by(
                category=quiz_category['id']).all()

        def get_random_question():
            return questions[random.randrange(0, len(questions), 1)]

        next_question = get_random_question()
        used = True

        while used:
            if next_question.id in previous_questions:
                next_question = get_random_question()
            else:
                used = False

        return jsonify({
            'success': True,
            'question': next_question.format()
        })

    @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
        
    return app
예제 #19
0
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand

from backend.flaskr.__init__ import create_app
from backend.models import setup_db

app = create_app()
db = setup_db(app)
migrate = Migrate(app, db)
manager = Manager(app)

manager.add_command('db', MigrateCommand)

if __name__ == '__main__':
    manager.run()
예제 #20
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)
    CORS(app)
    '''
     Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs
    '''
    # cors = CORS(app, resources={r"/api/*": {"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,PATCH,POST,DELETE,OPTIONS')
        return response

    '''
    Create an endpoint to handle GET requests 
    for all available categories.
    '''
    # @app.route('/index' , methods=['GET', 'POST'])
    # def index():
    #   if request.method == 'GET':
    #     place = request.args.get('place', None)
    #     if place:
    #       return place
    #     return "No place information is given"

    # global_query
    categories = Category.query.all()
    questions = Question.query.all()

    def row2dict(row):
        d = {}
        for column in row.__table__.columns:
            d[column.id] = str(getattr(row, column.type))
        return d

    QUESTION_PER_SHELF = 10

    def paginate_qustion(request, selection):
        page = request.args.get('page', 1, type=int)
        start = (page - 1) * QUESTION_PER_SHELF
        end = start + QUESTION_PER_SHELF
        question = [q.format() for q in selection]
        current_question = question[start:end]

        return current_question

    @app.route('/categories')
    def get_all_catogaries():
        try:
            id_list = []
            type_list = []
            for u in categories:
                id_list.append(u.id)
                type_list.append(u.type)
            cat_dict = dict(zip(id_list, type_list))

        except:
            # abort 404 if no categories found
            if (len(cat_dict) == 0):
                abort(404)

        # return data to view
        return jsonify({'success': True, 'categories': cat_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.
    '''

    @app.route('/questions')
    def get_questions():
        current_questions = Question.query.first()
        current_categories = Category.query.filter(
            Category.type ==
            current_questions.category).one_or_none().format()
        try:
            error = False
            question_list = []
            for q in Question.query.filter_by(
                    category=current_categories.get('type')):
                question_list.append(q)

        except:
            error = True
            abort(422)
        finally:
            p_q = paginate_qustion(request, current_questions.format())
            return jsonify({
                'Catogaries': [c.format() for c in categories],
                'Current category': current_categories,
                'totalQustion': len(question_list),
                'questions': current_questions.format()
            })

    '''
    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>/delete', methods=['DELETE'])
    @cross_origin()
    def delete_question(id):
        # delete via id
        question = Question.query.filter(Question.id == id).one_or_none()
        if question is None:
            abort(404)
        question.delete()
        return jsonify({
            "total books": len(Question.query.all()),
            'qustions state': 'deleted successfully',
            'delete Queston ID': id
        })
        # return render_template(url_for(get_questions))

    '''
    Create an endpoint to POST a new question, 
    which will require the question and answer text, 
    category, and difficulty score.  
    '''

    @app.route('/create/question', methods=['POST'])
    def create_question():
        try:
            body = request.get_json()
            new_qus = body.get('question', None)
            new_answer = body.get('answer', None)
            catog = body.get('rate', None)
            diff = body.get('difficulty', None)
            question = Question(question=new_qus,
                                answer=new_answer,
                                category=catog,
                                difficulty=diff)
            question.insert()
        except:
            abort(202)
        finally:
            return jsonify({
                "successful": True,
                "total books": len(Question.query.all()),
                "messege": 'Created',
                'created_question_id': question.id
            })

    ''' 
    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('/search/question', methods=['GET', 'POST'])
    def search_question():
        body = request.get_json()
        search_term = body.get('title', None)
        qSearch = Question.query.filter(
            Question.question.ilike("%{}%".format(search_term))).all()
        # method search_qustion declared in the Question class
        r = Question.search_qustion(search_term, qSearch)
        count = len(qSearch)
        if count is None:
            abort(202)
        return jsonify({
            "count": count,
            "question searched": [r for r in qSearch]
        })

    '''
    Create a GET endpoint to get questions based on category.  
    '''

    @app.route('/questions/categories')
    def category_question():
        error = False
        try:
            id_list_q = []
            question_list = []
            answer_list = []
            category_list = []
            difficulty_list = []
            #questions and categories in global variable for Questions  and Categories query defined top of the code
            for u in questions:
                id_list_q.append(u.id)
                question_list.append(u.question)
                answer_list.append(u.answer)
                category_list.append(u.category)
                difficulty_list.append(u.difficulty)
                # categories_dict = dict(zip(question_list, category_list))
            question_list_per_cat = []
            cat_for_qus = []
            for c in categories:
                for q in questions:
                    if q.category == c.type:
                        question_list_per_cat.append(q.question)
                        cat_for_qus.append(c.type)
                # qus_cat_dict = dict(zip(cat_for_qus, question_list_per_cat))
            allQues = []
            for q in zip(cat_for_qus, question_list_per_cat):
                allQues.append("{}: {}".format(*q))
        except:
            error = True
            abort(404)

        finally:
            return jsonify({
                'statues: ': 'Successfully done',
                'error': error,
                'Questions per catogery': [q for q in allQues]
            })

    ''' 
    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('/questions/quiz', methods=['POST', 'GET'])
    def quiz_question():
        question_list_per_cat = []
        cat_for_qus = []
        # body = request.get_json()
        # answer = body.get('answer', None)
        try:
            #questions and categories in global variable for Questions  and Categories query defined top of the code
            for c in categories:
                for q in questions:
                    if c.type == q.category:
                        question_list_per_cat.append(q.question)
                        cat_for_qus.append(q.category)
            answer = 'football'

        except:
            abort(404)
        finally:
            random_qus = random.choice(question_list_per_cat)
            random_qus_query = Question.query.filter(
                Question.question == random_qus).one_or_none()
            if random_qus_query.answer == answer:
                true_or_false = True
            else:
                true_or_false = False
            return jsonify({
                'random question ': random_qus,
                'Answer': true_or_false,
                'categories': cat_for_qus
            })

    '''
    Error handlers for all expected errors 
    including 404, 422 and 500. 
    '''

    # error handlers

    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            "success": False,
            "error": 404,
            "message": "sorry not found try another things"
        }), 404

    @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
예제 #21
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)
    '''
  Set up CORS. Allow '*' for origins. Delete the sample route after completing the TODOs
  '''
    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')
        response.headers.add('Access-Control-Allow-Methods',
                             'GET, POST, PATCH, DELETE, OPTIONS')
        return response

    '''
  Create an endpoint to handle GET requests 
  for all available categories.
  '''

    @app.route('/categories', methods=['GET'])
    def retrieve_all_categories():
        categories = Category.query.all()
        formatted_categories = [category.format() for category in categories]

        if categories is None:
            abort(404)

        else:
            return jsonify({
                'Success': True,
                'Categories': formatted_categories,
                'Total_Nums': len(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. 
  '''

    @app.route('/questions', methods=['GET'])
    def retrive_all_questions_by_page():
        nums_per_page = 10
        page = request.args.get('page', 1, type=int)
        start = (page - 1) * nums_per_page
        end = start + nums_per_page
        questions = Question.query.all()

        if questions is None:
            abort(404)

        else:
            formatted_questions = [question.format() for question in questions]

            return jsonify({
                'success': True,
                'questions': formatted_questions[start:end],
                'total_nums': len(formatted_questions),
                'current_page': page
            })

    '''
  @TODO: 
  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. 
  '''
    '''
  @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.router('/questions/<int:question_id>', methods=['DELETE'])
    def delete_specific_question(question_id):
        question = Question.query.filter(
            Question.id == question_id).one_or_none()

        if question is None:
            abort(404)
        else:
            return jsonify({'success': True, 'question': question.format()})

    '''
  @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.router('/questions', methods=['POST'])
    def post_new_question():
        body = request.get_json()

        new_content = body.get('question', None)
        new_answer = body.get('answer', None)
        new_category = body.get('category', None)
        new_score = body.get('score', None)

        search_term = body.get('search', None)

        if search_term is None:
            try:
                question = Question(question=new_content,
                                    answer=new_answer,
                                    category=new_category,
                                    difficulty=new_score)
                question.insert()
                return jsonify({
                    'success': True,
                    'created': question.id,
                    'question': question,
                    'total_questions': len(Question.query.all())
                })

            except:
                abort(422)

        else:
            questions = Question.query.filter(
                Question.question.ilike('%' + search_term + '%')).all()

            if questions is None:
                abort(404)
            else:
                formatted_questions = [
                    question.format() for question in questions
                ]

                return jsonify({
                    'success': True,
                    'questions': formatted_questions
                })

    '''
  @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.router('/questions/categories/<string:category_name>',
                methods=['GET'])
    def retrive_questions_for_specific_category(category_name):
        questions = Question.query.filter(
            Question.category == category_name).all()

        if questions is None:
            abort(404)

        else:
            formatted_questions = [question.format() for question in questions]
            return jsonify({
                'success': True,
                'category': category_name,
                'questions': formatted_questions,
                'total_nums': len(formatted_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.router('/questions/random', methods=['POST'])
    def get_random_question():
        body = request.get_json()
        previous_questions_id = body.get('previous_questions', None)
        category = body.get('category', None)
        if category is None:
            abort(404)
        else:
            questions = Question.query.filter(
                Question.category == category,
                ~Question.id.in_(previous_questions_id)).all()

            if questions is None:
                abort(404)
            else:
                formatted_questions = [
                    question.format() for question in questions
                ]
                formatted_previous_questions_ids = [
                    question.id for question in previous_questions_id
                ]
                length = len(formatted_questions)
                index = random.randint(0, length - 1)
                formatted_previous_questions_ids.append({id: index})
                return jsonify({
                    'success':
                    True,
                    'question':
                    formatted_questions[index],
                    'previous_questions':
                    formatted_previous_questions_ids
                })

    '''
  @TODO: 
  Create error handlers for all expected errors 
  including 404 and 422. 
  '''

    @app.errorhandler(404)
    def not_fount(error):
        return jsonify({
            'success': False,
            'error': 404,
            'message': 'Not Found'
        }), 404

    @app.errorhandler(422)
    def not_fount(error):
        return jsonify({
            'success': False,
            'error': 422,
            'message': 'Unprocessable Entity'
        }), 422

    return app
예제 #22
0
def create_app():
    #
    app = Flask(__name__)
    setup_db(app)
    cors = CORS(app, resources={r"/*": {"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,PATCH,INFO')
        return response

    # Endpoints
    '''
    Get /actors
        requires get:actors permission
        returns success boolean and an array of actors
        or appropriate status code indicating reason for failure
    '''

    @app.route('/actors')
    @requires_auth('get:actors')
    def actors(payload):
        actors_list = Actors.query.all()
        actors_formatted = [actor.format() for actor in actors_list]
        return jsonify({'success': True, 'actors': actors_formatted})

    '''
    POST /actors
        creates a new actor
        requires create:actor permission
        paramter : a json object containts actor's attribue :
                  string name, int age, string gender, and boolean is_available
        returns success boolean and new actor's id
        or appropriate status code indicating reason for failure
    '''

    @app.route('/actors', methods=['POST'])
    @requires_auth('create:actor')
    def add_actor(payload):
        # read form data from post request
        body = request.get_json()
        if (not body):
            abort(400)
        # read post data
        name = body.get('name', None)
        age = body.get('age', None)
        gender = body.get('gender', None)
        # check if all required data is available,
        # if so, then add the actor
        added = False
        new_actor_id = 0
        if (name and age and gender):
            # create Actor instance using form data
            new_actor = Actors(name=name, age=age, gender=gender)
            # add new actor to db
            added = False
            try:
                new_actor.insert()
                new_actor_id = new_actor.id
                added = True
            except:
                db.session.rollback()
            finally:
                db.session.close()
        else:
            # in case one or more of required fields are missing,
            # return 422  error
            abort(422)
        # return json response for success
        return jsonify({
            'success': added,
            'inserted': new_actor_id,
        })

    '''
    GET /actors/<int : actor_id>
        get actor's info
        requires get:actor-info permission
        paramter : no parameter
        returns success boolean and actor's info whose Id = actor_id
        or appropriate status code indicating reason for failure
    '''

    @app.route('/actors/<int:actor_id>', methods=['GET'])
    @requires_auth('get:actor-info')
    def get_actor_info(payload, actor_id):
        # get list of actor identified by actor_id
        actor = Actors.query.get(actor_id)
        # if actor does not exist, return 404 code
        if (not actor):
            abort(404)
        # if exist, return json object with success and actor's info
        return jsonify({
            'success': True,
            'info': actor.format(),
        })

    '''
    DELETE /actors/<int : actor_id>
        deletes an actor
        requires delete:actor permission
        paramter : no parameter
        returns success boolean and the Id of the deleted actor
        or appropriate status code indicating reason for failure
    '''

    @app.route('/actors/<int:actor_id>', methods=['DELETE'])
    @requires_auth('delete:actor')
    def delete_actor(payload, actor_id):
        # check if actor exist by querying Actors by the actor_id
        actor = Actors.query.get(actor_id)
        deleted = False
        if (actor):
            # if actor exist, try delete
            try:
                actor.delete()
                deleted = True
            except:
                db.session.rollback()
            finally:
                db.session.close()
        else:
            # if actor not exist, return 404 code
            abort(404)
        # return json response for success, with the deleted actor's id
        return jsonify({
            'success': deleted,
            'deleted': actor_id,
        })

    '''
    PATCH /actors/<int : actor_id>
        modify an actor's info
        requires edit:actor permission
        paramter : no parameter
        returns success boolean and the Id of the edited actor
        or appropriate status code indicating reason for failure
    '''

    @app.route('/actors/<int:actor_id>', methods=['PATCH'])
    @requires_auth('edit:actor')
    def update_actor(payload, actor_id):
        actor_to_update = Actors.query.get(actor_id)
        # check if actor exist, if not return 404 code
        if (not actor_to_update):
            abort(404)
        # read form data from post request
        body = request.get_json()
        # check if data not provided, then return 422 code
        if (not body):
            abort(422)
        # read post data
        name = body.get('name', None)
        age = body.get('age', None)
        gender = body.get('gender', None)
        # check for each attribute if provided
        # updated provided info
        updated = False
        if (name):
            actor_to_update.name = name
        if (age):
            actor_to_update.age = age
        if (gender):
            actor_to_update.gender = gender
        try:
            actor_to_update.update()
            updated = True
        except:
            db.session.rollback()
            abort(422)
        finally:
            db.session.close()
        # return json response for success with the updated actor's id
        return jsonify({
            'success': updated,
            'updated': actor_id,
        })

    '''
    GET /actors/<actor_id>/movies
        get a list of all actor's movies
        requires get:actor-movies permission
        paramter : no parameter
        returns success boolean and a list of all movies
        or appropriate status code indicating reason for failure
    '''

    @app.route('/actors/<actor_id>/movies')
    @requires_auth('get:actor-movies')
    def get_actor_movies(payload, actor_id):
        actor = Actors.query.get(actor_id)
        # check if actor exist, if not return 404 code
        if (not actor):
            abort(404)
        # prepare a list of movies for that actor
        movies = [movie.format() for movie in actor.movies]
        # return json response with success and movie's list
        return jsonify({'success': True, 'movies': movies})

    '''
    GET /movies
        get a list of all movies
        requires get:movies permission
        paramter : no parameter
        returns success boolean and a list of all movies
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies')
    @requires_auth('get:movies')
    def get_movies(payload):
        # get all movies list
        movies = Movies.query.all()
        # prepare as formatted objects, to jsonify
        movies_formatted = [movie.format() for movie in movies]
        # return json reponse with success and movies list
        return jsonify({'success': True, 'movies': movies_formatted})

    '''
    GET /movies/<int:movie_id>
        get a movie's info
        requires get:movie-info permission
        paramter : no parameter
        returns success boolean and movie's info
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies/<int:movie_id>')
    @requires_auth('get:movie-info')
    def get_movie_info(payload, movie_id):
        # query Movies to get movie identified by movie_id
        movie = Movies.query.get(movie_id)
        # if movie not exist, return 404 code
        if (not movie):
            abort(404)
        # return json reponse with success and movie's info
        return jsonify({'success': True, 'movie': movie.format()})

    '''
    POST /movies
        creates a new movie
        requires create:movie permission
        paramter : a json object contains the info of the movie
        returns success boolean and the new movie's id
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies', methods=['POST'])
    @requires_auth('create:movie')
    def create_movie(payload):
        # get request paramtetes
        body = request.get_json()
        # if not provided, return 400 code
        if (not body):
            abort(400)
        # read parameters
        title = body.get('title', None)
        release_date = body.get('release_date', None)
        movie_category = body.get('movie_category', None)
        movie_rating = body.get('movie_rating', None)
        created = False
        new_movie_id = 0
        # check all required attribute is provided
        if (title and release_date and movie_category and movie_rating):
            try:
                # prepare new movie object from provided data and insert to db
                new_movie = Movies(title=title,
                                   release_date=release_date,
                                   movie_rating=movie_rating,
                                   movie_category=movie_category)
                new_movie.insert()
                created = True
                new_movie_id = new_movie.id
            except:
                db.session.rollback()
            finally:
                db.session.close()
        else:
            # if not all required attributes provided, return 422 code
            abort(422)
        # return json reponse with success and new movie's id
        return jsonify({'success': created, 'new_movie_id': new_movie_id})

    '''
    PATCH /movies/<int:movie_id>
        get a movie's info
        requires edit:movie permission
        paramter : a json object of the new info to be updated
        returns success boolean and the id of the movie just updated
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies/<int:movie_id>', methods=['PATCH'])
    @requires_auth('edit:movie')
    def update_movie(payload, movie_id):
        # get the movie to be updated
        movie_to_update = Movies.query.get(movie_id)
        # if movie not exist, return 404
        if (not movie_to_update):
            abort(404)
        # read request data
        body = request.get_json()
        # if data not provided, return 400
        if (not body):
            abort(400)
        # read data and update availabe attributes
        title = body.get('title', None)
        release_date = body.get('release_date', None)
        movie_category = body.get('movie_category', None)
        movie_rating = body.get('movie_rating', None)
        updated = False
        if (title):
            movie_to_update.title = title
        if (release_date):
            movie_to_update.release_date = release_date
        if (movie_category):
            movie_to_update.movie_category = movie_category
        if (movie_rating):
            movie_to_update.movie_rating = movie_rating
        # try saving changes
        try:
            movie_to_update.update()
            updated = True
        except:
            db.session.rollback()
        finally:
            db.session.close()
        # return json with success result and the movie's id just updated
        return jsonify({'success': updated, 'updated': movie_id})

    '''
    GET /movies/<int:movie_id>/actors
        get a list of all movie's actors
        requires get:movie-actors permission
        paramter : no parameter
        returns success boolean and a list of all movie's actor
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies/<int:movie_id>/actors')
    @requires_auth('get:movie-actors')
    def get_movie_actors(payload, movie_id):
        # get the movie to read actors list
        movie = Movies.query.get(movie_id)
        # if movie not available, return 404 code
        if (not movie):
            abort(404)
        # prepare a list of all movie's actors
        actors = [actor.format() for actor in movie.actors]
        # return json response with successs and actors list
        return jsonify({'success': True, 'actors': actors})

    '''
    POST /movies/<int:movie_id>/actors
        add an actor to a movie's actors list
        requires add:movie-actor permission
        paramter : the id of the actor to be added
        returns success boolean and the id of the movie and the actor
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies/<int:movie_id>/actors', methods=['POST'])
    @requires_auth('add:movie-actor')
    def add_movie_actors(payload, movie_id):
        # get the movie to add actors for
        movie = Movies.query.get(movie_id)
        # if movie not exist, return 404 code
        if (not movie):
            abort(404)
        # read request
        body = request.get_json()
        # if request not available, return 400 code
        if (not body):
            abort(400)
        # get the actor's id from request
        actor_id = body.get("actor_id", 0)
        # get the actor identified by actor_id
        actor = Actors.query.get(actor_id)
        # if actor not exist, return 402 code
        if (not actor):
            abort(422)
        added = False
        # try to add actor to movie's actors list
        try:
            movie.actors.append(actor)
            db.session.commit()
            added = True
        except:
            db.session.rollback()
        finally:
            db.session.close()
        # return json response with success result, movie's id and actor's id
        return jsonify({
            'success': added,
            'movie': movie_id,
            'actor': actor_id
        })

    '''
    DELETE /movies/<int:movie_id>/actors
        remove an actor to a movie's actors list
        requires delete:movie-actor permission
        paramter : the id of the actor to be removed
        returns success boolean and the id of the movie and the actor
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies/<int:movie_id>/actors', methods=['DELETE'])
    @requires_auth('delete:movie-actor')
    def delete_movie_actors(payload, movie_id):
        # get the movie to delete actor from
        movie = Movies.query.get(movie_id)
        # if movie not exist, return 404 code
        if (not movie):
            abort(404)
        # read request
        body = request.get_json()
        # if request not available, return 400 code
        if (not body):
            abort(400)
        # get the actor's id from request
        actor_id = body.get("actor_id", 0)
        # get the actor identified by actor_id
        actor = Actors.query.get(actor_id)
        # if actor not exist, return 402 code
        if (not actor):
            abort(422)
        # try to delete actor to movie's actors list
        deleted = False
        try:
            movie.actors.remove(actor)
            db.session.commit()
            deleted = True
        except:
            db.session.rollback()
        finally:
            db.session.close()
        # return json response with success result, movie's id and actor's id
        return jsonify({
            'success': deleted,
            'movie': movie_id,
            'deleted': actor_id
        })

    '''
    DELETE /movies/<int:movie_id>
        delete a movie
        requires delete:movie permission
        paramter : no parameter
        returns success boolean and the id of the movie just deleted
        or appropriate status code indicating reason for failure
    '''

    @app.route('/movies/<int:movie_id>', methods=['DELETE'])
    @requires_auth('delete:movie')
    def delete_movie(payload, movie_id):
        # get the movie to be deleted
        movie_to_delete = Movies.query.get(movie_id)
        # if the movie not exist, return 404
        if (not movie_to_delete):
            abort(404)
        deleted = False
        # try to delete the movie
        try:
            movie_to_delete.delete()
            deleted = True
        except:
            db.session.rollback()
        finally:
            db.session.close()

        # return json response with success result and movie's id just deleted
        return jsonify({'success': deleted, 'deleted': movie_id})

    # Errors Handlers
    '''
    Create error handlers for all expected errors
    '''

    # error handler for 404 (Not Found)
    @app.errorhandler(404)
    def not_found(error):
        return jsonify({
            "success": False,
            "error": 404,
            "message": "resource not found"
        }), 404

    # error handler for 422 (unprocessable)
    @app.errorhandler(422)
    def unprocessable(error):
        return jsonify({
            "success": False,
            "error": 422,
            "message": "unprocessable"
        }), 422

    # error handler for 400 (bad request)
    @app.errorhandler(400)
    def bad_request(error):
        return jsonify({
            "success": False,
            "error": 400,
            "message": "bad request"
        }), 400

    # error handler for 405 (method not allowed)
    @app.errorhandler(405)
    def method_not_allowed(error):
        return jsonify({
            "success": False,
            "error": 405,
            "message": "method not allowed"
        }), 405

    # error handler for 500
    @app.errorhandler(500)
    def server_error(error):
        return jsonify({
            "success": False,
            "error": 500,
            "message": "internal server error"
        }), 500

    # error handling for AuthError
    @app.errorhandler(AuthError)
    def auth_error_handler(auth_error):
        status_code = auth_error.status_code
        message = auth_error.error
        return jsonify({
            "success": False,
            "error": status_code,
            "message": message
        }), status_code

    return app
예제 #23
0
def create_app(test_config=None):
    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

    # Fetches a list of categories
    @app.route('/categories')
    def get_categories():

        categories = Category.query.all()

        formatted_categories = {}

        for category in categories:
            formatted_categories[f'{category.id}'] = f'{category.type}'

        return jsonify({'success': True, 'categories': formatted_categories})

    # Fetches a list of paginated questions, where each page contains 10
    @app.route('/questions')
    def get_questions():

        questions = Question.query.all()
        paginated_questions = paginate_questions(request, questions)

        categories = Category.query.all()
        formatted_categories = [category.format() for category in categories]

        if len(paginated_questions) == 0:
            abort(404)

        return jsonify({
            'success': True,
            'questions': paginated_questions,
            'total_questions': len(questions),
            'current_category': None,
            'categories': formatted_categories
        })

    # Deletes the provided question id and returns a list of paginated questions
    @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)

        try:
            question.delete()
            questions = Question.query.all()
            paginated_questions = paginate_questions(request, questions)

            return jsonify({
                'success': True,
                'deleted': question_id,
                'questions': paginated_questions,
                'total_questions': len(questions)
            })

        except:
            abort(422)

    # Creates a question from request's json body and returns a list of paginated questions
    @app.route('/questions', methods=['POST'])
    def create_question():
        body = request.get_json()

        try:
            question = Question(question=body.get('question', None),
                                answer=body.get('answer', None),
                                category=body.get('category', None),
                                difficulty=body.get('difficulty', None))
            question.insert()

            questions = Question.query.all()
            paginated_questions = paginate_questions(request, questions)

            return jsonify({
                'success': True,
                'created': question.id,
                'questions': paginated_questions,
                'total_questions': len(questions)
            })

        except:
            abort(422)

    # Fetches a list of paginated questions based on the provided search term using form
    @app.route('/questions/search', methods=['POST'])
    def search_question():
        search_term = request.form['search_term']
        questions = Question.query.filter(
            Question.question.ilike(f'%{search_term}%')).all()

        if not len(questions):
            abort(422)

        paginated_questions = paginate_questions(request, questions)
        return jsonify({
            'success': True,
            'questions': paginated_questions,
            'total_questions': len(questions),
        })

    # Fetches a list of paginated questions based on the provided Category Type using request variable
    @app.route('/categories/<category_type>/questions', methods=['POST'])
    def get_questions_by_category(category_type):
        questions = Question.query.filter(
            Question.category.ilike(category_type)).all()

        if not len(questions):
            abort(422)

        paginated_questions = paginate_questions(request, questions)
        return jsonify({
            'success': True,
            'questions': paginated_questions,
            'total_questions': len(questions)
        })

    # Fetches a single question to play the quiz
    @app.route('/play', methods=['POST'])
    def play():
        body = request.get_json()

        previous_questions = body['previous_questions']
        previous_questions_ids = []
        for question in previous_questions:
            previous_questions_ids.append(question.id)

        category_id = body["quiz_category"]["id"]

        if category_id == 0:

            if previous_questions is not None:

                questions = Question.query.filter(
                    Question.id.notin_(previous_questions_ids)).all()

            else:

                questions = Question.query.all()

        else:

            category = Category.query.get(category_id)

            if previous_questions is not None:

                questions = Question.query. \
                    filter(
                    Question.id.notin_(previous_questions_ids),
                    Question.category == category_id) \
                    .all()

            else:

                questions = Question.query.filter(
                    Question.category == category.id).all()

        random_question = random.choice(questions).format()

        return jsonify({'success': True, 'question': random_question})

    @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(405)
    def method_not_allowed(error):
        return jsonify({
            "success": False,
            "error": 405,
            "message": "method_not_allowed"
        }), 405

    return app
예제 #24
0
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):
        """
        Handler for after a request has been made.
        :param response:
        """
        response.headers.add(
            'Access-Control-Allow-Headers',
            'Content-Type, Authorization'
        )
        response.headers.add(
            'Access-Control-Allow-Methods',
            'GET, POST, PUT, PATCH, DELETE, OPTIONS'
        )
        return response

    @app.route('/questions')
    def list_questions():
        """
        Get questions for a given page.
        :return:
        """
        page = request.args.get('page', 1, type=int)
        selection = Question.query.all()
        selection, total_selection_count = paginate_selection(selection, page=page, limit=QUESTIONS_PER_PAGE)

        categories = {
            category.id: category.type for category in Category.query.all()
        }

        if len(selection) == 0:
            abort(StatusCode.HTTP_404_NOT_FOUND.value)

        return jsonify({
            'success': True,
            'current_category': None,
            'categories': categories,
            'questions': format_selection(selection),
            'total_questions': total_selection_count
        })

    @app.route('/questions', methods=['POST'])
    def create_question():
        """
        Add a question to database.
        :return:
        """
        question = request.get_json()

        if not question:
            abort(StatusCode.HTTP_400_BAD_REQUEST.value)

        question = Question(**question)
        question.insert()

        return jsonify({
            'success': True, 'id': question.id
        }), StatusCode.HTTP_201_CREATED.value

    @app.route('/questions/<int:question_id>', methods=['DELETE'])
    def delete_question(question_id):
        """
        Delete question by given id.
        :param question_id:
        :return:
        """
        question = Question.query.get(question_id)
        if not question:
            abort(StatusCode.HTTP_404_NOT_FOUND.value)

        question.delete()
        return jsonify({
            'success': True
        }), StatusCode.HTTP_204_NO_CONTENT.value

    @app.route('/questions/filter', methods=['POST'])
    def filter_questions():
        """
        Return the list of questions after filteration.
        :return:
        """
        page = request.args.get('page', 1, type=int)
        search_term = request.get_json().get('searchTerm') or ''
        selection = Question.query.filter(Question.question.ilike(f'%{search_term}%')).all()
        selection, total_selection_count = paginate_selection(selection, page=page, limit=QUESTIONS_PER_PAGE)

        return jsonify({
            'success': True,
            'questions': format_selection(selection),
            'total_questions': total_selection_count,
        })

    @app.route('/categories')
    def list_categories():
        """
        Return the categories with id and type.
        :return:
        """
        result = {
            "success": True,
            "categories": {
                category.id: category.type
                for category in Category.query.all()
            }
        }
        return jsonify(result)

    @app.route('/categories/<int:category_id>/questions')
    def get_questions_by_category(category_id):
        """
        Get questions by category.
        :param category_id:
        :return:
        """
        category = Category.query.get(category_id)

        if not category:
            abort(StatusCode.HTTP_404_NOT_FOUND.value)

        page = request.args.get('page', 1, type=int)
        selection = Question.query.filter_by(category=category_id).all()
        selection, total_selection_count = paginate_selection(selection, page=page, limit=QUESTIONS_PER_PAGE)

        return jsonify({
            "success": True,
            "questions": format_selection(selection),
            "total_questions": total_selection_count,
            "current_category": category.format(),
        })

    @app.route('/quizzes', methods=['POST'])
    def play_quiz():
        """
        Play quiz route to get questions for quizzes.
        :return:
        """
        request_data = request.get_json()
        previous_questions = request_data.get('previous_questions', [])
        quiz_category = request_data.get('quiz_category')

        if not quiz_category:
            abort(StatusCode.HTTP_400_BAD_REQUEST.value)

        category_id = quiz_category.get('id', None)
        if category_id:
            questions = Question.query.filter_by(category=category_id)
        else:
            questions = Question.query

        questions = format_selection(questions.filter(~Question.id.in_(previous_questions)).all())
        random_question = random.choice(questions) if questions else None

        return jsonify({
            'question': random_question, 'success': True
        })

    @app.errorhandler(StatusCode.HTTP_400_BAD_REQUEST.value)
    def bad_request(error):
        """
        Error handler for bad request with status code 400.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_400_BAD_REQUEST.value,
            'message': StatusCode.HTTP_400_BAD_REQUEST.name
        }), StatusCode.HTTP_400_BAD_REQUEST.value

    @app.errorhandler(StatusCode.HTTP_401_UNAUTHORIZED.value)
    def unauthorized(error):
        """
        Error handler for unauthorized with status code 401.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_401_UNAUTHORIZED.value,
            'message': StatusCode.HTTP_401_UNAUTHORIZED.name
        }), StatusCode.HTTP_401_UNAUTHORIZED.value

    @app.errorhandler(StatusCode.HTTP_403_FORBIDDEN.value)
    def forbidden(error):
        """
        Error handler for forbidden with status code 403.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_403_FORBIDDEN.value,
            'message': StatusCode.HTTP_403_FORBIDDEN.name
        }), StatusCode.HTTP_403_FORBIDDEN.value

    @app.errorhandler(StatusCode.HTTP_404_NOT_FOUND.value)
    def not_found(error):
        """
        Error handler for not found with status code 404.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_404_NOT_FOUND.value,
            'message': StatusCode.HTTP_404_NOT_FOUND.name
        }), StatusCode.HTTP_404_NOT_FOUND.value

    @app.errorhandler(StatusCode.HTTP_405_METHOD_NOT_ALLOWED.value)
    def method_not_allowed(error):
        """
        Error handler for method not allowed with status code 405.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_405_METHOD_NOT_ALLOWED.value,
            'message': StatusCode.HTTP_405_METHOD_NOT_ALLOWED.name
        }), StatusCode.HTTP_405_METHOD_NOT_ALLOWED.value

    @app.errorhandler(StatusCode.HTTP_422_UNPROCESSABLE_ENTITY.value)
    def unprocessable_entity(error):
        """
        Error handler for unprocessable entity with status code 422.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_422_UNPROCESSABLE_ENTITY.value,
            'message': StatusCode.HTTP_422_UNPROCESSABLE_ENTITY.name
        }), StatusCode.HTTP_422_UNPROCESSABLE_ENTITY.value

    @app.errorhandler(StatusCode.HTTP_500_INTERNAL_SERVER_ERROR.value)
    def internal_server_error(error):
        """
        Error handler for internal server error with status code 500.
        :param: error
        :return:
        """
        return jsonify({
            'success': False,
            'error': StatusCode.HTTP_500_INTERNAL_SERVER_ERROR.value,
            'message': StatusCode.HTTP_500_INTERNAL_SERVER_ERROR.name
        }), StatusCode.HTTP_500_INTERNAL_SERVER_ERROR.value

    return app
예제 #25
0
def create_app(test_config=None):
    # create and configure the app
    app = Flask(__name__)
    setup_db(app)

    # set up CORS, allowing all origins
    CORS(app, resources={'/': {'origins': '*'}})

    @app.after_request
    def after_request(response):
        '''
    Sets access control.
    '''
        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

    '''
  @TODO: 
  Create an endpoint to handle GET requests 
  for all available categories.
  '''

    @app.route("/categories")
    def categories():
        # get all categories and add to dict
        categories = Category.query.all()
        categories_dict = {}
        for category in categories:
            categories_dict[category.id] = category.type

        # abort 404 if no categories found
        if (len(categories_dict) == 0):
            abort(404)

        # return data to view
        return jsonify({'success': True, 'categories': categories_dict})

    '''
  @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 questions():
        # get all questions and paginate
        selection = Question.query.all()
        total_questions = len(selection)
        current_questions = paginate_questions(request, selection)

        # get all categories and add to dict
        categories = Category.query.all()
        categories_dict = {}
        for category in categories:
            categories_dict[category.id] = category.type

        # abort 404 if no questions
        if (len(current_questions) == 0):
            abort(404)

        # return data to view
        return jsonify({
            'success': True,
            'questions': current_questions,
            'total_questions': total_questions,
            'categories': categories_dict
        })

    '''
  @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):
        try:

            selected_row = Question.query.filter_by(id=id).one_or_none()

            if selected_row is None:
                abort(404)

            selected_row.delete()

            # return data to view
            return jsonify({'success': True})

        except:
            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_questions():
        details = request.get_json()

        # if search term is present
        if "searchTerm" in details:
            search_term = details.get('searchTerm')
            # query the database using search term
            selection = Question.query.filter(
                Question.question.ilike(f'%{search_term}%')).all()

            if len(selection) == 0:
                abort(404)

            # paginate the results
            paginated = paginate_questions(request, selection)

            # return results
            return jsonify({
                'success': True,
                'questions': paginated,
                'total_questions': len(Question.query.all())
            })

        else:
            #save data
            question = details["question"]
            answer = details["answer"]
            difficulty = details["difficulty"]
            category = details["category"]

            # ensure all fields have data
            if ((question is None) or (answer is None) or (difficulty is None)
                    or (category is None)):
                abort(422)

            try:
                # create and insert new question
                question = Question(question=question,
                                    answer=answer,
                                    difficulty=difficulty,
                                    category=category)
                question.insert()

                # return data to view
                return jsonify({'success': True})

            except:
                # abort unprocessable if exception
                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: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
        })

    '''
  @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_quiz_question():
        '''
    Handles POST requests for playing quiz.
    '''

        # load the request body
        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()
        # load questions for given category
        else:
            questions = Question.query.filter_by(category=category['id']).all()

        total = len(questions)

        def check_if_used(question):
            used = False
            for q in previous:
                if (q == question.id):
                    used = True

            return used

        question = questions[random.randrange(0, len(questions), 1)]

        while (check_if_used(question)):
            question = questions[random.randrange(0, len(questions), 1)]

            if (len(previous) == total):
                return jsonify({'success': True})

        return jsonify({'success': True, 'question': question.format()})

    @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