User:BZPN/FindOutdatedPages.js

From Test Wiki
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
//<nowiki>
// Author: 
// License: 

mw.loader.using(['oojs-ui', 'mediawiki.util']).done(function () {
    var scriptActivationLink = mw.util.addPortletLink(
        'p-tb',
        '#',
        'Find Outdated Test Pages and Files',
        'pt-find-outdated-pages',
        'Finds and manages outdated test pages and files.',
        null,
        '#pt-adminlinks'
    );

    $(scriptActivationLink).click(function () {
        var progressBar = new OO.ui.ProgressBarWidget();
        var progressField = new OO.ui.FieldLayout(
            progressBar,
            {
                label: "Searching for outdated pages and files...",
                align: 'top'
            }
        );

        var textPanel = new OO.ui.PanelLayout({
            expanded: false,
            framed: false,
            padded: false,
        });

        var canDelete = false;
        var outdatedPagesAndFiles = [];

        function OutdatedPagesProc(config) {
            OutdatedPagesProc.super.call(this, config);
        }
        OO.inheritClass(OutdatedPagesProc, OO.ui.ProcessDialog);

        OutdatedPagesProc.static.name = "Outdated Pages and Files Process";
        OutdatedPagesProc.static.title = "List of Outdated Test Pages and Files:";
        OutdatedPagesProc.static.actions = [
            {
                action: "delete",
                label: "Delete Selected",
                flags: "primary"
            },
            {
                label: "Cancel",
                flags: "safe"
            }
        ];

        OutdatedPagesProc.prototype.initialize = function () {
            OutdatedPagesProc.super.prototype.initialize.apply(this, arguments);
            this.content = new OO.ui.FieldsetLayout();
            this.content.addItems([progressField]);
            this.content.$element.css('padding', '1em');
            this.$body.append(this.content.$element);
        };

        OutdatedPagesProc.prototype.getActionProcess = function (action) {
            var dialog = this;
            if (action && canDelete) {
                return new OO.ui.Process(function () {
                    if (action == "delete") {
                        deleteSelectedItems();
                    }
                    dialog.close({
                        action: action
                    });
                });
            }
            return OutdatedPagesProc.super.prototype.getActionProcess.call(this, action);
        };

        OutdatedPagesProc.prototype.getBodyHeight = function () {
            return this.content.$element.outerHeight(true);
        };

        var windowManager = new OO.ui.WindowManager();
        var outdatedPagesProc = new OutdatedPagesProc({
            size: "large"
        });

        windowManager.addWindows([outdatedPagesProc]);
        $('body').append(windowManager.$element);
        windowManager.openWindow(outdatedPagesProc);

        var totalPages = 0;
        var checkedPages = 0;

        // Fetch list of pages from specified namespaces
        function fetchPages(namespaces) {
            namespaces.forEach(function (ns) {
                $.getJSON(
                    mw.util.wikiScript('api'),
                    {
                        format: 'json',
                        action: 'query',
                        list: 'allpages',
                        apnamespace: ns, // Specify namespace
                        aplimit: 100, // Fetch up to 100 pages per request
                        apfilterredir: 'nonredirect' // Exclude redirects
                    }
                ).done(function (data) {
                    var pages = data.query.allpages;
                    totalPages += pages.length;

                    pages.forEach(function (page) {
                        checkPage(page);
                    });
                }).fail(function () {
                    console.log("Error fetching pages from namespace: " + ns);
                });
            });
        }

        // Fetch pages from specified namespaces
        fetchPages([0, 10, 2, 4]); // Main namespace (0), Template (10), User (2), TestWiki (4)

        $.getJSON(
            mw.util.wikiScript('api'),
            {
                format: 'json',
                action: 'query',
                list: 'allimages',
                ailimit: 100
            }
        ).done(function (data) {
            var files = data.query.allimages;
            totalPages += files.length;
            files.forEach(function (file) {
                checkFile(file);
            });
        }).fail(function () {
            console.log("Error fetching files.");
        });

        function checkPage(page) {
            $.getJSON(
                mw.util.wikiScript('api'),
                {
                    format: 'json',
                    action: 'query',
                    prop: 'revisions',
                    titles: page.title,
                    rvprop: 'timestamp|content',
                    rvslots: 'main',
                    rvlimit: 1
                }
            ).done(function (data) {
                var pageData = Object.values(data.query.pages)[0];
                var content = pageData.revisions[0].slots.main['*'];
                var isBlanked = content.trim() === "";

                if (isBlanked) {
                    outdatedPagesAndFiles.push({ title: page.title, status: "blanked page" });
                } else {
                    var lastEdit = new Date(pageData.revisions[0].timestamp);
                    var now = new Date();
                    var tenHoursAgo = new Date(now - 10 * 60 * 60 * 1000);
                    
                    if (lastEdit < tenHoursAgo && content.length < 10) {
                        outdatedPagesAndFiles.push({ title: page.title, status: "short content" });
                    }
                }

                checkedPages++;
                progressBar.setProgress(parseInt((checkedPages / totalPages) * 100));

                if (checkedPages === totalPages) {
                    listOutdatedItems();
                }
            }).fail(function () {
                console.log("Error checking page: " + page.title);
            });
        }

        function checkFile(file) {
            $.getJSON(
                mw.util.wikiScript('api'),
                {
                    format: 'json',
                    action: 'query',
                    titles: 'File:' + file.name,
                    prop: 'imageinfo|revisions|categories',
                    iiprop: 'timestamp|user|comment',
                    rvprop: 'content',
                    rvlimit: 1,
                    clshow: '!hidden',
                    cllimit: 'max'
                }
            ).done(function (data) {
                var fileData = Object.values(data.query.pages)[0];
                var description = fileData.revisions[0]['*'];
                var categories = fileData.categories ? fileData.categories.map(cat => cat.title) : [];
                var outOfScope = !description.includes('{{Information}}') && !categories.includes('Category:Non-test files');
                var isMaintScript = description.includes('Maintenance script') || description.includes('Uploaded by Maintenance script');

                if (outOfScope && !isMaintScript) {
                    checkFileUsage(file);
                } else {
                    checkedPages++;
                }
            }).fail(function () {
                console.log("Error checking file: " + file.name);
            });
        }

        function checkFileUsage(file) {
            $.getJSON(
                mw.util.wikiScript('api'),
                {
                    format: 'json',
                    action: 'query',
                    list: 'imageusage',
                    iutitle: 'File:' + file.name,
                    iulimit: 1
                }
            ).done(function (data) {
                if (data.query.imageusage.length === 0) {
                    outdatedPagesAndFiles.push({ title: 'File:' + file.name, status: 'unused file' });
                }

                checkedPages++;
                progressBar.setProgress(parseInt((checkedPages / totalPages) * 100));

                if (checkedPages === totalPages) {
                    listOutdatedItems();
                }
            }).fail(function () {
                console.log("Error checking file usage: " + file.name);
            });
        }

        function listOutdatedItems() {
            outdatedPagesAndFiles.sort((a, b) => a.title.localeCompare(b.title)).forEach(function (item) {
                var itemLink = `<li><input type="checkbox" class="page-checkbox" data-page="${item.title}"> <a href="/wiki/${item.title}">${item.title}</a> <span style="color: red;">(${item.status})</span></li>`;
                textPanel.$element.append(itemLink);
            });

            outdatedPagesProc.content.clearItems();
            outdatedPagesProc.content.addItems([textPanel]);
            outdatedPagesProc.updateSize();
            canDelete = true;
        }

        function deleteSelectedItems() {
            var selectedItems = [];
            $('.page-checkbox:checked').each(function () {
                selectedItems.push($(this).data('page'));
            });

            if (selectedItems.length === 0) {
                alert("No pages or files selected for deletion.");
                return;
            }

            selectedItems.forEach(function (item) {
                $.post(
                    mw.util.wikiScript('api'),
                    {
                        format: 'json',
                        action: 'delete',
                        title: item,
                        reason: 'Outdated test page or out of scope file - automated cleanup',
                        token: mw.user.tokens.get('csrfToken')
                    }
                ).done(function () {
                    console.log("Deleted item: " + item);
                }).fail(function () {
                    console.log("Error deleting item: " + item);
                });
            });

            alert("Selected pages and files have been deleted.");
        }
    });
});
//</nowiki>