Exemplo n.º 1
0
def user_update_delete_logic(cls, user_or_token):
    """A user can update or delete themselves, and a super admin can delete
    or update any user."""

    if user_or_token.is_admin:
        return public.query_accessible_rows(cls, user_or_token)

    # non admin users can only update or delete themselves
    user_id = UserAccessControl.user_id_from_user_or_token(user_or_token)

    return DBSession().query(cls).filter(cls.id == user_id)
Exemplo n.º 2
0
    def query_accessible_rows(self, cls, user_or_token, columns=None):
        """Construct a Query object that, when executed, returns the rows of a
        specified table that are accessible to a specified user or token.

        Parameters
        ----------
        cls: `baselayer.app.models.DeclarativeMeta`
            The mapped class of the target table.
        user_or_token: `baselayer.app.models.User` or `baselayer.app.models.Token`
            The User or Token to check.
        columns: list of sqlalchemy.Column, optional, default None
            The columns to retrieve from the target table. If None, queries
            the mapped class directly and returns mapped instances.

        Returns
        -------
        query: sqlalchemy.Query
            Query for the accessible rows.
        """

        # system admins automatically get full access
        if user_or_token.is_admin:
            return public.query_accessible_rows(cls,
                                                user_or_token,
                                                columns=columns)

        # return only selected columns if requested
        if columns is not None:
            query = DBSession().query(*columns).select_from(cls)
        else:
            query = DBSession().query(cls)

        # traverse the relationship chain via sequential JOINs
        for relationship_name in self.relationship_names:
            self.check_cls_for_attributes(cls, [relationship_name])
            relationship = sa.inspect(
                cls).mapper.relationships[relationship_name]
            # not a private attribute, just has an underscore to avoid name
            # collision with python keyword
            cls = relationship.entity.class_

            if str(relationship) == "Group.users":
                # For the last relationship between Group and User, just join
                # in the join table and not the join table and the full User table
                # since we only need the GroupUser.user_id field to match on
                query = query.join(GroupUser)
            else:
                query = query.join(relationship.class_attribute)

        # filter for records with at least one matching user
        user_id = self.user_id_from_user_or_token(user_or_token)
        query = query.filter(GroupUser.user_id == user_id)
        return query
Exemplo n.º 3
0
def updatable_by_token_with_listener_acl(cls, user_or_token):
    if user_or_token.is_admin:
        return public.query_accessible_rows(cls, user_or_token)

    instruments_with_apis = (
        Instrument.query_records_accessible_by(user_or_token).filter(
            Instrument.listener_classname.isnot(None)).all())

    api_map = {
        instrument.id: instrument.listener_class.get_acl_id()
        for instrument in instruments_with_apis
    }

    accessible_instrument_ids = [
        instrument_id for instrument_id, acl_id in api_map.items()
        if acl_id in user_or_token.permissions
    ]

    return (DBSession().query(cls).join(Allocation).join(Instrument).filter(
        Instrument.id.in_(accessible_instrument_ids)))