r68628 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r68627‎ | r68628 | r68629 >
Date:16:15, 27 June 2010
Author:nikerabbit
Status:ok
Tags:
Comment:
First untested version of translatable page moving feature.

Not yet enabled by default, and there is a reason for that.
Modified paths:
  • /trunk/extensions/Translate/PageTranslation.i18n.php (modified) (history)
  • /trunk/extensions/Translate/Translate.php (modified) (history)
  • /trunk/extensions/Translate/_autoload.php (modified) (history)
  • /trunk/extensions/Translate/tag/MoveJob.php (added) (history)
  • /trunk/extensions/Translate/tag/PageTranslationHooks.php (modified) (history)
  • /trunk/extensions/Translate/tag/SpecialPageTranslationMovePage.php (added) (history)

Diff [purge]

Index: trunk/extensions/Translate/tag/PageTranslationHooks.php
@@ -347,6 +347,8 @@
348348 return false;
349349 }
350350 } elseif ( $action === 'move' || $action === 'delete' ) {
 351+ global $wgTranslateEnablePageMoving;
 352+ if ( $wgTranslateEnablePageMoving && $action === 'move' ) return true;
351353 $page = TranslatablePage::newFromTitle( $title );
352354 if ( $page->getMarkedTag() ) {
353355 $result = array( 'tpt-move-impossible' );
@@ -533,15 +535,36 @@
534536
535537 $language = $forContent ? $wgContLang : $wgLang;
536538 $opts = array( 'parseinline', 'language' => $language );
 539+
537540 $_ = unserialize( $params[0] );
538541 $user = $_['user'];
539542
540543 if ( $action === 'mark' ) {
541 - $revision = $_['revision'];
542 - return wfMsgExt( 'pt-log-mark', $opts, $title->getPrefixedText(), $user, $revision );
 544+ return wfMsgExt( 'pt-log-mark', $opts, $title->getPrefixedText(), $user, $_['revision'] );
543545 } elseif( $action === 'unmark' ) {
544546 return wfMsgExt( 'pt-log-unmark', $opts, $title->getPrefixedText(), $user );
 547+ } elseif( $action === 'moveok' ) {
 548+ return wfMsgExt( 'pt-log-moveok', $opts, $title->getPrefixedText(), $user, $_['target'] );
 549+ } elseif( $action === 'movenok' ) {
 550+ return wfMsgExt( 'pt-log-moveok', $opts, $title->getPrefixedText(), $user, $_['target'] );
545551 }
546552 }
547553
 554+ public static function replaceMovePage( &$list ) {
 555+ $list['Movepage'] = 'SpecialPageTranslationMovePage';
 556+ return true;
 557+ }
 558+
 559+ public static function lockedPagesCheck( $title, $user, $action, &$result ) {
 560+ global $wgMemc;
 561+ if ( $wgMemc->get( 'pt-lock', $title->getPrefixedText() ) === true ) {
 562+ $result = array( 'pt-locked-page' );
 563+ return false;
 564+ }
 565+
 566+ return true;
 567+ }
 568+
 569+
 570+
548571 }
Index: trunk/extensions/Translate/tag/SpecialPageTranslationMovePage.php
@@ -0,0 +1,450 @@
 2+<?php
 3+
 4+class SpecialPageTranslationMovePage extends SpecialPage {
 5+ // Basif form parameters both as text and as titles
 6+ protected $newText, $newTitle, $oldText, $oldTitle;
 7+
 8+ // Other form parameters
 9+ /**
 10+ * 'check' or 'perform'
 11+ */
 12+ protected $subaction;
 13+
 14+ /**
 15+ * There must be reason for everything.
 16+ */
 17+ protected $reason;
 18+
 19+ /**
 20+ * Allow skipping non-translation subpages.
 21+ */
 22+ protected $moveSubpages;
 23+
 24+
 25+ /**
 26+ * TranslatablePage instance.
 27+ */
 28+ protected $page;
 29+
 30+ /**
 31+ * User instance.
 32+ */
 33+ protected $user;
 34+
 35+ public function __construct() {
 36+ parent::__construct( 'Movepage' );
 37+ }
 38+
 39+ /*
 40+ * Partially copies from SpecialMovepage.php, because it cannot be
 41+ * extented in other ways.
 42+ */
 43+ public function execute( $par ) {
 44+ global $wgOut, $wgRequest, $wgUser;
 45+
 46+ // Yes, the use of getVal() and getText() is wanted, see bug 20365
 47+ $this->oldText = $wgRequest->getVal( 'wpOldTitle', $par );
 48+ $this->newText = $wgRequest->getText( 'wpNewTitle' );
 49+
 50+ $this->oldTitle = Title::newFromText( $this->oldText );
 51+ $this->newTitle = Title::newFromText( $this->newText );
 52+
 53+ $this->reason = $wgRequest->getText( 'reason' );
 54+ // Checkboxes that default being checked are tricky
 55+ $this->moveSubpages = $wgRequest->getBool( 'subpages', !$wgRequest->wasPosted() );
 56+
 57+ $this->user = $wgUser;
 58+
 59+ if ( $this->doBasicChecks() !== true ) {
 60+ return;
 61+ }
 62+
 63+ // Real stuff starts here
 64+ $page = TranslatablePage::newFromTitle( $this->oldTitle );
 65+ if ( $page->getMarkedTag() !== false ) {
 66+ $this->page = $page;
 67+
 68+ $wgOut->setPagetitle( wfMsg( 'pt-movepage-title', $this->oldText ) );
 69+ $link = $this->user->getSkin()->link( $this->oldTitle );
 70+ $wgOut->setSubtitle( wfMsg( 'move-page-backlink', $link ) );
 71+
 72+
 73+ if ( !$this->user->isAllowed( 'pagetranslation' ) ) {
 74+ $wgOut->permissionRequired( 'pagetranslation' );
 75+ return;
 76+ }
 77+
 78+ // Is there really no better way to do this?
 79+ $subactionText = $wgRequest->getText( 'subaction' );
 80+ switch ( $subactionText ) {
 81+ case wfMsg( 'pt-movepage-action-check'):
 82+ $subaction = 'check'; break;
 83+ case wfMsg( 'pt-movepage-action-perform'):
 84+ $subaction = 'perform'; break;
 85+ case wfMsg( 'pt-movepage-action-other'):
 86+ $subaction = ''; break;
 87+ default:
 88+ $subaction = '';
 89+ }
 90+
 91+ if ( $subaction === 'check' && $this->checkToken() && $wgRequest->wasPosted() ) {
 92+ $blockers = $this->checkMoveBlockers( );
 93+ if ( count( $blockers ) ) {
 94+ $this->showErrors( $blockers );
 95+ $this->showForm();
 96+ } else {
 97+ $this->showConfirmation();
 98+ }
 99+ } elseif( $subaction === 'perform' && $this->checkToken() && $wgRequest->wasPosted() ) {
 100+ $this->performAction();
 101+ } else {
 102+ $this->showForm();
 103+ }
 104+
 105+ } else {
 106+ // Delegate... don't want to reimplement this
 107+ $this->doNormalMovePage();
 108+ }
 109+ }
 110+
 111+ /**
 112+ * Do the basic checks whether moving is possible and whether
 113+ * the input looks anywhere near sane.
 114+ */
 115+ protected function doBasicChecks() {
 116+ global $wgOut;
 117+ # Check for database lock
 118+ if ( wfReadOnly() ) {
 119+ $wgOut->readOnlyPage();
 120+ return;
 121+ }
 122+
 123+ if( $this->oldTitle === null ) {
 124+ $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
 125+ return;
 126+ }
 127+
 128+ if( !$this->oldTitle->exists() ) {
 129+ $wgOut->showErrorPage( 'nopagetitle', 'nopagetext' );
 130+ return;
 131+ }
 132+
 133+ # Check rights
 134+ $permErrors = $this->oldTitle->getUserPermissionsErrors( 'move', $this->user );
 135+ if( !empty( $permErrors ) ) {
 136+ $wgOut->showPermissionsErrorPage( $permErrors );
 137+ return;
 138+ }
 139+
 140+ // Let the caller know it's safe to continue
 141+ return true;
 142+ }
 143+
 144+ protected function doNormalMovePage() {
 145+ global $action, $wgRequest;
 146+ $form = new MovePageForm( $this->oldTitle, $this->newTitle );
 147+ if ( $action === 'submit' && $this->checkToken() && $wgRequest->wasPosted() ) {
 148+ $form->doSubmit();
 149+ } else {
 150+ $form->showForm( '' );
 151+ }
 152+ }
 153+
 154+ /**
 155+ * Checks token. Use before real actions happen. Have to use wpEditToken
 156+ * for compatibility for SpecialMovepage.php.
 157+ */
 158+ protected function checkToken() {
 159+ global $wgRequest;
 160+ return $this->user->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) );
 161+ }
 162+
 163+ /**
 164+ * Pretty-print the list of errors.
 165+ * @param $errors Array with message key and parameters
 166+ */
 167+ protected function showErrors( array $errors ) {
 168+ global $wgOut, $wgLang;
 169+ if ( count( $errors ) ) {
 170+ $wgOut->addHTML( Html::openElement( 'div', array( 'class' => 'error' ) ) );
 171+ $wgOut->addWikiMsg( 'pt-movepage-blockers', $wgLang->formatNum( count( $errors ) ) );
 172+ $wgOut->addHTML( '<ul>' );
 173+ foreach( $errors as $error ) {
 174+ $wgOut->wrapWikiMsg( '<li>$1</li>', $error + array( 'options' => 'parsemag' ) );
 175+ }
 176+ $wgOut->addHTML( '</ul></div>' );
 177+ }
 178+ }
 179+
 180+ /**
 181+ * The query form.
 182+ */
 183+ protected function showForm( ) {
 184+ global $wgOut;
 185+
 186+ $wgOut->addWikiMsg( 'pt-movepage-intro' );
 187+
 188+ $br = Html::element( 'br' );
 189+ $subaction = array( 'name' => 'subaction' );
 190+ $disabled = array( 'disabled' => 'disabled' );
 191+ $formParams = array( 'method' => 'post', 'action' => $this->getTitle( $this->oldText)->getLocalURL() );
 192+
 193+ $form = array();
 194+ $form[] = Xml::fieldset( wfMsg( 'pt-movepage-legend' ) );
 195+ $form[] = Html::openElement( 'form', $formParams );
 196+ $form[] = Html::hidden( 'wpEditToken', $this->user->editToken() );
 197+ $form[] = Html::hidden( 'wpOldTitle', $this->oldText );
 198+ $this->addInputLabel( $form, wfMsg( 'pt-movepage-current' ), 'wpOldTitleFake', 30, $this->oldText, $disabled );
 199+ $this->addInputLabel( $form, wfMsg( 'pt-movepage-new' ), 'wpNewTitle', 30, $this->newText );
 200+ $this->addInputLabel( $form, wfMsg( 'pt-movepage-reason' ), 'reason', 60, $this->reason );
 201+ $form[] = Xml::checkLabel( wfMsg( 'pt-movepage-subpages' ), 'subpages', 'mw-subpages', $this->moveSubpages, $disabled ) . $br;
 202+ $form[] = Xml::submitButton( wfMsg( 'pt-movepage-action-check' ), $subaction );
 203+ $form[] = Html::closeElement( 'form' );
 204+ $form[] = Html::closeElement( 'fieldset' );
 205+ $wgOut->addHTML( implode( "\n", $form ) );
 206+ }
 207+
 208+ /**
 209+ * Shortcut for keeping the code at least a bit readable. Adds label and input into $form array.
 210+ * @params Many
 211+ */
 212+ protected function addInputLabel( &$form, $label, $name, $size = false , $text = false, $attribs = array() ) {
 213+ $br = Html::element( 'br' );
 214+ list( $label, $input ) = Xml::inputLabelSep( $label, $name, $name, $size, $text, $attribs );
 215+ $form[] = $label.$br;
 216+ $form[] = $input.$br;
 217+ }
 218+
 219+ /**
 220+ * The second form, which still allows changing some things.
 221+ * Lists all the action which would take place.
 222+ */
 223+ protected function showConfirmation() {
 224+ global $wgOut, $wgLang;
 225+
 226+ $wgOut->addWikiMsg( 'pt-movepage-intro' );
 227+
 228+ $base = $this->oldTitle->getPrefixedText();
 229+ $target = $this->newTitle;
 230+ $count = 1; // Base page
 231+
 232+ $wgOut->wrapWikiMsg( '== $1 ==', 'pt-movepage-list-pages' );
 233+ $this->printChangeLine( $base, $this->oldTitle, $target );
 234+
 235+ $wgOut->wrapWikiMsg( '=== $1 ===', 'pt-movepage-list-translation' );
 236+ $translationPages = $this->getTranslationPages();
 237+ foreach ( $translationPages as $old ) {
 238+ $count++;
 239+ $this->printChangeLine( $base, $old, $target );
 240+ }
 241+
 242+ $wgOut->wrapWikiMsg( '=== $1 ===', 'pt-movepage-list-section' );
 243+ $sectionPages = $this->getSectionPages();
 244+ foreach ( $sectionPages as $old ) {
 245+ $count++;
 246+ $this->printChangeLine( $base, $old, $target );
 247+ }
 248+
 249+ $wgOut->wrapWikiMsg( '=== $1 ===', 'pt-movepage-list-other' );
 250+ $subpages = $this->getSubpages();
 251+ foreach ( $subpages as $old ) {
 252+ if ( TranslatablePage::isTranslationPage( $old ) ) continue;
 253+ if ( $this->moveSubpages ) { $count++; }
 254+ $this->printChangeLine( $base, $old, $target, $this->moveSubpages );
 255+ }
 256+
 257+ $wgOut->addWikiText( "----\n" );
 258+ $wgOut->addWikiMsg( 'pt-movepage-list-count', $wgLang->formatNum( $count ) );
 259+
 260+ $br = Html::element( 'br' );
 261+ $disabled = array( 'disabled' => 'disabled' );
 262+ $subaction = array( 'name' => 'subaction' );
 263+ $formParams = array( 'method' => 'post', 'action' => $this->getTitle( $this->oldText )->getLocalURL() );
 264+
 265+ $form = array();
 266+ $form[] = Xml::fieldset( wfMsg( 'pt-movepage-legend' ) );
 267+ $form[] = Html::openElement( 'form', $formParams );
 268+ $form[] = Html::hidden( 'wpEditToken', $this->user->editToken() );
 269+ // Apparently HTML spec says that disabled elements are not submitted... ARGH!
 270+ $form[] = Html::hidden( 'wpOldTitle', $this->oldText );
 271+ $form[] = Html::hidden( 'wpNewTitle', $this->newText );
 272+ $this->addInputLabel( $form, wfMsg( 'pt-movepage-current' ), 'wpOldTitleFake', 30, $this->oldText, $disabled );
 273+ $this->addInputLabel( $form, wfMsg( 'pt-movepage-new' ), 'wpNewTitleFake', 30, $this->newText, $disabled );
 274+ $this->addInputLabel( $form, wfMsg( 'pt-movepage-reason' ), 'reason', 60, $this->reason );
 275+ $form[] = Xml::checkLabel( wfMsg( 'pt-movepage-subpages' ), 'subpages', 'mw-subpages', $this->moveSubpages ) . $br;
 276+ $form[] = Xml::submitButton( wfMsg( 'pt-movepage-action-perform' ), $subaction );
 277+ $form[] = Xml::submitButton( wfMsg( 'pt-movepage-action-other' ), $subaction );
 278+ $form[] = Html::closeElement( 'form' );
 279+ $form[] = Html::closeElement( 'fieldset' );
 280+ $wgOut->addHTML( implode( "\n", $form ) );
 281+ }
 282+
 283+ protected function printChangeLine( $base, $old, $target, $enabled = true ) {
 284+ global $wgOut;
 285+ $to = $this->newPageTitle( $base, $old, $target );
 286+ if ( $enabled ) {
 287+ $wgOut->addWikiText( '* ' . $old->getPrefixedText() . ' → ' . $to );
 288+ } else {
 289+ $wgOut->addWikiText( '* ' . $old->getPrefixedText() );
 290+ }
 291+ }
 292+
 293+ protected function performAction() {
 294+ $jobs = array();
 295+ $titles = array();
 296+
 297+ $target = $this->newTitle;
 298+ $base = $this->oldTitle->getPrefixedText();
 299+
 300+ $translationPages = $this->getTranslationPages();
 301+ foreach ( $translationPages as $old ) {
 302+ $to = $this->newPageTitle( $base, $old, $target );
 303+ $jobs[$old->getPrefixedText()] = MoveJob::newJob( $old, $to, $base );
 304+ }
 305+
 306+ $sectionPages = $this->getSectionPages();
 307+ foreach ( $sectionPages as $old ) {
 308+ $to = $this->newPageTitle( $base, $old, $target );
 309+ $jobs[$old->getPrefixedText()] = MoveJob::newJob( $old, $to, $base );
 310+ }
 311+
 312+ if ( $this->subpages ) {
 313+ $subpages = $this->getSubpages();
 314+ foreach ( $subpages as $old ) {
 315+ if ( TranslatablePage::isTranslationPage( $old ) ) continue;
 316+ $to = $this->newPageTitle( $base, $old, $target );
 317+ $jobs[$old->getPrefixedText()] = MoveJob::newJob( $old, $to, $base );
 318+ }
 319+ }
 320+
 321+ Job::batchInsert( $jobs );
 322+
 323+ global $wgMemc;
 324+ $wgMemc->set( wfMemcKey( 'pt-base', $base ), array_keys( $jobs ), 60*60*6 );
 325+
 326+ $errors = $this->oldTitle->moveTo( $this->newTitle(), true, $this->reason, false );
 327+ if ( $errors ) {
 328+ $this->showErrors( $errors );
 329+ }
 330+
 331+
 332+ //TODO: defer or make faster
 333+ MessageIndexRebuilder::execute();
 334+ $wgOut->addWikiMsg( 'pt-movepage-started' );
 335+ }
 336+
 337+ protected function checkMoveBlockers() {
 338+ $blockers = array();
 339+
 340+ $target = $this->newTitle;
 341+
 342+ if ( !$target ) {
 343+ $blockers[] = array( 'pt-movepage-block-base-invalid' );
 344+ return $blockers;
 345+ }
 346+
 347+ if ( $target->getNamespace() == NS_MEDIAWIKI || $target->getNamespace() == NS_TRANSLATIONS ) {
 348+ $blockers[] = array( 'immobile-target-namespace', $target->getNsText() );
 349+ return $blockers;
 350+ }
 351+
 352+ $base = $this->oldTitle->getPrefixedText();
 353+
 354+ if ( $target->exists() ) {
 355+ $blockers[] = array( 'pt-movepage-block-base-exists', $target->getPrefixedText() );
 356+ } else {
 357+ $errors = $this->oldTitle->isValidMoveOperation( $target, true, $this->reason );
 358+ if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors );
 359+ }
 360+
 361+ // Don't spam the same errors for all pages if base page fails
 362+ if ( $blockers ) return $blockers;
 363+
 364+ $translationPages = $this->getTranslationPages();
 365+ foreach ( $translationPages as $old ) {
 366+ $new = $this->newPageTitle( $base, $old, $target );
 367+ if ( !$new ) {
 368+ $blockers[] = array( 'pt-movepage-block-tp-invalid', $old->getPrefixedText() );
 369+ } elseif ( $new->exists() ) {
 370+ $blockers[] = array( 'pt-movepage-block-tp-exists', $old->getPrefixedText(), $new->getPrefixedText() );
 371+ } else {
 372+ $errors = $old->isValidMoveOperation( $target, false );
 373+ if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors );
 374+ }
 375+ }
 376+
 377+ $sections = $this->getSectionPages();
 378+ foreach ( $sections as $old ) {
 379+ $new = $this->newPageTitle( $base, $old, $target );
 380+ if ( !$new ) {
 381+ $blockers[] = array( 'pt-movepage-block-section-invalid', $old->getPrefixedText() );
 382+ } elseif ( $new->exists() ) {
 383+ $blockers[] = array( 'pt-movepage-block-section-exists', $old->getPrefixedText(), $new->getPrefixedText() );
 384+ } else {
 385+ $errors = $old->isValidMoveOperation( $target, false );
 386+ if ( is_array( $errors ) ) $blockers = array_merge( $blockers, $errors );
 387+ }
 388+ }
 389+
 390+ return $blockers;
 391+ }
 392+
 393+ /**
 394+ * Makes old title into a new title by replacing $base part of old title
 395+ * with $target.
 396+ * @param $base String Title::getPrefixedText() of the base page.
 397+ * @param $old Title The title to convert.
 398+ * @param $target Title The target title for the base page.
 399+ * @return Title
 400+ */
 401+ protected function newPageTitle( $base, Title $old, Title $target ) {
 402+ $search = preg_quote( $base, '~' );
 403+ if ( $old->getNamespace() == NS_TRANSLATIONS ) {
 404+ $new = $old->getText();
 405+ $new = preg_replace( "~^$search~", $target->getPrefixedText(), $new, 1 );
 406+ return Title::makeTitleSafe( NS_TRANSLATIONS, $new );
 407+ } else {
 408+ $new = $old->getPrefixedText();
 409+ $new = preg_replace( "~^$search~", $target->getPrefixedText(), $new, 1 );
 410+ return Title::newFromText( $new );
 411+ }
 412+ }
 413+
 414+ /**
 415+ * Returns all section pages, including those which are currently not active.
 416+ * @return TitleArray.
 417+ */
 418+ protected function getSectionPages() {
 419+ if ( !isset( $this->sectionPages ) ) {
 420+ $base = $this->page->getTitle()->getPrefixedDBKey();
 421+
 422+ $dbw = wfGetDB( DB_MASTER );
 423+ $fields = array( 'page_namespace', 'page_title' );
 424+ $titleCond = 'page_title like \'' . $dbw->escapeLike( $base ) . "/%%'";
 425+ $conds = array( 'page_namespace' => NS_TRANSLATIONS, $titleCond );
 426+ $result = $dbw->select( 'page', $fields, $conds, __METHOD__ );
 427+ $this->sectionPages = TitleArray::newFromResult( $result );
 428+ }
 429+ return $this->sectionPages;
 430+ }
 431+
 432+ /**
 433+ * Returns only translation subpages.
 434+ * @return Array of titles.
 435+ */
 436+ protected function getTranslationPages() {
 437+ if ( !isset( $this->translationPages ) ) {
 438+ $this->translationPages = $this->page->getTranslationPages();
 439+ }
 440+ return $this->translationPages;
 441+ }
 442+
 443+ /**
 444+ * Returns all subpages, if the namespace has them enabled.
 445+ * @return Empty array or TitleArray
 446+ */
 447+ protected function getSubpages() {
 448+ return $this->page->getTitle()->getSubpages();
 449+ }
 450+
 451+}
\ No newline at end of file
Property changes on: trunk/extensions/Translate/tag/SpecialPageTranslationMovePage.php
___________________________________________________________________
Name: svn:eol-style
1452 + native
Index: trunk/extensions/Translate/tag/MoveJob.php
@@ -0,0 +1,147 @@
 2+<?php
 3+/**
 4+ * Job for moving translation pages.
 5+ *
 6+ * @ingroup Extensions
 7+ *
 8+ * @author Niklas Laxström
 9+ * @copyright Copyright © 2008-2010, Niklas Laxström
 10+ * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License 2.0 or later
 11+ */
 12+
 13+class MoveJob extends Job {
 14+ public static function newJob( Title $source, Title $target, $base, User $performer ) {
 15+ global $wgTranslateFuzzyBotName;
 16+
 17+ $job = new self( $source );
 18+ $job->setUser( $wgTranslateFuzzyBotName );
 19+ $job->setTarget( $target->getPrefixedText() );
 20+ $job->setSummary( wfMsgForContent( 'pt-movepage-logreason', $target->getPrefixedText() ) );
 21+ $job->setBase( $base );
 22+ $job->setPerformer( $performer );
 23+ $job->lock();
 24+ return $job;
 25+ }
 26+
 27+ function __construct( $title, $params = array(), $id = 0 ) {
 28+ parent::__construct( __CLASS__, $title, $params, $id );
 29+ }
 30+
 31+ function run() {
 32+ global $wgUser;
 33+
 34+ // Initialization
 35+ $title = $this->title;
 36+ // Other stuff
 37+ $user = $this->getUser();
 38+ $summary = $this->getSummary();
 39+ $target = $this->getTarget();
 40+
 41+ PageTranslationHooks::$allowTargetEdit = true;
 42+ $oldUser = $wgUser;
 43+ $wgUser = $user;
 44+
 45+ // Don't check perms, don't leave a redirect
 46+ $ok = $source->moveTo( $target, false, $summary, false );
 47+ if ( $ok ) {
 48+ $logger = new LogPage( 'pagetranslation' );
 49+ $params = array(
 50+ 'user' => $this->getPerformer(),
 51+ 'target' => $target->getPrefixedText(),
 52+ 'error' => base64_encode( $ok ),
 53+ );
 54+ $logger->addEntry( 'moveok', $title, null, array( serialize( $params ) ) );
 55+ }
 56+
 57+ $wgUser = $oldUser;
 58+ PageTranslationHooks::$allowTargetEdit = false;
 59+
 60+ $this->unlock();
 61+
 62+ global $wgMemc;
 63+ $pages = $wgMemc->get( 'pt-base', $base );
 64+ foreach ( $pages as $page ) {
 65+ if ( $wgMemc->get( 'pt-lock', $page ) === true ) {
 66+ return true;
 67+ }
 68+ }
 69+
 70+ $logger = new LogPage( 'pagetranslation' );
 71+ $params = array(
 72+ 'user' => $this->getPerformer(),
 73+ 'target' => $target->getPrefixedText(),
 74+ );
 75+ $logger->addEntry( 'moveok', $title, null, array( serialize( $params ) ) );
 76+
 77+
 78+ return true;
 79+ }
 80+
 81+ public function setSummary( $summary ) {
 82+ $this->params['summary'] = $summary;
 83+ }
 84+
 85+ public function getSummary() {
 86+ return $this->params['summary'];
 87+ }
 88+
 89+ public function setBase( $base ) {
 90+ $this->params['base'] = $base;
 91+ }
 92+
 93+ public function getBase() {
 94+ return $this->params['base'];
 95+ }
 96+
 97+ public function setPerformer( $performer ) {
 98+ if ( $performer instanceof Performer ) {
 99+ $this->params['performer'] = $performer->getName();
 100+ } else {
 101+ $this->params['performer'] = $performer;
 102+ }
 103+ }
 104+
 105+ public function getPerformer() {
 106+ return $this->params['performer'];
 107+ }
 108+
 109+ public function setTarget( $target ) {
 110+ if ( $target instanceof Title ) {
 111+ $this->params['target'] = $target->getPrefixedText();
 112+ } else {
 113+ $this->params['target'] = $target;
 114+ }
 115+ }
 116+
 117+ public function getTarget() {
 118+ return Title::newFromText( $this->params['summary'] );
 119+ }
 120+
 121+ public function setUser( $user ) {
 122+ if ( $user instanceof User ) {
 123+ $this->params['user'] = $user->getName();
 124+ } else {
 125+ $this->params['user'] = $user;
 126+ }
 127+ }
 128+
 129+ /**
 130+ * Get a user object for doing edits.
 131+ */
 132+ public function getUser() {
 133+ return User::newFromName( $this->params['user'], false );
 134+ }
 135+
 136+ public function lock() {
 137+ global $wgMemc;
 138+ $wgMemc->set( wfMemcKey( 'pt-lock', $title->getPrefixedText() ), true, 60*60*6 );
 139+ $wgMemc->set( wfMemcKey( 'pt-lock', $this->getTarget()->getPrefixedText() ), true, 60*60*6 );
 140+ }
 141+
 142+ public function unlock() {
 143+ global $wgMemc;
 144+ $wgMemc->delete( wfMemcKey( 'pt-lock', $title->getPrefixedText() ) );
 145+ $wgMemc->delete( wfMemcKey( 'pt-lock', $this->getTarget()->getPrefixedText() ) );
 146+ }
 147+
 148+}
Property changes on: trunk/extensions/Translate/tag/MoveJob.php
___________________________________________________________________
Name: svn:eol-style
1149 + native
Index: trunk/extensions/Translate/Translate.php
@@ -77,8 +77,6 @@
7878 # Translation memory updates
7979 $wgHooks['ArticleSaveComplete'][] = 'TranslationMemoryUpdater::update';
8080
81 -
82 -$wgJobClasses['RenderJob'] = 'RenderJob';
8381 $wgAvailableRights[] = 'translate';
8482 $wgAvailableRights[] = 'translate-import';
8583 $wgAvailableRights[] = 'translate-manage';
@@ -364,6 +362,10 @@
365363 */
366364 $wgTranslateYamlLibrary = 'spyc';
367365
 366+
 367+# Temporary variable
 368+$wgTranslateEnablePageMoving = false;
 369+
368370 # Startup code
369371
370372 function efTranslateInit() {
@@ -400,7 +402,13 @@
401403 $wgLogNames['pagetranslation'] = 'pt-log-name';
402404 $wgLogActionsHandlers['pagetranslation/mark'] = 'PageTranslationHooks::formatLogEntry';
403405 $wgLogActionsHandlers['pagetranslation/unmark'] = 'PageTranslationHooks::formatLogEntry';
 406+ $wgLogActionsHandlers['pagetranslation/moveok'] = 'PageTranslationHooks::formatLogEntry';
 407+ $wgLogActionsHandlers['pagetranslation/movenok'] = 'PageTranslationHooks::formatLogEntry';
404408
 409+ global $wgJobClasses;
 410+ $wgJobClasses['RenderJob'] = 'RenderJob';
 411+ $wgJobClasses['MoveJob'] = 'MoveJob';
 412+
405413 // Namespaces
406414 global $wgPageTranslationNamespace, $wgExtraNamespaces;
407415 global $wgNamespacesWithSubpages, $wgNamespaceProtection;
@@ -443,13 +451,22 @@
444452 // Prevent editing of unknown pages in Translations namespace
445453 $wgHooks['getUserPermissionsErrorsExpensive'][] = 'PageTranslationHooks::translationsCheck';
446454
 455+ // Locking during page moves
 456+ $wgHooks['getUserPermissionsErrorsExpensive'][] = 'PageTranslationHooks::lockedPagesCheck';
 457+
447458 $wgHooks['ArticleViewHeader'][] = 'PageTranslationHooks::test';
448459
449460 $wgHooks['ParserTestTables'][] = 'PageTranslationHooks::parserTestTables';
450461
451462 $wgHooks['SkinTemplateToolboxEnd'][] = 'PageTranslationHooks::exportToolbox';
452463
 464+ // Prevent section pages appearing in categories
453465 $wgHooks['LinksUpdate'][] = 'PageTranslationHooks::preventCategorization';
 466+
 467+ global $wgTranslateEnablePageMoving;
 468+ if ( $wgTranslateEnablePageMoving ) {
 469+ $wgHooks['SpecialPage_initList'][] = 'PageTranslationHooks::replaceMovePage';
 470+ }
454471 }
455472 }
456473
Index: trunk/extensions/Translate/_autoload.php
@@ -115,7 +115,9 @@
116116 $wgAutoloadClasses['TPParse'] = $dir . 'tag/TPParse.php';
117117 $wgAutoloadClasses['TPSection'] = $dir . 'tag/TPSection.php';
118118 $wgAutoloadClasses['SpecialPageTranslation'] = $dir . 'tag/SpecialPageTranslation.php';
 119+$wgAutoloadClasses['SpecialPageTranslationMovePage'] = $dir . 'tag/SpecialPageTranslationMovePage.php';
119120 $wgAutoloadClasses['RenderJob'] = $dir . 'tag/RenderJob.php';
 121+$wgAutoloadClasses['MoveJob'] = $dir . 'tag/MoveJob.php';
120122
121123 $wgAutoloadClasses['TranslateYaml'] = $dir . 'utils/TranslateYaml.php';
122124 $wgAutoloadClasses['SpecialManageGroups'] = $dir . 'SpecialManageGroups.php';
Index: trunk/extensions/Translate/PageTranslation.i18n.php
@@ -95,10 +95,53 @@
9696 Section text: <pre>$1</pre>',
9797 'pt-shake-empty' => 'Empty section for marker $1.',
9898
 99+ # logging system
99100 'pt-log-header' => 'Log for actions related to the page translation system',
100101 'pt-log-name' => 'Page translation log',
101102 'pt-log-mark' => '{{GENDER:$2|marked}} revision $3 of page "[[:$1]]" for translation',
102103 'pt-log-unmark' => '{{GENDER:$2|removed}} page "[[:$1]]" from translation',
 104+ 'pt-log-moveok' => '{{GENDER:$2|renamed}} translatable page $1 to [[:$3]]',
 105+ 'pt-log-movenok' => '{{GENDER:$2|encountered}} a problem while moving [[:$1]] to [[:$3]]',
 106+
 107+
 108+ # move page replacement
 109+ 'pt-movepage-title' => 'Move translatable page $1',
 110+ 'pt-movepage-blockers' => 'The translatable page cannot be moved to a new name because of the following {{PLURAL:$1|error|errors}}:',
 111+ 'pt-movepage-block-base-exists' => 'The target base page [[:$1]] exists.',
 112+ 'pt-movepage-block-base-invalid' => 'The target base page is not a valid title.',
 113+ 'pt-movepage-block-tp-exists' => 'The target translation page [[:$2]] exists.',
 114+ 'pt-movepage-block-tp-invalid' => 'The target translation page title for [[:$1]] would be invalid (too long?).',
 115+ 'pt-movepage-block-section-exists' => 'The target section page [[:$2]] exists.',
 116+ 'pt-movepage-block-section-invalid' => 'The target section page title for [[:$1]] would be invalid (too long?).',
 117+
 118+ 'pt-movepage-list-pages' => 'List of pages to move',
 119+ 'pt-movepage-list-translation' => 'Translation pages',
 120+ 'pt-movepage-list-section' => 'Section pages',
 121+ 'pt-movepage-list-other' => 'Other subpages',
 122+ 'pt-movepage-list-count' => 'In total $1 {{PLURAL:$1|page|pages}} to move.',
 123+
 124+
 125+ 'pt-movepage-legend' => 'Move translatable page',
 126+ 'pt-movepage-current' => 'Current name:',
 127+ 'pt-movepage-new' => 'New name:',
 128+ 'pt-movepage-reason' => 'Reason:',
 129+ 'pt-movepage-subpages' => 'Move all subpages',
 130+
 131+ 'pt-movepage-action-check' => 'Check if the move is possible',
 132+ 'pt-movepage-action-perform' => 'Do the move',
 133+ 'pt-movepage-action-other' => 'Change target',
 134+
 135+ 'pt-movepage-intro' => 'This special page allows you to move pages which are marked for translation.
 136+The move action will not be instant, because many pages will need to be moved.
 137+The job queue will be used for moving the pages.
 138+While the pages are being moved, it is not possible interact with the pages in question.
 139+Failures will be logged in the page translation log and they need to be repaired by hand.',
 140+
 141+ 'pt-movepage-logreason' => 'Part of translatable page $1.',
 142+ 'pt-movepage-started' => 'The base page is now moved.
 143+Please check the page translation log for errors and completion message.',
 144+
 145+ 'pt-locked-page' => 'This page is locked because translatable page is currently being moved.',
103146 );
104147
105148 /** Message documentation (Message documentation)
@@ -220,7 +263,6 @@
221264 'tpt-sections-deleted' => 'وحدات الترجمة المحذوفة',
222265 'tpt-sections-template' => 'قالب صفحة ترجمة',
223266 'tpt-badtitle' => 'اسم الصّفحة المعطى ($1) ليس عنوانا صحيحا',
224 - 'tpt-nosuchpage' => 'الصفحة $1 غير موجودة',
225267 'tpt-oldrevision' => '$2 ليست آخر نسخة للصّفحة [[$1]].
226268 فقط آخر النسخ يمكن أن تؤشّر للترجمة.',
227269 'tpt-notsuitable' => 'الصفحة $1 غير مناسبة للترجمة.
@@ -233,7 +275,6 @@
234276 'tpt-mark-summary' => 'علَّم هذه النسخة للترجمة',
235277 'tpt-edit-failed' => 'تعذّر تحديث الصفحة: $1',
236278 'tpt-already-marked' => 'آخر نسخة من هذه الصفحة مُعلّمة بالفعل للترجمة.',
237 - 'tpt-unmarked' => 'الصفحة $1 لم تعد مُعلّمة للترجمة',
238279 'tpt-list-nopages' => 'لا صفحات مُعلّمة للترجمة أو جاهزة للتعليم للترجمة.',
239280 'tpt-old-pages' => 'إحدى نسخ {{PLURAL:$1||هذه الصفحة|هاتان الصفحتان|هذه الصفحات}} عُلّمت للترجمة.',
240281 'tpt-new-pages' => '{{PLURAL:$1|هذه الصفحة تحتوي|هذه الصفحات تحتوي}} على نص بوسوم ترجمة، لكن لا نسخة من {{PLURAL:$1|هذه الصفحة|هذه الصفحات}} معلمة حاليا للترجمة.',

Status & tagging log