Forum / models.py
kuro223's picture
o9
91073d4
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
# User roles
class Role:
MEMBER = 'member'
MODERATOR = 'moderator'
ADMIN = 'admin'
# Association table for topics and tags
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)
)
# User model
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)
# Relationships
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}>'
# Category model
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)
# Relationships
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}>'
# Topic model
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)
# Foreign keys
category_id = db.Column(db.Integer, db.ForeignKey('category.id'), nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
# Relationships
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 # Subtract first post
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}>'
# Post model
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)
# Foreign keys
topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'), nullable=False)
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
# Relationships
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}>'
# Tag model
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}>'
# Reaction model
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)
# Foreign keys
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
# Enforce unique reaction per user per post
__table_args__ = (
db.UniqueConstraint('user_id', 'post_id', name='_user_post_reaction_uc'),
)
def __repr__(self):
return f'<Reaction {self.reaction_type}>'
# Report model
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)
# Foreign keys
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)
# Relationships
resolved_by = db.relationship('User', foreign_keys=[resolved_by_id])
def __repr__(self):
return f'<Report {self.id}>'