Skip to content

Commit eb8bdc5

Browse files
authored
Merge pull request #1010 from RS-PYTHON/feat/rspy-564-limit-the-limit
RSPY 564: limit the limit
2 parents 954719a + bb80c92 commit eb8bdc5

File tree

3 files changed

+58
-23
lines changed

3 files changed

+58
-23
lines changed

services/cadip/rs_server_cadip/api/cadip_search.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ def process_session_search( # type: ignore # pylint: disable=too-many-arguments
474474
sortby: str,
475475
limit: Annotated[
476476
Union[int, None],
477-
Query(gt=0, le=10000, default=1000, description="Pagination Limit"),
477+
Query(gt=0, default=100, description="Pagination Limit"),
478478
],
479479
page: Union[int, None] = 1,
480480
) -> stac_pydantic.ItemCollection:
@@ -487,7 +487,7 @@ def process_session_search( # type: ignore # pylint: disable=too-many-arguments
487487
request (Request): The request object (unused).
488488
station (str): CADIP station identifier (e.g., MTI, SGS, MPU, INU).
489489
queryables: Lists of queryables applicable to search op.
490-
limit (int, optional): Maximum number of products to return. Beetween 0 and 10000, defaults to 1000.
490+
limit (int, optional): Maximum number of products to return. Greater than 0, defaults to 100.
491491
sortby (str): Sort by +/-fieldName (ascending/descending).
492492
page (int): Page number to be displayed, defaults to first one.
493493
Returns:

services/common/rs_server_common/data_retrieval/eodag_provider.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -116,30 +116,32 @@ def __init__(self, config_file: Path, provider: str): # type: ignore
116116

117117
def _specific_search(self, **kwargs) -> Union[SearchResult, List]:
118118
"""
119-
Conducts a search for products within a specified time range.
119+
Conducts a search for products using the specified OData arguments.
120120
121-
This private method interfaces with the client's search functionality,
122-
retrieving products that fall within the given time range. The 'between'
123-
parameter is expected to be a TimeRange object, encompassing start and end
124-
timestamps. The method returns a dictionary of products keyed by their
125-
respective identifiers.
121+
This private method interfaces with the EODAG client's search functionality
122+
to retrieve products that match the given search parameters. It handles
123+
special cases such as `PublicationDate` and session ID lists while enforcing
124+
pagination constraints as per provider limitations.
126125
127126
Args:
128-
date_time: An object representing search datetime, can be fixed or open/closed interval.
127+
**kwargs: Arbitrary keyword arguments specifying search parameters,
128+
including all queryables defined in the provider's configuration as OData arguments.
129129
130130
Returns:
131-
SearchResult: A dictionary where keys are product identifiers and
132-
values are EOProduct instances.
133-
134-
Note:
135-
The time format of the 'between' parameter should be verified or formatted
136-
appropriately before invoking this method. The method also assumes that the
137-
client's search function is correctly set up to handle the provided time
138-
range format.
131+
Union[SearchResult, List]: A `SearchResult` object containing the matched products
132+
or an empty list if no matches are found.
139133
140134
Raises:
141-
Exception: If the search encounters an error or fails, an exception is raised.
135+
HTTPException: If a validation error occurs in the search query.
136+
SearchProductFailed: If the search request fails due to request errors,
137+
misconfiguration, or authentication issues.
138+
ValueError: If authentication with EODAG fails.
139+
140+
Notes:
141+
- Ensures compliance with provider-specific constraints, such as pagination limits.
142+
- Logs encountered errors and provides detailed messages in case of failures.
142143
"""
144+
143145
mapped_search_args: Dict[str, Union[str, None]] = {}
144146
if session_id := kwargs.pop("SessionId", None):
145147
# Map session_id to the appropriate eodag parameter
@@ -157,11 +159,6 @@ def _specific_search(self, **kwargs) -> Union[SearchResult, List]:
157159
value = ", ".join(f"'{p}'" for p in platform) if isinstance(platform, list) else f"'{platform}'"
158160
mapped_search_args[key] = value
159161

160-
# TODO: check if it is the right way of doing this, looks very cumbersome to do it for every field
161-
# Tempfix, will be updated, to dirrectly, to verify kwargs and then forward to search.
162-
if retransfer := kwargs.pop("retransfer", None):
163-
mapped_search_args["Retransfer"] = str(retransfer).lower()
164-
165162
if date_time := kwargs.pop("PublicationDate", False):
166163
# Since now both for files and sessions, time interval is optional, map it if provided.
167164
fixed, start, end = [str(date) if date else None for date in date_time]
@@ -172,6 +169,14 @@ def _specific_search(self, **kwargs) -> Union[SearchResult, List]:
172169
"StopPublicationDate": end,
173170
},
174171
)
172+
max_items_allowed = int(self.client.providers_config[self.provider].search.pagination["max_items_per_page"])
173+
if int(kwargs["items_per_page"]) > max_items_allowed:
174+
logger.warning(
175+
f"Requesting {kwargs['items_per_page']} exceeds maximum of {max_items_allowed} "
176+
"allowed for this provider!",
177+
)
178+
logger.warning(f"Number of items per page was set to {max_items_allowed - 1}.")
179+
kwargs["items_per_page"] = max_items_allowed - 1
175180
try:
176181
logger.info(f"Searching from {self.provider} with parameters {mapped_search_args}")
177182
# Start search -> user defined search params in mapped_search_args (id), pagination in kwargs (top, limit).

tests/test_search_endpoint.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -903,6 +903,36 @@ def test_invalid_limit_values(self, client, endpoint):
903903
"Input should be greater than 0",
904904
)
905905

906+
@pytest.mark.unit
907+
@pytest.mark.parametrize(
908+
"endpoint, odata",
909+
[
910+
(
911+
"/auxip/collections/s2_adgs2_AUX_OBMEMC/items?limit=10000000",
912+
"http://127.0.0.1:5001/Products?$filter=Attributes/OData.CSC.StringAttribute/any(att:att/Name eq "
913+
"'productType' and att/OData.CSC.StringAttribute/Value eq 'AUX_OBMEMC')&$orderby=PublicationDate "
914+
"desc&$top=9999&$skip=0&$expand=Attributes",
915+
),
916+
(
917+
"/cadip/collections/cadip_session_by_id/items?limit=10000000",
918+
"http://127.0.0.1:5000/Sessions?$filter=SessionId eq 'S1A_20200105072204051312'&$orderby="
919+
"PublicationDate desc&$top=9999&$skip=0",
920+
),
921+
],
922+
)
923+
@responses.activate
924+
def test_bigger_limit_than_allowed(self, client, mock_token_validation, endpoint, odata):
925+
"""
926+
Test that if user request with a limit value bigger than max allowed in config
927+
the limit value is set to max_allowed - 1.
928+
Limit in request is set to 1_000_000, for given collection max allowed is set to 10000, therefore
929+
in the final odata request, $top is set to 9999.
930+
"""
931+
mock_token_validation()
932+
responses.add(responses.GET, odata, json={"value": []}, status=200)
933+
response = client.get(endpoint)
934+
assert response.status_code == status.HTTP_200_OK
935+
906936
@pytest.mark.unit
907937
@pytest.mark.parametrize(
908938
"endpoint",

0 commit comments

Comments
 (0)