Bug fixes (double submission, escaping of ><! in answers, further redis docs
This commit is contained in:
@@ -11,15 +11,27 @@ import asyncpg.exceptions
|
||||
import bleach
|
||||
from fastapi import APIRouter, HTTPException, Depends
|
||||
from pydantic import BaseModel
|
||||
import html
|
||||
|
||||
from classquiz.config import settings, redis, storage, meilisearch, ALLOWED_TAGS_FOR_QUIZ, arq
|
||||
from classquiz.config import (
|
||||
settings,
|
||||
redis,
|
||||
storage,
|
||||
meilisearch,
|
||||
ALLOWED_TAGS_FOR_QUIZ,
|
||||
arq,
|
||||
)
|
||||
from classquiz.db.models import Quiz, QuizInput, User, QuizQuestionType, StorageItem
|
||||
from classquiz.auth import get_current_user
|
||||
import os
|
||||
from datetime import datetime
|
||||
from uuid import UUID
|
||||
|
||||
from classquiz.helpers import get_meili_data, check_image_string, extract_image_ids_from_quiz
|
||||
from classquiz.helpers import (
|
||||
get_meili_data,
|
||||
check_image_string,
|
||||
extract_image_ids_from_quiz,
|
||||
)
|
||||
from classquiz.storage.errors import DeletionFailedError
|
||||
|
||||
settings = settings()
|
||||
@@ -79,15 +91,15 @@ async def finish_edit(edit_id: str, quiz_input: QuizInput):
|
||||
quiz_input.background_color = bleach.clean(quiz_input.background_color, tags=[], strip=True)
|
||||
|
||||
for i, question in enumerate(quiz_input.questions):
|
||||
if question.type == QuizQuestionType.ABCD:
|
||||
if question.type == QuizQuestionType.ABCD or question.type == QuizQuestionType.VOTING:
|
||||
for i2, answer in enumerate(question.answers):
|
||||
if answer.color is not None:
|
||||
quiz_input.questions[i].answers[i2].color = bleach.clean(answer.color, tags=[], strip=True)
|
||||
if answer.answer == "":
|
||||
quiz_input.questions[i].answers[i2].answer = None
|
||||
if answer.answer is not None:
|
||||
quiz_input.questions[i].answers[i2].answer = bleach.clean(
|
||||
answer.answer, tags=ALLOWED_TAGS_FOR_QUIZ, strip=True
|
||||
quiz_input.questions[i].answers[i2].answer = html.unescape(
|
||||
bleach.clean(answer.answer, tags=ALLOWED_TAGS_FOR_QUIZ, strip=True)
|
||||
)
|
||||
|
||||
images_to_delete = []
|
||||
|
||||
@@ -25,7 +25,11 @@ from classquiz.db.models import (
|
||||
from pydantic import BaseModel, ValidationError
|
||||
from datetime import datetime
|
||||
|
||||
from classquiz.socket_server.helpers import check_answer, check_captcha
|
||||
from classquiz.socket_server.helpers import (
|
||||
check_answer,
|
||||
check_captcha,
|
||||
has_already_answered,
|
||||
)
|
||||
from .models import (
|
||||
RejoinGameData,
|
||||
JoinGameData,
|
||||
@@ -286,7 +290,12 @@ async def submit_answer(sid: str, data: dict):
|
||||
return
|
||||
data.answer = str(data.answer)
|
||||
session = await get_session(sid, sio)
|
||||
question_index = int(float(data.question_index))
|
||||
game_data = await PlayGame.get_from_redis(session["game_pin"])
|
||||
already_answered = await has_already_answered(session["game_pin"], question_index, session["username"])
|
||||
if already_answered:
|
||||
await sio.emit("already_replied", room=sid)
|
||||
return
|
||||
(answer_right, answer) = check_answer(game_data, data)
|
||||
latency = int(float(session["ping"]))
|
||||
time_q_started = datetime.fromisoformat(await redis.get(f"game:{session['game_pin']}:current_time"))
|
||||
@@ -295,7 +304,7 @@ async def submit_answer(sid: str, data: dict):
|
||||
if answer_right:
|
||||
score = calculate_score(
|
||||
abs(diff) - latency,
|
||||
int(float(game_data.questions[int(float(data.question_index))].time)),
|
||||
int(float(game_data.questions[question_index].time)),
|
||||
)
|
||||
if score > 1000:
|
||||
score = 1000
|
||||
|
||||
@@ -10,6 +10,7 @@ from classquiz.db.models import (
|
||||
ABCDQuizAnswer,
|
||||
VotingQuizAnswer,
|
||||
RangeQuizAnswer,
|
||||
AnswerDataList,
|
||||
)
|
||||
from classquiz.socket_server.models import SubmitAnswerData
|
||||
from .models import SubmitAnswerDataOrderType
|
||||
@@ -131,3 +132,12 @@ def check_check_question(answer: str, answers: list[ABCDQuizAnswer]) -> bool:
|
||||
if a.right:
|
||||
correct_string += str(i)
|
||||
return bool(correct_string == answer)
|
||||
|
||||
|
||||
async def has_already_answered(game_pin: str, q_index: int, username: str) -> bool:
|
||||
answers = await AnswerDataList.get_redis_or_empty(game_pin, q_index)
|
||||
if answers is None:
|
||||
return False
|
||||
else:
|
||||
answers = list(filter(lambda a: a.username == username, answers.root))
|
||||
return len(answers) > 0
|
||||
|
||||
@@ -82,6 +82,9 @@ SPDX-License-Identifier: MPL-2.0
|
||||
});
|
||||
|
||||
const selectAnswer = (answer: string) => {
|
||||
if (selected_answer !== undefined) {
|
||||
return;
|
||||
}
|
||||
selected_answer = answer;
|
||||
//timer_res = '0';
|
||||
socket.emit('submit_answer', {
|
||||
@@ -262,7 +265,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<input
|
||||
type="text"
|
||||
bind:value={text_input}
|
||||
disabled={selected_answer}
|
||||
disabled={selected_answer !== undefined}
|
||||
class="bg-gray-50 focus:ring text-gray-900 rounded-lg focus:ring-blue-500 block w-full p-2 dark:bg-gray-700 dark:text-white dark:focus:ring-blue-500 outline-hidden transition text-center disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
/>
|
||||
</div>
|
||||
@@ -271,7 +274,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div class="w-1/3">
|
||||
<BrownButton
|
||||
type="button"
|
||||
disabled={selected_answer}
|
||||
disabled={selected_answer !== undefined}
|
||||
on:click={() => {
|
||||
selectAnswer(text_input);
|
||||
}}
|
||||
@@ -367,7 +370,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div class="w-full mt-2">
|
||||
<BrownButton
|
||||
type="button"
|
||||
disabled={selected_answer}
|
||||
disabled={selected_answer !== undefined}
|
||||
on:click={() => {
|
||||
select_complex_answer(question.answers);
|
||||
}}>{$t('words.submit')}</BrownButton
|
||||
@@ -389,7 +392,7 @@ SPDX-License-Identifier: MPL-2.0
|
||||
<div class="flex justify-center h-[5%]">
|
||||
<div class="w-1/2">
|
||||
<BrownButton
|
||||
disabled={!selected_answer}
|
||||
disabled={selected_answer !== undefined}
|
||||
on:click={() => selectAnswer(selected_answer)}
|
||||
>{$t('words.submit')}
|
||||
</BrownButton>
|
||||
|
||||
@@ -134,3 +134,17 @@ data: `{PLAYER_NAME} = {CUSTOM_FIELD_VALUE}`
|
||||
{cqc_code} is the code used to join with a **C**lass**Q**uiz**C**ontroller
|
||||
|
||||
Only holds the game-pin
|
||||
|
||||
## game_in_lobby:{admin_user_id} [string]
|
||||
Set if game is waiting for players to join for the admin to enable remote control
|
||||
|
||||
model: GameInLobby
|
||||
|
||||
example:
|
||||
```json
|
||||
{
|
||||
"game_pin": "1234543",
|
||||
"quiz_title": "Some random title",
|
||||
"game_id": "uuid of game"
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user