예제 #1
0
 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)
예제 #2
0
    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
예제 #3
0
    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)
예제 #4
0
    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
예제 #5
0
 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
예제 #6
0
 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
예제 #7
0
    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
예제 #8
0
 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
예제 #9
0
 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()
예제 #10
0
    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
예제 #11
0
 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'}