Skip to content

Commit 85da305

Browse files
committed
fix logs
1 parent bef7da2 commit 85da305

3 files changed

Lines changed: 81 additions & 92 deletions

File tree

atlassian/confluence/server/__init__.py

Lines changed: 76 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,6 @@ def get_content_descendants(self, content_id, **kwargs):
105105
"""Get descendant content."""
106106
return self.get(f"content/{content_id}/descendant", **kwargs)
107107

108-
def get_child_pages(self, content_id, **kwargs):
109-
"""Get child pages of a content item."""
110-
return self.get(f"content/{content_id}/child/page", **kwargs)
111-
112108
def get_descendant_pages(self, content_id, **kwargs):
113109
"""Get all descendant pages of a content item."""
114110
return self.get(f"content/{content_id}/descendant/page", **kwargs)
@@ -236,12 +232,14 @@ def get_child_id_list(self, page_id, type="page", start=None, limit=None):
236232
child_id_list = [child["id"] for child in child_page]
237233
return child_id_list
238234

239-
def get_child_pages(self, page_id):
235+
def get_child_pages(self, page_id, **kwargs):
240236
"""
241237
Get child pages for the provided page_id
242238
:param page_id:
243239
:return:
244240
"""
241+
if self.cloud:
242+
return self.get(f"content/{page_id}/child/page", **kwargs)
245243
return self.get_page_child_by_type(page_id=page_id, type="page")
246244

247245
def get_page_id(self, space, title, type="page"):
@@ -2032,23 +2030,25 @@ def get_spaces(self, **kwargs):
20322030
"""Get all spaces."""
20332031
return self.get("space", **kwargs)
20342032

2035-
def get_space(self, space_key, expand="description.plain,homepage", params=None):
2033+
def get_space(self, space_key, expand=None, params=None, **kwargs):
20362034
"""
20372035
Get information about a space through space key
20382036
:param space_key: The unique space key name
20392037
:param expand: OPTIONAL: additional info from description, homepage
20402038
:param params: OPTIONAL: dictionary of additional URL parameters
20412039
:return: Returns the space along with its ID
20422040
"""
2043-
url = f"rest/api/space/{space_key}"
2044-
params = params or {}
2041+
url = f"space/{space_key}"
2042+
request_params = params.copy() if params else {}
20452043
if expand:
2046-
params["expand"] = expand
2044+
request_params["expand"] = expand
2045+
request_kwargs = dict(kwargs)
2046+
if request_params:
2047+
request_kwargs["params"] = request_params
20472048
try:
2048-
response = self.get(url, params=params)
2049+
response = self.get(url, **request_kwargs)
20492050
except HTTPError as e:
20502051
if e.response.status_code == 404:
2051-
# Raise ApiError as the documented reason is ambiguous
20522052
raise ApiError(
20532053
"There is no space with the given key, "
20542054
"or the calling user does not have permission to view the space",
@@ -2057,33 +2057,30 @@ def get_space(self, space_key, expand="description.plain,homepage", params=None)
20572057
raise
20582058
return response
20592059

2060-
def create_space(self, space_key, space_name):
2060+
def create_space(self, space_key, space_name=None, **kwargs):
20612061
"""
2062-
Create space
2063-
:param space_key:
2064-
:param space_name:
2065-
:return:
2062+
Create space.
2063+
Accepts either a full data dictionary or the legacy space_key/space_name pair.
20662064
"""
2067-
data = {"key": space_key, "name": space_name}
2068-
self.post("rest/api/space", data=data)
2065+
data = space_key if isinstance(space_key, dict) else {"key": space_key, "name": space_name}
2066+
return self.post("space", data=data, **kwargs)
20692067

20702068
def update_space(self, space_key, data, **kwargs):
20712069
"""Update existing space."""
20722070
return self.put(f"space/{space_key}", data=data, **kwargs)
20732071

2074-
def delete_space(self, space_key):
2072+
def delete_space(self, space_key, **kwargs):
20752073
"""
20762074
Delete space
20772075
:param space_key:
20782076
:return:
20792077
"""
2080-
url = f"rest/api/space/{space_key}"
2078+
url = f"space/{space_key}"
20812079

20822080
try:
2083-
response = self.delete(url)
2081+
response = self.delete(url, **kwargs)
20842082
except HTTPError as e:
20852083
if e.response.status_code == 404:
2086-
# Raise ApiError as the documented reason is ambiguous
20872084
raise ApiError(
20882085
"There is no space with the given key, "
20892086
"or the calling user does not have permission to delete it",
@@ -2118,11 +2115,12 @@ def get_space_property(self, space_key, expand=None):
21182115
def get_space_content(
21192116
self,
21202117
space_key,
2121-
depth="all",
2122-
start=0,
2123-
limit=500,
2118+
depth=None,
2119+
start=None,
2120+
limit=None,
21242121
content_type=None,
2125-
expand="body.storage",
2122+
expand=None,
2123+
**kwargs,
21262124
):
21272125
"""
21282126
Get space content.
@@ -2131,29 +2129,26 @@ def get_space_content(
21312129
:param content_type:
21322130
:param space_key: The unique space key name
21332131
:param depth: OPTIONAL: all|root
2134-
Gets all space pages or only root pages
2135-
:param start: OPTIONAL: The start point of the collection to return. Default: 0.
2136-
:param limit: OPTIONAL: The limit of the number of pages to return, this may be restricted by
2137-
fixed system limits. Default: 500
2138-
:param expand: OPTIONAL: by default expands page body in confluence storage format.
2139-
See atlassian documentation for more information.
2140-
:return: Returns the space along with its ID
2132+
:param start: OPTIONAL: The start point of the collection to return.
2133+
:param limit: OPTIONAL: The limit of the number of pages to return.
2134+
:param expand: OPTIONAL: additional content properties to expand.
2135+
:return: Returns the space content
21412136
"""
2142-
2143-
content_type = f"{'/' + content_type if content_type else ''}"
2144-
url = f"rest/api/space/{space_key}/content{content_type}"
2145-
params = {
2146-
"depth": depth,
2147-
"start": start,
2148-
"limit": limit,
2149-
}
2150-
if expand:
2137+
params = {"spaceKey": space_key, **kwargs}
2138+
if depth is not None:
2139+
params["depth"] = depth
2140+
if start is not None:
2141+
params["start"] = start
2142+
if limit is not None:
2143+
params["limit"] = limit
2144+
if content_type is not None:
2145+
params["type"] = content_type
2146+
if expand is not None:
21512147
params["expand"] = expand
21522148
try:
2153-
response = self.get(url, params=params)
2149+
response = self.get("content", params=params)
21542150
except HTTPError as e:
21552151
if e.response.status_code == 404:
2156-
# Raise ApiError as the documented reason is ambiguous
21572152
raise ApiError(
21582153
"There is no space with the given key, "
21592154
"or the calling user does not have permission to view the space",
@@ -2293,20 +2288,28 @@ def get_group(self, group_name, **kwargs):
22932288
"""Get group by name."""
22942289
return self.get("group", params={"groupname": group_name, **kwargs})
22952290

2296-
def get_group_members(self, group_name="confluence-users", start=0, limit=1000, expand=None):
2291+
def get_group_members(self, group_name="confluence-users", start=None, limit=None, expand=None, **kwargs):
22972292
"""
22982293
Get a paginated collection of users in the given group
22992294
:param group_name
2300-
:param start: OPTIONAL: The start point of the collection to return. Default: None (0).
2301-
:param limit: OPTIONAL: The limit of the number of users to return, this may be restricted by
2302-
fixed system limits. Default: 1000
2303-
:param expand: OPTIONAL: A comma separated list of properties to expand on the content. status
2295+
:param start: OPTIONAL: The start point of the collection to return.
2296+
:param limit: OPTIONAL: The limit of the number of users to return.
2297+
:param expand: OPTIONAL: A comma separated list of properties to expand.
23042298
:return:
23052299
"""
2306-
url = f"rest/api/group/{group_name}/member?limit={limit}&start={start}&expand={expand}"
2300+
request_kwargs = dict(kwargs)
2301+
params = {}
2302+
if start is not None:
2303+
params["start"] = start
2304+
if limit is not None:
2305+
params["limit"] = limit
2306+
if expand is not None:
2307+
params["expand"] = expand
2308+
if params:
2309+
request_kwargs["params"] = params
23072310

23082311
try:
2309-
response = self.get(url)
2312+
response = self.get(f"group/{group_name}/member", **request_kwargs)
23102313
except HTTPError as e:
23112314
if e.response.status_code == 403:
23122315
raise ApiPermissionError(
@@ -2316,7 +2319,7 @@ def get_group_members(self, group_name="confluence-users", start=0, limit=1000,
23162319

23172320
raise
23182321

2319-
return response.get("results")
2322+
return response
23202323

23212324
# Label Management
23222325
def get_labels(self, **kwargs):
@@ -2360,24 +2363,22 @@ def update_attachment(self, attachment_id, data, **kwargs):
23602363
"""Update existing attachment."""
23612364
return self.put(f"content/{attachment_id}", data=data, **kwargs)
23622365

2363-
def delete_attachment(self, page_id, filename="", version=None):
2366+
def delete_attachment(self, attachment_id, filename="", version=None, **kwargs):
23642367
"""
2365-
Remove completely a file if version is None or delete version
2366-
:param version:
2367-
:param page_id: file version
2368-
:param filename:
2369-
:return:
2368+
Delete an attachment by content ID, or remove a legacy page attachment when filename/version is supplied.
23702369
"""
2371-
params = {"pageId": page_id}
2372-
if filename:
2373-
params["filename"] = filename
2374-
if version:
2375-
params["version"] = version
2376-
return self.post(
2377-
"json/removeattachment.action",
2378-
params=params,
2379-
headers=self.form_token_headers,
2380-
)
2370+
if filename or version:
2371+
params = {"pageId": attachment_id}
2372+
if filename:
2373+
params["filename"] = filename
2374+
if version:
2375+
params["version"] = version
2376+
return self.post(
2377+
"json/removeattachment.action",
2378+
params=params,
2379+
headers=self.form_token_headers,
2380+
)
2381+
return self.delete(f"content/{attachment_id}", **kwargs)
23812382

23822383
def download_attachment(self, attachment_id, **kwargs):
23832384
"""Download attachment."""
@@ -3135,8 +3136,7 @@ def reindex(self):
31353136
It is not public method for reindex Confluence
31363137
:return:
31373138
"""
3138-
url = "rest/prototype/1/index/reindex"
3139-
return self.post(url)
3139+
return self.post("reindex")
31403140

31413141
def get_reindex_progress(self, **kwargs):
31423142
"""Get reindex progress."""
@@ -3476,18 +3476,16 @@ def change_my_password(self, oldpass, newpass):
34763476
}
34773477
self.post(url, data=data)
34783478

3479-
def add_user_to_group(self, username, group_name):
3479+
def add_user_to_group(self, group_name, username, **kwargs):
34803480
"""
34813481
Add given user to a group
3482-
3483-
:param username: str - username of user to add to group
34843482
:param group_name: str - name of group to add user to
3483+
:param username: str - username of user to add to group
34853484
:return: Current state of the group
34863485
"""
3487-
url = f"rest/api/user/{username}/group/{group_name}"
3488-
return self.put(url)
3486+
return self.post(f"group/{group_name}/member", data={"name": username}, **kwargs)
34893487

3490-
def remove_user_from_group(self, username, group_name):
3488+
def remove_user_from_group(self, group_name, username, **kwargs):
34913489
"""
34923490
Remove the given {@link User} identified by username from the given {@link Group} identified by groupName.
34933491
This method is idempotent i.e. if the membership is not present then no action will be taken.
@@ -3496,8 +3494,7 @@ def remove_user_from_group(self, username, group_name):
34963494
:param group_name: str - name of group to add user to
34973495
:return: Current state of the group
34983496
"""
3499-
url = f"rest/api/user/{username}/group/{group_name}"
3500-
return self.delete(url)
3497+
return self.delete(f"group/{group_name}/member/{username}", **kwargs)
35013498

35023499
# Space Permissions
35033500
def get_all_space_permissions(self, space_key):
@@ -3805,19 +3802,8 @@ def remove_space_permission(self, space_key, user, permission):
38053802
def get_space_permissions(self, space_key, **kwargs):
38063803
"""
38073804
Get space permissions.
3808-
The JSON-RPC APIs for Confluence are provided here to help you browse and discover APIs you have access to.
3809-
JSON-RPC APIs operate differently than REST APIs.
3810-
To learn more about how to use these APIs,
3811-
please refer to the Confluence JSON-RPC documentation on Atlassian Developers.
38123805
"""
3813-
url = "rpc/json-rpc/confluenceservice-v2"
3814-
data = {
3815-
"jsonrpc": "2.0",
3816-
"method": "getSpacePermissionSets",
3817-
"id": 7,
3818-
"params": [space_key],
3819-
}
3820-
return self.post(url, data=data).get("result") or {}
3806+
return self.get(f"space/{space_key}/permission", **kwargs)
38213807

38223808
def get_subtree_of_content_ids(self, page_id):
38233809
"""

atlassian/rest_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# coding=utf-8
22

33
import logging
4+
import math
45
import random
56
import time
67
from datetime import datetime, timezone
@@ -319,7 +320,7 @@ def _parse_retry_after_header(self, header_value: Optional[str]) -> Optional[flo
319320

320321
if retry_after_dt.tzinfo is None:
321322
retry_after_dt = retry_after_dt.replace(tzinfo=timezone.utc)
322-
delay_seconds = (retry_after_dt - datetime.now(timezone.utc)).total_seconds()
323+
delay_seconds = float(math.ceil((retry_after_dt - datetime.now(timezone.utc)).total_seconds()))
323324

324325
if delay_seconds is None:
325326
return None

tests/confluence/test_confluence_server.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,9 @@ def test_get_space(self, mock_get, confluence_server):
302302
"""Test get_space method."""
303303
mock_get.return_value = {"key": "TEST", "name": "Test Space"}
304304
result = confluence_server.get_space("TEST")
305-
mock_get.assert_called_once_with("space/TEST", )
305+
mock_get.assert_called_once_with(
306+
"space/TEST",
307+
)
306308
assert result == {"key": "TEST", "name": "Test Space"}
307309

308310
@patch.object(ConfluenceServer, "post")

0 commit comments

Comments
 (0)