def _update_qs_fields(cls, type_schema: str, fields: List[str], qs: QueryStringManager = None, name_foreign_key: str = None) -> None: """ Обновляем fields в qs для работы схемы (чтобы она не обращалась к полям, которые не доступны пользователю) :param str type_schema: название типа схемы Meta.type_ :param List[str] fields: список доступных полей :param QueryStringManager qs: параметры из get запроса :param str name_foreign_key: название поля в схеме, которое ссылается на схему type_schema :return: """ old_fields = qs._get_key_values("fields") if type_schema in old_fields: new_fields = list( set(old_fields.get(type_schema, [])) & set(fields)) else: new_fields = fields new_qs = {k: v for k, v in qs.qs.items() if v != ""} include = new_qs.get("include", "").split(",") if not new_fields and include and name_foreign_key in include: new_qs["include"] = ",".join( [inc for inc in include if inc != name_foreign_key]) else: new_qs[f"fields[{type_schema}]"] = ",".join(new_fields) qs.qs = ImmutableMultiDict(new_qs)
def test_data_layer_get_collection_update_query(self, mock_eagerload_includes, instance, permission_user, session, sqlalchemy_data_layer): PermissionToMapper.add_permission('get', ModelWithMeta, [PermissionWithJoinsAndFilters]) kwargs = dict(query=session.query(ModelWithMeta), qs=QueryStringManager( {'fields[model_with_meta]': 'type,flags'}, ModelWithMetaSchema), self_json_api=sqlalchemy_data_layer, view_kwargs={'_permission_user': permission_user}) result = instance.data_layer_get_collection_update_query(**kwargs) permission_get = permission_user.permission_for_get(ModelWithMeta) expected_query = str( session.query(ModelWithMeta) # check that joins and filters from permission were applied .join(*permission_get.joins[0]).filter(*permission_get.filters) # and only requested and allowed fields were selected .with_entities(ModelWithMeta.id, ModelWithMeta.type).statement) assert str(result.statement) == expected_query
def test__get_joinedload_object_for_include__wrong_field_name( self, permission_user): qs = QueryStringManager({}, ModelWithMeta) with pytest.raises(InvalidInclude): PermissionPlugin._get_joinedload_object_for_include( 'wrong_field', qs, permission_user, ModelWithMetaSchema(), ModelWithMeta)
def test__get_joinedload_object_for_splitted_include__not_allowed( self, mock_is_access_foreign_key, permission_user): qs = QueryStringManager({}, ModelWithMeta) result = PermissionPlugin._get_joinedload_object_for_splitted_include( 'related_model_id', qs, permission_user, ModelWithMetaSchema(), ModelWithMeta) assert result is None
def test__get_or_update_joinedload_object(self, mock_property, permission_user): mock_property.mapper = mock_mapper qs = QueryStringManager({}, ModelWithMeta) joinedload_object, related_schema = PermissionPlugin._get_or_update_joinedload_object( None, qs, permission_user, ModelWithMeta, ModelWithMetaSchema, 'related_model_id', 'related_model_id', 0) assert joinedload_object.path[0] == ModelWithMeta.related_model_id assert related_schema is RelatedModelSchema
def test__eagerload_includes__no_includes(self, mock_current_app, session, permission_user, sqlalchemy_data_layer): mock_current_app.config.get.return_value = None query = session.query(ModelWithMeta) qs = QueryStringManager({}, ModelWithMeta) result = PermissionPlugin._eagerload_includes(query, qs, permission_user, sqlalchemy_data_layer) assert result is query
def test__get_joinedload_object_for_include(self, mock_is_access_foreign_key, mock_property, permission_user): qs = QueryStringManager({}, ModelWithMeta) result = PermissionPlugin._get_joinedload_object_for_include( 'related_model_id', qs, permission_user, ModelWithMetaSchema(), ModelWithMeta) assert result.path[0] == ModelWithMeta.related_model_id
def test__update_qs_fields(self, permission_user, qs, new_fields, new_include): PermissionToMapper.add_permission('get', ModelWithMeta, [SomePermission]) qs = QueryStringManager(qs, ModelWithMetaSchema) PermissionPlugin._update_qs_fields( ModelWithMetaSchema.Meta.type_, list(permission_user.permission_for_get(ModelWithMeta).columns), qs, 'related_model_id') assert set(qs.fields['model_with_meta']) == new_fields assert qs.qs['include'] == new_include
def test__eagerload_includes__with_not_allowed_includes( self, mock_current_app, mock_get_joinedload_object_for_include, mock_is_access_foreign_key, session, permission_user, sqlalchemy_data_layer): mock_current_app.config.get.return_value = None query = session.query(ModelWithMeta) include = 'related_model_id' qs = QueryStringManager({'include': include}, ModelWithMeta) result = PermissionPlugin._eagerload_includes(query, qs, permission_user, sqlalchemy_data_layer) assert result is query mock_get_joinedload_object_for_include.assert_not_called()
def test_eagerload_includes__with_splitted_includes( self, mock_current_app, mock_get_joinedload_object_for_splitted_include, permission_user, sqlalchemy_data_layer): mock_current_app.config.get.return_value = None query = mock.Mock() include = 'foo.bar' qs = QueryStringManager({'include': include}, ModelWithMeta) result = PermissionPlugin._eagerload_includes(query, qs, permission_user, sqlalchemy_data_layer) mock_get_joinedload_object_for_splitted_include.assert_called_once_with( include, qs, permission_user, ModelWithMetaSchema, ModelWithMeta) query.options.assert_called_once_with( mock_get_joinedload_object_for_splitted_include.return_value) assert result == query.options.return_value
def test__get_access_fields_in_schema(self, mock__update_qs_fields, permission_user): qs = QueryStringManager({}, ModelWithMetaSchema) expected_result = {'id', 'other_field'} result = PermissionPlugin._get_access_fields_in_schema( 'related_model_id', ModelWithMetaSchema, permission_user, ModelWithMeta, qs=qs) assert set(result) == expected_result mock__update_qs_fields.assert_called_once() args, kwargs = mock__update_qs_fields.call_args[ 0], mock__update_qs_fields.call_args[1] assert args[0] == RelatedModelSchema.Meta.type_ assert set(args[1]) == expected_result assert kwargs == {'qs': qs, 'name_foreign_key': 'related_model_id'}