from datetime import datetime from enum import Enum from flask_login import UserMixin from .extensions import db class UserStatus(str, Enum): pending = "pending" approved = "approved" rejected = "rejected" class Visibility(str, Enum): public = "public" followers = "followers" private = "private" class ReviewStatus(str, Enum): pending = "pending" approved = "approved" rejected = "rejected" class ActivityStatus(str, Enum): draft = "draft" published = "published" closed = "closed" class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(255), unique=True, nullable=False) username = db.Column(db.String(64), unique=True, nullable=False) password_hash = db.Column(db.String(255), nullable=False) role = db.Column(db.String(32), default="user") status = db.Column(db.Enum(UserStatus), default=UserStatus.pending, nullable=False) must_change_password = db.Column(db.Boolean, default=False) identity_photo_path = db.Column(db.String(512)) created_at = db.Column(db.DateTime, default=datetime.utcnow) profile = db.relationship("Profile", backref="user", uselist=False) class Profile(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) avatar_path = db.Column(db.String(512)) bio = db.Column(db.Text) grade = db.Column(db.String(32)) class_name = db.Column(db.String(32)) links = db.Column(db.Text) updated_at = db.Column(db.DateTime, default=datetime.utcnow) class Post(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) title = db.Column(db.String(255), nullable=False) description = db.Column(db.Text) visibility = db.Column(db.Enum(Visibility), default=Visibility.private, nullable=False) status = db.Column(db.Enum(ReviewStatus), default=ReviewStatus.approved, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) published_at = db.Column(db.DateTime) user = db.relationship("User", backref=db.backref("posts", lazy=True)) class PostImage(db.Model): id = db.Column(db.Integer, primary_key=True) post_id = db.Column(db.Integer, db.ForeignKey("post.id"), nullable=False) original_path = db.Column(db.String(512), nullable=False) web_path = db.Column(db.String(512)) thumb_path = db.Column(db.String(512)) exif_json = db.Column(db.Text) order_index = db.Column(db.Integer, default=0) post = db.relationship("Post", backref=db.backref("images", lazy=True, cascade="all, delete-orphan")) class Comment(db.Model): id = db.Column(db.Integer, primary_key=True) post_id = db.Column(db.Integer, db.ForeignKey("post.id"), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) body = db.Column(db.Text, nullable=False) status = db.Column(db.String(32), default="active") created_at = db.Column(db.DateTime, default=datetime.utcnow) class Follow(db.Model): follower_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True) followee_id = db.Column(db.Integer, db.ForeignKey("user.id"), primary_key=True) created_at = db.Column(db.DateTime, default=datetime.utcnow) class Activity(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(255), nullable=False) theme = db.Column(db.String(255)) description = db.Column(db.Text) start_at = db.Column(db.DateTime) end_at = db.Column(db.DateTime) status = db.Column(db.Enum(ActivityStatus), default=ActivityStatus.draft, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) class ActivitySubmission(db.Model): id = db.Column(db.Integer, primary_key=True) activity_id = db.Column(db.Integer, db.ForeignKey("activity.id"), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) status = db.Column(db.Enum(ReviewStatus), default=ReviewStatus.pending, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) activity = db.relationship("Activity", backref=db.backref("submissions", lazy=True)) class SubmissionImage(db.Model): id = db.Column(db.Integer, primary_key=True) submission_id = db.Column(db.Integer, db.ForeignKey("activity_submission.id"), nullable=False) original_path = db.Column(db.String(512), nullable=False) web_path = db.Column(db.String(512)) thumb_path = db.Column(db.String(512)) exif_json = db.Column(db.Text) order_index = db.Column(db.Integer, default=0) class Like(db.Model): id = db.Column(db.Integer, primary_key=True) post_id = db.Column(db.Integer, db.ForeignKey("post.id"), nullable=False) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) class Notification(db.Model): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) type = db.Column(db.String(64), nullable=False) payload_json = db.Column(db.Text) read_at = db.Column(db.DateTime) created_at = db.Column(db.DateTime, default=datetime.utcnow) class ReviewLog(db.Model): id = db.Column(db.Integer, primary_key=True) target_type = db.Column(db.String(32), nullable=False) target_id = db.Column(db.Integer, nullable=False) admin_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False) action = db.Column(db.String(32), nullable=False) reason = db.Column(db.Text) created_at = db.Column(db.DateTime, default=datetime.utcnow)