User:Synoman Barris/common.js: Difference between revisions

From TestWiki
Content added Content deleted
(Undid revision 41490 by Synoman Barris (talk))
Tag: Undo
(Undid revision 41489 by Synoman Barris (talk))
Tag: Undo
Line 1: Line 1:
// <nowiki>
//<nowiki>
$(function() {
/*
var namespace = mw.config.get('wgNamespaceNumber'),
* SpamUserPage
pageName = mw.config.get('wgPageName'),
*
myUserName = mw.config.get('wgUserName'),
* This gadget deletes a user page, blocks the user, and notifies them on their
userName = mw.config.get('wgRelevantUserName'),
* talk page. See [[User:Mr. Stradivarius/gadgets/SpamUserPage]] for
templateName = "script",
* documentation.
blockReason,
*
api;
* To install the script, add the following to your personal .js page:
importScript( 'User:Mr. Stradivarius/gadgets/SpamUserPage.js' ); // Linkback: [[User:Mr. Stradivarius/gadgets/SpamUserPage.js]]
* Author: Mr. Stradivarius
* Licence: MIT
*
* The MIT License (MIT)
*
* Copyright (c) 2015 Mr. Stradivarius
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


if([0,2,3].indexOf(namespace) !== -1) {
mw.loader.using( [
'mediawiki.api',
mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).done( function() {
api = new mw.Api();
'mediawiki.Title',
mw.util.addPortletLink(
'mediawiki.util',
'p-cactions', 'javascript:void(0)',
'oojs-ui'
'Block vandal', 'ca-spamublock', 'Delete user page and execute {{uw-spamublock}} on current user'
], function () {
);
"use strict";
} );


$('#ca-spamublock').on('click', function() {
var config = mw.config.get( [
if (confirm('This script will delete the current user page, block the relevant user or page creator as {{uw-spamublock}} and leave that template on their talk page, or the template specified at [[Special:MyPage/uw-spamublock]], if present.\n\nARE YOU SURE YOU WANT TO PROCEED?')) {
'wgTitle',
$('#ca-spamublock').text('Please wait...');
'wgNamespaceNumber',
if(!userName) {
'wgUserName'
api.get({
] );
action: 'query',
prop: 'revisions',
titles: pageName,
rvdir: 'newer',
rvlimit: '1',
rvprop: 'user'
}).then(function(data) {
var pages = data.query.pages;
userName = pages[Object.keys(pages)[0]].revisions[0].user;
getTemplate();
});
} else {
getTemplate();
}
}
});
}


function getTemplate() {
// Exit if we are not in user or user talk space.
api.get({
if ( config.wgNamespaceNumber !== 2 && config.wgNamespaceNumber !== 3 ) {
action: 'query',
return;
titles: 'User:'+myUserName+'/uw-spamublock'
}
}).then(function(data) {
var query = data.query.pages;
if(Object.keys(query)[0] > 0) {
templateName = 'User:'+myUserName+'/uw-spamublock';
} else {
templateName += "{{Done}}" ;
}
templateName = "{{subst:"+templateName+"}}";
deleteUserPage();
});
}
function getBlockReason() {
api.get({
action: 'query',
titles: 'User:'+myUserName+'/spamublock-message'
}).then(function(data) {
var query = data.query.pages;
if(Object.keys(query)[0] > 0) {
blockReason = '{{User:'+myUserName+'/spamublock-message}}';
} else {
blockReason = 'Testing blocking script';
}
blockUser();
});
}


function deleteUserPage() {
/**************************************************************************
api.postWithToken("delete", {
* ApiManager class
action: 'delete',
**************************************************************************/
reason: 'Testing script',
title: pageName
}).then(function(deleteData) {
$("#mw-content-text").html(
"<p><b>Deleted</b> page <a href='"+mw.util.getUrl(pageName)+"'>"+pageName+"</a> <i>(<a href='"+mw.util.getUrl('WP:G11')+"'>G11</a>: Unambiguous <a href='"+mw.util.getUrl('WP:NOTADVERTISING')+"'>advertising</a> or promotion)</i></p>"
);
getBlockReason();
},function(error) {
$("#mw-content-text").html(
"<p><b>Error</b> deleting page "+pageName+": "+error+"</p>"
);
});
}


var ApiManager = function () {
function blockUser() {
api.postWithToken("block", {
var i, len, preset, key, customPresetIds, defaultPreset, hasUserPreference;
action: 'block',
allowusertalk: false,
autoblock: true,
nocreate: true,
reason: blockReason,
user: userName
}).then(function(blockData) {
$("#mw-content-text").append(
"<p><b>Blocked</b> <a href='"+mw.util.getUrl('User:'+userName)+"'>"+userName+"</a> (account creation blocked) with an expiry time of indefinite <i>(<span id='spamublock-blocked-reason'></span>)</i></p>"
);
$('<span/>').text(blockReason).appendTo("#spamublock-blocked-reason");
templateUser();
}, function(error) {
$("#mw-content-text").append(
"<p><b>Error</b> blocking <a href='"+mw.util.getUrl('User:'+userName)+"'>"+userName+"</a>: "+error+"</p>"
);
});
}


function templateUser() {
this.api = new mw.Api();
var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
this.currentTitle = new mw.Title( config.wgTitle, config.wgNamespaceNumber );
d = new Date();
this.userName = this.currentTitle.getMainText().replace( /\/.*$/, '' );
this.userTalkTitle = new mw.Title( this.userName, 3 );
this.userPreferences = typeof window.SpamUserPage === 'object' ? window.SpamUserPage : {};


api.postWithToken( "edit", {
// Set up caches
action: "edit",
this.menuItemCache = {};
section: 'new',

sectiontitle: monthNames[d.getMonth()] + ' ' + d.getFullYear(),
// Get presets
summary: "You have been indefinitely blocked because am testing a script",
this.presets = {};
text: "\n"+templateName,
this.presetIds = [];
title: "User talk:"+userName
customPresetIds = []; // Track custom preset IDs separately so that we can put them first.
}).then(function(editData) {

$("#mw-content-text").append(
function setPreset( obj, thisArg ) {
"<p><b>Edited</b> <a href='"+mw.util.getUrl('User talk:'+userName)+"'>User talk:"+userName+"</a>: Created new section with template "+templateName+"</p>" +
var ret = thisArg.presets[ obj.id ] || {};
"<p><b>Complete (<a href='javascript:document.location.reload()'>reload</a>)</b></p>"
ret.id = obj.id;
);
for ( key in ApiManager.static.presetDefaults ) {
},function(error) {
if ( ApiManager.static.presetDefaults.hasOwnProperty( key ) ) {
$("#mw-content-text").append(
if ( obj[ key ] !== undefined ) {
"<p><b>Error</b> editing <a href='"+mw.util.getUrl('User talk:'+userName)+"'>User talk:"+userName+"</a>: "+error+"</p>"
ret[ key ] = obj[ key ];
);
}
});
if ( ret[ key ] === undefined ) {
}
ret[ key ] = ApiManager.static.presetDefaults[ key ];
});
}
//</nowiki>
}
}
thisArg.presets[ ret.id ] = ret;
}

for ( i = 0, len = ApiManager.static.presets.length; i < len; i++ ) {
preset = ApiManager.static.presets[ i ];
this.presetIds.push( preset.id );
setPreset( preset, this );
}
if ( $.isArray( this.userPreferences.presets ) ) {
for ( i = 0, len = this.userPreferences.presets.length; i < len; i++ ) {
preset = this.userPreferences.presets[ i ];
if ( typeof preset === 'object' ) {
if ( typeof preset.id === 'string' ) {
if ( !this.presets[ preset.id ] ) {
customPresetIds.push( preset.id );
}
setPreset( preset, this );
} else {
throw new Error( "missing or invalid 'id' field in custom preset #" + i );
}
}
}
}
this.presetIds = customPresetIds.concat( this.presetIds );

// Get defaults
this.defaults = {};
hasUserPreference = false;
if ( typeof this.userPreferences.preset === 'string' ) {
defaultPreset = this.userPreferences.preset;
if ( !this.presets[ defaultPreset ] ) {
throw new Error( "'" + defaultPreset + "' is not a valid preset ID" );
}
} else {
defaultPreset = ApiManager.static.otherDefaults.preset;
}

function setDefaults( obj, thisArg ) {
for ( key in obj ) {
if ( obj.hasOwnProperty( key ) ) {
if ( thisArg.userPreferences[ key ] !== undefined ) {
hasUserPreference = true;
thisArg.defaults[ key ] = thisArg.userPreferences[ key ];
} else if ( thisArg.presets[ defaultPreset ][ key ] !== undefined ) {
thisArg.defaults[ key ] = thisArg.presets[ defaultPreset ][ key ];
} else {
thisArg.defaults[ key ] = ApiManager.static.otherDefaults[ key ];
}
}
}
}

setDefaults( ApiManager.static.presetDefaults, this );
setDefaults( ApiManager.static.otherDefaults, this );
if ( hasUserPreference ) {
this.defaults.preset = null;
} else {
this.defaults.preset = defaultPreset;
}
};

OO.initClass( ApiManager );

ApiManager.static.presets = [
{
id: 'spamublock',
label: 'Spam-only account, username violation',
deletesummary: '[[WP:CSD#G11|G11]]: Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion',
blocksummary: '{{uw-spamublock}}',
editsummary: 'You have been indefinitely blocked from editing because your account is being ' +
'used only for [[WP:SPAM|spam or advertising]] and your username is a violation of the ' +
'[[WP:U|username policy]].',
template: '{{subst:uw-spamublock|sig=yes}}'
},
{
id: 'soablock',
label: 'Spam-only account',
deletesummary: '[[WP:CSD#G11|G11]]: Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion',
blocksummary: '[[WP:Spam|Spam]] / [[WP:NOTADVERTISING|advertising]]-only account',
editsummary: 'You have been indefinitely blocked from editing because your account is being ' +
'used only for [[WP:SPAM|spam, advertising, or promotion]]',
template: '{{subst:uw-soablock|sig=yes}}'
},
{
id: 'sblock',
label: 'Spamming',
deletesummary: '[[WP:CSD#G11|G11]]: Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion',
expiry: '31 hours',
blocksummary: 'Using Wikipedia for [[WP:SPAM|spam]] purposes',
editsummary: 'You have been blocked from editing for using Wikipedia for [[WP:SPAM|spam]] purposes',
template: '{{subst:uw-sblock|sig=yes}}'
},
{
id: 'vaublock',
label: 'Vandalism-only account, username violation',
deletesummary: '[[WP:CSD#G3|G3]]: [[WP:Vandalism|Vandalism]]',
blocksummary: '{{uw-vaublock}}',
editsummary: 'You have been indefinitely blocked from editing because your account is being ' +
'[[WP:VOA|used only for vandalism]] and your username is a blatant violation of the ' +
'[[WP:U|username policy]]',
template: '{{subst:uw-vaublock|sig=yes}}'
},
{
id: 'voablock',
label: 'Vandalism-only account',
deletesummary: '[[WP:CSD#G3|G3]]: [[WP:Vandalism|Vandalism]]',
blocksummary: '[[WP:Vandalism-only account|Vandalism-only account]]',
editsummary: 'You have been indefinitely blocked from editing because your account is being ' +
'[[WP:VOA|used only for vandalism]]',
template: '{{subst:uw-voablock|sig=yes}}'
},
{
id: 'vblock',
label: 'Vandalism',
deletesummary: '[[WP:CSD#G3|G3]]: [[WP:Vandalism|Vandalism]]',
expiry: '31 hours',
blocksummary: '[[WP:Vandalism|Vandalism]]',
editsummary: 'You have been blocked from editing for persistent [[WP:VAND|vandalism]]',
template: '{{subst:uw-vblock|sig=yes}}'
},
{
id: 'softerblock',
label: 'Promotional username, soft block',
deletesummary: '[[WP:CSD#G11|G11]]: Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion',
blocksummary: '{{uw-softerblock}}',
editsummary: 'You have been indefinitely blocked from editing because your [[WP:U|username]] ' +
'gives the impression that the account represents a group, organization or website.',
template: '{{subst:uw-softerblock|sig=yes}}',
nocreate: false,
autoblock: false
},
{
id: 'causeblock',
label: 'Username of a non-profit, soft block',
deletesummary: '[[WP:CSD#G11|G11]]: Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion',
blocksummary: '{{uw-causeblock}}',
editsummary: 'You have been indefinitely blocked from editing because your [[WP:U|username]] ' +
'gives the impression that the account represents a group, organization or website.',
template: '{{subst:uw-causeblock|sig=yes}}',
nocreate: false,
autoblock: false
},
{
id: 'copyrightblock',
label: 'Copyright violations',
deletesummary: '[[WP:CSD#G12|G12]]: Unambiguous [[WP:CV|copyright infringement]]',
expiry: '24 hours',
blocksummary: '[[WP:Copyright violations|Copyright violations]]',
editsummary: 'You have been blocked from editing for continued [[WP:COPYVIO|copyright infringement]]',
template: '{{subst:uw-copyrightblock|sig=yes}}'
},
{
id: 'myblock',
label: 'Using Wikipedia as a blog or web host',
deletesummary: '[[WP:CSD#U5|U5]]: [[WP:NOTWEBHOST|Misuse of Wikipedia as a web host]]',
expiry: '24 hours',
blocksummary: 'Using Wikipedia as a [[WP:NOTMYSPACE|blog, web host, social networking site or forum]]',
editsummary: 'You have been blocked from editing for using user and/or article pages ' +
'as a [[WP:NOTMYSPACE|blog, web host, social networking site or forum]]',
template: '{{subst:uw-myblock|sig=yes}}'
},
{
id: 'npblock',
label: 'Creating nonsense pages',
deletesummary: '[[WP:CSD#G1|G1]]: [[WP:PN|Patent nonsense]], meaningless, or incomprehensible',
expiry: '24 hours',
blocksummary: 'Creating [[WP:Patent nonsense|patent nonsense]] or other inappropriate pages',
editsummary: 'You have been blocked from editing for creating [[WP:PN|nonsense pages]]',
template: '{{subst:uw-npblock|sig=yes}}'
}
];

ApiManager.static.menuDefaults = {
expiry: [
'indefinite',
'3 hours',
'12 hours',
'24 hours',
'31 hours',
'36 hours',
'48 hours',
'60 hours',
'72 hours',
'1 week',
'2 weeks',
'1 month',
'3 months',
'6 months',
'1 year',
'2 years',
'3 years'
],
deletesummary: [
// If you change the order of these, please also update the number of the
// default deletion summary in ApiManager.static.presetDefaults.
'[[WP:CSD#G1|G1]]: [[WP:PN|Patent nonsense]], meaningless, or incomprehensible',
'[[WP:CSD#G2|G2]]: Test page',
'[[WP:CSD#G3|G3]]: [[WP:Vandalism|Vandalism]]',
'[[WP:CSD#G3|G3]]: Blatant [[WP:Do not create hoaxes|hoax]]',
'[[WP:CSD#G4|G4]]: Recreation of a page that was [[WP:DEL|deleted]] per a [[WP:XFD|deletion discussion]]',
'[[WP:CSD#G5|G5]]: Creation by a [[WP:BLOCK|blocked]] or [[WP:BAN|banned]] user in violation of block or ban',
'[[WP:CSD#G6|G6]]: Housekeeping and routine (non-controversial) cleanup',
'[[WP:CSD#G7|G7]]: One author who has requested deletion or blanked the page',
'[[WP:CSD#G8|G8]]: Page dependent on a deleted or nonexistent page',
'[[WP:CSD#G10|G10]]: [[WP:ATP|Attack page]] or negative unsourced [[WP:BLP|BLP]]',
'[[WP:CSD#G11|G11]]: Unambiguous [[WP:NOTADVERTISING|advertising]] or promotion',
'[[WP:CSD#G12|G12]]: Unambiguous [[WP:CV|copyright infringement]]',
'[[WP:CSD#G13|G13]]: Abandoned [[WP:AFC|Article for creation]]? to retrieve it, see [[WP:REFUND/G13]]',
'[[WP:CSD#U1|U1]]: User request to delete page in own userspace',
'[[WP:CSD#U2|U2]]: Userpage or subpage of a nonexistent user',
'[[WP:CSD#U3|U3]]: [[WP:NFC|Non-free]] [[Help:Gallery|gallery]]',
'[[WP:CSD#U5|U5]]: [[WP:NOTWEBHOST|Misuse of Wikipedia as a web host]]'
],
blocksummary: [
'{{uw-spamublock}}',
'[[WP:Spam|Spam]] / [[WP:NOTADVERTISING|advertising]]-only account',
'Using Wikipedia for [[WP:Spam|spam]] or [[WP:NOTADVERTISING|advertising]] purposes',
'{{uw-vaublock}}',
'[[WP:Vandalism-only account|Vandalism-only account]]',
'[[WP:Vandalism|Vandalism]]',
'[[WP:Copyright violations|Copyright violations]]',
'{{uw-softerblock}}',
'{{uw-causeblock}}',
'Creating [[WP:Attack page|attack pages]]',
'Violations of the [[WP:Biographies of living persons|Biographies of living persons]] policy',
'Creating [[WP:Patent nonsense|patent nonsense]] or other inappropriate pages',
'[[WP:Disruptive editing|Disruptive editing]]',
'[[WP:No personal attacks|Personal attacks]] or [[WP:Harassment|harassment]]',
'[[WP:Blocking policy#Evasion of blocks|Block evasion]]',
'Abusing [[WP:Sock puppetry|multiple accounts]]',
'[[WP:Long-term abuse|Long-term abuse]]',
],
editsummary: [
'You have been blocked from editing because your account ' +
'is being used only for [[WP:SPAM|spam or advertising]] and your ' +
'username is a violation of the [[WP:U|username policy]].',
'You have been blocked from editing for [[WP:SOAP|advertising or self-promotion]]',
'You have been blocked from editing for using Wikipedia for [[WP:SPAM|spam]] purposes',
'You have been blocked from editing because your account is being ' +
'used only for [[WP:SPAM|spam, advertising, or promotion]]',
'You have been indefinitely blocked from editing because your account ' +
'is being [[WP:VOA|used only for vandalism]] and your username is ' +
'a blatant violation of the [[WP:U|username policy]]',
'You have been blocked from editing for persistent [[WP:VAND|vandalism]]',
'You have been blocked from editing because your account is being ' +
'[[WP:VOA|used only for vandalism]]',
'You have been indefinitely blocked from editing because your [[WP:U|username]] ' +
'gives the impression that the account represents a group, organization or website.',
'You have been blocked from editing for continued [[WP:COPYVIO|copyright infringement]]',
'You have been blocked from editing for using user and/or article ' +
'pages as a [[WP:NOTMYSPACE|blog, web host, social networking site or forum]]',
],
template: [
'{{subst:uw-spamublock|sig=yes}}',
'{{subst:uw-sblock|sig=yes}}',
'{{subst:uw-soablock|sig=yes}}',
'{{subst:uw-adblock|sig=yes}}',
'{{subst:uw-aoablock|sig=yes}}',
'{{subst:uw-vaublock|sig=yes}}',
'{{subst:uw-vblock|sig=yes}}',
'{{subst:uw-voablock|sig=yes}}',
'{{subst:uw-softerblock|sig=yes}}',
'{{subst:uw-causeblock|sig=yes}}',
'{{subst:uw-copyrightblock|sig=yes}}',
'{{subst:uw-myblock|sig=yes}}'
]
};

ApiManager.static.presetDefaults = {
label: '<label missing>',
deletesummary: ApiManager.static.menuDefaults.deletesummary[ 10 ],
expiry: ApiManager.static.menuDefaults.expiry[ 0 ],
blocksummary: ApiManager.static.menuDefaults.blocksummary[ 0 ],
nocreate: true,
autoblock: true,
noemail: false,
nousertalk: false,
template: ApiManager.static.menuDefaults.template[ 0 ],
editsummary: ApiManager.static.menuDefaults.editsummary[ 0 ]
};

ApiManager.static.otherDefaults = {
preset :ApiManager.static.presets[ 0 ].id,
watchlist: 'preferences',
menulocation: 'p-cactions',
menuposition: null,
oneclick: false
};

ApiManager.static.months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];

ApiManager.static.summarySuffix = '([[WP:SUPG|SUPG]])';

ApiManager.prototype.getCurrentTitle = function () {
return this.currentTitle;
};

ApiManager.prototype.getUserName = function () {
return this.userName;
};

ApiManager.prototype.getUserTalkTitle = function () {
return this.userTalkTitle;
};

ApiManager.prototype._getNotificationDate = function () {
// We cache the result of this method so that we will always get the
// same date string as we used for the talk notification, even if a
// user happened to have the page open over a month boundary.
var date, month;
if ( !this.notificationDate ) {
date = new Date();
month = this.constructor.static.months[ date.getMonth() ];
this.notificationDate = month + ' ' + date.getFullYear();
}
return this.notificationDate;
};

ApiManager.prototype.getDefault = function ( key ) {
return this.defaults[ key ];
};

ApiManager.prototype.getPresetIds = function () {
return this.presetIds;
};

ApiManager.prototype.getPresetValue = function ( presetId, key ) {
return this.presets[ presetId ][ key ];
};

ApiManager.prototype.getMenuItems = function ( key ) {
var menuItems, pref, keyItems, isDupe, i, len, val;
if ( typeof key !== 'string' ) {
throw new TypeError( "argument #1 to 'getMenuItems' was not a string" );
}
function copyArray ( arr ) {
var ret = [];
for ( var i = 0, len = arr.length; i < len; i++ ) {
ret[ i ] = arr[ i ];
}
return ret;
}

if ( this.menuItemCache[ key ] === undefined ) {
menuItems = this.constructor.static.menuDefaults[ key ];
if ( menuItems ) {
this.menuItemCache[ key ] = menuItems;
pref = this.userPreferences[ key ];
if ( pref ) {
isDupe = false;
for ( i = 0, len = menuItems.length; i < len; i++ ) {
val = menuItems[ i ];
if ( val === pref ) {
isDupe = true;
break;
}
}
if ( !isDupe ) {
// Create a copy of the static array so we can manipulate it.
menuItems = copyArray( menuItems );
menuItems.unshift( pref );
this.menuItemCache[ key ] = menuItems;
}
}
} else {
this.menuItemCache[ key ] = null;
}
}
return this.menuItemCache[ key ];
};

ApiManager.prototype.addPortletLink = function () {
return mw.util.addPortletLink(
this.getDefault( 'menulocation' ),
'#',
'Delete and block',
'ca-spamuserpage',
'Delete this page and block this user',
null,
this.getDefault( 'menuposition' )
);
};

ApiManager.prototype.openTalkPage = function () {
window.open(
this.getUserTalkTitle().getUrl() +
'#' +
mw.util.wikiUrlencode( this._getNotificationDate() ),
'_top'
);
};

ApiManager.prototype._deleteCurrentPage = function ( options ) {
options = options || {};
var reason = options.deletesummary !== undefined ?
options.deletesummary :
this.getDefault( 'deletesummary' );
reason += ' ' + this.constructor.static.summarySuffix;
return this.api.postWithToken( 'delete', {
format: 'json',
action: 'delete',
title: this.currentTitle.getPrefixedText(),
reason: reason,
watchlist: options.watchlist || this.getDefault( 'watchlist' )
} );
};

ApiManager.prototype._blockUser = function ( options, deletePromise ) {
var deleteFinishedPromise, reason;
var apiManager = this;
options = options || {};

// Make a new promise that is resolved when the delete promise is
// either resolved or rejected.
deleteFinishedPromise = $.Deferred( function ( deferred ) {
deletePromise.always( function () {
deferred.resolve();
} );
} ).promise();

reason = options.blocksummary !== undefined ?
options.blocksummary :
apiManager.getDefault( 'blocksummary' );
reason += ' <!-- ' + apiManager.constructor.static.summarySuffix + ' -->';

return deleteFinishedPromise.then( function () {
return apiManager.api.postWithToken( 'block', {
format: 'json',
action: 'block',
user: apiManager.getUserName(),
expiry: options.expiry !== undefined ?
options.expiry :
apiManager.getDefault( 'expiry' ),
reason: reason,
nocreate: options.nocreate ? '' : undefined,
autoblock: options.autoblock ? '' : undefined,
noemail: options.noemail ? '' : undefined,
allowusertalk: !options.nousertalk ? '' : undefined
} );
} );
};

ApiManager.prototype._postTalkNotification = function ( options, blockPromise ) {
var self = this;
options = options || {};
return $.Deferred( function ( deferred ) {
// Reject the deferred if the block failed.
blockPromise.fail( function () {
return deferred.reject( 'usernotblocked', { error: {
id: 'usernotblocked',
info: 'There was an error while trying to block the user, ' +
'so notification was aborted'
} } );
} );

blockPromise.done( function () {
// Get the talk page content. We will use this to check if there is
// already a section heading for the current month.
return self.api.get( {
format: 'json',
action: 'query',
prop: 'revisions',
rvprop: 'content',
indexpageids: '',
titles: self.getUserTalkTitle().getPrefixedText(),
redirects: ''
} ).then( function ( obj ) {
var title, content, headings, lastHeading,
notificationDate, editPromise, summary;
var template = options.template !== undefined ?
options.template :
self.getDefault( 'template' );
var pageid = obj.query.pageids[ 0 ];

// If we got a redirect from the GET request, follow it.
if ( obj.query.redirects ) {
title = obj.query.redirects[ 0 ].to;
} else {
title = self.getUserTalkTitle().getPrefixedText();
}

if ( pageid === '-1' ) {
// The page doesn't exist.
content = '';
} else {
// The page exists; get the content.
content = obj.query.pages[ pageid ].revisions[ 0 ][ '*' ];

// Separate our notification from whatever the previous content was.
if ( content.match( /\S/ ) ) {
content += '\n\n';
}
}

// Add a heading for the current month if it is not already the
// last heading on the page.
headings = content.match( /^==[^=].*==[ \t]*$/gm );
if ( headings ) {
lastHeading = headings[ headings.length - 1 ].slice( 2, -2 ).trim();
}
notificationDate = self._getNotificationDate();
if ( !lastHeading || lastHeading !== notificationDate ) {
content += '== ' + notificationDate + ' ==\n\n';
}

// Add the block template.
content += template;

// Generate the edit summary.
summary = options.editsummary !== undefined ?
options.editsummary :
self.getDefault( 'editsummary' );
summary += ' ' + self.constructor.static.summarySuffix;

// Overwrite the page with our new content.
editPromise = self.api.postWithToken( 'edit', {
format: 'json',
action: 'edit',
title: title,
summary: summary,
notminor: '',
text: content,
watchlist: options.watchlist || self.getDefault( 'watchlist' )
} );

editPromise.done( function () {
return deferred.resolve();
} );

editPromise.fail( function ( id, obj ) {
return deferred.reject( id, obj );
} );
} );
} );
} ).promise();
};

ApiManager.prototype.submit = function ( options ) {
var promises = {};
options = options || {};
promises[ 'delete' ] = this._deleteCurrentPage( options );
promises.block = this._blockUser( options, promises[ 'delete' ] );
promises.notify = this._postTalkNotification( options, promises.block );
promises.all = $.when(
promises[ 'delete' ],
promises.block,
promises.notify
);
return promises;
};

/**************************************************************************
* Dialog class
**************************************************************************/

var Dialog = function ( options ) {
options = options || {};
this.apiManager = new ApiManager();
this.hasBeenSubmitted = false;
Dialog.super.call( this, options );
};

OO.inheritClass( Dialog, OO.ui.ProcessDialog );

Dialog.static.name = 'SpamUserPageDialog';
Dialog.static.title = 'Delete, block and notify';

Dialog.static.actions = [
{ action: 'submit', label: 'Submit', flags: [ 'primary', 'destructive' ] },
{ label: 'Cancel', flags: 'safe' }
];

Dialog.prototype.getApiManager = function () {
return this.apiManager;
};

Dialog.prototype.getBodyHeight = function () {
return 440;
};

Dialog.prototype.initialize = function () {
Dialog.super.prototype.initialize.apply( this, arguments );
var apiManager = this.getApiManager();

// Converts an array of data from ApiManager into a format usable with
// OOjs-ui menus.
function makeMenu( arr, labelCallback ) {
var i, len;
var items = [];
for ( i = 0, len = arr.length; i < len; i++ ) {
items[ i ] = new OO.ui.MenuOptionWidget( {
data: arr[ i ],
label: labelCallback ? labelCallback( arr[ i ] ) : arr[ i ]
} );
}
return { items: items };
}

// Initialize edit panel
this.editPanel = new OO.ui.PanelLayout( {
expanded: false
} );
this.editFieldset = new OO.ui.FieldsetLayout( {
classes: [ 'container' ]
} );
this.editPanel.$element.append( this.editFieldset.$element );

// Initialize preset widget
this.presetDropdown = new OO.ui.DropdownWidget( {
data: { label: 'Select a preset' },
menu: makeMenu( apiManager.getPresetIds(), function ( id ) {
return apiManager.getPresetValue( id, 'label' );
} )
} );
if ( apiManager.getDefault( 'preset' ) ) {
this.presetDropdown.getMenu().selectItemByData(
apiManager.getDefault( 'preset' )
);
} else {
this.presetDropdown.setLabel( this.presetDropdown.getData().label );
}
this.editFieldset.addItems( [
new OO.ui.FieldLayout( this.presetDropdown, {
label: 'Preset',
} )
] );

// Initialize deletion widgets
this.deleteSummaryInput = new OO.ui.ComboBoxInputWidget( {
value: apiManager.getDefault( 'deletesummary' ),
menu: makeMenu( apiManager.getMenuItems( 'deletesummary' ) )
} );
this.editFieldset.addItems( [
new OO.ui.FieldLayout( this.deleteSummaryInput, {
label: 'Deletion summary'
} )
] );

// Initialize notification widgets
this.editSummaryInput = new OO.ui.ComboBoxInputWidget( {
value: apiManager.getDefault( 'editsummary' ),
menu: makeMenu( apiManager.getMenuItems( 'editsummary' ) )
} );
this.templateInput = new OO.ui.ComboBoxInputWidget( {
value: apiManager.getDefault( 'template' ),
menu: makeMenu( apiManager.getMenuItems( 'template' ) )
} );
this.editFieldset.addItems( [
new OO.ui.FieldLayout( this.templateInput, {
label: 'Notification template'
} ),
new OO.ui.FieldLayout( this.editSummaryInput, {
label: 'Edit summary'
} )
] );

// Initialize block widgets
this.blockSummaryInput = new OO.ui.ComboBoxInputWidget( {
value: apiManager.getDefault( 'blocksummary' ),
menu: makeMenu( apiManager.getMenuItems( 'blocksummary' ) )
} );
this.expiryInput = new OO.ui.ComboBoxInputWidget( {
value: apiManager.getDefault( 'expiry' ),
menu: makeMenu( apiManager.getMenuItems( 'expiry' ) )
} );
this.nocreateToggleButton = new OO.ui.ToggleButtonWidget( {
label: 'Block account creation',
value: apiManager.getDefault( 'nocreate' )
} );
this.noemailToggleButton = new OO.ui.ToggleButtonWidget( {
label: 'Block email',
value: apiManager.getDefault( 'noemail' )
} );
this.nousertalkToggleButton = new OO.ui.ToggleButtonWidget( {
label: 'Block talk',
value: apiManager.getDefault( 'nousertalk' )
} );
this.autoblockToggleButton = new OO.ui.ToggleButtonWidget( {
label: 'Autoblock',
value: apiManager.getDefault( 'autoblock' )
} );
this.blockButtonGroup = new OO.ui.ButtonGroupWidget( {
items: [
this.nocreateToggleButton,
this.noemailToggleButton,
this.nousertalkToggleButton,
this.autoblockToggleButton
]
} );
this.editFieldset.addItems( [
new OO.ui.FieldLayout( this.blockSummaryInput, {
label: 'Block summary'
} ),
new OO.ui.FieldLayout( this.expiryInput, {
label: 'Block expiry'
} ),
new OO.ui.FieldLayout( this.blockButtonGroup, {
label: 'Block options',
align: 'top'
} ),
] );

// Initialize watchlist widgets
this.watchlistOptions = {};
this.watchlistOptions.watch = new OO.ui.ButtonOptionWidget( {
data: 'watch',
label: 'Watch',
title: 'Watch option'
} );
this.watchlistOptions.unwatch = new OO.ui.ButtonOptionWidget( {
data: 'unwatch',
label: 'Unwatch',
title: 'Unwatch option'
} );
this.watchlistOptions.preferences = new OO.ui.ButtonOptionWidget( {
data: 'preferences',
label: 'Follow preferences',
title: 'Follow preferences option'
} );
this.watchlistOptions.nochange = new OO.ui.ButtonOptionWidget( {
data: 'nochange',
label: 'No change',
title: 'No change option'
} );
this.watchlistButtonSelect = new OO.ui.ButtonSelectWidget( {
items: [
this.watchlistOptions.watch,
this.watchlistOptions.unwatch,
this.watchlistOptions.preferences,
this.watchlistOptions.nochange
]
} );
this.watchlistButtonSelect.selectItemByData(
apiManager.getDefault( 'watchlist' )
);
this.editFieldset.addItems( [
new OO.ui.FieldLayout( this.watchlistButtonSelect, {
label: 'Watchlist options',
align: 'top'
} )
] );

// Initialize submit panel
this.submitPanel = new OO.ui.PanelLayout( {
$: this.$,
expanded: false
} );
this.submitFieldset = new OO.ui.FieldsetLayout( {
classes: [ 'container' ]
} );
this.submitPanel.$element.append( this.submitFieldset.$element );
this.deleteProgressLabel = new OO.ui.LabelWidget();
this.deleteProgressField = new OO.ui.FieldLayout( this.deleteProgressLabel );
this.blockProgressLabel = new OO.ui.LabelWidget();
this.blockProgressField = new OO.ui.FieldLayout( this.blockProgressLabel );
this.notifyProgressLabel = new OO.ui.LabelWidget();
this.notifyProgressField = new OO.ui.FieldLayout( this.notifyProgressLabel );
this.openTalkProgressField = new OO.ui.FieldLayout( new OO.ui.LabelWidget() );
this.submitFieldset.addItems( [
this.deleteProgressField,
this.blockProgressField,
this.notifyProgressField,
this.openTalkProgressField
] );

// Initialize stack widget
this.stackLayout= new OO.ui.StackLayout( {
items: [ this.editPanel, this.submitPanel ],
padded: true
} );

// Add widgets to the DOM
this.$body.append( this.stackLayout.$element );

// Add event handlers
if ( apiManager.getDefault( 'preset' ) ) {
this.changeInputEventHandlers( 'on', this.onFirstChangeAfterPreset, null, this );
}
this.presetDropdown.getMenu().on( 'select', this.onPresetSelect, null, this );
};

Dialog.prototype.onPresetSelect = function () {
var presetId = this.presetDropdown.getMenu().findSelectedItem().getData();
var apiManager = this.getApiManager();

// Detach any input event handlers. If they are still attached, they will
// clear the preset selection, which we don't want.
this.changeInputEventHandlers( 'off', this.onFirstChangeAfterPreset, this );

// Set values
this.deleteSummaryInput.getInput().setValue(
apiManager.getPresetValue( presetId, 'deletesummary' )
);
this.deleteSummaryInput.getMenu().toggle( false );
this.expiryInput.getInput().setValue(
apiManager.getPresetValue( presetId, 'expiry' )
);
this.expiryInput.getMenu().toggle( false );
this.templateInput.getInput().setValue(
apiManager.getPresetValue( presetId, 'template' )
);
this.templateInput.getMenu().toggle( false );
this.editSummaryInput.getInput().setValue(
apiManager.getPresetValue( presetId, 'editsummary' )
);
this.editSummaryInput.getMenu().toggle( false );
this.blockSummaryInput.getInput().setValue(
apiManager.getPresetValue( presetId, 'blocksummary' )
);
this.blockSummaryInput.getMenu().toggle( false );
this.nocreateToggleButton.setValue(
apiManager.getPresetValue( presetId, 'nocreate' )
);
this.autoblockToggleButton.setValue(
apiManager.getPresetValue( presetId, 'autoblock' )
);
this.noemailToggleButton.setValue(
apiManager.getPresetValue( presetId, 'noemail' )
);
this.nousertalkToggleButton.setValue(
apiManager.getPresetValue( presetId, 'nousertalk' )
);

// Attach one-time event handler
this.changeInputEventHandlers( 'on', this.onFirstChangeAfterPreset, null, this );
};

Dialog.prototype.changeInputEventHandlers = function ( method, func, arg3, arg4 ) {
this.deleteSummaryInput.getInput()[ method ]( 'change', func, arg3, arg4 );
this.deleteSummaryInput.getMenu()[ method ]( 'select', func, arg3, arg4 );
this.expiryInput.getInput()[ method ]( 'change', func, arg3, arg4 );
this.expiryInput.getMenu()[ method ]( 'select', func, arg3, arg4 );
this.templateInput.getInput()[ method ]( 'change', func, arg3, arg4 );
this.templateInput.getMenu()[ method ]( 'select', func, arg3, arg4 );
this.editSummaryInput.getInput()[ method ]( 'change', func, arg3, arg4 );
this.editSummaryInput.getMenu()[ method ]( 'select', func, arg3, arg4 );
this.blockSummaryInput.getInput()[ method ]( 'change', func, arg3, arg4 );
this.blockSummaryInput.getMenu()[ method ]( 'select', func, arg3, arg4 );
this.nocreateToggleButton[ method ]( 'change', func, arg3, arg4 );
this.autoblockToggleButton[ method ]( 'change', func, arg3, arg4 );
this.noemailToggleButton[ method ]( 'change', func, arg3, arg4 );
this.nousertalkToggleButton[ method ]( 'change', func, arg3, arg4 );
};

Dialog.prototype.onFirstChangeAfterPreset = function () {
// Detach all input event handlers
this.changeInputEventHandlers( 'off', this.onFirstChangeAfterPreset, this );

// Clear the selected preset. Before doing this we detach its select event
// listener, as that will cause problems if it's still attached.
this.presetDropdown.getMenu().off( 'select', this.onPresetSelect, this );
this.presetDropdown.getMenu().selectItem();
this.presetDropdown.setLabel( this.presetDropdown.getData().label );
this.presetDropdown.getMenu().on( 'select', this.onPresetSelect, null, this );
};

Dialog.prototype.onSubmit = function () {
var self = this;
var options, promises;
var apiManager = this.getApiManager();
var title = apiManager.getCurrentTitle().getPrefixedText();
var user = apiManager.getUserName();

// Record that the dialog has been submitted. This is necessary to
// prevent the "Submit" button from being reactivated after the window
// is closed and reopened.
self.hasBeenSubmitted = true;

// Disable input
self.actions.setAbilities( { submit: false } );

// Increase the pending level by 4: one each for the delete, block,
// notify, and all promises.
self.pushPending();
self.pushPending();
self.pushPending();
self.pushPending();

// Set progress labels
self.deleteProgressField.setLabel( 'Deleting "' + title + '"...' );
self.blockProgressField.setLabel( 'Blocking ' + user + '...' );
self.notifyProgressField.setLabel( 'Notifying ' + user + '...' );
self.stackLayout.setItem( self.submitPanel );

// Get options and submit
options = {
watchlist: self.watchlistButtonSelect.findSelectedItem().getData(),
deletesummary: self.deleteSummaryInput.getInput().getValue(),
expiry: self.expiryInput.getInput().getValue(),
template: self.templateInput.getInput().getValue(),
editsummary: self.editSummaryInput.getInput().getValue(),
blocksummary: self.blockSummaryInput.getInput().getValue(),
nocreate: self.nocreateToggleButton.getValue(),
autoblock: self.autoblockToggleButton.getValue(),
noemail: self.noemailToggleButton.getValue(),
nousertalk: self.nousertalkToggleButton.getValue()
};
promises = self.getApiManager().submit( options );

// Update progress
// This involves editing the progress labels and reducing the pending
// level.
function updateProgress( promise, label ) {
promise.done( function () {
label.setLabel( $( '<span>' )
.addClass( 'spamuserpage-success' )
.text( 'Done.' )
);
} );
promise.fail( function ( id, obj ) {
if ( obj && obj.error && obj.error.info ) {
label.setLabel( $( '<span>' )
.addClass( 'spamuserpage-error' )
.text( 'Error: ' + obj.error.info + '.' )
);
} else {
label.setLabel( 'An unknown error occurred.' );
}
} );
promise.always( function () {
self.popPending();
} );
}
updateProgress( promises[ 'delete' ], self.deleteProgressLabel );
updateProgress( promises.block, self.blockProgressLabel );
updateProgress( promises.notify, self.notifyProgressLabel );

// Clean up when everything is done
promises.all.done( function () {
self.openTalkProgressField.setLabel(
'Opening "' +
apiManager.getUserTalkTitle().getPrefixedText() +
'"...'
);
apiManager.openTalkPage();
} );
promises.all.fail( function () {
// Pop pending only on failure, so that it still looks like we're
// loading something while the talk page is being opened.
self.popPending();
} );
};

Dialog.prototype.getReadyProcess = function ( data ) {
// Parent getReadyProcess method
return Dialog.super.prototype.getReadyProcess.call( this, data )
.next( function () {
if ( this.hasBeenSubmitted ) {
// The dialog has already been submitted when it was previously
// opened, so disable the Submit button.
this.actions.setAbilities( { submit: false } );
} else if ( this.getApiManager().getDefault( 'oneclick' ) ) {
this.executeAction( 'submit' );
}
}, this );
};

Dialog.prototype.getActionProcess = function ( action ) {
return Dialog.super.prototype.getActionProcess.call( this, action )
.next( function () {
if ( action === 'submit' ) {
return this.onSubmit();
} else {
return Dialog.super.prototype.getActionProcess.call( this, action );
}
}, this );
};

/**************************************************************************
* Main
**************************************************************************/

function main() {
var portletLink;
var supDialog = new Dialog( { size: 'large' } );
var apiManager = supDialog.getApiManager();
var userName = apiManager.getUserName();
if (
// Don't run in the current user's userspace or on any user talk pages.
userName !== config.wgUserName &&
!(
config.wgNamespaceNumber === 3 &&
config.wgTitle === userName
)
) {
// Load CSS
importStylesheet( "User:Mr. Stradivarius/gadgets/SpamUserPage.css" );
// Set up window manager
var windowManager = new OO.ui.WindowManager();
$( 'body' ).append( windowManager.$element );
windowManager.addWindows( [ supDialog ] );

// Add portlet link
portletLink = apiManager.addPortletLink();
$( portletLink ).click( function ( event ) {
event.preventDefault();
windowManager.openWindow( supDialog );
} );
}
}

main();
} );

// </nowiki>

Revision as of 17:55, 6 March 2022

//<nowiki>
$(function() {
  var namespace = mw.config.get('wgNamespaceNumber'),
    pageName = mw.config.get('wgPageName'),
    myUserName = mw.config.get('wgUserName'),
    userName = mw.config.get('wgRelevantUserName'),
    templateName = "script",
    blockReason,
    api;

  if([0,2,3].indexOf(namespace) !== -1) {
  	mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).done( function() {
  		api = new mw.Api();
	    mw.util.addPortletLink(
	      'p-cactions', 'javascript:void(0)',
	        'Block vandal', 'ca-spamublock', 'Delete user page and execute {{uw-spamublock}} on current user'
	    );
	} );

    $('#ca-spamublock').on('click', function() {
      if (confirm('This script will delete the current user page, block the relevant user or page creator as {{uw-spamublock}} and leave that template on their talk page, or the template specified at [[Special:MyPage/uw-spamublock]], if present.\n\nARE YOU SURE YOU WANT TO PROCEED?')) {
        $('#ca-spamublock').text('Please wait...');
        if(!userName) {
        	api.get({
		      action: 'query',
		      prop: 'revisions',
		      titles: pageName,
		      rvdir: 'newer',
		      rvlimit: '1',
		      rvprop: 'user'
		    }).then(function(data) {
		      var pages = data.query.pages;
		      userName = pages[Object.keys(pages)[0]].revisions[0].user;
		      getTemplate();
		    });
        } else {
	        getTemplate();
        }
      }
    });
  }

  function getTemplate() {
    api.get({
      action: 'query',
      titles: 'User:'+myUserName+'/uw-spamublock'
    }).then(function(data) {
      var query = data.query.pages;
      if(Object.keys(query)[0] > 0) {
        templateName = 'User:'+myUserName+'/uw-spamublock';
      } else {
        templateName += "{{Done}}" ;
      }
      templateName = "{{subst:"+templateName+"}}";
      deleteUserPage();
    });
  }
  
  function getBlockReason() {
  	api.get({
      action: 'query',
      titles: 'User:'+myUserName+'/spamublock-message'
    }).then(function(data) {
      var query = data.query.pages;
      if(Object.keys(query)[0] > 0) {
        blockReason = '{{User:'+myUserName+'/spamublock-message}}';
      } else {
      	blockReason = 'Testing blocking script';
      }
      blockUser();
    });
  }

  function deleteUserPage() {
    api.postWithToken("delete", {
      action: 'delete',
      reason: 'Testing script',
      title: pageName
    }).then(function(deleteData) {
      $("#mw-content-text").html(
        "<p><b>Deleted</b> page <a href='"+mw.util.getUrl(pageName)+"'>"+pageName+"</a> <i>(<a href='"+mw.util.getUrl('WP:G11')+"'>G11</a>: Unambiguous <a href='"+mw.util.getUrl('WP:NOTADVERTISING')+"'>advertising</a> or promotion)</i></p>"
      );
      getBlockReason();
    },function(error) {
      $("#mw-content-text").html(
        "<p><b>Error</b> deleting page "+pageName+": "+error+"</p>"
      );
    });
  }

  function blockUser() {
    api.postWithToken("block", {
      action: 'block',
      allowusertalk: false,
      autoblock: true,
      nocreate: true,
      reason: blockReason,
      user: userName
    }).then(function(blockData) {
      $("#mw-content-text").append(
        "<p><b>Blocked</b> <a href='"+mw.util.getUrl('User:'+userName)+"'>"+userName+"</a> (account creation blocked) with an expiry time of indefinite <i>(<span id='spamublock-blocked-reason'></span>)</i></p>"
      );
      $('<span/>').text(blockReason).appendTo("#spamublock-blocked-reason");
      templateUser();
    }, function(error) {
      $("#mw-content-text").append(
        "<p><b>Error</b> blocking <a href='"+mw.util.getUrl('User:'+userName)+"'>"+userName+"</a>: "+error+"</p>"
      );
    });
  }

  function templateUser() {
    var monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
      d = new Date();

    api.postWithToken( "edit", {
      action: "edit",
      section: 'new',
      sectiontitle: monthNames[d.getMonth()] + ' ' + d.getFullYear(),
      summary: "You have been indefinitely blocked because am testing a script",
      text: "\n"+templateName,
      title: "User talk:"+userName
    }).then(function(editData) {
      $("#mw-content-text").append(
        "<p><b>Edited</b> <a href='"+mw.util.getUrl('User talk:'+userName)+"'>User talk:"+userName+"</a>: Created new section with template "+templateName+"</p>" +
        "<p><b>Complete (<a href='javascript:document.location.reload()'>reload</a>)</b></p>"
      );
    },function(error) {
      $("#mw-content-text").append(
        "<p><b>Error</b> editing <a href='"+mw.util.getUrl('User talk:'+userName)+"'>User talk:"+userName+"</a>: "+error+"</p>"
      );
    });
  }
});
//</nowiki>