Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# Changelog

## [Version 1.1.2](https://github.com/dataiku/dss-plugin-confluence/releases/tag/v1.1.2) - Feature release - 2025-12-05

- Add support for links to flow_zone, scenario, dashboard, recipe, managed_folder, statistics_worksheet, lambda_service and analysis

## [Version 1.1.1](https://github.com/dataiku/dss-plugin-confluence/releases/tag/v1.1.1) - Feature release - 2025-06-28

- Fix following API change
- Add support for links to flow_zone, scenario, dashboard, recipe, managed_folder, statistics_worksheet, lambda_service

## [Version 1.1.0](https://github.com/dataiku/dss-plugin-confluence/releases/tag/v1.1.0) - Feature release - 2024-06-14

Expand Down
4 changes: 2 additions & 2 deletions parameter-sets/confluence-login/parameter-set.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
},
{
"name": "orgname",
"label": "Organization name",
"label": "Subdomain",
"type": "STRING",
"description": "",
"description": "First part of your URL: https://<subdomain>.atlassian.net",
"visibilityCondition": "model.server_type == 'remote'",
"mandatory": false
},
Expand Down
4 changes: 2 additions & 2 deletions plugin.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"id": "confluence",
"version": "1.1.1",
"version": "1.1.2",
"meta": {
"label": "Confluence wiki",
"description": "Export a DSS wiki to a Confluence space",
"author": "Dataiku (Alex Bourret)",
"icon": "icon-cloud-upload",
"licenseInfo": "Apache Software License",
"url": "https://www.dataiku.com/product/plugins/confluence/",
"tags": ["Governance", "Cloud", "Productivity"],
"tags": ["Business Applications", "Productivity", "Export", "Governance"],
"supportLevel": "NOT_SUPPORTED"
}
}
15 changes: 13 additions & 2 deletions python-lib/md2conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,19 @@ def upload_attachment(page_id, file, comment, confluence_api_url, username, pass
session.headers.update({'X-Atlassian-Token': 'no-check'})

res = session.post(url, files=file_to_upload)

return True
link = None
try:
json_response = res.json()
url_base = json_response.get("_links", {}).get("base", "")
if "results" in json_response:
json_response = json_response.get("results")[0]
link = "{}{}".format(
url_base,
json_response.get("_links", {}).get("download", ""),
)
except Exception as error:
print("Error {}".format(error))
return link

def urlEncodeNonAscii(b):
return re.sub('[\x80-\xFF]', lambda c: '%%%02x' % ord(c.group(0)), b)
Expand Down
77 changes: 73 additions & 4 deletions python-lib/wikitransfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ def recurse_taxonomy(self, taxonomy, ancestor=None):
for article in taxonomy:
if len(article['children']) > 0:
confluence_id = self.transfer_article(article['id'], ancestor)
self.recurse_taxonomy(article['children'], confluence_id)
self.recurse_taxonomy(article['children'], ancestor=confluence_id)
else:
self.transfer_article(article['id'], ancestor)
self.transfer_article(article['id'], parent_id=ancestor)

def transfer_article(self, article_id, parent_id=None):
self.attachment_table.reset()
self.transfered_attachments = []
self.transfered_links = []
article_data = self.wiki.get_article(article_id).get_data()
dss_page_name = article_data.get_name()
dss_page_body = article_data.get_body()
Expand Down Expand Up @@ -90,6 +91,9 @@ def convert(self, md_input, article_id, new_id, article_data):
md = md + u'\n' + self.attachment_table.to_md()
md = self.convert_math_blocks(md)
md = self.develop_dss_links(md)
md = self.develop_image_md_links(md)
md = self.develop_dss_md_links(md)
md = self.develop_md_links(md)
html = markdown.markdown(md, extensions=['markdown.extensions.tables',
'markdown.extensions.fenced_code',
'markdown.extensions.nl2br',
Expand Down Expand Up @@ -164,6 +168,67 @@ def develop_dss_links(self, md):
md = re.sub(object_type + r':' + initial_id, self.build_dss_url(object_type, object_path), md, flags=re.IGNORECASE)
return md

def develop_md_links(self, md):
# Processing all [name](link) links
links = self.find_md_links(md)
for link in links:
link_name = link[0]
link_target = link[1]
if link_name in self.transfered_attachments:
target_link = self.transfered_links[self.transfered_attachments.index(link_name)]
replacement = '<a href="{}">{}</a>'.format(target_link, link_name)
md = md.replace(
"[{}]({})".format(link_name, link_target),
replacement
)
return md

def develop_image_md_links(self, md):
# Processing all ![name](link) links
links = self.find_image_md_links(md)
for link in links:
link_name = link[0]
link_target = link[1]
if link_name in self.transfered_attachments:
target_link = self.transfered_links[self.transfered_attachments.index(link_name)]
replacement = '<img src="{}" alt="{}" />'.format(target_link, link_name)
md = md.replace(
"![{}]({})".format(link_name, link_target),
replacement
)
return md

def develop_dss_md_links(self, md):
# Processing all [name]{name}(link) links
links = self.find_dss_md_links(md)
for link in links:
link_name = link[0]
link_target = link[1]
link_target_2 = link[2]
if link_name in self.transfered_attachments:
target_link = self.transfered_links[self.transfered_attachments.index(link_name)]
replacement = '<a href="{}">{}</a>'.format(target_link, link_name)
md = md.replace(
"[{}]{{{}}}({})".format(link_name, link_target, link_target_2),
replacement
)
return md

def find_dss_md_links(self, md):
pattern = r'\[([^\]]+)\]\{([^)]+)\}\(([^)]+)\)'
matches = re.findall(pattern, md)
return matches

def find_md_links(self, md):
pattern = r'\[([^\]]+)\]\(([^)]+)\)'
matches = re.findall(pattern, md)
return matches

def find_image_md_links(self, md):
pattern = r'\!\[([^\]]+)\]\(([^)]+)\)'
matches = re.findall(pattern, md)
return matches

def article_title(self, project_key, article_id):
name = ""
try:
Expand Down Expand Up @@ -219,8 +284,9 @@ def process_linked_items(self, md, article_id, new_id):
try:
attachment = self.get_uploaded_file(article, project_id, upload_id)
if file_name not in self.transfered_attachments:
upload_attachment(new_id, file_name, "", self.confluence_url, self.confluence_username, self.confluence_password, raw=attachment)
url = upload_attachment(new_id, file_name, "", self.confluence_url, self.confluence_username, self.confluence_password, raw=attachment)
self.transfered_attachments.append(file_name)
self.transfered_links.append(url)
md = self.replace_md_links_with_confluence_links(md, project_id, upload_id, file_name)
except Exception as err:
md = self.replace_md_links_with_confluence_links(md, project_id, upload_id, file_name, error_message='*Item could not be transfered*')
Expand Down Expand Up @@ -288,11 +354,14 @@ def process_attachments(self, article_id, article):
for attachment in article.article_data['article']['attachments']:
if attachment[u'attachmentType'] == 'FILE' and attachment[u'attachmentType'] not in self.transfered_attachments:
attachment_name = attachment['details']['objectDisplayName']
logger.info("Uploading attachement {} / id: {}".format(attachment_name, attachment['smartId']))
article = self.wiki.get_article(article.article_id)
try:
file = article.get_uploaded_file(attachment['smartId'])
upload_attachment(article_id, attachment_name, "", self.confluence_url, self.confluence_username, self.confluence_password, raw=file)
url = upload_attachment(article_id, attachment_name, "", self.confluence_url, self.confluence_username, self.confluence_password, raw=file)
self.transfered_attachments.append(attachment_name)
self.transfered_links.append(url)
logger.info("Adding {}, {}, {}".format(file, attachment_name, url))
except Exception as err:
# get_uploaded_file not implemented yet on backend, older version of DSS
logger.info("Attachement could not be uploaded because of older DSS backend:{}".format(err))
Expand Down
2 changes: 1 addition & 1 deletion python-runnables/export-wiki/runnable.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def run(self, progress_callback):
else:
self.space_homepage_id = None

self.recurse_taxonomy(self.taxonomy, self.space_homepage_id)
self.recurse_taxonomy(self.taxonomy, ancestor=self.space_homepage_id)

if self.space_homepage_id is not None:
self.update_landing_page(self.space_homepage_id)
Expand Down