models.py 5.5 KB

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