diff --git a/api-clients/python/.openapi-generator/FILES b/api-clients/python/.openapi-generator/FILES index 432c3e611..3b4d8abc8 100644 --- a/api-clients/python/.openapi-generator/FILES +++ b/api-clients/python/.openapi-generator/FILES @@ -276,7 +276,9 @@ docs/SpatialReferenceSpecification.md docs/SpatialReferencesApi.md docs/SpatialResolution.md docs/StacApiRetries.md +docs/StacAssetBand.md docs/StacDataProviderDefinition.md +docs/StacProviderAuthentication.md docs/StacProviderDataset.md docs/StacProviderDatasetBand.md docs/StacProviderS3Config.md @@ -664,7 +666,9 @@ geoengine_api_client/models/spatial_reference_specification.py geoengine_api_client/models/spatial_resolution.py geoengine_api_client/models/st_rectangle.py geoengine_api_client/models/stac_api_retries.py +geoengine_api_client/models/stac_asset_band.py geoengine_api_client/models/stac_data_provider_definition.py +geoengine_api_client/models/stac_provider_authentication.py geoengine_api_client/models/stac_provider_dataset.py geoengine_api_client/models/stac_provider_dataset_band.py geoengine_api_client/models/stac_provider_s3_config.py @@ -1046,7 +1050,9 @@ test/test_spatial_references_api.py test/test_spatial_resolution.py test/test_st_rectangle.py test/test_stac_api_retries.py +test/test_stac_asset_band.py test/test_stac_data_provider_definition.py +test/test_stac_provider_authentication.py test/test_stac_provider_dataset.py test/test_stac_provider_dataset_band.py test/test_stac_provider_s3_config.py diff --git a/api-clients/python/README.md b/api-clients/python/README.md index 251468ad7..177a2d4dd 100644 --- a/api-clients/python/README.md +++ b/api-clients/python/README.md @@ -458,7 +458,9 @@ Class | Method | HTTP request | Description - [SpatialReferenceSpecification](docs/SpatialReferenceSpecification.md) - [SpatialResolution](docs/SpatialResolution.md) - [StacApiRetries](docs/StacApiRetries.md) + - [StacAssetBand](docs/StacAssetBand.md) - [StacDataProviderDefinition](docs/StacDataProviderDefinition.md) + - [StacProviderAuthentication](docs/StacProviderAuthentication.md) - [StacProviderDataset](docs/StacProviderDataset.md) - [StacProviderDatasetBand](docs/StacProviderDatasetBand.md) - [StacProviderS3Config](docs/StacProviderS3Config.md) diff --git a/api-clients/python/geoengine_api_client/__init__.py b/api-clients/python/geoengine_api_client/__init__.py index 4e149b864..427ff1271 100644 --- a/api-clients/python/geoengine_api_client/__init__.py +++ b/api-clients/python/geoengine_api_client/__init__.py @@ -304,7 +304,9 @@ "SpatialReferenceSpecification", "SpatialResolution", "StacApiRetries", + "StacAssetBand", "StacDataProviderDefinition", + "StacProviderAuthentication", "StacProviderDataset", "StacProviderDatasetBand", "StacProviderS3Config", @@ -697,7 +699,9 @@ from geoengine_api_client.models.spatial_reference_specification import SpatialReferenceSpecification as SpatialReferenceSpecification from geoengine_api_client.models.spatial_resolution import SpatialResolution as SpatialResolution from geoengine_api_client.models.stac_api_retries import StacApiRetries as StacApiRetries +from geoengine_api_client.models.stac_asset_band import StacAssetBand as StacAssetBand from geoengine_api_client.models.stac_data_provider_definition import StacDataProviderDefinition as StacDataProviderDefinition +from geoengine_api_client.models.stac_provider_authentication import StacProviderAuthentication as StacProviderAuthentication from geoengine_api_client.models.stac_provider_dataset import StacProviderDataset as StacProviderDataset from geoengine_api_client.models.stac_provider_dataset_band import StacProviderDatasetBand as StacProviderDatasetBand from geoengine_api_client.models.stac_provider_s3_config import StacProviderS3Config as StacProviderS3Config diff --git a/api-clients/python/geoengine_api_client/models/__init__.py b/api-clients/python/geoengine_api_client/models/__init__.py index f6f028d67..7ff7c43b0 100644 --- a/api-clients/python/geoengine_api_client/models/__init__.py +++ b/api-clients/python/geoengine_api_client/models/__init__.py @@ -273,7 +273,9 @@ from geoengine_api_client.models.spatial_reference_specification import SpatialReferenceSpecification from geoengine_api_client.models.spatial_resolution import SpatialResolution from geoengine_api_client.models.stac_api_retries import StacApiRetries +from geoengine_api_client.models.stac_asset_band import StacAssetBand from geoengine_api_client.models.stac_data_provider_definition import StacDataProviderDefinition +from geoengine_api_client.models.stac_provider_authentication import StacProviderAuthentication from geoengine_api_client.models.stac_provider_dataset import StacProviderDataset from geoengine_api_client.models.stac_provider_dataset_band import StacProviderDatasetBand from geoengine_api_client.models.stac_provider_s3_config import StacProviderS3Config diff --git a/api-clients/python/geoengine_api_client/models/stac_asset_band.py b/api-clients/python/geoengine_api_client/models/stac_asset_band.py new file mode 100644 index 000000000..eca1e9be8 --- /dev/null +++ b/api-clients/python/geoengine_api_client/models/stac_asset_band.py @@ -0,0 +1,94 @@ +# coding: utf-8 + +""" + Geo Engine API + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + Contact: dev@geoengine.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List, Optional +from typing import Optional, Set +from typing_extensions import Self + +class StacAssetBand(BaseModel): + """ + StacAssetBand + """ # noqa: E501 + asset_title: StrictStr = Field(alias="assetTitle") + band_name: Optional[StrictStr] = Field(default=None, alias="bandName") + __properties: ClassVar[List[str]] = ["assetTitle", "bandName"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of StacAssetBand from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + # set to None if band_name (nullable) is None + # and model_fields_set contains the field + if self.band_name is None and "band_name" in self.model_fields_set: + _dict['bandName'] = None + + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of StacAssetBand from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "assetTitle": obj.get("assetTitle"), + "bandName": obj.get("bandName") + }) + return _obj + + diff --git a/api-clients/python/geoengine_api_client/models/stac_data_provider_definition.py b/api-clients/python/geoengine_api_client/models/stac_data_provider_definition.py index 1a01b310d..c810cc97a 100644 --- a/api-clients/python/geoengine_api_client/models/stac_data_provider_definition.py +++ b/api-clients/python/geoengine_api_client/models/stac_data_provider_definition.py @@ -20,6 +20,7 @@ from pydantic import BaseModel, ConfigDict, Field, StrictInt, StrictStr, field_validator from typing import Any, ClassVar, Dict, List, Optional from uuid import UUID +from geoengine_api_client.models.stac_provider_authentication import StacProviderAuthentication from geoengine_api_client.models.stac_provider_dataset import StacProviderDataset from geoengine_api_client.models.stac_provider_s3_config import StacProviderS3Config from geoengine_api_client.models.time_dimension import TimeDimension @@ -38,10 +39,12 @@ class StacDataProviderDefinition(BaseModel): api_url: StrictStr = Field(alias="apiUrl") collection_name: StrictStr = Field(alias="collectionName") s3_config: Optional[StacProviderS3Config] = Field(default=None, alias="s3Config") + authentication: Optional[StacProviderAuthentication] = None time_dimension: TimeDimension = Field(alias="timeDimension") datasets: List[StacProviderDataset] query_timeout_secs: Optional[StrictInt] = Field(default=None, description="Timeout in seconds for outgoing STAC API HTTP requests.", alias="queryTimeoutSecs") - __properties: ClassVar[List[str]] = ["type", "name", "id", "description", "priority", "apiUrl", "collectionName", "s3Config", "timeDimension", "datasets", "queryTimeoutSecs"] + page_limit: Optional[StrictInt] = Field(default=None, alias="pageLimit") + __properties: ClassVar[List[str]] = ["type", "name", "id", "description", "priority", "apiUrl", "collectionName", "s3Config", "authentication", "timeDimension", "datasets", "queryTimeoutSecs", "pageLimit"] @field_validator('type') def type_validate_enum(cls, value): @@ -92,6 +95,9 @@ def to_dict(self) -> Dict[str, Any]: # override the default output from pydantic by calling `to_dict()` of s3_config if self.s3_config: _dict['s3Config'] = self.s3_config.to_dict() + # override the default output from pydantic by calling `to_dict()` of authentication + if self.authentication: + _dict['authentication'] = self.authentication.to_dict() # override the default output from pydantic by calling `to_dict()` of time_dimension if self.time_dimension: _dict['timeDimension'] = self.time_dimension.to_dict() @@ -112,6 +118,11 @@ def to_dict(self) -> Dict[str, Any]: if self.s3_config is None and "s3_config" in self.model_fields_set: _dict['s3Config'] = None + # set to None if authentication (nullable) is None + # and model_fields_set contains the field + if self.authentication is None and "authentication" in self.model_fields_set: + _dict['authentication'] = None + return _dict @classmethod @@ -132,9 +143,11 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: "apiUrl": obj.get("apiUrl"), "collectionName": obj.get("collectionName"), "s3Config": StacProviderS3Config.from_dict(obj["s3Config"]) if obj.get("s3Config") is not None else None, + "authentication": StacProviderAuthentication.from_dict(obj["authentication"]) if obj.get("authentication") is not None else None, "timeDimension": TimeDimension.from_dict(obj["timeDimension"]) if obj.get("timeDimension") is not None else None, "datasets": [StacProviderDataset.from_dict(_item) for _item in obj["datasets"]] if obj.get("datasets") is not None else None, - "queryTimeoutSecs": obj.get("queryTimeoutSecs") + "queryTimeoutSecs": obj.get("queryTimeoutSecs"), + "pageLimit": obj.get("pageLimit") }) return _obj diff --git a/api-clients/python/geoengine_api_client/models/stac_provider_authentication.py b/api-clients/python/geoengine_api_client/models/stac_provider_authentication.py new file mode 100644 index 000000000..02715502b --- /dev/null +++ b/api-clients/python/geoengine_api_client/models/stac_provider_authentication.py @@ -0,0 +1,91 @@ +# coding: utf-8 + +""" + Geo Engine API + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + Contact: dev@geoengine.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json + +from pydantic import BaseModel, ConfigDict, Field, StrictStr +from typing import Any, ClassVar, Dict, List +from typing import Optional, Set +from typing_extensions import Self + +class StacProviderAuthentication(BaseModel): + """ + StacProviderAuthentication + """ # noqa: E501 + endpoint: StrictStr + username: StrictStr + password: StrictStr = Field(description="A wrapper type that serializes to \"*****\" and can be deserialized from any string. If the inner value is \"*****\", it is considered unknown and `as_option` returns `None`. This is useful for secrets that should not be exposed in API responses, but can be set in API requests.") + __properties: ClassVar[List[str]] = ["endpoint", "username", "password"] + + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + protected_namespaces=(), + ) + + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Optional[Self]: + """Create an instance of StacProviderAuthentication from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + `self.model_dump(by_alias=True)`: + + * `None` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value `None` + are ignored. + """ + excluded_fields: Set[str] = set([ + ]) + + _dict = self.model_dump( + by_alias=True, + exclude=excluded_fields, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: + """Create an instance of StacProviderAuthentication from a dict""" + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "endpoint": obj.get("endpoint"), + "username": obj.get("username"), + "password": obj.get("password") + }) + return _obj + + diff --git a/api-clients/python/geoengine_api_client/models/stac_provider_dataset_band.py b/api-clients/python/geoengine_api_client/models/stac_provider_dataset_band.py index 32630fc9b..0354fe8f1 100644 --- a/api-clients/python/geoengine_api_client/models/stac_provider_dataset_band.py +++ b/api-clients/python/geoengine_api_client/models/stac_provider_dataset_band.py @@ -17,8 +17,10 @@ import re # noqa: F401 import json -from pydantic import BaseModel, ConfigDict, Field, StrictStr -from typing import Any, ClassVar, Dict, List, Optional +from pydantic import BaseModel, ConfigDict, Field +from typing import Any, ClassVar, Dict, List +from geoengine_api_client.models.raster_band_descriptor import RasterBandDescriptor +from geoengine_api_client.models.stac_asset_band import StacAssetBand from typing import Optional, Set from typing_extensions import Self @@ -26,9 +28,9 @@ class StacProviderDatasetBand(BaseModel): """ StacProviderDatasetBand """ # noqa: E501 - asset_title: StrictStr = Field(alias="assetTitle") - band_name: Optional[StrictStr] = Field(default=None, alias="bandName") - __properties: ClassVar[List[str]] = ["assetTitle", "bandName"] + asset_band: StacAssetBand = Field(description="The band inside the STAC asset that this dataset band reads from (addressing: which asset file + which raster channel within it).", alias="assetBand") + band_descriptor: RasterBandDescriptor = Field(description="The band descriptor of the resulting geo engine dataset layer.", alias="bandDescriptor") + __properties: ClassVar[List[str]] = ["assetBand", "bandDescriptor"] model_config = ConfigDict( populate_by_name=True, @@ -69,11 +71,12 @@ def to_dict(self) -> Dict[str, Any]: exclude=excluded_fields, exclude_none=True, ) - # set to None if band_name (nullable) is None - # and model_fields_set contains the field - if self.band_name is None and "band_name" in self.model_fields_set: - _dict['bandName'] = None - + # override the default output from pydantic by calling `to_dict()` of asset_band + if self.asset_band: + _dict['assetBand'] = self.asset_band.to_dict() + # override the default output from pydantic by calling `to_dict()` of band_descriptor + if self.band_descriptor: + _dict['bandDescriptor'] = self.band_descriptor.to_dict() return _dict @classmethod @@ -86,8 +89,8 @@ def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]: return cls.model_validate(obj) _obj = cls.model_validate({ - "assetTitle": obj.get("assetTitle"), - "bandName": obj.get("bandName") + "assetBand": StacAssetBand.from_dict(obj["assetBand"]) if obj.get("assetBand") is not None else None, + "bandDescriptor": RasterBandDescriptor.from_dict(obj["bandDescriptor"]) if obj.get("bandDescriptor") is not None else None }) return _obj diff --git a/api-clients/python/test/test_stac_asset_band.py b/api-clients/python/test/test_stac_asset_band.py new file mode 100644 index 000000000..6425b1865 --- /dev/null +++ b/api-clients/python/test/test_stac_asset_band.py @@ -0,0 +1,53 @@ +# coding: utf-8 + +""" + Geo Engine API + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + Contact: dev@geoengine.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from geoengine_api_client.models.stac_asset_band import StacAssetBand + +class TestStacAssetBand(unittest.TestCase): + """StacAssetBand unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> StacAssetBand: + """Test StacAssetBand + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `StacAssetBand` + """ + model = StacAssetBand() + if include_optional: + return StacAssetBand( + asset_title = '', + band_name = '' + ) + else: + return StacAssetBand( + asset_title = '', + ) + """ + + def testStacAssetBand(self): + """Test StacAssetBand""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/api-clients/python/test/test_stac_data_provider_definition.py b/api-clients/python/test/test_stac_data_provider_definition.py index ad4151e5a..07ae378ab 100644 --- a/api-clients/python/test/test_stac_data_provider_definition.py +++ b/api-clients/python/test/test_stac_data_provider_definition.py @@ -46,6 +46,10 @@ def make_instance(self, include_optional) -> StacDataProviderDefinition: endpoint = '', access_key = null, secret_key = null, ), + authentication = geoengine_api_client.models.stac_provider_authentication.StacProviderAuthentication( + endpoint = '', + username = '', + password = '', ), time_dimension = None, datasets = [ geoengine_api_client.models.stac_provider_dataset.StacProviderDataset( @@ -74,11 +78,12 @@ def make_instance(self, include_optional) -> StacDataProviderDefinition: descriptor = 'source', ), bands = [ geoengine_api_client.models.stac_provider_dataset_band.StacProviderDatasetBand( - asset_title = '', - band_name = '', ) + asset_band = null, + band_descriptor = null, ) ], ) ], - query_timeout_secs = 56 + query_timeout_secs = 56, + page_limit = 56 ) else: return StacDataProviderDefinition( @@ -116,8 +121,8 @@ def make_instance(self, include_optional) -> StacDataProviderDefinition: descriptor = 'source', ), bands = [ geoengine_api_client.models.stac_provider_dataset_band.StacProviderDatasetBand( - asset_title = '', - band_name = '', ) + asset_band = null, + band_descriptor = null, ) ], ) ], ) diff --git a/api-clients/python/test/test_stac_provider_authentication.py b/api-clients/python/test/test_stac_provider_authentication.py new file mode 100644 index 000000000..028009357 --- /dev/null +++ b/api-clients/python/test/test_stac_provider_authentication.py @@ -0,0 +1,56 @@ +# coding: utf-8 + +""" + Geo Engine API + + No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + + Contact: dev@geoengine.de + Generated by OpenAPI Generator (https://openapi-generator.tech) + + Do not edit the class manually. +""" # noqa: E501 + + +import unittest + +from geoengine_api_client.models.stac_provider_authentication import StacProviderAuthentication + +class TestStacProviderAuthentication(unittest.TestCase): + """StacProviderAuthentication unit test stubs""" + + def setUp(self): + pass + + def tearDown(self): + pass + + def make_instance(self, include_optional) -> StacProviderAuthentication: + """Test StacProviderAuthentication + include_optional is a boolean, when False only required + params are included, when True both required and + optional params are included """ + # uncomment below to create an instance of `StacProviderAuthentication` + """ + model = StacProviderAuthentication() + if include_optional: + return StacProviderAuthentication( + endpoint = '', + username = '', + password = '' + ) + else: + return StacProviderAuthentication( + endpoint = '', + username = '', + password = '', + ) + """ + + def testStacProviderAuthentication(self): + """Test StacProviderAuthentication""" + # inst_req_only = self.make_instance(include_optional=False) + # inst_req_and_optional = self.make_instance(include_optional=True) + +if __name__ == '__main__': + unittest.main() diff --git a/api-clients/python/test/test_stac_provider_dataset.py b/api-clients/python/test/test_stac_provider_dataset.py index 995265586..008839f4f 100644 --- a/api-clients/python/test/test_stac_provider_dataset.py +++ b/api-clients/python/test/test_stac_provider_dataset.py @@ -60,8 +60,8 @@ def make_instance(self, include_optional) -> StacProviderDataset: descriptor = 'source', ), bands = [ geoengine_api_client.models.stac_provider_dataset_band.StacProviderDatasetBand( - asset_title = '', - band_name = '', ) + asset_band = null, + band_descriptor = null, ) ] ) else: @@ -91,8 +91,8 @@ def make_instance(self, include_optional) -> StacProviderDataset: descriptor = 'source', ), bands = [ geoengine_api_client.models.stac_provider_dataset_band.StacProviderDatasetBand( - asset_title = '', - band_name = '', ) + asset_band = null, + band_descriptor = null, ) ], ) """ diff --git a/api-clients/python/test/test_stac_provider_dataset_band.py b/api-clients/python/test/test_stac_provider_dataset_band.py index 1ba2089bf..5baf7d40c 100644 --- a/api-clients/python/test/test_stac_provider_dataset_band.py +++ b/api-clients/python/test/test_stac_provider_dataset_band.py @@ -35,12 +35,21 @@ def make_instance(self, include_optional) -> StacProviderDatasetBand: model = StacProviderDatasetBand() if include_optional: return StacProviderDatasetBand( - asset_title = '', - band_name = '' + asset_band = geoengine_api_client.models.stac_asset_band.StacAssetBand( + asset_title = '', + band_name = '', ), + band_descriptor = geoengine_api_client.models.raster_band_descriptor.RasterBandDescriptor( + name = '', + measurement = null, ) ) else: return StacProviderDatasetBand( - asset_title = '', + asset_band = geoengine_api_client.models.stac_asset_band.StacAssetBand( + asset_title = '', + band_name = '', ), + band_descriptor = geoengine_api_client.models.raster_band_descriptor.RasterBandDescriptor( + name = '', + measurement = null, ), ) """ diff --git a/api-clients/python/test/test_typed_data_provider_definition.py b/api-clients/python/test/test_typed_data_provider_definition.py index 2039d3add..33b978cb4 100644 --- a/api-clients/python/test/test_typed_data_provider_definition.py +++ b/api-clients/python/test/test_typed_data_provider_definition.py @@ -112,6 +112,10 @@ def make_instance(self, include_optional) -> TypedDataProviderDefinition: endpoint = '', access_key = null, secret_key = null, ), + authentication = geoengine_api_client.models.stac_provider_authentication.StacProviderAuthentication( + endpoint = '', + username = '', + password = '', ), time_dimension = None, datasets = [ geoengine_api_client.models.stac_provider_dataset.StacProviderDataset( @@ -140,11 +144,12 @@ def make_instance(self, include_optional) -> TypedDataProviderDefinition: descriptor = 'source', ), bands = [ geoengine_api_client.models.stac_provider_dataset_band.StacProviderDatasetBand( - asset_title = '', - band_name = '', ) + asset_band = null, + band_descriptor = null, ) ], ) ], query_timeout_secs = 56, + page_limit = 56, user = '', refresh_token = '', expiry_date = datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f') @@ -230,8 +235,8 @@ def make_instance(self, include_optional) -> TypedDataProviderDefinition: descriptor = 'source', ), bands = [ geoengine_api_client.models.stac_provider_dataset_band.StacProviderDatasetBand( - asset_title = '', - band_name = '', ) + asset_band = null, + band_descriptor = null, ) ], ) ], ) diff --git a/api-clients/rust/.openapi-generator/FILES b/api-clients/rust/.openapi-generator/FILES index 92923a5df..eb8e398b3 100644 --- a/api-clients/rust/.openapi-generator/FILES +++ b/api-clients/rust/.openapi-generator/FILES @@ -275,7 +275,9 @@ docs/SpatialReferencesApi.md docs/SpatialResolution.md docs/StRectangle.md docs/StacApiRetries.md +docs/StacAssetBand.md docs/StacDataProviderDefinition.md +docs/StacProviderAuthentication.md docs/StacProviderDataset.md docs/StacProviderDatasetBand.md docs/StacProviderS3Config.md @@ -661,7 +663,9 @@ src/models/spatial_reference_specification.rs src/models/spatial_resolution.rs src/models/st_rectangle.rs src/models/stac_api_retries.rs +src/models/stac_asset_band.rs src/models/stac_data_provider_definition.rs +src/models/stac_provider_authentication.rs src/models/stac_provider_dataset.rs src/models/stac_provider_dataset_band.rs src/models/stac_provider_s3_config.rs diff --git a/api-clients/rust/README.md b/api-clients/rust/README.md index 5ebb6bf46..67c875ec4 100644 --- a/api-clients/rust/README.md +++ b/api-clients/rust/README.md @@ -391,7 +391,9 @@ Class | Method | HTTP request | Description - [SpatialResolution](docs/SpatialResolution.md) - [StRectangle](docs/StRectangle.md) - [StacApiRetries](docs/StacApiRetries.md) + - [StacAssetBand](docs/StacAssetBand.md) - [StacDataProviderDefinition](docs/StacDataProviderDefinition.md) + - [StacProviderAuthentication](docs/StacProviderAuthentication.md) - [StacProviderDataset](docs/StacProviderDataset.md) - [StacProviderDatasetBand](docs/StacProviderDatasetBand.md) - [StacProviderS3Config](docs/StacProviderS3Config.md) diff --git a/api-clients/rust/docs/StacAssetBand.md b/api-clients/rust/docs/StacAssetBand.md new file mode 100644 index 000000000..debb76d4c --- /dev/null +++ b/api-clients/rust/docs/StacAssetBand.md @@ -0,0 +1,12 @@ +# StacAssetBand + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**asset_title** | **String** | | +**band_name** | Option<**String**> | | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/api-clients/rust/docs/StacDataProviderDefinition.md b/api-clients/rust/docs/StacDataProviderDefinition.md index 05cdb89cf..79e76848d 100644 --- a/api-clients/rust/docs/StacDataProviderDefinition.md +++ b/api-clients/rust/docs/StacDataProviderDefinition.md @@ -12,9 +12,11 @@ Name | Type | Description | Notes **api_url** | **String** | | **collection_name** | **String** | | **s3_config** | Option<[**models::StacProviderS3Config**](StacProviderS3Config.md)> | | [optional] +**authentication** | Option<[**models::StacProviderAuthentication**](StacProviderAuthentication.md)> | | [optional] **time_dimension** | [**models::TimeDimension**](TimeDimension.md) | | **datasets** | [**Vec**](StacProviderDataset.md) | | **query_timeout_secs** | Option<**i64**> | Timeout in seconds for outgoing STAC API HTTP requests. | [optional] +**page_limit** | Option<**i64**> | | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/api-clients/rust/docs/StacProviderAuthentication.md b/api-clients/rust/docs/StacProviderAuthentication.md new file mode 100644 index 000000000..f28d0f5de --- /dev/null +++ b/api-clients/rust/docs/StacProviderAuthentication.md @@ -0,0 +1,13 @@ +# StacProviderAuthentication + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**endpoint** | **String** | | +**username** | **String** | | +**password** | **String** | A wrapper type that serializes to \"*****\" and can be deserialized from any string. If the inner value is \"*****\", it is considered unknown and `as_option` returns `None`. This is useful for secrets that should not be exposed in API responses, but can be set in API requests. | + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/api-clients/rust/docs/StacProviderDatasetBand.md b/api-clients/rust/docs/StacProviderDatasetBand.md index 79f9fe69e..59598b878 100644 --- a/api-clients/rust/docs/StacProviderDatasetBand.md +++ b/api-clients/rust/docs/StacProviderDatasetBand.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**asset_title** | **String** | | -**band_name** | Option<**String**> | | [optional] +**asset_band** | [**models::StacAssetBand**](StacAssetBand.md) | The band inside the STAC asset that this dataset band reads from (addressing: which asset file + which raster channel within it). | +**band_descriptor** | [**models::RasterBandDescriptor**](RasterBandDescriptor.md) | The band descriptor of the resulting geo engine dataset layer. | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/api-clients/rust/src/models/mod.rs b/api-clients/rust/src/models/mod.rs index 405e977de..411718223 100644 --- a/api-clients/rust/src/models/mod.rs +++ b/api-clients/rust/src/models/mod.rs @@ -518,8 +518,12 @@ pub mod st_rectangle; pub use self::st_rectangle::StRectangle; pub mod stac_api_retries; pub use self::stac_api_retries::StacApiRetries; +pub mod stac_asset_band; +pub use self::stac_asset_band::StacAssetBand; pub mod stac_data_provider_definition; pub use self::stac_data_provider_definition::StacDataProviderDefinition; +pub mod stac_provider_authentication; +pub use self::stac_provider_authentication::StacProviderAuthentication; pub mod stac_provider_dataset; pub use self::stac_provider_dataset::StacProviderDataset; pub mod stac_provider_dataset_band; diff --git a/api-clients/rust/src/models/stac_asset_band.rs b/api-clients/rust/src/models/stac_asset_band.rs new file mode 100644 index 000000000..ef58c3f6a --- /dev/null +++ b/api-clients/rust/src/models/stac_asset_band.rs @@ -0,0 +1,29 @@ +/* + * Geo Engine API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct StacAssetBand { + #[serde(rename = "assetTitle")] + pub asset_title: String, + #[serde(rename = "bandName", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub band_name: Option>, +} + +impl StacAssetBand { + pub fn new(asset_title: String) -> StacAssetBand { + StacAssetBand { + asset_title, + band_name: None, + } + } +} + diff --git a/api-clients/rust/src/models/stac_data_provider_definition.rs b/api-clients/rust/src/models/stac_data_provider_definition.rs index 41785f0a7..df21f30c1 100644 --- a/api-clients/rust/src/models/stac_data_provider_definition.rs +++ b/api-clients/rust/src/models/stac_data_provider_definition.rs @@ -28,6 +28,8 @@ pub struct StacDataProviderDefinition { pub collection_name: String, #[serde(rename = "s3Config", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] pub s3_config: Option>>, + #[serde(rename = "authentication", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] + pub authentication: Option>>, #[serde(rename = "timeDimension")] pub time_dimension: Box, #[serde(rename = "datasets")] @@ -35,6 +37,8 @@ pub struct StacDataProviderDefinition { /// Timeout in seconds for outgoing STAC API HTTP requests. #[serde(rename = "queryTimeoutSecs", skip_serializing_if = "Option::is_none")] pub query_timeout_secs: Option, + #[serde(rename = "pageLimit", skip_serializing_if = "Option::is_none")] + pub page_limit: Option, } impl StacDataProviderDefinition { @@ -48,9 +52,11 @@ impl StacDataProviderDefinition { api_url, collection_name, s3_config: None, + authentication: None, time_dimension: Box::new(time_dimension), datasets, query_timeout_secs: None, + page_limit: None, } } } diff --git a/api-clients/rust/src/models/stac_provider_authentication.rs b/api-clients/rust/src/models/stac_provider_authentication.rs new file mode 100644 index 000000000..28fe6bce1 --- /dev/null +++ b/api-clients/rust/src/models/stac_provider_authentication.rs @@ -0,0 +1,33 @@ +/* + * Geo Engine API + * + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * Generated by: https://openapi-generator.tech + */ + +use crate::models; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] +pub struct StacProviderAuthentication { + #[serde(rename = "endpoint")] + pub endpoint: String, + #[serde(rename = "username")] + pub username: String, + /// A wrapper type that serializes to \"*****\" and can be deserialized from any string. If the inner value is \"*****\", it is considered unknown and `as_option` returns `None`. This is useful for secrets that should not be exposed in API responses, but can be set in API requests. + #[serde(rename = "password")] + pub password: String, +} + +impl StacProviderAuthentication { + pub fn new(endpoint: String, username: String, password: String) -> StacProviderAuthentication { + StacProviderAuthentication { + endpoint, + username, + password, + } + } +} + diff --git a/api-clients/rust/src/models/stac_provider_dataset_band.rs b/api-clients/rust/src/models/stac_provider_dataset_band.rs index 308b85c22..adaacd56b 100644 --- a/api-clients/rust/src/models/stac_provider_dataset_band.rs +++ b/api-clients/rust/src/models/stac_provider_dataset_band.rs @@ -12,17 +12,19 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)] pub struct StacProviderDatasetBand { - #[serde(rename = "assetTitle")] - pub asset_title: String, - #[serde(rename = "bandName", default, with = "::serde_with::rust::double_option", skip_serializing_if = "Option::is_none")] - pub band_name: Option>, + /// The band inside the STAC asset that this dataset band reads from (addressing: which asset file + which raster channel within it). + #[serde(rename = "assetBand")] + pub asset_band: Box, + /// The band descriptor of the resulting geo engine dataset layer. + #[serde(rename = "bandDescriptor")] + pub band_descriptor: Box, } impl StacProviderDatasetBand { - pub fn new(asset_title: String) -> StacProviderDatasetBand { + pub fn new(asset_band: models::StacAssetBand, band_descriptor: models::RasterBandDescriptor) -> StacProviderDatasetBand { StacProviderDatasetBand { - asset_title, - band_name: None, + asset_band: Box::new(asset_band), + band_descriptor: Box::new(band_descriptor), } } } diff --git a/api-clients/typescript/README.md b/api-clients/typescript/README.md index eb97d0685..9e567a693 100644 --- a/api-clients/typescript/README.md +++ b/api-clients/typescript/README.md @@ -421,7 +421,9 @@ All URIs are relative to *https://geoengine.io/api* - [SpatialReferenceSpecification](docs/SpatialReferenceSpecification.md) - [SpatialResolution](docs/SpatialResolution.md) - [StacApiRetries](docs/StacApiRetries.md) +- [StacAssetBand](docs/StacAssetBand.md) - [StacDataProviderDefinition](docs/StacDataProviderDefinition.md) +- [StacProviderAuthentication](docs/StacProviderAuthentication.md) - [StacProviderDataset](docs/StacProviderDataset.md) - [StacProviderDatasetBand](docs/StacProviderDatasetBand.md) - [StacProviderS3Config](docs/StacProviderS3Config.md) diff --git a/api-clients/typescript/dist/esm/models/StacAssetBand.d.ts b/api-clients/typescript/dist/esm/models/StacAssetBand.d.ts new file mode 100644 index 000000000..85187a13c --- /dev/null +++ b/api-clients/typescript/dist/esm/models/StacAssetBand.d.ts @@ -0,0 +1,37 @@ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/** + * + * @export + * @interface StacAssetBand + */ +export interface StacAssetBand { + /** + * + * @type {string} + * @memberof StacAssetBand + */ + assetTitle: string; + /** + * + * @type {string} + * @memberof StacAssetBand + */ + bandName?: string | null; +} +/** + * Check if a given object implements the StacAssetBand interface. + */ +export declare function instanceOfStacAssetBand(value: object): value is StacAssetBand; +export declare function StacAssetBandFromJSON(json: any): StacAssetBand; +export declare function StacAssetBandFromJSONTyped(json: any, ignoreDiscriminator: boolean): StacAssetBand; +export declare function StacAssetBandToJSON(json: any): StacAssetBand; +export declare function StacAssetBandToJSONTyped(value?: StacAssetBand | null, ignoreDiscriminator?: boolean): any; diff --git a/api-clients/typescript/dist/esm/models/StacAssetBand.js b/api-clients/typescript/dist/esm/models/StacAssetBand.js new file mode 100644 index 000000000..615b13438 --- /dev/null +++ b/api-clients/typescript/dist/esm/models/StacAssetBand.js @@ -0,0 +1,44 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/** + * Check if a given object implements the StacAssetBand interface. + */ +export function instanceOfStacAssetBand(value) { + if (!('assetTitle' in value) || value['assetTitle'] === undefined) + return false; + return true; +} +export function StacAssetBandFromJSON(json) { + return StacAssetBandFromJSONTyped(json, false); +} +export function StacAssetBandFromJSONTyped(json, ignoreDiscriminator) { + if (json == null) { + return json; + } + return { + 'assetTitle': json['assetTitle'], + 'bandName': json['bandName'] == null ? undefined : json['bandName'], + }; +} +export function StacAssetBandToJSON(json) { + return StacAssetBandToJSONTyped(json, false); +} +export function StacAssetBandToJSONTyped(value, ignoreDiscriminator = false) { + if (value == null) { + return value; + } + return { + 'assetTitle': value['assetTitle'], + 'bandName': value['bandName'], + }; +} diff --git a/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.d.ts b/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.d.ts index 0cff0fe18..23df86ad4 100644 --- a/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.d.ts +++ b/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.d.ts @@ -10,6 +10,7 @@ */ import type { StacProviderS3Config } from './StacProviderS3Config'; import type { StacProviderDataset } from './StacProviderDataset'; +import type { StacProviderAuthentication } from './StacProviderAuthentication'; import type { TimeDimension } from './TimeDimension'; /** * @@ -65,6 +66,12 @@ export interface StacDataProviderDefinition { * @memberof StacDataProviderDefinition */ s3Config?: StacProviderS3Config | null; + /** + * + * @type {StacProviderAuthentication} + * @memberof StacDataProviderDefinition + */ + authentication?: StacProviderAuthentication | null; /** * * @type {TimeDimension} @@ -83,6 +90,12 @@ export interface StacDataProviderDefinition { * @memberof StacDataProviderDefinition */ queryTimeoutSecs?: number; + /** + * + * @type {number} + * @memberof StacDataProviderDefinition + */ + pageLimit?: number; } /** * @export diff --git a/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.js b/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.js index 7e66ead31..156b51234 100644 --- a/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.js +++ b/api-clients/typescript/dist/esm/models/StacDataProviderDefinition.js @@ -12,6 +12,7 @@ */ import { StacProviderS3ConfigFromJSON, StacProviderS3ConfigToJSON, } from './StacProviderS3Config'; import { StacProviderDatasetFromJSON, StacProviderDatasetToJSON, } from './StacProviderDataset'; +import { StacProviderAuthenticationFromJSON, StacProviderAuthenticationToJSON, } from './StacProviderAuthentication'; import { TimeDimensionFromJSON, TimeDimensionToJSON, } from './TimeDimension'; /** * @export @@ -57,9 +58,11 @@ export function StacDataProviderDefinitionFromJSONTyped(json, ignoreDiscriminato 'apiUrl': json['apiUrl'], 'collectionName': json['collectionName'], 's3Config': json['s3Config'] == null ? undefined : StacProviderS3ConfigFromJSON(json['s3Config']), + 'authentication': json['authentication'] == null ? undefined : StacProviderAuthenticationFromJSON(json['authentication']), 'timeDimension': TimeDimensionFromJSON(json['timeDimension']), 'datasets': (json['datasets'].map(StacProviderDatasetFromJSON)), 'queryTimeoutSecs': json['queryTimeoutSecs'] == null ? undefined : json['queryTimeoutSecs'], + 'pageLimit': json['pageLimit'] == null ? undefined : json['pageLimit'], }; } export function StacDataProviderDefinitionToJSON(json) { @@ -78,8 +81,10 @@ export function StacDataProviderDefinitionToJSONTyped(value, ignoreDiscriminator 'apiUrl': value['apiUrl'], 'collectionName': value['collectionName'], 's3Config': StacProviderS3ConfigToJSON(value['s3Config']), + 'authentication': StacProviderAuthenticationToJSON(value['authentication']), 'timeDimension': TimeDimensionToJSON(value['timeDimension']), 'datasets': (value['datasets'].map(StacProviderDatasetToJSON)), 'queryTimeoutSecs': value['queryTimeoutSecs'], + 'pageLimit': value['pageLimit'], }; } diff --git a/api-clients/typescript/dist/esm/models/StacProviderAuthentication.d.ts b/api-clients/typescript/dist/esm/models/StacProviderAuthentication.d.ts new file mode 100644 index 000000000..e9b154418 --- /dev/null +++ b/api-clients/typescript/dist/esm/models/StacProviderAuthentication.d.ts @@ -0,0 +1,45 @@ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/** + * + * @export + * @interface StacProviderAuthentication + */ +export interface StacProviderAuthentication { + /** + * + * @type {string} + * @memberof StacProviderAuthentication + */ + endpoint: string; + /** + * + * @type {string} + * @memberof StacProviderAuthentication + */ + username: string; + /** + * A wrapper type that serializes to "*****" and can be deserialized from any string. + * If the inner value is "*****", it is considered unknown and `as_option` returns `None`. + * This is useful for secrets that should not be exposed in API responses, but can be set in API requests. + * @type {string} + * @memberof StacProviderAuthentication + */ + password: string; +} +/** + * Check if a given object implements the StacProviderAuthentication interface. + */ +export declare function instanceOfStacProviderAuthentication(value: object): value is StacProviderAuthentication; +export declare function StacProviderAuthenticationFromJSON(json: any): StacProviderAuthentication; +export declare function StacProviderAuthenticationFromJSONTyped(json: any, ignoreDiscriminator: boolean): StacProviderAuthentication; +export declare function StacProviderAuthenticationToJSON(json: any): StacProviderAuthentication; +export declare function StacProviderAuthenticationToJSONTyped(value?: StacProviderAuthentication | null, ignoreDiscriminator?: boolean): any; diff --git a/api-clients/typescript/dist/esm/models/StacProviderAuthentication.js b/api-clients/typescript/dist/esm/models/StacProviderAuthentication.js new file mode 100644 index 000000000..876879837 --- /dev/null +++ b/api-clients/typescript/dist/esm/models/StacProviderAuthentication.js @@ -0,0 +1,50 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/** + * Check if a given object implements the StacProviderAuthentication interface. + */ +export function instanceOfStacProviderAuthentication(value) { + if (!('endpoint' in value) || value['endpoint'] === undefined) + return false; + if (!('username' in value) || value['username'] === undefined) + return false; + if (!('password' in value) || value['password'] === undefined) + return false; + return true; +} +export function StacProviderAuthenticationFromJSON(json) { + return StacProviderAuthenticationFromJSONTyped(json, false); +} +export function StacProviderAuthenticationFromJSONTyped(json, ignoreDiscriminator) { + if (json == null) { + return json; + } + return { + 'endpoint': json['endpoint'], + 'username': json['username'], + 'password': json['password'], + }; +} +export function StacProviderAuthenticationToJSON(json) { + return StacProviderAuthenticationToJSONTyped(json, false); +} +export function StacProviderAuthenticationToJSONTyped(value, ignoreDiscriminator = false) { + if (value == null) { + return value; + } + return { + 'endpoint': value['endpoint'], + 'username': value['username'], + 'password': value['password'], + }; +} diff --git a/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.d.ts b/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.d.ts index b1199183c..667f85fa4 100644 --- a/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.d.ts +++ b/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.d.ts @@ -8,6 +8,8 @@ * https://openapi-generator.tech * Do not edit the class manually. */ +import type { StacAssetBand } from './StacAssetBand'; +import type { RasterBandDescriptor } from './RasterBandDescriptor'; /** * * @export @@ -15,17 +17,18 @@ */ export interface StacProviderDatasetBand { /** - * - * @type {string} + * The band inside the STAC asset that this dataset band reads from + * (addressing: which asset file + which raster channel within it). + * @type {StacAssetBand} * @memberof StacProviderDatasetBand */ - assetTitle: string; + assetBand: StacAssetBand; /** - * - * @type {string} + * The band descriptor of the resulting geo engine dataset layer. + * @type {RasterBandDescriptor} * @memberof StacProviderDatasetBand */ - bandName?: string | null; + bandDescriptor: RasterBandDescriptor; } /** * Check if a given object implements the StacProviderDatasetBand interface. diff --git a/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.js b/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.js index 5dc9d4a4f..fa6014aa7 100644 --- a/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.js +++ b/api-clients/typescript/dist/esm/models/StacProviderDatasetBand.js @@ -10,11 +10,15 @@ * https://openapi-generator.tech * Do not edit the class manually. */ +import { StacAssetBandFromJSON, StacAssetBandToJSON, } from './StacAssetBand'; +import { RasterBandDescriptorFromJSON, RasterBandDescriptorToJSON, } from './RasterBandDescriptor'; /** * Check if a given object implements the StacProviderDatasetBand interface. */ export function instanceOfStacProviderDatasetBand(value) { - if (!('assetTitle' in value) || value['assetTitle'] === undefined) + if (!('assetBand' in value) || value['assetBand'] === undefined) + return false; + if (!('bandDescriptor' in value) || value['bandDescriptor'] === undefined) return false; return true; } @@ -26,8 +30,8 @@ export function StacProviderDatasetBandFromJSONTyped(json, ignoreDiscriminator) return json; } return { - 'assetTitle': json['assetTitle'], - 'bandName': json['bandName'] == null ? undefined : json['bandName'], + 'assetBand': StacAssetBandFromJSON(json['assetBand']), + 'bandDescriptor': RasterBandDescriptorFromJSON(json['bandDescriptor']), }; } export function StacProviderDatasetBandToJSON(json) { @@ -38,7 +42,7 @@ export function StacProviderDatasetBandToJSONTyped(value, ignoreDiscriminator = return value; } return { - 'assetTitle': value['assetTitle'], - 'bandName': value['bandName'], + 'assetBand': StacAssetBandToJSON(value['assetBand']), + 'bandDescriptor': RasterBandDescriptorToJSON(value['bandDescriptor']), }; } diff --git a/api-clients/typescript/dist/esm/models/index.d.ts b/api-clients/typescript/dist/esm/models/index.d.ts index 3d1779235..e2b2b6da3 100644 --- a/api-clients/typescript/dist/esm/models/index.d.ts +++ b/api-clients/typescript/dist/esm/models/index.d.ts @@ -258,7 +258,9 @@ export * from './SpatialPartition2D'; export * from './SpatialReferenceSpecification'; export * from './SpatialResolution'; export * from './StacApiRetries'; +export * from './StacAssetBand'; export * from './StacDataProviderDefinition'; +export * from './StacProviderAuthentication'; export * from './StacProviderDataset'; export * from './StacProviderDatasetBand'; export * from './StacProviderS3Config'; diff --git a/api-clients/typescript/dist/esm/models/index.js b/api-clients/typescript/dist/esm/models/index.js index 2a105e270..1ad128c79 100644 --- a/api-clients/typescript/dist/esm/models/index.js +++ b/api-clients/typescript/dist/esm/models/index.js @@ -260,7 +260,9 @@ export * from './SpatialPartition2D'; export * from './SpatialReferenceSpecification'; export * from './SpatialResolution'; export * from './StacApiRetries'; +export * from './StacAssetBand'; export * from './StacDataProviderDefinition'; +export * from './StacProviderAuthentication'; export * from './StacProviderDataset'; export * from './StacProviderDatasetBand'; export * from './StacProviderS3Config'; diff --git a/api-clients/typescript/dist/models/StacAssetBand.d.ts b/api-clients/typescript/dist/models/StacAssetBand.d.ts new file mode 100644 index 000000000..85187a13c --- /dev/null +++ b/api-clients/typescript/dist/models/StacAssetBand.d.ts @@ -0,0 +1,37 @@ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/** + * + * @export + * @interface StacAssetBand + */ +export interface StacAssetBand { + /** + * + * @type {string} + * @memberof StacAssetBand + */ + assetTitle: string; + /** + * + * @type {string} + * @memberof StacAssetBand + */ + bandName?: string | null; +} +/** + * Check if a given object implements the StacAssetBand interface. + */ +export declare function instanceOfStacAssetBand(value: object): value is StacAssetBand; +export declare function StacAssetBandFromJSON(json: any): StacAssetBand; +export declare function StacAssetBandFromJSONTyped(json: any, ignoreDiscriminator: boolean): StacAssetBand; +export declare function StacAssetBandToJSON(json: any): StacAssetBand; +export declare function StacAssetBandToJSONTyped(value?: StacAssetBand | null, ignoreDiscriminator?: boolean): any; diff --git a/api-clients/typescript/dist/models/StacAssetBand.js b/api-clients/typescript/dist/models/StacAssetBand.js new file mode 100644 index 000000000..e3c3253d1 --- /dev/null +++ b/api-clients/typescript/dist/models/StacAssetBand.js @@ -0,0 +1,51 @@ +"use strict"; +/* tslint:disable */ +/* eslint-disable */ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.instanceOfStacAssetBand = instanceOfStacAssetBand; +exports.StacAssetBandFromJSON = StacAssetBandFromJSON; +exports.StacAssetBandFromJSONTyped = StacAssetBandFromJSONTyped; +exports.StacAssetBandToJSON = StacAssetBandToJSON; +exports.StacAssetBandToJSONTyped = StacAssetBandToJSONTyped; +/** + * Check if a given object implements the StacAssetBand interface. + */ +function instanceOfStacAssetBand(value) { + if (!('assetTitle' in value) || value['assetTitle'] === undefined) + return false; + return true; +} +function StacAssetBandFromJSON(json) { + return StacAssetBandFromJSONTyped(json, false); +} +function StacAssetBandFromJSONTyped(json, ignoreDiscriminator) { + if (json == null) { + return json; + } + return { + 'assetTitle': json['assetTitle'], + 'bandName': json['bandName'] == null ? undefined : json['bandName'], + }; +} +function StacAssetBandToJSON(json) { + return StacAssetBandToJSONTyped(json, false); +} +function StacAssetBandToJSONTyped(value, ignoreDiscriminator = false) { + if (value == null) { + return value; + } + return { + 'assetTitle': value['assetTitle'], + 'bandName': value['bandName'], + }; +} diff --git a/api-clients/typescript/dist/models/StacDataProviderDefinition.d.ts b/api-clients/typescript/dist/models/StacDataProviderDefinition.d.ts index 0cff0fe18..23df86ad4 100644 --- a/api-clients/typescript/dist/models/StacDataProviderDefinition.d.ts +++ b/api-clients/typescript/dist/models/StacDataProviderDefinition.d.ts @@ -10,6 +10,7 @@ */ import type { StacProviderS3Config } from './StacProviderS3Config'; import type { StacProviderDataset } from './StacProviderDataset'; +import type { StacProviderAuthentication } from './StacProviderAuthentication'; import type { TimeDimension } from './TimeDimension'; /** * @@ -65,6 +66,12 @@ export interface StacDataProviderDefinition { * @memberof StacDataProviderDefinition */ s3Config?: StacProviderS3Config | null; + /** + * + * @type {StacProviderAuthentication} + * @memberof StacDataProviderDefinition + */ + authentication?: StacProviderAuthentication | null; /** * * @type {TimeDimension} @@ -83,6 +90,12 @@ export interface StacDataProviderDefinition { * @memberof StacDataProviderDefinition */ queryTimeoutSecs?: number; + /** + * + * @type {number} + * @memberof StacDataProviderDefinition + */ + pageLimit?: number; } /** * @export diff --git a/api-clients/typescript/dist/models/StacDataProviderDefinition.js b/api-clients/typescript/dist/models/StacDataProviderDefinition.js index 4f903d069..8317c630a 100644 --- a/api-clients/typescript/dist/models/StacDataProviderDefinition.js +++ b/api-clients/typescript/dist/models/StacDataProviderDefinition.js @@ -20,6 +20,7 @@ exports.StacDataProviderDefinitionToJSON = StacDataProviderDefinitionToJSON; exports.StacDataProviderDefinitionToJSONTyped = StacDataProviderDefinitionToJSONTyped; const StacProviderS3Config_1 = require("./StacProviderS3Config"); const StacProviderDataset_1 = require("./StacProviderDataset"); +const StacProviderAuthentication_1 = require("./StacProviderAuthentication"); const TimeDimension_1 = require("./TimeDimension"); /** * @export @@ -65,9 +66,11 @@ function StacDataProviderDefinitionFromJSONTyped(json, ignoreDiscriminator) { 'apiUrl': json['apiUrl'], 'collectionName': json['collectionName'], 's3Config': json['s3Config'] == null ? undefined : (0, StacProviderS3Config_1.StacProviderS3ConfigFromJSON)(json['s3Config']), + 'authentication': json['authentication'] == null ? undefined : (0, StacProviderAuthentication_1.StacProviderAuthenticationFromJSON)(json['authentication']), 'timeDimension': (0, TimeDimension_1.TimeDimensionFromJSON)(json['timeDimension']), 'datasets': (json['datasets'].map(StacProviderDataset_1.StacProviderDatasetFromJSON)), 'queryTimeoutSecs': json['queryTimeoutSecs'] == null ? undefined : json['queryTimeoutSecs'], + 'pageLimit': json['pageLimit'] == null ? undefined : json['pageLimit'], }; } function StacDataProviderDefinitionToJSON(json) { @@ -86,8 +89,10 @@ function StacDataProviderDefinitionToJSONTyped(value, ignoreDiscriminator = fals 'apiUrl': value['apiUrl'], 'collectionName': value['collectionName'], 's3Config': (0, StacProviderS3Config_1.StacProviderS3ConfigToJSON)(value['s3Config']), + 'authentication': (0, StacProviderAuthentication_1.StacProviderAuthenticationToJSON)(value['authentication']), 'timeDimension': (0, TimeDimension_1.TimeDimensionToJSON)(value['timeDimension']), 'datasets': (value['datasets'].map(StacProviderDataset_1.StacProviderDatasetToJSON)), 'queryTimeoutSecs': value['queryTimeoutSecs'], + 'pageLimit': value['pageLimit'], }; } diff --git a/api-clients/typescript/dist/models/StacProviderAuthentication.d.ts b/api-clients/typescript/dist/models/StacProviderAuthentication.d.ts new file mode 100644 index 000000000..e9b154418 --- /dev/null +++ b/api-clients/typescript/dist/models/StacProviderAuthentication.d.ts @@ -0,0 +1,45 @@ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +/** + * + * @export + * @interface StacProviderAuthentication + */ +export interface StacProviderAuthentication { + /** + * + * @type {string} + * @memberof StacProviderAuthentication + */ + endpoint: string; + /** + * + * @type {string} + * @memberof StacProviderAuthentication + */ + username: string; + /** + * A wrapper type that serializes to "*****" and can be deserialized from any string. + * If the inner value is "*****", it is considered unknown and `as_option` returns `None`. + * This is useful for secrets that should not be exposed in API responses, but can be set in API requests. + * @type {string} + * @memberof StacProviderAuthentication + */ + password: string; +} +/** + * Check if a given object implements the StacProviderAuthentication interface. + */ +export declare function instanceOfStacProviderAuthentication(value: object): value is StacProviderAuthentication; +export declare function StacProviderAuthenticationFromJSON(json: any): StacProviderAuthentication; +export declare function StacProviderAuthenticationFromJSONTyped(json: any, ignoreDiscriminator: boolean): StacProviderAuthentication; +export declare function StacProviderAuthenticationToJSON(json: any): StacProviderAuthentication; +export declare function StacProviderAuthenticationToJSONTyped(value?: StacProviderAuthentication | null, ignoreDiscriminator?: boolean): any; diff --git a/api-clients/typescript/dist/models/StacProviderAuthentication.js b/api-clients/typescript/dist/models/StacProviderAuthentication.js new file mode 100644 index 000000000..c595a6155 --- /dev/null +++ b/api-clients/typescript/dist/models/StacProviderAuthentication.js @@ -0,0 +1,57 @@ +"use strict"; +/* tslint:disable */ +/* eslint-disable */ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.instanceOfStacProviderAuthentication = instanceOfStacProviderAuthentication; +exports.StacProviderAuthenticationFromJSON = StacProviderAuthenticationFromJSON; +exports.StacProviderAuthenticationFromJSONTyped = StacProviderAuthenticationFromJSONTyped; +exports.StacProviderAuthenticationToJSON = StacProviderAuthenticationToJSON; +exports.StacProviderAuthenticationToJSONTyped = StacProviderAuthenticationToJSONTyped; +/** + * Check if a given object implements the StacProviderAuthentication interface. + */ +function instanceOfStacProviderAuthentication(value) { + if (!('endpoint' in value) || value['endpoint'] === undefined) + return false; + if (!('username' in value) || value['username'] === undefined) + return false; + if (!('password' in value) || value['password'] === undefined) + return false; + return true; +} +function StacProviderAuthenticationFromJSON(json) { + return StacProviderAuthenticationFromJSONTyped(json, false); +} +function StacProviderAuthenticationFromJSONTyped(json, ignoreDiscriminator) { + if (json == null) { + return json; + } + return { + 'endpoint': json['endpoint'], + 'username': json['username'], + 'password': json['password'], + }; +} +function StacProviderAuthenticationToJSON(json) { + return StacProviderAuthenticationToJSONTyped(json, false); +} +function StacProviderAuthenticationToJSONTyped(value, ignoreDiscriminator = false) { + if (value == null) { + return value; + } + return { + 'endpoint': value['endpoint'], + 'username': value['username'], + 'password': value['password'], + }; +} diff --git a/api-clients/typescript/dist/models/StacProviderDatasetBand.d.ts b/api-clients/typescript/dist/models/StacProviderDatasetBand.d.ts index b1199183c..667f85fa4 100644 --- a/api-clients/typescript/dist/models/StacProviderDatasetBand.d.ts +++ b/api-clients/typescript/dist/models/StacProviderDatasetBand.d.ts @@ -8,6 +8,8 @@ * https://openapi-generator.tech * Do not edit the class manually. */ +import type { StacAssetBand } from './StacAssetBand'; +import type { RasterBandDescriptor } from './RasterBandDescriptor'; /** * * @export @@ -15,17 +17,18 @@ */ export interface StacProviderDatasetBand { /** - * - * @type {string} + * The band inside the STAC asset that this dataset band reads from + * (addressing: which asset file + which raster channel within it). + * @type {StacAssetBand} * @memberof StacProviderDatasetBand */ - assetTitle: string; + assetBand: StacAssetBand; /** - * - * @type {string} + * The band descriptor of the resulting geo engine dataset layer. + * @type {RasterBandDescriptor} * @memberof StacProviderDatasetBand */ - bandName?: string | null; + bandDescriptor: RasterBandDescriptor; } /** * Check if a given object implements the StacProviderDatasetBand interface. diff --git a/api-clients/typescript/dist/models/StacProviderDatasetBand.js b/api-clients/typescript/dist/models/StacProviderDatasetBand.js index d16f200b9..dec0fa988 100644 --- a/api-clients/typescript/dist/models/StacProviderDatasetBand.js +++ b/api-clients/typescript/dist/models/StacProviderDatasetBand.js @@ -17,11 +17,15 @@ exports.StacProviderDatasetBandFromJSON = StacProviderDatasetBandFromJSON; exports.StacProviderDatasetBandFromJSONTyped = StacProviderDatasetBandFromJSONTyped; exports.StacProviderDatasetBandToJSON = StacProviderDatasetBandToJSON; exports.StacProviderDatasetBandToJSONTyped = StacProviderDatasetBandToJSONTyped; +const StacAssetBand_1 = require("./StacAssetBand"); +const RasterBandDescriptor_1 = require("./RasterBandDescriptor"); /** * Check if a given object implements the StacProviderDatasetBand interface. */ function instanceOfStacProviderDatasetBand(value) { - if (!('assetTitle' in value) || value['assetTitle'] === undefined) + if (!('assetBand' in value) || value['assetBand'] === undefined) + return false; + if (!('bandDescriptor' in value) || value['bandDescriptor'] === undefined) return false; return true; } @@ -33,8 +37,8 @@ function StacProviderDatasetBandFromJSONTyped(json, ignoreDiscriminator) { return json; } return { - 'assetTitle': json['assetTitle'], - 'bandName': json['bandName'] == null ? undefined : json['bandName'], + 'assetBand': (0, StacAssetBand_1.StacAssetBandFromJSON)(json['assetBand']), + 'bandDescriptor': (0, RasterBandDescriptor_1.RasterBandDescriptorFromJSON)(json['bandDescriptor']), }; } function StacProviderDatasetBandToJSON(json) { @@ -45,7 +49,7 @@ function StacProviderDatasetBandToJSONTyped(value, ignoreDiscriminator = false) return value; } return { - 'assetTitle': value['assetTitle'], - 'bandName': value['bandName'], + 'assetBand': (0, StacAssetBand_1.StacAssetBandToJSON)(value['assetBand']), + 'bandDescriptor': (0, RasterBandDescriptor_1.RasterBandDescriptorToJSON)(value['bandDescriptor']), }; } diff --git a/api-clients/typescript/dist/models/index.d.ts b/api-clients/typescript/dist/models/index.d.ts index 3d1779235..e2b2b6da3 100644 --- a/api-clients/typescript/dist/models/index.d.ts +++ b/api-clients/typescript/dist/models/index.d.ts @@ -258,7 +258,9 @@ export * from './SpatialPartition2D'; export * from './SpatialReferenceSpecification'; export * from './SpatialResolution'; export * from './StacApiRetries'; +export * from './StacAssetBand'; export * from './StacDataProviderDefinition'; +export * from './StacProviderAuthentication'; export * from './StacProviderDataset'; export * from './StacProviderDatasetBand'; export * from './StacProviderS3Config'; diff --git a/api-clients/typescript/dist/models/index.js b/api-clients/typescript/dist/models/index.js index fdc9aa83e..a1dd07add 100644 --- a/api-clients/typescript/dist/models/index.js +++ b/api-clients/typescript/dist/models/index.js @@ -276,7 +276,9 @@ __exportStar(require("./SpatialPartition2D"), exports); __exportStar(require("./SpatialReferenceSpecification"), exports); __exportStar(require("./SpatialResolution"), exports); __exportStar(require("./StacApiRetries"), exports); +__exportStar(require("./StacAssetBand"), exports); __exportStar(require("./StacDataProviderDefinition"), exports); +__exportStar(require("./StacProviderAuthentication"), exports); __exportStar(require("./StacProviderDataset"), exports); __exportStar(require("./StacProviderDatasetBand"), exports); __exportStar(require("./StacProviderS3Config"), exports); diff --git a/api-clients/typescript/docs/StacAssetBand.md b/api-clients/typescript/docs/StacAssetBand.md new file mode 100644 index 000000000..277eeaa44 --- /dev/null +++ b/api-clients/typescript/docs/StacAssetBand.md @@ -0,0 +1,36 @@ + +# StacAssetBand + + +## Properties + +Name | Type +------------ | ------------- +`assetTitle` | string +`bandName` | string + +## Example + +```typescript +import type { StacAssetBand } from '@geoengine/api-client' + +// TODO: Update the object below with actual values +const example = { + "assetTitle": null, + "bandName": null, +} satisfies StacAssetBand + +console.log(example) + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example) +console.log(exampleJSON) + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as StacAssetBand +console.log(exampleParsed) +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + + diff --git a/api-clients/typescript/docs/StacDataProviderDefinition.md b/api-clients/typescript/docs/StacDataProviderDefinition.md index c2c89b940..84129d494 100644 --- a/api-clients/typescript/docs/StacDataProviderDefinition.md +++ b/api-clients/typescript/docs/StacDataProviderDefinition.md @@ -14,9 +14,11 @@ Name | Type `apiUrl` | string `collectionName` | string `s3Config` | [StacProviderS3Config](StacProviderS3Config.md) +`authentication` | [StacProviderAuthentication](StacProviderAuthentication.md) `timeDimension` | [TimeDimension](TimeDimension.md) `datasets` | [Array<StacProviderDataset>](StacProviderDataset.md) `queryTimeoutSecs` | number +`pageLimit` | number ## Example @@ -33,9 +35,11 @@ const example = { "apiUrl": null, "collectionName": null, "s3Config": null, + "authentication": null, "timeDimension": null, "datasets": null, "queryTimeoutSecs": null, + "pageLimit": null, } satisfies StacDataProviderDefinition console.log(example) diff --git a/api-clients/typescript/docs/StacProviderAuthentication.md b/api-clients/typescript/docs/StacProviderAuthentication.md new file mode 100644 index 000000000..c11f31d27 --- /dev/null +++ b/api-clients/typescript/docs/StacProviderAuthentication.md @@ -0,0 +1,38 @@ + +# StacProviderAuthentication + + +## Properties + +Name | Type +------------ | ------------- +`endpoint` | string +`username` | string +`password` | string + +## Example + +```typescript +import type { StacProviderAuthentication } from '@geoengine/api-client' + +// TODO: Update the object below with actual values +const example = { + "endpoint": null, + "username": null, + "password": null, +} satisfies StacProviderAuthentication + +console.log(example) + +// Convert the instance to a JSON string +const exampleJSON: string = JSON.stringify(example) +console.log(exampleJSON) + +// Parse the JSON string back to an object +const exampleParsed = JSON.parse(exampleJSON) as StacProviderAuthentication +console.log(exampleParsed) +``` + +[[Back to top]](#) [[Back to API list]](../README.md#api-endpoints) [[Back to Model list]](../README.md#models) [[Back to README]](../README.md) + + diff --git a/api-clients/typescript/docs/StacProviderDatasetBand.md b/api-clients/typescript/docs/StacProviderDatasetBand.md index bb5b3a7c3..da43c8f71 100644 --- a/api-clients/typescript/docs/StacProviderDatasetBand.md +++ b/api-clients/typescript/docs/StacProviderDatasetBand.md @@ -6,8 +6,8 @@ Name | Type ------------ | ------------- -`assetTitle` | string -`bandName` | string +`assetBand` | [StacAssetBand](StacAssetBand.md) +`bandDescriptor` | [RasterBandDescriptor](RasterBandDescriptor.md) ## Example @@ -16,8 +16,8 @@ import type { StacProviderDatasetBand } from '@geoengine/api-client' // TODO: Update the object below with actual values const example = { - "assetTitle": null, - "bandName": null, + "assetBand": null, + "bandDescriptor": null, } satisfies StacProviderDatasetBand console.log(example) diff --git a/api-clients/typescript/docs/TypedDataProviderDefinition.md b/api-clients/typescript/docs/TypedDataProviderDefinition.md index 94115c59e..80950d0ae 100644 --- a/api-clients/typescript/docs/TypedDataProviderDefinition.md +++ b/api-clients/typescript/docs/TypedDataProviderDefinition.md @@ -40,9 +40,11 @@ Name | Type `queryBuffer` | [StacQueryBuffer](StacQueryBuffer.md) `collectionName` | string `s3Config` | [StacProviderS3Config](StacProviderS3Config.md) +`authentication` | [StacProviderAuthentication](StacProviderAuthentication.md) `timeDimension` | [TimeDimension](TimeDimension.md) `datasets` | [Array<StacProviderDataset>](StacProviderDataset.md) `queryTimeoutSecs` | number +`pageLimit` | number `user` | string `refreshToken` | string `expiryDate` | Date @@ -88,9 +90,11 @@ const example = { "queryBuffer": null, "collectionName": null, "s3Config": null, + "authentication": null, "timeDimension": null, "datasets": null, "queryTimeoutSecs": null, + "pageLimit": null, "user": null, "refreshToken": null, "expiryDate": null, diff --git a/api-clients/typescript/src/models/StacAssetBand.ts b/api-clients/typescript/src/models/StacAssetBand.ts new file mode 100644 index 000000000..034bf175b --- /dev/null +++ b/api-clients/typescript/src/models/StacAssetBand.ts @@ -0,0 +1,73 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface StacAssetBand + */ +export interface StacAssetBand { + /** + * + * @type {string} + * @memberof StacAssetBand + */ + assetTitle: string; + /** + * + * @type {string} + * @memberof StacAssetBand + */ + bandName?: string | null; +} + +/** + * Check if a given object implements the StacAssetBand interface. + */ +export function instanceOfStacAssetBand(value: object): value is StacAssetBand { + if (!('assetTitle' in value) || value['assetTitle'] === undefined) return false; + return true; +} + +export function StacAssetBandFromJSON(json: any): StacAssetBand { + return StacAssetBandFromJSONTyped(json, false); +} + +export function StacAssetBandFromJSONTyped(json: any, ignoreDiscriminator: boolean): StacAssetBand { + if (json == null) { + return json; + } + return { + + 'assetTitle': json['assetTitle'], + 'bandName': json['bandName'] == null ? undefined : json['bandName'], + }; +} + +export function StacAssetBandToJSON(json: any): StacAssetBand { + return StacAssetBandToJSONTyped(json, false); +} + +export function StacAssetBandToJSONTyped(value?: StacAssetBand | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + + 'assetTitle': value['assetTitle'], + 'bandName': value['bandName'], + }; +} + diff --git a/api-clients/typescript/src/models/StacDataProviderDefinition.ts b/api-clients/typescript/src/models/StacDataProviderDefinition.ts index cd98f0127..53e953f6a 100644 --- a/api-clients/typescript/src/models/StacDataProviderDefinition.ts +++ b/api-clients/typescript/src/models/StacDataProviderDefinition.ts @@ -26,6 +26,13 @@ import { StacProviderDatasetToJSON, StacProviderDatasetToJSONTyped, } from './StacProviderDataset'; +import type { StacProviderAuthentication } from './StacProviderAuthentication'; +import { + StacProviderAuthenticationFromJSON, + StacProviderAuthenticationFromJSONTyped, + StacProviderAuthenticationToJSON, + StacProviderAuthenticationToJSONTyped, +} from './StacProviderAuthentication'; import type { TimeDimension } from './TimeDimension'; import { TimeDimensionFromJSON, @@ -88,6 +95,12 @@ export interface StacDataProviderDefinition { * @memberof StacDataProviderDefinition */ s3Config?: StacProviderS3Config | null; + /** + * + * @type {StacProviderAuthentication} + * @memberof StacDataProviderDefinition + */ + authentication?: StacProviderAuthentication | null; /** * * @type {TimeDimension} @@ -106,6 +119,12 @@ export interface StacDataProviderDefinition { * @memberof StacDataProviderDefinition */ queryTimeoutSecs?: number; + /** + * + * @type {number} + * @memberof StacDataProviderDefinition + */ + pageLimit?: number; } @@ -151,9 +170,11 @@ export function StacDataProviderDefinitionFromJSONTyped(json: any, ignoreDiscrim 'apiUrl': json['apiUrl'], 'collectionName': json['collectionName'], 's3Config': json['s3Config'] == null ? undefined : StacProviderS3ConfigFromJSON(json['s3Config']), + 'authentication': json['authentication'] == null ? undefined : StacProviderAuthenticationFromJSON(json['authentication']), 'timeDimension': TimeDimensionFromJSON(json['timeDimension']), 'datasets': ((json['datasets'] as Array).map(StacProviderDatasetFromJSON)), 'queryTimeoutSecs': json['queryTimeoutSecs'] == null ? undefined : json['queryTimeoutSecs'], + 'pageLimit': json['pageLimit'] == null ? undefined : json['pageLimit'], }; } @@ -176,9 +197,11 @@ export function StacDataProviderDefinitionToJSONTyped(value?: StacDataProviderDe 'apiUrl': value['apiUrl'], 'collectionName': value['collectionName'], 's3Config': StacProviderS3ConfigToJSON(value['s3Config']), + 'authentication': StacProviderAuthenticationToJSON(value['authentication']), 'timeDimension': TimeDimensionToJSON(value['timeDimension']), 'datasets': ((value['datasets'] as Array).map(StacProviderDatasetToJSON)), 'queryTimeoutSecs': value['queryTimeoutSecs'], + 'pageLimit': value['pageLimit'], }; } diff --git a/api-clients/typescript/src/models/StacProviderAuthentication.ts b/api-clients/typescript/src/models/StacProviderAuthentication.ts new file mode 100644 index 000000000..2a1305274 --- /dev/null +++ b/api-clients/typescript/src/models/StacProviderAuthentication.ts @@ -0,0 +1,85 @@ +/* tslint:disable */ +/* eslint-disable */ +/** + * Geo Engine API + * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator) + * + * Contact: dev@geoengine.de + * + * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). + * https://openapi-generator.tech + * Do not edit the class manually. + */ + +import { mapValues } from '../runtime'; +/** + * + * @export + * @interface StacProviderAuthentication + */ +export interface StacProviderAuthentication { + /** + * + * @type {string} + * @memberof StacProviderAuthentication + */ + endpoint: string; + /** + * + * @type {string} + * @memberof StacProviderAuthentication + */ + username: string; + /** + * A wrapper type that serializes to "*****" and can be deserialized from any string. + * If the inner value is "*****", it is considered unknown and `as_option` returns `None`. + * This is useful for secrets that should not be exposed in API responses, but can be set in API requests. + * @type {string} + * @memberof StacProviderAuthentication + */ + password: string; +} + +/** + * Check if a given object implements the StacProviderAuthentication interface. + */ +export function instanceOfStacProviderAuthentication(value: object): value is StacProviderAuthentication { + if (!('endpoint' in value) || value['endpoint'] === undefined) return false; + if (!('username' in value) || value['username'] === undefined) return false; + if (!('password' in value) || value['password'] === undefined) return false; + return true; +} + +export function StacProviderAuthenticationFromJSON(json: any): StacProviderAuthentication { + return StacProviderAuthenticationFromJSONTyped(json, false); +} + +export function StacProviderAuthenticationFromJSONTyped(json: any, ignoreDiscriminator: boolean): StacProviderAuthentication { + if (json == null) { + return json; + } + return { + + 'endpoint': json['endpoint'], + 'username': json['username'], + 'password': json['password'], + }; +} + +export function StacProviderAuthenticationToJSON(json: any): StacProviderAuthentication { + return StacProviderAuthenticationToJSONTyped(json, false); +} + +export function StacProviderAuthenticationToJSONTyped(value?: StacProviderAuthentication | null, ignoreDiscriminator: boolean = false): any { + if (value == null) { + return value; + } + + return { + + 'endpoint': value['endpoint'], + 'username': value['username'], + 'password': value['password'], + }; +} + diff --git a/api-clients/typescript/src/models/StacProviderDatasetBand.ts b/api-clients/typescript/src/models/StacProviderDatasetBand.ts index 4327ac5b5..364bfad2c 100644 --- a/api-clients/typescript/src/models/StacProviderDatasetBand.ts +++ b/api-clients/typescript/src/models/StacProviderDatasetBand.ts @@ -12,6 +12,21 @@ */ import { mapValues } from '../runtime'; +import type { StacAssetBand } from './StacAssetBand'; +import { + StacAssetBandFromJSON, + StacAssetBandFromJSONTyped, + StacAssetBandToJSON, + StacAssetBandToJSONTyped, +} from './StacAssetBand'; +import type { RasterBandDescriptor } from './RasterBandDescriptor'; +import { + RasterBandDescriptorFromJSON, + RasterBandDescriptorFromJSONTyped, + RasterBandDescriptorToJSON, + RasterBandDescriptorToJSONTyped, +} from './RasterBandDescriptor'; + /** * * @export @@ -19,24 +34,26 @@ import { mapValues } from '../runtime'; */ export interface StacProviderDatasetBand { /** - * - * @type {string} + * The band inside the STAC asset that this dataset band reads from + * (addressing: which asset file + which raster channel within it). + * @type {StacAssetBand} * @memberof StacProviderDatasetBand */ - assetTitle: string; + assetBand: StacAssetBand; /** - * - * @type {string} + * The band descriptor of the resulting geo engine dataset layer. + * @type {RasterBandDescriptor} * @memberof StacProviderDatasetBand */ - bandName?: string | null; + bandDescriptor: RasterBandDescriptor; } /** * Check if a given object implements the StacProviderDatasetBand interface. */ export function instanceOfStacProviderDatasetBand(value: object): value is StacProviderDatasetBand { - if (!('assetTitle' in value) || value['assetTitle'] === undefined) return false; + if (!('assetBand' in value) || value['assetBand'] === undefined) return false; + if (!('bandDescriptor' in value) || value['bandDescriptor'] === undefined) return false; return true; } @@ -50,8 +67,8 @@ export function StacProviderDatasetBandFromJSONTyped(json: any, ignoreDiscrimina } return { - 'assetTitle': json['assetTitle'], - 'bandName': json['bandName'] == null ? undefined : json['bandName'], + 'assetBand': StacAssetBandFromJSON(json['assetBand']), + 'bandDescriptor': RasterBandDescriptorFromJSON(json['bandDescriptor']), }; } @@ -66,8 +83,8 @@ export function StacProviderDatasetBandToJSONTyped(value?: StacProviderDatasetBa return { - 'assetTitle': value['assetTitle'], - 'bandName': value['bandName'], + 'assetBand': StacAssetBandToJSON(value['assetBand']), + 'bandDescriptor': RasterBandDescriptorToJSON(value['bandDescriptor']), }; } diff --git a/api-clients/typescript/src/models/index.ts b/api-clients/typescript/src/models/index.ts index 2a105e270..1ad128c79 100644 --- a/api-clients/typescript/src/models/index.ts +++ b/api-clients/typescript/src/models/index.ts @@ -260,7 +260,9 @@ export * from './SpatialPartition2D'; export * from './SpatialReferenceSpecification'; export * from './SpatialResolution'; export * from './StacApiRetries'; +export * from './StacAssetBand'; export * from './StacDataProviderDefinition'; +export * from './StacProviderAuthentication'; export * from './StacProviderDataset'; export * from './StacProviderDatasetBand'; export * from './StacProviderS3Config'; diff --git a/geoengine/services/src/api/model/services.rs b/geoengine/services/src/api/model/services.rs index 9e85e6a6e..ffecf009a 100644 --- a/geoengine/services/src/api/model/services.rs +++ b/geoengine/services/src/api/model/services.rs @@ -988,6 +988,38 @@ impl From for StacProvide } } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct StacProviderAuthentication { + pub endpoint: String, + pub username: String, + pub password: Secret, +} + +impl From + for crate::datasets::external::stac::StacProviderAuthentication +{ + fn from(value: StacProviderAuthentication) -> Self { + Self { + endpoint: value.endpoint, + username: value.username, + password: value.password.0, + } + } +} + +impl From + for StacProviderAuthentication +{ + fn from(value: crate::datasets::external::stac::StacProviderAuthentication) -> Self { + Self { + endpoint: value.endpoint, + username: value.username, + password: Secret(value.password), + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, ToSchema)] #[serde(rename_all = "camelCase")] pub struct StacAssetBand { @@ -1118,6 +1150,7 @@ pub struct StacDataProviderDefinition { pub api_url: String, pub collection_name: String, pub s3_config: Option, + pub authentication: Option, pub time_dimension: TimeDimension, pub datasets: Vec, /// Timeout in seconds for outgoing STAC API HTTP requests. @@ -1147,6 +1180,7 @@ impl From api_url: value.api_url, collection_name: value.collection_name, s3_config: value.s3_config.map(Into::into), + authentication: value.authentication.map(Into::into), time_dimension: value.time_dimension.into(), datasets: value.datasets.into_iter().map(Into::into).collect(), page_limit: value.page_limit, @@ -1168,6 +1202,7 @@ impl From api_url: value.api_url, collection_name: value.collection_name, s3_config: value.s3_config.map(Into::into), + authentication: value.authentication.map(Into::into), time_dimension: value.time_dimension.into(), datasets: value.datasets.into_iter().map(Into::into).collect(), page_limit: value.page_limit, @@ -1483,8 +1518,8 @@ impl TryIntoHeaderPair for ComputationId { #[cfg(test)] mod tests { use super::{ - SpatialResolution, StacDataProviderDefinition, StacProviderS3Config, - TypedDataProviderDefinition, + SpatialResolution, StacDataProviderDefinition, StacProviderAuthentication, + StacProviderS3Config, TypedDataProviderDefinition, }; use crate::api::model::services::SECRET_REPLACEMENT; use geoengine_datatypes::test_data; @@ -1540,4 +1575,25 @@ mod tests { }) ); } + + #[test] + fn stac_authentication_password_is_redacted_in_api_conversion() { + let internal = crate::datasets::external::stac::StacProviderAuthentication { + endpoint: "https://identity.example/token".to_owned(), + username: "test-user".to_owned(), + password: "test-password".to_owned(), + }; + + let api: StacProviderAuthentication = internal.into(); + let api_json = serde_json::to_value(&api).expect("api config must serialize to json"); + + assert_eq!( + api_json, + serde_json::json!({ + "endpoint": "https://identity.example/token", + "username": "test-user", + "password": SECRET_REPLACEMENT, + }) + ); + } } diff --git a/geoengine/services/src/cli/stac_harvester/discover.rs b/geoengine/services/src/cli/stac_harvester/discover.rs index d825ff744..6a1c1713f 100644 --- a/geoengine/services/src/cli/stac_harvester/discover.rs +++ b/geoengine/services/src/cli/stac_harvester/discover.rs @@ -201,6 +201,7 @@ pub(super) async fn discover_mapping(params: StacDiscoverMapping) -> Result<(), api_url: params.stac_url.clone(), collection_name: params.stac_collection.clone(), s3_config, + authentication: None, time_dimension, datasets, page_limit: params.page_limit as i64, diff --git a/geoengine/services/src/cli/stac_harvester/harvest.rs b/geoengine/services/src/cli/stac_harvester/harvest.rs index aa9ff2de3..7129a8722 100644 --- a/geoengine/services/src/cli/stac_harvester/harvest.rs +++ b/geoengine/services/src/cli/stac_harvester/harvest.rs @@ -1634,6 +1634,7 @@ mod tests { api_url: "https://earth-search.aws.element84.com/v0".to_string(), collection_name: "sentinel-2-l2a".to_string(), s3_config: None, + authentication: None, time_dimension: geoengine_datatypes::primitives::TimeDimension::Regular( geoengine_datatypes::primitives::RegularTimeDimension::new_with_epoch_origin( geoengine_datatypes::primitives::TimeStep { diff --git a/geoengine/services/src/contexts/migrations/current_schema.sql b/geoengine/services/src/contexts/migrations/current_schema.sql index 2834f97c0..2d0440c19 100644 --- a/geoengine/services/src/contexts/migrations/current_schema.sql +++ b/geoengine/services/src/contexts/migrations/current_schema.sql @@ -882,6 +882,12 @@ CREATE TYPE "StacProviderS3Config" AS ( secret_key text ); +CREATE TYPE "StacProviderAuthentication" AS ( + endpoint text, + username text, + password text +); + CREATE TYPE "StacAssetBand" AS ( asset_title text, band_name text @@ -913,7 +919,8 @@ CREATE TYPE "StacDataProviderDefinition" AS ( time_dimension "TimeDimension", datasets "StacProviderDataset" [], query_timeout_secs bigint, - page_limit bigint + page_limit bigint, + authentication "StacProviderAuthentication" ); CREATE TYPE "DataProviderDefinition" AS ( diff --git a/geoengine/services/src/contexts/migrations/migration_0030_stac_provider_authentication.rs b/geoengine/services/src/contexts/migrations/migration_0030_stac_provider_authentication.rs new file mode 100644 index 000000000..9680afbd8 --- /dev/null +++ b/geoengine/services/src/contexts/migrations/migration_0030_stac_provider_authentication.rs @@ -0,0 +1,30 @@ +use super::database_migration::{DatabaseVersion, Migration}; +use crate::{ + contexts::migrations::migration_0029_stac_provider_band_name::Migration0029StacProviderBandName, + error::Result, +}; +use async_trait::async_trait; +use tokio_postgres::Transaction; + +/// This migration adds optional OAuth password-grant authentication to STAC providers. +pub struct Migration0030StacProviderAuthentication; + +#[async_trait] +impl Migration for Migration0030StacProviderAuthentication { + fn prev_version(&self) -> Option { + Some(Migration0029StacProviderBandName.version()) + } + + fn version(&self) -> DatabaseVersion { + "0030_stac_provider_authentication".into() + } + + async fn migrate(&self, tx: &Transaction<'_>) -> Result<()> { + tx.batch_execute(include_str!( + "migration_0030_stac_provider_authentication.sql" + )) + .await?; + + Ok(()) + } +} diff --git a/geoengine/services/src/contexts/migrations/migration_0030_stac_provider_authentication.sql b/geoengine/services/src/contexts/migrations/migration_0030_stac_provider_authentication.sql new file mode 100644 index 000000000..b8db5044a --- /dev/null +++ b/geoengine/services/src/contexts/migrations/migration_0030_stac_provider_authentication.sql @@ -0,0 +1,8 @@ +CREATE TYPE "StacProviderAuthentication" AS ( + endpoint text, + username text, + password text +); + +ALTER TYPE "StacDataProviderDefinition" +ADD ATTRIBUTE authentication "StacProviderAuthentication"; diff --git a/geoengine/services/src/contexts/migrations/mod.rs b/geoengine/services/src/contexts/migrations/mod.rs index 400213eff..155f9d850 100644 --- a/geoengine/services/src/contexts/migrations/mod.rs +++ b/geoengine/services/src/contexts/migrations/mod.rs @@ -14,6 +14,7 @@ pub use crate::contexts::migrations::{ migration_0027_tile_z_index::Migration0027TileZIndex, migration_0028_stac_provider::Migration0028StacProvider, migration_0029_stac_provider_band_name::Migration0029StacProviderBandName, + migration_0030_stac_provider_authentication::Migration0030StacProviderAuthentication, }; pub use database_migration::{ DatabaseVersion, Migration, MigrationResult, initialize_database, migrate_database, @@ -35,6 +36,7 @@ mod migration_0026_gdal_tiles; mod migration_0027_tile_z_index; mod migration_0028_stac_provider; mod migration_0029_stac_provider_band_name; +mod migration_0030_stac_provider_authentication; #[cfg(test)] mod schema_info; @@ -70,6 +72,7 @@ pub fn all_migrations() -> Vec> { Box::new(Migration0027TileZIndex), Box::new(Migration0028StacProvider), Box::new(Migration0029StacProviderBandName), + Box::new(Migration0030StacProviderAuthentication), ] } diff --git a/geoengine/services/src/datasets/external/stac/auth.rs b/geoengine/services/src/datasets/external/stac/auth.rs new file mode 100644 index 000000000..47cd3580f --- /dev/null +++ b/geoengine/services/src/datasets/external/stac/auth.rs @@ -0,0 +1,172 @@ +use super::StacProviderAuthentication; +use crate::error::Result; +use reqwest::RequestBuilder; +use serde::{Deserialize, Serialize}; +use std::fmt; +use std::sync::{Arc, Weak}; +use std::time::Duration; +use tokio::sync::RwLock; +use tracing::{error, warn}; + +const CLIENT_ID: &str = "code-de3-public"; +const TOKEN_REFRESH_FACTOR: f64 = 0.8; +const TOKEN_REFRESH_RETRY_DELAY: Duration = Duration::from_secs(1); + +#[derive(Clone, Deserialize)] +struct TokenResponse { + access_token: String, + refresh_token: String, + expires_in: u64, + refresh_expires_in: u64, +} + +impl TokenResponse { + fn refresh_delay(&self) -> Duration { + let lifetime = self.expires_in.min(self.refresh_expires_in); + Duration::from_secs(lifetime) + .mul_f64(TOKEN_REFRESH_FACTOR) + .max(Duration::from_millis(100)) + } +} + +#[derive(Serialize)] +struct PasswordGrant<'a> { + grant_type: &'static str, + username: &'a str, + password: &'a str, + client_id: &'static str, +} + +#[derive(Serialize)] +struct RefreshTokenGrant<'a> { + grant_type: &'static str, + refresh_token: &'a str, + client_id: &'static str, +} + +/// Authentication state shared by the provider and all metadata instances it creates. +#[derive(Clone)] +pub(super) struct StacAuthentication { + tokens: Arc>, +} + +impl fmt::Debug for StacAuthentication { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter + .debug_struct("StacAuthentication") + .finish_non_exhaustive() + } +} + +impl StacAuthentication { + pub async fn initialize( + client: reqwest::Client, + config: StacProviderAuthentication, + ) -> Result { + let tokens = request_password_tokens(&client, &config).await?; + let tokens = Arc::new(RwLock::new(tokens)); + + tokio::spawn(refresh_tokens(client, config, Arc::downgrade(&tokens))); + + Ok(Self { tokens }) + } + + pub(super) async fn access_token(&self) -> String { + self.tokens.read().await.access_token.clone() + } + + pub async fn authorize(&self, request: RequestBuilder) -> RequestBuilder { + let access_token = self.access_token().await; + request.bearer_auth(access_token) + } +} + +async fn request_password_tokens( + client: &reqwest::Client, + config: &StacProviderAuthentication, +) -> Result { + Ok(client + .post(&config.endpoint) + .form(&PasswordGrant { + grant_type: "password", + username: &config.username, + password: &config.password, + client_id: CLIENT_ID, + }) + .send() + .await? + .error_for_status()? + .json() + .await?) +} + +async fn request_refreshed_tokens( + client: &reqwest::Client, + config: &StacProviderAuthentication, + refresh_token: &str, +) -> Result { + Ok(client + .post(&config.endpoint) + .form(&RefreshTokenGrant { + grant_type: "refresh_token", + refresh_token, + client_id: CLIENT_ID, + }) + .send() + .await? + .error_for_status()? + .json() + .await?) +} + +async fn refresh_tokens( + client: reqwest::Client, + config: StacProviderAuthentication, + tokens: Weak>, +) { + let Some(initial_tokens) = tokens.upgrade() else { + return; + }; + let mut refresh_delay = initial_tokens.read().await.refresh_delay(); + drop(initial_tokens); + + loop { + tokio::time::sleep(refresh_delay).await; + + let Some(current_tokens) = tokens.upgrade() else { + return; + }; + + let refresh_token = current_tokens.read().await.refresh_token.clone(); + drop(current_tokens); + + let refreshed_tokens = + match request_refreshed_tokens(&client, &config, &refresh_token).await { + Ok(tokens) => tokens, + Err(refresh_error) => { + warn!( + error = %refresh_error, + "refreshing STAC authentication tokens failed; trying password grant" + ); + + match request_password_tokens(&client, &config).await { + Ok(tokens) => tokens, + Err(password_error) => { + error!( + error = %password_error, + "renewing STAC authentication tokens failed" + ); + refresh_delay = TOKEN_REFRESH_RETRY_DELAY; + continue; + } + } + } + }; + + let Some(current_tokens) = tokens.upgrade() else { + return; + }; + refresh_delay = refreshed_tokens.refresh_delay(); + *current_tokens.write().await = refreshed_tokens; + } +} diff --git a/geoengine/services/src/datasets/external/stac/loading_info.rs b/geoengine/services/src/datasets/external/stac/loading_info.rs index ac3dabf88..2aa89500d 100644 --- a/geoengine/services/src/datasets/external/stac/loading_info.rs +++ b/geoengine/services/src/datasets/external/stac/loading_info.rs @@ -1,5 +1,8 @@ use super::common; -use super::{StacDataProvider, StacProviderDataset, StacProviderS3Config, cache::StacQueryCache}; +use super::{ + StacDataProvider, StacProviderDataset, StacProviderS3Config, auth::StacAuthentication, + cache::StacQueryCache, +}; use crate::error::Result; use crate::util::join_base_url_and_path; use crate::util::retry::{RetryPolicy, retry_http}; @@ -41,6 +44,7 @@ struct StacMultiBandMetaData { dataset: StacProviderDataset, page_limit: i64, client: reqwest::Client, + authentication: Option, /// Shared query-result cache from the provider. query_cache: Arc, } @@ -59,6 +63,7 @@ enum StacQueryState { async fn query_stac_item_collection( client: &reqwest::Client, + authentication: Option<&StacAuthentication>, query_state: &StacQueryState, ) -> geoengine_operators::util::Result<(stac::ItemCollection, StacQueryState)> { let request_policy = RetryPolicy::new().stop_on_status(&[400, 404]); @@ -74,14 +79,13 @@ async fn query_stac_item_collection( let item_collection: stac::ItemCollection = retry_http( || async { - client - .get(query_url.clone()) - .query(query_params) - .send() - .await? - .error_for_status()? - .json() - .await + let request = client.get(query_url.clone()).query(query_params); + let request = match authentication { + Some(authentication) => authentication.authorize(request).await, + None => request, + }; + + request.send().await?.error_for_status()?.json().await }, &format!("Fetch STAC items from {query_url}"), &request_policy, @@ -117,13 +121,13 @@ async fn query_stac_item_collection( let item_collection: stac::ItemCollection = retry_http( || async { - client - .get(next_url.clone()) - .send() - .await? - .error_for_status()? - .json() - .await + let request = client.get(next_url.clone()); + let request = match authentication { + Some(authentication) => authentication.authorize(request).await, + None => request, + }; + + request.send().await?.error_for_status()?.json().await }, &format!("Fetch next STAC page from {next_url}"), &request_policy, @@ -213,8 +217,12 @@ impl let mut time_steps = Vec::new(); while !matches!(query_state, StacQueryState::Finished) { - let (item_collection, next_state) = - query_stac_item_collection(&self.client, &query_state).await?; + let (item_collection, next_state) = query_stac_item_collection( + &self.client, + self.authentication.as_ref(), + &query_state, + ) + .await?; for item in item_collection.items { self.process_stac_item(&item, &mut time_steps, &mut files) @@ -643,6 +651,7 @@ impl dataset: dataset.clone(), page_limit: self.page_limit, client: self.client.clone(), + authentication: self.authentication.clone(), query_cache: self.query_cache.clone(), })) } @@ -672,7 +681,12 @@ mod tests { use geoengine_operators::source::{ MultiBandGdalLoadingInfo, MultiBandGdalLoadingInfoQueryRectangle, }; - use httptest::{Expectation, Server, matchers::request, responders}; + use httptest::{ + Expectation, Server, all_of, + matchers::{contains, request, url_decoded}, + responders, + }; + use std::time::Duration; use tokio_postgres::NoTls; fn make_stac_provider_def( @@ -687,6 +701,7 @@ mod tests { api_url, collection_name: "sentinel-2-l2a".to_owned(), s3_config: None, + authentication: None, time_dimension: TimeDimension::Regular(RegularTimeDimension::new_with_epoch_origin( TimeStep { granularity: TimeGranularity::Days, @@ -732,6 +747,159 @@ mod tests { serde_json::from_str(json_str).expect("code-de-marburg.json should be valid JSON") } + fn token_response( + access_token: &str, + refresh_token: &str, + expires_in: u64, + refresh_expires_in: u64, + ) -> serde_json::Value { + serde_json::json!({ + "access_token": access_token, + "refresh_token": refresh_token, + "expires_in": expires_in, + "refresh_expires_in": refresh_expires_in, + "token_type": "Bearer", + }) + } + + #[tokio::test] + #[allow(clippy::too_many_lines)] + async fn authenticated_stac_requests_use_and_refresh_tokens() { + let server = Server::run(); + + server.expect( + Expectation::matching(all_of![ + request::method_path("POST", "/token"), + request::headers(contains(( + "content-type", + "application/x-www-form-urlencoded" + ))), + request::body(url_decoded(all_of![ + contains(("grant_type", "password")), + contains(("username", "test-user")), + contains(("password", "test-password")), + contains(("client_id", "code-de3-public")), + ])), + ]) + .times(1) + .respond_with(responders::json_encoded(token_response( + "access-token-1", + "refresh-token-1", + 1, + 1, + ))), + ); + + server.expect( + Expectation::matching(all_of![ + request::method_path("POST", "/token"), + request::body(url_decoded(all_of![ + contains(("grant_type", "refresh_token")), + contains(("refresh_token", "refresh-token-1")), + contains(("client_id", "code-de3-public")), + ])), + ]) + .times(1) + .respond_with(responders::json_encoded(token_response( + "access-token-2", + "refresh-token-2", + 1, + 1, + ))), + ); + + server.expect( + Expectation::matching(all_of![ + request::method_path("POST", "/token"), + request::body(url_decoded(all_of![ + contains(("grant_type", "refresh_token")), + contains(("refresh_token", "refresh-token-2")), + contains(("client_id", "code-de3-public")), + ])), + ]) + .times(1) + .respond_with(responders::json_encoded(token_response( + "access-token-3", + "refresh-token-3", + 3_600, + 7_200, + ))), + ); + + server.expect( + Expectation::matching(all_of![ + request::method_path("GET", "/initial-items"), + request::headers(contains(("authorization", "Bearer access-token-1"))), + ]) + .times(1) + .respond_with(responders::json_encoded(stac_items_response())), + ); + + server.expect( + Expectation::matching(all_of![ + request::method_path("GET", "/next-items"), + request::headers(contains(("authorization", "Bearer access-token-1"))), + ]) + .times(1) + .respond_with(responders::json_encoded(stac_items_response())), + ); + + server.expect( + Expectation::matching(all_of![ + request::method_path("GET", "/refreshed-items"), + request::headers(contains(("authorization", "Bearer access-token-3"))), + ]) + .times(1) + .respond_with(responders::json_encoded(stac_items_response())), + ); + + let client = reqwest::Client::new(); + let authentication = StacAuthentication::initialize( + client.clone(), + crate::datasets::external::stac::StacProviderAuthentication { + endpoint: server.url_str("/token"), + username: "test-user".to_owned(), + password: "test-password".to_owned(), + }, + ) + .await + .expect("initial password grant should succeed"); + + let initial_query = StacQueryState::FirstPage { + query_url: Url::parse(&server.url_str("/initial-items")).unwrap(), + query_params: vec![], + }; + query_stac_item_collection(&client, Some(&authentication), &initial_query) + .await + .expect("initial authenticated STAC request should succeed"); + + let next_page_query = StacQueryState::NextPage { + next_url: Url::parse(&server.url_str("/next-items")).unwrap(), + }; + query_stac_item_collection(&client, Some(&authentication), &next_page_query) + .await + .expect("authenticated STAC pagination request should succeed"); + + tokio::time::timeout(Duration::from_secs(4), async { + loop { + if authentication.access_token().await == "access-token-3" { + break; + } + tokio::time::sleep(Duration::from_millis(25)).await; + } + }) + .await + .expect("both access and refresh tokens should rotate before they expire"); + + let refreshed_query = StacQueryState::FirstPage { + query_url: Url::parse(&server.url_str("/refreshed-items")).unwrap(), + query_params: vec![], + }; + query_stac_item_collection(&client, Some(&authentication), &refreshed_query) + .await + .expect("refreshed authenticated STAC request should succeed"); + } + /// Replicates the steps from `test_ndvi.http` without making real web requests: #[crate::ge_context::test] #[allow(clippy::too_many_lines)] @@ -888,6 +1056,7 @@ mod tests { api_url: server.url_str("/"), collection_name: "sentinel-2-l2a".to_owned(), s3_config: None, + authentication: None, time_dimension: TimeDimension::Regular(RegularTimeDimension::new_with_epoch_origin( TimeStep { granularity: TimeGranularity::Days, diff --git a/geoengine/services/src/datasets/external/stac/mod.rs b/geoengine/services/src/datasets/external/stac/mod.rs index a794ccfcb..937ff36a9 100644 --- a/geoengine/services/src/datasets/external/stac/mod.rs +++ b/geoengine/services/src/datasets/external/stac/mod.rs @@ -13,6 +13,7 @@ use postgres_types::{FromSql, ToSql}; use serde::{Deserialize, Serialize}; use std::sync::Arc; +mod auth; mod cache; pub(crate) mod common; mod listing; @@ -32,6 +33,7 @@ pub struct StacDataProviderDefinition { pub api_url: String, pub collection_name: String, pub s3_config: Option, + pub authentication: Option, pub time_dimension: TimeDimension, // TODO: should this be on dataset level? pub datasets: Vec, /// Timeout in seconds for outgoing STAC API HTTP requests. @@ -57,6 +59,14 @@ pub struct StacProviderS3Config { pub secret_key: Option, } +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, ToSql, FromSql)] +#[postgres(name = "StacProviderAuthentication")] +pub struct StacProviderAuthentication { + pub endpoint: String, + pub username: String, + pub password: String, +} + /// A geo engine dataset derived from a STAC collection. /// As all bands and tiles of a geo engine data set must have the same data type, resolution and projection, /// a stac collection will be split into multiple geo engine datasets if it contains bands with different data types, resolutions or projections. @@ -140,7 +150,7 @@ impl DataProviderDefinition for StacDataProviderDefinition { if self.time_dimension == TimeDimension::Irregular { return Err(crate::error::Error::StacIrregularTimeDimensionNotSupported); } - Ok(Box::new(StacDataProvider::new( + let mut provider = StacDataProvider::new( self.id, self.name, self.description, @@ -151,7 +161,16 @@ impl DataProviderDefinition for StacDataProviderDefinition { self.datasets, self.page_limit, self.query_timeout_secs, - ))) + ); + + if let Some(authentication) = self.authentication { + provider.authentication = Some( + auth::StacAuthentication::initialize(provider.client.clone(), authentication) + .await?, + ); + } + + Ok(Box::new(provider)) } fn type_name(&self) -> &'static str { @@ -189,6 +208,15 @@ impl DataProviderDefinition for StacDataProviderDefinition { } } + if let (Some(current_authentication), Some(new_authentication)) = + (&self.authentication, &mut new.authentication) + && new_authentication.password == SECRET_REPLACEMENT + { + new_authentication + .password + .clone_from(¤t_authentication.password); + } + TypedDataProviderDefinition::StacDataProviderDefinition(new) } _ => new, @@ -209,6 +237,7 @@ pub struct StacDataProvider { page_limit: i64, /// Shared HTTP client, reused across all requests for this provider. client: reqwest::Client, + authentication: Option, /// In-memory cache for STAC query results (tile files), keyed by dataset /// name and spatial/temporal query bounds. query_cache: Arc, @@ -243,6 +272,7 @@ impl StacDataProvider { datasets, page_limit, client, + authentication: None, query_cache: Arc::new(StacQueryCache::default()), } } diff --git a/openapi.json b/openapi.json index c2f6b928e..d447a4fc2 100644 --- a/openapi.json +++ b/openapi.json @@ -12331,6 +12331,16 @@ } ] }, + "authentication": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/components/schemas/StacProviderAuthentication" + } + ] + }, "timeDimension": { "$ref": "#/components/schemas/TimeDimension" }, @@ -12351,6 +12361,25 @@ } } }, + "StacProviderAuthentication": { + "type": "object", + "required": [ + "endpoint", + "username", + "password" + ], + "properties": { + "endpoint": { + "type": "string" + }, + "username": { + "type": "string" + }, + "password": { + "$ref": "#/components/schemas/Secret_String" + } + } + }, "StacProviderDataset": { "type": "object", "required": [