Exemple #1
0
            class Test:

                id = Integer(primary_key=True)
                properties = Json()
                name = JsonRelated(json_column='properties',
                                   keys=['name'],
                                   set_adapter=str,
                                   get_adapter=int)
Exemple #2
0
class Resource(Declarations.Model.FuretUI.Menu, Declarations.Mixin.FuretUIMenu,
               Declarations.Mixin.FuretUIMenuParent):
    resource = Many2One(model=Declarations.Model.FuretUI.Resource,
                        nullable=False)
    default = Boolean(default=False)
    tags = String()
    order_by = String()
    filters = Json(default={})

    def check_acl(self):
        return self.resource.check_acl()
Exemple #3
0
class Sub:

    id = Integer(primary_key=True)
    sequence = Integer(nullable=False, default=100)
    label = String(nullable=False)
    properties = Json(default={})
    login_state = Selection(selections={
        'logged': 'Logged',
        'unlogged': 'Unlogged',
        'both': 'Logged and Unlogged',
    },
                            nullable=False,
                            default='both')
    parent = Many2One(model=Declarations.Model.FuretUI.Menu,
                      one2many="children")

    @classmethod
    def update_query_from_authenticated_id(cls, query, authenticated_userid):
        if authenticated_userid:
            query = query.filter(cls.login_state.in_(['logged', 'both']))
        else:
            query = query.filter(cls.login_state.in_(['unlogged', 'both']))

        return query

    @classmethod
    def get_for(cls, parent, authenticated_userid):
        # TODO raise if MENU_TYPE is None
        query = cls.query()
        query = query.filter(cls.parent == parent)
        query = cls.update_query_from_authenticated_id(query,
                                                       authenticated_userid)

        query = query.order_by(cls.sequence)
        return [x.format_menu(authenticated_userid) for x in query]

    def format_menu(self, authenticated_userid):
        menu = {}
        if self.properties:
            menu.update(self.properties)

        menu.update({
            'name': self.id,
            'label': self.label,
        })
        return menu
Exemple #4
0
            class Test:

                id = Integer(primary_key=True)
                properties = Json()
                name = JsonRelated(json_column='properties',
                                   keys=['name'],
                                   set_adapter='fromint',
                                   get_adapter='toint')

                def fromint(self, value):
                    if value:
                        return str(value)

                    return value

                def toint(self, value):
                    if value:
                        return int(value)

                    return value
Exemple #5
0
class Message(Declarations.Mixin.DramatiqMessageStatus):
    """Message model for dramatiq"""

    id = UUID(primary_key=True, nullable=False)
    updated_at = DateTime()
    message = Json(nullable=False)

    def __str__(self):
        return '<Message (id={self.id}, status={self.status.label})>'.format(
            self=self)

    @classmethod
    def insert(cls, *args, **kwargs):
        """Over write the insert to add the first history line"""
        self = super(Message, cls).insert(*args, **kwargs)
        self.updated_at = datetime.now()
        self.registry.Dramatiq.Message.History.insert(
            status=self.status, created_at=self.updated_at, message=self)
        return self

    @classmethod
    def get_instance_of(cls, message):
        """Called by the middleware to get the model instance of the message"""
        return cls.query().filter(cls.id == message.message_id).one_or_none()

    def update_status(self, status, error=None):
        """Called by the middleware to change the status and history"""
        logger.info("Update message %s status => %s", self,
                    dict(self.STATUSES).get(status))
        self.status = status
        self.updated_at = datetime.now()
        self.registry.Dramatiq.Message.History.insert(
            status=status,
            created_at=self.updated_at,
            message=self,
            error=error)
Exemple #6
0
class Parameter:
    """Applications parameters.

    This Model is provided by ``anyblok-core`` to give applications a uniform
    way of specifying in-database configuration.

    It is a simple key/value representation, where values can be of any type
    that can be encoded as JSON.

    A simple access API is provided with the :meth:`get`, :meth:`set`,
    :meth:`is_exist` and further methods.
    """

    key = String(primary_key=True)
    value = Json(nullable=False)
    multi = Boolean(default=False)

    @classmethod
    def set(cls, key, value):
        """ Insert or update parameter value for a key.

        .. note:: if the key already exists, the value will be updated

        :param str key: key to save
        :param value: value to save
        """
        multi = False
        if not isinstance(value, dict):
            value = {'value': value}
        else:
            multi = True

        if cls.is_exist(key):
            param = cls.from_primary_keys(key=key)
            param.update(value=value, multi=multi)
        else:
            cls.insert(key=key, value=value, multi=multi)

    @classmethod
    def is_exist(cls, key):
        """ Check if one parameter exist for the key

        :param key: key to check
        :rtype: bool
        """
        query = cls.query().filter(cls.key == key)
        return True if query.count() else False

    @classmethod
    def get(cls, key, default=NOT_PROVIDED):
        """ Return the value of the key

        :param key: key whose value to retrieve
        :param default: default value if key does not exists
        :return: associated value
        :rtype: anything JSON encodable
        :raises ParameterException: if the key doesn't exist and default is not
                                    set.
        """
        if not cls.is_exist(key):
            if default is NOT_PROVIDED:
                raise ParameterException(
                    "unexisting key %r" % key)
            return default

        param = cls.from_primary_keys(key=key)
        if param.multi:
            return param.value

        return param.value['value']

    @classmethod
    def pop(cls, key):
        """Remove the given key and return the associated value.

        :param str key: the key to remove
        :return: the value before removal
        :rtype: any JSON encodable type
        :raises ParameterException: if the key wasn't present
        """
        if not cls.is_exist(key):
            raise ParameterException(
                "unexisting key %r" % key)

        param = cls.from_primary_keys(key=key)
        if param.multi:
            res = param.value
        else:
            res = param.value['value']

        param.delete()
        return res
Exemple #7
0
class Document:
    DOCUMENT_TYPE = None

    uuid = UUID(primary_key=True, binary=False, nullable=False)
    version_number = Integer(primary_key=True, nullable=False)
    version = Function(fget="get_version")

    created_at = DateTime(default=datetime.now, nullable=False)
    historied_at = DateTime()

    data = Json(default=dict)

    file_added_at = DateTime()
    filename = String(size=256)
    contenttype = String()
    filesize = Integer()
    file = LargeBinary()
    hash = String(size=256)

    type = Selection(selections={
        'latest': 'Latest',
        'history': 'History'
    },
                     nullable=False)

    previous_doc_uuid = UUID()
    previous_doc_version_number = Integer()
    previous_version = Function(fget="get_previous_version")
    next_version = Function(fget="get_next_version")
    previous_versions = Function(fget="get_previous_versions")

    @classmethod
    def get_file_fields(cls):
        return [
            'file', 'file_added_at', 'contenttype', 'filename', 'hash',
            'filesize'
        ]

    def get_file(self):
        return self.to_dict(*self.get_file_fields())

    def set_file(self, file_):
        self.file = file_

    def get_version(self):
        return "V-%06d" % self.version_number

    def get_previous_version(self):
        Doc = self.anyblok.Attachment.Document
        query = Doc.query()
        query = query.filter(Doc.uuid == self.previous_doc_uuid)
        query = query.filter(
            Doc.version_number == self.previous_doc_version_number)
        return query.one_or_none()

    def get_next_version(self):
        Doc = self.anyblok.Attachment.Document
        query = Doc.query()
        query = query.filter(Doc.previous_doc_uuid == self.uuid)
        query = query.filter(
            Doc.previous_doc_version_number == self.version_number)
        return query.one_or_none()

    def get_previous_versions(self):
        res = []
        current = self
        while current.previous_version:
            current = current.previous_version
            res.append(current)

        return res

    @classmethod
    def define_mapper_args(cls):
        mapper_args = super(Document, cls).define_mapper_args()
        if cls.__registry_name__ == 'Model.Attachment.Document':
            mapper_args.update({'polymorphic_on': cls.type})

        mapper_args.update({'polymorphic_identity': cls.DOCUMENT_TYPE})
        return mapper_args

    @classmethod
    def insert(cls, *args, **kwargs):
        if cls.__registry_name__ == 'Model.Attachment.Document':
            return cls.anyblok.Attachment.Document.Latest.insert(
                *args, **kwargs)

        return super(Document, cls).insert(*args, **kwargs)

    @classmethod
    def query(cls, *args, **kwargs):
        query = super(Document, cls).query(*args, **kwargs)
        if cls.__registry_name__ != 'Model.Attachment.Document':
            query = query.filter(cls.type == cls.DOCUMENT_TYPE)

        return query

    def has_file(self):
        if self.file:
            return True

        return False

    @classmethod
    def filter_has_not_file(cls):
        return cls.file == None  # noqa
Exemple #8
0
            class Test:

                id = Integer(primary_key=True)
                properties = Json()
                name = JsonRelated(json_column='properties')
Exemple #9
0
            class Test:

                id = Integer(primary_key=True)
                properties = Json()
                name = JsonRelated(keys=['name'])
Exemple #10
0
class Mapping:

    key = String(primary_key=True)
    model = String(primary_key=True,
                   foreign_key=Model.System.Model.use('name'))
    primary_key = Json(nullable=False)
    blokname = String(label="Blok name",
                      foreign_key=Model.System.Blok.use('name'))

    @hybrid_method
    def filter_by_model_and_key(self, model, key):
        """ SQLAlechemy hybrid method to filter by model and key

        :param model: model of the mapping
        :param key: external key of the mapping
        """
        return (self.model == model) & (self.key == key)

    @hybrid_method
    def filter_by_model_and_keys(self, model, *keys):
        """ SQLAlechemy hybrid method to filter by model and key

        :param model: model of the mapping
        :param key: external key of the mapping
        """
        return (self.model == model) & self.key.in_(keys)

    def remove_element(self, byquery=False):
        val = self.registry.get(self.model).from_primary_keys(
            **self.primary_key)
        logger.info("Remove entity for %r.%r: %r" % (
            self.model, self.key, val))
        val.delete(byquery=byquery, remove_mapping=False)

    @classmethod
    def multi_delete(cls, model, *keys, **kwargs):
        """ Delete all the keys for this model

        :param model: model of the mapping
        :param \*keys: list of the key
        :rtype: Boolean True if the mappings are removed
        """
        mapping_only = kwargs.get('mapping_only', True)
        byquery = kwargs.get('byquery', False)
        query = cls.query()
        query = query.filter(cls.filter_by_model_and_keys(model, *keys))
        count = query.count()
        if count:
            if not mapping_only:
                query.all().remove_element(byquery=byquery)

            query.delete(synchronize_session='fetch', remove_mapping=False)
            cls.registry.expire_all()
            return count

        return 0

    @classmethod
    def delete(cls, model, key, mapping_only=True, byquery=False):
        """ Delete the key for this model

        :param model: model of the mapping
        :param key: string of the key
        :rtype: Boolean True if the mapping is removed
        """
        query = cls.query()
        query = query.filter(cls.filter_by_model_and_key(model, key))
        count = query.count()
        if count:
            if not mapping_only:
                query.one().remove_element(byquery=byquery)

            query.delete(remove_mapping=False)
            return count

        return 0

    @classmethod
    def get_mapping_primary_keys(cls, model, key):
        """ return primary key for a model and an external key

        :param model: model of the mapping
        :param key: string of the key
        :rtype: dict primary key: value or None
        """
        query = cls.query()
        query = query.filter(cls.filter_by_model_and_key(model, key))
        if query.count():
            pks = query.first().primary_key
            cls.check_primary_keys(model, *pks.keys())
            return pks

        return None

    @classmethod
    def check_primary_keys(cls, model, *pks):
        """ check if the all the primary keys match with primary keys of the
        model

        :param model: model to check
        :param pks: list of the primary keys to check
        :exception: IOMappingCheckException
        """
        for pk in cls.get_model(model).get_primary_keys():
            if pk not in pks:
                raise IOMappingCheckException(
                    "No primary key %r found in %r for model %r" % (
                        pk, pks, model))

    @classmethod
    def set_primary_keys(cls, model, key, pks, raiseifexist=True,
                         blokname=None):
        """ Add or update a mmping with a model and a external key

        :param model: model to check
        :param key: string of the key
        :param pks: dict of the primary key to save
        :param raiseifexist: boolean (True by default), if True and the entry
            exist then an exception is raised
        :param blokname: name of the blok where come from the mapping
        :exception: IOMappingSetException
        """
        if cls.get_mapping_primary_keys(model, key):
            if raiseifexist:
                raise IOMappingSetException(
                    "One value found for model %r and key %r" % (model, key))
            cls.delete(model, key)

        if not pks:
            raise IOMappingSetException(
                "No value to save %r for model %r and key %r" % (
                    pks, model, key))

        cls.check_primary_keys(model, *pks.keys())
        vals = dict(model=model, key=key, primary_key=pks)
        if blokname is not None:
            vals['blokname'] = blokname

        return cls.insert(**vals)

    @classmethod
    def set(cls, key, instance, raiseifexist=True, blokname=None):
        """ Add or update a mmping with a model and a external key

        :param model: model to check
        :param key: string of the key
        :param instance: instance of the model to save
        :param raiseifexist: boolean (True by default), if True and the entry
            exist then an exception is raised
        :param blokname: name of the blok where come from the mapping
        :exception: IOMappingSetException
        """
        pks = instance.to_primary_keys()
        return cls.set_primary_keys(instance.__registry_name__, key, pks,
                                    blokname=blokname,
                                    raiseifexist=raiseifexist)

    @classmethod
    def get(cls, model, key):
        """ return instance of the model with this external key

        :param model: model of the mapping
        :param key: string of the key
        :rtype: instance of the model
        """
        pks = cls.get_mapping_primary_keys(model, key)
        if pks is None:
            return None

        return cls.get_model(model).from_primary_keys(**pks)

    @classmethod
    def get_from_model_and_primary_keys(cls, model, pks):
        query = cls.query().filter(cls.model == model)
        for mapping in query.all():
            if mapping.primary_key == pks:
                return mapping

        return None

    @classmethod
    def get_from_entry(cls, entry):
        return cls.get_from_model_and_primary_keys(
            entry.__registry_name__, entry.to_primary_keys())

    @classmethod
    def __get_models(cls, models):
        """Return models name

        if models is not: return all the existing model
        if models is a list of instance model, convert them

        :params models: list of model
        """
        if models is None:
            models = cls.registry.System.Model.query().all().name
        elif not isinstance(models, (list, tuple)):
            models = [models]

        return [m.__registry_name__ if hasattr(m, '__registry_name__') else m
                for m in models]

    @classmethod
    def clean(cls, bloknames=None, models=None):
        """Clean all mapping with removed object linked::

            Mapping.clean(bloknames=['My blok'])

        .. warning::

            For filter only the no blokname::

                Mapping.clean(bloknames=[None])

        :params bloknames: filter by blok, keep the order to remove the mapping
        :params models: filter by model, keep the order to remove the mapping
        """
        if bloknames is None:
            bloknames = cls.registry.System.Blok.query().all().name + [None]
        elif not isinstance(bloknames, (list, tuple)):
            bloknames = [bloknames]
        models = cls.__get_models(models)

        removed = 0
        for blokname in bloknames:
            for model in models:
                query = cls.query().filter_by(blokname=blokname, model=model)
                for key in query.all().key:
                    if cls.get(model, key) is None:
                        cls.delete(model, key)
                        removed += 1

        return removed

    @classmethod
    def delete_for_blokname(cls, blokname, models=None, byquery=False):
        """Clean all mapping with removed object linked::

            Mapping.clean('My blok')

        .. warning::

            For filter only the no blokname::

                Mapping.clean(None)

        :params blokname: filter by blok
        :params models: filter by model, keep the order to remove the mapping
        """
        models = cls.__get_models(models)

        removed = 0
        for model in models:
            query = cls.query().filter_by(blokname=blokname, model=model)
            for key in query.all().key:
                if cls.get(model, key):
                    cls.delete(model, key, mapping_only=False, byquery=byquery)
                    cls.registry.flush()
                    removed += 1

        return removed
class Authorization:
    """A model to store autorization rules (permissions for users against an
    Anyblok model or a Pyramid resource)"""

    id = Integer(primary_key=True)
    order = Integer(default=100, nullable=False)

    resource = String()
    model = String(
        foreign_key=Declarations.Model.System.Model.use('name').options(
            ondelete="cascade"))
    primary_keys = Json(default={})
    filter = Json(default={})  # next step

    role = Many2One(model=User.Role,
                    foreign_key_options={'ondelete': 'cascade'})
    login = String(foreign_key=User.use('login').options(ondelete="cascade"))
    user = Many2One(model=User)
    perms = Json(default={})

    perm_create = JsonRelated(json_column='perms', keys=['create'])
    perm_read = JsonRelated(json_column='perms', keys=['read'])
    perm_update = JsonRelated(json_column='perms', keys=['update'])
    perm_delete = JsonRelated(json_column='perms', keys=['delete'])

    @classmethod
    def get_acl_filter_model(cls):
        """Return the Model to use to check the permission"""
        return {
            'User': cls.registry.User,
            'Role': cls.registry.User.Role,
        }

    @classmethod
    def get_acl(cls, login, resource, params=None):
        """Return the Pyramid ACL in function of the resource and user

        :param login: str, login of the user
        :param resource: str, name of the resource
        """
        # cache the method
        User = cls.registry.User
        Role = cls.registry.User.Role

        query = cls.query()
        query = query.filter(
            or_(cls.resource == resource, cls.model == resource))
        query = query.order_by(cls.order)
        Q1 = query.filter(cls.login == login)
        Q2 = query.join(cls.role).filter(Role.name.in_(User.get_roles(login)))
        res = []
        for query in (Q1, Q2):
            for self in query.all():
                allow_perms = []
                deny_perms = []
                perms = list((self.perms or {}).keys())
                perms.sort()
                for perm in perms:
                    p = self.perms[perm]
                    query = User.query()
                    query = query.filter(User.login == login)
                    query = query.join(User.roles)
                    if self.filter:
                        query = query.condition_filter(
                            self.filter, cls.get_acl_filter_model())

                    if 'condition' in p:
                        query = query.condition_filter(
                            p['condition'], cls.get_acl_filter_model())

                    ismatched = True if query.count() else False
                    if p.get('matched' if ismatched else 'unmatched') is True:
                        allow_perms.append(perm)
                    elif (p.get('matched' if ismatched else 'unmatched') is
                          False):
                        deny_perms.append(perm)

                if len(allow_perms):
                    res.append((Allow, login, allow_perms))

                if len(deny_perms):
                    res.append((Deny, login, deny_perms))

        res.append((Deny, login, ALL_PERMISSIONS))
        return res

    @classmethod
    def before_insert_orm_event(cls, mapper, connection, target):
        target.check_validity()

    @classmethod
    def before_update_orm_event(cls, mapper, connection, target):
        target.check_validity()

    def check_validity(self):
        """When creating or updating a User.Authorization, check that all rules
        objects exists or return an AuthorizationValidationException

        :exception: AuthorizationValidationException
        """
        if not (self.role or self.login or self.user or self.role_name):
            raise AuthorizationValidationException(
                "No role and login to apply in the authorization (%s)" % self)

        if not (self.resource or self.model):
            raise AuthorizationValidationException(
                "No resource and model to apply in the authorization (%s)" %
                self)

        if not self.model and self.primary_keys:
            raise AuthorizationValidationException(
                "Primary keys without model to apply in the authorization "
                "(%s)" % self)
Exemple #12
0
class Authorization:
    """A model to store autorization rules (permissions for users against an
    Anyblok model or a Pyramid resource)"""

    id = Integer(primary_key=True)
    code = String(nullable=True, unique=True, size=256)
    order = Integer(default=100, nullable=False)

    resource = String()
    model = String(
        foreign_key=Declarations.Model.System.Model.use('name').options(
            ondelete="cascade"),
        size=256,
    )
    primary_keys = Json(default={})
    filter = Json(default={})  # next step

    role = Many2One(
        model=Pyramid.Role, foreign_key_options={'ondelete': 'cascade'})
    login = String(
        foreign_key=Pyramid.User.use('login').options(ondelete="cascade"))
    user = Many2One(model=Pyramid.User)
    perms = Json(default={})

    perm_create = JsonRelated(json_column='perms', keys=['create'])
    perm_read = JsonRelated(json_column='perms', keys=['read'])
    perm_update = JsonRelated(json_column='perms', keys=['update'])
    perm_delete = JsonRelated(json_column='perms', keys=['delete'])

    @classmethod
    def get_acl_filter_model(cls):
        """Return the Model to use to check the permission"""
        return {
            'User': cls.anyblok.Pyramid.User,
            'Role': cls.anyblok.Pyramid.Role,
        }

    @classmethod
    def get_acl(cls, login, resource, params=None):
        """Return the Pyramid ACL in function of the resource and user

        :param login: str, login of the user
        :param resource: str, name of the resource
        """
        # cache the method
        User = cls.anyblok.Pyramid.User
        Role = cls.anyblok.Pyramid.Role

        query = cls.query()
        query = query.filter(
            or_(cls.resource == resource, cls.model == resource))
        query = query.order_by(cls.order)
        Q1 = query.filter(cls.login == login)
        Q2 = query.join(cls.role).filter(Role.name.in_(User.get_roles(login)))
        res = []
        for query in (Q1, Q2):
            for self in query.all():
                allow_perms = []
                deny_perms = []
                perms = list((self.perms or {}).keys())
                perms.sort()
                for perm in perms:
                    p = self.perms[perm]
                    query = User.query()
                    query = query.filter(User.login == login)
                    query = query.join(User.roles)
                    if self.filter:
                        query = query.condition_filter(
                            self.filter,
                            cls.get_acl_filter_model()
                        )

                    if 'condition' in p:
                        query = query.condition_filter(
                            p['condition'],
                            cls.get_acl_filter_model()
                        )

                    ismatched = True if query.count() else False
                    if p.get('matched' if ismatched else 'unmatched') is True:
                        allow_perms.append(perm)
                    elif (
                        p.get('matched' if ismatched else 'unmatched') is False
                    ):
                        deny_perms.append(perm)

                if len(allow_perms):
                    res.append((Allow, login, allow_perms))

                if len(deny_perms):
                    res.append((Deny, login, deny_perms))

        res.append((Deny, login, ALL_PERMISSIONS))
        return res

    @classmethod
    def check_acl(cls, login, resource, type_):
        """Return the Pyramid ACL in function of the resource and user

        :param login: str, login of the user
        :param resource: str, name of the resource
        :param type: str, name of the action
        """
        # cache the method
        User = cls.anyblok.Pyramid.User
        Role = cls.anyblok.Pyramid.Role

        query = cls.query()
        query = query.filter(
            or_(cls.resource == resource, cls.model == resource))
        query = query.order_by(cls.order)
        Q1 = query.filter(cls.login == login)
        Q2 = query.join(cls.role).filter(Role.name.in_(User.get_roles(login)))
        for query in (Q1, Q2):
            for self in query.all():
                perms = list((self.perms or {}).keys())
                if type_ not in perms:
                    continue

                p = self.perms[type_]
                query = User.query()
                query = query.filter(User.login == login)
                query = query.join(User.roles, isouter=True)
                if self.filter:
                    query = query.condition_filter(
                        self.filter,
                        cls.get_acl_filter_model()
                    )

                if 'condition' in p:
                    query = query.condition_filter(
                        p['condition'],
                        cls.get_acl_filter_model()
                    )

                ismatched = True if query.count() else False
                if p.get('matched' if ismatched else 'unmatched') is True:
                    return True
                elif (
                    p.get('matched' if ismatched else 'unmatched') is False
                ):
                    return False

        return False

    @classmethod
    def before_insert_orm_event(cls, mapper, connection, target):
        target.check_validity()

    @classmethod
    def before_update_orm_event(cls, mapper, connection, target):
        target.check_validity()

    def check_validity(self):
        """When creating or updating a User.Authorization, check that all rules
        objects exists or return an AuthorizationValidationException

        :exception: AuthorizationValidationException
        """
        if not (self.role or self.login or self.user or self.role_name):
            raise AuthorizationValidationException(
                "No role and login to apply in the authorization (%s)" % self)

        if not (self.resource or self.model):
            raise AuthorizationValidationException(
                "No resource and model to apply in the authorization (%s)" %
                self)

        if not self.model and self.primary_keys:
            raise AuthorizationValidationException(
                "Primary keys without model to apply in the authorization "
                "(%s)" % self)

    @classmethod
    def ensure_exists(
        cls, code, **kwargs
    ):
        """Ensure role's authorization is present

        :param code: String, authorization code.
        :param kwargs: authorization fields
        """
        if not kwargs:
            kwargs = {}  # pragma: no cover

        # pv: at some point adding index on this criteria may boost things
        # while setting authorizations
        authz = (
            cls.anyblok.Pyramid.Authorization.query()
            .filter_by(
                code=code,
            )
            .one_or_none()
        )
        if not authz:
            authz = cls.anyblok.Pyramid.Authorization.insert(
                code=code, **kwargs
            )
        else:
            authz.update(**kwargs)
            jsonfields = {"perms", "primary_keys", "filter"}
            perms_related = {
                "perm_create",
                "perm_read",
                "perm_update",
                "perm_delete"
            }

            modified = (jsonfields | perms_related) & set(kwargs.keys())
            if modified:
                if perms_related & modified:
                    modified = modified | {"perms"}
                authz.flag_modified(*(jsonfields & modified))
        return authz
Exemple #13
0
class Job:
    """The job is an execution of an instance of task"""
    STATUS_NEW = "new"
    STATUS_WAITING = "waiting"
    STATUS_RUNNING = "running"
    STATUS_FAILED = "failed"
    STATUS_DONE = "done"

    STATUSES = [
        (STATUS_NEW, "New"),
        (STATUS_WAITING, "Waiting"),
        (STATUS_RUNNING, "Running"),
        (STATUS_FAILED, "Failed"),
        (STATUS_DONE, "Done"),
    ]

    uuid = UUID(primary_key=True, nullable=False, default=uuid1, binary=False)
    create_at = DateTime(default=datetime.now, nullable=False)
    update_at = DateTime(default=datetime.now,
                         nullable=False,
                         auto_update=True)
    run_at = DateTime()
    data = Json(nullable=False)
    status = Selection(selections=STATUSES, default=STATUS_NEW, nullable=False)
    task = Many2One(model=Declarations.Model.Dramatiq.Task, nullable=False)
    main_job = Many2One(model='Model.Dramatiq.Job', one2many="sub_jobs")
    error = Text()

    @actor_send()
    def run(cls, job_uuid=None):
        """dramatiq actor to execute a specific task"""
        autocommit = EnvironmentManager.get('job_autocommit', True)
        try:
            job = cls.query().filter(cls.uuid == job_uuid).one()
            job.status = cls.STATUS_RUNNING
            if autocommit:
                cls.registry.commit()  # use to save the state

            job.task.run(job)

            if autocommit:
                cls.registry.commit()  # use to save the state
        except Exception as e:
            logger.error(str(e))
            cls.registry.rollback()
            job.status = cls.STATUS_FAILED
            job.error = str(e)

            if autocommit:
                cls.registry.commit()  # use to save the state

            raise e

    def lock(self):
        """lock the job to be sure that only one thread execute the run_next"""
        Job = self.__class__
        while True:
            try:
                Job.query().with_for_update(nowait=True).filter(
                    Job.uuid == self.uuid).one()
                break
            except OperationalError:
                sleep(1)

    def call_main_job(self):
        """Call the main job if exist to do the next action of the main job"""
        if self.main_job:
            self.main_job.lock()
            self.main_job.task.run_next(self.main_job)
Exemple #14
0
class Menu:
    MENU_TYPE = None

    id = Integer(primary_key=True)
    sequence = Integer(nullable=False, default=100)
    label = String(nullable=False)
    component = String()
    properties = Json(default={})
    login_state = Selection(selections={
        'logged': 'Logged',
        'unlogged': 'Unlogged',
        'both': 'Logged and Unlogged',
    },
                            nullable=False)
    label_is_props = String()
    type = Selection(selections={
        'user': '******',
        'spaces': 'Space',
        'spaceiMenus': 'Space menus'
    },
                     nullable=False)

    @classmethod
    def define_mapper_args(cls):
        mapper_args = super(Menu, cls).define_mapper_args()
        if cls.__registry_name__ == 'Model.FuretUI.Menu':
            mapper_args.update({'polymorphic_on': cls.type})

        mapper_args.update({'polymorphic_identity': cls.MENU_TYPE})
        return mapper_args

    @classmethod
    def query(cls, *args, **kwargs):
        query = super(Menu, cls).query(*args, **kwargs)
        if cls.__registry_name__ != 'Model.FuretUI.Menu':
            query = query.filter(cls.type == cls.MENU_TYPE)

        return query

    @classmethod
    def update_query_from_authenticated_id(cls, query, authenticated_userid):
        query = query.order_by(cls.sequence)
        if authenticated_userid:
            query = query.filter(cls.login_state.in_(['logged', 'both']))
        else:
            query = query.filter(cls.login_state.in_(['unlogged', 'both']))

        return query

    @classmethod
    def get_for(cls, authenticated_userid):
        # TODO raise if MENU_TYPE is None
        query = cls.query()
        query = cls.update_query_from_authenticated_id(query,
                                                       authenticated_userid)
        return [x.format_menu(authenticated_userid) for x in query]

    def format_menu(self, authenticated_userid):
        menu = {}
        if self.properties:
            menu.update(self.properties)

        menu.update({
            'name': self.id,
            'label': self.label,
        })
        if self.component:
            menu['component'] = self.component

        if self.label_is_props:
            if 'props' not in menu:
                menu['props'] = {}

            menu['props'][self.label_is_props] = self.label

        children = self.registry.FuretUI.Menu.Sub.get_for(
            self, authenticated_userid)
        if children:
            menu['props']['children'] = children

        return menu
class Jinja(Mixin.WkHtml2Pdf, Attachment.Template):
    """Jinja templating"""
    TYPE = TYPE

    uuid = UUID(primary_key=True,
                nullable=False,
                binary=False,
                foreign_key=Attachment.Template.use('uuid').options(
                    ondelete='cascade'))
    jinja_paths = Text(nullable=False)
    contenttype = Selection(selections={
        'text/html': 'HTML',
        'application/pdf': 'PDF',
    },
                            default='application/pdf',
                            nullable=False)
    options = Json(default={}, nullable=False)
    wkhtml2pdf_configuration = Many2One(
        model=Declarations.Model.Attachment.WkHtml2Pdf, nullable=True)

    def check_flush_validity(self):
        super(Jinja, self).check_flush_validity()
        if self.contenttype == 'application/pdf':
            if not self.wkhtml2pdf_configuration:
                raise TemplateJinjaException(
                    "No WkHtml2Pdf configuration for %r" % self)

    def update_document(self, document, file_, data):
        super(Jinja, self).update_document(document, file_, data)
        document.contenttype = self.contenttype

    def render(self, data):
        if self.contenttype == 'text/html':
            return self.render_html(data)

        return self.render_pdf(data)

    def render_html(self, data):
        jinja_paths = []
        if self.jinja_paths:
            for jinja_path in self.jinja_paths.split(','):
                jinja_path = format_path(jinja_path.strip())
                if not os.path.isdir(jinja_path):
                    raise TemplateJinjaException("%r must be a folder" %
                                                 jinja_path)

                jinja_paths.append(jinja_path)

        jinja_env = SandboxedEnvironment(
            loader=jinja2.FileSystemLoader(jinja_paths),
            undefined=jinja2.StrictUndefined,
        )
        parser = self.get_parser()
        if not hasattr(parser, 'serialize_jinja_options'):
            raise TemplateJinjaException(
                ("The parser %r must declare a method "
                 "'serialize_jinja_options' for %r") % (parser, self))

        options = self.get_parser().serialize_jinja_options(self.options)
        return jinja_env.from_string(self.get_template()).render(
            data=data, str=str, **options).encode('utf-8')

    def render_pdf(self, data):
        html_content = self.render_html(data)
        return self.wkhtml2pdf(html_content)
Exemple #16
0
class Parameter:
    """System Parameter"""

    key = String(primary_key=True)
    value = Json(nullable=False)
    multi = Boolean(default=False)

    @classmethod
    def set(cls, key, value):
        """ Insert or Update parameter for the key

        :param key: key to save
        :param value: value to save
        """
        multi = False
        if not isinstance(value, dict):
            value = {'value': value}
        else:
            multi = True

        if cls.is_exist(key):
            param = cls.from_primary_keys(key=key)
            param.update(value=value, multi=multi)
        else:
            cls.insert(key=key, value=value, multi=multi)

    @classmethod
    def is_exist(cls, key):
        """ Check if one parameter exist for the key

        :param key: key to check
        :rtype: Boolean, True if exist
        """
        query = cls.query().filter(cls.key == key)
        return True if query.count() else False

    @classmethod
    def get(cls, key):
        """ Return the value of the key

        :param key: key to check
        :rtype: return value
        :exception: ExceptionParameter
        """
        if not cls.is_exist(key):
            raise ParameterException("unexisting key %r" % key)

        param = cls.from_primary_keys(key=key)
        if param.multi:
            return param.value

        return param.value['value']

    @classmethod
    def pop(cls, key):
        """Remove return the value of the key

        :param key: key to check
        :rtype: return value
        :exception: ExceptionParameter
        """
        if not cls.is_exist(key):
            raise ParameterException("unexisting key %r" % key)

        param = cls.from_primary_keys(key=key)
        if param.multi:
            res = param.value
        else:
            res = param.value['value']

        param.delete()
        return res