Most dependencies updated, mostly tested
This commit is contained in:
Generated
+1200
-972
File diff suppressed because it is too large
Load Diff
+25
-12
@@ -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):
|
||||
|
||||
@@ -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", {})
|
||||
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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}"),
|
||||
|
||||
Reference in New Issue
Block a user