r81018 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r81017‎ | r81018 | r81019 >
Date:11:18, 26 January 2011
Author:questpc
Status:deferred
Tags:
Comment:
v0.3.2. Suppress the creation of informational null revisions in XML importer (on by default, can be re-enabled). ImportStreamSource constructor result handling is compatible to both 1.15 and 1.17. ApiRevisionHistory improvements. Fixes non-plural from r75865.
Modified paths:
  • /trunk/extensions/WikiSync/INSTALL (modified) (history)
  • /trunk/extensions/WikiSync/README (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.i18n.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.js (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncApi.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncClient.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncExporter.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncPage.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncQXML.php (modified) (history)

Diff [purge]

Index: trunk/extensions/WikiSync/WikiSyncExporter.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.3.1
 32+ * @version 0.3.2
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -83,7 +83,11 @@
8484 # call the parent to do the logging
8585 # avoid bug in 1.15.4 Special:Import (new file page text without the file uploaded)
8686 # PHP Fatal error: Call to a member function insertOn() on a non-object in E:\www\psychologos\includes\specials\SpecialImport.php on line 334
87 - if ( $title->getArticleId() !== 0 ) {
 87+ // do not create informational null revisions
 88+ // because they are placed on top of real user made revisions,
 89+ // making the binary search algorithm used to compare local and remote revs to fail
 90+ // TODO: change the binary search algorithm to two/three level hashes
 91+ if ( WikiSyncSetup::$report_null_revisions && $title->getArticleId() !== 0 ) {
8892 parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
8993 }
9094 }
Index: trunk/extensions/WikiSync/WikiSyncApi.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.3.1
 32+ * @version 0.3.2
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -46,7 +46,7 @@
4747 // we construct like ApiBase, however we also use SQL select building methods from ApiQueryBase
4848 public function __construct( $mainModule, $moduleName, $modulePrefix = '' ) {
4949 // we call ApiBase only, ApiQueryBase is unsuitable to our needs
50 - parent::__construct( $mainModule, $moduleName, $modulePrefix );
 50+ ApiBase::__construct( $mainModule, $moduleName, $modulePrefix = '' );
5151 $this->mDb = null;
5252 $this->resetQueryParams();
5353 }
@@ -245,9 +245,9 @@
246246 }
247247
248248 public function execute() {
249 - $db = $this->getDB();
250249 /* Get the parameters of the request. */
251250 $params = $this->extractRequestParams();
 251+ $db = $this->getDB();
252252 # next line is required, because getCustomPrinter() is not being executed from FauxRequest
253253 $this->xmlDumpMode = $params['xmldump'];
254254
@@ -259,19 +259,36 @@
260260 'rev_user_text',
261261 'OCTET_LENGTH( old_text ) AS text_len'
262262 );
263 - $this->addFields( $selectFields );
264263 $this->addTables( array( 'revision', 'text' ) );
265264 $this->addWhereRange( 'rev_id', $params['dir'], $params['startid'], $params['endid'] );
266265 $this->addOption( 'LIMIT', $params['limit'] + 1 );
 266+ if ( $params['exclude_user'] !== null ) {
 267+ # we are not including revisions created by WikiSyncBot, which are created in
 268+ # ImportReporter::reportPage to log the reason of import (set by constructors of
 269+ # WikiSyncImportReporter / ImportReporter)
 270+ # otherwise, fake reverse synchronizations might occur
 271+ $this->addWhere( 'rev_user_text != ' . $db->addQuotes( $params['exclude_user'] ) );
 272+ }
267273 $this->addJoinConds(
268274 array(
269275 'text' => array( 'INNER JOIN', 'rev_text_id=old_id' )
270276 )
271277 );
 278+ if ( $params['pageinfo'] === true ) {
 279+ $this->addTables( 'page' );
 280+ $this->addJoinConds(
 281+ array(
 282+ 'page' => array( 'INNER JOIN', 'page_id=rev_page' ),
 283+ )
 284+ );
 285+ $selectFields = array_merge( $selectFields,
 286+ array( 'page_namespace', 'page_title', 'page_latest' )
 287+ );
 288+ }
 289+ $this->addFields( $selectFields );
272290 $dbres = $this->select(__METHOD__);
273 -
 291+ $limit = $params['limit'];
274292 $result = $this->getResult();
275 - $limit = $params['limit'];
276293
277294 if ( $this->xmlDumpMode ) {
278295 # use default IIS / Apache execution time limit which much larger than default PHP limit
@@ -280,19 +297,30 @@
281298 $db->dataSeek( $dbres, $count - 1 );
282299 $last_row = $db->fetchObject( $dbres );
283300 $db->dataSeek( $dbres, 0 );
284 - # I don't know how to remove last element of db result list without of re-sending the select
285 - # do we really need rev_deleted ???
 301+ $this->addOption( 'LIMIT', $params['limit'] );
286302 $selectFields = array_merge( $selectFields,
287 - array( 'page_id', 'page_namespace', 'page_title', 'page_restrictions', 'page_is_redirect', 'rev_user', 'rev_text_id', 'rev_deleted', 'rev_minor_edit', 'rev_comment', 'old_text' )
 303+ array( 'page_id',
 304+ 'page_restrictions',
 305+ 'page_is_redirect',
 306+ 'rev_user',
 307+ 'rev_text_id',
 308+ 'rev_deleted',
 309+ 'rev_minor_edit',
 310+ 'rev_comment',
 311+ 'old_text' )
288312 );
 313+ if ( $params['pageinfo'] !== true ) {
 314+ $this->addTables( 'page' );
 315+ $this->addJoinConds(
 316+ array(
 317+ 'page' => array( 'INNER JOIN', 'page_id=rev_page' ),
 318+ )
 319+ );
 320+ $selectFields = array_merge( $selectFields,
 321+ array( 'page_namespace', 'page_title', 'page_latest' )
 322+ );
 323+ }
289324 $this->addFields( $selectFields );
290 - $this->addTables( 'page' );
291 - $this->addOption( 'LIMIT', $params['limit'] );
292 - $this->addJoinConds(
293 - array(
294 - 'page' => array( 'INNER JOIN', 'page_id=rev_page' ),
295 - )
296 - );
297325 $dbres = $this->select(__METHOD__);
298326 if ( !$this->rawOutputMode ) {
299327 while ( $row = $db->fetchObject( $dbres ) ) {
@@ -351,7 +379,7 @@
352380 $vals['textlen'] = $row->text_len;
353381 $vals['usertext'] = $row->rev_user_text;
354382 if ( isset( $row->page_namespace ) ) {
355 - $vals['namespace'] = $row->page_namespace;
 383+ $vals['namespace'] = intval( $row->page_namespace );
356384 }
357385 if ( isset( $row->page_title ) ) {
358386 $vals['title'] = $row->page_title;
@@ -359,6 +387,9 @@
360388 if ( isset( $row->page_is_redirect ) ) {
361389 $vals['redirect'] = $row->page_is_redirect;
362390 }
 391+ if ( isset( $row->page_latest ) ) {
 392+ $vals['latest'] = $row->page_latest;
 393+ }
363394 return $vals;
364395 }
365396
@@ -396,6 +427,10 @@
397428 ApiBase :: PARAM_MAX => ApiBase :: LIMIT_BIG1,
398429 ApiBase :: PARAM_MAX2 => ApiBase :: LIMIT_BIG2
399430 ),
 431+ 'exclude_user' => array(
 432+ ApiBase :: PARAM_TYPE => 'user'
 433+ ),
 434+ 'pageinfo' => false,
400435 'xmldump' => false,
401436 'rawxml' => false
402437 );
@@ -407,7 +442,9 @@
408443 'endid' => 'stop revision enumeration on this revid (enum)',
409444 'dir' => 'direction of enumeration - towards "newer" or "older" revisions (enum)',
410445 'limit' => 'limit how many revisions will be returned (enum)',
411 - 'xmldump' => 'return xml dump of selected revisions instead',
 446+ 'exclude_user' => 'exclude revisions created by particular user',
 447+ 'pageinfo' => 'return also information about pages associated with selected revisions',
 448+ 'xmldump' => 'return also xml dump of selected revisions',
412449 'rawxml' => 'return xml dump as raw xml'
413450 );
414451 }
@@ -422,12 +459,18 @@
423460 'api.php?action=revisionhistory',
424461 'The same as it would look in JSON (use without fm postfix)',
425462 'api.php?action=revisionhistory&format=jsonfm',
 463+ 'The same with associated page info (use without fm postfix)',
 464+ 'api.php?action=revisionhistory&pageinfo&format=jsonfm',
 465+ 'Most recently created revisions with no revisions created by WikiSyncBot',
 466+ 'api.php?action=revisionhistory&exclude_user=WikiSyncBot',
426467 'Get first results (with continuation) of revisions with id from 20000 to 19000',
427468 'api.php?action=revisionhistory&startid=20000&endid=19000',
428469 'Get first results (with continuation) of revisions with id values from 19000 to 20000 in reverse order',
429470 'api.php?action=revisionhistory&startid=19000&endid=20000&dir=newer',
430471 'Get xml dump of first results (with continuation) of revisions with id values from 19000 (wrap)',
431472 'api.php?action=revisionhistory&startid=19000&dir=newer&xmldump&format=jsonfm',
 473+ 'Get xml dump of first results (with continuation) of revisions with id values from 19000 (wrap) with associated page info',
 474+ 'api.php?action=revisionhistory&startid=19000&dir=newer&xmldump&format=jsonfm',
432475 'Get xml dump of first results (no continuation) of revisions with id values from 19000 (raw xml)',
433476 'api.php?action=revisionhistory&startid=19000&dir=newer&xmldump&rawxml',
434477 'Standard api xml export in nowrap mode (just for comparsion)',
@@ -440,7 +483,7 @@
441484 }
442485 } /* end of ApiRevisionHistory class */
443486
444 -class ApiGetFile extends ApiQueryBase {
 487+class ApiGetFile extends ApiBase {
445488
446489 var $dbkey = ''; // a dbkey name of file
447490 var $fpath; // a filesystem path to file
@@ -604,3 +647,88 @@
605648 }
606649
607650 } /* end of ApiGetFile class */
 651+
 652+class ApiSyncImport extends ApiImport {
 653+
 654+ public function __construct($main, $action) {
 655+ parent :: __construct($main, $action);
 656+ }
 657+
 658+ public function execute() {
 659+ global $wgUser;
 660+ if ( !$wgUser->isAllowed( 'import' ) ) {
 661+ $this->dieUsageMsg( array('cantimport') );
 662+ }
 663+ $params = $this->extractRequestParams();
 664+ if ( !isset( $params['token'] ) ) {
 665+ $this->dieUsageMsg( array('missingparam', 'token') );
 666+ }
 667+ if ( !$wgUser->matchEditToken( $params['token'] ) ) {
 668+ $this->dieUsageMsg( array('sessionfailure') );
 669+ }
 670+ $source = null;
 671+ if ( !$wgUser->isAllowed( 'importupload' ) ) {
 672+ $this->dieUsageMsg( array('cantimport-upload') );
 673+ }
 674+ $source = ImportStreamSource::newFromUpload( 'xml' );
 675+ if ( $source instanceof Status ) {
 676+ if ( $source->isOK() ) {
 677+ $source = $source->value;
 678+ } else {
 679+ $this->dieUsageMsg( array('import-unknownerror', $source->getWikiText() ) );
 680+ }
 681+ } elseif ( $source instanceof WikiErrorMsg ) {
 682+ $this->dieUsageMsg( array_merge( array($source->getMessageKey()), $source->getMessageArgs() ) );
 683+ } elseif ( WikiError::isError( $source ) ) {
 684+ // This shouldn't happen
 685+ $this->dieUsageMsg( array('import-unknownerror', $source->getMessage() ) );
 686+ }
 687+ $importer = new WikiImporter( $source );
 688+ $reporter = new WikiSyncImportReporter( $importer, true, '', wfMsg( 'wikisync_log_imported_by' ) );
 689+
 690+ $result = $importer->doImport();
 691+ if ( $result instanceof WikiXmlError ) {
 692+ $this->dieUsageMsg( array('import-xml-error',
 693+ $result->mLine,
 694+ $result->mColumn,
 695+ $result->mByte . $result->mContext,
 696+ xml_error_string($result->mXmlError) ) );
 697+ } elseif ( WikiError::isError( $result ) ) {
 698+ // This shouldn't happen
 699+ $this->dieUsageMsg( array('import-unknownerror', $result->getMessage() ) );
 700+ }
 701+ $resultData = $reporter->getData();
 702+ $this->getResult()->setIndexedTagName( $resultData, 'page' );
 703+ $this->getResult()->addValue( null, $this->getModuleName(), $resultData );
 704+ }
 705+
 706+ public function getAllowedParams() {
 707+ global $wgImportSources;
 708+ return array (
 709+ 'token' => null,
 710+ 'xml' => null,
 711+ );
 712+ }
 713+
 714+ public function getParamDescription() {
 715+ return array (
 716+ 'token' => 'Import token obtained through prop=info',
 717+ 'xml' => 'Uploaded XML file',
 718+ );
 719+ }
 720+
 721+ public function getDescription() {
 722+ return array (
 723+ 'Import a page from XML file, with suppressing of creation of informational null revisions'
 724+ );
 725+ }
 726+
 727+ protected function getExamples() {
 728+ return array();
 729+ }
 730+
 731+ public function getVersion() {
 732+ return __CLASS__ . ': $Id$';
 733+ }
 734+
 735+} /* end of ApiSyncImport class */
Index: trunk/extensions/WikiSync/WikiSyncPage.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.3.1
 32+ * @version 0.3.2
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -61,7 +61,7 @@
6262 ),
6363 array( '__tag'=>'tr',
6464 array( '__tag'=>'td', wfMsgHtml( 'wikisync_remote_wiki_user' ) ),
65 - array( '__tag'=>'td', array( '__tag'=>'input', 'type'=>'text', 'name'=>'remote_wiki_user', 'value'=>$remote_wiki_user ) )
 65+ array( '__tag'=>'td', array( '__tag'=>'input', 'type'=>'text', 'name'=>'remote_wiki_user', 'value'=>$remote_wiki_user, 'disabled'=>'' ) )
6666 ),
6767 array( '__tag'=>'tr',
6868 array( '__tag'=>'td', wfMsgHtml( 'wikisync_remote_wiki_pass' ) ),
Index: trunk/extensions/WikiSync/WikiSyncClient.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.3.1
 32+ * @version 0.3.2
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -260,7 +260,7 @@
261261 return true;
262262 }
263263
264 - /*
 264+ /**
265265 * called via AJAX to perform remote login via the API
266266 * @param $args[0] : remote wiki root
267267 * @param $args[1] : remote wiki user
@@ -347,22 +347,23 @@
348348 return $json_result->getResult( $response->login->result );
349349 }
350350
351 - /*
 351+ /**
352352 * Access to local API
353353 * @param $api_params string in JSON format {key:val} or PHP array ($key=>val)
354354 * @return result of local API query
355355 */
356356 static function localAPIwrap( $api_params ) {
 357+ global $wgEnableWriteAPI;
357358 if ( is_string( $api_params ) ) {
358359 $api_params = FormatJson::decode( $api_params, true );
359360 }
360361 $req = new FauxRequest( $api_params );
361 - $api = new ApiMain( $req );
 362+ $api = new ApiMain( $req, $wgEnableWriteAPI );
362363 $api->execute();
363364 return $api->getResultData();
364365 }
365366
366 - /*
 367+ /**
367368 * called via AJAX to perform API request on local wiki (HTTP GET)
368369 * @param $args[0] : API query parameters line in JSON format {'key':'val'} or PHP associative array
369370 * @param $args[1] : optional, type of result:
@@ -402,7 +403,7 @@
403404 return $json_result->getResult();
404405 }
405406
406 - /*
 407+ /**
407408 * called via AJAX to perform API request on remote wiki (HTTP GET/POST)
408409 * @param $args[0] : remote context in JSON format, keys
409410 * { 'wikiroot':val, 'userid':val, 'username':val, 'logintoken':val, 'cookieprefix':val, 'sessionid':val }
@@ -549,7 +550,8 @@
550551 }
551552 fclose( $fp );
552553 if ( self::$directionToLocal ) {
553 - # suppress "pear mail" smtp bugs in EmailNotification::actuallyNotifyOnPageChange()
 554+ # suppress "pear mail" possible smtp fatal errors
 555+ # in EmailNotification::actuallyNotifyOnPageChange()
554556 $wgSMTP = false;
555557 $wgEnableEmail = false;
556558 $wgEnableUserEmail = false;
@@ -565,25 +567,46 @@
566568 return $json_result->getResult( 'no_import_rights' );
567569 }
568570 $source = ImportStreamSource::newFromFile( $fname );
569 - if ( !$source->isOK() ) {
 571+ $err_msg = null;
 572+ if ( $source instanceof Status ) {
 573+ if ( $source->isOK() ) {
 574+ $source = $source->value;
 575+ } else {
 576+ $err_msg = $source->getWikiText();
 577+ }
 578+ } elseif ( $source instanceof WikiErrorMsg || WikiError::isError( $source ) ) {
 579+ $err_msg = $source->getMessage();
 580+ }
 581+ if ( $err_msg !== null ) {
570582 @unlink( $fname );
571 - return $json_result->getResult( 'import', $source->getWikiText() );
 583+ return $json_result->getResult( 'import', $err_msg );
572584 }
573 - $importer = new WikiImporter( $source->value );
574 - $reporter = new WikiSyncImportReporter( $importer, true, '', wfMsg( 'wikisync_log_imported_by' ) );
575 - try {
576 - $importer->doImport();
577 - } catch ( MWException $e ) {
578 - return $json_result->getResult( 'import', $e->getMessage() );
 585+ $importer = new WikiImporter( $source );
 586+ $reporter = new WikiSyncImportReporter( $importer, false, '', wfMsg( 'wikisync_log_imported_by' ) );
 587+ $result = $importer->doImport();
 588+ @fclose( $source->mHandle );
 589+ if ( !WikiSyncSetup::$debug_mode ) {
 590+ @unlink( $fname );
579591 }
580 - @fclose( $source->value->mHandle );
581 - @unlink( $fname );
 592+ if ( $result instanceof WikiXmlError ) {
 593+ $r =
 594+ array(
 595+ 'line' => $result->mLine,
 596+ 'column' => $result->mColumn,
 597+ 'context' => $result->mByte . $result->mContext,
 598+ 'xmlerror' => xml_error_string( $result->mXmlError )
 599+ );
 600+ $json_result->append( $r );
 601+ return $json_result->getResult( 'import', $result->getMessage() );
 602+ } elseif ( WikiError::isError( $result ) ) {
 603+ return $json_result->getResult( 'import', $source->getMessage() );
 604+ }
582605 $resultData = $reporter->getData();
583606 $json_result->setStatus( '1' ); // API success
584607 return $json_result->getResult();
585608 } else {
586609 $APIparams = array(
587 - 'action' => 'import',
 610+ 'action' => 'syncimport',
588611 'format' => 'json',
589612 'token' => $dstImportToken,
590613 );
@@ -597,7 +620,7 @@
598621 }
599622 }
600623
601 - /*
 624+ /**
602625 * called via AJAX to perform synchronization of one XML chunk from source to destination wiki
603626 * @param $args[0] : remote context in JSON format, keys
604627 * { 'wikiroot':val, 'userid':val, 'username':val, 'logintoken':val, 'cookieprefix':val, 'sessionid':val }
@@ -613,6 +636,7 @@
614637 $APIparams = array(
615638 'action' => 'revisionhistory',
616639 'format' => 'json',
 640+ 'exclude_user' => WikiSyncSetup::$remote_wiki_user,
617641 'xmldump' => '',
618642 'dir' => 'newer',
619643 'startid' => $client_params['startid'],
@@ -623,7 +647,7 @@
624648 $result['ws_msg'] = 'source: ' . $result['ws_msg'] . ' (' . __METHOD__ . ')';
625649 return FormatJson::encode( $result );
626650 }
627 - # collect the file titles existed in current chunk's revisions
 651+ # collect the file titles that exist in current chunk's revisions
628652 $files = array();
629653 foreach ( $result['query']['revisionhistory'] as $entry ) {
630654 if ( $entry['namespace'] == NS_FILE && $entry['redirect'] === '0' ) {
@@ -658,7 +682,7 @@
659683 return array( 'titles'=>$titles, 'sha1'=>$sha1, 'sizes'=>$sizes, 'timestamps'=>$timestamps );
660684 }
661685
662 - /*
 686+ /**
663687 * called via AJAX to compare source and destination list of files
664688 * @param $args[0] : remote context in JSON format, keys
665689 * { 'wikiroot':val, 'userid':val, 'username':val, 'logintoken':val, 'cookieprefix':val, 'sessionid':val }
@@ -726,7 +750,7 @@
727751 return $wgTmpDirectory . '/' . $snoopy->logintoken . '_' . $snoopy->sessionid . '_' . $chunk_fname;
728752 }
729753
730 - /*
 754+ /**
731755 * called via AJAX to transfer one chunk of file from source to destination wiki
732756 * @param $args[0] : remote context in JSON format, keys
733757 * { 'wikiroot':val, 'userid':val, 'username':val, 'logintoken':val, 'cookieprefix':val, 'sessionid':val }
@@ -833,8 +857,8 @@
834858 }
835859 }
836860
837 - /*
838 - * called via AJAX to transfer one chunk of file from source to destination wiki
 861+ /**
 862+ * called via AJAX to store previousely uploaded temporary file into local repository
839863 * @param $args[0] : remote context in JSON format, keys
840864 * { 'wikiroot':val, 'userid':val, 'username':val, 'logintoken':val, 'cookieprefix':val, 'sessionid':val }
841865 * @param $args[1] : client parameters line in JSON format {'key':'val'}
@@ -871,7 +895,7 @@
872896 if ( !$status->isGood() ) {
873897 return $json_result->getResult( 'upload', $status->getWikiText() );
874898 }
875 - if ( !unlink( $chunk_fpath ) ) {
 899+ if ( !@unlink( $chunk_fpath ) ) {
876900 return $json_result->getResult( 'chunk_file', 'Cannot unlink temporary file ' . $chunk_fpath . ' in ' . __METHOD__ );
877901 }
878902 // API success
Index: trunk/extensions/WikiSync/WikiSync.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.3.1
 32+ * @version 0.3.2
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -108,10 +108,17 @@
109109 class WikiSyncSetup {
110110
111111 const COOKIE_EXPIRE_TIME = 2592000; // 60 * 60 * 24 * 30; see also WikiSync.js, WikiSync.cookieExpireTime
 112+ # please never change next value in between the synchronizations
 113+ # otherwise null revisions created by ImportReporter::reportPage
 114+ # will not be skipped, thus fake synchronizations might occur
 115+ const WIKISYNC_BOT_NAME = 'WikiSyncBot';
112116
 117+ static $remote_wiki_user = self::WIKISYNC_BOT_NAME;
 118+ static $report_null_revisions = false;
113119 # {{{ changable in LocalSettings.php :
 120+ # debug mode (do not erase temporary XML dump files)
 121+ static $debug_mode = false;
114122 static $remote_wiki_root = 'http://www.mediawiki.org/w';
115 - static $remote_wiki_user = '';
116123 static $proxy_address = ''; # 'http://10.0.0.78:3128';
117124 # which user groups can synchronize from remote to local
118125 static $rtl_access_groups = array( 'user' );
@@ -126,7 +133,7 @@
127134 static $proxy_pass = '';
128135 # }}}
129136
130 - static $version = '0.3.1'; // version of extension
 137+ static $version = '0.3.2'; // version of extension
131138 static $ExtDir; // filesys path with windows path fix
132139 static $ScriptPath; // apache virtual path
133140
@@ -181,11 +188,13 @@
182189 $wgAutoloadClasses['ApiWikiSync'] =
183190 $wgAutoloadClasses['ApiRevisionHistory'] =
184191 $wgAutoloadClasses['ApiFindSimilarRev'] =
185 - $wgAutoloadClasses['ApiGetFile'] = self::$ExtDir . '/WikiSyncApi.php';
 192+ $wgAutoloadClasses['ApiGetFile'] =
 193+ $wgAutoloadClasses['ApiSyncImport'] = self::$ExtDir . '/WikiSyncApi.php';
186194
187195 $wgAPIModules['revisionhistory'] = 'ApiRevisionHistory';
188196 $wgAPIModules['similarrev'] = 'ApiFindSimilarRev';
189197 $wgAPIModules['getfile'] = 'ApiGetFile';
 198+ $wgAPIModules['syncimport'] = 'ApiSyncImport';
190199
191200 $wgAjaxExportList[] = 'WikiSyncClient::remoteLogin';
192201 $wgAjaxExportList[] = 'WikiSyncClient::localAPIget';
@@ -273,15 +282,15 @@
274283 }
275284
276285 static function checkUserMembership( $groups ) {
277 - global $wgUser, $wgLang;
278 - $ug = $wgUser->getEffectiveGroups();
279 - if ( !$wgUser->isAnon() && !in_array( 'user', $ug ) ) {
 286+ global $wgLang;
 287+ $ug = self::$user->getEffectiveGroups();
 288+ if ( !self::$user->isAnon() && !in_array( 'user', $ug ) ) {
280289 $ug[] = 'user';
281290 }
282291 if ( array_intersect( $groups, $ug ) ) {
283292 return true;
284293 }
285 - return wfMsg( 'wikisync_api_result_noaccess', $wgLang->commaList( $groups ) );
 294+ return wfMsgExt( 'wikisync_api_result_noaccess', array( 'parsemag' ), $wgLang->commaList( $groups ), count( $groups ) );
286295 }
287296
288297 /**
@@ -294,12 +303,15 @@
295304 * @return true, when the current user has access to synchronization;
296305 * string error message, when the current user has no access
297306 */
298 - static function initUser( $direction = null) {
 307+ static function initUser( $direction = null ) {
299308 global $wgUser, $wgRequest;
300309 self::$user = is_object( $wgUser ) ? $wgUser : new User();
301310 self::$response = $wgRequest->response();
 311+ self::$cookie_prefix = 'WikiSync_' . md5( self::$user->getName() ) . '_';
302312 wfLoadExtensionMessages( 'WikiSync' );
303 - self::$cookie_prefix = 'WikiSync_' . md5( self::$user->getName() ) . '_';
 313+ if ( self::$user->getName() !== self::WIKISYNC_BOT_NAME ) {
 314+ return wfMsg( 'wikisync_unsupported_user', self::WIKISYNC_BOT_NAME );
 315+ }
304316 if ( $direction === true ) {
305317 return self::checkUserMembership( self::$rtl_access_groups );
306318 } elseif ( $direction === false ) {
Index: trunk/extensions/WikiSync/WikiSyncQXML.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.3.1
 32+ * @version 0.3.2
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
Index: trunk/extensions/WikiSync/README
@@ -1,4 +1,4 @@
2 -MediaWiki extension WikiSync, version 0.3.1
 2+MediaWiki extension WikiSync, version 0.3.2
33
44 WikiSync allows an AJAX-based synchronization of revisions and files between
55 global wiki site and it's local mirror. Files download can optionally be disabled,
Index: trunk/extensions/WikiSync/WikiSync.i18n.php
@@ -35,9 +35,10 @@
3636 'wikisync_apply_button' => 'Apply',
3737 'wikisync_log_imported_by' => 'Imported by [[Special:WikiSync|WikiSync]]',
3838 'wikisync_log_uploaded_by' => 'Uploaded by [[Special:WikiSync|WikiSync]]',
 39+ 'wikisync_unsupported_user' => 'Only a special bot user $1 can perform wiki synchronizations. Please login as $1. Do not change $1 name in between the synchronizations, otherwise informational null revisions will not be properly skipped (see [http://www.mediawiki.org/wiki/Extension:WikiSync] for more info).',
3940 'wikisync_api_result_unknown_action' => 'Unknown API action',
4041 'wikisync_api_result_exception' => 'Exception occured in local API call',
41 - 'wikisync_api_result_noaccess' => 'Only members of the following groups can perform this action: $1',
 42+ 'wikisync_api_result_noaccess' => 'Only members of the following {{PLURAL:$2|group|groups}} can perform this action: $1',
4243 'wikisync_api_result_invalid_parameter' => 'Invalid value of parameter',
4344 'wikisync_api_result_http' => 'HTTP error while querying data from remote API',
4445 'wikisync_api_result_Unsupported' => 'Your version of MediaWiki is unsupported (less than 1.15)',
@@ -1232,6 +1233,7 @@
12331234 'wikisync_apply_button' => 'Применить',
12341235 'wikisync_log_imported_by' => 'Импортировано с помощью [[Special:WikiSync]]',
12351236 'wikisync_log_uploaded_by' => 'Загружено с помощью [[Special:WikiSync]]',
 1237+ 'wikisync_unsupported_user' => 'Только специальный бот под именем $1 может синхронизировать вики сайты. Пожалуйста зайдите как пользователь $1. Не изменяйте имя учетной записи $1 между синхронизациями, в противном случае информационные нулевые ревизии не будут правильно пропущены (см. [http://www.mediawiki.org/wiki/Extension:WikiSync] для более подробной информации).',
12361238 'wikisync_api_result_unknown_action' => 'Неизвестное действие (action) API',
12371239 'wikisync_api_result_exception' => 'Произошло исключение в местном API-вызове',
12381240 'wikisync_api_result_noaccess' => 'Только пользователи, входящие в нижеперечисленные группы, могут выполнять указанное действие: ($1)',
Index: trunk/extensions/WikiSync/INSTALL
@@ -1,4 +1,4 @@
2 -MediaWiki extension WikiSync, version 0.3.1
 2+MediaWiki extension WikiSync, version 0.3.2
33
44 * download the latest available version and extract it to your wiki extension directory.
55 * add the following line to LocalSettings.php
Index: trunk/extensions/WikiSync/WikiSync.js
@@ -27,7 +27,7 @@
2828 * * Add this line at the end of your LocalSettings.php file :
2929 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3030 *
31 - * @version 0.3.1
 31+ * @version 0.3.2
3232 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3333 * @author Dmitriy Sintsov <questpc@rambler.ru>
3434 * @addtogroup Extensions
@@ -127,6 +127,9 @@
128128 srcWikiRoot : '',
129129 dstWikiRoot : '',
130130
 131+ // remote login form DOM node
 132+ loginForm : null,
 133+
131134 // revision ids of source wiki (dichotomy search)
132135 // note that all of these should be numbers, while API/callback parameters should be string
133136 srcFirstId : null, // very first revid
@@ -153,7 +156,7 @@
154157 syncFiles : false, // true, when files should be synched as well
155158 fileList : [], // list of files in format of {'title':,'size':,'timestamp':}
156159 fileListIdx : 0, // current index of the list of files
157 - // currently _accumulated_ size of all files in fileList (counted in chunks, file by fule)
 160+ // currently _accumulated_ size of all files in fileList (counted in chunks, file by file)
158161 fileListSize : 0,
159162 // currently accumulated offset (which is also a current size) of currently transferred file
160163 currFileOffset : 0,
@@ -824,8 +827,8 @@
825828 case 'xml_chunk' :
826829 var clientParams = {
827830 'startid' : parseInt( operation.startid ),
828 - // please do not use larger value because it can cause memory exhaust errors and php timeouts
829 - 'limit' : 10,
 831+ // please do not use larger value because it may cause memory exhaust errors and php timeouts
 832+ 'limit' : (typeof operation.limit === 'undefined') ? 10 : parseInt( operation.limit ),
830833 'dst_import_token' : this.dstImportToken
831834 };
832835 var nextOp = {
@@ -862,12 +865,12 @@
863866 return;
864867 }
865868 // try to synchronize next chunk
866 - var params = {
 869+ var nextOp = {
867870 'fname' : 'synchronize',
868871 'opcode' : 'xml_chunk',
869872 'startid' : '' + this.xmlContinueStartId
870873 };
871 - this.synchronize( params );
 874+ this.synchronize( nextOp );
872875 return;
873876 case 'success' :
874877 this.filesPercents.setVisibility( false );
@@ -972,6 +975,7 @@
973976 case 'start' :
974977 var APIparams = {
975978 'action' : 'revisionhistory',
 979+ 'exclude_user' : 'WikiSyncBot',
976980 'format' : 'json',
977981 'dir' : 'older',
978982 'limit' : '1'
@@ -1045,6 +1049,7 @@
10461050 }
10471051 // disable all buttons
10481052 this.setButtons( false );
 1053+ this.syncFiles = this.loginForm.ws_sync_files.checked;
10491054 WikiSyncScheduler.reset();
10501055 this.schedulerLogger.log(
10511056 this.formatMessage(
@@ -1073,10 +1078,10 @@
10741079 this.filesPercents.setVisibility( false );
10751080 this.showIframe( '' );
10761081 this.errorDefaultAction();
1077 - var loginForm = document.getElementById( 'remote_login_form' );
 1082+ this.loginForm = document.getElementById( 'remote_login_form' );
10781083 // {{{ restore remote login / password cookies to login form, if any
1079 - WikiSyncUtils.cookieToInput( 'ruser', loginForm.remote_wiki_user );
1080 - var rpass = WikiSyncUtils.cookieToInput( 'rpass', loginForm.remote_wiki_pass );
 1084+ WikiSyncUtils.cookieToInput( 'ruser', this.loginForm.remote_wiki_user );
 1085+ var rpass = WikiSyncUtils.cookieToInput( 'rpass', this.loginForm.remote_wiki_pass );
10811086 // }}}
10821087 // {{{ restore scheduler cookies to scheduler form, if any
10831088 var schedulerForm = document.getElementById( 'scheduler_form' );
@@ -1085,9 +1090,9 @@
10861091 WikiSyncUtils.cookieToInput( 'auto_sync_time_interval', schedulerForm.ws_auto_sync_time_interval );
10871092 // }}}
10881093 if ( rpass !== null ) {
1089 - loginForm.ws_store_password.checked = true;
 1094+ this.loginForm.ws_store_password.checked = true;
10901095 // try to autologin
1091 - this.submitRemoteLogin( loginForm );
 1096+ this.submitRemoteLogin( this.loginForm );
10921097 }
10931098 WikiSyncScheduler.setup( schedulerForm );
10941099 window.setTimeout( function() { WikiSyncScheduler.poll(); }, this.pollTimeout );

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r75865v 0.2.1. Separate settings for user groups allowed to perform wiki synchroniz...questpc18:57, 2 November 2010

Status & tagging log