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