✨ Fixed #51
This commit is contained in:
@@ -99,10 +99,6 @@ class TokenData(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class PlayGame(BaseModel):
|
class PlayGame(BaseModel):
|
||||||
"""
|
|
||||||
For JWT
|
|
||||||
"""
|
|
||||||
|
|
||||||
quiz_id: uuid.UUID | str
|
quiz_id: uuid.UUID | str
|
||||||
description: str
|
description: str
|
||||||
title: str
|
title: str
|
||||||
@@ -110,6 +106,7 @@ class PlayGame(BaseModel):
|
|||||||
game_id: uuid.UUID
|
game_id: uuid.UUID
|
||||||
game_pin: str
|
game_pin: str
|
||||||
started: bool = False
|
started: bool = False
|
||||||
|
captcha_enabled: bool = False
|
||||||
|
|
||||||
|
|
||||||
class GamePlayer(BaseModel):
|
class GamePlayer(BaseModel):
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from random import randint
|
|||||||
from classquiz.helpers import get_meili_data
|
from classquiz.helpers import get_meili_data
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError, BaseModel
|
||||||
import bleach
|
import bleach
|
||||||
|
|
||||||
from classquiz.auth import get_current_user
|
from classquiz.auth import get_current_user
|
||||||
@@ -76,7 +76,7 @@ async def get_public_quiz(quiz_id: str):
|
|||||||
|
|
||||||
|
|
||||||
@router.post("/start/{quiz_id}")
|
@router.post("/start/{quiz_id}")
|
||||||
async def start_quiz(quiz_id: str, user: User = Depends(get_current_user)):
|
async def start_quiz(quiz_id: str, captcha_enabled: bool = True, user: User = Depends(get_current_user)):
|
||||||
try:
|
try:
|
||||||
quiz_id = uuid.UUID(quiz_id)
|
quiz_id = uuid.UUID(quiz_id)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
@@ -94,11 +94,24 @@ async def start_quiz(quiz_id: str, user: User = Depends(get_current_user)):
|
|||||||
game_id=uuid.uuid4(),
|
game_id=uuid.uuid4(),
|
||||||
title=quiz.title,
|
title=quiz.title,
|
||||||
description=quiz.description,
|
description=quiz.description,
|
||||||
|
captcha_enabled=captcha_enabled,
|
||||||
)
|
)
|
||||||
await redis.set(f"game:{str(game.game_pin)}", (game.json()), ex=18000)
|
await redis.set(f"game:{str(game.game_pin)}", (game.json()), ex=18000)
|
||||||
return {**quiz.dict(exclude={"id"}), **game.dict(exclude={"questions"})}
|
return {**quiz.dict(exclude={"id"}), **game.dict(exclude={"questions"})}
|
||||||
|
|
||||||
|
|
||||||
|
class CheckIfCaptchaEnabledResponse(BaseModel):
|
||||||
|
enabled: bool
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/play/check_captcha/{game_pin}", response_model=CheckIfCaptchaEnabledResponse)
|
||||||
|
async def check_if_captcha_enabled(game_pin: str):
|
||||||
|
game = await redis.get(f"game:{game_pin}")
|
||||||
|
if game is None:
|
||||||
|
return JSONResponse(status_code=404, content={"detail": "game not found"})
|
||||||
|
return CheckIfCaptchaEnabledResponse(**{"enabled": json.loads(game)["captcha_enabled"]})
|
||||||
|
|
||||||
|
|
||||||
@router.get("/join/{game_pin}")
|
@router.get("/join/{game_pin}")
|
||||||
async def get_game_id(game_pin: str):
|
async def get_game_id(game_pin: str):
|
||||||
redis_res = (await redis.get(f"game:{game_pin}")).decode()
|
redis_res = (await redis.get(f"game:{game_pin}")).decode()
|
||||||
|
|||||||
@@ -13,20 +13,21 @@ settings = settings()
|
|||||||
@sio.event
|
@sio.event
|
||||||
async def join_game(sid, data):
|
async def join_game(sid, data):
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session:
|
||||||
try:
|
redis_res = await redis.get(f"game:{data['game_pin']}")
|
||||||
async with session.post(
|
if json.loads(redis_res)["captcha_enabled"]:
|
||||||
"https://hcaptcha.com/siteverify",
|
try:
|
||||||
data={"response": data["captcha"], "secret": settings.hcaptcha_key},
|
async with session.post(
|
||||||
) as resp:
|
"https://hcaptcha.com/siteverify",
|
||||||
resp_data = await resp.json()
|
data={"response": data["captcha"], "secret": settings.hcaptcha_key},
|
||||||
if not resp_data["success"]:
|
) as resp:
|
||||||
print("CAPTCHA FAILED")
|
resp_data = await resp.json()
|
||||||
return
|
if not resp_data["success"]:
|
||||||
except KeyError:
|
print("CAPTCHA FAILED")
|
||||||
print("CAPTCHA FAILED")
|
return
|
||||||
|
except KeyError:
|
||||||
|
print("CAPTCHA FAILED")
|
||||||
|
|
||||||
return
|
return
|
||||||
redis_res = await redis.get(f"game:{data['game_pin']}")
|
|
||||||
if redis_res is None:
|
if redis_res is None:
|
||||||
await sio.emit("game_not_found", room=sid)
|
await sio.emit("game_not_found", room=sid)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -44,17 +44,22 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let captcha_resp: string;
|
let captcha_resp: string;
|
||||||
try {
|
const captcha_enabled = (
|
||||||
const { response } = await hcaptcha.execute(hcaptchaWidgetID, {
|
await (await fetch(`/api/v1/quiz/play/check_captcha/${game_pin}`)).json()
|
||||||
async: true
|
).enabled;
|
||||||
});
|
if (captcha_enabled) {
|
||||||
captcha_resp = response;
|
try {
|
||||||
} catch (e) {
|
const { response } = await hcaptcha.execute(hcaptchaWidgetID, {
|
||||||
if (import.meta.env.VITE_SENTRY !== null) {
|
async: true
|
||||||
Sentry.captureException(e);
|
});
|
||||||
|
captcha_resp = response;
|
||||||
|
} catch (e) {
|
||||||
|
if (import.meta.env.VITE_SENTRY !== null) {
|
||||||
|
Sentry.captureException(e);
|
||||||
|
}
|
||||||
|
alert('Captcha failed, reloading the page probably helps!');
|
||||||
|
window.location.reload();
|
||||||
}
|
}
|
||||||
alert('Captcha failed, reloading the page probably helps!');
|
|
||||||
window.location.reload();
|
|
||||||
}
|
}
|
||||||
socket.emit('join_game', {
|
socket.emit('join_game', {
|
||||||
username: username,
|
username: username,
|
||||||
|
|||||||
@@ -48,12 +48,17 @@
|
|||||||
|
|
||||||
const startGame = async (id: string): Promise<void> => {
|
const startGame = async (id: string): Promise<void> => {
|
||||||
console.log('start game', id);
|
console.log('start game', id);
|
||||||
const res = await fetch(`/api/v1/quiz/start/${id}`, {
|
let res;
|
||||||
method: 'POST'
|
if (window.confirm('Do you want to enable the captcha for players?')) {
|
||||||
// headers: {
|
res = await fetch(`/api/v1/quiz/start/${id}?captcha_enabled=True`, {
|
||||||
// 'Content-Type': 'application/json'
|
method: 'POST'
|
||||||
// }
|
});
|
||||||
});
|
} else {
|
||||||
|
res = await fetch(`/api/v1/quiz/start/${id}?captcha_enabled=False`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
alert('Failed to start game!');
|
alert('Failed to start game!');
|
||||||
console.error(`Failed to start game, ${await res.text()}`);
|
console.error(`Failed to start game, ${await res.text()}`);
|
||||||
|
|||||||
@@ -64,12 +64,16 @@
|
|||||||
|
|
||||||
const startGame = async (id: string): Promise<void> => {
|
const startGame = async (id: string): Promise<void> => {
|
||||||
console.log('start game', id);
|
console.log('start game', id);
|
||||||
const res = await fetch(`/api/v1/quiz/start/${id}`, {
|
let res;
|
||||||
method: 'POST'
|
if (window.confirm('Do you want to enable the captcha for players?')) {
|
||||||
// headers: {
|
res = await fetch(`/api/v1/quiz/start/${id}?captcha_enabled=True`, {
|
||||||
// 'Content-Type': 'application/json'
|
method: 'POST'
|
||||||
// }
|
});
|
||||||
});
|
} else {
|
||||||
|
res = await fetch(`/api/v1/quiz/start/${id}?captcha_enabled=False`, {
|
||||||
|
method: 'POST'
|
||||||
|
});
|
||||||
|
}
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw new Error('Failed to start game');
|
throw new Error('Failed to start game');
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user