| from datetime import datetime |
| from app import db |
| from flask_login import UserMixin |
| from werkzeug.security import generate_password_hash, check_password_hash |
| from sqlalchemy.ext.associationproxy import association_proxy |
|
|
| |
| class Role: |
| MEMBER = 'member' |
| MODERATOR = 'moderator' |
| ADMIN = 'admin' |
|
|
| |
| topic_tag = db.Table('topic_tag', |
| db.Column('topic_id', db.Integer, db.ForeignKey('topic.id'), primary_key=True), |
| db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'), primary_key=True) |
| ) |
|
|
| |
| class User(UserMixin, db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| username = db.Column(db.String(64), unique=True, nullable=False, index=True) |
| email = db.Column(db.String(120), unique=True, nullable=False, index=True) |
| password_hash = db.Column(db.String(256), nullable=False) |
| role = db.Column(db.String(20), nullable=False, default=Role.MEMBER) |
| avatar = db.Column(db.String(120), nullable=True, default='default.png') |
| signature = db.Column(db.String(200), nullable=True) |
| location = db.Column(db.String(100), nullable=True) |
| website = db.Column(db.String(120), nullable=True) |
| bio = db.Column(db.Text, nullable=True) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| last_seen = db.Column(db.DateTime, default=datetime.utcnow) |
| is_active = db.Column(db.Boolean, default=True) |
| is_banned = db.Column(db.Boolean, default=False) |
| ban_reason = db.Column(db.Text, nullable=True) |
| |
| |
| topics = db.relationship('Topic', backref='author', lazy='dynamic') |
| posts = db.relationship('Post', backref='author', lazy='dynamic', foreign_keys='Post.author_id') |
| reactions = db.relationship('Reaction', backref='user', lazy='dynamic') |
| reports = db.relationship('Report', backref='reporter', lazy='dynamic', foreign_keys='Report.reporter_id') |
| |
| def set_password(self, password): |
| self.password_hash = generate_password_hash(password) |
| |
| def check_password(self, password): |
| return check_password_hash(self.password_hash, password) |
| |
| def is_admin(self): |
| return self.role == Role.ADMIN |
| |
| def is_moderator(self): |
| return self.role == Role.MODERATOR or self.role == Role.ADMIN |
| |
| def update_last_seen(self): |
| self.last_seen = datetime.utcnow() |
| db.session.commit() |
| |
| def __repr__(self): |
| return f'<User {self.username}>' |
|
|
| |
| class Category(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| name = db.Column(db.String(100), nullable=False) |
| description = db.Column(db.Text, nullable=True) |
| order = db.Column(db.Integer, default=0) |
| |
| |
| topics = db.relationship('Topic', backref='category', lazy='dynamic') |
| |
| def topic_count(self): |
| return self.topics.count() |
| |
| def post_count(self): |
| count = 0 |
| for topic in self.topics: |
| count += topic.posts.count() |
| return count |
| |
| def __repr__(self): |
| return f'<Category {self.name}>' |
|
|
| |
| class Topic(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| title = db.Column(db.String(200), nullable=False) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) |
| views = db.Column(db.Integer, default=0) |
| is_locked = db.Column(db.Boolean, default=False) |
| is_pinned = db.Column(db.Boolean, default=False) |
| |
| |
| category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False) |
| author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) |
| |
| |
| posts = db.relationship('Post', backref='topic', lazy='dynamic', cascade='all, delete-orphan') |
| tags = db.relationship('Tag', secondary=topic_tag, backref=db.backref('topics', lazy='dynamic')) |
| reports = db.relationship('Report', backref='topic', lazy='dynamic', |
| primaryjoin="and_(Report.topic_id==Topic.id, Report.post_id==None)") |
| |
| def reply_count(self): |
| return self.posts.count() - 1 |
| |
| def last_post(self): |
| return self.posts.order_by(Post.created_at.desc()).first() |
| |
| def increment_view(self): |
| self.views += 1 |
| db.session.commit() |
| |
| def __repr__(self): |
| return f'<Topic {self.title}>' |
|
|
| |
| class Post(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| content = db.Column(db.Text, nullable=False) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) |
| edited_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) |
| |
| |
| topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), nullable=False) |
| author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) |
| |
| |
| reactions = db.relationship('Reaction', backref='post', lazy='dynamic', cascade='all, delete-orphan') |
| reports = db.relationship('Report', backref='post', lazy='dynamic', |
| primaryjoin="Report.post_id==Post.id") |
| |
| edited_by = db.relationship('User', foreign_keys=[edited_by_id]) |
| |
| def get_reaction_count(self, reaction_type=None): |
| if reaction_type: |
| return self.reactions.filter_by(reaction_type=reaction_type).count() |
| return self.reactions.count() |
| |
| def __repr__(self): |
| return f'<Post {self.id}>' |
|
|
| |
| class Tag(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| name = db.Column(db.String(50), nullable=False, unique=True) |
| |
| def __repr__(self): |
| return f'<Tag {self.name}>' |
|
|
| |
| class Reaction(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| reaction_type = db.Column(db.String(20), nullable=False, default='like') |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| |
| |
| user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) |
| post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False) |
| |
| |
| __table_args__ = ( |
| db.UniqueConstraint('user_id', 'post_id', name='_user_post_reaction_uc'), |
| ) |
| |
| def __repr__(self): |
| return f'<Reaction {self.reaction_type}>' |
|
|
| |
| class Report(db.Model): |
| id = db.Column(db.Integer, primary_key=True) |
| reason = db.Column(db.Text, nullable=False) |
| created_at = db.Column(db.DateTime, default=datetime.utcnow) |
| is_resolved = db.Column(db.Boolean, default=False) |
| resolved_at = db.Column(db.DateTime, nullable=True) |
| resolved_by_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=True) |
| |
| |
| reporter_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) |
| topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), nullable=True) |
| post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True) |
| |
| |
| resolved_by = db.relationship('User', foreign_keys=[resolved_by_id]) |
| |
| def __repr__(self): |
| return f'<Report {self.id}>' |
|
|