Skip to content

Commit

Permalink
feature/2-implement-endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
ChinhQuoc committed Sep 21, 2024
1 parent ff183af commit 3fbaf1e
Show file tree
Hide file tree
Showing 5 changed files with 235 additions and 111 deletions.
132 changes: 122 additions & 10 deletions backend/flaskr/__init__.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import os
from flask import Flask, request, abort, jsonify
from flask import Flask, request, abort, jsonify, Response
from flask_sqlalchemy import SQLAlchemy
from flask_cors import CORS
import random
from sqlalchemy import delete

from models import setup_db, Question, Category
from models import db, setup_db, Question, Category

QUESTIONS_PER_PAGE = 10

Expand Down Expand Up @@ -46,13 +47,12 @@ def get_categories():
start = (page - 1) * 10
end = start + 10

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

return jsonify({
'success': True,
'categories': formatted_categories[start:end],
'total_categories': len(formatted_categories)
'categories': categories[start:end],
'total_categories': len(categories)
})

"""
Expand All @@ -67,15 +67,14 @@ def get_categories():
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')
@app.route('/questions', methods=['GET'])
def get_questions():
# Implement pagination
page = request.args.get('page', 1, type=int)
start = (page - 1) * 10
end = start + 10

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

questions = Question.query.all()
formatted_questions = [question.format() for question in questions]
Expand All @@ -84,7 +83,7 @@ def get_questions():
'success': True,
'questions': formatted_questions[start:end],
'total_questions': len(formatted_questions),
'categories': formatted_categories,
'categories': categories
})

"""
Expand All @@ -94,6 +93,32 @@ def get_questions():
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):
id_question = int(id)

try:
question = Question.query.filter(Question.id == id_question).one_or_none()

if question is None:
handle_error(404, 'Error: question not found')

db.session.delete(question)
db.session.commit()
except:
handle_error(422, 'An error occurred!')

return jsonify({
'success': True,
'message': "deleted successfully"
})

# return jsonify({
# 'success': True,
# 'deleted': id_question,
# 'question': current_questions,
# 'total_question': len(current_questions)
# })

"""
@TODO:
Expand All @@ -105,6 +130,24 @@ def get_questions():
the form will clear and the question will appear at the end of the last page
of the questions list in the "List" tab.
"""
@app.route('/questions', methods=['POST'])
def create_question():
body = request.get_json()
new_question = body.get('question', None)
new_answer = body.get('answer', None)
new_difficulty = body.get('difficulty', None)
new_category = body.get('category', None)

try:
question = Question(question=new_question, answer=new_answer, category=int(new_category), difficulty=int(new_difficulty))
question.insert()
except:
handle_error(422, 'An error occurred!')

return({
'success': True,
'message': 'Create successfully!'
})

"""
@TODO:
Expand All @@ -116,6 +159,22 @@ def get_questions():
only question that include that string within their question.
Try using the word "title" to start.
"""
@app.route('/questions/search', methods=['POST'])
def search_questions():
page = request.args.get('page', 1, type=int)
start = (page - 1) * 10
end = start + 10

body = request.get_json()
key_word = body['searchTerm']
questions = db.session.query(Question).filter(Question.question.ilike(f'%{key_word}%')).all()
formatted_questions = [question.format() for question in questions]

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

"""
@TODO:
Expand All @@ -125,6 +184,25 @@ def get_questions():
categories in the left column will cause only questions of that
category to be shown.
"""
@app.route("/categories/<int:id>/questions")
def get_all_question(id):
# Implement pagination
page = request.args.get('page', 1, type=int)
start = (page - 1) * 10
end = start + 10

id_category = int(id)
categories = Category.query.filter_by(id=id_category).all()
formatted_categories = [category.format() for category in categories]
questions = Question.query.filter_by(category=id_category).all()
formatted_questions = [question.format() for question in questions]

return jsonify({
'success': True,
'questions': formatted_questions[start:end],
'total_questions': len(formatted_questions),
'currentCategory': formatted_categories[0]
})

"""
@TODO:
Expand All @@ -137,12 +215,46 @@ def get_questions():
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_question_to_play():
data = request.get_json()
previous_questions = data.get('previous_questions')
quiz_category = data.get('quiz_category')
result = None
questions = []

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

format_questions = [question.format() for question in questions]
if len(format_questions) != 0:
if len(previous_questions) is 0:
result = format_questions[0]
else:
data = [question for question in format_questions if question['id'] not in previous_questions]
if len(data) != 0:
result = data[0]

return jsonify({
'question': result
})

"""
@TODO:
Create error handlers for all expected errors
including 404 and 422.
"""
def handle_error(code, message):
error_message = ({'message': message})
abort(Response(error_message, code))

def get_all_formatted_category():
categories = Category.query.all()
formatted_categories = [category.format() for category in categories]
return formatted_categories

return app

71 changes: 41 additions & 30 deletions frontend/src/components/FormView.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,52 @@
import React, { Component } from 'react';
import $ from 'jquery';
import '../stylesheets/FormView.css';
import React, { Component } from "react";
import $ from "jquery";
import "../stylesheets/FormView.css";

class FormView extends Component {
constructor(props) {
super();
this.state = {
question: '',
answer: '',
question: "",
answer: "",
difficulty: 1,
category: 1,
categories: {},
categories: [],
};
}

componentDidMount() {
$.ajax({
url: `/categories`, //TODO: update request URL
type: 'GET',
type: "GET",
success: (result) => {
console.log(result);
this.setState({ categories: result.categories });
return;
},
error: (error) => {
alert('Unable to load categories. Please try your request again');
alert("Unable to load categories. Please try your request again");
return;
},
});
}

submitQuestion = (event) => {
if (
!this.state.question ||
!this.state.answer ||
!this.state.question.trim() ||
!this.state.answer.trim()
) {
alert("The question or answer is invalid!");
return;
}

event.preventDefault();
$.ajax({
url: '/questions', //TODO: update request URL
type: 'POST',
dataType: 'json',
contentType: 'application/json',
url: "/questions", //TODO: update request URL
type: "POST",
dataType: "json",
contentType: "application/json",
data: JSON.stringify({
question: this.state.question,
answer: this.state.answer,
Expand All @@ -47,11 +58,11 @@ class FormView extends Component {
},
crossDomain: true,
success: (result) => {
document.getElementById('add-question-form').reset();
document.getElementById("add-question-form").reset();
return;
},
error: (error) => {
alert('Unable to add question. Please try your request again');
alert("Unable to add question. Please try your request again");
return;
},
});
Expand All @@ -63,44 +74,44 @@ class FormView extends Component {

render() {
return (
<div id='add-form'>
<div id="add-form">
<h2>Add a New Trivia Question</h2>
<form
className='form-view'
id='add-question-form'
className="form-view"
id="add-question-form"
onSubmit={this.submitQuestion}
>
<label>
Question
<input type='text' name='question' onChange={this.handleChange} />
<input type="text" name="question" onChange={this.handleChange} />
</label>
<label>
Answer
<input type='text' name='answer' onChange={this.handleChange} />
<input type="text" name="answer" onChange={this.handleChange} />
</label>
<label>
Difficulty
<select name='difficulty' onChange={this.handleChange}>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='3'>3</option>
<option value='4'>4</option>
<option value='5'>5</option>
<select name="difficulty" onChange={this.handleChange}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
</label>
<label>
Category
<select name='category' onChange={this.handleChange}>
{Object.keys(this.state.categories).map((id) => {
<select name="category" onChange={this.handleChange}>
{this.state.categories.map((category) => {
return (
<option key={id} value={id}>
{this.state.categories[id]}
<option key={category.id} value={category.id}>
{category.type}
</option>
);
})}
</select>
</label>
<input type='submit' className='button' value='Submit' />
<input type="submit" className="button" value="Submit" />
</form>
</div>
);
Expand Down
Loading

0 comments on commit 3fbaf1e

Please sign in to comment.