- Add reminders_disabled boolean column to users (DB source of truth). - Scheduler reads the DB column directly; Redis no longer used for opt-out checks. - Scheduler now deactivates reminders when a user has no completed attempts left for a quiz (e.g., after deleting their attempts). - Settings API: GET returns DB value for reminders_disabled; PUT persists that key to DB and keeps the rest of the blob in Redis. Rollback point for Alembic wiring.
34 lines
1.3 KiB
Python
34 lines
1.3 KiB
Python
from datetime import datetime
|
|
|
|
from sqlalchemy import Column, Integer, String, DateTime, Boolean
|
|
from sqlalchemy.orm import relationship
|
|
from sqlalchemy.sql import false as sa_false
|
|
|
|
from app.database import Base
|
|
|
|
|
|
class User(Base):
|
|
__tablename__ = "users"
|
|
|
|
id = Column(Integer, primary_key=True, index=True)
|
|
email = Column(String, unique=True, index=True, nullable=False)
|
|
hashed_password = Column(String, nullable=False)
|
|
name = Column(String, nullable=False)
|
|
role = Column(String, default="user") # admin, moderator, user
|
|
is_unthrottled = Column(Integer, default=0) # 1 = exempt from rate limits
|
|
reminders_disabled = Column(Boolean, default=False, nullable=False, server_default=sa_false())
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|
|
|
documents = relationship("PDFDocument", back_populates="user")
|
|
quizzes = relationship("Quiz", back_populates="user")
|
|
attempts = relationship("QuizAttempt", back_populates="user")
|
|
reminders = relationship("ReminderSchedule", back_populates="user")
|
|
favorites = relationship("Favorite", back_populates="user", cascade="all, delete-orphan")
|
|
|
|
@property
|
|
def is_admin(self):
|
|
return self.role == "admin"
|
|
|
|
@property
|
|
def is_moderator(self):
|
|
return self.role in ("admin", "moderator")
|