User:Username/BlockAbuser.js: Difference between revisions

From Test Wiki
Jump to navigation Jump to search
Content deleted Content added
No edit summary
No edit summary
Line 7: Line 7:
const userData = {}; // username => { latestLogId, extraHits, $li, $userLink, allLinks: [] }
const userData = {}; // username => { latestLogId, extraHits, $li, $userLink, allLinks: [] }
const ipRegex = /^(?:\d{1,3}\.){3}\d{1,3}$|:/;
const ipRegex = /^(?:\d{1,3}\.){3}\d{1,3}$|:/;
const api = new mw.Api();


function getUsernameFromHref(href) {
function getUsernameFromHref(href) {
Line 14: Line 15:
}
}


// Collect user info, group links by username
// 1. Collect user info, group links by username
$content.find('li').each(function () {
$content.find('li').each(function () {
const $li = $(this);
const $li = $(this);
Line 47: Line 48:
$li: $li,
$li: $li,
$userLink: $link,
$userLink: $link,
allLinks: [$link]
allLinks: [$link],
blocked: false // to be updated after API call
};
};
} else {
} else {
Line 61: Line 63:
});
});


// Delink all but most recent user link per user
// 2. Delink all but most recent user link per user
Object.entries(userData).forEach(([username, data]) => {
Object.entries(userData).forEach(([username, data]) => {
data.allLinks.forEach(($link) => {
data.allLinks.forEach(($link) => {
Line 70: Line 72:
});
});


// 3. Check blocked status via API for all users
// Add control button above log
const $btn = $('<button>')
const usernames = Object.keys(userData);
if (usernames.length === 0) {
.text('Open all user AbuseLogs, talk deletion, and show summary')
// No users found, just add the button and return
.css({
margin: '1em 0',
addButtonAndSetup(userData);
padding: '6px 12px',
return;
}
cursor: 'pointer'
});


// MediaWiki API query to check if users are blocked
$content.prepend($btn);
api.get({

action: 'query',
$btn.on('click', function () {
list: 'users',
const usernames = Object.keys(userData);
if (usernames.length === 0) {
ususers: usernames.join('|'),
usprop: 'blockinfo'
alert('No users found to process.');
}).done(function (data) {
return;
if (data && data.query && data.query.users) {
data.query.users.forEach(user => {
if (user.blockid) {
const u = user.name;
if (userData[u]) {
userData[u].blocked = true;
}
}
});
}
}


// Now update UI with "(blocked)" labels
let summaryLines = [];
usernames.forEach(username => {
Object.entries(userData).forEach(([username, data]) => {
const data = userData[username];
if (data.blocked) {
// Append (blocked) after the user link (or text node)
const latestLogId = data.latestLogId;
const extraHits = parseInt(data.extraHits, 10);
const $userLink = data.$userLink;
// Check if (blocked) is already there to avoid duplicates
if (!$userLink.next('.blocked-label').length) {
$('<span>')
.text(' (blocked)')
.addClass('blocked-label')
.css({ color: 'red', fontWeight: 'bold', marginLeft: '4px' })
.insertAfter($userLink);
}
}
});


addButtonAndSetup(userData);
// Open filtered AbuseLog tab
}).fail(function () {
const abuseLogUrl = mw.util.getUrl('Special:AbuseLog', {
wpSearchUser: username
// If API fails, just add the button without blocked labels
});
addButtonAndSetup(userData);
});
window.open(abuseLogUrl, '_blank');


// 4. Add control button and handle click
// Open User Talk deletion tab with prefilled reason
function addButtonAndSetup(userData) {
const talkDeleteUrl = mw.util.getUrl('Special:Delete/' + 'User_talk:' + encodeURIComponent(username), {
const $btn = $('<button>')
reason: `Talk page of an indefinitely blocked user that has little value. The content was: blahblah.`
.text('Open all user AbuseLogs, talk deletion, and show summary')
.css({
margin: '1em 0',
padding: '6px 12px',
cursor: 'pointer'
});
});
window.open(talkDeleteUrl, '_blank');


// Compose summary line
$content.prepend($btn);

let line = `[[Special:AbuseLog/${latestLogId}]]`;
if (extraHits > 0) {
$btn.on('click', function () {
const usernames = Object.keys(userData);
line += ` (+[[Special:AbuseLog/${username}|${extraHits}]])`;
if (usernames.length === 0) {
alert('No users found to process.');
return;
}
}
summaryLines.push(line);
});


const summaryText =
let summaryLines = [];
usernames.forEach(username => {
'Spambot or spam-only accounts detected. Details:\n' +
summaryLines.join('\n');
const data = userData[username];
const latestLogId = data.latestLogId;
const extraHits = parseInt(data.extraHits, 10);


// Open filtered AbuseLog tab
alert(summaryText);
const abuseLogUrl = mw.util.getUrl('Special:AbuseLog', {
});
wpSearchUser: username
});
window.open(abuseLogUrl, '_blank');

// Open User Talk deletion tab with prefilled reason
const talkDeleteUrl = mw.util.getUrl('Special:Delete/' + 'User_talk:' + encodeURIComponent(username), {
reason: `Talk page of an indefinitely blocked user that has little value. The content was: blahblah.`
});
window.open(talkDeleteUrl, '_blank');

// Compose summary line
let line = `[[Special:AbuseLog/${latestLogId}]]`;
if (extraHits > 0) {
line += ` (+[[Special:AbuseLog/${username}|${extraHits}]])`;
}
summaryLines.push(line);
});

const summaryText =
'Spambot or spam-only accounts detected. Details:\n' +
summaryLines.join('\n');

alert(summaryText);
});
}
});
});

Revision as of 02:31, 21 January 2026

mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery'], function () {
    if (mw.config.get('wgPageName') !== 'Special:AbuseLog') {
        return;
    }

    const $content = $('#mw-content-text');
    const userData = {}; // username => { latestLogId, extraHits, $li, $userLink, allLinks: [] }
    const ipRegex = /^(?:\d{1,3}\.){3}\d{1,3}$|:/;
    const api = new mw.Api();

    function getUsernameFromHref(href) {
        const parts = href.split('/wiki/User:');
        if (parts.length < 2) return null;
        return decodeURIComponent(parts[1]).replace(/_/g, ' ').trim();
    }

    // 1. Collect user info, group links by username
    $content.find('li').each(function () {
        const $li = $(this);

        const $userLinks = $li.find('a').filter(function () {
            const href = $(this).attr('href') || '';
            return href.includes('/wiki/User:');
        });

        if ($userLinks.length === 0) return;

        $userLinks.each(function () {
            const $link = $(this);
            const username = getUsernameFromHref($link.attr('href'));
            if (!username || ipRegex.test(username)) return;

            let logId = null;
            $li.find('a').each(function () {
                const href = $(this).attr('href') || '';
                const match = href.match(/Special:AbuseLog\/(\d+)/);
                if (match) {
                    logId = match[1];
                    return false;
                }
            });
            if (!logId) return;

            if (!userData[username]) {
                userData[username] = {
                    latestLogId: logId,
                    extraHits: 0,
                    $li: $li,
                    $userLink: $link,
                    allLinks: [$link],
                    blocked: false // to be updated after API call
                };
            } else {
                userData[username].allLinks.push($link);
                if (parseInt(logId) > parseInt(userData[username].latestLogId)) {
                    userData[username].latestLogId = logId;
                    userData[username].$li = $li;
                    userData[username].$userLink = $link;
                }
                userData[username].extraHits++;
            }
        });
    });

    // 2. Delink all but most recent user link per user
    Object.entries(userData).forEach(([username, data]) => {
        data.allLinks.forEach(($link) => {
            if ($link[0] !== data.$userLink[0]) {
                $link.replaceWith(document.createTextNode($link.text()));
            }
        });
    });

    // 3. Check blocked status via API for all users
    const usernames = Object.keys(userData);
    if (usernames.length === 0) {
        // No users found, just add the button and return
        addButtonAndSetup(userData);
        return;
    }

    // MediaWiki API query to check if users are blocked
    api.get({
        action: 'query',
        list: 'users',
        ususers: usernames.join('|'),
        usprop: 'blockinfo'
    }).done(function (data) {
        if (data && data.query && data.query.users) {
            data.query.users.forEach(user => {
                if (user.blockid) {
                    const u = user.name;
                    if (userData[u]) {
                        userData[u].blocked = true;
                    }
                }
            });
        }

        // Now update UI with "(blocked)" labels
        Object.entries(userData).forEach(([username, data]) => {
            if (data.blocked) {
                // Append (blocked) after the user link (or text node)
                const $userLink = data.$userLink;
                // Check if (blocked) is already there to avoid duplicates
                if (!$userLink.next('.blocked-label').length) {
                    $('<span>')
                        .text(' (blocked)')
                        .addClass('blocked-label')
                        .css({ color: 'red', fontWeight: 'bold', marginLeft: '4px' })
                        .insertAfter($userLink);
                }
            }
        });

        addButtonAndSetup(userData);
    }).fail(function () {
        // If API fails, just add the button without blocked labels
        addButtonAndSetup(userData);
    });

    // 4. Add control button and handle click
    function addButtonAndSetup(userData) {
        const $btn = $('<button>')
            .text('Open all user AbuseLogs, talk deletion, and show summary')
            .css({
                margin: '1em 0',
                padding: '6px 12px',
                cursor: 'pointer'
            });

        $content.prepend($btn);

        $btn.on('click', function () {
            const usernames = Object.keys(userData);
            if (usernames.length === 0) {
                alert('No users found to process.');
                return;
            }

            let summaryLines = [];
            usernames.forEach(username => {
                const data = userData[username];
                const latestLogId = data.latestLogId;
                const extraHits = parseInt(data.extraHits, 10);

                // Open filtered AbuseLog tab
                const abuseLogUrl = mw.util.getUrl('Special:AbuseLog', {
                    wpSearchUser: username
                });
                window.open(abuseLogUrl, '_blank');

                // Open User Talk deletion tab with prefilled reason
                const talkDeleteUrl = mw.util.getUrl('Special:Delete/' + 'User_talk:' + encodeURIComponent(username), {
                    reason: `Talk page of an indefinitely blocked user that has little value. The content was: blahblah.`
                });
                window.open(talkDeleteUrl, '_blank');

                // Compose summary line
                let line = `[[Special:AbuseLog/${latestLogId}]]`;
                if (extraHits > 0) {
                    line += ` (+[[Special:AbuseLog/${username}|${extraHits}]])`;
                }
                summaryLines.push(line);
            });

            const summaryText =
                'Spambot or spam-only accounts detected. Details:\n' +
                summaryLines.join('\n');

            alert(summaryText);
        });
    }
});