Skip to content

Commit 470ee16

Browse files
authored
[Confluence] added new method get_space_export + docs + examples (#1466)
* added expand to get_issue method, added new method * get_issue_status_changelog method
1 parent fb9c354 commit 470ee16

File tree

3 files changed

+126
-0
lines changed

3 files changed

+126
-0
lines changed

atlassian/confluence.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,6 +2657,103 @@ def get_page_as_word(self, page_id):
26572657
url = "exportword?pageId={pageId}".format(pageId=page_id)
26582658
return self.get(url, headers=headers, not_json_response=True)
26592659

2660+
def get_space_export(self, space_key: str, export_type: str) -> str:
2661+
"""
2662+
Export a Confluence space to a file of the specified type.
2663+
(!) This method was developed for Confluence Cloud and may not work with Confluence on-prem.
2664+
(!) This is an experimental method that does not trigger an officially supported REST endpoint. It may break if Atlassian changes the space export front-end logic.
2665+
2666+
:param space_key: The key of the space to export.
2667+
:param export_type: The type of export to perform. Valid values are: 'html', 'csv', 'xml', 'pdf'.
2668+
:return: The URL to download the exported file.
2669+
"""
2670+
2671+
def get_atl_request(url: str):
2672+
# Nested function used to get atl_token used for XSRF protection. this is only applicable to html/csv/xml space exports
2673+
try:
2674+
response = self.get(url, advanced_mode=True)
2675+
parsed_html = BeautifulSoup(response.text, "html.parser")
2676+
atl_token = parsed_html.find("input", {"name": "atl_token"}).get("value")
2677+
return atl_token
2678+
except Exception as e:
2679+
raise ApiError("Problems with getting the atl_token for get_space_export method :", reason=e)
2680+
2681+
# Checks if space_ke parameter is valid and if api_token has relevant permissions to space
2682+
self.get_space(space_key=space_key, expand="permissions")
2683+
2684+
try:
2685+
log.info(
2686+
"Initiated experimental get_space_export method for export type: "
2687+
+ export_type
2688+
+ " from Confluence space: "
2689+
+ space_key
2690+
)
2691+
if export_type == "csv":
2692+
form_data = {
2693+
"atl_token": get_atl_request(f"spaces/exportspacecsv.action?key={space_key}"),
2694+
"exportType": "TYPE_CSV",
2695+
"contentOption": "all",
2696+
"includeComments": "true",
2697+
"confirm": "Export",
2698+
}
2699+
elif export_type == "html":
2700+
form_data = {
2701+
"atl_token": get_atl_request(f"spaces/exportspacehtml.action?key={space_key}"),
2702+
"exportType": "TYPE_HTML",
2703+
"contentOption": "visibleOnly",
2704+
"includeComments": "true",
2705+
"confirm": "Export",
2706+
}
2707+
elif export_type == "xml":
2708+
form_data = {
2709+
"atl_token": get_atl_request(f"spaces/exportspacexml.action?key={space_key}"),
2710+
"exportType": "TYPE_XML",
2711+
"contentOption": "all",
2712+
"includeComments": "true",
2713+
"confirm": "Export",
2714+
}
2715+
elif export_type == "pdf":
2716+
url = "spaces/flyingpdf/doflyingpdf.action?key=" + space_key
2717+
log.info("Initiate PDF space export from space " + str(space_key))
2718+
return self.get_pdf_download_url_for_confluence_cloud(url)
2719+
else:
2720+
raise ValueError("Invalid export_type parameter value. Valid values are: 'html/csv/xml/pdf'")
2721+
url = self.url_joiner(url=self.url, path=f"spaces/doexportspace.action?key={space_key}")
2722+
2723+
# Sending a POST request that triggers the space export.
2724+
response = self.session.post(url, headers=self.form_token_headers, data=form_data)
2725+
parsed_html = BeautifulSoup(response.text, "html.parser")
2726+
# Getting the poll URL to get the export progress status
2727+
try:
2728+
poll_url = parsed_html.find("meta", {"name": "ajs-pollURI"}).get("content")
2729+
except Exception as e:
2730+
raise ApiError("Problems with getting the poll_url for get_space_export method :", reason=e)
2731+
running_task = True
2732+
while running_task:
2733+
try:
2734+
progress_response = self.get(poll_url)
2735+
log.info("Space" + space_key + " export status: " + progress_response["message"])
2736+
if progress_response["complete"]:
2737+
parsed_html = BeautifulSoup(progress_response["message"], "html.parser")
2738+
download_url = parsed_html.find("a", {"class": "space-export-download-path"}).get("href")
2739+
if self.url in download_url:
2740+
return download_url
2741+
else:
2742+
combined_url = self.url + download_url
2743+
# Ensure only one /wiki is included in the path
2744+
if combined_url.count("/wiki") > 1:
2745+
combined_url = combined_url.replace("/wiki/wiki", "/wiki")
2746+
return combined_url
2747+
time.sleep(30)
2748+
except Exception as e:
2749+
raise ApiError(
2750+
"Encountered error during space export status check from space " + space_key, reason=e
2751+
)
2752+
2753+
return "None" # Return None if the while loop does not return a value
2754+
except Exception as e:
2755+
raise ApiError("Encountered error during space export from space " + space_key, reason=e)
2756+
26602757
def export_page(self, page_id):
26612758
"""
26622759
Alias method for export page as pdf
@@ -2905,6 +3002,7 @@ def get_pdf_download_url_for_confluence_cloud(self, url):
29053002
and provides a link to download the PDF once the process completes.
29063003
This functions polls the long-running task page and returns the
29073004
download url of the PDF.
3005+
This method is used in get_space_export() method for space-> PDF export.
29083006
:param url: URL to initiate PDF export
29093007
:return: Download url for PDF file
29103008
"""

docs/confluence.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,9 @@ Get spaces info
240240
# Get Space permissions set based on json-rpc call
241241
confluence.get_space_permissions(space_key)
242242
243+
# Get Space export download url
244+
confluence.get_space_export(space_key, export_type)
245+
243246
Users and Groups
244247
----------------
245248

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from atlassian import Confluence
2+
3+
# init the Confluence object
4+
host = "<cloud_instance_url/wiki>"
5+
username = "<user_email>"
6+
password = "<API_TOKEN>"
7+
confluence = Confluence(
8+
url=host,
9+
username=username,
10+
password=password,
11+
)
12+
space_key = "TEST"
13+
confluence.get_space_export(space_key=space_key, export_type="html")
14+
# This method should be used to trigger the space export action.
15+
# Provide `space_key` and `export_type` (html/pdf/xml/csv) as arguments.
16+
17+
# It was tested on Confluence Cloud and might not work properly with Confluence on-prem.
18+
# (!) This is an experimental method that should be considered a workaround for the missing space export REST endpoint.
19+
# (!) The method might break if Atlassian implements changes to their space export front-end logic.
20+
21+
# The while loop does not have an exit condition; it will run until the space export is completed.
22+
# It is possible that the space export progress might get stuck. It is up to the library user to handle this scenario.
23+
24+
# Method returns the link to the space export file.
25+
# It is up to the library user to handle the file download action.

0 commit comments

Comments
 (0)