288 lines
13 KiB
Python
288 lines
13 KiB
Python
# models.py
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from datetime import datetime
|
|
import json
|
|
|
|
db = SQLAlchemy()
|
|
|
|
class User(db.Model):
|
|
__tablename__ = 'user'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(80), nullable=False)
|
|
email = db.Column(db.String(120), unique=True, nullable=True)
|
|
phone = db.Column(db.String(20), unique=True, nullable=True)
|
|
password = db.Column(db.String(128), nullable=False)
|
|
role = db.Column(db.String(20), default='student') # student, teacher, admin
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
avatar = db.Column(db.String(200), nullable=True)
|
|
|
|
exams_created = db.relationship('Exam', backref='creator', lazy=True)
|
|
submissions = db.relationship('Submission', backref='user', lazy=True)
|
|
drafts = db.relationship('Draft', backref='user', lazy=True)
|
|
posts = db.relationship('Post', backref='author', lazy=True)
|
|
replies = db.relationship('Reply', backref='author', lazy=True)
|
|
reactions = db.relationship('Reaction', backref='user', lazy=True)
|
|
bookmarks = db.relationship('Bookmark', backref='user', lazy=True)
|
|
notifications = db.relationship('Notification', backref='user', lazy=True)
|
|
contest_registrations = db.relationship('ContestRegistration', backref='user', lazy=True)
|
|
teacher_applications = db.relationship('TeacherApplication', backref='user', lazy=True)
|
|
# exam_bookmarks 关系将由 ExamBookmark 中的 backref 自动创建,此处不再定义
|
|
|
|
|
|
class Exam(db.Model):
|
|
__tablename__ = 'exam'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
title = db.Column(db.String(200), nullable=False)
|
|
subject = db.Column(db.String(50))
|
|
duration = db.Column(db.Integer, default=120)
|
|
total_score = db.Column(db.Integer, default=100)
|
|
status = db.Column(db.String(20), default='available')
|
|
creator_id = db.Column(db.Integer, db.ForeignKey('user.id'))
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
_questions = db.Column(db.Text, default='[]')
|
|
|
|
submissions = db.relationship('Submission', backref='exam', lazy=True, cascade='all, delete-orphan')
|
|
drafts = db.relationship('Draft', backref='exam', lazy=True, cascade='all, delete-orphan')
|
|
# bookmarked_by 关系将由 ExamBookmark 中的 backref 自动创建,此处不再定义
|
|
|
|
def set_questions(self, questions):
|
|
self._questions = json.dumps(questions, ensure_ascii=False)
|
|
|
|
def get_questions(self):
|
|
return json.loads(self._questions) if self._questions else []
|
|
|
|
|
|
class Submission(db.Model):
|
|
__tablename__ = 'submission'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
_answers = db.Column(db.Text, default='{}')
|
|
_question_scores = db.Column(db.Text, default='{}')
|
|
score = db.Column(db.Integer, default=0)
|
|
graded = db.Column(db.Boolean, default=False)
|
|
graded_by = db.Column(db.String(80), default='')
|
|
submitted_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
def set_answers(self, answers):
|
|
self._answers = json.dumps(answers, ensure_ascii=False)
|
|
|
|
def get_answers(self):
|
|
return json.loads(self._answers) if self._answers else {}
|
|
|
|
def set_question_scores(self, scores):
|
|
self._question_scores = json.dumps(scores, ensure_ascii=False)
|
|
|
|
def get_question_scores(self):
|
|
return json.loads(self._question_scores) if self._question_scores else {}
|
|
|
|
@property
|
|
def user_name(self):
|
|
return self.user.name if self.user else ''
|
|
|
|
|
|
class Draft(db.Model):
|
|
__tablename__ = 'draft'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
_answers = db.Column(db.Text, default='{}')
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
def set_answers(self, answers):
|
|
self._answers = json.dumps(answers, ensure_ascii=False)
|
|
|
|
def get_answers(self):
|
|
return json.loads(self._answers) if self._answers else {}
|
|
|
|
|
|
class Contest(db.Model):
|
|
__tablename__ = 'contest'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
name = db.Column(db.String(200), nullable=False)
|
|
organizer = db.Column(db.String(100))
|
|
description = db.Column(db.Text)
|
|
start_date = db.Column(db.String(20))
|
|
end_date = db.Column(db.String(20))
|
|
status = db.Column(db.String(20), default='upcoming')
|
|
participants = db.Column(db.Integer, default=0)
|
|
created_by = db.Column(db.String(50))
|
|
contact = db.Column(db.String(100))
|
|
_past_papers = db.Column(db.Text, default='[]')
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
registrations = db.relationship('ContestRegistration', backref='contest', lazy=True)
|
|
posts = db.relationship('Post', backref='contest', lazy=True)
|
|
|
|
def set_past_papers(self, papers):
|
|
self._past_papers = json.dumps(papers, ensure_ascii=False)
|
|
|
|
def get_past_papers(self):
|
|
return json.loads(self._past_papers) if self._past_papers else []
|
|
|
|
|
|
class ContestRegistration(db.Model):
|
|
__tablename__ = 'contest_registration'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
contest_id = db.Column(db.Integer, db.ForeignKey('contest.id'), nullable=False)
|
|
registered_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class ContestMembership(db.Model):
|
|
__tablename__ = 'contest_membership'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
contest_id = db.Column(db.Integer, db.ForeignKey('contest.id'), nullable=False)
|
|
role = db.Column(db.String(20), default='member')
|
|
joined_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class Post(db.Model):
|
|
__tablename__ = 'post'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
title = db.Column(db.String(200), nullable=False)
|
|
content = db.Column(db.Text, nullable=False)
|
|
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
contest_id = db.Column(db.Integer, db.ForeignKey('contest.id'), nullable=True)
|
|
tag = db.Column(db.String(50), default='全部')
|
|
is_official = db.Column(db.Boolean, default=False)
|
|
pinned = db.Column(db.Boolean, default=False)
|
|
likes = db.Column(db.Integer, default=0)
|
|
replies_count = db.Column(db.Integer, default=0)
|
|
views = db.Column(db.Integer, default=0)
|
|
has_poll = db.Column(db.Boolean, default=False)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
replies = db.relationship('Reply', backref='post', lazy=True, cascade='all, delete-orphan')
|
|
reactions = db.relationship('Reaction', backref='post', lazy=True, cascade='all, delete-orphan')
|
|
bookmarks = db.relationship('Bookmark', backref='post', lazy=True, cascade='all, delete-orphan')
|
|
poll = db.relationship('Poll', backref='post', uselist=False, cascade='all, delete-orphan')
|
|
|
|
|
|
class Reply(db.Model):
|
|
__tablename__ = 'reply'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
|
|
author_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
content = db.Column(db.Text, nullable=False)
|
|
reply_to = db.Column(db.String(80), nullable=True)
|
|
likes = db.Column(db.Integer, default=0)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|
|
|
reactions = db.relationship('Reaction', backref='reply', lazy=True, cascade='all, delete-orphan')
|
|
|
|
|
|
class Poll(db.Model):
|
|
__tablename__ = 'poll'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False, unique=True)
|
|
question = db.Column(db.String(200), nullable=False)
|
|
multi = db.Column(db.Boolean, default=False)
|
|
total_votes = db.Column(db.Integer, default=0)
|
|
_options = db.Column(db.Text, default='[]')
|
|
_voters = db.Column(db.Text, default='{}')
|
|
|
|
def set_options(self, options):
|
|
self._options = json.dumps(options, ensure_ascii=False)
|
|
|
|
def get_options(self):
|
|
return json.loads(self._options) if self._options else []
|
|
|
|
def set_voters(self, voters):
|
|
self._voters = json.dumps(voters, ensure_ascii=False)
|
|
|
|
def get_voters(self):
|
|
return json.loads(self._voters) if self._voters else {}
|
|
|
|
|
|
class Reaction(db.Model):
|
|
__tablename__ = 'reaction'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True)
|
|
reply_id = db.Column(db.Integer, db.ForeignKey('reply.id'), nullable=True)
|
|
reaction = db.Column(db.String(20), nullable=False)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class Bookmark(db.Model):
|
|
__tablename__ = 'bookmark'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=False)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class Notification(db.Model):
|
|
__tablename__ = 'notification'
|
|
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(50))
|
|
content = db.Column(db.String(200))
|
|
from_user = db.Column(db.String(80))
|
|
post_id = db.Column(db.Integer, nullable=True)
|
|
read = db.Column(db.Boolean, default=False)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class EditHistory(db.Model):
|
|
__tablename__ = 'edit_history'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
post_id = db.Column(db.Integer, db.ForeignKey('post.id'), nullable=True)
|
|
reply_id = db.Column(db.Integer, db.ForeignKey('reply.id'), nullable=True)
|
|
editor_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
old_content = db.Column(db.Text)
|
|
new_content = db.Column(db.Text)
|
|
edited_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class Report(db.Model):
|
|
__tablename__ = 'report'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
type = db.Column(db.String(20))
|
|
target_id = db.Column(db.Integer, nullable=False)
|
|
reporter_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
reason = db.Column(db.String(100))
|
|
detail = db.Column(db.Text)
|
|
status = db.Column(db.String(20), default='pending')
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class TeacherApplication(db.Model):
|
|
__tablename__ = 'teacher_application'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
name = db.Column(db.String(80), nullable=False)
|
|
email = db.Column(db.String(120), nullable=False)
|
|
reason = db.Column(db.Text, nullable=False)
|
|
status = db.Column(db.String(20), default='pending')
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
|
|
class Friend(db.Model):
|
|
__tablename__ = 'friend'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
friend_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
status = db.Column(db.String(20), default='pending')
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
user = db.relationship('User', foreign_keys=[user_id], backref=db.backref('friends_initiated', lazy='dynamic'))
|
|
friend = db.relationship('User', foreign_keys=[friend_id], backref=db.backref('friends_received', lazy='dynamic'))
|
|
|
|
|
|
class ExamBookmark(db.Model):
|
|
__tablename__ = 'exam_bookmark'
|
|
id = db.Column(db.Integer, primary_key=True)
|
|
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
|
|
exam_id = db.Column(db.Integer, db.ForeignKey('exam.id'), nullable=False)
|
|
created_at = db.Column(db.DateTime, default=datetime.utcnow)
|
|
|
|
# 使用 backref 自动在 User 和 Exam 上创建 'exam_bookmarks' 和 'bookmarked_by' 属性
|
|
user = db.relationship('User', backref=db.backref('exam_bookmarks', lazy='dynamic', cascade='all, delete-orphan'))
|
|
exam = db.relationship('Exam', backref=db.backref('bookmarked_by', lazy='dynamic', cascade='all, delete-orphan'))
|
|
|
|
__table_args__ = (db.UniqueConstraint('user_id', 'exam_id', name='unique_exam_bookmark'),) |