From 2f650db27f4b0ca58f4c9b0f166a7fbcddd4d9d0 Mon Sep 17 00:00:00 2001 From: Mohamed Abdel Wedoud Date: Wed, 21 Feb 2024 17:20:01 +0100 Subject: [PATCH] feat(study-search): add a studies counting endpoint --- antarest/study/service.py | 16 ++++ antarest/study/web/studies_blueprint.py | 102 ++++++++++++++++++------ 2 files changed, 94 insertions(+), 24 deletions(-) diff --git a/antarest/study/service.py b/antarest/study/service.py index 81af28a473..dc3288b4e2 100644 --- a/antarest/study/service.py +++ b/antarest/study/service.py @@ -478,6 +478,22 @@ def get_studies_information( studies[study_metadata.id] = study_metadata return studies + def count_studies( + self, + study_filter: StudyFilter, + ) -> int: + """ + Get number of matching studies. + Args: + study_filter: filtering parameters + + Returns: total number of studies matching the filtering criteria + """ + total: int = self.repository.count_studies( + study_filter=study_filter, + ) + return total + def _try_get_studies_information(self, study: Study) -> t.Optional[StudyMetadataDTO]: try: return self.storage_service.get_storage(study).get_study_information(study) diff --git a/antarest/study/web/studies_blueprint.py b/antarest/study/web/studies_blueprint.py index 9007ed2894..6565538281 100644 --- a/antarest/study/web/studies_blueprint.py +++ b/antarest/study/web/studies_blueprint.py @@ -34,6 +34,8 @@ logger = logging.getLogger(__name__) +QUERY_REGEX = r"^\s*(?:\d+\s*(?:,\s*\d+\s*)*)?$" + def _split_comma_separated_values(value: str, *, default: t.Sequence[str] = ()) -> t.Sequence[str]: """Split a comma-separated list of values into an ordered set of strings.""" @@ -76,23 +78,11 @@ def get_studies( managed: t.Optional[bool] = Query(None, description="Filter studies based on their management status."), archived: t.Optional[bool] = Query(None, description="Filter studies based on their archive status."), variant: t.Optional[bool] = Query(None, description="Filter studies based on their variant status."), - versions: str = Query( - "", - description="Comma-separated list of versions for filtering.", - regex=r"^\s*(?:\d+\s*(?:,\s*\d+\s*)*)?$", - ), - users: str = Query( - "", - description="Comma-separated list of user IDs for filtering.", - regex=r"^\s*(?:\d+\s*(?:,\s*\d+\s*)*)?$", - ), + versions: str = Query("", description="Comma-separated list of versions for filtering.", regex=QUERY_REGEX), + users: str = Query("", description="Comma-separated list of user IDs for filtering.", regex=QUERY_REGEX), groups: str = Query("", description="Comma-separated list of group IDs for filtering."), tags: str = Query("", description="Comma-separated list of tags for filtering."), - study_ids: str = Query( - "", - description="Comma-separated list of study IDs for filtering.", - alias="studyIds", - ), + study_ids: str = Query("", description="Comma-separated list of study IDs for filtering.", alias="studyIds"), exists: t.Optional[bool] = Query(None, description="Filter studies based on their existence on disk."), workspace: str = Query("", description="Filter studies based on their workspace."), folder: str = Query("", description="Filter studies based on their folder."), @@ -102,23 +92,17 @@ def get_studies( description="Sort studies based on their name (case-insensitive) or creation date.", alias="sortBy", ), - page_nb: NonNegativeInt = Query( - 0, - description="Page number (starting from 0).", - alias="pageNb", - ), + page_nb: NonNegativeInt = Query(0, description="Page number (starting from 0).", alias="pageNb"), page_size: NonNegativeInt = Query( - 0, - description="Number of studies per page (0 = no limit).", - alias="pageSize", + 0, description="Number of studies per page (0 = no limit).", alias="pageSize" ), ) -> t.Dict[str, StudyMetadataDTO]: """ Get the list of studies matching the specified criteria. Args: + - `name`: Filter studies based on their name. Case-insensitive search for studies - whose name contains the specified value. - `managed`: Filter studies based on their management status. - `archived`: Filter studies based on their archive status. - `variant`: Filter studies based on their variant status. @@ -171,6 +155,76 @@ def get_studies( return matching_studies + @bp.get( + "/studies/count", + tags=[APITag.study_management], + summary="Count Studies", + ) + def count_studies( + current_user: JWTUser = Depends(auth.get_current_user), + name: str = Query("", description="Case-insensitive: filter studies based on their name.", alias="name"), + managed: t.Optional[bool] = Query(None, description="Management status filter."), + archived: t.Optional[bool] = Query(None, description="Archive status filter."), + variant: t.Optional[bool] = Query(None, description="Variant status filter."), + versions: str = Query("", description="Comma-separated versions filter.", regex=QUERY_REGEX), + users: str = Query("", description="Comma-separated user IDs filter.", regex=QUERY_REGEX), + groups: str = Query("", description="Comma-separated group IDs filter."), + tags: str = Query("", description="Comma-separated tags filter."), + study_ids: str = Query("", description="Comma-separated study IDs filter.", alias="studyIds"), + exists: t.Optional[bool] = Query(None, description="Existence on disk filter."), + workspace: str = Query("", description="Workspace filter."), + folder: str = Query("", description="Study folder filter."), + ) -> int: + """ + Get the number of studies matching the specified criteria. + + Args: + + - `name`: Regexp to filter through studies based on their names + - `managed`: Whether to limit the selection based on management status. + - `archived`: Whether to limit the selection based on archive status. + - `variant`: Whether to limit the selection either raw or variant studies. + - `versions`: Comma-separated versions for studies to be selected. + - `users`: Comma-separated user IDs for studies to be selected. + - `groups`: Comma-separated group IDs for studies to be selected. + - `tags`: Comma-separated tags for studies to be selected. + - `studyIds`: Comma-separated IDs of studies to be selected. + - `exists`: Whether to limit the selection based on studies' existence on disk. + - `workspace`: to limit studies selection based on their workspace. + - `folder`: to limit studies selection based on their folder. + + Returns: + - An integer representing the total number of studies matching the filters above and the user permissions. + """ + + logger.info("Counting matching studies", extra={"user": current_user.id}) + params = RequestParameters(user=current_user) + + user_list = [int(v) for v in _split_comma_separated_values(users)] + + if not params.user: + raise UserHasNotPermissionError("FAIL permission: user is not logged") + + count = study_service.count_studies( + study_filter=StudyFilter( + name=name, + managed=managed, + archived=archived, + variant=variant, + versions=_split_comma_separated_values(versions), + users=user_list, + groups=_split_comma_separated_values(groups), + tags=_split_comma_separated_values(tags), + study_ids=_split_comma_separated_values(study_ids), + exists=exists, + workspace=workspace, + folder=folder, + access_permissions=AccessPermissions.from_params(params), + ), + ) + + return count + @bp.get( "/studies/{uuid}/comments", tags=[APITag.study_management],