class Grant(db.Model, CRUDMixin): id = db.Column(db.Integer, primary_key=True) user_id = db.Column(db.Integer) user = db.relationship('User', primaryjoin='User.id == Grant.user_id', foreign_keys='Grant.user_id', cascade="all, delete") client_id = db.Column(db.String(40), nullable=False) client = db.relationship('Client', primaryjoin='Client.client_id == Grant.client_id', foreign_keys='Grant.client_id', cascade="all, delete") code = db.Column(db.String(255), index=True, nullable=False) redirect_uri = db.Column(db.String(255)) _scopes = db.Column('scopes', db.Text) expires = db.Column(db.DateTime) @property def scopes(self): if self._scopes: return self._scopes.split() return [] @scopes.setter def scopes(self, scopes): self._scopes = ' '.join(scopes)
class Permission(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(150)) object_type = db.Column(db.String(150)) action_name = db.Column(db.String(150)) action_type = db.Column(db.String(150)) object_id = db.Column(db.Integer) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
class Setting(db.Model, CRUDMixin): id = db.Column(db.Integer, primary_key=True) key = db.Column(db.String(150), nullable=False) value = 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)
class Role(db.Model, CRUDMixin): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100)) slug = db.Column(db.String(100)) description = 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) permissions = db.relationship( 'Permission', backref='roles', secondary=role_permission, primaryjoin='Role.id==role_permission.c.role_id', secondaryjoin='role_permission.c.permission_id==Permission.id', foreign_keys=[ role_permission.c.role_id, role_permission.c.permission_id ])
class Token(db.Model, CRUDMixin): id = db.Column(db.Integer, primary_key=True) client_id = db.Column(db.String(40), nullable=False) client = db.relationship('Client', backref=db.backref('tokens', cascade="all, delete"), primaryjoin='Client.client_id == Token.client_id', foreign_keys='Token.client_id') user_id = db.Column(db.Integer) user = db.relationship('User', backref=db.backref('token', uselist=False, cascade="all, delete"), primaryjoin='User.id == Token.user_id', foreign_keys='Token.user_id') token_type = db.Column(db.String(40)) access_token = db.Column(db.String(255)) refresh_token = db.Column(db.String(255)) expires = db.Column(db.DateTime) _scopes = db.Column('scopes', db.Text) def __init__(self, **kwargs): expires_in = kwargs.pop('expires_in') self.expires = datetime.utcnow() + timedelta(seconds=expires_in) for k, v in kwargs.items(): setattr(self, k, v) @property def scopes(self): if self._scopes: return self._scopes.split() return [] @scopes.setter def scopes(self, scopes): self._scopes = ' '.join(scopes) @property def is_expired(self): return datetime.utcnow() > self.expires
class Tag(db.Model, CRUDMixin): STATUS_DRAFT = 0 STATUS_PUBLIC = 1 STATUS_REMOVED = 2 STATUSES = { STATUS_DRAFT: 'draft', STATUS_PUBLIC: 'public', STATUS_REMOVED: 'closed' } id = db.Column(db.Integer, primary_key=True) _name = db.Column('name', db.String(150)) _slug = db.Column('slug', db.String(150), unique=True) description = db.Column(db.Text) _image = db.Column('image', db.String(255)) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) __mapper_args__ = {'order_by': id.desc()} @hybrid_property def slug(self): return self._slug @slug.setter def slug(self, slug): slugify_slug = slugify(slug) if slug else slugify(self.title) if not self._slug: self._slug = slugify_slug for x in itertools.count(1): if not db.session.query( db.exists().where(Tag.slug == self._slug)).scalar(): break self._slug = "{}-{}".format(slugify_slug, x) return self._slug = slugify_slug @hybrid_property def name(self): return self._name @name.setter def name(self, name): self._name = name.strip() if self.slug is None: self.slug = slugify(name)[:255] @hybrid_property def num_posts(self): return len(self.posts) @hybrid_property def image(self): if self._image: return dict(url=storage.url(self._image), filename=self._image) return {} @image.setter def image(self, image=None): if image is None: image = {} self._image = image.get('filename') image = db.synonym("_image", descriptor=image)
class Post(db.Model, CRUDMixin): STATUS_DRAFT = 'draft' STATUS_PUBLIC = 'published' STATUS_REMOVED = 'removed' id = db.Column(db.Integer, primary_key=True) _title = db.Column('title', db.String(255)) _slug = db.Column('slug', db.String(255), unique=True) _markdown = db.Column('markdown', db.Text) content = db.Column(db.Text) excerpt = db.Column(db.Text) _image = db.Column('image', db.String(255)) views = db.Column(db.Integer, default=0) status = db.Column(db.String(150), default=STATUS_DRAFT) created_at = db.Column(db.DateTime, default=datetime.utcnow) created_by = db.Column(db.Integer, index=True) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) updated_by = db.Column(db.Integer, index=True) published_at = db.Column(db.DateTime) published_by = db.Column(db.Integer, index=True) __mapper_args__ = {'order_by': id.desc()} tags = db.relationship( 'Tag', secondary=post_tag, primaryjoin='Post.id == post_tag.c.post_id', secondaryjoin='post_tag.c.tag_id==Tag.id', foreign_keys='[post_tag.c.post_id, post_tag.c.tag_id]', backref='posts') author = db.relationship('User', primaryjoin='Post.created_by == User.id', foreign_keys='Post.created_by', backref='posts') @hybrid_property def markdown(self): return self._markdown @markdown.setter def markdown(self, markdown): self._markdown = markdown renderer = mistune.Renderer(escape=False) markdown = mistune.Markdown(renderer=renderer) self.content = markdown(self._markdown) def get_excerpt(self, length=100): # return re.sub(r'<.*?>', '', (self.excerpt or self.content))[:length] return Markup(self.excerpt or self.content).striptags()[:length] @hybrid_property def title(self): return self._title @title.setter def title(self, title): self._title = title.strip() if self.slug is None: self.slug = slugify(title)[:255] @hybrid_property def slug(self): return self._slug @slug.setter def slug(self, slug): slugify_slug = slugify(slug) if slug else slugify(self.title) if not self._slug: self._slug = slugify_slug for x in itertools.count(1): if not db.session.query( db.exists().where(Post.slug == self._slug)).scalar(): break self._slug = "{}-{}".format(slugify_slug, x) return self._slug = slugify_slug @hybrid_property def image(self): if self._image: return dict(url=storage.url(self._image), filename=self._image) return {} @image.setter def image(self, image=None): if image is None: image = {} self._image = image.get('filename') image = db.synonym("_image", descriptor=image)
class User(db.Model, CRUDMixin): query_class = UserQuery STATUS_ACTIVE = 'active' STATUS_FORBIDDEN = 'forbidden' id = db.Column(db.Integer, primary_key=True) _name = db.Column('name', db.String(100), unique=True, index=True) _slug = db.Column('slug', db.String(100), unique=True, index=True) _password = db.Column("password", db.String(60), nullable=False) email = db.Column(db.String(100), unique=True, nullable=False) primary_role_id = db.Column(db.Integer) status = db.Column(db.String(100), nullable=False, default=STATUS_ACTIVE) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) primary_role = db.relationship('Role', lazy="joined", backref="primary_users", uselist=False, primaryjoin='User.primary_role_id==Role.id', foreign_keys=[primary_role_id]) secondary_roles = db.relationship( 'Role', backref=db.backref('users', lazy='dynamic'), secondary=user_role, primaryjoin='User.id==user_role.c.user_id', secondaryjoin='user_role.c.role_id==Role.id', foreign_keys=[user_role.c.user_id, user_role.c.role_id], lazy='dynamic') @hybrid_property def name(self): return self._name @name.setter def name(self, name): self._name = name.strip() if self.slug is None: self.slug = slugify(name)[:255] @hybrid_property def slug(self): return self._slug @slug.setter def slug(self, slug): self._slug = slugify(slug) if slug else slugify(self.name) @hybrid_property def password(self): return self._password @password.setter def password(self, password): self._password = generate_password_hash(password) def check_password(self, password): return check_password_hash(self._password, password) @property def roles(self): return [self.primary_role] + list(self.secondary_roles) @cached_property def permissions(self): perms = [] for role in self.roles: perms.extend(role.permissions) role = Role.query.filter_by(slug='owner').first() if role and self.primary_role == role: perms.extend(Permission.query.all()) return list(set(perms)) @cached_property def provides(self): needs = [RoleNeed('authenticated'), UserNeed(self.id)] needs.extend([ Need(perm.object_type, perm.action_type, perm.object_id) for perm in self.permissions ]) return needs @cached_property def avatar(self): gravatar_url = "https://www.gravatar.com/avatar/" return gravatar_url + hashlib.md5(self.email.lower()).hexdigest()
class Client(db.Model, CRUDMixin): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(40), unique=True) client_id = db.Column(db.String(40), index=True, default=gen_salt(40)) client_secret = db.Column(db.String(55), unique=True, index=True, nullable=False, default=gen_salt(40)) _redirect_uris = db.Column('redirect_uris', db.Text, default=" ".join([ 'http://localhost:8000/authorized', 'http://127.0.0.1:8000/authorized', 'http://127.0.1:8000/authorized', 'http://127.1:8000/authorized', ])) _default_scopes = db.Column('default_scopes', db.Text, default='email address') disallow_grant_type = db.Column(db.String(20)) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) @hybrid_property def redirect_uris(self): if self._redirect_uris: return self._redirect_uris.split() return [] @redirect_uris.setter def redirect_uris(self, redirect_uris): self._redirect_uris = ' '.join(redirect_uris) @property def default_redirect_uri(self): return self.redirect_uris[0] @hybrid_property def default_scopes(self): if self._default_scopes: return self._default_scopes.split() return [] @default_scopes.setter def default_scopes(self, default_scopes): self._default_scope = ' '.join(default_scopes) @property def allowed_grant_types(self): types = [ 'authorization_code', 'password', 'client_credentials', 'refresh_token', ] if self.disallow_grant_type: types.remove(self.disallow_grant_type) return types