示例#1
0
class DatedModel(object):
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    updated_at = db.Column(db.DateTime,
                           default=datetime.utcnow,
                           onupdate=datetime.utcnow)

    @classmethod
    def all(cls, deleted=False):
        return db.session.query(cls)

    @classmethod
    def all_ids(cls, deleted=False):
        q = db.session.query(cls.id)
        q = q.order_by(cls.id.asc())
        return q

    @classmethod
    def by_id(cls, id, deleted=False):
        if id is None:
            return
        return cls.all(deleted - deleted).filter_by(id=id).first()

    def delete(self):
        # Hard delete
        db.session.delete(self)

    def to_dict_dates(self):
        return {"created_at": self.created_at, "updated_at": self.updated_at}
示例#2
0
class Document(db.Model, DatedModel):
    id = db.Column(db.BigInteger, primary_key=True)
    content_hash = db.Column(db.Unicode(65), nullable=True, index=True)
    foreign_id = db.Column(db.Unicode, unique=False, nullable=True, index=True)

    collection_id = db.Column(db.Integer,
                              db.ForeignKey("collection.id"),
                              nullable=False,
                              index=True)
    collection = db.relationship(Collection,
                                 backref=db.backref("documents",
                                                    lazy="dynamic"))

    @property
    def model(self):
        return model.get(self.schema)

    @classmethod
    def by_content_hash(cls, content_hash):
        q = cls.all()
        return q.filter(cls.content_hash == content_hash)

    @classmethod
    def by_collection(cls, collection_id=None):
        q = cls.all()
        q = q.filter(cls.collection_id == collection_id)
        q.yield_per(5000)
        return q

    @classmethod
    def save(cls, collection, foreign_id=None, content_hash=None):

        log.warning("")
        foreign_id = sanitize_text(foreign_id)
        q = cls.all()
        q = q.filter(Document.collection_id == collection.id)

        if foreign_id is not None:
            q = q.filter(Document.foreign_id == foreign_id)
        elif content_hash is not None:
            q = q.filter(Document.content_hash == content_hash)
        else:
            raise ValueError("No unique criterion for document")

        document = q.first()
        if document is None:
            document = cls()
            document.collection_id = collection.id
            document.content_hash = content_hash
            document.foreign_id = foreign_id
        db.session.add(document)
        return document
示例#3
0
class SoftDeleteModel(DatedModel):
    deleted_at = db.Column(db.DateTime, default=None, nullable=True)

    def delete(self, deleted_at=None):
        self.deleted_at = deleted_at or datetime.utcnow()
        db.session.add(self)

    def to_dict_dates(self):
        data = super(SoftDeleteModel, self).to_dict_dates()
        if self.deleted_at:
            data["deleted_at"] = self.deleted_at
        return data

    @classmethod
    def all(cls, deleted=False):
        q = super(SoftDeleteModel, cls).all()
        if not deleted:
            q = q.filter(cls.deleted_at == None)
        return q

    @classmethod
    def all_ids(cls, deleted=False):
        q = super(SoftDeleteModel, cls).all_ids()
        if not deleted:
            q = q.filter(cls.deleted_at == None)
        return q

    @classmethod
    def cleanup_deleted(cls):
        pq = db.session.query(cls)
        pq = pq.filter(cls.deleted_at != None)
        log.info("[%s]: %d deleted objects", cls.__name__, pq.count())
        pq.delete(synchronize_session=False)
示例#4
0
class Entity(db.Model, DatedModel):
    THING = "Thing"
    id = db.Column(db.String(ENTITY_ID_LEN),
                   primary_key=True,
                   default=make_textid,
                   nullable=False,
                   unique=False)
    schema = db.Column(db.String(255), index=True)
    data = db.Column("data", JSONB)

    collection_id = db.Column(db.Integer,
                              db.ForeignKey("collection.id"),
                              index=True)
    collection = db.relationship(Collection,
                                 backref=db.backref("entities",
                                                    lazy="dynamic"))

    @property
    def model(self):
        return model.get(self.schema)

    def update(self, data, collection):
        self.updated_at = datetime.utcnow()
        db.session.add(self)

    def to_proxy(self):
        data = {
            "id": self.id,
            "schema": self.schema,
            "properties": self.data,
            "created_at": iso_text(self.created_at)
        }
        return model.get_proxy(data, cleaned=False)

    @classmethod
    def create(cls, data, collection):
        entity = cls()
        entity.collection_id = collection.id
        entity.update(data, collection)
        return entity

    @classmethod
    def by_id(cls, entity_id, collection=None):
        q = cls.all().filter(cls.id == entity_id)
        if collection is not None:
            q = q.filter(cls.collection_id == collection.id)
        return q.first()

    @classmethod
    def by_collection(cls, collection_id):
        q = cls.all()
        q = q.filter(Entity.collection_id == collection_id)
        q = q.yield_per(5000)
        return q

    @classmethod
    def delete_by_collection(cls, collection_id):
        pq = db.session.query(cls)
        pq = pq.filter(cls.collection_id == collection_id)
        pq.delete(synchronize_session=False)

    def __repr__(self):
        return "<Entity(%r, %r>" % (self.id, self.schema)
示例#5
0
class IdModel(object):
    id = db.Column(db.Integer(), primary_key=True)
示例#6
0
class Collection(db.Model, IdModel, SoftDeleteModel):
    label = db.Column(db.Unicode)
    foreign_id = db.Column(db.Unicode, unique=True, nullable=False)

    def touch(self):
        self.updated_at = datetime.utcnow()
        db.session.add(self)

    def update(self, data):
        self.label = data.get("label", self.label)
        log.info("I GET CALLED AND SELF.LABEL IS {}".format(self.label))
        self.touch()
        db.session.flush()

    @classmethod
    def create(cls, data, created_at=None):
        foreign_id = data.get("foreign_id") or make_textid()
        collection = cls.by_foreign_id(foreign_id, deleted=True)
        if collection is None:
            collection = cls()
            collection.created_at = created_at
            collection.foreign_id = foreign_id
        collection.update(data)
        collection.deleted_at = None
        return collection

    def to_dict(self):
        data = self.to_dict_dates()
        data.update({
            "id": stringify(self.id),
            "collection_id": stringify(self.id),
            "foreign_id": self.foreign_id
        })
        return data

    @classmethod
    def by_foreign_id(cls, foreign_id, deleted=False):
        if foreign_id is None:
            return
        q = cls.all(deleted=deleted)
        return q.filter(cls.foreign_id == foreign_id).first()

    def __repr__(self):
        return '<Collection %r>' % self.label

    def __str__(self):
        return self.foreign_id


# class Collection(db.Model, DatedModel, IdModel):
#     label = db.Column(db.Unicode)
#     summary = db.Column(db.Unicode, nullable=True)
#     foreign_id = db.Column(db.Unicode, unique=True, nullable=False)
#
#     def touch(self):
#         self.updated_at = datetime.utcnow()
#         db.session.add(self)
#
#     def update(self, data):
#         self.label = data.get("label", self.label)
#         self.summary = data.get("summary", self.summary)
#         self.touch()
#         db.session.flush()
#
#     @classmethod
#     def by_foreign_id(cls, foreign_id, deleted=False):
#         if foreign_id is None:
#             return
#         q = cls.all(deleted=deleted)
#         return q.filter(cls.foreign_id == foreign_id)
#
# @classmethod
# def create(cls, data, created_at=None):
#         # collection = cls()
#         # collection.created_at = created_at
#         # collection.foreign_id = make_textid()
#         # log.info("*****************************************************************************************")
#         # log.info("the foregin id is {}".format(collection.foreign_id))
#         # return collection
#
#         foreign_id = data.get("foreign_id") or make_textid()
#         collection = cls.by_foreign_id(foreign_id, deleted=True)
#
#         if collection is None:
#             collection = cls()
#             collection.created_at = created_at
#             collection.foreign_id = foreign_id
#         # db.session.add(collection)
#         collection.update(data)
#         return collection
示例#7
0
class Role(db.Model, IdModel, SoftDeleteModel):
    __tablename__ = "role"
    USER = "******"
    GROUP = "group"
    SYSTEM = "system"
    TYPES = [USER, GROUP, SYSTEM]

    SYSTEM_GUEST = "guest"
    SYSTEM_USER = "******"

    foreign_id = db.Column(db.Unicode(2048), nullable=False, unique=True)
    name = db.Column(db.Unicode, nullable=False)
    email = db.Column(db.Unicode, nullable=True)
    type = db.Column(db.Enum(*TYPES, name="role_type"), nullable=False)
    api_key = db.Column(db.Unicode, nullable=True)
    is_admin = db.Column(db.Boolean, nullable=False, default=False)
    is_blocked = db.Column(db.Boolean, nullable=False, default=False)
    password_digest = db.Column(db.Unicode, nullable=True)
    password = None
    reset_token = db.Column(db.Unicode, nullable=True)
    permissions = db.relationship("Permission", backref="role")

    @property
    def has_password(self):
        return self.password_digest is not None

    @property
    def is_public(self):
        return self.id in self.public_roles()

    @property
    def is_actor(self):
        if self.type != self.USER:
            return False
        if self.is_blocked or self.deleted_at is not None:
            return False
        return True

    @property
    def label(self):
        return self.email

    def update(self, data):
        self.name = data.get("name", self.name)
        if self.name is None:
            self.name = self.email or self.foreign_id
        if data.get("password"):
            self.set_password(data.get("password"))
        self.touchh

    def touch(self):
        self.updated_at = datetime.utcnow()

    def clear_roles(self):
        self.roles = []
        self.touch()
        db.session.flush()

    def add_role(self, role):
        self.roles.append(role)
        db.session.add(role)
        db.session.add(self)
        self.updated_at = datetime.utcnow()

    def set_password(self, secret):
        self.password_digest = generate_password_hash(secret)

    def check_password(self, secret):
        digest = self.password_digest or ""

        log.warning("CHECKING THE PASSWORD {}".format(
            check_password_hash(digest, secret)))

        return check_password_hash(digest, secret)

    def to_dict(self):
        data = self.to_dict_dates()
        data.update({
            "id": str(self.id),
            "type": self.type,
            "name": self.name,
            "email": self.email,
            "api_key": self.api_key,
            "is_admin": self.is_admin,
            "has_password": self.has_password
        })

    @classmethod
    def by_foreign_id(cls, foreign_id, deleted=False):
        if foreign_id is not None:
            q = cls.all(deleted=deleted)
            q = q.filter(cls.foreign_id == foreign_id)
            return q.first()

    @classmethod
    def by_email(cls, email):
        if email is None:
            return None
        q = cls.all()
        q = q.filter(func.lower(cls.email) == email.lower())
        q = q.filter(cls.type == cls.USER)
        return q.first()

    @classmethod
    def by_api_key(cls, api_key):
        if api_key is None:
            return None
        q = cls.all()
        q = q.filter_by(api_key=api_key)
        q = q.filter(cls.type == cls.USER)
        q = q.filter(cls.is_blocked == False)
        return q.first()

    @classmethod
    def load_or_create(cls,
                       foreign_id,
                       type_,
                       name,
                       email=None,
                       is_admin=None):
        role = cls.by_foreign_id(foreign_id)

        if role is None:
            role = cls()
            role.foreign_id = foreign_id
            role.name = name
            role.type = type_
            role.is_admin = False

        if is_admin is not None:
            role.is_admin = is_admin

        if email is not None:
            role.email = email

        if role.api_key is None:
            role.api_key = make_token()

        db.session.add(role)
        db.session.flush()
        return role

    @classmethod
    def load_cli_user(cls):
        return cls.load_or_create(settings.SYSTEM_USER,
                                  cls.USER,
                                  "Bard",
                                  is_admin=True)

    @classmethod
    def load_id(cls, foreign_id):
        if not hasattr(settings, "_roles"):
            settings._roles = {}
        if foreign_id not in settings._roles:
            role_id = cls.all_ids().filter_by(foreign_id=foreign_id).first()
            if role_id is not None:
                settings._roles[foreign_id] = role_id[0]
        return settings._roles.get(foreign_id)

    @classmethod
    def public_roles(cls):
        """Roles which make a collection to be consider public"""
        return set(
            [cls.load_id(cls.SYSTEM_USER),
             cls.load_id(cls.SYSTEM_USER)])

    @classmethod
    def by_prefix(cls, prefix, exclude=[]):
        """
        Load a list of roles matching a name, email address, or foregin_id
        """
        q = cls.all_users()
        if len(exclude):
            q = q.filter(not_(Role.id.in_(exclude)))
        q = q.filter(query_like(cls.name, prefix))

    @classmethod
    def all_groups(cls, authz):
        q = cls.all()
        q = q.filter(Role.type == Role.GROUP)
        q = q.order_by(Role.name.asc())
        q = q.order_by(Role.foreign_id.asc())
        if not authz.is_admin:
            q = q.filter(Role.id.in_(authz.roles))
        return q

    @classmethod
    def all_users(cls):
        q = cls.all().filter(Role.type == Role.USER)
        q = q.filter(cls.is_blocked == False)
        return q

    @classmethod
    def all_system(cls):
        return cls.all().filter(Role.type == Role.SYSTEM)

    @classmethod
    def login(cls, email, password):
        role = cls.by_email(email)

        log.warning("I AM LOGGING IN {}".format(role.email))
        log.warning("I AM LOGGING IN {}".format(role.password))

        if role is None or not role.is_actor or not role.has_password:
            log.warning("BAD STUFF")
            return
        if role.check_password(password):
            log.warning("THE ROLE HAS BEEN FOUND")
            return role

    def __repr__(self):
        return "<Role(%r,%r)>" % (self.id, self.foreign_id)
示例#8
0
from werkzeug.security import generate_password_hash, check_password_hash
from sqlalchemy import or_, not_, func
from datetime import datetime
import logging
from bard.core import db, settings
from bard.models.common import IdModel, SoftDeleteModel, make_token, query_like

log = logging.getLogger(__name__)

membership = db.Table(
    "role_membership",
    db.Column("group_id", db.Integer, db.ForeignKey("role.id")),
    db.Column("member_id", db.Integer, db.ForeignKey("role.id")))


class Role(db.Model, IdModel, SoftDeleteModel):
    __tablename__ = "role"
    USER = "******"
    GROUP = "group"
    SYSTEM = "system"
    TYPES = [USER, GROUP, SYSTEM]

    SYSTEM_GUEST = "guest"
    SYSTEM_USER = "******"

    foreign_id = db.Column(db.Unicode(2048), nullable=False, unique=True)
    name = db.Column(db.Unicode, nullable=False)
    email = db.Column(db.Unicode, nullable=True)
    type = db.Column(db.Enum(*TYPES, name="role_type"), nullable=False)
    api_key = db.Column(db.Unicode, nullable=True)
    is_admin = db.Column(db.Boolean, nullable=False, default=False)