Add support for editing questions through the admin site

Need to accept the input from the hidden_answer and multiple_choice
Disable input when loading data to make /admin/questions/ more robust
This commit is contained in:
Matthew Welch 2021-03-22 20:25:35 -07:00
parent b4efbc8f3f
commit f3a089df24
5 changed files with 135 additions and 2 deletions

View File

@ -20,10 +20,20 @@ def questions():
return render_template("admin/question_list.html") return render_template("admin/question_list.html")
@Admin.route("/admin/questions/edit/<int:question_id>") @Admin.route("/admin/questions/edit/<int:question_id>", methods=["GET", "POST"])
@roles_required("admin") @roles_required("admin")
def edit_question(question_id): def edit_question(question_id):
if request.method == "POST":
print(f"edit question: {request.form.get('question_text')}")
database.update_question(question_id,
request.form.get("question_text"),
request.form.get("answer"),
request.form.get("addresses")
)
return redirect(url_for("admin.edit_question", question_id=question_id))
question: database.AllQuestions = get_question(database.AllQuestions, question_id) question: database.AllQuestions = get_question(database.AllQuestions, question_id)
if "application/json" in request.accept_mimetypes.values():
return jsonify(question.get_dict())
return render_template("admin/edit_question.html", question=question) return render_template("admin/edit_question.html", question=question)

View File

@ -4,6 +4,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Admin</title> <title>Admin</title>
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}"> <link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<script src="https://kit.fontawesome.com/f2d4307e62.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/cosmo/bootstrap.min.css"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootswatch/4.5.2/cosmo/bootstrap.min.css">
{% block head %}{% endblock %} {% block head %}{% endblock %}

View File

@ -0,0 +1,67 @@
{% extends "admin/base.html" %}
{% block body %}
<form class="container mt-5" method="post">
<div class="form-group">
<label for="question_text">Question</label>
<input id="question_text" name="question_text" type="text" class="form-control" value="{{ question.question }}">
</div>
<div class="form-group">
<label for="answer">Answer</label>
<input id="answer" name="answer" type="text" class="form-control" value="{{ question.answer }}">
</div>
<div class="form-group">
<label for="addresses">Bible Verses</label>
<input id="addresses" name="addresses" type="text" class="form-control" value="{{ question.addresses }}">
</div>
{% if question.multiple_choice is not none %}
<label class="mt-3">Multiple Choice</label>
<div class="form-group">
<label for="multiple_choice_difficulty">Difficulty</label>
<div class="form-group">
<select id="multiple_choice_difficulty" name="multiple_choice_difficulty" class="custom-select">
<option {% if question.multiple_choice.difficulty is none %}selected=""{% endif %}>None</option>
<option {% if question.multiple_choice.difficulty == 1 %}selected=""{% endif %} value="1">Easy</option>
<option {% if question.multiple_choice.difficulty == 2 %}selected=""{% endif %} value="2">Medium</option>
<option {% if question.multiple_choice.difficulty == 3 %}selected=""{% endif %} value="3">Hard</option>
</select>
</div>
<div class="form-group">
<label>Wrong Answers</label>
<ul class="list-group">
{% for answer in question.multiple_choice.wrong_answers %}
<li class="list-group-item d-flex justify-content-between align-items-center">
<input id="answer_{{ loop.index0 }}" name="wrong_answers" class="form-control" value="{{ answer }}">
<button class="btn" type="button" onclick="$(this).parent().remove()"><i class="fas fa-times"></i></button>
</li>
{% endfor %}
</ul>
<button id="add_wrong_answer" class="btn btn-secondary" type="button">Add Answer</button>
</div>
</div>
{% endif %}
{% if question.hidden_answer is not none %}
<label class="mt-3">Hidden Answer</label>
<div class="form-group">
<label for="hidden_answer_difficulty">Difficulty</label>
<div class="form-group">
<select id="hidden_answer_difficulty" name="hidden_answer_difficulty" class="custom-select">
<option {% if question.hidden_answer.difficulty is none %}selected=""{% endif %}>None</option>
<option {% if question.hidden_answer.difficulty == 1 %}selected=""{% endif %} value="1">Easy</option>
<option {% if question.hidden_answer.difficulty == 2 %}selected=""{% endif %} value="2">Medium</option>
<option {% if question.hidden_answer.difficulty == 3 %}selected=""{% endif %} value="3">Hard</option>
</select>
</div>
</div>
{% endif %}
<button id="save" name="save" type="submit" class="btn btn-primary">Save</button>
</form>
{% endblock %}
{% block scripts %}
<script>
$("#add_wrong_answer").on("click", () => {
})
</script>
{% endblock %}

View File

@ -1,7 +1,6 @@
{% extends "admin/base.html" %} {% extends "admin/base.html" %}
{% block head %} {% block head %}
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.18.2/dist/bootstrap-table.min.css"> <link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.18.2/dist/bootstrap-table.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.18.2/extensions/filter-control/bootstrap-table-filter-control.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.18.2/extensions/filter-control/bootstrap-table-filter-control.min.css">
{% endblock %} {% endblock %}
@ -22,6 +21,16 @@
var filter_data = [true, false] var filter_data = [true, false]
function disable_input() {
console.log("disable");
$("input, select").attr("disabled", true);
}
function enable_input() {
console.log("enable");
$("input, select").removeAttr("disabled");
}
$("#question-table").bootstrapTable({ $("#question-table").bootstrapTable({
url: "/admin/question_query", url: "/admin/question_query",
pagination: true, pagination: true,
@ -30,6 +39,15 @@
queryParams: query_params, queryParams: query_params,
showRefresh: true, showRefresh: true,
searchOnEnterKey: true, searchOnEnterKey: true,
{#disableControlWhenSearch: true,#}
onClickRow: (item, element) => {
console.log(item);
console.log(element);
window.location.href = `/admin/questions/edit/${item["question_id"]}`
},
onLoadSuccess: enable_input,
onPageChange: disable_input,
onSearch: disable_input,
columns: [ columns: [
{ {
field: "question_id", field: "question_id",

View File

@ -71,6 +71,19 @@ class AllQuestions(Base):
def __repr__(self): def __repr__(self):
return f"<Question: {self.question_id}>" return f"<Question: {self.question_id}>"
def get_dict(self):
result = {
"question_id": self.question_id,
"question": self.question,
"answer": self.answer,
"addresses": self.addresses,
}
if self.hidden_answer:
result["hidden_answer"] = self.hidden_answer.get_dict()
if self.multiple_choice:
result["multiple_choice"] = self.multiple_choice.get_dict()
return result
class HiddenAnswer(Base): class HiddenAnswer(Base):
__tablename__ = "category_hidden_answer" __tablename__ = "category_hidden_answer"
@ -93,6 +106,13 @@ class HiddenAnswer(Base):
def __repr__(self): def __repr__(self):
return f"<Question Hidden Answer: {self.question_id}>" return f"<Question Hidden Answer: {self.question_id}>"
def get_dict(self):
return {
"question_id": self.question_id,
"difficulty": self.difficulty,
"hint": self.hint,
}
class MultipleChoice(Base): class MultipleChoice(Base):
__tablename__ = "category_multiple_choice" __tablename__ = "category_multiple_choice"
@ -123,6 +143,14 @@ class MultipleChoice(Base):
def __repr__(self): def __repr__(self):
return f"<Question Multiple Choice: {self.question_id}>" return f"<Question Multiple Choice: {self.question_id}>"
def get_dict(self):
return {
"question_id": self.question_id,
"difficulty": self.difficulty,
"hint": self.hint,
"wrong_answers": self.wrong_answers,
}
Base.metadata.create_all(engine) Base.metadata.create_all(engine)
@ -208,3 +236,12 @@ def query_all_questions(offset, limit, query: dict = None, sort=None, order=None
questions = q.offset(offset).limit(limit).all() questions = q.offset(offset).limit(limit).all()
count = q.count() count = q.count()
return questions, count return questions, count
def update_question(question_id, question_text, answer, addresses):
session: sqlalchemy.orm.session.Session = Session()
question: AllQuestions = session.query(AllQuestions).get(question_id)
question.question = question_text
question.answer = answer
question.addresses = addresses
session.commit()