diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 278532a32483..0fa8cf0bc68e 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -9576,9 +9576,11 @@ export interface components { UserDeletionPayload: { /** * Purge user - * @description Purge the user + * @deprecated + * @description Purge the user. Deprecated, please use the `purge` query parameter instead. + * @default false */ - purge: boolean; + purge?: boolean; }; /** UserEmail */ UserEmail: { @@ -18633,6 +18635,10 @@ export interface operations { delete_user_api_users__user_id__delete: { /** Delete a user. Only admins can delete others or purge users. */ parameters: { + /** @description Whether to definitely remove this user. Only deleted users can be purged. */ + query?: { + purge?: boolean; + }; /** @description The user ID that will be used to effectively make this API call. Only admins and designated users can make API calls on behalf of other users. */ header?: { "run-as"?: string; diff --git a/lib/galaxy/managers/users.py b/lib/galaxy/managers/users.py index ee9b05c3ac78..0600feb36275 100644 --- a/lib/galaxy/managers/users.py +++ b/lib/galaxy/managers/users.py @@ -227,9 +227,10 @@ def purge(self, user, flush=True): if self.app.config.redact_email_during_deletion: role.name = role.name.replace(user.email, email_hash) role.description = role.description.replace(user.email, email_hash) - private_role.name = email_hash - private_role.description = f"Private Role for {email_hash}" - self.session().add(private_role) + self.session().add(role) + private_role.name = email_hash + private_role.description = f"Private Role for {email_hash}" + self.session().add(private_role) # Redact user's email and username user.email = email_hash user.username = uname_hash diff --git a/lib/galaxy/schema/schema.py b/lib/galaxy/schema/schema.py index 6920fe5dbb94..95e8bcb7b931 100644 --- a/lib/galaxy/schema/schema.py +++ b/lib/galaxy/schema/schema.py @@ -351,7 +351,12 @@ class RemoteUserCreationPayload(Model): class UserDeletionPayload(Model): - purge: bool = Field(default=Required, title="Purge user", description="Purge the user") + purge: bool = Field( + default=False, + title="Purge user", + description="Purge the user. Deprecated, please use the `purge` query parameter instead.", + deprecated=True, + ) class FavoriteObject(Model): diff --git a/lib/galaxy/tool_util/verify/interactor.py b/lib/galaxy/tool_util/verify/interactor.py index 94cdb25a8efd..5aef947c72ba 100644 --- a/lib/galaxy/tool_util/verify/interactor.py +++ b/lib/galaxy/tool_util/verify/interactor.py @@ -938,10 +938,10 @@ def _post( kwd["timeout"] = kwd.pop("timeout", util.DEFAULT_SOCKET_TIMEOUT) return requests.post(url, **kwd) - def _delete(self, path, data=None, key=None, headers=None, admin=False, anon=False, json=False): + def _delete(self, path, data=None, key=None, headers=None, admin=False, anon=False, json=False, params=None): headers = self.api_key_header(key=key, admin=admin, anon=anon, headers=headers) url = self.get_api_url(path) - kwd = self._prepare_request_params(data=data, as_json=json, headers=headers) + kwd = self._prepare_request_params(data=data, as_json=json, params=params, headers=headers) kwd["timeout"] = kwd.pop("timeout", util.DEFAULT_SOCKET_TIMEOUT) return requests.delete(url, **kwd) diff --git a/lib/galaxy/webapps/galaxy/api/users.py b/lib/galaxy/webapps/galaxy/api/users.py index 917e4955bdaa..ee9608cf088f 100644 --- a/lib/galaxy/webapps/galaxy/api/users.py +++ b/lib/galaxy/webapps/galaxy/api/users.py @@ -22,6 +22,7 @@ ) from markupsafe import escape from pydantic import Required +from typing_extensions import Annotated from galaxy import ( exceptions, @@ -135,7 +136,6 @@ }, } -UserDeletionBody = Body(default=None, title="Purge user", description="Purge the user.") UserUpdateBody = Body(default=Required, title="Update user", description="The user values to update.") FavoriteObjectBody = Body( default=Required, title="Set favorite", description="The id of an object the user wants to favorite." @@ -656,13 +656,17 @@ def delete( self, trans: ProvidesUserContext = DependsOnTrans, user_id: DecodedDatabaseIdField = UserIdPathParamQueryParam, - payload: Optional[UserDeletionPayload] = UserDeletionBody, + purge: Annotated[ + bool, + Query( + title="Purge user", + description="Whether to definitely remove this user. Only deleted users can be purged.", + ), + ] = False, + payload: Optional[UserDeletionPayload] = None, ) -> DetailedUserModel: user_to_update = self.service.user_manager.by_id(user_id) - if payload: - purge = payload.purge - else: - purge = False + purge = payload and payload.purge or purge if trans.user_is_admin: if purge: log.debug("Purging user %s", user_to_update) diff --git a/lib/galaxy_test/api/test_users.py b/lib/galaxy_test/api/test_users.py index a92e13769a8e..d1c3a4e05904 100644 --- a/lib/galaxy_test/api/test_users.py +++ b/lib/galaxy_test/api/test_users.py @@ -108,11 +108,11 @@ def test_purge_user(self): user = self._setup_user(TEST_USER_EMAIL_PURGE) response = self._delete(f"users/{user['id']}", admin=True) self._assert_status_code_is_ok(response) - data = dict(purge="True") - response = self._delete(f"users/{user['id']}", data=data, admin=True, json=True) + params = dict(purge="True") + response = self._delete(f"users/{user['id']}", params=params, admin=True, json=True) self._assert_status_code_is_ok(response) - payload = {"deleted": "True"} - purged_user = self._get(f"users/{user['id']}", payload, admin=True).json() + params = {"deleted": "True"} + purged_user = self._get(f"users/{user['id']}", params, admin=True).json() assert purged_user["deleted"] is True, purged_user assert purged_user["purged"] is True, purged_user