Example #1
0
def create_question():
    data = request.get_json()

    fields = {
        'question': data.get('question') or None,  # Force none if empty string
        'answer': data.get('answer') or None,  # Force none if empty string
        'difficulty': data.get('difficulty', None),
        'category': data.get('category', None),
    }

    # Check required fields are populated
    validate_required_fields(fields)

    # Validate specific fields
    errors = []
    if fields['difficulty'] <= 0 or fields['difficulty'] > 5:
        errors.append(
            {'difficulty': 'Difficulty must be an integer between 1 and 5'})

    category = Category.query.get(int(fields['category']))
    if not category:
        errors.append({'category': 'Category is not supported'})

    if errors:
        abort(400, errors)

    # Create the question
    try:
        with db_session():
            question = Question(**fields)
            question.insert()
            return jsonify(question.format())
            # TODO: Test side effect return 422
    except:
        abort(422)
 def add_questions():
     resposta = request.get_json()
     print(resposta)
     cat = int(resposta['category'])
     print(cat)
     question = Question(question=resposta['question'],
                         answer=resposta['answer'],
                         category=cat + 1,
                         difficulty=resposta['difficulty'])
     Question.insert(question)
     return jsonify({'success': True})
    def test_delete_question_by_id(self):
        question = Question(question='How long is a mile in kilometers?',
                            answer='Answer',
                            category='Math',
                            difficulty=5)
        question.insert()

        res = self.client().delete(f'/questions/{question.id}')

        assert res.status_code == 200
        data = json.loads(res.data)
        assert data == {'success': True, 'deleted': question.id}
Example #4
0
    def create_question():
        try:
            body = request.get_json()
            search_term = body.get('search', None)

            if body == {}:
                abort(422)

            # question search
            if search_term is not None:
                search = "{}".format(search_term.lower())

                search_results = Question.query.filter(
                    Question.question.ilike('%' + search + '%')).all()

                formatted_search_results = [
                    question.format for question in search_results
                ]
                paginated_results = paginate_questions(request, search_results)

                return jsonify({
                    'success': True,
                    'questions': paginated_results,
                    'total_questions': len(search_results)
                })
            # question add
            else:
                question = body.get('question', None)
                answer = body.get('answer', None)
                category = body.get('category', None)
                difficulty = body.get('difficulty', None)

                if question is None or answer is None or category is None or difficulty is None:
                    abort(422)

                new_question = Question(question=question,
                                        answer=answer,
                                        category=category,
                                        difficulty=difficulty)
                new_question.insert()

                selection = Question.query.order_by('id').all()
                paged_questions = paginate_questions(request, selection)

                return jsonify({
                    'success': True,
                    'created': new_question.id,
                    'questions': paged_questions,
                    'total_questions': len(selection)
                }), 201

        except ():
            abort(422)
    def test_delete_question(self):
        question = Question(question='new question',
                            answer='new answer',
                            difficulty=1,
                            category=1)
        question.insert()
        record_id = question.id
        res = self.client().delete(f'/questions/{record_id}/')
        data = json.loads(res.data)

        self.assertEqual(res.status_code, 200)
        self.assertEqual(data['success'], True)
        self.assertEqual(data['deleted'], record_id)
def create_questions(db, count=12):
    some_category = Category(type='Some Category')
    some_category.insert()

    questions = []
    for index in range(count):
        question = Question(question=f'The question? {index}',
                            answer='The answer',
                            category=some_category.id,
                            difficulty=5)
        question.insert()
        questions.append(question)
    return questions, some_category
def post_new_question():
    body = request.get_json()
    if not body:
        # posting an envalid json should return a 400 error.
        abort(400)
    if (body.get('question') and body.get('answer') and body.get('difficulty')
            and body.get('category')):
        # posted a new question
        new_question = body.get('question')
        new_answer = body.get('answer')
        new_category = body.get('category')
        new_difficulty = body.get('difficulty')
        # insure that difficulty is only from 1 to 5
        if not 1 <= int(new_difficulty) < 6:
            abort(400)
        try:
            # insert the new question to the database
            question = Question(new_question, new_answer, new_category,
                                new_difficulty)
            question.insert()
            # query the database for all questions
            page = request.args.get('page', 1, type=int)
            selection = Question.query.order_by(Question.id).paginate(
                page, current_app.config['QUESTIONS_PER_PAGE'], True)
            total_questions = selection.total
            if total_questions == 0:
                # no questions were found, return a 404 error.
                abort(404)
            current_questions = [
                question.format() for question in selection.items
            ]
            return jsonify({
                'success': True,
                'id': question.id,
                'question': question.question,
                'questions': current_questions,
                'total_questions': total_questions
            })
        except:
            # creating the question failed, rollback and close the connection
            db.session.rollback()
            abort(422)
    else:
        # anything else posted in the body should return a 400 error
        abort(400)
Example #8
0
def create_question():
    body = request.get_json()

    # if the body containts a search term execute the search function
    # otherwise continue with creating a new question
    search_term = body.get("searchTerm")
    if search_term:
        return search_questions(search_term)

    else:
        for key in ["question", "answer", "category", "difficulty"]:
            if body.get(key) is None:
                abort(422)

        new_question = body.get("question", None)
        answer = body.get("answer", None)
        category = body.get("category", None)
        difficulty = body.get("difficulty", None)

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

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

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

        except:
            abort(422)
Example #9
0
    def create_question():
        try:
            data = request.get_json() if request.is_json else None

            if data is None or len(data) == 0:
                abort(400)
            ''' 
                verify that data does contain (question and answer, category, and difficulty),
                as well as no additional key/value data that is not required,
                and finally verify that data has not empty strings.
                
                Note: I executed it this way so
                 it can dynamically verify needed data from user if i added extra column to Question Model.
                 all i should do when adding a new column to Question is to represent this coulumn as
                 name:type pair in required_question_args
            '''
            required_question_args = {
                'question': str,
                'answer': str,
                'difficulty': int,
                'category': str
            }
            for k in data:
                if len(data) != len(required_question_args) \
                        or k not in required_question_args \
                        or type(data[k]) is not required_question_args[k] \
                        or isinstance(data[k], str) and len(data[k]) == 0:
                    abort(400)

            new_question = Question(**data)
            new_question.insert()

            return jsonify({'success': True, 'created': new_question.id})

        except BadRequest:
            abort(400)
        except:
            abort(500)
    def test_questions_search(self):
        question1 = Question(question='How long is a mile in kilometers?',
                             answer='Answer',
                             category='Math',
                             difficulty=5)
        question1.insert()
        question2 = Question(question='How many centimeters is an inch?',
                             answer='Answer',
                             category='Math',
                             difficulty=5)
        question2.insert()

        search_term = 'kilometers'
        res = self.client().post('/questions/search',
                                 json={'searchTerm': search_term})

        assert res.status_code == 200
        data = json.loads(res.data)
        assert len(data['questions']) == 1
        assert data == {
            'questions': [question1.format()],
            'total_questions': 1
        }
Example #11
0
    def test_question_list(self):
        """Test that hitting the question list GET endpoint returns a list of question(s), as well as categories"""
        third_question = Question('Why is science?', 'Only Bill Nye knows', self.science.id, 5)
        third_question.insert()

        # Test list with pagination only returns 2 result
        resp = self.client.get('/api/questions')
        assert resp.status_code == 200

        data = json.loads(resp.data)
        assert 'categories' in data
        assert 'questions' in data
        assert 'total_questions' in data

        assert data == {
            'categories': {
                '1': 'Science',
                '2': 'Geography'
            },
            'questions': [
                {
                    'answer': 'Nobody knows',
                    'category': 1,
                    'difficulty': 5,
                    'id': 1,
                    'question': 'What is science?'
                },
                {
                    'answer': 'Probably not',
                    'category': 2,
                    'difficulty': 5,
                    'id': 2, 'question':
                    'Is geography real?'
                }
            ],
            'total_questions': 3
        }
Example #12
0
def add_question():
    """
    Adds a question
    :return: Id of the question that has been created
    """
    body = request.get_json()

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

    try:
        question = Question(question=body.get('question'),
                            answer=body.get('answer'),
                            difficulty=body.get('difficulty'),
                            category=body.get('category'),
                            )
        question.insert()
        return jsonify({
            'success': True,
            'created': question.id,
        })
    except:
        abort(422)
Example #13
0
class TriviaApiTestCase(BaseTestClass):

    def setUp(self):
        super().setUp()

        # Add some categories
        self.science = Category('Science')
        self.geography = Category('Geography')
        db.session.add(self.science)
        db.session.add(self.geography)
        db.session.commit()

        # Add some questions
        self.science_question = Question('What is science?', 'Nobody knows', self.science.id, 5)
        self.geog_question = Question('Is geography real?', 'Probably not', self.geography.id, 5)
        self.science_question.insert()
        self.geog_question.insert()

    def test_question_list(self):
        """Test that hitting the question list GET endpoint returns a list of question(s), as well as categories"""
        third_question = Question('Why is science?', 'Only Bill Nye knows', self.science.id, 5)
        third_question.insert()

        # Test list with pagination only returns 2 result
        resp = self.client.get('/api/questions')
        assert resp.status_code == 200

        data = json.loads(resp.data)
        assert 'categories' in data
        assert 'questions' in data
        assert 'total_questions' in data

        assert data == {
            'categories': {
                '1': 'Science',
                '2': 'Geography'
            },
            'questions': [
                {
                    'answer': 'Nobody knows',
                    'category': 1,
                    'difficulty': 5,
                    'id': 1,
                    'question': 'What is science?'
                },
                {
                    'answer': 'Probably not',
                    'category': 2,
                    'difficulty': 5,
                    'id': 2, 'question':
                    'Is geography real?'
                }
            ],
            'total_questions': 3
        }

    def test_question_by_category_404(self):
        """Test that a 404 is returned when a category id is not found"""
        resp = self.client.get(f'/api/categories/5000/questions')
        assert resp.status_code == 404

        assert json.loads(resp.data) == {
            'error': '404: Not Found',
            'message': 'Category matching the provided ID was not found'
        }

    def test_question_by_category(self):
        """
        Test that only questions for a given category will be returned when hitting the GET category questions endpoint.
        """
        assert Category.query.count() == 2
        cat = self.science
        resp = self.client.get(f'/api/categories/{cat.id}/questions')
        assert resp.status_code == 200

        data = json.loads(resp.data)

        assert 'current_category' in data
        assert data['current_category'] == cat.id

        assert 'questions' in data
        assert data['questions'][0]['category'] == cat.id

        # Check response shape
        assert data == {
            'current_category': 1,
            'questions': [
                {
                    'answer': 'Nobody knows',
                    'category': 1,
                    'difficulty': 5,
                    'id': 1,
                    'question': 'What is science?'
                }
            ],
            'total_questions': 1
        }

    def test_category_list(self):
        """Test that hitting the categories list GET endpoint returns a dictionary of supported categories"""
        resp = self.client.get('/api/categories')
        assert resp.status_code == 200

        data = json.loads(resp.data)
        assert data == {
            'categories': {
                '1': 'Science',
                '2': 'Geography'
            }
        }

    def test_create_question_fields(self):
        """Test field validations on question create POST endpoint"""
        url = '/api/questions'

        # Test missing fields
        data = {}
        resp = self.client.post(url, json=data)
        assert resp.status_code == 400
        assert json.loads(resp.data) == {
            'error': '400: Bad Request',
            'message': [
                {'question': 'Field is required'},
                {'answer': 'Field is required'},
                {'difficulty': 'Field is required'},
                {'category': 'Field is required'}
            ]
        }

        data = {
            'question': 'Why is science?',
            'answer': 'Only Bill Nye knows',
            'category': 5000,
            'difficulty': 0
        }

        # Test difficulty and cateory validation
        resp = self.client.post(url, json=data)
        assert resp.status_code == 400
        assert json.loads(resp.data) == {
            'error': '400: Bad Request',
            'message': [
                {'difficulty': 'Difficulty must be an integer between 1 and 5'},
                {'category': 'Category is not supported'}
            ]
        }

    @patch('flaskr.api.views.Question.insert')
    def test_create_question_422(self, mock_insert):
        """Test that a 422 error is returned when there is an error raised while processing question creation"""
        # Force raise an exeception while creating question in DB
        mock_insert.side_effect = Exception

        assert Question.query.count() == 2

        data = {
            'question': 'Why is science?',
            'answer': 'Only Bill Nye knows',
            'category': self.science.id,
            'difficulty': 3
        }

        resp = self.client.post('/api/questions', json=data)
        assert resp.status_code == 422
        assert json.loads(resp.data) == {
            'error': '422: Unprocessable Entity',
            'message': 'The request was well-formed but was unable to be followed due to semantic errors.'
        }

        # Ensure changes dont persist
        assert Question.query.count() == 2

    def test_create(self):
        """Test successful creation of a question"""
        assert Question.query.count() == 2

        data = {
            'question': 'Why is science?',
            'answer': 'Only Bill Nye knows',
            'category': self.science.id,
            'difficulty': 3
        }
        resp = self.client.post('/api/questions', json=data)
        assert resp.status_code == 200
        resp_data = json.loads(resp.data)
        assert resp_data == {
            'answer': 'Only Bill Nye knows',
            'category': 1,
            'difficulty': 3,
            'id': 3,
            'question': 'Why is science?'
        }

        # Ensure changes persist in DB
        assert Question.query.count() == 3
        question = Question.query.get(resp_data['id'])
        assert question is not None
        assert question.format() == resp_data

    def test_delete_question_404(self):
        """Test the trying to delete a non-existent question id returns a 404"""
        resp = self.client.delete('/api/questions/5000')
        assert resp.status_code == 404
        assert json.loads(resp.data) == {
            'error': '404: Not Found',
            'message': 'Question matching the provided ID was not found for delete'
        }

    @patch('flaskr.api.views.Question.delete')
    def test_delete_question_500(self, mock_delete):
        """Test that a 500 error is returned when there is an error raised while processing question deletion"""
        # Force raise an exeception while deleting question in DB
        mock_delete.side_effect = Exception

        assert Question.query.count() == 2

        resp = self.client.delete(f'/api/questions/{self.geog_question.id}')
        assert resp.status_code == 500
        assert json.loads(resp.data) == {
            'error': '500: Internal Server Error',
            'message': 'The server encountered an internal error and was unable to complete your request. '
                       'Either the server is overloaded or there is an error in the application.'
        }

        # Ensure delete does not persist in DB
        assert Question.query.count() == 2

    def test_delete_question(self):
        """Test question deletion response and persists in the database"""
        assert Question.query.count() == 2

        resp = self.client.delete(f'/api/questions/{self.geog_question.id}')
        assert resp.status_code == 204

        # Ensure changes persist in DB
        assert Question.query.count() == 1
        assert Question.query.get(self.geog_question.id) is None

    def test_search(self):
        """
        Test that question search can search by:
            - partial category match
            - partial question match
            - partial answer match
            - Specify a category search under
        """
        url = '/api/questions/search'

        search = {
            'searchTerm': 'sci'
        }

        # test category contains
        resp = self.client.post(url, json=search)
        assert resp.status_code == 200
        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'}
            ],
            'total_questions': 1
        }

        # Test question contains
        search['searchTerm'] = 'what is'
        resp = self.client.post(url, json=search)
        assert resp.status_code == 200
        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'}
            ],
            'total_questions': 1
        }

        # Test answer contains
        search['searchTerm'] = 'nobody'
        resp = self.client.post(url, json=search)
        assert resp.status_code == 200

        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'}
            ],
            'total_questions': 1
        }

        # test within category
        new_question = Question('Why is science?', 'Only Bill Nye knows', self.science.id, 5)
        new_question.insert()
        search['categoryId'] = self.science.id
        search['searchTerm'] = 'knows'

        resp = self.client.post(url, json=search)
        assert resp.status_code == 200
        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'},
                {'answer': 'Only Bill Nye knows', 'category': 1, 'difficulty': 5, 'id': 3, 'question': 'Why is science?'}
            ],
            'total_questions': 2
        }

    def test_quiz_question_categorized(self):
        """Test get random quiz question from specific category"""
        url = '/api/quizzes'
        previous_questions = []

        data = {
            'previous_questions': previous_questions,
            'quiz_category': self.science.id
        }

        # There is only 1 possible question in the science category
        resp = self.client.post(url, json=data)
        assert resp.status_code == 200
        resp_data = json.loads(resp.data)

        assert resp_data == {
            'question': {
                'answer': 'Nobody knows',
                'category': 1,
                'difficulty': 5,
                'id': 1,
                'question': 'What is science?'
            }
        }

        # Get depleted  questions
        previous_questions.append(resp_data['question']['id'])
        data['previous_questions'] = previous_questions

        resp = self.client.post(url, json=data)
        assert resp.status_code == 200

        resp_data = json.loads(resp.data)
        assert resp_data['question'] is None

    def test_quiz_question_uncategorized(self):
        """Test get random quiz question from any category"""
        url = '/api/quizzes'
        previous_questions = []
        data = {'previous_questions': previous_questions}

        resp = self.client.post(url, json=data)
        assert resp.status_code == 200
        resp_data = json.loads(resp.data)

        # Check response for question that was returned
        assert 'question' in resp_data
        assert 'id' in resp_data['question']
        question1 = Question.query.get(resp_data['question']['id'])
        assert question1 is not None
        assert resp_data['question'] == question1.format()

        # Get next question
        previous_questions.append(question1.id)
        data['previous_questions'] = previous_questions

        resp = self.client.post(url, json=data)
        assert resp.status_code == 200

        resp_data = json.loads(resp.data)
        question2 = Question.query.get(resp_data['question']['id'])
        assert question2 is not None
        assert question2.id not in previous_questions

        # Get depleted questions
        previous_questions.append(question2.id)
        data['previous_questions'] = previous_questions

        resp = self.client.post(url, json=data)
        assert resp.status_code == 200

        resp_data = json.loads(resp.data)
        assert resp_data['question'] is None
Example #14
0
    def test_search(self):
        """
        Test that question search can search by:
            - partial category match
            - partial question match
            - partial answer match
            - Specify a category search under
        """
        url = '/api/questions/search'

        search = {
            'searchTerm': 'sci'
        }

        # test category contains
        resp = self.client.post(url, json=search)
        assert resp.status_code == 200
        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'}
            ],
            'total_questions': 1
        }

        # Test question contains
        search['searchTerm'] = 'what is'
        resp = self.client.post(url, json=search)
        assert resp.status_code == 200
        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'}
            ],
            'total_questions': 1
        }

        # Test answer contains
        search['searchTerm'] = 'nobody'
        resp = self.client.post(url, json=search)
        assert resp.status_code == 200

        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'}
            ],
            'total_questions': 1
        }

        # test within category
        new_question = Question('Why is science?', 'Only Bill Nye knows', self.science.id, 5)
        new_question.insert()
        search['categoryId'] = self.science.id
        search['searchTerm'] = 'knows'

        resp = self.client.post(url, json=search)
        assert resp.status_code == 200
        assert json.loads(resp.data) == {
            'questions': [
                {'answer': 'Nobody knows', 'category': 1, 'difficulty': 5, 'id': 1, 'question': 'What is science?'},
                {'answer': 'Only Bill Nye knows', 'category': 1, 'difficulty': 5, 'id': 3, 'question': 'Why is science?'}
            ],
            'total_questions': 2
        }
    def post(self):
        errors = []
        good_data = True

        data = json.loads(request.data)

        if data['question'] is None or data['question'].__class__ != str or len(
                data['question'].strip()) < 1:
            good_data = False
            errors.append('Question text cannot be blank, or was not a string')

        if data['answer'] is None or data['answer'].__class__ != str or len(
                data['answer'].strip()) < 1:
            good_data = False
            errors.append('Answer text cannot be blank, or was not a string')

        try:
            if data['difficulty'] is None or data[
                    'difficulty'].__class__ != str or int(
                        data['difficulty']) < 1 or int(data['difficulty']) > 5:
                good_data = False
                errors.append(
                    'Difficulty integer cannot be blank, and must be an integer between 1 and 5'
                )
        except:
            good_data = False
            errors.append(
                'Difficulty integer cannot be blank, and must be an integer between 1 and 5'
            )

        try:
            if data['category'] is None or data[
                    'category'].__class__ != str or db.session.query(
                        Category).filter_by(
                            id=int(data['category'])).one_or_none() is None:
                good_data = False
                errors.append(
                    'Category integer cannot be blank, or is set to an invalid category'
                )
        except:
            good_data = False
            errors.append(
                'Category integer cannot be blank, or is set to an invalid category'
            )

        if good_data:
            q = Question(question=bleach.clean(data['question']),
                         answer=bleach.clean(data['answer']),
                         difficulty=bleach.clean(data['difficulty']),
                         category=bleach.clean(data['category']))
            q.insert()
            payload = {
                'message': 'New question successfully added',
                'question': q.format()
            }
            return payload, 201

        return {
            'success': False,
            'error': 400,
            'message': 'New question was not added, check errors for reasons',
            'errors': errors
        }, 400