Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
  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">
    <form class="aui" 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                        }\n                    },\n                    {\n                        \"displayName\": \"Alice Brown\",\n                        \"emailAddress\": \"alice@example.com\",\n                        \"profilePicture\": {\n                            \"path\": \"https://icon-library.com/images/user-icon-png/user-icon-png-29.jpg\"\n                        }\n                    }\n                ];\n            }\n            else if(groupId == 2){\n                groupMembers = [\n                    {\n                        \"displayName\": \"Bob Johnson\",\n                        \"emailAddress\": \"bob@example.com\",\n                        \"profilePicture\": {\n                            \"path\": \"https://icon-library.com/images/user-png-icon/user-png-icon-5.jpg\"\n                        }\n                    },\n                    {\n                        \"displayName\": \"Charlie White\",\n                        \"emailAddress\": \"charlie@example.com\",\n                        \"profilePicture\": {\n                            \"path\": \"https://icon-library.com/images/user-image-icon/user-image-icon-10.jpg\"\n                        }\n                    }\n                ];\n            }\n            else{\n                groupMembers = [\n                    {\n                        \"displayName\": \"David Black\",\n                        \"emailAddress\": \"david@example.com\",\n                        \"profilePicture\": {\n                            \"path\": \"https://icon-library.com/images/icon-for-user/icon-for-user-1.jpg\"\n                        }\n                    }\n                ];\n            }\n        }\n\n        // Build and display the table\n        let table = `\n                <table class=\"aui\" border=\"1\" style=\"width: 100%; border-collapse: collapse;\">\n                <thead>\n                <tr>\n                    <th></th>                \n                    <th>Name</th>\n                    <th>Email</th>\n                </tr>\n                </thead>\n                <tbody>\n                `;\n\n        for (const member of groupMembers) {\n\n            let img = `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;\n            img = member.profilePicture?.path;\n            if (!img) {\n                img = `https://www.gravatar.com/avatar/${member.emailAddress}?s=32&d=identicon`;\n            }\n            else{\n                if(!img.startsWith(\"http\")){\n                    img = `${AP._hostOrigin}/${img}`;\n                }\n            }\n            table += `\n                        <tr>\n                            <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                        </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>"}