User:Polygnotus/Scripts/FilterInactiveOrBlocked.js: Difference between revisions

Content deleted Content added
No edit summary
No edit summary
Line 1:
// Wikipedia User Block & Activity Checker for common.js
// Checks if users are blocked and categorizesif themthey've been active in the last 12 months
// Features: maxlag support, HTTP error handling, exponential backoff retry (1min, 3min, 5min)
 
Line 68:
$('#status-area').show();
const statusDiv = $('#status-text');
statusDiv.html(`<div>Checking ${users.length} users for blocks and activity (last 12 months)...</div>`);
console.log(`Checking ${users.length} users for blocks and activity...`);
const activeUsers = [];
const blockedUsers = [];
const inactiveUsers = [];
// Disable the Check Users button during processing
Line 89 ⟶ 90:
try {
// Check if user is blocked first
const isBlocked = await isUserBlocked(userInfo.username);
Line 96 ⟶ 98:
console.log(`✗ ${userInfo.username} is blocked`);
} else {
activeUsers.push(userInfo.original);// If not blocked, check activity
statusDiv.append(`<divconst isActive style="color: #00af89;">${progress}await ✓ ${isUserActive(userInfo.username} is active</div>`);
console.log(`✓ ${userInfo.username} is active`);
if (isActive) {
activeUsers.push(userInfo.original);
statusDiv.append(`<div style="color: #00af89;">${progress} ✓ ${userInfo.username} is active (not blocked + active in last 12 months)</div>`);
console.log(`✓ ${userInfo.username} is active (not blocked + active in last 12 months)`);
} else {
inactiveUsers.push(userInfo.original);
statusDiv.append(`<div style="color: #fc3;">${progress} ⚠ ${userInfo.username} is not blocked but inactive (no edits in last 12 months)</div>`);
console.log(`⚠ ${userInfo.username} is not blocked but inactive (no edits in last 12 months)`);
}
}
Line 118 ⟶ 129:
// Re-enable button and show completion
checkButton.prop('disabled', false).text('Check Users');
statusDiv.append(`<div style="font-weight: bold; margin-top: 10px;">✓ Completed! ${activeUsers.length} active, ${blockedUsers.length} blocked, ${inactiveUsers.length} inactive</div>`);
statusDiv.scrollTop(statusDiv[0].scrollHeight);
// Display results
console.log("\n=== RESULTS ===");
console.log(`\nActive/Non-blocked users (not blocked + active in last 12 months) (${activeUsers.length}):`);
activeUsers.forEach(user => console.log(user));
console.log(`\nBlocked/Inactive users (${blockedUsers.length}):`);
blockedUsers.forEach(user => console.log(user));
console.log(`\nInactive users (not blocked but no edits in last 12 months) (${inactiveUsers.length}):`);
inactiveUsers.forEach(user => console.log(user));
// Show results in a separate dialog
displayResults(activeUsers, blockedUsers, inactiveUsers);
}
 
Line 185 ⟶ 199:
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed for ${username} (block check):`, error);
// Check if this is a maxlag error
Line 199 ⟶ 213:
if (attempt < maxRetries) {
const delay = retryDelays[attempt];
console.log(`Retryable error for ${username} (block check). Waiting ${delay / 1000}s before retry ${attempt + 2}...`);
await sleep(delay);
continue;
} else {
console.error(`Max retries exceeded for ${username} (block check). Final error:`, error);
throw new Error(`Failed after ${maxRetries + 1} attempts: ${error.message}`);
}
} else {
// Non-retryable error, fail immediately
console.error(`Non-retryable error for ${username} (block check):`, error);
throw error;
}
}
}
}
 
async function isUserActive(username) {
const maxRetries = 3;
const retryDelays = [60000, 180000, 300000]; // 1min, 3min, 5min in milliseconds
const cutoffDate = new Date();
cutoffDate.setMonth(cutoffDate.getMonth() - 12); // 12 months ago
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const api = new mw.Api();
const response = await api.get({
action: 'query',
format: 'json',
list: 'usercontribs',
ucuser: username,
uclimit: 1,
maxlag: 5 // Wait if server lag is more than 5 seconds
});
const usercontribs = response.query.usercontribs;
if (usercontribs && usercontribs.length > 0) {
const lastContrib = usercontribs[0];
const timestamp = lastContrib.timestamp;
// Parse timestamp (format: 2024-01-15T10:30:45Z)
const lastActivity = new Date(timestamp);
return lastActivity > cutoffDate;
}
return false; // No contributions found
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed for ${username} (activity check):`, error);
// Check if this is a maxlag error
if (error.code === 'maxlag') {
const lagTime = error.lag || 5;
console.log(`Server lag detected (${lagTime}s). Waiting before retry...`);
await sleep((lagTime + 1) * 1000); // Wait lag time + 1 second
continue;
}
// Check for HTTP error codes that warrant retry
if (isRetryableError(error)) {
if (attempt < maxRetries) {
const delay = retryDelays[attempt];
console.log(`Retryable error for ${username} (activity check). Waiting ${delay / 1000}s before retry ${attempt + 2}...`);
await sleep(delay);
continue;
} else {
console.error(`Max retries exceeded for ${username} (activity check). Final error:`, error);
throw new Error(`Failed after ${maxRetries + 1} attempts: ${error.message}`);
}
} else {
// Non-retryable error, fail immediately
console.error(`Non-retryable error for ${username} (activity check):`, error);
throw error;
}
Line 248 ⟶ 326:
}
 
function displayResults(activeUsers, blockedUsers, inactiveUsers) {
// Create a results dialog
const resultsHtml = `
<div style="max-height: 400px500px; overflow-y: auto;">
<h3>Active/Non-blocked Users (not blocked + active in last 12 months) (${activeUsers.length})</h3>
<textarea readonly style="width: 100%; height: 150px120px; font-family: monospace; margin-bottom: 10px;">
${activeUsers.join('\n')}</textarea>
<h3>Blocked/Inactive Users (${blockedUsers.length})</h3>
<textarea readonly style="width: 100%; height: 150px120px; font-family: monospace; margin-bottom: 10px;">
${blockedUsers.join('\n')}</textarea>
<h3>⚠ Inactive Users (not blocked but no edits in last 12 months) (${inactiveUsers.length})</h3>
<textarea readonly style="width: 100%; height: 120px; font-family: monospace;">
${inactiveUsers.join('\n')}</textarea>
</div>
`;
Line 264 ⟶ 346:
// Create and show results dialog (non-modal)
$('<div>').html(resultsHtml).dialog({
title: 'User Block & Activity Check Results',
width: 600700,
height: 500600,
modal: false,
resizable: true,
Line 280 ⟶ 362:
navigator.clipboard.writeText(blockedUsers.join('\n')).then(() => {
mw.notify('Blocked users copied to clipboard!', { type: 'success' });
}).catch(() => {
mw.notify('Failed to copy to clipboard', { type: 'error' });
});
},
'Copy Inactive Users': function() {
navigator.clipboard.writeText(inactiveUsers.join('\n')).then(() => {
mw.notify('Inactive users copied to clipboard!', { type: 'success' });
}).catch(() => {
mw.notify('Failed to copy to clipboard', { type: 'error' });
Line 299 ⟶ 388:
portletId,
'#',
'Check User Blocks & Activity',
't-check-blocks',
'Check if users are blocked and active (last 12 months)'
);