Files
power-math/server/api.py

124 lines
4.0 KiB
Python

"""
api.py
Organizes all API routes for acquiring, checking, removing questions, as well as other important and miscellaneous
API interactions, static or dynamic.
"""
import copy
import random
from flask_restful import Resource, reqparse, abort
from server import questions, exceptions
from server.helpers import generate_id
# Stores active questions in memory for checking answers.
# Keys represent random question IDs. Values are Question objects.
active_questions = {}
# Question categories, key name, value function for acquiring a random question generator.
categories = {
'arithmetic': (
questions.get_arithmetic,
'The basic four mathematical functions, plus fractions, exponents and a little more.'
)
}
parser = reqparse.RequestParser()
parser.add_argument(
'category',
required=False, type=str, choices=tuple(categories.keys()), help='Invalid Category: {error_msg}'
)
class Question(Resource):
"""
Questions are small objects represented generated questions for users with a prompt and a answer.
They are identified by a String ID.
"""
def get(self, question_id=None):
"""Retrieve information about a given question, including the answer for it."""
if question_id is not None:
if question_id in active_questions.keys():
return active_questions[question_id]
else:
raise exceptions.InvalidQuestion(404, question=question_id)
else:
abort(404, message='Use PUT to create questions, otherwise specify a question ID')
def put(self, question_id=None):
"""
Request a new question.
A category can be specified in the query arguments in order to filter the question type.
Furthermore, a question type can be also specified .
The Question object is returned, although the answer is omitted.
"""
args = parser.parse_args()
# Generate new Question ID
q_id = Nonewt
while q_id in active_questions.keys() or q_id is None:
q_id = generate_id(5)
# Get category arg or choose one if not specified.
if args.get('category') is not None:
category = args.get('category')
# Check that the category is valid
if category not in categories.keys():
raise exceptions.InvalidCategory(404, category=category)
else:
category = random.choice(list(categories.keys()))
# Acquire a question generator and generate a function, then store the result.
active_questions[q_id] = categories[category][0]()()
# Make a shallow copy, hide 'answer' key.
question = copy.copy(active_questions[q_id])
del question['answer']
return 201, question
def delete(self, question_id):
"""Delete a question object from the running before it is automatically removed."""
if question_id in active_questions.keys():
del active_questions[question_id]
return {'message': f'Successfully deleted Question ID {question_id}'}
else:
raise exceptions.InvalidQuestion(404, question=question_id)
class Questions(Resource):
"""
Simple resource for listing all available question objects.
"""
def get(self):
return active_questions
class Category(Resource):
"""
A category is a static designation for a problem to be classified as.
Any question will only have one category it belongs to.
"""
def get(self, category_id):
"""Get all information about a category"""
if category_id in categories.keys():
return categories[category_id][1]
else:
raise exceptions.InvalidCategory(404, category=category_id)
class Categories(Resource):
"""
Categories are static identifiers for the different types of questions available to users.
They are identified with pre-chosen identifiers.
"""
def get(self):
"""Get a list of all categories."""
return list(categories.keys()), 200