User:TheAstorPastor/common.js: Difference between revisions
From Test Wiki
Content deleted Content added
Undo revision 60266 by TheAstorPastor (talk) Tags: Replaced Undo Reverted |
No edit summary Tag: Reverted |
||
| Line 1: | Line 1: | ||
// Only run on Test Wiki:Request for Permissions page |
|||
if (mw.config.get('wgTitle') === 'Request for permissions' && |
|||
mw.config.get('wgNamespaceNumber') === 4) { // NS 4 is "Project" namespace (Test Wiki:) |
|||
$(document).ready(function() { |
|||
//importScript('User:Joepayne/grantBureaucrat.js'); // Backlink: [[User:Joepayne/grantBureaucrat.js]] |
|||
// Initialize the script |
|||
importScript('User:Joepayne/stripRights.js'); // Backlink: [[User:Joepayne/stripRights.js]] |
|||
testWikiRfPManager.init(); |
|||
//importScript('User:MacFan4000/grantAdmin.js'); // Backlink: [[User:MacFan4000/grantAdmin.js]] |
|||
}); |
|||
//importScript('User:Kiteretsu/js/all-in-one.js'); // Backlink: [[User:Kiteretsu/js/all-in-one.js]] |
|||
//importScript('User:DodoMan/chatbot.js'); // Backlink: [[User:DodoMan/chatbot.js]] |
|||
const testWikiRfPManager = { |
|||
importScript('User:JJBullet/findInactiveSysops.js'); // Backlink: [[User:JJBullet/findInactiveSysops.js]] |
|||
// Configuration |
|||
importScript('User:Harvici/find-archived-section.js'); // Backlink: [[User:Harvici/find-archived-section.js]] |
|||
config: { |
|||
importScript('User:Harvici/UTCLiveClock.js'); // Backlink: [[User:Harvici/UTCLiveClock.js]] |
|||
// Rights that can be assigned with corresponding templates |
|||
importScript('User:Harvici/Twinkle-preferences-toolbar.js'); // Backlink: [[User:Harvici/Twinkle-preferences-toolbar.js]] |
|||
rights: { |
|||
importScript('User:Kiteretsu/rollbackSum.js'); // Backlink: [[User:Kiteretsu/rollbackSum.js]] |
|||
'sysop': { |
|||
importScript('User:Kiteretsu/DiscussionCloser.js'); // Backlink: [[User:Kiteretsu/DiscussionCloser.js]] |
|||
displayName: 'Administrator', |
|||
importScript('User:TheAstorPastor/VisualEditorEverywhere.js'); // Backlink: [[User:TheAstorPastor/VisualEditorEverywhere.js]] |
|||
template: '{{administrator granted}} [[User:TheAstorPastor|<span style="font-family:Segoe print; color:#8B0000; text-shadow:gray 0.2em 0.2em 0.4em;">The AP </span>]] ([[User talk:TheAstorPastor|<span style="font-family:Segoe print; color:#AA336A">''talk''</span>]]) 13:57, 11 April 2025 (UTC)' |
|||
}, |
|||
'bureaucrat': { |
|||
displayName: 'Bureaucrat', |
|||
template: '{{bureaucrat granted}} [[User:TheAstorPastor|<span style="font-family:Segoe print; color:#8B0000; text-shadow:gray 0.2em 0.2em 0.4em;">The AP </span>]] ([[User talk:TheAstorPastor|<span style="font-family:Segoe print; color:#AA336A">''talk''</span>]]) 13:57, 11 April 2025 (UTC)' |
|||
}, |
|||
'interface-admin': { |
|||
displayName: 'Interface Administrator', |
|||
template: '{{interface administrator granted}} [[User:TheAstorPastor|<span style="font-family:Segoe print; color:#8B0000; text-shadow:gray 0.2em 0.2em 0.4em;">The AP </span>]] ([[User talk:TheAstorPastor|<span style="font-family:Segoe print; color:#AA336A">''talk''</span>]]) 13:57, 11 April 2025 (UTC)' |
|||
}, |
|||
'non-stewardsuppress': { |
|||
displayName: 'Suppressor', |
|||
template: '{{done}}. [[User:TheAstorPastor|<span style="font-family:Segoe print; color:#8B0000; text-shadow:gray 0.2em 0.2em 0.4em;">The AP </span>]] ([[User talk:TheAstorPastor|<span style="font-family:Segoe print; color:#AA336A">''talk''</span>]]) 13:57, 11 April 2025 (UTC)' |
|||
}, |
|||
'abusefilter-admin': { |
|||
displayName: 'Abuse Filter Administrator', |
|||
template: '{{done}}. [[User:TheAstorPastor|<span style="font-family:Segoe print; color:#8B0000; text-shadow:gray 0.2em 0.2em 0.4em;">The AP </span>]] ([[User talk:TheAstorPastor|<span style="font-family:Segoe print; color:#AA336A">''talk''</span>]]) 13:57, 11 April 2025 (UTC)' |
|||
} |
|||
} |
|||
}, |
|||
// Initialize the script |
|||
init: function() { |
|||
// Check if user has the required permissions |
|||
if (!mw.config.get('wgUserGroups').includes('sysop')) { |
|||
console.log('TestWiki RfP Manager: User does not have sysop rights'); |
|||
return; |
|||
} |
|||
// Load required styles |
|||
this.loadStyles(); |
|||
// Process each RfP section |
|||
this.processRfPSections(); |
|||
}, |
|||
// Load CSS styles for the script |
|||
loadStyles: function() { |
|||
mw.loader.addStyleTag(` |
|||
.twrm-container { |
|||
background-color: #f8f9fa; |
|||
border: 1px solid #a2a9b1; |
|||
border-radius: 3px; |
|||
padding: 12px; |
|||
margin: 10px 0; |
|||
box-shadow: 0 1px 2px rgba(0,0,0,0.1); |
|||
} |
|||
.twrm-header { |
|||
font-weight: bold; |
|||
margin-bottom: 8px; |
|||
color: #222; |
|||
font-size: 14px; |
|||
padding-bottom: 5px; |
|||
border-bottom: 1px solid #eaecf0; |
|||
} |
|||
.twrm-controls { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
gap: 10px; |
|||
align-items: center; |
|||
margin-bottom: 8px; |
|||
} |
|||
.twrm-select { |
|||
padding: 6px 8px; |
|||
border: 1px solid #a2a9b1; |
|||
border-radius: 2px; |
|||
background-color: white; |
|||
min-width: 200px; |
|||
} |
|||
.twrm-button { |
|||
padding: 6px 12px; |
|||
background-color: #36c; |
|||
color: white; |
|||
border: none; |
|||
border-radius: 2px; |
|||
cursor: pointer; |
|||
font-weight: bold; |
|||
} |
|||
.twrm-button:hover { |
|||
background-color: #447ff5; |
|||
} |
|||
.twrm-button:disabled { |
|||
background-color: #c8ccd1; |
|||
cursor: not-allowed; |
|||
} |
|||
.twrm-result { |
|||
margin-top: 10px; |
|||
padding: 8px; |
|||
background-color: #eaf3ff; |
|||
border: 1px solid #c8ccd1; |
|||
border-radius: 2px; |
|||
display: none; |
|||
} |
|||
.twrm-copy-button { |
|||
padding: 4px 8px; |
|||
background-color: #f8f9fa; |
|||
border: 1px solid #a2a9b1; |
|||
border-radius: 2px; |
|||
margin-top: 8px; |
|||
cursor: pointer; |
|||
} |
|||
.twrm-copy-button:hover { |
|||
background-color: #eaecf0; |
|||
} |
|||
.twrm-user-info { |
|||
margin-bottom: 8px; |
|||
font-style: italic; |
|||
} |
|||
.twrm-success { |
|||
color: #14866d; |
|||
font-weight: bold; |
|||
margin-top: 5px; |
|||
display: none; |
|||
} |
|||
`); |
|||
}, |
|||
// Process all RfP sections on the page |
|||
processRfPSections: function() { |
|||
const self = this; |
|||
// Find all h2 headers which typically denote user request sections |
|||
$('.mw-parser-output > h2').each(function() { |
|||
const $header = $(this); |
|||
const username = $header.find('.mw-headline').text().trim(); |
|||
if (username) { |
|||
// Find the section content |
|||
let $section = $header.nextUntil('h2, h1'); |
|||
// Extract requested right from the section |
|||
const requestedRight = self.extractRequestedRight($section); |
|||
// Create rights manager UI |
|||
self.createRightsManagerUI($header, username, requestedRight); |
|||
} |
|||
}); |
|||
}, |
|||
// Extract the requested right from section content |
|||
extractRequestedRight: function($section) { |
|||
let rightText = ''; |
|||
// Look for the "Requested right" line |
|||
$section.each(function() { |
|||
const text = $(this).text(); |
|||
if (text.includes('Requested right')) { |
|||
// Extract the right from the text |
|||
const match = text.match(/Requested right[:\s]*([^*\n]+)/i); |
|||
if (match && match[1]) { |
|||
rightText = match[1].trim(); |
|||
} |
|||
return false; // Break the loop |
|||
} |
|||
}); |
|||
// Map common variations to our defined rights |
|||
const rightMap = { |
|||
'administrator': 'sysop', |
|||
'admin': 'sysop', |
|||
'sysop': 'sysop', |
|||
'bureaucrat': 'bureaucrat', |
|||
'crat': 'bureaucrat', |
|||
'interface administrator': 'interface-admin', |
|||
'interface admin': 'interface-admin', |
|||
'suppressor': 'non-stewardsuppress', |
|||
'suppress': 'non-stewardsuppress', |
|||
'abuse filter administrator': 'abusefilter-admin', |
|||
'abusefilter admin': 'abusefilter-admin', |
|||
'abuse filter admin': 'abusefilter-admin' |
|||
}; |
|||
// Try to match the requested right |
|||
for (const [key, value] of Object.entries(rightMap)) { |
|||
if (rightText.toLowerCase().includes(key.toLowerCase())) { |
|||
return value; |
|||
} |
|||
} |
|||
return ''; // No match found |
|||
}, |
|||
// Create the UI for managing rights |
|||
createRightsManagerUI: function($header, username, preselectedRight) { |
|||
const self = this; |
|||
// Create container |
|||
const $container = $('<div>') |
|||
.addClass('twrm-container') |
|||
.insertAfter($header); |
|||
// Create header |
|||
$('<div>') |
|||
.addClass('twrm-header') |
|||
.text('Rights Manager') |
|||
.appendTo($container); |
|||
// Add user info |
|||
$('<div>') |
|||
.addClass('twrm-user-info') |
|||
.text(`Request by: ${username}`) |
|||
.appendTo($container); |
|||
// Create controls container |
|||
const $controls = $('<div>') |
|||
.addClass('twrm-controls') |
|||
.appendTo($container); |
|||
// Create right selection dropdown |
|||
const $select = $('<select>') |
|||
.addClass('twrm-select') |
|||
.appendTo($controls); |
|||
// Add default option |
|||
$('<option>') |
|||
.val('') |
|||
.text('Select right to grant...') |
|||
.appendTo($select); |
|||
// Add options for each available right |
|||
for (const [right, config] of Object.entries(this.config.rights)) { |
|||
$('<option>') |
|||
.val(right) |
|||
.text(config.displayName) |
|||
.prop('selected', right === preselectedRight) |
|||
.appendTo($select); |
|||
} |
|||
// Create grant button |
|||
const $grantButton = $('<button>') |
|||
.addClass('twrm-button') |
|||
.text('Grant Rights') |
|||
.prop('disabled', !preselectedRight) |
|||
.appendTo($controls); |
|||
// Create API button |
|||
const $apiButton = $('<button>') |
|||
.addClass('twrm-button') |
|||
.text('Grant via API') |
|||
.prop('disabled', !preselectedRight) |
|||
.appendTo($controls); |
|||
// Create result container |
|||
const $result = $('<div>') |
|||
.addClass('twrm-result') |
|||
.appendTo($container); |
|||
// Create copy button |
|||
const $copyButton = $('<button>') |
|||
.addClass('twrm-copy-button') |
|||
.text('Copy to Clipboard') |
|||
.appendTo($result); |
|||
// Create success message |
|||
const $success = $('<div>') |
|||
.addClass('twrm-success') |
|||
.text('Rights granted successfully!') |
|||
.appendTo($container); |
|||
// Handle select change |
|||
$select.on('change', function() { |
|||
const hasSelection = $(this).val() !== ''; |
|||
$grantButton.prop('disabled', !hasSelection); |
|||
$apiButton.prop('disabled', !hasSelection); |
|||
$result.hide(); |
|||
$success.hide(); |
|||
}); |
|||
// Handle grant button click |
|||
$grantButton.on('click', function() { |
|||
const selectedRight = $select.val(); |
|||
if (selectedRight && self.config.rights[selectedRight]) { |
|||
// Show template response |
|||
$result.show().text(self.config.rights[selectedRight].template); |
|||
} |
|||
}); |
|||
// Handle API button click |
|||
$apiButton.on('click', function() { |
|||
const selectedRight = $select.val(); |
|||
if (selectedRight && self.config.rights[selectedRight]) { |
|||
// Set button to loading state |
|||
const originalText = $apiButton.text(); |
|||
$apiButton.text('Processing...').prop('disabled', true); |
|||
// Grant the right using MediaWiki API |
|||
self.grantRightViaAPI(username, selectedRight) |
|||
.then(function(success) { |
|||
if (success) { |
|||
$success.show(); |
|||
$result.show().text(self.config.rights[selectedRight].template); |
|||
} else { |
|||
$result.show().text('Error granting rights. Please try again or use manual method.'); |
|||
} |
|||
}) |
|||
.catch(function() { |
|||
$result.show().text('Error granting rights. Please try again or use manual method.'); |
|||
}) |
|||
.finally(function() { |
|||
// Reset button state |
|||
$apiButton.text(originalText).prop('disabled', false); |
|||
}); |
|||
} |
|||
}); |
|||
// Handle copy button click |
|||
$copyButton.on('click', function() { |
|||
const textToCopy = $result.text(); |
|||
navigator.clipboard.writeText(textToCopy).then(function() { |
|||
$copyButton.text('Copied!'); |
|||
setTimeout(function() { |
|||
$copyButton.text('Copy to Clipboard'); |
|||
}, 2000); |
|||
}); |
|||
}); |
|||
}, |
|||
// Grant rights via MediaWiki API |
|||
grantRightViaAPI: function(username, right) { |
|||
return new Promise(function(resolve) { |
|||
// Get API token |
|||
mw.user.getToken('csrf').then(function(token) { |
|||
// Make API request to grant right |
|||
new mw.Api().postWithToken('csrf', { |
|||
action: 'userrights', |
|||
user: username, |
|||
add: right, |
|||
reason: 'Granted per request on [[Test Wiki:Request for Permissions]]', |
|||
token: token |
|||
}) |
|||
.done(function() { |
|||
resolve(true); |
|||
}) |
|||
.fail(function() { |
|||
resolve(false); |
|||
}); |
|||
}); |
|||
}); |
|||
} |
|||
}; |
|||
} |
|||