Skip to content

Commit ab3adf6

Browse files
authored
[Confluence] Add get_all_spaces and switch Cloud space methods to v2 plural endpoint (#1638)
* [Confluence] Add get_all_spaces and switch Cloud space methods to v2 plural endpoint Fixes #1560. After commit 63e744f the legacy `get_all_spaces` was removed entirely from the Cloud module — `Confluence("https://api.atlassian.com/ex/confluence/...")` routes to the new `Cloud` class, which only has `get_spaces` (singular path). Calling `c.get_all_spaces()` now raises AttributeError; users with OAuth/PAT tokens routed through the API gateway lose the paginated enumeration they had under the old v1 path. Cloud's space methods also use the singular `space` path (e.g. `self.get("space")`) while `api_root="wiki/api/v2"`, so the constructed URL `/wiki/api/v2/space` doesn't match the documented v2 endpoint `/wiki/api/v2/spaces` (plural — see https://developer.atlassian.com/cloud/confluence/rest/v2/api-group-space/). This change: - Adds `Cloud.get_all_spaces()` returning a paginated generator over `_get_paged("spaces")`, restoring the back-compat surface and using v2. - Switches `get_spaces`, `get_space`, `create_space`, `update_space`, `delete_space`, `get_space_content` from `space[/...]` to `spaces[/...]`. - Updates the existing space mock-tests to assert the v2 plural path and adds a pagination test for `get_all_spaces`. The Server implementation is unchanged (still uses v1 `space` paths correctly, since Server is not affected by gateway routing). Signed-off-by: 1fanwang <1fannnw@gmail.com> * [Confluence] Fix multi-line docstrings in cloud space methods to D213 (summary on second line) Signed-off-by: 1fanwang <1fannnw@gmail.com> --------- Signed-off-by: 1fanwang <1fannnw@gmail.com>
1 parent 2fc67b7 commit ab3adf6

2 files changed

Lines changed: 56 additions & 19 deletions

File tree

atlassian/confluence/cloud/__init__.py

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,28 +70,45 @@ def get_content_ancestors(self, content_id, **kwargs):
7070

7171
# Space Management
7272
def get_spaces(self, **kwargs):
73-
"""Get all spaces."""
74-
return self.get("space", **kwargs)
73+
"""
74+
Get all spaces (single page).
75+
76+
Calls the Confluence Cloud v2 endpoint ``/wiki/api/v2/spaces``.
77+
For paginated enumeration of every space, use :meth:`get_all_spaces`.
78+
"""
79+
return self.get("spaces", **kwargs)
80+
81+
def get_all_spaces(self, **kwargs):
82+
"""
83+
Get all spaces with full pagination.
84+
85+
Returns a generator yielding each space dict from the Confluence Cloud
86+
v2 endpoint ``/wiki/api/v2/spaces``. Replaces the legacy v1
87+
``get_all_spaces`` (which hit ``/rest/api/space``) — that endpoint is
88+
not available on the OAuth API gateway and returns
89+
``GoneException: This deprecated endpoint has been removed``.
90+
"""
91+
return self._get_paged("spaces", params=kwargs)
7592

7693
def get_space(self, space_id, **kwargs):
7794
"""Get space by ID."""
78-
return self.get(f"space/{space_id}", **kwargs)
95+
return self.get(f"spaces/{space_id}", **kwargs)
7996

8097
def create_space(self, data, **kwargs):
8198
"""Create new space."""
82-
return self.post("space", data=data, **kwargs)
99+
return self.post("spaces", data=data, **kwargs)
83100

84101
def update_space(self, space_id, data, **kwargs):
85102
"""Update existing space."""
86-
return self.put(f"space/{space_id}", data=data, **kwargs)
103+
return self.put(f"spaces/{space_id}", data=data, **kwargs)
87104

88105
def delete_space(self, space_id, **kwargs):
89106
"""Delete space."""
90-
return self.delete(f"space/{space_id}", **kwargs)
107+
return self.delete(f"spaces/{space_id}", **kwargs)
91108

92109
def get_space_content(self, space_id, **kwargs):
93110
"""Get space content."""
94-
return self.get(f"space/{space_id}/content", **kwargs)
111+
return self.get(f"spaces/{space_id}/content", **kwargs)
95112

96113
# User Management
97114
def get_users(self, **kwargs):

tests/confluence/test_confluence_cloud.py

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,52 +150,72 @@ def test_get_content_ancestors(self, mock_get, confluence_cloud):
150150
# Space Management Tests
151151
@patch.object(ConfluenceCloud, "get")
152152
def test_get_spaces(self, mock_get, confluence_cloud):
153-
"""Test get_spaces method."""
153+
"""get_spaces calls the v2 plural endpoint /wiki/api/v2/spaces."""
154154
mock_get.return_value = {"results": [{"id": "TEST", "name": "Test Space"}]}
155155
result = confluence_cloud.get_spaces()
156-
mock_get.assert_called_once_with("space", **{})
156+
mock_get.assert_called_once_with("spaces", **{})
157157
assert result == {"results": [{"id": "TEST", "name": "Test Space"}]}
158158

159+
@patch.object(ConfluenceCloud, "get")
160+
def test_get_all_spaces_paginates(self, mock_get, confluence_cloud):
161+
"""get_all_spaces yields every space across paginated v2 responses."""
162+
mock_get.side_effect = [
163+
{
164+
"results": [{"id": "1", "name": "A"}, {"id": "2", "name": "B"}],
165+
"_links": {"next": "/wiki/api/v2/spaces?cursor=NEXT"},
166+
},
167+
{"results": [{"id": "3", "name": "C"}], "_links": {}},
168+
]
169+
result = list(confluence_cloud.get_all_spaces())
170+
assert result == [
171+
{"id": "1", "name": "A"},
172+
{"id": "2", "name": "B"},
173+
{"id": "3", "name": "C"},
174+
]
175+
# Entry-point URL is the v2 plural path; pagination URL handling is
176+
# covered by existing _get_paged tests.
177+
assert mock_get.call_args_list[0].args[0] == "spaces"
178+
159179
@patch.object(ConfluenceCloud, "get")
160180
def test_get_space(self, mock_get, confluence_cloud):
161-
"""Test get_space method."""
181+
"""get_space calls the v2 plural endpoint."""
162182
mock_get.return_value = {"id": "TEST", "name": "Test Space"}
163183
result = confluence_cloud.get_space("TEST")
164-
mock_get.assert_called_once_with("space/TEST", **{})
184+
mock_get.assert_called_once_with("spaces/TEST", **{})
165185
assert result == {"id": "TEST", "name": "Test Space"}
166186

167187
@patch.object(ConfluenceCloud, "post")
168188
def test_create_space(self, mock_post, confluence_cloud):
169-
"""Test create_space method."""
189+
"""create_space calls the v2 plural endpoint."""
170190
space_data = {"name": "New Space", "key": "NEW"}
171191
mock_post.return_value = {"id": "NEW", "name": "New Space", "key": "NEW"}
172192
result = confluence_cloud.create_space(space_data)
173-
mock_post.assert_called_once_with("space", data=space_data, **{})
193+
mock_post.assert_called_once_with("spaces", data=space_data, **{})
174194
assert result == {"id": "NEW", "name": "New Space", "key": "NEW"}
175195

176196
@patch.object(ConfluenceCloud, "put")
177197
def test_update_space(self, mock_put, confluence_cloud):
178-
"""Test update_space method."""
198+
"""update_space calls the v2 plural endpoint."""
179199
space_data = {"name": "Updated Space"}
180200
mock_put.return_value = {"id": "TEST", "name": "Updated Space"}
181201
result = confluence_cloud.update_space("TEST", space_data)
182-
mock_put.assert_called_once_with("space/TEST", data=space_data, **{})
202+
mock_put.assert_called_once_with("spaces/TEST", data=space_data, **{})
183203
assert result == {"id": "TEST", "name": "Updated Space"}
184204

185205
@patch.object(ConfluenceCloud, "delete")
186206
def test_delete_space(self, mock_delete, confluence_cloud):
187-
"""Test delete_space method."""
207+
"""delete_space calls the v2 plural endpoint."""
188208
mock_delete.return_value = {"success": True}
189209
result = confluence_cloud.delete_space("TEST")
190-
mock_delete.assert_called_once_with("space/TEST", **{})
210+
mock_delete.assert_called_once_with("spaces/TEST", **{})
191211
assert result == {"success": True}
192212

193213
@patch.object(ConfluenceCloud, "get")
194214
def test_get_space_content(self, mock_get, confluence_cloud):
195-
"""Test get_space_content method."""
215+
"""get_space_content calls the v2 plural endpoint."""
196216
mock_get.return_value = {"results": [{"id": "123", "title": "Page in Space"}]}
197217
result = confluence_cloud.get_space_content("TEST")
198-
mock_get.assert_called_once_with("space/TEST/content", **{})
218+
mock_get.assert_called_once_with("spaces/TEST/content", **{})
199219
assert result == {"results": [{"id": "123", "title": "Page in Space"}]}
200220

201221
# User Management Tests

0 commit comments

Comments
 (0)