Jump to content

User:DannyS712/SelectiveDeleter.js

From Meta, a Wikimedia project coordination wiki

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
// <nowiki>
// Quick script to carry out selective deletion
// @author DannyS712
$(() => {
const SelectiveDeleter = {};
window.SelectiveDeleter = SelectiveDeleter;

SelectiveDeleter.load = function () {
	if ( mw.config.get( 'wgAction' ) === 'history' ) {
		mw.loader.using(
			[ 'mediawiki.util', 'oojs-ui-widgets' ],
			function () {
				var button = new OO.ui.ButtonInputWidget( {
				    label: 'Selectively delete',
    				flags: [ 'destructive' ]
				} );
				$('.mw-history-compareselectedversions:first input').after( button.$element );
				button.on( 'click', function () {
					var revIds = [];
					$('#pagehistory li:has(input[type=checkbox]:checked)').each( function () {
						console.log( $( this ).attr( 'data-mw-revid' ) );
						revIds.push( $( this ).attr( 'data-mw-revid' ) );
					} );
					var url = mw.util.getUrl(
						'Special:BlankPage/SelectiveDeleter',
						{
							page: mw.config.get( 'wgRelevantPageName' ),
							ids: revIds.join( ',' )
						}
					);
					console.log( url );
					location.href = url;
				} );
			}
		);
	}
	if ( mw.config.get( 'wgNamespaceNumber' ) === -1 ) {
		const page = mw.config.get( 'wgCanonicalSpecialPageName' );
		if ( page === 'Blankpage' ) {
			const page2 = mw.config.get( 'wgTitle' ).split( '/' );
			if ( page2[1] && page2[1] === 'SelectiveDeleter' ) {
				window.SelectiveDeleter.init();
			}
		}
	}
};

SelectiveDeleter.init = function () {
	window.document.title = 'Selective Deletion';
	$( '#firstHeading' ).text( 'Selective Deletion' );
	mw.loader.using(
		[ 'mediawiki.api', 'mediawiki.util', 'oojs-ui-core', 'oojs-ui-widgets', 'oojs-ui-windows' ],
		SelectiveDeleter.run
	);
};

SelectiveDeleter.onErrHandler = function () {
	// Shared error handler
	alert( 'Something went wrong' );
	console.log( arguments );
};

SelectiveDeleter.run = function () {
	mw.util.addCSS( `
		.SelectiveDeleter-bad {
			color: #F00;
		}
		.SelectiveDeleter-good {
			color: #0F0;
		}
		#SelectiveDeleter-results {
			white-space: pre;
		}
	` );
	var pageWidget = new OO.ui.TextInputWidget( {
		value: mw.util.getParamValue( 'page' )
	} );
	var pageLayout = new OO.ui.FieldLayout(
		pageWidget,
		{ label: 'Page to selectively delete revisions from' }
	);
	var revIdsToDelete = mw.util.getParamValue( 'ids' );
	if ( revIdsToDelete === null ) {
		revIdsToDelete = '';
	}
	
	var revIdsWidget = new OO.ui.MultilineTextInputWidget( {
		value: revIdsToDelete.split(',').join('\n'),
		rows: 5
	} );
	var revIdsLayout = new OO.ui.FieldLayout(
		revIdsWidget,
		{ label: 'Revision ids for the revisions to selectively delete' }
	);
	var submit = new OO.ui.ButtonInputWidget( { 
		label: 'Delete',
		flags: [
			'primary',
			'progressive'
		]
	} );
	submit.on( 'click', function () {
		var submittedValues = {
			page: pageWidget.value,
			revIds: revIdsWidget.value
		};
		console.log( submittedValues );
		SelectiveDeleter.onSubmit( submittedValues );
	} );
	$( window ).on( 'keypress', function ( e ) {
		// press enter to start
		if ( e.which == 13 ) {
			submit.simulateLabelClick();
		}
	} );
	
	var fieldSet = new OO.ui.FieldsetLayout( { 
		label: 'Selectively delete specific revisions by deleting the page and undeleting the other revisions'
	} );
	
	fieldSet.addItems( [
		pageLayout,
		revIdsLayout,
		new OO.ui.FieldLayout( submit )
	] );

	var $results = $( '<div>' )
		.attr( 'id', 'SelectiveDeleter-results' );
	$( '#mw-content-text' ).empty().append(
		fieldSet.$element,
		$( '<hr>' ),
		$results
	);
};

SelectiveDeleter.onSubmit = function ( inputs ) {
	console.log( inputs );
	
	$( '#SelectiveDeleter-results' ).empty();
	var $progress = $( '<div>' )
		.attr( 'id', 'SelectiveDeleter-progress' );
	$( '#SelectiveDeleter-results' ).append( $progress );
	
	var revIdsToDelete = inputs.revIds.split( "\n" );
	if ( revIdsToDelete.length === 0 ) {
		SelectiveDeleter.addProgressLine( 'No rev ids to delete!', 'bad' );
		return;
	}

	SelectiveDeleter.addProgressLine( 'Getting page info from API for page: ' + inputs.page );
	var mwApi = new mw.Api();
	
	mwApi.get( {
		action: 'query',
		prop: 'revisions',
		titles: [ inputs.page ],
		rvlimit: 500,
		formatversion: 2
	} ).then(
		function ( response ) {
			console.log( response );
			if ( response.continue ) {
				SelectiveDeleter.addProgressLine(
					'There were too many revisions, more than 500!',
					'bad'
				);
				return;
			}
			var pageInfo = response.query.pages[0];
			if ( pageInfo.missing ) {
				SelectiveDeleter.addProgressLine(
					'The page does not exist! Just selectively undelete manually...',
					'bad'
				);
				return;
			}
			
			var allRevisions = pageInfo.revisions;
			var foundRevIdsToDelete = [];
			var foundRevsToKeep = [];
			var timestampsToKeep = [];
			allRevisions.forEach( function ( rev ) {
				if ( revIdsToDelete.indexOf( rev.revid.toString() ) !== -1 ) {
					foundRevIdsToDelete.push( rev.revid );
				} else {
					foundRevsToKeep.push( rev );
					timestampsToKeep.push( rev.timestamp );
				}
			} );
			console.log( 'Found to delete:', foundRevIdsToDelete );
			console.log( 'Found to keep:', foundRevsToKeep );
			if ( revIdsToDelete.length !== foundRevIdsToDelete.length ) {
				SelectiveDeleter.addProgressLine(
					'Uh oh, something went wrong with revision ids - are they all from the correct page? The revisions to delete were: ',
					'bad'
				);
				SelectiveDeleter.addProgressLine( '\t' + revIdsToDelete.join( ',' ), 'bad' );
				SelectiveDeleter.addProgressLine( 'And the ones the script found to delete were: ', 'bad' );
				SelectiveDeleter.addProgressLine( '\t' + foundRevIdsToDelete.join( ',' ), 'bad' );
				return;
			}
			if ( foundRevsToKeep.length === 0 ) {
				SelectiveDeleter.addProgressLine(
					'Uh oh, no revisions found to keep... maybe just delete the page entirely?',
					'bad'
				);
				return;
			}
			SelectiveDeleter.addProgressLine(
				'Found ' + foundRevsToKeep.length + ' revisions to keep',
				'good'
			);
			mwApi.postWithEditToken( {
				action: 'delete',
				title: inputs.page,
				reason: 'Preparing for selecting undeletion'
			} ).then(
				function ( response2 ) {
					console.log( response2 );
					SelectiveDeleter.addProgressLine( 'Page deleted!', 'good' );
					mwApi.postWithEditToken( {
						action: 'undelete',
						title: inputs.page,
						timestamps: timestampsToKeep,
						reason: 'Selectively undeleting'
					} ).then(
						function ( response3 ) {
							console.log( response3 );
							SelectiveDeleter.addProgressLine( 'Page undeleted!', 'good' );
						},
						SelectiveDeleter.onErrHandler
					);
				},
				SelectiveDeleter.onErrHandler
			);
		},
		SelectiveDeleter.onErrHandler
	);
};

SelectiveDeleter.addProgressLine = function ( text, type ) {
	type = type || '';
	var lineClass = '';
	if ( type === 'good' ) {
		lineClass = 'SelectiveDeleter-good';
	} else if ( type === 'bad' ) {
		lineClass = 'SelectiveDeleter-bad';
	}
	$( '#SelectiveDeleter-results' ).append(
		$( '<p>' )
			.text( text )
			.addClass( lineClass )
	);
};

});

$( document ).ready( () => {
	mw.loader.using(
		[ 'mediawiki.user' ],
		function () {
			mw.user.getGroups(
				function ( groups ) {
					if ( groups.indexOf( 'sysop' ) !== -1 ) {
						SelectiveDeleter.load();
					}
				}
			);
		}
	);
} );

// </nowiki>