Security: - Nginx: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, CSP, Referrer-Policy, Permissions-Policy headers - Redis-backed login rate limiting (survives container restarts) - Admin litellm/models endpoint: api_key moved from GET query param to POST body - Nextcloud credentials moved from localStorage to sessionStorage (cleared on tab close) UX / Layout: - Login: unverified users see inline "Resend verification email" option - QuizPage mobile: TTS Listen button on its own row below question text - QuizPage mobile: Voice selector on its own row in header card (not squashed with timer) - QuizEditPage: scroll position preserved after saving a question edit Quiz Categories: - New QuizCategory model + quiz_categories table - category_id column added to quizzes table - GET/POST/DELETE /api/categories endpoints - Quizzes grouped by category in QuizzesPage; moderators can assign via 🏷 menu - Uncategorized section shown when categories exist Question Bank: - GET /api/questions/bank — search all questions across quizzes - POST /api/questions/from-bank — create new quiz from selected questions (copies, originals untouched) - QuestionBankPage: search, checkbox select, study modal, create quiz form - "Question Bank" link added to Navbar Search: - "View all N questions →" button expands to full question list - Each question has a Study button opening in-place modal with study mode - Summary view shows 2 questions per quiz with Study button Extraction prompt: - Stronger emphasis on correct_answer field with step-by-step letter → full text example - Explicit instruction never to store just the letter Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
15 lines
558 B
Python
15 lines
558 B
Python
from datetime import datetime
|
|
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
|
|
from sqlalchemy.orm import relationship
|
|
from app.database import Base
|
|
|
|
|
|
class QuizCategory(Base):
|
|
__tablename__ = "quiz_categories"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
name = Column(String, nullable=False)
|
|
user_id = Column(Integer, ForeignKey("users.id"), nullable=False)
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
quizzes = relationship("Quiz", back_populates="category", foreign_keys="Quiz.category_id")
|