class Comment(db.Model): __tablename__ = 'comments' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(64), nullable=True) node_id = db.Column(db.Integer, db.ForeignKey('nodes.id')) owner_id = db.Column(db.Integer, db.ForeignKey('users.id')) owner = db.relationship('User', backref=db.backref('comments', lazy='dynamic')) description = db.Column(db.String(2048)) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return '{}'.format(self.title) def to_dict(self): return { 'id': self.id, 'node_id': self.node_id, 'title': self.title, 'owner_id': self.owner_id, 'owner_name': self.owner.name, 'description': self.description, }
class Role(db.Model, RoleMixin): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True) default = db.Column(db.Boolean, default=False) name = db.Column(db.String(80), unique=True, index=True, nullable=True) permissions = db.Column(db.Integer) created_at = db.Column(db.DateTime, default=datetime.now) updated_at = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) @staticmethod def insert_roles(): roles = { 'User': (Permission.OPERATE_MAPS | Permission.OPERATE_QUESTION | Permission.OPERATE_RESOURCE, True), 'Administrator': (0xff, False), } for r in roles: role = Role.query.filter_by(name=r).first() if role is None: role = Role(name=r) role.permissions = roles[r][0] role.default = roles[r][1] db.session.add(role) else: # then db.session.commit() @staticmethod def get(name): return Role.query.filter_by(name=name).first() def __repr__(self): return '{}'.format(self.name)
class NodeRelation(db.Model): __tablename__ = 'node_relations' source_node_id = db.Column(db.Integer, db.ForeignKey('nodes.id'), primary_key=True) target_node_id = db.Column(db.Integer, db.ForeignKey('nodes.id'), primary_key=True) graph_id = db.Column(db.Integer, db.ForeignKey('graphs.id')) owner_id = db.Column(db.Integer, db.ForeignKey('users.id')) timestamp = db.Column(db.DateTime, default=datetime.utcnow) info = db.Column(db.String(255), default='') color = db.Column(db.String(255)) is_dual_way = db.Column(db.Boolean, default=False) # 是双向还是单向 line_type = db.Column(db.String(255)) # 线的类型 created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): arch = '<->' if self.is_dual_way else '->' return '<NodeRelation {!r}{}{!r}>'.format(self.from_node.name, arch, self.to_node.name) @classmethod def find_relation(cls, sid, tid, gid, oid=None): kwargs = { 'source_node_id': sid, 'target_node_id': tid, 'graph_id': gid, } if oid is not None: kwargs.update({'owner_id': oid}) rels = cls.query.filter_by(**kwargs).first() return rels @classmethod def get_relation_by_node_id(cls, nid): return cls.query.filter( or_(cls.source_node_id == nid, cls.target_node_id == nid)).all()
class Article(db.Model): __tablename__ = 'articles' id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(64), nullable=True) node_id = db.Column(db.Integer, db.ForeignKey('nodes.id')) owner_id = db.Column(db.Integer, db.ForeignKey('users.id')) url = db.Column(db.String(128)) author = db.Column(db.String(64)) source = db.Column(db.String(32)) description = db.Column(db.String(2048)) body = db.Column(db.Text()) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return '{}'.format(self.title)
class Graph(db.Model): __tablename__ = 'graphs' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), index=True, nullable=True) owner_id = db.Column(db.Integer, db.ForeignKey('users.id')) graph_type = db.Column(db.String(64)) is_private = db.Column(db.Boolean, default=False) # 是否仅自己可见 nodes = db.relationship('Node', backref='graph', cascade='all, delete-orphan') relations = db.relationship('NodeRelation', backref='graph', cascade='all, delete-orphan') created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return '{}'.format(self.name)
class Book(db.Model): __tablename__ = 'books' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), nullable=True) node_id = db.Column(db.Integer, db.ForeignKey('nodes.id')) owner_id = db.Column(db.Integer, db.ForeignKey('users.id')) url = db.Column(db.String(256)) author = db.Column(db.String(64)) source = db.Column(db.String(32)) description = db.Column(db.String(2048)) image = db.Column(db.String(256)) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) @property def pic(self): return '{}.jpg'.format(self.id)
class Node(db.Model): __tablename__ = 'nodes' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(64), index=True, nullable=True) relate_page_url = db.Column(db.String(128)) is_template = db.Column(db.Boolean, default=False) # 是否作为模板 color = db.Column(db.String(255)) size = db.Column(db.String(255)) # 大小 shape = db.Column(db.String(255)) # 形状 description = db.Column(db.String(255)) owner_id = db.Column(db.Integer, db.ForeignKey('users.id')) graph_id = db.Column(db.Integer, db.ForeignKey('graphs.id')) from_nodes = db.relationship('NodeRelation', foreign_keys=[NodeRelation.target_node_id], backref=db.backref('to_node', lazy='joined'), lazy='dynamic', cascade='all, delete-orphan') to_nodes = db.relationship('NodeRelation', foreign_keys=[NodeRelation.source_node_id], backref=db.backref('from_node', lazy='joined'), lazy='dynamic', cascade='all, delete-orphan') created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return '{}'.format(self.name) @property def pic(self): return '{}.jpg'.format(self.id)
class User(db.Model, UserMixin): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(80), unique=True, index=True, nullable=True) password = db.Column(db.String(255)) phone = db.Column(db.String(32)) gender = db.Column(db.String(8)) birthday = db.Column(db.Date) email = db.Column(db.String(120), unique=True) has_verified = db.Column(db.Boolean, default=False) roles = db.relationship('Role', secondary=roles_users, backref=db.backref('users', lazy='dynamic')) own_graphs = db.relationship('Graph', backref='owner') active = db.Column(db.Boolean, default=True) create_time = db.Column(db.DateTime, default=datetime.utcnow) write_time = db.Column(db.DateTime) current_sign_in_time = db.Column(db.DateTime, default=datetime.utcnow) last_sign_in_time = db.Column(db.DateTime) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def __repr__(self): return '{}'.format(self.name or self.email) def __init__(self, **kwargs): super(User, self).__init__(**kwargs) # if self.role is None: # if self.email in current_app.config['ITMAP_ADMINS']: # self.role = Role.query.filter_by(permissions=0xff).first() # else: # self.role = Role.query.filter_by(default=True).first() @property def to_dict(self): return { 'name': self.name, 'email': self.email, 'has_verified': self.has_verified, # 'role': self.role.name, 'active': self.active, # 'current_sign_in_time': arrow.get(self.current_sign_in_time).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss'), # 'last_sign_in_time': arrow.get(self.last_sign_in_time).to('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss'), # 'own_graphs': [{'id':g.id, 'name':g.name, 'owner_id': self.id} for g in self.own_graphs], 'avatar': self.avatar, 'phone': self.phone, 'gender': self.gender, } #@property #def url(self): # return url_for('user.detail', id=str(self.id)) @property def email_md5(self): email = self.email.strip() if isinstance(email, str): email = email.encode('utf-8') return hashlib.md5(email).hexdigest() @property def avatar(self): return '{}.jpg'.format(self.email_md5) @staticmethod def get(id): return User.query.get(id) @staticmethod def generate_password(password): return security.generate_password_hash( current_app.config['SECRET_KEY'] + password ) @staticmethod def create_token(length=16): return security.gen_salt(length) @classmethod def create_user(cls, username, email, password, **kwargs): password = cls.generate_password(password) user = cls(name=username, password=password, email=email, **kwargs) db.session.add(user) db.session.commit() return user def set_password(self, password): self.password = self.generate_password(password) def check_password(self, password): return security.check_password_hash( self.password, current_app.config['SECRET_KEY'] + password ) def reset_password(self): if not self.has_verified: return False, 'Should verify first' key = self.name + 'change_password_token' token = self.create_token() redis.set(key, token) redis.expire(key, 3600) msg = Message(subject=u'重设密码', body='http://127.0.0.1:5000/auth/change_password?token={}'.format(token), # need modify recipients=[self.email]) # thread = Thread(target=send_async_email, args=[current_app, msg]) # thread.start() # 虽然很多地方都给出了以上的用法,但这种方法会报错:RuntimeError: Working outside of application context. # 大概原因是current_app是线程的本地对象,不能传给别的线程? mail.send(msg) return True, 'Success' def change_password(self, password, token): key = self.name + 'change_password_token' if token != redis.get(key): return False, 'Token expired or wrong' new_password = self.generate_password(password) if self.password == new_password: return False, 'Duplicate password' else: self.password = new_password db.session.add(self) db.session.commit() redis.remove(key) return True, 'Success' def send_verify_email(self): if self.has_verified: return False, 'Already verified' key = self.name + self.email + 'verify_email_token' token = self.create_token() redis.set(key, token) redis.expire(key, 3600) msg = Message(subject=u'验证邮箱', body='http://www.songcser.com/auth/verified_by_email?token={}'.format(token), # need modify recipients=[self.email]) # thread = Thread(target=send_async_email, args=[current_app, msg]) # thread.start() mail.send(msg) return True, 'Success' def verified_by_email(self, token): key = self.name + self.email + 'verify_email_token' if token != redis.get(key): return False, 'Token expired or wrong' self.has_verified = True db.session.add(self) db.session.commit() redis.remove(key) return True, 'Success' @classmethod def by_email(cls, email): return cls.query.filter_by(email=email).first() # def can(self, permissions): # return self.role is not None and \ # (self.role.permissions & permissions) == permissions # def is_administrator(self): # return self.can(Permission.ADMINISTER) def sign_stamp(self): self.last_sign_in_time = self.current_sign_in_time self.current_sign_in_time = datetime.utcnow() db.session.add(self) db.session.commit()