Extension:MirrorTools
|
MirrorTools Release status: experimental |
|
|---|---|
| Implementation | API |
| Description | This extension facilitates real-time mirroring of page histories. |
| Author(s) | Tisanetalk |
| Last version | 1.0.0 |
| MediaWiki | 1.17+ |
| PHP | 5 |
| Database changes | yes |
| Schema registration | yes |
| License | GPL |
| Download |
SVN [?]:
|
| Check usage and version matrix | |
| This extension stores its source code on a wiki page. Please be aware that this code may be unreviewed or maliciously altered. They may contain security holes, outdated interfaces that are no longer compatible etc. Note: No localisation updates are provided for this extension by translatewiki.net. |
This is the MirrorTools extension and some bots that go with it.
Contents |
What can this extension do? [edit]
This extension extends various API classes to allow revisions to be added with arbitrary user names (and, in a later version, timestamps). This aids in mirroring of another wiki's content.
Installation [edit]
Edit LocalSettings.php in the root of your MediaWiki installation, and add the following line near the bottom:
require_once("$IP/extensions/MirrorTools/MirrorTools.php");
Then run update.php to install the tables.
Usage [edit]
See the api.php on your wiki for more details on parameters for the various MirrorTools API modules.
To get the bot to work:
- Put your usernames, passwords, database info, etc. in Extension:MirrorTools#inclubot_passwords.php.
- Get the files for Chris G's botclasses and put them in your bot directory. Specifically, get http.php, lyricswiki.php, and mediawiki.php. Maybe get lyricwiki.php too.
- Manually add this table to your mirrorbot database (not your wiki database): Extension:MirrorTools/Queue table.
Development notes [edit]
Presently, this only handles mirroring of account creations. Partially written (and therefore not yet available) is mirroring of edits (mirroredit). Also needed are:
- moves (mirrormove)
- deletions (mirrordelete, to be handled by placing a deletion marker in the history)
- undeletions (mirrorundelete, to be handled similarly to page creation)
- protect (mirrorprotect)
- unprotect (mirrorunprotect)
- etc.
It may happen that a page is created on the remote wiki with a page title that already exists on the local wiki. That's fine; just merge the histories. It may happen that on the remote wiki, a page is moved to a page title that already exists on the local wiki. In such a case, the two page histories would be switched. E.g., suppose foo exists on the remote wiki (and is mirrored locally), and bar exists on the local wiki but not on the remote wiki. Then on the remote wiki, foo is moved to bar. On the local wiki, bar is then moved to foo, and foo is then moved to bar, and a redirect is put on top of the page history of foo redirecting the user to bar.
It may happen that some revisions will need to be buried in the page history below what already exists. This will require changing around the rev_parent_id values and such.
After all these are done, the next step will be to lock down mirrored pages to prevent any changes from being made to them, except by the mirrorbot.
Once that is done, the next step will be to cause clicks on "edit," "move," etc. tabs to take one to the appropriate urls at the remote wiki.
Next development steps [edit]
It needs to be programmed to have a loop that pulls and pushes at appropriate intervals. What that interval might be, I'm not sure. Maybe x seconds? Or, preferably, it can detect how far behind it's gotten and calibrate itself accordingly, based on the average account creations, edits, etc. per x seconds.
Files [edit]
inclubot_passwords.php [edit]
<? // MirrorBot API url $wikiUrl = "http://localhost/w/api.php"; // MirrorPullBot bot login $pullUser = 'YourWikipediaBotUsername'; $pullPass = 'yourwikipediabotpassword'; // MirrorPushBot bot login $pushUser = 'YourLocalBotUsername'; $pushPass = 'yourlocalbotpassword'; // Credentials for direct access to bot's database $host = "localhost"; $hostUser = "root"; $hostPass = "hostpassword"; $hostDbName = "hostdbname";
mirrorpullbot.php [edit]
<?php // Two options: -q rc, -q rev $options = getopt( 'q:'); if ( !isset ( $options['q'] ) ) { die ( 'Usage: php mirrorpullbot.php -q<option (e.g. rc, rev)>' . "\n" ); } $allowableOptions = array( 'rc', 'rev', 'us' ); if ( !in_array ( $options[ 'q' ], $allowableOptions ) ) { die ( "Allowable options: rc, rev, us\n" ); } // Get the passwords $passwordFile = 'inclubot_passwords.php'; if ( !file_exists ( $passwordFile ) ) { die ( "File $passwordFile does not exist\n" ); } $con = new mysqli( $host, $hostUser, $hostPass, $hostDbName ); if (!$con) { die('Could not connect: ' . mysql_error()); } /* Setup my classes. */ include('botclasses.php'); include('inclubot_passwords.php'); $wiki = new wikipedia; $wiki->url = "http://en.wikipedia.org/w/api.php"; #$wiki->url = "http://meta.wikimedia.org/w/api.php"; $wiki->login($user,$pass); unset($pass); switch ( $options[ 'q' ] ) { case 'rc': // Patrolled flag removed because of a lack of patrol right without being autoconfirmed :( $ret = $wiki->query ('?action=query&list=recentchanges&rcstart=2012-11-09T21:47:37Z' . '&rcdir=newer&rcprop=user|userid|comment|timestamp|title|ids|sizes|redirect|loginfo' . '|flags|loginfo|tags&rclimit=500&format=php' , true); $events = $ret['query']['recentchanges']; $table = 'mb_rc_queue'; $fields = array ( 'mbrcq_rc_id' => 'rcid', 'mbrcq_anon' => 'anon', 'mbrcq_rc_bot' => 'bot', 'mbrcq_rc_comment' => 'comment', 'mbrcq_rc_log_action' => 'logaction', 'mbrcq_rc_logid' => 'logid', 'mbrcq_rc_logtype' => 'logtype', 'mbrcq_rc_minor' => 'minor', 'mbrcq_rc_new' => 'new', 'mbrcq_rc_new_len' => 'newlen', 'mbrcq_rc_namespace' => 'ns', 'mbrcq_rc_old_len' => 'oldlen', 'mbrcq_rc_cur_id' => 'pageid', 'mbrcq_rc_patrolled' => 'patrolled', 'mbrcq_rc_thisoldid' => 'revid', 'mbrcq_rc_lastoldidid' => 'revoldid', 'mbrcq_redirect' => 'redirect', 'mbrcq_rc_timestamp' => 'timestamp', 'mbrcq_rc_title' => 'title', 'mbrcq_rc_type' => 'type', 'mbrcq_rc_user' => 'userid', 'mbrcq_rc_user_text' => 'user', 'mbrcq_user' => 'addeduserid', // This isn't actually in the API result 'mbrcq_user_text' => 'addeduser' // This isn't actually in the API result ); $stringFields = array ( 'title', 'type', 'action', 'user', 'comment', 'tags', 'logaction', 'logtype', 'addeduser', ); $booleanFields = array ( 'anon', 'bot', 'minor', 'new', 'patrolled', 'redirect', ); $defaultFields = array ( 'rcid' => 0, 'anon' => 0, 'bot' => 0, 'comment' => "''", 'logaction' => 'NULL', 'logid' => 0, 'logtype' => "''", 'minor' => 0, 'new' => 0, 'newlen' => 0, 'ns' => 0, 'oldlen' => 0, 'pageid' => 0, 'patrolled' => 0, 'revid' => 0, 'revoldid' => 0, 'redirect' => 0, 'timestamp' => "''", 'title' => "''", 'type' => 'NULL', 'user' => "''", 'userid' => 0, 'addeduser' => "''", 'addeduserid' => 0, ); break; case 'us': $table = 'mb_rc_queue'; $where = "mbrcq_rc_log_action='create2' AND mbrcq_user=0"; $ret = $con->query( "SELECT * FROM mb_rc_queue " ."WHERE $where LIMIT 500" ); if ( !$ret ) { die ( "No $where items\n" ); } $userTitle = array(); while ( $value = $ret->fetch_assoc() ) { $userTitle[] = $value[ 'mbrcq_rc_title' ]; } $firstUserTitle = true; $queryChunk = ''; foreach ( $userTitle as $thisUserTitle ) { if ( !$firstUserTitle ) { $queryChunk .= '|'; } $firstUserTitle = false; $queryChunk .= $thisUserTitle; } $ret = $wiki->query ('?action=query&list=users&ususers=' . $queryChunk . '&format=php' , true); if ( !$ret ) { echo "Error: Did not retrieve any user IDs from query\n"; } $events = $ret['query']['users']; foreach ( $events as $thisEvent ) { $name = "'" . $con->real_escape_string( $thisEvent[ 'name' ] ) . "'"; $pageTitle = "'User:" . $con->real_escape_string( $thisEvent[ 'name' ] ) . "'"; $query = 'UPDATE mb_rc_queue SET ' . 'mbrcq_user=' . $thisEvent[ 'userid'] . ', mbrcq_user_text=' . $name . " WHERE mbrcq_rc_log_action='create2' AND mbrcq_rc_title=" . $pageTitle; echo $query . "\n"; $status = $con->query ( $query ); if ( $status ) { echo "Success\n"; } else { echo "Failure\n"; } } die(); break; } $dbFields = array_keys ( $fields ); $userRow = array_values ( $fields ); $undesirables = array ( '-', ':', 'T', 'Z' ); $row = 'insert into ' . $table . ' ( ' . implode ( ', ', $dbFields ) . ' ) values '; $isFirstInEvent = true; // For each user creation event in that result set foreach ( $events as $thisLogevent ) { // Default values for adduserid and adduser if ( isset ( $thisLogevent[ 'userid' ] ) ) { $thisLogevent[ 'addeduserid' ] = $thisLogevent[ 'userid' ]; } if ( isset ( $thisLogevent[ 'user' ] ) ) { $thisLogevent[ 'addeduser' ] = $thisLogevent[ 'user' ]; } // Make those different if it's a create2 if ( isset ( $thisLogevent[ 'logaction' ] ) ) { if ( $thisLogevent[ 'logaction' ] == 'create2' ) { $thisLogevent [ 'addeduserid' ] = 0; $title = $thisLogevent[ 'title' ]; $strposTitle = strpos ( $title, ':' ); $thisLogevent [ 'addeduser' ] = substr ( $title, $strposTitle + 1 , strlen ( $title ) - $strposTitle ); } } if ( !$isFirstInEvent ) { $row .= ', '; } $isFirstInEvent = false; $row .= '( '; $isFirstInItem = true; // Get rid of dashes, colons, Ts and Zs in timestamp $thisLogevent['timestamp'] = str_replace ( $undesirables, '', $thisLogevent['timestamp'] ); // Iterate over those database fields foreach ( $userRow as $thisRowItem ) { if ( !$isFirstInItem ) { $row .= ', '; } $isFirstInItem = false; // If it's a boolean field, 1 if it's there, 0 if not if ( in_array( $thisRowItem, $booleanFields ) ) { if ( isset ( $thisLogevent[ $thisRowItem ] ) ) { $row .= '1'; } else { $row .= '0'; } } else { if ( isset ( $thisLogevent[$thisRowItem] ) ) { // If it's an array (e.g. tag array), implode it if ( is_array ( $thisLogevent[$thisRowItem] ) ) { $thisLogevent[$thisRowItem] = implode ( $thisLogevent[$thisRowItem] ); } // If it's a string field, escape it if ( in_array ( $thisRowItem, $stringFields ) ) { $thisLogevent[$thisRowItem] = "'" . $con->real_escape_string ( $thisLogevent[$thisRowItem] ) . "'"; } $row .= $thisLogevent[$thisRowItem]; } else { $row .= $defaultFields[$thisRowItem]; } } } $row .= ')'; } $row .= ';'; echo $row . "\n"; $con->query ( $row ); if ( $con ) { echo "Success\n"; } else { echo "Failure\n"; } $con->close();
mirrorpushbot.php [edit]
<?php /* Setup my classes. */ include('botclasses.php'); $wiki = new wikipedia; $wiki->url = $wikiUrl; $dbread = new mysqli( $host, $hostUser, $hostPass, $hostDbName ); if ( !$dbread ) { die( 'Could not connect: ' . mysql_error()); } $ret = $dbread->query( "SELECT * FROM mb_rc_queue WHERE mbrcq_rc_logtype='newusers'" ); if ( !$ret ) { die ( "No newusers rows found\n" ); } $row = $ret->fetch_assoc(); // Just do one row for testing purposes $row = $ret->fetch_assoc(); // Just do one row for testing purposes $row = $ret->fetch_assoc(); // Just do one row for testing purposes var_dump ( $row ); $wiki->login($pushUser,$pushPass); $token = $wiki->getedittoken (); unset($pass); $fields = array( 'rcid' => 'mbrcq_rc_id', 'logid' => 'mbrcq_rc_logid', 'pageid' => 'mbrcq_rc_cur_id', 'pagenamespace' => 'mbrcq_rc_namespace', 'pagetitle' => 'mbrcq_rc_title', 'type' => 'mbrcq_rc_logtype', 'logaction' => 'mbrcq_rc_log_action', 'user' => 'mbrcq_rc_user_text', 'userid' => 'mbrcq_rc_user', 'timestamp' => 'mbrcq_rc_timestamp', 'comment' => 'mbrcq_rc_comment', 'tags' => 'mbrcq_tags' ); $query = '?action=createaccount&format=php'; foreach ( $fields as $key => $value ) { if ( isset ( $row[ $value ] ) ) { $query .= '&' . $key . '=' . $row[ $value ]; } } $ret = $wiki->query ( '?action=createaccount&format=php' . '&rcid=' . $row['mbrcq_rc_id'] . '&logid=' . $row['mbrcq_rc_logid'] . '&pageid=' . $row['mbrcq_rc_cur_id'] . '&pagenamespace=' . $row['mbrcq_rc_namespace'] . '&pagetitle=' . $row['mbrcq_rc_title'] . '&type=' . $row['mbrcq_rc_logtype'] . '&logaction=' . $row['mbrcq_rc_log_action'] . '&user=' . $row['mbrcq_rc_user_text'] . '&userid=' . $row['mbrcq_rc_user'] . '×tamp=' . $row['mbrcq_rc_timestamp'] . '&comment=' . $row['mbrcq_rc_comment'] . '&tags=' . $row['mbrcq_tags'] . '&token=' . $token , true ); // Post var_dump ( $ret );
mirrorpushbot.php [edit]
<?php /* Setup my classes. */ include('botclasses.php'); $wiki = new wikipedia; $wiki->url = $wikiUrl; $dbread = new mysqli( $host, $hostUser, $hostPass, $hostDbName ); if ( !$dbread ) { die( 'Could not connect: ' . mysql_error()); } $ret = $dbread->query( "SELECT * FROM mb_rc_queue WHERE mbrcq_rc_logtype='newusers'" ); if ( !$ret ) { die ( "No newusers rows found\n" ); } $row = $ret->fetch_assoc(); // Just do one row for testing purposes $row = $ret->fetch_assoc(); // Just do one row for testing purposes $row = $ret->fetch_assoc(); // Just do one row for testing purposes var_dump ( $row ); $wiki->login($pushUser,$pushPass); $token = $wiki->getedittoken (); unset($pass); $fields = array( 'rcid' => 'mbrcq_rc_id', 'logid' => 'mbrcq_rc_logid', 'pageid' => 'mbrcq_rc_cur_id', 'pagenamespace' => 'mbrcq_rc_namespace', 'pagetitle' => 'mbrcq_rc_title', 'type' => 'mbrcq_rc_logtype', 'logaction' => 'mbrcq_rc_log_action', 'user' => 'mbrcq_rc_user_text', 'userid' => 'mbrcq_rc_user', 'timestamp' => 'mbrcq_rc_timestamp', 'comment' => 'mbrcq_rc_comment', 'tags' => 'mbrcq_tags' ); $query = '?action=createaccount&format=php'; foreach ( $fields as $key => $value ) { if ( isset ( $row[ $value ] ) ) { $query .= '&' . $key . '=' . $row[ $value ]; } } $ret = $wiki->query ( '?action=createaccount&format=php' . '&rcid=' . $row['mbrcq_rc_id'] . '&logid=' . $row['mbrcq_rc_logid'] . '&pageid=' . $row['mbrcq_rc_cur_id'] . '&pagenamespace=' . $row['mbrcq_rc_namespace'] . '&pagetitle=' . $row['mbrcq_rc_title'] . '&type=' . $row['mbrcq_rc_logtype'] . '&logaction=' . $row['mbrcq_rc_log_action'] . '&user=' . $row['mbrcq_rc_user_text'] . '&userid=' . $row['mbrcq_rc_user'] . '×tamp=' . $row['mbrcq_rc_timestamp'] . '&comment=' . $row['mbrcq_rc_comment'] . '&tags=' . $row['mbrcq_tags'] . '&token=' . $token , true ); // Post var_dump ( $ret );
MirrorTools.php [edit]
<?php /** * MirrorTools extension by Tisane * URL: http://www.mediawiki.org/wiki/Extension:MirrorTools * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html */ /* Alert the user that this is not a valid entry point to MediaWiki if they try to access the special pages file directly.*/ if ( !defined( 'MEDIAWIKI' ) ) { echo <<<EOT To install the MirrorTools extension, put the following line in LocalSettings.php: require( "extensions/MirrorTools/MirrorTools.php" ); EOT; exit( 1 ); } $wgExtensionCredits['other'][] = array( 'path' => __FILE__, 'name' => 'MirrorTools', 'author' => 'Leucosticte', 'url' => 'https://www.mediawiki.org/wiki/Extension:MirrorTools', 'descriptionmsg' => 'mirrortools-desc', 'version' => '1.1.1', ); $dir = dirname( __FILE__ ) . '/'; #$wgAutoloadClasses['ApiMirrorEditPage'] = $dir . 'APIMirrorTools.php'; $wgAutoloadClasses['ApiCreateAccount'] = $dir . 'ApiCreateAccount.php'; $wgAutoloadClasses['MirrorEditPage'] = $dir . 'MirrorTools.classes.php'; #$wgAPIModules['mirroredit'] = 'ApiMirrorEditPage'; $wgAPIModules['createaccount'] = 'ApiCreateAccount'; // Path to internationalization file $wgExtensionMessagesFiles['MirrorTools'] = $dir . 'MirrorTools.i18n.php'; // New user rights $wgAvailableRights[] = 'mirroredit'; $wgGroupPermissions['MirrorTools']['mirroredit'] = true; $wgHooks['LoadExtensionSchemaUpdates'][] = 'MirrorToolsHooks::MirrorToolsCreateTable'; class MirrorToolsHooks { public static function MirrorToolsCreateTable( $updater ) { $updater->addExtensionUpdate( array( 'addTable', 'mirror_logging', dirname( __FILE__ ) . '/mirror-logging.sql', true ) ); $updater->addExtensionUpdate( array( 'addTable', 'mirror_page', dirname( __FILE__ ) . '/mirror-page.sql', true ) ); $updater->addExtensionUpdate( array( 'addTable', 'mirror_revision', dirname( __FILE__ ) . '/mirror-revision.sql', true ) ); $updater->addExtensionUpdate( array( 'addTable', 'mirror_user', dirname( __FILE__ ) . '/mirror-user.sql', true ) ); return true; } }
ApiCreateAccount.php [edit]
<?php /** * Created on August 7, 2012 * * Copyright © 2012 Tyler Romeo <tylerromeo@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * http://www.gnu.org/copyleft/gpl.html * * @file */ /** * Unit to authenticate account registration attempts to the current wiki. * * @ingroup API */ class ApiCreateAccount extends ApiBase { public function execute() { $params = $this->extractRequestParams(); $isUserAlreadyThere = User::idFromName ( $params['user'] ); if ( $isUserAlreadyThere ) { $this->dieUsageMsg( 'userexists' ); } $dbw = wfGetDB( DB_MASTER ); #$nextUserId = $dbw->nextSequenceValue( 'user_user_id_seq' ); $userRow = array ( 'user_name' => $params['user'], 'user_password' => User::crypt ( str_shuffle ( 'abcdefghijklmnopqrstuvwxyz' ) ), ); $dbw->insert ( 'user', $userRow ); $nextUserId = $dbw->insertId(); $addedUser = $logRow = array ( 'log_type' => 'newusers', 'log_action' => $params['logaction'], 'log_timestamp' => $params['timestamp'], 'log_user' => $nextUserId, 'log_user_text' => $params['user'], 'log_namespace' => $params['pagenamespace'], 'log_title' => $params['pagetitle'], 'log_page' => $params['pageid'], 'log_comment' => $params['comment'], ); $dbw->insert ( 'logging', $logRow ); $nextLogId = $dbw->insertId(); $mirrorUserRow = array ( 'mrus_user_id' => $nextUserId, 'mrus_mr_user_id' => $params['userid'], ); $dbw->insert ( 'mirror_user', $mirrorUrc_serRow ); $mirrorLogRow = array ( 'mrlg_log_id' => $nextLogId, 'mrlg_mr_log_id' => $params['logid'], ); $dbw->insert ( 'mirror_logging', $mirrorLogRow ); $rcRow = array ( 'rc_timestamp' => $params['timestamp'], 'rc_user' => $nextUserId, 'rc_user_text' => $params['user'], 'rc_namespace' => $params['pagenamespace'], 'rc_title' => $params['pagetitle'], 'rc_comment' => $params['comment'], 'rc_minor' => 0, 'rc_bot' => 0, 'rc_new' => 0, 'rc_cur_id' => 0, 'rc_this_oldid' => 0, 'rc_last_oldid' => 0, 'rc_type' => 3, 'rc_moved_to_ns' => 0, 'rc_moved_to_title' => '', 'rc_patrolled' => 1, 'rc_ip' => '', // The local wiki will not have access to this info 'rc_deleted' => 0, 'rc_logid' => $nextLogId, 'rc_log_type' => 'newusers', 'rc_log_action' => 'create', 'rc_params' => 2 ); $dbw->insert( 'recentchanges' )->$rwRow; $nextRcId = $dbw->insertId(); $mirrorRcRow = array ( 'mrrc_rc_id' => $nextRcId, 'mrrc_mr_rc_id' => $params['rc_id'], 'mrrc_mr_cur_id' => 0, 'mrrc_mr_user' => $nextUser, 'mrrc_mr_user_text' => $params['userid'], 'mrrc_timestamp' => wfTimestampNow() ); $result['result'] = 'success'; } public function getDescription() { return 'Create a new user account.'; } public function needsToken() { return true; } public function mustBePosted() { return true; } public function isReadMode() { return false; } public function isWriteMode() { return true; } public function getAllowedParams() { global $wgEmailConfirmToEdit; return array( 'logid' => array ( ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_REQUIRED => true ), 'pageid' => array ( ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_REQUIRED => true ), 'pagenamespace' => array ( ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_REQUIRED => true ), 'pagetitle' => array ( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ), 'type' => array ( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ), 'logaction' => array ( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ), 'user' => array ( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ), 'userid' => array ( ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_REQUIRED => true ), 'timestamp' => array ( ApiBase::PARAM_TYPE => 'timestamp', ApiBase::PARAM_REQUIRED => true ), 'comment' => array ( ApiBase::PARAM_TYPE => 'string', ), 'tags' => array ( ApiBase::PARAM_TYPE => 'string', ), 'rcid' => array ( ApiBase::PARAM_TYPE => 'integer', ApiBase::PARAM_REQUIRED => true ), 'token' => array ( ApiBase::PARAM_TYPE => 'string', ApiBase::PARAM_REQUIRED => true ) ); } public function getParamDescription() { $p = $this->getModulePrefix(); return array( 'logid' => null, 'pageid' => null, 'pagenamespace' => null, 'pagetitle' => null, 'type' => null, 'logaction' => null, 'user' => null, 'userid' => null, 'timestamp' => null, 'comment' => null, 'tags' => null, 'rcid' => null, 'token' => null, ); } public function getResultProperties() { return array( 'createaccount' => array( 'result' => array( ApiBase::PROP_TYPE => array( 'success', 'warning', 'needtoken' ) ), 'username' => array( ApiBase::PROP_TYPE => 'string', ApiBase::PROP_NULLABLE => true ), 'userid' => array( ApiBase::PROP_TYPE => 'int', ApiBase::PROP_NULLABLE => true ), 'token' => array( ApiBase::PROP_TYPE => 'string', ApiBase::PROP_NULLABLE => true ), ) ); } public function getPossibleErrors() { $localErrors = array( 'wrongpassword', 'sessionfailure', 'sorbs_create_account_reason', 'noname', 'userexists', 'password-name-match', 'password-login-forbidden', 'noemailtitle', 'invalidemailaddress', 'externaldberror' ); $errors = parent::getPossibleErrors(); // All local errors are from LoginForm, which means they're actually message keys. foreach( $localErrors as $error ) { $errors[] = array( 'code' => $error, 'info' => wfMessage( $error )->parse() ); } // 'passwordtooshort' has parameters. :( global $wgMinimalPasswordLength; $errors[] = array( 'code' => 'passwordtooshort', 'info' => wfMessage( 'passwordtooshort', $wgMinimalPasswordLength )->parse() ); return $errors; } public function getExamples() { return array( 'api.php?action=createaccount&name=testuser&password=test123', 'api.php?action=createaccount&name=testmailuser&mailpassword=true&reason=MyReason', ); } public function getHelpUrls() { return 'https://www.mediawiki.org/wiki/API:Account creation'; } public function getVersion() { return __CLASS__ . ': $Id$'; } }
mirror-logging.sql [edit]
-- This table keeps track of which log events are mirrored and what local log IDs correspond -- to what remote log IDs. -- CREATE TABLE mirror_logging ( -- Unique ID to identify each mirrored log event mrlg_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, -- Local logging.log_id mrlg_log_id INT UNSIGNED NOT NULL, -- Remote logging.log_id mrlg_mr_log_id INT UNSIGNED NOT NULL, -- Time at which the mirroring took place mrlg_timestamp BINARY(14) NOT NULL DEFAULT '' ); CREATE INDEX mrlg_id ON mirror_logging (mrlg_id); COMMIT;
mirror-page.sql [edit]
-- This table keeps track of which pages are mirrored and what local page IDs correspond -- to what remote page IDs. -- CREATE TABLE mirror_page ( -- Unique ID to identify each mirrored page mrpg_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, -- Local page.page_id mrpg_page_id INT UNSIGNED NOT NULL, -- Remote page.page_id mrpg_mr_page_id INT UNSIGNED NOT NULL ); CREATE INDEX mrpg_id ON mirror_page (mrpg_id); COMMIT;
mirror-recentchanges.sql [edit]
-- This table lists data pertaining to mirrored recent changes. -- CREATE TABLE mirror_recentchanges ( -- Unique ID to identify each mirrored recentchange mrrc_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, -- Recentchanges ID (recentchanges.rc_id on this wiki) mrrc_rc_id INT UNSIGNED NOT NULL, -- Mirrored recentchanges ID (recentchanges.rc_id on mirrored wiki) mrrc_mr_rc_id INT UNSIGNED NOT NULL, -- Mirrored page ID (recentchanges.rc_cur_id on mirrored wiki) mrrc_mr_cur_id INT UNSIGNED NOT NULL, -- Mirrored user ID (recentchanges.rc_user on mirrored wiki) mrrc_mr_user INT UNSIGNED NOT NULL DEFAULT 0, -- Mirrored user name (revision.rev_user_text on mirrored wiki) mrrc_mr_rev_user_text VARCHAR(255) BINARY NOT NULL DEFAULT '', -- Time at which the mirroring took place mrrc_timestamp BINARY(14) NOT NULL DEFAULT '' ) MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; CREATE INDEX mrrc_id ON mirror_recentchanges (mrrc_id); COMMIT;
mirror-revision.sql [edit]
-- This table lists data pertaining to mirrored content. -- CREATE TABLE mirror_revision ( -- Unique ID to identify each mirrored revision mrrv_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, -- Revision ID (revision.rev_id on this wiki) mrrv_rev_id INT UNSIGNED NOT NULL, -- Mirrored revision ID (revision.rev_id on mirrored wiki) mrrv_mr_rev_id INT UNSIGNED NOT NULL, -- Mirrored page ID (revision.rev_page on mirrored wiki) mrrv_mr_rev_page INT UNSIGNED NOT NULL, -- Mirrored user ID (revision.rev_user on mirrored wiki) mrrv_mr_rev_user INT UNSIGNED NOT NULL DEFAULT 0, -- Mirrored user name (revision.rev_user_text on mirrored wiki) mrrv_mr_rev_user_text VARCHAR(255) BINARY NOT NULL DEFAULT '', -- Time at which the mirroring took place mrrv_timestamp BINARY(14) NOT NULL DEFAULT '', -- Mirrored parent ID (revision.rev_parent_id on mirrored wiki) mrrv_mr_rev_parent_id INT UNSIGNED NOT NULL ) MAX_ROWS=10000000 AVG_ROW_LENGTH=1024; CREATE INDEX mrrv_id ON mirror_revision (mrrv_id); COMMIT;
mirror-user.sql [edit]
-- This table keeps track of which users are mirrored and what local user IDs correspond -- to what remote user IDs. -- CREATE TABLE mirror_user ( -- Unique ID to identify each mirrored user mrus_id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, -- Local user.user_id mrus_user_id INT UNSIGNED NOT NULL, -- Remote user.user_id mrus_mr_user_id INT UNSIGNED NOT NULL ); CREATE INDEX mrus_id ON mirror_user (mrus_id); COMMIT;