Skip to content

Commit

Permalink
Add Protect API
Browse files Browse the repository at this point in the history
Add an API call for the Protect API endpoint.

This takes all of the arguments available for the Protect API.
  • Loading branch information
andrewnicols committed May 6, 2022
1 parent 72a9b9d commit 52071e9
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ divdavem (https://github.com/divdavem)
maxkueng (https://github.com/maxkueng)
stdob (https://github.com/stdob)
Technical-13 (https://github.com/Technical-13)
Andrew Lyons (https://github.com/andrewnicols)
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,22 @@ Purge a given list of articles (titles or page IDs can be provided) - [read more

> By providing `Category:Foo` as `titles` argument you can purge all pages in a given category (available since [MW 1.21](https://github.com/wikimedia/mediawiki/commit/62216932c197f1c248ca2d95bc230f87a79ccd71))
### bot.protect(title, protections, options, callback)

Protect a page (A title or page ID can be provided) - [read more](https://www.mediawiki.org/wiki/API:Protect)

The `protections` value is an Array of protection information in the format:

```
{
action: string,
level?: string = 'all',
expiry?: string | number = 'never'
}
```

Calls to the Protect endpoint are not additive. Each call must include a list of _all_ intended protections, including any already in place. Each call will _replace_ all existing protections.

### bot.sendEmail(username, subject, text, callback)

Send an email to an user - [read more](http://www.mediawiki.org/wiki/API:Email)
Expand Down
26 changes: 26 additions & 0 deletions examples/protect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env node
/**
* Example script getting current user information
*
* @see http://www.mediawiki.org/wiki/API:Protect
*/
'use strict';

const Bot = require( '..' );
const client = new Bot( 'examples/config.js' );

client.logIn( function () {
// Protections takes an array so allow multiple protections to be configured.
const protections = [];

// Protect the page from edits.
protections.push( {
type: 'edit',
level: 'sysop',
expiry: 'never'
} );

client.protect( 'Albert_Einstein', protections, ( err, data ) => {
console.log( JSON.stringify( data, null, '\t' ) );
} );
} );
94 changes: 94 additions & 0 deletions lib/bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,100 @@ Bot.prototype = {
} );
},

protect( title, protections, options, callback ) {
// @see https://www.mediawiki.org/wiki/API:Protect
if ( this.dryRun ) {
callback( new Error( 'In dry-run mode' ) );
return;
}

if ( typeof options === 'function' ) {
// This is the callback; options was nonexistent.
callback = options;
options = {};
}

if ( !options ) {
options = {};
}

const params = {
action: 'protect'
};

if ( typeof title === 'number' ) {
params.pageid = title;
} else {
params.title = title;
}

const formattedProtections = [];
const expiries = [];
let failed = false;
Array.from( protections ).forEach( ( protection ) => {
if ( !protection.type ) {
callback( new Error( 'Invalid protection. An action type must be specified.' ) );
failed = true;
return;
}

const level = protection.level ? protection.level : 'all';
formattedProtections.push( `${protection.type}=${level}` );

if ( protection.expiry ) {
expiries.push( protection.expiry );
} else {
// If no expiry was specified, then set the expiry to never.
expiries.push( 'never' );
}
} );

if ( failed ) {
return;
}

params.protections = formattedProtections.join( '|' );
params.expiry = expiries.join( '|' );

if ( options.reason ) {
params.reason = options.reason;
}

if ( options.tags ) {
if ( Array.isArray( options.tags ) ) {
params.tags = options.tags.join( '|' );
} else if ( typeof options.tags === 'string' ) {
params.tags = options.tags;
}
}

if ( options.cascade ) {
params.cascade = options.cascade ? 1 : 1;
}

if ( options.watchlist && typeof options.watchlist === 'string' ) {
params.watchlist = options.watchlist;
}

// Params have been generated. Now fetch the csrf token and call the API.
this.getToken( title, 'csrf', ( err, token ) => {
if ( err ) {
callback( err );
return;
}

params.token = token;

this.api.call( params, ( _err, data ) => {
if ( !_err && data.title && data.protections ) {
callback( null, data );
} else {
callback( _err );
}
}, 'POST' );
} );
},

purge( titles, callback ) {
// @see https://www.mediawiki.org/wiki/API:Purge
const params = {
Expand Down
27 changes: 27 additions & 0 deletions test/mediawiki-api-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,32 @@ vows.describe( 'Mediawiki API' ).addBatch( {
assert.isTrue( firstItem.ns === 0 );
assert.isTrue( firstItem.title.includes( 'Albert Einstein' ) );
}
},
'protect()': {
'Command cannot run in dry-run mode.': {
topic: function () {
client.dryRun = true;
client.protect(
ARTICLE,
[ { type: 'edit', level: 'sysop' } ],
this.callback
);
},
'Command not available in dry-run mode': function ( e, res ) {
assert.isTrue( res !== null );
}
},
'When no action type is provided, no error is thrown': {
topic: function () {
client.protect(
ARTICLE,
[ { level: 'all' } ],
this.callback
);
},
'Missing action throws an Error': function ( e, res ) {
assert.isTrue( res !== null );
}
}
}
} ).export( module );

0 comments on commit 52071e9

Please sign in to comment.