Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

version3

...

  1. Edit Confluence page, add HTML Macro for Confluence or Advanced Macro for Confluence to your page

...

  1. The macro editor will be opened. Copy & paste below code to the macro and adjust it based on your requirement.

Code Block
languagejs

<div id=\"group-audit-container\">\n
    <label<form forclass=\"groupName\aui">Select Group: </label>\n    <select id=\"groupName\">\n style="margin-top: 20px; margin-left: 10px; margin-right: 10px;" onsubmit="return false;" >
        <label for="groupName">Select Group: </label>
        <select id="groupName" class="select">
            <option value="1">administrators</option>
            <option value="2">site-admins</option>
            <option value="3">confluence-users</option>
        </select>
        <button id="fetchGroupDetails" class="aui-button">Fetch Group Details</button>
        <div id="groupDetails" style="margin-top: 20px; border: 1px solid #ddd; padding: 10px;"></div>
    </form>
</div>

<script>    
    fetchGroups();
    async function fetchGroups(){

        let groups = [];
        let url = `/rest/api/group`;
        while(url){

            try{
                const response = await AP.request({
                    url: url,            
                    type: "GET",
                    contentType: "application/json"
                });

                let data = JSON.parse(response.body);

                if (!data.results || data.results.length === 0) {
                    break;
                }

                groups = groups.concat(data.results);
                url = data._links.next;        

            } catch (error) {
                console.error("Error:", error);
                url = undefined;
            }   
        }

        if(groups.length === 0){            
            return;
        }

        const groupSelect = document.getElementById("groupName");
        groupSelect.innerHTML = ""; // Clear existing options

        groups.forEach(group => {
            const option = document.createElement("option");
            option.value = group.id;
            option.textContent = group.name;
            groupSelect.appendChild(option);
        });
    }    

    async function fetchGroupMembers(groupId) {
        const groupDetailsDiv = document.getElementById("groupDetails");
        groupDetailsDiv.textContent = "Fetching group details...";

        let groupMembers = [];
        let url = `/rest/api/group/${groupId}/membersByGroupId`;

        while(url){

            try {
                const response = await AP.request({
                    url: url,            
                    type: "GET",
                    contentType: "application/json"
                });

                if (response.xhr.status !== 200) {
                    throw new Error(`Error fetching group members: ${response.statusText}`);
                }

                let data = JSON.parse(response.body);

                if (!data.results || data.results.length === 0) {                
                    break;
                }

                groupMembers = groupMembers.concat(data.results);
                url = data._links.next;             

            } catch (error) {
                console.error("Error:", error);
                groupDetailsDiv.textContent = "Failed to fetch group members. Check the console for details.";
                url = undefined;
            }
        }

        if (groupMembers.length === 0) {
            groupDetailsDiv.textContent = "No members found for this group.";
            return;            
        }

        // Build and display the table
        let table = `
                <table class="aui" border="1" style="width: 100%; border-collapse: collapse;">
                <thead>
                <tr>
                    <th></th>                
                    <th>Name</th>
                    <th>Email</th>
                </tr>
                </thead>
                <tbody>
                `;

        for (const member of groupMembers) {

            let img = `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;
            img = member.profilePicture?.path;
            if (!img) {
                img = `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;
            }
            else{
                if(!img.startsWith("http")){
                    img = `${AP._hostOrigin}/${img}`;
                }
            }
            table += `
                        <tr>
                            <td><img style="width:32px; hight:32px;" src="${img}" alt="Avatar"></td>
                            <td>${member.displayName}</td>
                            <td>${member.emailAddress || "N/A"}</td>                            
                        </tr>
                        `;
        }

        table += "</tbody></table>";
        groupDetailsDiv.innerHTML = table;
    }

    document.getElementById("fetchGroupDetails").addEventListener("click", () => {
        const groupId = document.getElementById("groupName").value.trim();

        if (!groupId) {
            alert("Please select a group.");
            return;
        }

        fetchGroupMembers(groupId);
    });   

</script>

  1. Publish your page and see the result:

Advanced html
version15
{"htmlContent":"\n<div id=\"group-audit-container\">\n    <form class=\"aui\" style=\"margin-top: 20px; margin-left: 10px; margin-right: 10px;\" onsubmit=\"return false;\" >\n        <label for=\"groupName\">Select Group: </label>\n        <select id=\"groupName\" class=\"select\">\n            <option value=\"1\">administrators</option>\n            <option value=\"2\">site-admins</option>\n            <option value=\"3\">confluence-users</option>\n        </select>\n        <button id=\"fetchGroupDetails\" class=\"aui-button\">Fetch Group Details</button>\n        <div id=\"groupDetails\" style=\"margin-top: 20px; border: 1px solid #ddd; padding: 10px;\"></div>\n    </form>\n</div>\n\n<script>\n    \n    fetchGroups();\n    async function fetchGroups(){\n\n        let groups = [];\n        let url = `/rest/api/group`;\n        while(url){\n\n            try{\n                const response = await AP.request({\n                    url: url,            \n                    type: \"GET\",\n                    contentType: \"application/json\"\n                });\n\n                let data = JSON.parse(response.body);\n\n                if (!data.results || data.results.length === 0) {\n                    break;\n                }\n\n                groups = groups.concat(data.results);\n                url = data._links.next;        \n\n            } catch (error) {\n                console.error(\"Error:\", error);\n                url = undefined;\n            }   \n        }\n\n        //console.log(groups);\n\n        if(groups.length === 0){\n\n            fetchGroupMembers(1); // Hardcoded group members for testing\n            //alert(\"No groups found\");\n            return;\n        }\n\n        const groupSelect = document.getElementById(\"groupName\");\n        groupSelect.innerHTML = \"\"; // Clear existing options\n\n        groups.forEach(group => {\n            const option = document.createElement(\"option\");\n            option.value = group.id;\n            option.textContent = group.name;\n            groupSelect.appendChild(option);\n        });\n    }\n    \n\n    async function fetchGroupMembers(groupId) {\n        const groupDetailsDiv = document.getElementById(\"groupDetails\");\n        groupDetailsDiv.textContent = \"Fetching group details...\";\n\n        let groupMembers = [];\n        let url = `/rest/api/group/${groupId}/membersByGroupId`;\n\n        while(url){\n\n            try {\n                const response = await AP.request({\n                    url: url,            \n                    type: \"GET\",\n                    contentType: \"application/json\"\n                });\n\n                if (response.xhr.status !== 200) {\n                    throw new Error(`Error fetching group members: ${response.statusText}`);\n                }\n\n                let data = JSON.parse(response.body);\n\n                if (!data.results || data.results.length === 0) {                \n                    break;\n                }\n\n                groupMembers = groupMembers.concat(data.results);\n                url = data._links.next;             \n\n            } catch (error) {\n                console.error(\"Error:\", error);\n                groupDetailsDiv.textContent = \"Failed to fetch group members. Check the console for details.\";\n                url = undefined;\n            }\n        }\n\n        if (groupMembers.length === 0) {\n            //groupDetailsDiv.textContent = \"No members found for this group.\";\n            //return;\n            if(groupId == 1){ // Hardcoded group members for testing              \n                groupMembers = [\n                    {\n                        \"displayName\": \"John Doe\",\n                        \"emailAddress\": \"john@example.com\",\n                        \"profilePicture\": {\n                            \"path\": \"https://icon-library.com/images/admin-user-icon/admin-user-icon-4.jpg\"\n                        }\n                    },\n                    {\n                        \"displayName\": \"Jane Smith\",\n                        \"emailAddress\": \"jane@example.com\",\n                        \"profilePicture\": {\n                            \"path\": \"https://icon-library.com/images/google-user-icon/google-user-icon-11.jpg\"\n              <option value=\"confluence-users-cloud-testing-910\">confluence-users-cloud-testing-910</option>\n        <option value=\"org-admins\">org-admins</option> }\n        <option value=\"confluence-users\">confluence-users</option>            },\n    </select>\n       <button id=\"fetchGroupDetails\">Fetch Group Details</button>\n    <div id=\"groupDetails\" style=\"margin-top: 20px; border: 1px solid #ddd; padding: 10px;\"></div>\n</div>\n\n<script>\n {\n                \n    fetchGroups();\n    async function fetchGroups(){\n\"displayName\": \"Alice Brown\",\n        let    groups = [];\n        let url = `/rest/api/group`;\n \"emailAddress\": \"alice@example.com\",\n            while(url){\n\n            try\"profilePicture\": {\n                const   response = await AP.request({\n         \"path\": \"https://icon-library.com/images/user-icon-png/user-icon-png-29.jpg\"\n           url: url,            }\n                    type: \"GET\",\}\n                    contentType: \"application/json\"\];\n                });\n\n            else if(groupId == 2){\n   let data = JSON.parse(response.body);\n\n          groupMembers = [\n    if (!data.results || data.results.length === 0) {\n          {\n          break;\n              \"displayName\": \"Bob }Johnson\n",\n                groups = groups.concat(data.results);        \"emailAddress\": \"bob@example.com\",\n                url = data._links.next;        \"profilePicture\": {\n\n            } catch (error) {\n                console.error(\"path\"Error:\", error); \"https://icon-library.com/images/user-png-icon/user-png-icon-5.jpg\"\n                url = undefined;\n            }   \n        }\n\n        console.log(groups);\n\n    },\n    const groupSelect = document.getElementById(\"groupName\");\n        groupSelect.innerHTML = \"\"; // Clear existing options\n{\n        groups.forEach(group => {\n            const option = document.createElement(\"option\"); \"displayName\": \"Charlie White\",\n            option.value = group.id;\n          \"emailAddress\":  option.textContent = group.name;\n\"charlie@example.com\",\n               groupSelect.appendChild(option);\n          });\"profilePicture\": {\n    }\n       \n\n    async function fetchGroupMembers(groupId) {\n        const groupDetailsDiv = document.getElementById(\"groupDetails\"); \"path\": \"https://icon-library.com/images/user-image-icon/user-image-icon-10.jpg\"\n        groupDetailsDiv.textContent  = \"Fetching group details...\";\n\n        let groupMembers = [];}\n        let url = `/rest/api/group/${groupId}/membersByGroupId`;\n\n            }\n                while(url){\n];\n            try {}\n            else{\n    const  response = await AP.request({\n       groupMembers = [\n           url: url,        {\n    \n                    type\"displayName\": \"GETDavid Black\",\n                     contentType   \"emailAddress\": \"application/jsondavid@example.com\",\n                });\n\n                if (response.xhr.status !== 200)  \"profilePicture\": {\n                       throw new Error(`Error fetching group members: ${response.statusText}`);\"path\": \"https://icon-library.com/images/icon-for-user/icon-for-user-1.jpg\"\n                }\n\n        }\n        let data = JSON.parse(response.body);\n\n         }\n       if (!data.results || data.results.length === 0) {   ];\n             }\n        }\n\n        // Build and display the break;table\n        let table = `\n     }\n\n           <table class=\"aui\" border=\"1\" style=\"width:  groupMembers = groupMembers.concat(data.results);\n100%; border-collapse: collapse;\">\n                <thead>\n url = data._links.next;             <tr>\n\n  n          } catch (error) {\n       <th></th>         console.error(\"Error:\", error);\n      \n          groupDetailsDiv.textContent = \"Failed to fetch group members. Check the console for details.\"; <th>Name</th>\n                 url  = undefined;<th>Email</th>\n             }\n   </tr>\n     }\n\n        if (groupMembers.length === 0) { </thead>\n            groupDetailsDiv.textContent = \"No members found for this group.<tbody>\";\n            return;\n        }`;\n\n        //for Build(const andmember displayof the table\ngroupMembers) {\n\n            let tableimg = ``https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;\n            img    <table border=\"1\" style=\"width: 100%; border-collapse: collapse;\">\ member.profilePicture?.path;\n            if    <thead>(!img) {\n                 <tr>img = `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;\n                <th>Name</th>}\n                <th>Email</th>else{\n                <th>Product Access</th>if(!img.startsWith(\"http\")){\n                </tr>\n    img            </thead>= `${AP._hostOrigin}/${img}`;\n                <tbody>}\n                `;}\n\n         for (const member oftable groupMembers)+= {`\n            // Display member info (dummy product access added for simplicity)\n      <tr>\n      table += `\n                    <td><img style=\"width:32px; hight:32px;\"  <tr>src=\"${img}\" alt=\"Avatar\"></td>\n                            <td>${member.displayName}</td>\n                            <td>${member.emailAddress || \"N/A\"}</td>\n                            <td>No Product Access API in Confluence Cloud</td>\n                        </tr>\n                        `;\n        }\n\n        table += \"</tbody></table>\";\n        groupDetailsDiv.innerHTML = table;\n    }\n\n    document.getElementById(\"fetchGroupDetails\").addEventListener(\"click\", () => {\n        const groupId = document.getElementById(\"groupName\").value.trim();\n\n        if (!groupId) {\n            alert(\"Please select a group.\");\n            return;\n        }\n\n        fetchGroupMembers(groupId);\n    });\n\n    \n\n</script>"}