diff --git a/backend/app/models/report.py b/backend/app/models/report.py new file mode 100644 index 0000000..4f1fc46 --- /dev/null +++ b/backend/app/models/report.py @@ -0,0 +1,60 @@ +"""Report model for Trust & Safety.""" + +from sqlalchemy import ( + Column, + Integer, + String, + Text, + DateTime, + ForeignKey, + Enum as SAEnum, +) +from sqlalchemy.orm import relationship +from sqlalchemy.sql import func + +from app.database import Base + + +class Report(Base): + __tablename__ = "reports" + + id = Column(Integer, primary_key=True) + reporter_id = Column(Integer, ForeignKey("users.id"), nullable=False) + target_type = SAEnum("user", "world", "asset", "chat_message", name="target_type_enum", nullable=False) + target_id = Column(String(64), nullable=False) + reason_category = SAEnum( + "harassment", + "hate_speech", + "sexual_content", + "violence", + "spam", + "self_harm", + "other", + name="reason_category_enum", + nullable=False, + ) + details = Column(Text, nullable=True) + status = SAEnum( + "open", + "in_review", + "resolved", + "dismissed", + name="report_status_enum", + default="open", + nullable=False, + ) + resolved_by = Column(Integer, ForeignKey("users.id"), nullable=True) + resolution = SAEnum( + "action_taken", + "action_not_needed", + "duplicate", + name="resolution_enum", + nullable=True, + ) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + updated_at = Column(DateTime(timezone=True), onupdate=func.now()) + resolved_at = Column(DateTime(timezone=True), nullable=True) + + # Relationships + reporter = relationship("User", foreign_keys=[reporter_id]) + resolved_by_user = relationship("User", foreign_keys=[resolved_by]) diff --git a/backend/app/models/user.py b/backend/app/models/user.py index acb5684..1bdb945 100644 --- a/backend/app/models/user.py +++ b/backend/app/models/user.py @@ -1,23 +1,13 @@ from datetime import date from typing import Optional -from sqlalchemy import Column, Integer, String, Boolean, DateTime, Date, Enum +from sqlalchemy import Column, Integer, String, Boolean, DateTime, Date, Enum, Text, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.sql import func from app.database import Base -class UserRole: - USER = "user" - MODERATOR = "moderator" - ADMIN = "admin" - - @staticmethod - def choices(): - return [UserRole.USER, UserRole.MODERATOR, UserRole.ADMIN] - - class User(Base): __tablename__ = "users" @@ -27,7 +17,7 @@ class User(Base): hashed_password = Column(String(255), nullable=False) date_of_birth = Column(Date, nullable=True) is_active = Column(Boolean, default=True) - role = Column(Enum(UserRole.USER, UserRole.MODERATOR, UserRole.ADMIN), default=UserRole.USER, nullable=False) + role = Column(Enum("user", "moderator", "admin", name="user_role", default="user"), default="user") banned_until = Column(DateTime(timezone=True), nullable=True) suspended_until = Column(DateTime(timezone=True), nullable=True) created_at = Column(DateTime(timezone=True), server_default=func.now()) @@ -36,12 +26,6 @@ class User(Base): sessions = relationship("Session", back_populates="user", cascade="all, delete-orphan") worlds = relationship("World", back_populates="owner") assets = relationship("Asset", back_populates="owner") - reports_made = relationship("Report", back_populates="reporter", foreign_keys="Report.reporter_id") - reports_resolved = relationship("Report", back_populates="resolved_by_user", foreign_keys="Report.resolved_by") - moderation_actions_created = relationship("ModerationAction", back_populates="moderator", foreign_keys="ModerationAction.moderator_id") - moderation_actions_target = relationship("ModerationAction", back_populates="target_user", foreign_keys="ModerationAction.target_user_id") - appeals = relationship("Appeal", back_populates="user", foreign_keys="Appeal.user_id") - appeals_reviewed = relationship("Appeal", back_populates="reviewer", foreign_keys="Appeal.reviewed_by") @property def is_adult(self) -> bool: