User:Username/BlockAbuser.js: Difference between revisions

From Test Wiki
Jump to navigation Jump to search
Content deleted Content added
hopefully this makes my life easier
No edit summary
Line 1: Line 1:
mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery'], function () {
mw.loader.using(['mediawiki.util', 'mediawiki.api', 'jquery'], function () {
// Only run on the exact Special:AbuseLog main page
if (mw.config.get('wgPageName') !== 'Special:AbuseLog') {
if (mw.config.get('wgPageName') !== 'Special:AbuseLog') {
return;
return;
Line 6: Line 5:


const $content = $('#mw-content-text');
const $content = $('#mw-content-text');
const userData = {}; // username => { latestLogId, extraHits, $li, $userLink, allLinks: [] }
const seenUsers = new Set();
const userData = {}; // username => { latestLogId, extraHits, $li, $userLink }

const ipRegex = /^(?:\d{1,3}\.){3}\d{1,3}$|:/;
const ipRegex = /^(?:\d{1,3}\.){3}\d{1,3}$|:/;


// Helper: decode username from URL
function getUsernameFromHref(href) {
function getUsernameFromHref(href) {
const parts = href.split('/wiki/User:');
const parts = href.split('/wiki/User:');
Line 18: Line 14:
}
}


// Scan all <li> entries (AbuseLog entries)
// Collect user info, group links by username
$content.find('li').each(function () {
$content.find('li').each(function () {
const $li = $(this);
const $li = $(this);


const $userLinks = $li.find('a').filter(function () {
// Find first user link inside this <li>
const $userLink = $li.find('a').filter(function () {
const href = $(this).attr('href') || '';
const href = $(this).attr('href') || '';
return href.includes('/wiki/User:');
return href.includes('/wiki/User:');
}).first();
});


if ($userLink.length === 0) return; // no user link in this li
if ($userLinks.length === 0) return;


$userLinks.each(function () {
const username = getUsernameFromHref($userLink.attr('href'));
if (!username) return;
const $link = $(this);
const username = getUsernameFromHref($link.attr('href'));
if (ipRegex.test(username)) return; // skip IPs
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]) {
// Find AbuseLog id from any 'details' or 'examine' link inside this <li>
let logId = null;
userData[username] = {
latestLogId: logId,
$li.find('a').each(function () {
const href = $(this).attr('href') || '';
extraHits: 0,
const match = href.match(/Special:AbuseLog\/(\d+)/);
$li: $li,
if (match) {
$userLink: $link,
logId = match[1];
allLinks: [$link]
return false; // break loop
};
} 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++;
}
}
});
});

if (!logId) return;

// Store or update userData with most recent log id
if (!userData[username]) {
userData[username] = { latestLogId: logId, extraHits: 0, $li: $li, $userLink: $userLink };
} else {
if (parseInt(logId) > parseInt(userData[username].latestLogId)) {
userData[username].latestLogId = logId;
userData[username].$li = $li;
userData[username].$userLink = $userLink;
}
userData[username].extraHits++;
}
});
});


// Delink all but most recent user link per user
// Insert checkboxes once per user, inside their latest abuse log <li> before username link
Object.entries(userData).forEach(([username, data]) => {
Object.entries(userData).forEach(([username, data]) => {
data.allLinks.forEach(($link) => {
if (data.$userLink.prev('.blockabuser-checkbox').length) return; // checkbox already exists
if ($link[0] !== data.$userLink[0]) {

$link.replaceWith(document.createTextNode($link.text()));
const $checkbox = $('<input>', {
type: 'checkbox',
}
});
class: 'blockabuser-checkbox',
'data-username': username,
'data-latestlogid': data.latestLogId,
'data-extrahits': data.extraHits
}).css({
marginRight: '6px',
verticalAlign: 'middle',
cursor: 'pointer'
}).attr('title', 'Select this user for block review');

data.$userLink.before($checkbox);
});
});


// Add the control button above the log
// Add control button above log
const $btn = $('<button>')
const $btn = $('<button>')
.text('Open selected user AbuseLogs and generate summary')
.text('Open all user AbuseLogs, talk deletion, and show summary')
.css({
.css({
margin: '1em 0',
margin: '1em 0',
Line 91: Line 82:


$btn.on('click', function () {
$btn.on('click', function () {
const checked = $('.blockabuser-checkbox:checked');
const usernames = Object.keys(userData);
if (!checked.length) {
if (usernames.length === 0) {
alert('Please select at least one user.');
alert('No users found to process.');
return;
return;
}
}


let summaryLines = [];
let summaryLines = [];
checked.each(function () {
usernames.forEach(username => {
const $cb = $(this);
const data = userData[username];
const username = $cb.data('username');
const latestLogId = data.latestLogId;
const latestLogId = $cb.data('latestlogid');
const extraHits = parseInt(data.extraHits, 10);
const extraHits = parseInt($cb.data('extrahits'), 10);


// Open AbuseLog filtered by user in a new tab
// Open filtered AbuseLog tab
const abuseLogUrl = mw.util.getUrl('Special:AbuseLog', {
const abuseLogUrl = mw.util.getUrl('Special:AbuseLog', {
wpSearchUser: username
wpSearchUser: username
});
});
window.open(abuseLogUrl, '_blank');
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
// Compose summary line

Revision as of 02:29, 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}$|:/;

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

    // 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]
                };
            } 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++;
            }
        });
    });

    // 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()));
            }
        });
    });

    // Add control button above log
    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);
    });
});