db.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # **************************************************************************
  4. # Copyright © 2016 jianglin
  5. # File Name: models.py
  6. # Author: jianglin
  7. # Email: xiyang0807@gmail.com
  8. # Created: 2016-12-15 20:52:07 (CST)
  9. # Last Update: Monday 2019-05-06 23:37:22 (CST)
  10. # By:
  11. # Description:
  12. # **************************************************************************
  13. from datetime import datetime
  14. from flask_login import current_user
  15. from flask_maple.models import ModelMixin
  16. from forums.extension import db
  17. from forums.count import Count
  18. from forums.jinja import safe_clean, markdown
  19. topic_follower = db.Table(
  20. 'topic_follower',
  21. db.Column('topic_id', db.Integer, db.ForeignKey('topics.id')),
  22. db.Column('follower_id', db.Integer, db.ForeignKey('user.id')))
  23. class Topic(db.Model, ModelMixin):
  24. __tablename__ = 'topics'
  25. __searchable__ = ['title', 'content']
  26. CONTENT_TYPE_TEXT = '0'
  27. CONTENT_TYPE_MARKDOWN = '1'
  28. CONTENT_TYPE_ORGMODE = '2'
  29. CONTENT_TYPE = (('0', 'text'), ('1', 'markdown'), ('2', 'org-mode'))
  30. id = db.Column(db.Integer, primary_key=True)
  31. title = db.Column(db.String(81), nullable=False)
  32. content = db.Column(db.Text, nullable=False)
  33. content_type = db.Column(
  34. db.String(10), nullable=False, default=CONTENT_TYPE_MARKDOWN)
  35. created_at = db.Column(
  36. db.DateTime, default=datetime.utcnow(), nullable=False)
  37. updated_at = db.Column(
  38. db.DateTime, default=datetime.utcnow(), onupdate=datetime.utcnow())
  39. is_good = db.Column(db.Boolean, default=False)
  40. is_top = db.Column(db.Boolean, default=False)
  41. author_id = db.Column(db.Integer,
  42. db.ForeignKey('user.id', ondelete="CASCADE"))
  43. author = db.relationship(
  44. "User",
  45. backref=db.backref(
  46. 'topics', cascade='all,delete-orphan', lazy='dynamic'),
  47. lazy='joined')
  48. board_id = db.Column(db.Integer,
  49. db.ForeignKey('boards.id', ondelete="CASCADE"))
  50. board = db.relationship(
  51. "Board",
  52. backref=db.backref(
  53. 'topics', cascade='all,delete-orphan', lazy='dynamic'),
  54. lazy='joined')
  55. followers = db.relationship(
  56. "User",
  57. secondary=topic_follower,
  58. backref=db.backref('following_topics', lazy='dynamic'),
  59. lazy='dynamic')
  60. __mapper_args__ = {"order_by": created_at.desc()}
  61. def is_followed(self, user=None):
  62. if user is None:
  63. user = current_user
  64. return db.session.query(topic_follower).filter(
  65. topic_follower.c.topic_id == self.id,
  66. topic_follower.c.follower_id == user.id).exists()
  67. def is_collected(self, user=None):
  68. if user is None:
  69. user = current_user
  70. return self.collects.filter_by(author_id=user.id).exists()
  71. @property
  72. def text(self):
  73. if self.content_type == Topic.CONTENT_TYPE_TEXT:
  74. return safe_clean(self.content)
  75. elif self.content_type == Topic.CONTENT_TYPE_MARKDOWN:
  76. return markdown(self.content, False)
  77. return self.content
  78. @property
  79. def newest_reply(self):
  80. return self.replies.order_by('-id').first()
  81. @property
  82. def reply_count(self):
  83. return Count.topic_reply_count(self.id)
  84. @reply_count.setter
  85. def reply_count(self, value):
  86. return Count.topic_reply_count(self.id, value)
  87. @property
  88. def read_count(self):
  89. return Count.topic_read_count(self.id)
  90. @read_count.setter
  91. def read_count(self, value):
  92. return Count.topic_read_count(self.id, value)
  93. def __str__(self):
  94. return self.title
  95. def __repr__(self):
  96. return "<Topic %r>" % self.title
  97. reply_liker = db.Table(
  98. 'reply_liker',
  99. db.Column('reply_id', db.Integer, db.ForeignKey('replies.id')),
  100. db.Column('liker_id', db.Integer, db.ForeignKey('user.id')))
  101. class Reply(db.Model, ModelMixin):
  102. __tablename__ = 'replies'
  103. id = db.Column(db.Integer, primary_key=True)
  104. content = db.Column(db.Text, nullable=False)
  105. created_at = db.Column(
  106. db.DateTime, default=datetime.utcnow(), nullable=False)
  107. updated_at = db.Column(
  108. db.DateTime, default=datetime.utcnow(), onupdate=datetime.utcnow())
  109. topic_id = db.Column(db.Integer,
  110. db.ForeignKey('topics.id', ondelete="CASCADE"))
  111. topic = db.relationship(
  112. Topic,
  113. backref=db.backref(
  114. 'replies', cascade='all,delete-orphan', lazy='dynamic'),
  115. lazy='joined')
  116. author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
  117. author = db.relationship(
  118. "User", backref=db.backref('replies', lazy='dynamic'), lazy='joined')
  119. likers = db.relationship(
  120. "User",
  121. secondary=reply_liker,
  122. backref=db.backref('like_replies', lazy='dynamic'),
  123. lazy='dynamic')
  124. def is_liked(self, user=None):
  125. if user is None:
  126. user = current_user
  127. if not user.is_authenticated:
  128. return False
  129. return self.likers.filter_by(id=user.id).exists()
  130. @property
  131. def liker_count(self):
  132. return Count.reply_liker_count(self.id)
  133. @liker_count.setter
  134. def liker_count(self, value):
  135. return Count.reply_liker_count(self.id, value)
  136. def __str__(self):
  137. return self.content[:10]
  138. def __repr__(self):
  139. return "<Topic %r>" % self.content[:10]