def _add_permissions_filter(self, query, model_class): """Filter by the users present in either the `viewers` or `owners` lists """ # not used from a request handler - no relevant user if not has_request_context(): return query # Queries of elements that aren't resources (tenants, users, etc.), # shouldn't be filtered if not model_class.is_resource: return query # For users that are allowed to see all resources, regardless of tenant is_admin = is_administrator(self.current_tenant) if is_admin: return query # Only get resources that are public - not private (note that ~ stands # for NOT, in SQLA), *or* those where the current user is the creator user_filter = sql_or( model_class.visibility != VisibilityState.PRIVATE, model_class.creator == current_user ) return query.filter(user_filter)
def strain(self, query): if not self._filters: return query filters = [] tables = set() basename = self._strainer.tablename for f in self._filters: filters.append(f['filter']) tbl, _ = self._strainer.split_name(f['name']) if tbl != basename: tables.add(tbl) join_type = 'join' if self._strainer.restrictive: query = query.filter(*filters) else: query = query.filter(sql_or(*filters)) join_type = 'outerjoin' # todo: validate repeated join relations act as set for tbl in tables: query = getattr(query, join_type)(*self._strainer.relatives[tbl].join) flags = self._strainer.relatives[tbl].flags if flags: query = query.filter(*flags) return query.distinct()
def _add_tenant_filter(self, query, model_class, all_tenants): """Filter by the tenant ID associated with `model_class` (either directly via a relationship with the tenants table, or via an ancestor who has such a relationship) """ # Users/Groups etc. don't have tenants if not model_class.is_resource: return query # not used from a request handler - no relevant user if not has_request_context(): return query # If a user that is allowed to get all the tenants in the system # passed the `all_tenants` flag, no need to filter if all_tenants_authorization() and all_tenants: return query if all_tenants: tenant_ids = [tenant.id for tenant in current_user.all_tenants] else: tenant_ids = [self.current_tenant.id] # Match any of the applicable tenant ids or if it's a global resource tenant_filter = sql_or( model_class.resource_availability == AvailabilityState.GLOBAL, model_class._tenant_id.in_(tenant_ids)) return query.filter(tenant_filter)
def _get_unique_resource_id_query(self, model_class, resource_id, tenant): """ Query for all the resources with the same id of the given instance, if it's in the given tenant, or if it's a global resource """ query = model_class.query query = query.filter(model_class.id == resource_id) unique_resource_filter = sql_or( model_class.tenant == tenant, model_class.visibility == VisibilityState.GLOBAL) query = query.filter(unique_resource_filter) return query
def _get_unique_resource_id_query(self, model_class, resource_id, tenant): """ Query for all the resources with the same id of the given instance, if it's in the given tenant, or if it's a global resource """ query = model_class.query query = query.filter(model_class.id == resource_id) unique_resource_filter = sql_or( model_class.tenant == tenant, model_class.visibility == VisibilityState.GLOBAL ) query = query.filter(unique_resource_filter) return query
def _add_permissions_filter(query, model_class): """Filter by the users present in either the `viewers` or `owners` lists """ # System administrators should see all resources, regardless of tenant. # Queries of elements that aren't resources (tenants, users, etc.), # shouldn't be filtered as well if not model_class.is_resource or current_user.is_admin: return query # Only get resources that are public - not private (note that ~ stands # for NOT, in SQLA), *or* those where the current user is the creator user_filter = sql_or(~model_class.private_resource, model_class.creator == current_user) return query.filter(user_filter)
def _add_tenant_filter(self, query, model_class, all_tenants): """Filter by the tenant ID associated with `model_class` (either directly via a relationship with the tenants table, or via an ancestor who has such a relationship) """ # Users/Groups etc. don't have tenants if not model_class.is_resource: return query # not used from a request handler - no relevant user if not has_request_context(): return query current_tenant = self.current_tenant # If a user passed the `all_tenants` flag if all_tenants: # If a user that is allowed to get all the tenants in the system # no need to filter if all_tenants_authorization(): return query # Filter by all the tenants the user is allowed to list in tenant_ids = [ tenant.id for tenant in current_user.all_tenants if utils.tenant_specific_authorization(tenant, model_class.__name__) ] else: # Specific tenant only tenant_ids = [current_tenant.id] if current_tenant else [] # Match any of the applicable tenant ids or if it's a global resource tenant_filter = sql_or( model_class.visibility == VisibilityState.GLOBAL, model_class._tenant_id.in_(tenant_ids) ) return query.filter(tenant_filter)
def _build_select_subquery(model, filters, range_filters, tenant_id): """Build select subquery. :param model: Model used to build the query (either Event or Log) :type model: :class:`manager_rest.storage.resource_models.Event` :class:`manager_rest.storage.resource_models.Log` :param filters: Filters passed as request argument :type filters: dict(str, list(str)) :param range_filters: Range filtres passed as request argument :type range_filters: dict(str, dict(str)) :returns: Select events query :rtype: :class:`sqlalchemy.orm.query.Query` """ def select_column(column_name, label=None): """Select column from model by name. If column is not present in the model, then select `NULL` value instead. :param column_name: Name of the column to select :type column_name: str :return: Selected colum :rtype: :class:`` """ if not label: label = column_name if hasattr(model, column_name): return getattr(model, column_name).label(label) return literal_column('NULL').label(label) query = (db.session.query( select_column('id'), select_column('_storage_id'), select_column('timestamp'), select_column('reported_timestamp'), Blueprint.id.label('blueprint_id'), Deployment.id.label('deployment_id'), Execution.id.label('execution_id'), Execution.workflow_id.label('workflow_id'), select_column('message'), select_column('message_code'), select_column('error_causes'), select_column('event_type'), select_column('operation'), select_column('node_id'), select_column('source_id'), select_column('target_id'), NodeInstance.id.label('node_instance_id'), Node.id.label('node_name'), select_column('logger'), select_column('level'), literal_column("'cloudify_{}'".format( model.__name__.lower())).label('type'), ).filter( sql_or(model._tenant_id == tenant_id, model.visibility == VisibilityState.GLOBAL) ).outerjoin(NodeInstance, NodeInstance.id == model.node_id).outerjoin( Node, Node._storage_id == NodeInstance._node_fk).outerjoin( Execution, Execution._storage_id == model._execution_fk).outerjoin( Deployment, Deployment._storage_id == Execution._deployment_fk).outerjoin( Blueprint, Blueprint._storage_id == Deployment._blueprint_fk)) query = Events._apply_filters(query, model, filters) query = Events._apply_range_filters(query, model, range_filters) return query
def _build_select_subquery(model, filters, range_filters, tenant_id): """Build select subquery. :param model: Model used to build the query (either Event or Log) :type model: :class:`manager_rest.storage.resource_models.Event` :class:`manager_rest.storage.resource_models.Log` :param filters: Filters passed as request argument :type filters: dict(str, list(str)) :param range_filters: Range filtres passed as request argument :type range_filters: dict(str, dict(str)) :returns: Select events query :rtype: :class:`sqlalchemy.orm.query.Query` """ def select_column(column_name, label=None): """Select column from model by name. If column is not present in the model, then select `NULL` value instead. :param column_name: Name of the column to select :type column_name: str :return: Selected colum :rtype: :class:`` """ if not label: label = column_name if hasattr(model, column_name): return getattr(model, column_name).label(label) return literal_column('NULL').label(label) query = ( db.session.query( select_column('id'), select_column('_storage_id'), select_column('timestamp'), select_column('reported_timestamp'), Blueprint.id.label('blueprint_id'), Deployment.id.label('deployment_id'), Execution.id.label('execution_id'), Execution.workflow_id.label('workflow_id'), select_column('message'), select_column('message_code'), select_column('error_causes'), select_column('event_type'), select_column('operation'), select_column('node_id'), select_column('source_id'), select_column('target_id'), NodeInstance.id.label('node_instance_id'), Node.id.label('node_name'), select_column('logger'), select_column('level'), literal_column("'cloudify_{}'".format(model.__name__.lower())) .label('type'), ) .filter( sql_or( model._tenant_id == tenant_id, model.visibility == VisibilityState.GLOBAL ) ) .outerjoin(NodeInstance, NodeInstance.id == model.node_id) .outerjoin(Node, Node._storage_id == NodeInstance._node_fk) .outerjoin(Execution, Execution._storage_id == model._execution_fk) .outerjoin(Deployment, Deployment._storage_id == Execution._deployment_fk) .outerjoin( Blueprint, Blueprint._storage_id == Deployment._blueprint_fk) ) query = Events._apply_filters(query, model, filters) query = Events._apply_range_filters(query, model, range_filters) return query