Versions Compared

Key

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

...

version6

...

  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
    <form class=\"aui\" style=\"margin-top: 20px;\" onsubmit=\ 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(){
</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 groups = [];\n        let urldata = `/rest/api/group`JSON.parse(response.body);\n\n        while(url){\n\n        if (!data.results || data.results.length === 0)  try{\n                const\n response = await AP.request({\n                break;\n    url: url,            }\n\n                groupMembers = groupMembers.concat(data.results);\n  type: \"GET\",\n              url = data._links.next;        contentType: \"application/json\"     \n\n            } catch   });(error) {\n\n                let data = JSON.parse(response.bodyconsole.error(\"Error:\", error);\n\n                groupDetailsDiv.textContent  if (!data.results || data.results.length === 0) {= \"Failed to fetch group members. Check the console for details.\";\n                url =   breakundefined;\n                }\n\n        }\n\n        if groups(groupMembers.length = groups.concat(data.results);== 0) {\n                url = data._links.next;        \n//groupDetailsDiv.textContent = \"No members found for this group.\";\n            } catch (error) {//return;\n            if(groupId == 1){  console.error(\"Error:\", error);\n   // Hardcoded group members for testing             url = undefined;\n            }    groupMembers = [\n           }\n\n         //console.log(groups);\n{\n         if(groups.length === 0){\n               //alert(\"displayName\"No: groups\"John foundDoe\");,\n            return;\n        }\n\n        const groupSelect = document.getElementById(\"groupName\");\"emailAddress\": \"john@example.com\",\n        groupSelect.innerHTML = \"\"; // Clear existing options\n\n               groups.forEach(group => \"profilePicture\": {\n            const option = document.createElement(\"option\");\n            option.value = group.id;\n            option.textContent = group.name; \"path\": \"https://icon-library.com/images/admin-user-icon/admin-user-icon-4.jpg\"\n            groupSelect.appendChild(option);\n        });\n    }\n    \n\n    async function fetchGroupMembers(groupId) {\n        const groupDetailsDiv = document.getElementById(\"groupDetails\");\n    },\n     groupDetailsDiv.textContent = \"Fetching group details...\";\n\n        let groupMembers = [];{\n        let url = `/rest/api/group/${groupId}/membersByGroupId`;\n\n        while(url){\n\n     \"displayName\": \"Jane Smith\",\n     try {\n                 const response = await AP.request({ \"emailAddress\": \"jane@example.com\",\n                    url: url,   \"profilePicture\": {\n        \n                    type\"path\": \"GEThttps://icon-library.com/images/google-user-icon/google-user-icon-11.jpg\",\nn                       contentType: \"application/json\" }\n                    });,\n\n                if (response.xhr.status !== 200) {\n                    throw new Error(`Error fetching group members: ${response.statusText}`);\n                }\n \"displayName\": \"Alice Brown\",\n                let data = JSON.parse(response.body);\n\n     \"emailAddress\": \"alice@example.com\",\n          if (!data.results || data.results.length === 0) {                \"profilePicture\": {\n                    break;\n                 }\n\n\"path\": \"https://icon-library.com/images/user-icon-png/user-icon-png-29.jpg\"\n                     groupMembers  = groupMembers.concat(data.results);\n }\n                    }\n url = data._links.next;             \n];\n            } catch (error) {\n            else if(groupId   console.error(\"Error:\", error);== 2){\n                groupDetailsDiv.textContentgroupMembers = [\"Failedn to fetch group members. Check the console for details.\";\n           {\n     url = undefined;\n            }\n     \"displayName\": \"Bob  }Johnson\n",\n        if (groupMembers.length === 0) {\n            //groupDetailsDiv.textContent = \"No members found for this group.\";\"emailAddress\": \"bob@example.com\",\n            //return;\n            if(groupId == 1){\"profilePicture\": {\n                \n                groupMembers = [ \"path\": \"https://icon-library.com/images/user-png-icon/user-png-icon-5.jpg\"\n                    {\n    }\n                    \"displayName\": \"John Doe\"},\n                    {\n    \"emailAddress\": \"john@example.com\"\n                    \"displayName\":  }\"Charlie White\",\n                    {    \"emailAddress\": \"charlie@example.com\",\n                        \"displayNameprofilePicture\": \"Jane Smith\",\n{\n                            \"emailAddresspath\": \"janeĢ€@example.com\"https://icon-library.com/images/user-image-icon/user-image-icon-10.jpg\"\n                        },\n                    {}\n                        \"displayName\": \"Alice Brown\",\];\n            }\n            \"emailAddress\": \"alice@example.com\"else{\n                groupMembers =   }[\n                ];\n             }{\n            else if(groupId == 2){\n         \"displayName\": \"David Black\",\n     groupMembers = [\n                    {\"emailAddress\": \"david@example.com\",\n                        \"displayNameprofilePicture\": \"Bob Johnson\",\n{\n                            \"emailAddresspath\": \"bob@example.comhttps://icon-library.com/images/icon-for-user/icon-for-user-1.jpg\"\n                        },\n                    {}\n                        \"displayName\": \"Charlie White\",\];\n                        \"emailAddress\": \"charlie@example.com\"}\n        }\n\n        // Build and display the }table\n        let table       ];= `\n            }\n    <table class=\"aui\" border=\"1\" style=\"width: 100%;    else{border-collapse: collapse;\">\n                groupMembers = [<thead>\n                <tr>\n    {\n                <th></th>         \"displayName\": \"David Black\",\n     \n                   \"emailAddress\": \"david@example.com\"\ <th>Name</th>\n                    }<th>Email</th>\n                ];</tr>\n            }\n    </thead>\n    }\n\n        // Build and display the table<tbody>\n        let table = `\n         `;\n\n       <table class=\"aui\" border=\"1\" style=\"width: 100%; border-collapse: collapse;\"> for (const member of groupMembers) {\n\n            let img   <thead>= `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;\n            img    <tr>= member.profilePicture?.path;\n            if (!img) {\n  <th>Name</th>\n              img  <th>Email</th>= `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;\n            }\n    <th>Product Access</th>\n       else{\n         </tr>\n          if(!img.startsWith(\"http\")){\n      </thead>\n              img  <tbody>= `${AP._hostOrigin}/${img}`;\n                `;\n}\n        for (const member of groupMembers) {}\n            table += `\n // Display member info (dummy product access added for simplicity)\n            table += `<tr>\n                             <tr><td><img style=\"width:32px; hight:32px;\" 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>"}