models.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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-1-25 20:25:9 (CST)
  10. # By:
  11. # Description:
  12. # **************************************************************************
  13. from flask import current_app
  14. from flask_login import UserMixin
  15. from flask_maple.models import ModelMixin
  16. from flask_mail import Message
  17. from threading import Thread
  18. from werkzeug.security import (generate_password_hash, check_password_hash)
  19. from itsdangerous import (URLSafeTimedSerializer, BadSignature,
  20. SignatureExpired)
  21. from sqlalchemy import event
  22. from sqlalchemy.orm import object_session
  23. from forums.extension import db, mail
  24. from pytz import all_timezones
  25. from datetime import datetime
  26. users_follow_users = db.Table(
  27. 'users_follow_users',
  28. db.Column('users_id', db.Integer, db.ForeignKey('users.id')),
  29. db.Column('follow_users_id', db.Integer, db.ForeignKey('users.id')))
  30. class User(db.Model, UserMixin, ModelMixin):
  31. __tablename__ = 'users'
  32. id = db.Column(db.Integer, primary_key=True)
  33. username = db.Column(db.String(49), unique=True, nullable=False)
  34. email = db.Column(db.String(81), unique=True, nullable=False)
  35. password = db.Column(db.String(81), 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, nullable=True)
  40. followers = db.relationship(
  41. 'User',
  42. secondary=users_follow_users,
  43. primaryjoin=(id == users_follow_users.c.users_id),
  44. secondaryjoin=(id == users_follow_users.c.follow_users_id),
  45. backref=db.backref(
  46. 'following_users', lazy='dynamic'),
  47. lazy='dynamic')
  48. def __str__(self):
  49. return self.username
  50. def __repr__(self):
  51. return '<User %r>' % self.username
  52. def set_password(self, raw_password):
  53. self.password = generate_password_hash(raw_password)
  54. def check_password(self, raw_password):
  55. return check_password_hash(self.password, raw_password)
  56. def send_async_email(self, msg):
  57. app = current_app._get_current_object()
  58. with app.app_context():
  59. mail.send(msg)
  60. def send_email(self,
  61. subject='',
  62. recipients=None,
  63. body=None,
  64. html=None,
  65. **kwargs):
  66. if recipients is None:
  67. recipients = self.email
  68. if not isinstance(recipients, list):
  69. recipients = [recipients]
  70. msg = Message(subject=subject, recipients=recipients, html=html)
  71. thr = Thread(target=self.send_async_email, args=[msg])
  72. thr.start()
  73. @property
  74. def email_token(self):
  75. config = current_app.config
  76. secret_key = config.setdefault('SECRET_KEY')
  77. salt = config.setdefault('SECURITY_PASSWORD_SALT')
  78. serializer = URLSafeTimedSerializer(secret_key)
  79. token = serializer.dumps(self.email, salt=salt)
  80. return token
  81. @staticmethod
  82. def check_email_token(token, max_age=1800):
  83. config = current_app.config
  84. secret_key = config.setdefault('SECRET_KEY')
  85. salt = config.setdefault('SECURITY_PASSWORD_SALT')
  86. serializer = URLSafeTimedSerializer(secret_key)
  87. try:
  88. email = serializer.loads(token, salt=salt, max_age=max_age)
  89. except BadSignature:
  90. return False
  91. except SignatureExpired:
  92. return False
  93. user = User.query.filter_by(email=email).first()
  94. if user is None:
  95. return False
  96. return user
  97. @property
  98. def token(self):
  99. config = current_app.config
  100. secret_key = config.setdefault('SECRET_KEY')
  101. salt = config.setdefault('SECURITY_PASSWORD_SALT')
  102. serializer = URLSafeTimedSerializer(secret_key)
  103. token = serializer.dumps(self.username, salt=salt)
  104. return token
  105. @staticmethod
  106. def check_token(token, max_age=86400):
  107. config = current_app.config
  108. secret_key = config.setdefault('SECRET_KEY')
  109. salt = config.setdefault('SECURITY_PASSWORD_SALT')
  110. serializer = URLSafeTimedSerializer(secret_key)
  111. try:
  112. username = serializer.loads(token, salt=salt, max_age=max_age)
  113. except BadSignature:
  114. return False
  115. except SignatureExpired:
  116. return False
  117. user = User.query.filter_by(username=username).first()
  118. if user is None:
  119. return False
  120. return user
  121. class UserInfo(db.Model, ModelMixin):
  122. __tablename__ = 'userinfo'
  123. id = db.Column(db.Integer, primary_key=True)
  124. avatar = db.Column(db.String(128))
  125. school = db.Column(db.String(128), nullable=True)
  126. word = db.Column(db.Text, nullable=True)
  127. introduce = db.Column(db.Text, nullable=True)
  128. user_id = db.Column(
  129. db.Integer, db.ForeignKey(
  130. 'users.id', ondelete="CASCADE"))
  131. user = db.relationship(
  132. User,
  133. backref=db.backref(
  134. "info", uselist=False, cascade='all,delete', lazy='joined'),
  135. uselist=False,
  136. lazy='joined')
  137. def __repr__(self):
  138. return "<UserInfo %r>" % str(self.id)
  139. def __str__(self):
  140. return "%s's info" % self.user.username
  141. class UserSetting(db.Model, ModelMixin):
  142. STATUS_ALLOW_ALL = '0'
  143. STATUS_ALLOW_AUTHENTICATED = '1'
  144. STATUS_ALLOW_OWN = '2'
  145. STATUS = (('0', 'ALLOW ALL USER'), ('1', 'ALLOW AUTHENTICATED USER'),
  146. ('2', 'ALLOW OWN'))
  147. LOCALE_CHINESE = 'zh'
  148. LOCALE_ENGLISH = 'en'
  149. LOCALE = (('zh', 'Chinese'), ('en', 'English'))
  150. TIMEZONE_UTC = 'UTC'
  151. TIMEZONE = [(i, i) for i in all_timezones]
  152. __tablename__ = 'usersetting'
  153. id = db.Column(db.Integer, primary_key=True)
  154. online_status = db.Column(
  155. db.Integer, nullable=False, default=STATUS_ALLOW_ALL)
  156. topic_list = db.Column(
  157. db.String(10), nullable=False, default=STATUS_ALLOW_ALL)
  158. rep_list = db.Column(
  159. db.String(10), nullable=False, default=STATUS_ALLOW_ALL)
  160. ntb_list = db.Column(
  161. db.String(10), nullable=False, default=STATUS_ALLOW_OWN)
  162. collect_list = db.Column(
  163. db.String(10), nullable=False, default=STATUS_ALLOW_AUTHENTICATED)
  164. locale = db.Column(db.String(32), nullable=False, default=LOCALE_CHINESE)
  165. timezone = db.Column(db.String(32), nullable=False, default=TIMEZONE_UTC)
  166. user_id = db.Column(
  167. db.Integer, db.ForeignKey(
  168. 'users.id', ondelete="CASCADE"))
  169. user = db.relationship(
  170. User,
  171. backref=db.backref(
  172. "setting", uselist=False, cascade='all,delete', lazy='joined'),
  173. uselist=False,
  174. lazy='joined')
  175. def __repr__(self):
  176. return "<UserSetting %r>" % str(self.id)
  177. def __str__(self):
  178. return "%s's setting" % self.user.username
  179. @event.listens_for(User, 'before_insert')
  180. def add_info(mapper, connection, target):
  181. info = UserInfo()
  182. setting = UserSetting()
  183. object_session(target).add(info)
  184. object_session(target).add(setting)
  185. target.info = info
  186. target.setting = setting