Add support for adding/removing multiple choice wrong answers
Make multiple choice view more flexible with the number of choices
This commit is contained in:
parent
6ad7f2817a
commit
85909e7087
@ -24,12 +24,21 @@ def questions():
|
||||
@roles_required("admin")
|
||||
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")
|
||||
)
|
||||
data = {
|
||||
"question_text": request.form.get("question_text"),
|
||||
"answer": request.form.get("answer"),
|
||||
"addresses": request.form.get("addresses"),
|
||||
}
|
||||
multiple_choice_difficulty = request.form.get("multiple_choice_difficulty", None, int)
|
||||
wrong_answers = request.form.getlist("wrong_answers")
|
||||
hidden_answer_difficulty = request.form.get("hidden_answer_difficulty", None, int)
|
||||
if multiple_choice_difficulty is not None:
|
||||
data["multiple_choice_difficulty"] = multiple_choice_difficulty
|
||||
if len(wrong_answers) > 0:
|
||||
data["wrong_answers"] = wrong_answers
|
||||
if hidden_answer_difficulty is not None:
|
||||
data["hidden_answer_difficulty"] = hidden_answer_difficulty
|
||||
database.update_question(question_id, data)
|
||||
return redirect(url_for("admin.edit_question", question_id=question_id))
|
||||
question: database.AllQuestions = get_question(database.AllQuestions, question_id)
|
||||
if "application/json" in request.accept_mimetypes.values():
|
||||
@ -54,7 +63,7 @@ def query_questions():
|
||||
response_dict["rows"].append({
|
||||
"id": question.question_id,
|
||||
"question_id": question.question_id,
|
||||
"question": question.question,
|
||||
"question": question.question_text,
|
||||
"answer": question.answer,
|
||||
"multiple_choice": getattr(question, "multiple_choice", None) is not None,
|
||||
"hidden_answer": getattr(question, "hidden_answer", None) is not None,
|
||||
|
@ -4,7 +4,7 @@
|
||||
<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 }}">
|
||||
<input id="question_text" name="question_text" type="text" class="form-control" value="{{ question.question_text }}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="answer">Answer</label>
|
||||
@ -16,43 +16,47 @@
|
||||
</div>
|
||||
{% if question.multiple_choice is not none %}
|
||||
<label class="mt-3">Multiple Choice</label>
|
||||
<div class="container border mb-1">
|
||||
<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>
|
||||
<option {% if question.multiple_choice.multiple_choice_difficulty is none %}selected=""{% endif %}>None</option>
|
||||
<option {% if question.multiple_choice.multiple_choice_difficulty == 1 %}selected=""{% endif %} value="1">Easy</option>
|
||||
<option {% if question.multiple_choice.multiple_choice_difficulty == 2 %}selected=""{% endif %} value="2">Medium</option>
|
||||
<option {% if question.multiple_choice.multiple_choice_difficulty == 3 %}selected=""{% endif %} value="3">Hard</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Wrong Answers</label>
|
||||
<ul class="list-group">
|
||||
<ul id="wrong_answer_list" class="list-group">
|
||||
{% for answer in question.multiple_choice.wrong_answers %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center wrong_answer">
|
||||
<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>
|
||||
<button class="btn" type="button" onclick="remove_item($(this).parent())"><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>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if question.hidden_answer is not none %}
|
||||
<label class="mt-3">Hidden Answer</label>
|
||||
<div class="container border mb-1">
|
||||
<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>
|
||||
<option {% if question.hidden_answer.hidden_answer_difficulty is none %}selected=""{% endif %}>None</option>
|
||||
<option {% if question.hidden_answer.hidden_answer_difficulty == 1 %}selected=""{% endif %} value="1">Easy</option>
|
||||
<option {% if question.hidden_answer.hidden_answer_difficulty == 2 %}selected=""{% endif %} value="2">Medium</option>
|
||||
<option {% if question.hidden_answer.hidden_answer_difficulty == 3 %}selected=""{% endif %} value="3">Hard</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<button id="save" name="save" type="submit" class="btn btn-primary">Save</button>
|
||||
</form>
|
||||
@ -61,7 +65,28 @@
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$("#add_wrong_answer").on("click", () => {
|
||||
|
||||
let item = $("<li>")
|
||||
.addClass("list-group-item d-flex justify-content-between align-items-center wrong_answer")
|
||||
.append($("<input>")
|
||||
.attr("name", "wrong_answers")
|
||||
.addClass("form-control"))
|
||||
.append();
|
||||
let btn = $("<button>")
|
||||
.attr("type", "button")
|
||||
.addClass("btn")
|
||||
.on("click", () => {
|
||||
remove_item(item);
|
||||
})
|
||||
.append($("<i>")
|
||||
.addClass("fas fa-times"));
|
||||
item.append(btn);
|
||||
$("#wrong_answer_list").append(item);
|
||||
})
|
||||
|
||||
function remove_item(element) {
|
||||
if ($("#wrong_answer_list").children().length > 1) {
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -5,7 +5,7 @@ from QuizTheWord import database
|
||||
from QuizTheWord.admin import admin
|
||||
|
||||
app = Flask(__name__)
|
||||
environment_configuration = os.environ['CONFIGURATION_SETUP']
|
||||
environment_configuration = os.environ.get('CONFIGURATION_SETUP', "QuizTheWord.config.Development")
|
||||
with app.app_context():
|
||||
app.config.from_object(environment_configuration)
|
||||
user_datastore = SQLAlchemySessionUserDatastore(database.get_session(), database.User, database.Role)
|
||||
|
@ -21,11 +21,11 @@ class Production(Config):
|
||||
DEBUG = False
|
||||
DB_SOCKET_DIR = environ.get("DB_SOCKET_DIR", "/cloudsql")
|
||||
CLOUD_SQL_CONNECTION_NAME = environ.get("CLOUD_SQL_CONNECTION_NAME")
|
||||
DB_URL = f"postgres+psycopg2://{Config.DB_USER}:{Config.DB_PASSWORD}@{Config.DB_HOST}:{Config.DB_PORT}/{Config.DB_NAME}?host={DB_SOCKET_DIR}/{CLOUD_SQL_CONNECTION_NAME}"
|
||||
DB_URL = f"postgresql+psycopg2://{Config.DB_USER}:{Config.DB_PASSWORD}@{Config.DB_HOST}:{Config.DB_PORT}/{Config.DB_NAME}?host={DB_SOCKET_DIR}/{CLOUD_SQL_CONNECTION_NAME}"
|
||||
|
||||
|
||||
class Development(Config):
|
||||
FLASK_ENV = "development"
|
||||
DEBUG = True
|
||||
TESTING = True
|
||||
DB_URL = f"postgres+psycopg2://{Config.DB_USER}:{Config.DB_PASSWORD}@{Config.DB_HOST}:{Config.DB_PORT}/{Config.DB_NAME}"
|
||||
DB_URL = f"postgresql+psycopg2://{Config.DB_USER}:{Config.DB_PASSWORD}@{Config.DB_HOST}:{Config.DB_PORT}/{Config.DB_NAME}"
|
||||
|
@ -69,7 +69,7 @@ class AllQuestions(Base):
|
||||
__tablename__ = "all_questions"
|
||||
|
||||
question_id = Column(Integer, primary_key=True, nullable=False)
|
||||
question = Column(String)
|
||||
question_text = Column(String)
|
||||
answer = Column(String)
|
||||
addresses = Column(String)
|
||||
|
||||
@ -78,7 +78,7 @@ class AllQuestions(Base):
|
||||
|
||||
def __init__(self, question_id, question, answer, addresses):
|
||||
self.question_id = question_id
|
||||
self.question = question
|
||||
self.question_text = question
|
||||
self.answer = answer
|
||||
self.addresses = addresses
|
||||
|
||||
@ -88,7 +88,7 @@ class AllQuestions(Base):
|
||||
def get_dict(self):
|
||||
result = {
|
||||
"question_id": self.question_id,
|
||||
"question": self.question,
|
||||
"question": self.question_text,
|
||||
"answer": self.answer,
|
||||
"addresses": self.addresses,
|
||||
}
|
||||
@ -103,18 +103,18 @@ class HiddenAnswer(Base):
|
||||
__tablename__ = "category_hidden_answer"
|
||||
|
||||
question_id = Column(Integer, ForeignKey("all_questions.question_id"), primary_key=True)
|
||||
difficulty = Column(Integer)
|
||||
hint = Column(JSON)
|
||||
hidden_answer_difficulty = Column(Integer)
|
||||
hidden_answer_hint = Column(JSON)
|
||||
|
||||
all_question_relationship = relationship("AllQuestions", lazy="joined", back_populates="hidden_answer")
|
||||
question = association_proxy("all_question_relationship", "question")
|
||||
question_text = association_proxy("all_question_relationship", "question_text")
|
||||
answer = association_proxy("all_question_relationship", "answer")
|
||||
addresses = association_proxy("all_question_relationship", "addresses")
|
||||
|
||||
def __init__(self, question_id, difficulty, hint, base_question):
|
||||
self.question_id = question_id
|
||||
self.difficulty = difficulty
|
||||
self.hint = hint
|
||||
self.hidden_answer_difficulty = difficulty
|
||||
self.hidden_answer_hint = hint
|
||||
self.all_question_relationship = base_question
|
||||
|
||||
def __repr__(self):
|
||||
@ -123,8 +123,8 @@ class HiddenAnswer(Base):
|
||||
def get_dict(self):
|
||||
return {
|
||||
"question_id": self.question_id,
|
||||
"difficulty": self.difficulty,
|
||||
"hint": self.hint,
|
||||
"difficulty": self.hidden_answer_difficulty,
|
||||
"hint": self.hidden_answer_hint,
|
||||
}
|
||||
|
||||
|
||||
@ -132,19 +132,19 @@ class MultipleChoice(Base):
|
||||
__tablename__ = "category_multiple_choice"
|
||||
|
||||
question_id = Column(Integer, ForeignKey("all_questions.question_id"), primary_key=True)
|
||||
difficulty = Column(Integer)
|
||||
hint = Column(JSON)
|
||||
multiple_choice_difficulty = Column(Integer)
|
||||
multiple_choice_hint = Column(JSON)
|
||||
wrong_answers = Column(ARRAY(String))
|
||||
|
||||
all_question_relationship = relationship("AllQuestions", lazy="joined", back_populates="multiple_choice")
|
||||
question = association_proxy("all_question_relationship", "question")
|
||||
question_text = association_proxy("all_question_relationship", "question_text")
|
||||
answer = association_proxy("all_question_relationship", "answer")
|
||||
addresses = association_proxy("all_question_relationship", "addresses")
|
||||
|
||||
def __init__(self, question_id, difficulty, hint, wrong_answers, base_question):
|
||||
self.question_id = question_id
|
||||
self.difficulty = difficulty
|
||||
self.hint = hint
|
||||
self.multiple_choice_difficulty = difficulty
|
||||
self.multiple_choice_hint = hint
|
||||
self.wrong_answers = wrong_answers
|
||||
self.all_question_relationship = base_question
|
||||
self.answer_list = None
|
||||
@ -160,8 +160,8 @@ class MultipleChoice(Base):
|
||||
def get_dict(self):
|
||||
return {
|
||||
"question_id": self.question_id,
|
||||
"difficulty": self.difficulty,
|
||||
"hint": self.hint,
|
||||
"difficulty": self.multiple_choice_difficulty,
|
||||
"hint": self.multiple_choice_hint,
|
||||
"wrong_answers": self.wrong_answers,
|
||||
}
|
||||
|
||||
@ -205,20 +205,20 @@ Optional[Union[MultipleChoice, HiddenAnswer, AllQuestions]]:
|
||||
def get_random_question_of_difficulty(category: Union[Type[MultipleChoice], Type[HiddenAnswer]],
|
||||
difficulty: Literal[1, 2, 3]):
|
||||
session = get_session()
|
||||
return session.query(category).filter(category.difficulty == difficulty).order_by(func.random()).first()
|
||||
return session.query(category).filter(category.hidden_answer_difficulty == difficulty).order_by(func.random()).first()
|
||||
|
||||
|
||||
def get_random_hidden_answer(difficulty: Optional[Literal[1, 2, 3]] = None) -> HiddenAnswer:
|
||||
session = get_session()
|
||||
if difficulty is not None:
|
||||
return session.query(HiddenAnswer).filter(HiddenAnswer.difficulty == difficulty).order_by(func.random()).first()
|
||||
return session.query(HiddenAnswer).filter(HiddenAnswer.hidden_answer_difficulty == difficulty).order_by(func.random()).first()
|
||||
return session.query(HiddenAnswer).order_by(func.random()).first()
|
||||
|
||||
|
||||
def get_random_multiple_choice(difficulty: Optional[Literal[1, 2, 3]] = None) -> MultipleChoice:
|
||||
session = get_session()
|
||||
if difficulty is not None:
|
||||
return session.query(MultipleChoice).filter(MultipleChoice.difficulty == difficulty).order_by(
|
||||
return session.query(MultipleChoice).filter(MultipleChoice.multiple_choice_difficulty == difficulty).order_by(
|
||||
func.random()).first()
|
||||
return session.query(MultipleChoice).order_by(func.random()).first()
|
||||
|
||||
@ -252,10 +252,14 @@ def query_all_questions(offset, limit, query: dict = None, sort=None, order=None
|
||||
return questions, count
|
||||
|
||||
|
||||
def update_question(question_id, question_text, answer, addresses):
|
||||
def update_question(question_id, data):
|
||||
session = get_session()
|
||||
question: AllQuestions = session.query(AllQuestions).get(question_id)
|
||||
question.question = question_text
|
||||
question.answer = answer
|
||||
question.addresses = addresses
|
||||
for column in data.keys():
|
||||
if column in AllQuestions.__table__.columns:
|
||||
setattr(question, column, data[column])
|
||||
if column in MultipleChoice.__table__.columns:
|
||||
setattr(question.multiple_choice, column, data[column])
|
||||
if column in HiddenAnswer.__table__.columns:
|
||||
setattr(question.hidden_answer, column, data[column])
|
||||
session.commit()
|
||||
|
@ -5,7 +5,7 @@
|
||||
<h1 class="title">Quiz The Word</h1>
|
||||
<div id="easy-question" class="container-md align-content-center question">
|
||||
<div class="card question-text">
|
||||
<p id="easy-question">{{ easy.question }}</p>
|
||||
<p id="easy-question">{{ easy.question_text }}</p>
|
||||
<button class="btn btn-secondary show-answer" onclick="showAnswer()">Show Answer</button>
|
||||
<p id="easy-answer" class="answer">{{ easy.answer }}</p>
|
||||
<div id="easy-bible-verses">{{ easy.addresses }}</div>
|
||||
@ -13,7 +13,7 @@
|
||||
</div>
|
||||
<div id="medium-question" class="container-md align-content-center question" style="display: none">
|
||||
<div class="card question-text">
|
||||
<p id="medium-question">{{ medium.question }}</p>
|
||||
<p id="medium-question">{{ medium.question_text }}</p>
|
||||
<button class="btn btn-secondary show-answer" onclick="showAnswer()">Show Answer</button>
|
||||
<p id="medium-answer" class="answer">{{ medium.answer }}</p>
|
||||
<div id="medium-bible-verses">{{ medium.addresses }}</div>
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<div id="hard-question" class="container-md align-content-center question" style="display: none">
|
||||
<div class="card question-text">
|
||||
<p id="hard-question">{{ hard.question }}</p>
|
||||
<p id="hard-question">{{ hard.question_text }}</p>
|
||||
<button class="btn btn-secondary show-answer" onclick="showAnswer()">Show Answer</button>
|
||||
<p id="hard-answer" class="answer">{{ hard.answer }}</p>
|
||||
<div id="hard-bible-verses">{{ hard.addresses }}</div>
|
||||
|
@ -5,14 +5,10 @@
|
||||
<h1 class="title">Quiz The Word</h1>
|
||||
<div id="easy-question" class="container-md align-content-center question">
|
||||
<div class="card question-text">
|
||||
<p id="easy-question">{{ easy.question }}</p>
|
||||
<button id="{{ easy.question_id }}-0" class="btn btn-secondary m-1" onclick="checkAnswer({{ easy.question_id }}, 0, '{{ easy.answer_list[0] }}')">{{ easy.answer_list[0] }}</button>
|
||||
<button id="{{ easy.question_id }}-1" class="btn btn-secondary m-1" onclick="checkAnswer({{ easy.question_id }}, 1, '{{ easy.answer_list[1] }}')">{{ easy.answer_list[1] }}</button>
|
||||
<button id="{{ easy.question_id }}-2" class="btn btn-secondary m-1" onclick="checkAnswer({{ easy.question_id }}, 2, '{{ easy.answer_list[2] }}')">{{ easy.answer_list[2] }}</button>
|
||||
<button id="{{ easy.question_id }}-3" class="btn btn-secondary m-1" onclick="checkAnswer({{ easy.question_id }}, 3, '{{ easy.answer_list[3] }}')">{{ easy.answer_list[3] }}</button>
|
||||
{# <button class="btn btn-secondary show-answer" onclick="showAnswer()">Show Answer</button>#}
|
||||
{# <p id="easy-answer" class="answer">{{ easy.answer }}</p>#}
|
||||
{# <div id="easy-bible-verses">{{ easy.addresses }}</div>#}
|
||||
<p id="easy-question">{{ easy.question_text }}</p>
|
||||
{% for answer in easy.answer_list %}
|
||||
<button id="{{ easy.question_id }}-{{ loop.index0 }}" class="btn btn-secondary m-1" onclick="checkAnswer({{ easy.question_id }}, {{ loop.index0 }}, '{{ answer }}')">{{ answer }}</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -78,10 +74,5 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*function showAnswer() {
|
||||
$(".question:visible").find(".answer").css("display", "block");
|
||||
$(".show-answer:visible").css("display", "none");
|
||||
}*/
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
@ -9,3 +9,4 @@ python-dotenv==0.15.0
|
||||
scramp==1.2.0
|
||||
SQLAlchemy==1.3.23
|
||||
Werkzeug==1.0.1
|
||||
Flask-Security-Too~=4.0.0
|
||||
|
Loading…
Reference in New Issue
Block a user