From 197164d691bc294eade8072621455221b86d203e Mon Sep 17 00:00:00 2001 From: Matthew Welch Date: Sat, 20 Mar 2021 13:12:33 -0700 Subject: [PATCH] Started the admin site Can currently view all the questions and search through them --- admin/admin.py | 61 +++++++++++++++++++++++ admin/templates/admin/base.html | 40 +++++++++++++++ admin/templates/admin/index.html | 5 ++ admin/templates/admin/question_list.html | 63 ++++++++++++++++++++++++ config.py | 1 + database.py | 30 +++++++++-- main.py | 3 ++ 7 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 admin/admin.py create mode 100644 admin/templates/admin/base.html create mode 100644 admin/templates/admin/index.html create mode 100644 admin/templates/admin/question_list.html diff --git a/admin/admin.py b/admin/admin.py new file mode 100644 index 0000000..301e5ba --- /dev/null +++ b/admin/admin.py @@ -0,0 +1,61 @@ +import json +from flask import render_template, Blueprint, request, jsonify +import database +from database import get_all_questions, get_question + + +Admin = Blueprint("admin", __name__, template_folder="templates") + + +@Admin.route("/admin/") +def index(): + return render_template("admin/index.html", title="admin") + + +@Admin.route("/admin/questions/") +def questions(): + return render_template("admin/question_list.html") + + +@Admin.route("/admin/questions/edit/") +def edit_question(question_id): + question: database.AllQuestions = get_question(database.AllQuestions, question_id) + return render_template("admin/edit_question.html", question=question) + + +@Admin.route("/admin/question_query") +def query_questions(): + offset = request.args.get("offset", type=int) + limit = request.args.get("limit", type=int) + sort = request.args.get("sort") + order = request.args.get("order") + query = parse_question_query(request.args.get("filter")) + result = database.query_all_questions(offset, limit, query, sort, order) + response_dict = { + "total": result[1], + "rows": [], + } + for question in result[0]: + response_dict["rows"].append({ + "id": question.question_id, + "question_id": question.question_id, + "question": question.question, + "answer": question.answer, + "multiple_choice": getattr(question, "multiple_choice", None) is not None, + "hidden_answer": getattr(question, "hidden_answer", None) is not None, + }) + # question1 = get_question(database.AllQuestions, 0) + # question2 = get_question(database.AllQuestions, 1) + # question3 = get_question(database.AllQuestions, 2) + return jsonify(response_dict) + + +def parse_question_query(query): + if query: + query: dict = json.loads(query) + if "multiple_choice" in query.keys(): + query["multiple_choice"] = True if query["multiple_choice"] == "true" else False + if "hidden_answer" in query.keys(): + query["hidden_answer"] = True if query["hidden_answer"] == "true" else False + return query + return None diff --git a/admin/templates/admin/base.html b/admin/templates/admin/base.html new file mode 100644 index 0000000..5bf2938 --- /dev/null +++ b/admin/templates/admin/base.html @@ -0,0 +1,40 @@ + + + + + Admin + + + {% block head %}{% endblock %} + + + +
+ {% block body %}{% endblock %} +
+
+
+ Created By ItIsGood.com +
+
+ + + +{% block scripts %}{% endblock %} + \ No newline at end of file diff --git a/admin/templates/admin/index.html b/admin/templates/admin/index.html new file mode 100644 index 0000000..dd5b984 --- /dev/null +++ b/admin/templates/admin/index.html @@ -0,0 +1,5 @@ +{% extends "admin/base.html" %} + +{% block body %} +

This is the admin home page

+{% endblock %} diff --git a/admin/templates/admin/question_list.html b/admin/templates/admin/question_list.html new file mode 100644 index 0000000..19efa43 --- /dev/null +++ b/admin/templates/admin/question_list.html @@ -0,0 +1,63 @@ +{% extends "admin/base.html" %} + +{% block head %} + + + +{% endblock %} + +{% block body %} +
+{% endblock %} + +{% block scripts %} + + + +{% endblock %} diff --git a/config.py b/config.py index 70532a7..e05ca65 100644 --- a/config.py +++ b/config.py @@ -7,6 +7,7 @@ load_dotenv(".env") class Config: SECRET_KEY = environ.get("SECRET_KEY") + SECURITY_PASSWORD_SALT = environ.get("SECURITY_PASSWORD_SALT") DB_USER = environ.get("DB_USER") DB_PASSWORD = environ.get("DB_PASSWORD") DB_HOST = environ.get("DB_HOST") diff --git a/database.py b/database.py index 85e2ae4..afdfac9 100644 --- a/database.py +++ b/database.py @@ -26,6 +26,9 @@ class AllQuestions(Base): answer = Column(String) addresses = Column(String) + multiple_choice = relationship("MultipleChoice", uselist=False, back_populates="all_question_relationship") + hidden_answer = relationship("HiddenAnswer", uselist=False, back_populates="all_question_relationship") + def __init__(self, question_id, question, answer, addresses): self.question_id = question_id self.question = question @@ -43,7 +46,7 @@ class HiddenAnswer(Base): difficulty = Column(Integer) hint = Column(JSON) - all_question_relationship = relationship("AllQuestions", foreign_keys=[question_id], lazy="joined", uselist=False) + all_question_relationship = relationship("AllQuestions", lazy="joined", back_populates="hidden_answer") question = association_proxy("all_question_relationship", "question") answer = association_proxy("all_question_relationship", "answer") addresses = association_proxy("all_question_relationship", "addresses") @@ -66,7 +69,7 @@ class MultipleChoice(Base): hint = Column(JSON) wrong_answers = Column(ARRAY(String)) - all_question_relationship = relationship("AllQuestions", foreign_keys=[question_id], lazy="joined", uselist=False) + all_question_relationship = relationship("AllQuestions", lazy="joined", back_populates="multiple_choice") question = association_proxy("all_question_relationship", "question") answer = association_proxy("all_question_relationship", "answer") addresses = association_proxy("all_question_relationship", "addresses") @@ -118,7 +121,7 @@ def get_category_count(category: Union[Type[MultipleChoice], Type[HiddenAnswer], return session.query(category).count() -def get_question(category: Union[Type[MultipleChoice], Type[HiddenAnswer], Type[AllQuestions]], question_id: int) -> Optional[Union[Type[MultipleChoice], Type[HiddenAnswer], Type[AllQuestions]]]: +def get_question(category: Union[Type[MultipleChoice], Type[HiddenAnswer], Type[AllQuestions]], question_id: int) -> Optional[Union[MultipleChoice, HiddenAnswer, AllQuestions]]: session: sqlalchemy.orm.session.Session = Session() return session.query(category).filter(category.question_id == question_id).one_or_none() @@ -149,3 +152,24 @@ def check_answer(question_id: int, guess: str) -> Tuple[bool, str]: if question: answer = question.answer return answer == guess, answer + + +def query_all_questions(offset, limit, query: dict = None, sort=None, order=None) -> Tuple[List[AllQuestions], int]: + session: sqlalchemy.orm.session.Session = Session() + query_params = [] + if query is not None: + for key in query.keys(): + if key == "multiple_choice" or key == "hidden_answer": + if query[key]: + query_params.append(getattr(AllQuestions, key) != None) + else: + query_params.append(getattr(AllQuestions, key) == None) + else: + query_params.append(getattr(AllQuestions, key).ilike("%"+query[key]+"%")) + order_by = None + if sort and order: + order_by = getattr(getattr(AllQuestions, sort), order)() + q = session.query(AllQuestions).filter(*query_params).order_by(order_by) + questions = q.offset(offset).limit(limit).all() + count = q.count() + return questions, count diff --git a/main.py b/main.py index e48fb4a..8fa6ec5 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,11 @@ import os from flask import Flask, render_template, request, jsonify +from flask_security import Security import database +from admin import admin app = Flask(__name__) +app.register_blueprint(admin.Admin) environment_configuration = os.environ['CONFIGURATION_SETUP'] app.config.from_object(environment_configuration)