Prevent Confluence Down by limiting attachment copying with js code (1min)

스크린샷 2024-07-19 오전 10.53.51.png

If attachment > 300 can't copy.

disable_copy.png

If your company uses Confluence Server/Data Center, make sure to apply and share this tip with the admin. It will fundamentally resolve the issue of Confluence going down (without any apparent reason). Simply copy and paste the following JavaScript code at
<confluence_url>/admin/editcustomhtml.action > At end of the BODY. It only takes 30 seconds.


The core of this code is to prevent the copying of a page if it has more than 300 attachments. When copying a page, the background process of copying all attachments from the original page can significantly impact Confluence's performance. There may even be pages with thousands of attachments. Additionally, no logs are generated.

Typically, a single page shouldn't need more than 300 attachments. You can adjust this 300-attachment threshold to fit your company's situation. By preventing the copying of heavy pages (which is very easy to apply), you can easily resolve the issue of Confluence going down.

 

<script>

AJS.toInit(function() {




    var pageId = AJS.Meta.get("page-id");




    function fetchAttachments(start, totalFetched) {

        AJS.$.ajax({

            url: "/rest/api/content/" + pageId + "/child/attachment?limit=200&start=" + start,

            type: "GET",

            success: function(data) {

                var attachmentCount = data.results.length;

                totalFetched += attachmentCount;




                if (attachmentCount === 200 && data._links.next) {

                    fetchAttachments(start + 200, totalFetched);

                } else {

                    displayAttachmentCount(totalFetched);

                }

            },

            error: function(error) {

                console.log("Failed to fetch attachment information.", error);

            }

        });

    }




    function displayAttachmentCount(count) {

        if (count > 30) {

            var color = 'black'; // Default color




            if (count > 100) {

                color = 'red';

            } else if (count > 50) {

                color = 'blue';

            }




            AJS.$('#action-menu-link').after('<span id="attachment-count" style="color:' + color + '">(' + count + ')</span>');

            document.getElementById('action-copy-page-link').innerHTML = '<span style="color:' + color + '"> Copy (' + count + ')</span>';

        }

    }




    fetchAttachments(0, 0);

});

</script>




<script>

document.addEventListener("DOMContentLoaded", function() {

    var pageId = AJS.Meta.get("page-id");




    function fetchAttachments(start, totalFetched) {

        AJS.$.ajax({

            url: "/rest/api/content/" + pageId + "/child/attachment?limit=200&start=" + start,

            type: "GET",

            success: function(data) {

                var attachmentCount = data.results.length;

                totalFetched += attachmentCount;




                if (attachmentCount === 200 && data._links.next) {

                    fetchAttachments(start + 200, totalFetched);

                } else {

                    displayAttachmentCount(totalFetched);

                }

            },

            error: function(error) {

                console.log("Failed to fetch attachment information.", error);

            }

        });

    }




    function displayAttachmentCount(count) {

        // Add event listener for 'Copy' link click.

        var copyPageLink = document.getElementById('action-copy-page-link');

        if (copyPageLink) {

            copyPageLink.addEventListener('click', function() {

                setTimeout(function() {

                    var copyAttachmentsContainer = document.getElementById('copy-attachments-container');

                    

                    if (copyAttachmentsContainer && count > 30) {

                        var color = 'black';

                        if (count > 100) {

                            color = 'red';

                        } else if (count > 50) {

                            color = 'blue';

                        }




                        var attachmentCountSpan = document.createElement('span');

                        attachmentCountSpan.textContent = ' (' + count + ')';

                        attachmentCountSpan.style.color = color;




                        copyAttachmentsContainer.appendChild(attachmentCountSpan);

                    }

                }, 500); // 500ms delay

            });

        }

    }




    // Start fetching the number of attachments.

    fetchAttachments(0, 0);

});




</script>




<script>

document.addEventListener("DOMContentLoaded", function() {

    var pageId = AJS.Meta.get("page-id");




    function fetchAttachments(start, totalFetched) {

        AJS.$.ajax({

            url: "/rest/api/content/" + pageId + "/child/attachment?limit=200&start=" + start,

            type: "GET",

            success: function(data) {

                var attachmentCount = data.results.length;

                totalFetched += attachmentCount;




                if (attachmentCount === 200 && data._links.next) {

                    fetchAttachments(start + 200, totalFetched);

                } else {

                    processAttachmentCount(totalFetched);

                }

            },

            error: function(error) {

                console.log("Failed to fetch attachment information.", error);

            }

        });

    }




    function processAttachmentCount(count) {

        if (count >= 300) {

            // Disable 'Copy' button if there are more than 300 attachments.

            var copyPageLink = document.getElementById('action-copy-page-link');

            if (copyPageLink) {

                copyPageLink.style.pointerEvents = 'none';

                copyPageLink.style.opacity = '0.5';

            }

        }

    }




    // Start fetching the number of attachments.

    fetchAttachments(0, 0);

});




/** Add text to the lock icon */

function add_restrict_text() {

    /** Restriction message */

    // Get the element

    var element = document.getElementById("content-metadata-page-restrictions");




    // Get the value of the original-title attribute

    var originalTitle = element.getAttribute("title");




    // Print the value

    console.log(originalTitle);




    /** Check for class existence (red color) */

    // Get the element

    var element = document.getElementById("content-metadata-page-restrictions");

    var locked = true;




    // Check if the class exists

    if (element.classList.contains("aui-iconfont-unlocked")) {

        console.log("aui-iconfont-unlocked class exists.");

        locked = false;

        if(element.classList.contains("restricted")) {

            locked = true;

        }

    }




    /**

     * originalTitle: Text displayed when hovering over the lock icon

     * locked: true==unlocked icon, false==lock icon

     */

    var existingElement = document.getElementById("page-banner-end");




    // Create a new span element

    var newSpanElement = document.createElement("div");




    // Add attributes to the new span element (e.g., id and class)

    newSpanElement.setAttribute("id", "new-span-id");

    newSpanElement.setAttribute("class", "new-span-class");




    // Set top margin

    newSpanElement.style.marginTop = "10px";

    // Add text content to the new span element

    newSpanElement.textContent = "No Restrictions";

    if(originalTitle == "Restrictions apply" || originalTitle == "제한 적용") {

        if(locked) {

            newSpanElement.textContent = "View/Edit Restrictions";

            newSpanElement.style.color = "red";

        } else {

            newSpanElement.textContent = "Edit Restrictions";

            newSpanElement.style.color = "blue"; 

        }

    }




    // Insert the new span element after the existing element

    existingElement.insertAdjacentElement('afterend', newSpanElement);




}




// Get the target element to observe

var targetElement = document.getElementById("content-metadata-page-restrictions");




// Create a MutationObserver

var observer = new MutationObserver(function(mutations) {

  // Call the function to handle class changes

  handleClassChange();

});




// Observer configuration

var config = { attributes: true, attributeFilter: ["class"] };

observer.observe(targetElement, config);




// Define the function to handle class changes

function handleClassChange() {

  // Write the function or code you want to execute here.

  console.log("Class has changed!");

  // You can call additional functions or write more code here.

  // Get the element

  var elementToRemove = document.getElementById("new-span-id");




    // Check if the element exists and remove it

    if (elementToRemove) {

    elementToRemove.parentNode.removeChild(elementToRemove);

    } else {

    console.log("Element to remove not found.");

    }




  add_restrict_text();

}




add_restrict_text();




</script>

 

1 comment

Reese
Contributor
December 3, 2024

Surely Scriptrunner @Reece Lander _ScriptRunner - The Adaptavist Group_ can add some safeguards for number of attachments on a page?
Or better yet - Atlassian can fix underlying issue? Agree 300 attachments might be excessive, but I am not sure I pages close to this many attachments.

Comment

Log in or Sign up to comment
TAGS
AUG Leaders

Atlassian Community Events