Most dependencies updated, mostly tested

This commit is contained in:
Mawoka
2025-05-20 16:00:03 +02:00
parent 03e85f8586
commit f86832892d
7 changed files with 1246 additions and 1004 deletions
Generated
+1200 -972
View File
File diff suppressed because it is too large Load Diff
+25 -12
View File
@@ -10,7 +10,7 @@ from typing import Optional
import ormar
from ormar import ReferentialAction
from pydantic import BaseModel, Json, field_validator, ConfigDict, RootModel
from pydantic import BaseModel, Json, field_validator, ConfigDict, RootModel, ValidationInfo
from enum import Enum
from . import metadata, database
from .quiztivity import QuizTivityPage
@@ -102,7 +102,7 @@ class UserSession(ormar.Model):
class ABCDQuizAnswer(BaseModel):
right: bool
answer: str
color: str | None
color: str | None = None
class RangeQuizAnswer(BaseModel):
@@ -115,7 +115,7 @@ class RangeQuizAnswer(BaseModel):
class VotingQuizAnswer(BaseModel):
answer: str
image: str | None = None
color: str | None
color: str | None = None
class QuizQuestionType(str, Enum):
@@ -141,20 +141,20 @@ class QuizQuestion(BaseModel):
image: str | None = None
@field_validator("answers")
def answers_not_none_if_abcd_type(cls, v, values):
if values["type"] == QuizQuestionType.ABCD and not isinstance(v[0], ABCDQuizAnswer):
def answers_not_none_if_abcd_type(cls, v, info: ValidationInfo):
if info.data["type"] == QuizQuestionType.ABCD and not isinstance(v[0], ABCDQuizAnswer):
raise ValueError("Answers can't be none if type is ABCD")
if values["type"] == QuizQuestionType.RANGE and not isinstance(v, RangeQuizAnswer):
if info.data["type"] == QuizQuestionType.RANGE and not isinstance(v, RangeQuizAnswer):
raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE")
if values["type"] == QuizQuestionType.VOTING and not isinstance(v[0], VotingQuizAnswer):
if info.data["type"] == QuizQuestionType.VOTING and not isinstance(v[0], VotingQuizAnswer):
raise ValueError("Answer must be from type VotingQuizAnswer if type is VOTING")
if values["type"] == QuizQuestionType.TEXT and not isinstance(v[0], TextQuizAnswer):
if info.data["type"] == QuizQuestionType.TEXT and not isinstance(v[0], TextQuizAnswer):
raise ValueError("Answer must be from type TextQuizAnswer if type is TEXT")
if values["type"] == QuizQuestionType.ORDER and not isinstance(v[0], VotingQuizAnswer):
if info.data["type"] == QuizQuestionType.ORDER and not isinstance(v[0], VotingQuizAnswer):
raise ValueError("Answer must be from type VotingQuizAnswer if type is ORDER")
if values["type"] == QuizQuestionType.SLIDE and not isinstance(v, str):
if info.data["type"] == QuizQuestionType.SLIDE and not isinstance(v, str):
raise ValueError("Answer must be from type SlideElement if type is SLIDE")
if values["type"] == QuizQuestionType.CHECK and not isinstance(v[0], ABCDQuizAnswer):
if info.data["type"] == QuizQuestionType.CHECK and not isinstance(v[0], ABCDQuizAnswer):
raise ValueError("Answers can't be none if type is CHECK")
return v
@@ -278,7 +278,20 @@ class AnswerData(BaseModel):
score: int
AnswerDataList = RootModel[list[AnswerData]]
class AnswerDataList(RootModel):
root: list[AnswerData]
def __iter__(self):
return iter(self.root)
def __getitem__(self, item):
return self.root(item)
def append(self, item):
self.root.append(item)
def __len__(self) -> int:
return len(self.root)
class GameInLobby(BaseModel):
+7 -7
View File
@@ -33,10 +33,10 @@ class _LastEdit(BaseModel):
class _ImageMetadata(BaseModel):
id: UUID | None = None
content_type: Optional[str]
width: Optional[int]
height: Optional[int]
resources: Optional[str]
content_type: Optional[str] = None
width: Optional[int] = None
height: Optional[int] = None
resources: Optional[str] = None
class _SampleQuestion(BaseModel):
@@ -130,8 +130,8 @@ class _Video(BaseModel):
startTime: float
endTime: float
service: str
full_url: Optional[str]
id: Optional[str]
full_url: Optional[str] = None
id: Optional[str] = None
class _Question(BaseModel):
@@ -143,7 +143,7 @@ class _Question(BaseModel):
choices: List[_Choice]
image: str | None = None
imageMetadata: _ImageMetadata | None = None
resources: Optional[str]
resources: Optional[str] = None
video: _Video
questionFormat: int
languageInfo: _LanguageInfo | None = None
@@ -64,7 +64,7 @@ async def submit_answer_fn(data_answer: int, game_pin: str, player_id: str, now:
answers = await set_answer(answers, game_pin=game_pin, data=answer_data, q_index=game.current_question)
player_count = await redis.scard(f"game_session:{game_pin}:players")
await sio.emit("player_answer", {})
if answers is not None and len(answers.__root__) == player_count:
if answers is not None and len(answers) == player_count:
await sio.emit("everyone_answered", {})
+1 -1
View File
@@ -51,7 +51,7 @@ async def export_quiz(quiz_id: uuid.UUID, user: User = Depends(get_current_user)
question["image"] = i
if quiz.cover_image is not None:
image_urls[-1] = quiz.cover_image
quiz.cover_image = -1
quiz.cover_image = "-1"
quiz_dict = quiz.model_dump()
del quiz_dict["user_id"], quiz_dict["id"]
quiz_dict["created_at"] = quiz_dict["created_at"].isoformat()
+1 -1
View File
@@ -275,7 +275,7 @@ async def voting_results(game_pin: str, api_key: str, as_array: bool = False):
answer_dict = {}
for answer in game.questions[game.current_question].answers:
answer_dict[answer.answer] = 0
for answer in answer_list.__root__:
for answer in answer_list:
answer_dict[answer.answer] += 1
if as_array:
return [answer_dict]
+11 -10
View File
@@ -24,7 +24,7 @@ from classquiz.db.models import (
AnswerDataList,
AnswerData,
)
from pydantic import BaseModel, ValidationError, field_validator
from pydantic import BaseModel, ValidationError, field_validator, ValidationInfo
from datetime import datetime
from classquiz.socket_server.export_helpers import save_quiz_to_storage
@@ -61,10 +61,10 @@ def calculate_score(z: float, t: int) -> int:
async def set_answer(answers, game_pin: str, q_index: int, data: AnswerData) -> AnswerDataList:
if answers is None:
answers = AnswerDataList(__root__=[data])
answers = AnswerDataList([data])
else:
answers = AnswerDataList.model_validate_json(answers)
answers.__root__.append(data)
answers.append(data)
await redis.set(
f"game_session:{game_pin}:{q_index}",
answers.model_dump_json(),
@@ -279,7 +279,7 @@ async def get_question_results(sid: str, data: dict):
if redis_res is None:
redis_res = []
else:
redis_res = AnswerDataList.model_validate_json(redis_res).model_dump()["__root__"]
redis_res = AnswerDataList.model_validate_json(redis_res).model_dump()
game_data = PlayGame.model_validate_json(await redis.get(f"game:{session['game_pin']}"))
game_data.question_show = False
await redis.set(f"game:{session['game_pin']}", game_data.model_dump_json())
@@ -303,13 +303,13 @@ class ReturnQuestion(QuizQuestion):
type: QuizQuestionType = QuizQuestionType.ABCD
@field_validator("answers")
def answers_not_none_if_abcd_type(cls, v, values):
if values["type"] == QuizQuestionType.ABCD and type(v[0]) is not ABCDQuizAnswerWithoutSolution:
def answers_not_none_if_abcd_type(cls, v, info: ValidationInfo):
if info.data["type"] == QuizQuestionType.ABCD and type(v[0]) is not ABCDQuizAnswerWithoutSolution:
raise ValueError("Answers can't be none if type is ABCD")
if values["type"] == QuizQuestionType.RANGE and type(v) is not RangeQuizAnswerWithoutSolution:
if info.data["type"] == QuizQuestionType.RANGE and type(v) is not RangeQuizAnswerWithoutSolution:
raise ValueError("Answer must be from type RangeQuizAnswer if type is RANGE")
# skipcq: PTC-W0047
if values["type"] == QuizQuestionType.VOTING and type(v[0]) is not VotingQuizAnswer:
if info.data["type"] == QuizQuestionType.VOTING and type(v[0]) is not VotingQuizAnswer:
pass
return v
@@ -358,7 +358,7 @@ class _SubmitAnswerDataOrderType(BaseModel):
class _SubmitAnswerData(BaseModel):
question_index: int
answer: str
answer: str | int
complex_answer: list[_SubmitAnswerDataOrderType] | None = None
@@ -371,6 +371,7 @@ async def submit_answer(sid: str, data: dict):
await sio.emit("error", room=sid)
print(e)
return
data.answer = str(data.answer)
session = await sio.get_session(sid)
game_data = PlayGame.model_validate_json(await redis.get(f"game:{session['game_pin']}"))
answer_right = False
@@ -447,7 +448,7 @@ async def submit_answer(sid: str, data: dict):
)
player_count = await redis.scard(f"game_session:{session['game_pin']}:players")
await sio.emit("player_answer", {})
if len(answers.__root__) == player_count:
if len(answers) == player_count:
# await sio.emit(
# "question_results",
# await redis.get(f"game_session:{session['game_pin']}:{data.question_index}"),