diff --git a/atlassian/confluence/cloud/__init__.py b/atlassian/confluence/cloud/__init__.py index afad9f4d0..2fa60c111 100644 --- a/atlassian/confluence/cloud/__init__.py +++ b/atlassian/confluence/cloud/__init__.py @@ -647,6 +647,33 @@ def get_user(self, user_id, **kwargs): params = {**(kwargs.pop("params", None) or {}), "accountId": user_id} return self.get("rest/api/user", params=params, **kwargs) + def get_user_details_by_accountid(self, accountid, expand=None): + """ + Get information about a user through account ID. + + :param accountid: the user's account ID + :param expand: OPTIONAL user properties to expand, for example + "personalSpace" or "operations" + :return: the user details + """ + params = {"expand": expand} if expand else {} + + try: + return self.get_user(accountid, params=params) + except HTTPError as e: + if e.response.status_code == 403: + raise ApiPermissionError( + "The calling user does not have permission to view users", + reason=e, + ) + if e.response.status_code == 404: + raise ApiNotFoundError( + "The user with the given account does not exist", + reason=e, + ) + + raise + def get_current_user(self, **kwargs): """Get current user.""" return self.get("rest/api/user/current", **kwargs) diff --git a/docs/confluence.rst b/docs/confluence.rst index 0dc44fb6d..f27a6112e 100644 --- a/docs/confluence.rst +++ b/docs/confluence.rst @@ -934,6 +934,11 @@ Users and Groups # Get information about a user through username confluence.get_user_details_by_username(username, expand=None) + # Get information about a user through account ID + # ``ConfluenceCloud`` (and ``Confluence`` with a Cloud URL) also provide + # this, through ``/wiki/rest/api/user?accountId=...``. + confluence.get_user_details_by_accountid(accountid, expand=None) + # Get information about a user through user key confluence.get_user_details_by_userkey(userkey, expand=None) diff --git a/tests/confluence/test_confluence_cloud.py b/tests/confluence/test_confluence_cloud.py index ed2816a5e..45906ac27 100644 --- a/tests/confluence/test_confluence_cloud.py +++ b/tests/confluence/test_confluence_cloud.py @@ -12,7 +12,7 @@ from atlassian.confluence import Confluence, ConfluenceCloud from atlassian.confluence.cloud import Cloud from atlassian.confluence.cloud.cloud import ConfluenceCloud as ConfluenceCloudV2 -from atlassian.errors import ApiError, ApiPermissionError +from atlassian.errors import ApiError, ApiNotFoundError, ApiPermissionError @pytest.fixture @@ -720,6 +720,54 @@ def test_get_user_requests_wiki_user_endpoint(self, confluence_cloud): url = mock_request.call_args.kwargs["url"] assert url == "https://test.atlassian.net/wiki/rest/api/user?accountId=557058%3Af58131cb" + @patch.object(ConfluenceCloud, "get") + def test_get_user_details_by_accountid(self, mock_get, confluence_cloud): + mock_get.return_value = {"accountId": "user1", "displayName": "Test User"} + + assert confluence_cloud.get_user_details_by_accountid("user1") == { + "accountId": "user1", + "displayName": "Test User", + } + mock_get.assert_called_once_with("rest/api/user", params={"accountId": "user1"}) + + def test_get_user_details_by_accountid_requests_wiki_user_endpoint(self, confluence_cloud): + response = Response() + response.status_code = 200 + response._content = b'{"accountId": "557058:f58131cb", "displayName": "Test User"}' + + with patch.object(confluence_cloud._session, "request", return_value=response) as mock_request: + assert confluence_cloud.get_user_details_by_accountid("557058:f58131cb", expand="personalSpace") == { + "accountId": "557058:f58131cb", + "displayName": "Test User", + } + + url = mock_request.call_args.kwargs["url"] + assert url == "https://test.atlassian.net/wiki/rest/api/user?expand=personalSpace&accountId=557058%3Af58131cb" + + @pytest.mark.parametrize( + "status_code, error, message", + [ + (403, ApiPermissionError, "does not have permission to view users"), + (404, ApiNotFoundError, "The user with the given account does not exist"), + ], + ) + @patch.object(ConfluenceCloud, "get") + def test_get_user_details_by_accountid_errors(self, mock_get, status_code, error, message, confluence_cloud): + response = Response() + response.status_code = status_code + mock_get.side_effect = HTTPError(response=response) + + with pytest.raises(error, match=message): + confluence_cloud.get_user_details_by_accountid("user1") + + @patch.object(ConfluenceCloud, "get") + def test_get_user_details_by_accountid_through_confluence_factory(self, mock_get): + mock_get.return_value = {"accountId": "user1"} + confluence = Confluence(url="https://test.atlassian.net", username="user", password="api-token") + + assert confluence.get_user_details_by_accountid("user1") == {"accountId": "user1"} + mock_get.assert_called_once_with("rest/api/user", params={"accountId": "user1"}) + @patch.object(ConfluenceCloud, "get") def test_get_current_user(self, mock_get, confluence_cloud): """Test get_current_user method."""