diff --git a/classquiz/db/models.py b/classquiz/db/models.py index 829f867..496a46c 100644 --- a/classquiz/db/models.py +++ b/classquiz/db/models.py @@ -183,6 +183,7 @@ class PlayGame(BaseModel): game_mode: str | None current_question: int = -1 background_color: str | None + custom_field: str | None class GamePlayer(BaseModel): diff --git a/classquiz/helpers/__init__.py b/classquiz/helpers/__init__.py index 28f9eb8..4474484 100644 --- a/classquiz/helpers/__init__.py +++ b/classquiz/helpers/__init__.py @@ -29,9 +29,18 @@ async def get_meili_data(quiz: Quiz) -> dict: } -async def generate_spreadsheet(quiz_results: dict, quiz: Quiz) -> BytesIO: +async def generate_spreadsheet(quiz_results: dict, quiz: Quiz, player_fields: dict) -> BytesIO: storage = BytesIO() workbook = xlsxwriter.Workbook(storage, {"in_memory": True}) + player_worksheet = workbook.add_worksheet() + player_worksheet.name = "Players" + player_worksheet.write(0, 0, "Username") + player_worksheet.write(0, 1, "Score") + player_worksheet.write(0, 2, "Custom-Field") + for i, player in enumerate(player_fields.keys()): + player_worksheet.write(i + 1, 0, player) + player_worksheet.write(i + 1, 2, player_fields[player]) + worksheet = workbook.add_worksheet() worksheet.name = "Questions" worksheet.write(0, 0, "Question") diff --git a/classquiz/routers/quiz.py b/classquiz/routers/quiz.py index d63044a..24dd009 100644 --- a/classquiz/routers/quiz.py +++ b/classquiz/routers/quiz.py @@ -89,7 +89,11 @@ async def get_public_quiz(quiz_id: str): @router.post("/start/{quiz_id}") async def start_quiz( - quiz_id: str, game_mode: str, captcha_enabled: bool = True, user: User = Depends(get_current_user) + quiz_id: str, + game_mode: str, + captcha_enabled: bool = True, + custom_field: str | None = None, + user: User = Depends(get_current_user), ): try: quiz_id = uuid.UUID(quiz_id) @@ -101,6 +105,8 @@ async def start_quiz( if quiz is None: return JSONResponse(status_code=404, content={"detail": "quiz not found"}) game_pin = randint(10000000, 99999999) + if custom_field == "": + custom_field = None game = PlayGame( quiz_id=quiz_id, game_pin=str(game_pin), @@ -113,6 +119,7 @@ async def start_quiz( game_mode=game_mode, user_id=user.id, background_color=quiz.background_color, + custom_field=custom_field, ) await redis.set(f"game:{str(game.game_pin)}", game.json(), ex=18000) await redis.set(f"game_pin:{user.id}:{quiz_id}", game_pin, ex=18000) @@ -122,6 +129,7 @@ async def start_quiz( class CheckIfCaptchaEnabledResponse(BaseModel): enabled: bool game_mode: str | None + custom_field: str | None @router.get("/play/check_captcha/{game_pin}", response_model=CheckIfCaptchaEnabledResponse) @@ -131,9 +139,9 @@ async def check_if_captcha_enabled(game_pin: str): return JSONResponse(status_code=404, content={"detail": "game not found"}) game = PlayGame.parse_raw(game) if game.captcha_enabled: - return CheckIfCaptchaEnabledResponse(enabled=True, game_mode=game.game_mode) + return CheckIfCaptchaEnabledResponse(enabled=True, game_mode=game.game_mode, custom_field=game.custom_field) else: - return CheckIfCaptchaEnabledResponse(enabled=False, game_mode=game.game_mode) + return CheckIfCaptchaEnabledResponse(enabled=False, game_mode=game.game_mode, custom_field=game.custom_field) @router.get("/join/{game_pin}", deprecated=True) @@ -238,11 +246,14 @@ async def export_quiz_answers(export_token: str, game_pin: str): if data is None: raise HTTPException(status_code=404, detail="export token not found") data = json.loads(data) - game_data = PlayGame(**json.loads(await redis.get(f"game:{game_pin}"))) + data2 = await redis.get(f"game:{game_pin}") + game_data = PlayGame.parse_raw(data2) quiz = await Quiz.objects.get_or_none(id=game_data.quiz_id) if quiz is None: raise HTTPException(status_code=404, detail="quiz not found") - spreadsheet = await generate_spreadsheet(quiz=quiz, quiz_results=data) + + player_fields = await redis.hgetall(f"game:{game_pin}:player:custom_fields") + spreadsheet = await generate_spreadsheet(quiz=quiz, quiz_results=data, player_fields=player_fields) def iter_file(): yield from spreadsheet diff --git a/classquiz/socket_server/__init__.py b/classquiz/socket_server/__init__.py index 7691daa..c73d21f 100644 --- a/classquiz/socket_server/__init__.py +++ b/classquiz/socket_server/__init__.py @@ -43,6 +43,7 @@ class _JoinGameData(BaseModel): username: str game_pin: str captcha: str | None + custom_field: str | None @sio.event @@ -104,7 +105,11 @@ async def join_game(sid: str, data: dict): redis_res = GameSession.parse_raw(redis_res) await redis.set(f"game_session:{data.game_pin}:players:{data.username}", sid, ex=18000) await redis.sadd(f"game_session:{data.game_pin}:players", GamePlayer(username=data.username, sid=sid).json()) - print(GamePlayer(username=data.username, sid=sid).json()) + if data.custom_field == "": + data.custom_field = None + print(data.custom_field) + if data.custom_field is not None: + await redis.hset(f"game:{data.game_pin}:player:custom_fields", data.username, data.custom_field) # await redis.set( # f"game_session:{data.game_pin}", # GameSession(admin=redis_res.admin, game_id=redis_res.game_id, answers=[]).json(), diff --git a/frontend/src/lib/dashboard/start_game.svelte b/frontend/src/lib/dashboard/start_game.svelte index 5521f8d..978ab14 100644 --- a/frontend/src/lib/dashboard/start_game.svelte +++ b/frontend/src/lib/dashboard/start_game.svelte @@ -14,26 +14,26 @@ let captcha_selected = false; let selected_game_mode = 'kahoot'; let loading = false; + let custom_field = ''; const start_game = async (id: string) => { let res; loading = true; if (captcha_enabled && captcha_selected) { res = await fetch( - `/api/v1/quiz/start/${id}?captcha_enabled=True&game_mode=${selected_game_mode}`, + `/api/v1/quiz/start/${id}?captcha_enabled=True&game_mode=${selected_game_mode}&custom_field=${custom_field}`, { method: 'POST' } ); } else { res = await fetch( - `/api/v1/quiz/start/${id}?captcha_enabled=False&game_mode=${selected_game_mode}`, + `/api/v1/quiz/start/${id}?captcha_enabled=False&game_mode=${selected_game_mode}&custom_field=${custom_field}`, { method: 'POST' } ); } - if (res.status !== 200) { alertModal.set({ open: true, @@ -111,6 +111,9 @@

+
+ +