# retoor <retoor@molodetz.nl>
from urllib.parse import quote
from fastapi import Request
from fastapi.responses import RedirectResponse
from devplacepy.database import get_table, resolve_by_slug
from devplacepy.responses import json_error, wants_json
from devplacepy.seo import base_seo_context
from devplacepy.services.pubsub import publish
from devplacepy.services.quiz import QuizError, store
from devplacepy.utils import is_admin, not_found
def quiz_topic(quiz_uid: str) -> str:
return f"public.quiz.{quiz_uid}"
async def notify_quiz(quiz_uid: str) -> None:
if not quiz_uid:
return
try:
await publish(quiz_topic(quiz_uid), {"kind": "update", "quiz_uid": quiz_uid})
except Exception:
pass
def load_quiz(slug: str, user: dict | None) -> dict:
quiz = resolve_by_slug(get_table("quizzes"), slug)
if not quiz or not store.can_view_quiz(quiz, user):
raise not_found("Quiz not found")
return quiz
def require_owner(quiz: dict, user: dict):
if not (store.is_quiz_owner(quiz, user) or is_admin(user)):
raise not_found("Quiz not found")
return quiz
def require_editor(quiz: dict, user: dict):
if not store.is_quiz_owner(quiz, user):
raise not_found("Quiz not found")
return quiz
def action_error(request: Request, message: str, redirect_url: str):
if wants_json(request):
return json_error(400, message)
separator = "&" if "?" in redirect_url else "?"
return RedirectResponse(
url=f"{redirect_url}{separator}error={quote(message)}", status_code=302
)
def quiz_seo(request: Request, title: str, description: str, robots: str = "index,follow", **extra):
return base_seo_context(
request,
title=title,
description=description,
robots=robots,
breadcrumbs=[
{"name": "Home", "url": "/feed"},
{"name": "Quizzes", "url": "/quizzes"},
*extra.pop("breadcrumbs", []),
],
**extra,
)
def quiz_url(quiz: dict) -> str:
return f"/quizzes/{quiz.get('slug') or quiz['uid']}"
__all__ = [
"QuizError",
"action_error",
"load_quiz",
"notify_quiz",
"quiz_seo",
"quiz_topic",
"quiz_url",
"require_editor",
"require_owner",
]