From 081272c177992b2d5e1789e22f6add03b804123d Mon Sep 17 00:00:00 2001 From: Andrii Sosiuk <andrii.sosiuk@seco.com> Date: Tue, 5 Nov 2024 14:39:42 +0100 Subject: [PATCH] YT-260: Inherit restrictions from the parent Confluence page In each release, a Confluence page is created with expected restrictions specifying who can edit or update the page. Confluence automatically inherits "read" restrictions from the parent page, but "edit/update" restrictions are not inherited by design in Confluence. This ensures that restrictions are manually inherited from the parent page. Since the Confluence Python API module lacks functionality for setting restrictions, direct HTTP requests are used with the `requests` library instead of the Confluence module. --- build-pipeline.yml | 1 + scripts/confluence_create_or_update_page.py | 64 +++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/build-pipeline.yml b/build-pipeline.yml index f6f8524c..5c5a549b 100644 --- a/build-pipeline.yml +++ b/build-pipeline.yml @@ -655,6 +655,7 @@ workflow: [ -n "$line" ] && LABEL_ARGS="${LABEL_ARGS} --label=$line"; done < confluence-labels.txt - .gitlab-ci/scripts/confluence_create_or_update_page.py + --inherit-parent-restrictions --username="${CONFLUENCE_USERNAME}" --token="${CONFLUENCE_TOKEN}" --space-id="${CONFLUENCE_SPACE}" diff --git a/scripts/confluence_create_or_update_page.py b/scripts/confluence_create_or_update_page.py index 29c0c355..f92cc237 100755 --- a/scripts/confluence_create_or_update_page.py +++ b/scripts/confluence_create_or_update_page.py @@ -1,13 +1,26 @@ #!/usr/bin/env python3 import argparse +import json import requests from atlassian import Confluence +from requests.auth import HTTPBasicAuth import common +def str_to_bool(argument): # Helper, converter for parsing boolean argument values + if isinstance(argument, bool): + return argument + if argument.lower() in {"true", "yes", "1"}: + return True + elif argument.lower() in {"false", "no", "0"}: + return False + else: + raise argparse.ArgumentTypeError("Boolean value expected.") + + def main(): # Create parser and add possible command line arguments parser = argparse.ArgumentParser() @@ -68,6 +81,16 @@ def main(): required=False, ) + parser.add_argument( + "--inherit-parent-restrictions", + help="Inherit restrictions from parent page (default: false)", + dest="inherit_parent_restrictions", + type=str_to_bool, + nargs="?", + const=True, + default=False, + ) + # Parse command line arguments args, _ = parser.parse_known_args() @@ -131,6 +154,47 @@ def main(): for label in args.label: confluence.set_page_label(page["id"], label) + if args.inherit_parent_restrictions: + # Retrieve all restrictions applied to the parent page + parent_restrictions = confluence.get_all_restrictions_for_content( + args.parent_id + ) + # The retrieved data includes restrictions/permissions as well as references to the parent page. + # Before applying it to the new page, we need to remove these old references. + # For more details on the data structure, refer to: + # https://developer.atlassian.com/cloud/confluence/rest/v1/api-group-content-restrictions/#api-wiki-rest-api-content-id-restriction-get + + # Reset '_links' and '_expandable' fields from pointing to the parent page + restrictions_request = {"results": []} + + for key, value in parent_restrictions.items(): + if key == "_links" or key == "_expandable": + continue + if "_links" in value.keys(): + value["_links"] = {} + if "_expandable" in value.keys(): + value["_expandable"] = {} + + restrictions_request["results"].append(value) + + # Directly making this request, as the current Confluence module lacks methods for setting restrictions + + response = requests.request( + "PUT", + f'{args.confluence_url}/wiki/rest/api/content/{page["id"]}/restriction', + headers={ + "Accept": "application/json", + "Content-Type": "application/json", + }, + auth=HTTPBasicAuth(args.username, args.token), + data=json.dumps(restrictions_request), + ) + if response.ok: + print("Page restrictions have been updated.") + else: + print("Could not update page restrictions !") + exit(f"ERROR: {response.text}") + except requests.exceptions.HTTPError as e: exit(f"ERROR: {e}") -- GitLab