models.py 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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 21:09:08 (CST)
  9. # Last Update:星期六 2017-4-8 12:51:59 (CST)
  10. # By:
  11. # Description:
  12. # **************************************************************************
  13. from datetime import datetime, timedelta
  14. from flask import current_app
  15. from flask_login import UserMixin, current_user
  16. from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer
  17. from pytz import all_timezones
  18. from sqlalchemy import event
  19. from sqlalchemy.orm import object_session
  20. from werkzeug.security import check_password_hash, generate_password_hash
  21. from flask_maple.models import ModelMixin
  22. from flask_maple.mail import MailMixin
  23. from forums.count import Count
  24. from forums.extension import db, mail
  25. from forums.common.records import load_online_sign_users
  26. user_follower = db.Table(
  27. 'user_follower',
  28. db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
  29. db.Column('follower_id', db.Integer, db.ForeignKey('users.id')))
  30. class User(db.Model, UserMixin, ModelMixin, MailMixin):
  31. __tablename__ = 'users'
  32. id = db.Column(db.Integer, primary_key=True)
  33. username = db.Column(db.String(81), unique=True, nullable=False)
  34. email = db.Column(db.String(81), unique=True, nullable=False)
  35. password = db.Column(db.String(256), nullable=False)
  36. is_superuser = db.Column(db.Boolean, default=False)
  37. is_confirmed = db.Column(db.Boolean, default=False)
  38. register_time = db.Column(db.DateTime, default=datetime.now())
  39. last_login = db.Column(db.DateTime, default=datetime.now())
  40. followers = db.relationship(
  41. 'User',
  42. secondary=user_follower,
  43. primaryjoin=(id == user_follower.c.user_id),
  44. secondaryjoin=(id == user_follower.c.follower_id),
  45. backref=db.backref(
  46. 'following_users', lazy='dynamic'),
  47. lazy='dynamic')
  48. def is_followed(self, user=None):
  49. if user is None:
  50. user = current_user
  51. return db.session.query(user_follower).filter(
  52. user_follower.c.user_id == self.id,
  53. user_follower.c.follower_id == user.id).exists()
  54. @property
  55. def is_online(self):
  56. setting = self.setting
  57. if setting.online_status == UserSetting.STATUS_ALLOW_ALL:
  58. return self.username in load_online_sign_users()
  59. elif setting.online_status == UserSetting.STATUS_ALLOW_AUTHENTICATED:
  60. return self.username in load_online_sign_users(
  61. ) and current_user.is_authenticated
  62. elif setting.online_status == UserSetting.STATUS_ALLOW_OWN:
  63. return current_user.id == self.id
  64. return False
  65. @property
  66. def topic_count(self):
  67. return self.topics.count()
  68. @topic_count.setter
  69. def topic_count(self, value):
  70. return Count.user_topic_count(self.id, value)
  71. @property
  72. def reply_count(self):
  73. return self.replies.count()
  74. @reply_count.setter
  75. def reply_count(self, value):
  76. return Count.user_reply_count(self.id, value)
  77. @property
  78. def message_count(self):
  79. # return self.receive_messages.filter_by(status='0').count()
  80. return Count.user_message_count(self.id)
  81. @message_count.setter
  82. def message_count(self, value):
  83. return Count.user_message_count(self.id, value)
  84. @property
  85. def send_email_time(self):
  86. # return self.receive_messages.filter_by(status='0').count()
  87. return Count.user_email_time(self.id)
  88. @send_email_time.setter
  89. def send_email_time(self, value):
  90. return Count.user_email_time(self.id, value)
  91. @property
  92. def email_is_allowed(self):
  93. t = self.send_email_time
  94. t = datetime.strptime(t, '%Y-%m-%d %H:%M:%S')
  95. now = datetime.now()
  96. if t + timedelta(hours=3) < now:
  97. self.send_email_time = now.strftime('%Y-%m-%d %H:%M:%S')
  98. return True
  99. return False
  100. def __str__(self):
  101. return self.username
  102. def __repr__(self):
  103. return '<User %r>' % self.username
  104. def set_password(self, raw_password):
  105. self.password = generate_password_hash(raw_password)
  106. def check_password(self, raw_password):
  107. return check_password_hash(self.password, raw_password)
  108. @property
  109. def token(self):
  110. config = current_app.config
  111. secret_key = config.setdefault('SECRET_KEY')
  112. salt = config.setdefault('SECURITY_PASSWORD_SALT')
  113. serializer = URLSafeTimedSerializer(secret_key)
  114. token = serializer.dumps(self.username, salt=salt)
  115. return token
  116. @staticmethod
  117. def check_token(token, max_age=86400):
  118. config = current_app.config
  119. secret_key = config.setdefault('SECRET_KEY')
  120. salt = config.setdefault('SECURITY_PASSWORD_SALT')
  121. serializer = URLSafeTimedSerializer(secret_key)
  122. try:
  123. username = serializer.loads(token, salt=salt, max_age=max_age)
  124. except BadSignature:
  125. return False
  126. except SignatureExpired:
  127. return False
  128. user = User.query.filter_by(username=username).first()
  129. if user is None:
  130. return False
  131. return user
  132. def send_email(self, *args, **kwargs):
  133. kwargs.update(recipients=[self.email])
  134. mail.send_email(*args, **kwargs)
  135. def send_email_to_admin(self):
  136. ''''
  137. When someone registered an account,send email to admin.
  138. '''
  139. recipients = current_app.config['RECEIVER']
  140. subject = '{} has registered an account.'.format(self.username)
  141. html = '<p>username: {}</p><p>email: {}</p>'.format(self.username,
  142. self.email)
  143. mail.send_email(subject=subject, html=html, recipients=recipients)
  144. class UserInfo(db.Model, ModelMixin):
  145. __tablename__ = 'userinfo'
  146. id = db.Column(db.Integer, primary_key=True)
  147. avatar = db.Column(db.String(128))
  148. school = db.Column(db.String(128), nullable=True)
  149. word = db.Column(db.Text, nullable=True)
  150. introduce = db.Column(db.Text, nullable=True)
  151. user_id = db.Column(
  152. db.Integer, db.ForeignKey(
  153. 'users.id', ondelete="CASCADE"))
  154. user = db.relationship(
  155. User,
  156. backref=db.backref(
  157. "info", uselist=False, cascade='all,delete', lazy='joined'),
  158. uselist=False,
  159. lazy='joined')
  160. def __repr__(self):
  161. return "<UserInfo %r>" % str(self.id)
  162. def __str__(self):
  163. return "%s's info" % self.user_id
  164. class UserSetting(db.Model, ModelMixin):
  165. STATUS_ALLOW_ALL = '0'
  166. STATUS_ALLOW_AUTHENTICATED = '1'
  167. STATUS_ALLOW_OWN = '2'
  168. STATUS = (('0', 'ALLOW ALL USER'), ('1', 'ALLOW AUTHENTICATED USER'),
  169. ('2', 'ALLOW OWN'))
  170. LOCALE_CHINESE = 'zh'
  171. LOCALE_ENGLISH = 'en'
  172. LOCALE = (('zh', 'Chinese'), ('en', 'English'))
  173. TIMEZONE_UTC = 'UTC'
  174. TIMEZONE = [(i, i) for i in all_timezones]
  175. __tablename__ = 'usersetting'
  176. id = db.Column(db.Integer, primary_key=True)
  177. online_status = db.Column(
  178. db.String(10), nullable=False, default=STATUS_ALLOW_ALL)
  179. topic_list = db.Column(
  180. db.String(10), nullable=False, default=STATUS_ALLOW_ALL)
  181. rep_list = db.Column(
  182. db.String(10), nullable=False, default=STATUS_ALLOW_ALL)
  183. ntb_list = db.Column(
  184. db.String(10), nullable=False, default=STATUS_ALLOW_OWN)
  185. collect_list = db.Column(
  186. db.String(10), nullable=False, default=STATUS_ALLOW_AUTHENTICATED)
  187. locale = db.Column(db.String(32), nullable=False, default=LOCALE_CHINESE)
  188. timezone = db.Column(db.String(32), nullable=False, default=TIMEZONE_UTC)
  189. user_id = db.Column(
  190. db.Integer, db.ForeignKey(
  191. 'users.id', ondelete="CASCADE"))
  192. user = db.relationship(
  193. User,
  194. backref=db.backref(
  195. "setting", uselist=False, cascade='all,delete', lazy='joined'),
  196. uselist=False,
  197. lazy='joined')
  198. def __repr__(self):
  199. return "<UserSetting %r>" % str(self.id)
  200. def __str__(self):
  201. return "%s's setting" % self.user_id
  202. @event.listens_for(User, 'before_insert')
  203. def add_info(mapper, connection, target):
  204. info = UserInfo()
  205. setting = UserSetting()
  206. object_session(target).add(info)
  207. object_session(target).add(setting)
  208. target.info = info
  209. target.setting = setting