r67094 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r67093‎ | r67094 | r67095 >
Date:18:00, 30 May 2010
Author:churchofemacs
Status:reverted (Comments)
Tags:
Comment:
New feature RevisionMove (bug 21312). Introducing SpecialRevisionMove.php and revisionmove permission. Experimental, use at own risk (no group has this permission by default, so it should not break anything unless you are foolish enough to experiment with it :))
Modified paths:
  • /trunk/phase3/includes/Article.php (modified) (history)
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/DefaultSettings.php (modified) (history)
  • /trunk/phase3/includes/HistoryPage.php (modified) (history)
  • /trunk/phase3/includes/LogPage.php (modified) (history)
  • /trunk/phase3/includes/SpecialPage.php (modified) (history)
  • /trunk/phase3/includes/Wiki.php (modified) (history)
  • /trunk/phase3/includes/specials/SpecialRevisionMove.php (added) (history)
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/language/messages.inc
@@ -748,6 +748,24 @@
749749 'suppressionlog',
750750 'suppressionlogtext',
751751 ),
 752+ 'revisionmove' => array(
 753+ 'moverevlogentry',
 754+ 'revisionmove',
 755+ 'revmove-explain',
 756+ 'revmove-legend',
 757+ 'revmove-submit',
 758+ 'revisionmoveselectedversions',
 759+ 'revmove-reasonfield',
 760+ 'revmove-titlefield',
 761+ 'revmove-badparam-title' ,
 762+ 'revmove-badparam',
 763+ 'revmove-norevisions-title',
 764+ 'revmove-norevisions',
 765+ 'revmove-nullmove-title',
 766+ 'revmove-nullmove',
 767+ 'revmove-success-existing',
 768+ 'revmove-success-created',
 769+ ),
752770 'mergehistory' => array(
753771 'mergehistory',
754772 'mergehistory-header',
Index: trunk/phase3/includes/Article.php
@@ -1790,10 +1790,12 @@
17911791 * on.
17921792 * @param $lastRevIsRedirect Boolean: if given, will optimize adding and
17931793 * removing rows in redirect table.
 1794+ * @param $setNewFlag Boolean: Set to true if a page flag should be set
 1795+ * Needed when $lastRevision has to be set to sth. !=0
17941796 * @return bool true on success, false on failure
17951797 * @private
17961798 */
1797 - public function updateRevisionOn( &$dbw, $revision, $lastRevision = null, $lastRevIsRedirect = null ) {
 1799+ public function updateRevisionOn( &$dbw, $revision, $lastRevision = null, $lastRevIsRedirect = null, $setNewFlag = false ) {
17981800 wfProfileIn( __METHOD__ );
17991801
18001802 $text = $revision->getText();
@@ -1806,11 +1808,15 @@
18071809 $conditions['page_latest'] = $lastRevision;
18081810 }
18091811
 1812+ if ( !$setNewFlag ) {
 1813+ $setNewFlag = ( $lastRevision === 0 );
 1814+ }
 1815+
18101816 $dbw->update( 'page',
18111817 array( /* SET */
18121818 'page_latest' => $revision->getId(),
18131819 'page_touched' => $dbw->timestamp(),
1814 - 'page_is_new' => ( $lastRevision === 0 ) ? 1 : 0,
 1820+ 'page_is_new' => $setNewFlag,
18151821 'page_is_redirect' => $rt !== null ? 1 : 0,
18161822 'page_len' => strlen( $text ),
18171823 ),
Index: trunk/phase3/includes/HistoryPage.php
@@ -395,6 +395,20 @@
396396 wfMsg( 'showhideselectedversions' )
397397 ) . "\n";
398398 }
 399+ if( $wgUser->isAllowed( 'revisionmove' ) ) {
 400+ $float = $wgContLang->alignEnd();
 401+ # Note bug #20966, <button> is non-standard in IE<8
 402+ $this->buttons .= Xml::element( 'button',
 403+ array(
 404+ 'type' => 'submit',
 405+ 'name' => 'revisionmove',
 406+ 'value' => '1',
 407+ 'style' => "float: $float;",
 408+ 'class' => 'mw-history-revisionmove-button',
 409+ ),
 410+ wfMsg( 'revisionmoveselectedversions' )
 411+ ) . "\n";
 412+ }
399413 $this->buttons .= $this->submitButton( wfMsg( 'compareselectedversions'),
400414 array(
401415 'class' => 'historysubmit',
@@ -486,10 +500,11 @@
487501 $classes = array();
488502
489503 $del = '';
490 - // User can delete revisions...
491 - if( $wgUser->isAllowed( 'deleterevision' ) ) {
 504+ // Show checkboxes for each revision
 505+ if( $wgUser->isAllowed( 'deleterevision' ) || $wgUser->isAllowed( 'revisionmove' ) ) {
492506 // If revision was hidden from sysops, disable the checkbox
493 - if( !$rev->userCan( Revision::DELETED_RESTRICTED ) ) {
 507+ // However, if the user has revisionmove rights, we cannot disable the checkbox
 508+ if( !$rev->userCan( Revision::DELETED_RESTRICTED ) && !$wgUser->isAllowed( 'revisionmove' ) ) {
494509 $del = Xml::check( 'deleterevisions', false, array( 'disabled' => 'disabled' ) );
495510 // Otherwise, enable the checkbox...
496511 } else {
Index: trunk/phase3/includes/AutoLoader.php
@@ -571,6 +571,7 @@
572572 'RevDel_ArchivedFileItem' => 'includes/RevisionDelete.php',
573573 'RevDel_LogList' => 'includes/RevisionDelete.php',
574574 'RevDel_LogItem' => 'includes/RevisionDelete.php',
 575+ 'SpecialRevisionMove' => 'includes/specials/SpecialRevisionMove.php',
575576 'ShortPagesPage' => 'includes/specials/SpecialShortpages.php',
576577 'SpecialActiveUsers' => 'includes/specials/SpecialActiveusers.php',
577578 'SpecialAllpages' => 'includes/specials/SpecialAllpages.php',
Index: trunk/phase3/includes/Wiki.php
@@ -488,6 +488,8 @@
489489 if ( $action === 'historysubmit' ) {
490490 if ( $request->getBool( 'revisiondelete' ) ) {
491491 $action = 'revisiondelete';
 492+ } elseif ( $request->getBool( 'revisionmove' ) ) {
 493+ $action = 'revisionmove';
492494 } else {
493495 $action = 'view';
494496 }
@@ -576,6 +578,11 @@
577579 $special = SpecialPage::getPage( 'Revisiondelete' );
578580 $special->execute( '' );
579581 break;
 582+ case 'revisionmove':
 583+ # For revision move submission from history page
 584+ $special = SpecialPage::getPage( 'RevisionMove' );
 585+ $special->execute( '' );
 586+ break;
580587 default:
581588 if( wfRunHooks( 'UnknownAction', array( $action, $article ) ) ) {
582589 $output->showErrorPage( 'nosuchaction', 'nosuchactiontext' );
Index: trunk/phase3/includes/DefaultSettings.php
@@ -3326,6 +3326,7 @@
33273327 'upload/revert' => 'uploadedimage',
33283328 'move/move' => '1movedto2',
33293329 'move/move_redir' => '1movedto2_redir',
 3330+ 'move/move_rev' => 'moverevlogentry',
33303331 'import/upload' => 'import-logentry-upload',
33313332 'import/interwiki' => 'import-logentry-interwiki',
33323333 'merge/merge' => 'pagemerge-logentry',
Index: trunk/phase3/includes/specials/SpecialRevisionMove.php
@@ -0,0 +1,390 @@
 2+<?php
 3+/**
 4+ * Special page allowing users with the appropriate permissions to
 5+ * move revisions of a page to a new target (either an existing page or not)
 6+ *
 7+ * The user selects revisions in the page history (HistoryPage.php),
 8+ * clicks on the submit button and gets this special page.
 9+ * A form is shown (showForm()) where the user has to enter a target page
 10+ * name and confirm the action with a post request & edit token.
 11+ * Then submit() is called, which does some checks and calls moveRevisions().
 12+ * If the target doesn't exist, a new page gets created. rev_page of the
 13+ * selected revisions is updated, after that it is determined whether page_latest
 14+ * of the target page and the source page require an update.
 15+ *
 16+ * **** NOTE: This feature is EXPERIMENTAL. ****
 17+ * **** Do not use on any productive system. ****
 18+ *
 19+ * @file
 20+ * @ingroup SpecialPage
 21+ */
 22+
 23+/* TODO In case page_deleted gets introduced some day, use it.
 24+ * Currently it is possible with RevisionMove to make the latest revision
 25+ * of a page a RevisionDeleted one. When that happens, the user is presented
 26+ * an empty page with no error message whatsoever (in case he is not permitted
 27+ * to view deleted edits).
 28+*/
 29+
 30+class SpecialRevisionMove extends UnlistedSpecialPage {
 31+
 32+ # common objects
 33+ var $mOldTitle; # Title object.
 34+ var $mNewTitle; # Title object. Desired new title
 35+ var $request; # WebRequest object, $wgRequest by default
 36+ var $skin; # Skin object
 37+ var $user; # User object
 38+
 39+ # variables
 40+ var $mIds; # Array of Ids to look at
 41+ var $mRevlist; # RevDel_RevisionList object - borrowed from RevisionDelete
 42+ var $mReason; # User-supplied reason for performing the move operation
 43+ var $mSubmit; # Boolean: Is this a submitted request?
 44+ var $mIsAllowedRevisionMove = false;
 45+
 46+ public function __construct( $name = 'RevisionMove' ) {
 47+ parent::__construct( $name );
 48+ }
 49+
 50+ /**
 51+ * @param $par subpage part, standard special page parameter, is ignored here
 52+ * @param $request optional WebRequest object. If it isn't set, $this->request
 53+ * will be set to $wgRequest
 54+ *
 55+ * Mostly initializes variables and calls either showForm() or submit()
 56+ */
 57+ public function execute( $par = '', $request = null ) {
 58+ global $wgUser, $wgOut, $wgSkin;
 59+
 60+ $this->setHeaders();
 61+ $this->outputHeader();
 62+
 63+ $this->mIsAllowedRevisionMove = $wgUser->isAllowed( 'revisionmove' );
 64+ $this->user = $wgUser;
 65+ $this->skin = $wgUser->getSkin();
 66+ if ( !$request instanceof WebRequest ) {
 67+ $this->request = $GLOBALS['wgRequest'];
 68+ } else {
 69+ $this->request = $request;
 70+ }
 71+
 72+ # Get correct title
 73+ if ( $this->request->getVal( 'action' ) == 'historysubmit' ) {
 74+ $this->mOldTitle = Title::newFromText( $this->request->getVal( 'title' ) );
 75+ } else {
 76+ $this->mOldTitle = Title::newFromText( $this->request->getVal( 'oldTitle' ) );
 77+ }
 78+
 79+ if ( !$this->mOldTitle instanceof Title ) {
 80+ $wgOut->showErrorPage( 'revmove-badparam-title', 'revmove-badparam' );
 81+ return;
 82+ }
 83+
 84+ $wgOut->setPagetitle( wfMsg( 'revisionmove', $this->mOldTitle->getPrefixedText() ) );
 85+ $oldTitleLink = $this->skin->link( $this->mOldTitle );
 86+ $wgOut->setSubtitle( wfMsg( 'revisionmove-backlink', $oldTitleLink ) );
 87+
 88+ $this->mReason = $this->request->getText( 'wpReason' );
 89+
 90+ # TODO maybe not needed here? Copied from SpecialRevisiondelete.php.
 91+ # Keep for now, allow different inputs
 92+ # Handle our many different possible input types for ids
 93+ $ids = $this->request->getVal( 'ids' );
 94+ if ( !is_null( $ids ) ) {
 95+ # Allow CSV, for backwards compatibility, or a single ID for show/hide links
 96+ $this->mIds = explode( ',', $ids );
 97+ } else {
 98+ # Array input
 99+ $this->mIds = array_keys( $this->request->getArray( 'ids', array() ) );
 100+ }
 101+ $this->mIds = array_unique( array_filter( $this->mIds ) );
 102+
 103+ if ( is_null ( $this->mIds ) ) {
 104+ $wgOut->showErrorPage( 'revmove-badparam-title', 'revmove-badparam' );
 105+ return;
 106+ }
 107+ $this->mRevlist = new RevDel_RevisionList( $this, $this->mOldTitle, $this->mIds );
 108+
 109+ # Decide what to do: Show the form, or submit the changes
 110+ if ( $this->request->wasPosted() ) {
 111+ $this->submit();
 112+ } else {
 113+ $this->showForm();
 114+ }
 115+
 116+ }
 117+
 118+ /**
 119+ * Show a list of items that we will operate on and a field for the target name
 120+ */
 121+ public function showForm() {
 122+ global $wgOut, $wgUser;
 123+
 124+ if ( !$this->mIsAllowedRevisionMove ) {
 125+ $permErrors = $this->mOldTitle->getUserPermissionsErrors( 'revisionmove', $this->user );
 126+ $wgOut->showPermissionsErrorPage( $permErrors, 'revisionmove' );
 127+ return false;
 128+ }
 129+
 130+ $wgOut->addWikiMsg( 'revmove-explain', $this->mOldTitle->getPrefixedText() );
 131+ $listNotEmpty = $this->listItems();
 132+ if ( !$listNotEmpty ) {
 133+ return; # we're done, we already displayed an error earlier
 134+ }
 135+
 136+ $out = Xml::openElement( 'form', array( 'method' => 'post',
 137+ 'action' => $this->getTitle()->getLocalUrl( array( 'action' => 'submit' ) ),
 138+ 'id' => 'mw-revmove-form' ) ) .
 139+ Xml::fieldset( wfMsg( 'revmove-legend' ) ) .
 140+ Xml::hidden( 'wpEditToken', $wgUser->editToken() ) .
 141+ Xml::hidden( 'oldTitle', $this->mOldTitle->getPrefixedText() ) .
 142+ '<div>' . Xml::inputLabel( wfMsg( 'revmove-reasonfield' ), 'wpReason', 'revmove-reasonfield', 60 ) . '</div>' .
 143+ Xml::inputLabel( wfMsg( 'revmove-titlefield' ), 'newTitle', 'revmove-titlefield', 20, $this->mOldTitle->getPrefixedText() ) .
 144+ Xml::hidden( 'ids', implode( ',', $this->mIds ) ) .
 145+ Xml::submitButton( wfMsg( 'revmove-submit' ),
 146+ array( 'name' => 'wpSubmit' ) ) .
 147+ Xml::closeElement( 'fieldset' ) . "\n" .
 148+ Xml::closeElement( 'form' ) . "\n";
 149+ $wgOut->addHTML( $out );
 150+ }
 151+
 152+ /**
 153+ * Show a list of selected revisions and check the input
 154+ */
 155+ protected function listItems() {
 156+ global $wgOut;
 157+
 158+ $wgOut->addHTML( "<ul>" );
 159+
 160+ $numRevisions = 0;
 161+
 162+ # No revisions specified at all
 163+ if ( $this->mIds == array() ) {
 164+ $wgOut->showErrorPage( 'revmove-norevisions-title', 'revmove-norevisions' );
 165+ return false;
 166+ }
 167+
 168+ for ( $this->mRevlist->reset(); $this->mRevlist->current(); $this->mRevlist->next() ) {
 169+ $item = $this->mRevlist->current();
 170+ $numRevisions++;
 171+ $wgOut->addHTML( $item->getHTML() );
 172+ }
 173+
 174+ # No valid revisions specified (e.g. only revs belonging to another page)
 175+ if( $numRevisions == 0 ) {
 176+ $wgOut->showErrorPage( 'revmove-norevisions-title', 'revmove-norevisions' );
 177+ return false;
 178+ }
 179+
 180+ $wgOut->addHTML( "</ul>" );
 181+ return true;
 182+ }
 183+
 184+ /**
 185+ * Submit the posted changes (in $this->request).
 186+ *
 187+ * This function does some checks and then calls moveRevisions(), which does the real work
 188+ */
 189+ public function submit() {
 190+ global $wgUser, $wgOut;
 191+
 192+ # Confirm permissions
 193+ if ( !$this->mIsAllowedRevisionMove ) {
 194+ $permErrors = $this->mOldTitle->getUserPermissionsErrors( 'revisionmove', $this->user );
 195+ $wgOut->showPermissionsErrorPage( $permErrors, 'revisionmove' );
 196+ return false;
 197+ }
 198+ # Confirm Token
 199+ if( !$wgUser->matchEditToken( $this->request->getVal( 'wpEditToken' ) ) ) {
 200+ $wgOut->showErrorPage( 'sessionfailure-title', 'sessionfailure' );
 201+ return false;
 202+ }
 203+
 204+ $this->mNewTitle = Title::newFromText( $this->request->getVal( 'newTitle' ) );
 205+ if ( !$this->mNewTitle instanceof Title ) {
 206+ $wgOut->showErrorPage( 'badtitle', 'badtitletext' );
 207+ return false;
 208+ }
 209+
 210+ if ( $this->mNewTitle->getPrefixedText() == $this->mOldTitle->getPrefixedText() ) {
 211+ $pagename = array( $this->mOldTitle->getPrefixedText() );
 212+ $wgOut->showErrorPage( 'revmove-nullmove-title', 'revmove-nullmove', $pagename );
 213+ return;
 214+ }
 215+
 216+ $this->moveRevisions();
 217+ }
 218+
 219+ /**
 220+ * This function actually move the revision. NEVER call this function, call submit()
 221+ */
 222+ protected function moveRevisions() {
 223+ global $wgOut;
 224+
 225+ $oldArticle = new Article( $this->mOldTitle );
 226+ $newArticle = new Article( $this->mNewTitle );
 227+
 228+ $idstring = implode( ", ", $this->mIds );
 229+
 230+ # Get DB connection and begin transaction
 231+ $dbw = wfGetDB( DB_MASTER );
 232+ $dbw->begin();
 233+
 234+ # Check if the target exists. If not, try creating it
 235+ if ( !$this->mNewTitle->exists() ) {
 236+ $newArticle->insertOn( $dbw );
 237+ $this->createArticle = true;
 238+ } else {
 239+ $this->createArticle = false;
 240+ }
 241+
 242+ # This is where the magic happens:
 243+ # Update revision table
 244+ $dbw->update( 'revision',
 245+ array( 'rev_page' => $this->mNewTitle->getArticleID() ),
 246+ array(
 247+ 'rev_id IN (' . $idstring . ')',
 248+ 'rev_page' => $this->mOldTitle->getArticleID(),
 249+ ),
 250+ __METHOD__
 251+ );
 252+ $modifiedRevsNum = $dbw->affectedRows();
 253+
 254+ # Check if we need to update page_latest
 255+ # Get the latest version of the revisions we are moving
 256+ $timestampNewPage = $this->queryLatestTimestamp(
 257+ $dbw,
 258+ $this->mNewTitle->getArticleID(),
 259+ array( 'rev_id IN (' . $idstring . ')' )
 260+ );
 261+
 262+ # Compare the new page's page_latest against db query.
 263+ # If we create a new page, we have to update anyway
 264+
 265+ $currentNewPageRev = Revision::newFromId( $this->mNewTitle->getLatestRevID() );
 266+ if ( $this->createArticle || $timestampNewPage > $currentNewPageRev->getTimestamp() ) {
 267+ # we have to set page_latest to $timestampNewPage's revid
 268+ $this->updatePageLatest(
 269+ $dbw,
 270+ $this->mNewTitle,
 271+ $newArticle,
 272+ $timestampNewPage,
 273+ array( 'rev_id IN (' . $idstring . ')' )
 274+ );
 275+ }
 276+
 277+ # Update the old page's page_latest field
 278+ $timestampOldPage = $this->queryLatestTimestamp(
 279+ $dbw,
 280+ $this->mOldTitle->getArticleID()
 281+ );
 282+
 283+ # If the timestamp is null that means the page doesn't have
 284+ # any revisions associated and should be deleted. In other words,
 285+ # someone misused revisionmove for the normal move function.
 286+ if ( is_null( $timestampOldPage ) ) {
 287+ $dbw->delete(
 288+ 'page',
 289+ array( 'page_id = ' . $this->mOldTitle->getArticleID() ),
 290+ __METHOD__
 291+ );
 292+ $deletedOldPage = true;
 293+ } else {
 294+ # page_latest has to be updated
 295+ $currentOldPageRev = Revision::newFromId( $this->mOldTitle->getLatestRevID() );
 296+ if ( $timestampOldPage < $currentOldPageRev->getTimestamp() ) {
 297+ $this->updatePageLatest(
 298+ $dbw,
 299+ $this->mOldTitle,
 300+ $oldArticle,
 301+ $timestampOldPage
 302+ );
 303+ }
 304+ # Purge the old one only if it hasn't been deleted
 305+ $oldArticle->doPurge();
 306+ }
 307+
 308+ # All done, commit
 309+ $dbw->commit();
 310+
 311+ $this->logMove( $modifiedRevsNum );
 312+
 313+ # Purge new article
 314+ $newArticle->doPurge();
 315+
 316+ # If noting went wrong (i.e. returned), we are successful
 317+ $this->showSuccess( $modifiedRevsNum );
 318+ }
 319+
 320+ /**
 321+ * Query for the latest timestamp in order to update page_latest and
 322+ * page_timestamp.
 323+ * @param &$dbw Database object (Master)
 324+ * @param $articleId Integer page_id
 325+ * @param $conds array database conditions
 326+ *
 327+ * @return String timestamp
 328+ */
 329+ protected function queryLatestTimestamp( &$dbw, $articleId, $conds = array() ) {
 330+ $timestampNewRow = $dbw->selectRow(
 331+ 'revision',
 332+ 'max(rev_timestamp) as maxtime',
 333+ array_merge( array( 'rev_page' => $articleId ), $conds ),
 334+ __METHOD__
 335+ );
 336+ return $timestampNewRow->maxtime;
 337+ }
 338+
 339+ /**
 340+ * Updates page_latest and similar database fields (see Article::updateRevisionOn).
 341+ * Called two times, for the new and the old page
 342+ *
 343+ * @param &$dbw Database object (Master)
 344+ * @param $articleTitle Title object of the page
 345+ * @param $articleObj Article object of the page
 346+ * @param $timestamp to search for (use queryLatestTimestamp to get the latest)
 347+ * @param $conds array database conditions
 348+ *
 349+ * @return boolean indicating success
 350+ */
 351+ protected function updatePageLatest( &$dbw, $articleTitle, &$articleObj, $timestamp, $conds = array() ) {
 352+ # Query to find out the rev_id
 353+ $revisionRow = $dbw->selectRow(
 354+ 'revision',
 355+ 'rev_id',
 356+ array_merge( array(
 357+ 'rev_timestamp' => $timestamp,
 358+ 'rev_page' => $articleTitle->getArticleID(),
 359+ ), $conds ),
 360+ __METHOD__
 361+ );
 362+ # Update page_latest
 363+ $latestRev = Revision::newFromId( $revisionRow->rev_id );
 364+ return $articleObj->updateRevisionOn( $dbw, $latestRev, $articleTitle->getLatestRevID(), null, /* set new page flag */ true );
 365+ }
 366+
 367+ /**
 368+ * Add a log entry for the revision move
 369+ */
 370+ protected function logMove( $modifiedRevsNum ) {
 371+ $paramArray = array(
 372+ $this->mNewTitle->getPrefixedText(),
 373+ $modifiedRevsNum
 374+ );
 375+ $log = new LogPage( 'move' );
 376+ $log->addEntry( 'move_rev', $this->mOldTitle, $this->mReason, $paramArray, $this->user );
 377+
 378+ }
 379+
 380+ protected function showSuccess( $modifiedRevsNum ) {
 381+ global $wgOut;
 382+
 383+ if ( $this->createArticle ) {
 384+ $wgOut->addWikiMsg( 'revmove-success-created', $modifiedRevsNum,
 385+ $this->mOldTitle->getPrefixedText(), $this->mNewTitle->getPrefixedText() );
 386+ } else {
 387+ $wgOut->addWikiMsg( 'revmove-success-existing', $modifiedRevsNum,
 388+ $this->mOldTitle->getPrefixedText(), $this->mNewTitle->getPrefixedText() );
 389+ }
 390+ }
 391+}
Property changes on: trunk/phase3/includes/specials/SpecialRevisionMove.php
___________________________________________________________________
Added: svn:eol-style
1392 + native
Index: trunk/phase3/includes/SpecialPage.php
@@ -189,6 +189,7 @@
190190 'Mypage' => array( 'SpecialMypage' ),
191191 'Mytalk' => array( 'SpecialMytalk' ),
192192 'Revisiondelete' => 'SpecialRevisionDelete',
 193+ 'RevisionMove' => 'SpecialRevisionMove',
193194 'Specialpages' => array( 'UnlistedSpecialPage', 'Specialpages' ),
194195 'Userlogout' => array( 'UnlistedSpecialPage', 'Userlogout' ),
195196 );
Index: trunk/phase3/includes/LogPage.php
@@ -253,7 +253,7 @@
254254 }
255255
256256 // Page moves
257 - } else if ( $type == 'move' && count( $params ) == 3 ) {
 257+ } else if ( $type == 'move' && count( $params ) == 3 && $action != 'move_rev' ) {
258258 if( $params[2] ) {
259259 if ( $skin ) {
260260 $details .= ' [' . wfMsg( 'move-redirect-suppressed' ) . ']';
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -1553,6 +1553,27 @@
15541554 'suppressionlogtext' => 'Below is a list of deletions and blocks involving content hidden from administrators.
15551555 See the [[Special:IPBlockList|IP block list]] for the list of currently operational bans and blocks.',
15561556
 1557+# SpecialRevisionMove // FIXME add to messages.inc
 1558+'moverevlogentry' => 'moved $3 revisions from $1 to $2',
 1559+'revisionmove' => 'Move revisions from "$1"',
 1560+'revisionmove-backlink' => '← $1',
 1561+'revmove-explain' => 'The following revisions will be moved from $1 to the specified target page. If the target doesn\'t exist, it is created. Otherwise, these revisions will be merged into the page history.',
 1562+'revmove-legend' => 'Set target page and summary',
 1563+'revmove-submit' => 'Move revisions to selected page',
 1564+'revisionmoveselectedversions' => 'Move selected revisions',
 1565+'revmove-reasonfield' => 'Summary and reason:',
 1566+'revmove-titlefield' => 'Target page:',
 1567+'revmove-badparam-title' => 'Bad parameters',
 1568+'revmove-badparam' => '<span class="error">Your request contains illegal or insufficient parameters. Please hit "back" and try again.</span>',
 1569+'revmove-norevisions-title' => 'Invalid target revision',
 1570+'revmove-norevisions' => 'You have either not specified a target revision(s) to perform this function or the specified revision does not exist.',
 1571+'revmove-nullmove-title' => 'Bad title',
 1572+'revmove-nullmove' => '<span class="error">Source and target page are identical. Please hit "back" and enter a page name different to "$1".</span>',
 1573+'revmove-permissionerror-title' => 'Blub',
 1574+'revmove-permissionerror' => 'Bla',
 1575+'revmove-success-existing' => '{{PLURAL:$1|One revision from [[$2]] has|$1 revisions from [[$2]] have}} been moved to the existing page [[$3]].',
 1576+'revmove-success-created' => '{{PLURAL:$1|One revision from [[$2]] has|$1 revisions from [[$2]] have}} been moved to the newly created page [[$3]].',
 1577+
15571578 # History merging
15581579 'mergehistory' => 'Merge page histories',
15591580 'mergehistory-header' => 'This page lets you merge revisions of the history of one source page into a newer page.
@@ -1955,6 +1976,7 @@
19561977 'action-userrights' => 'edit all user rights',
19571978 'action-userrights-interwiki' => 'edit user rights of users on other wikis',
19581979 'action-siteadmin' => 'lock or unlock the database',
 1980+'action-revisionmove' => 'move revisions',
19591981
19601982 # Recent changes
19611983 'nchanges' => '$1 {{PLURAL:$1|change|changes}}',
@@ -2739,7 +2761,10 @@
27402762 'revertpage-nouser' => 'Reverted edits by (username removed) to last revision by [[User:$1|$1]]',
27412763 'rollback-success' => 'Reverted edits by $1;
27422764 changed back to last revision by $2.',
2743 -'sessionfailure' => 'There seems to be a problem with your login session;
 2765+
 2766+# Edit tokens
 2767+'sessionfailure-title' => 'Session failure',
 2768+'sessionfailure' => 'There seems to be a problem with your login session;
27442769 this action has been canceled as a precaution against session hijacking.
27452770 Please hit "back" and reload the page you came from, then try again.',
27462771

Follow-up revisions

RevisionCommit summaryAuthorDate
r67099fixing messages of r67094. thanks to siebrand for these suggestionschurchofemacs18:21, 30 May 2010
r67111Follow-up r67094: Tweak message filesraymond19:51, 30 May 2010
r67112Follow-up r67094: Tweak message filesraymond20:06, 30 May 2010
r67115Follow-up r67094: Tweak message filesraymond20:20, 30 May 2010
r67398follow-up on r67094: fixing presumed cause for php strict standards message a...churchofemacs11:59, 5 June 2010
r81425Followup r67094...reedy22:23, 2 February 2011
r81427Followup r67094, factor out code duplication in HistoryPage::getStartBody()reedy22:31, 2 February 2011
r814481.17: Revert r67094 (RevisionMove) and followups including r67099, r67111, r6...catrope13:22, 3 February 2011
r86155Merge r81448 from REL1_17: reverting RevisionMove feature back out until some...demon23:28, 15 April 2011

Comments

#Comment by Nikerabbit (talk | contribs)   16:06, 4 June 2010

[04-Jun-2010 16:01:12] PHP Strict Standards: Declaration of SpecialRevisionMove::execute() should be compatible with that of SpecialPage::execute() in /www/w/includes/specials/SpecialRevisionMove.php on line 390

#Comment by Church of emacs (talk | contribs)   12:01, 5 June 2010

I wasn't able to reproduce this bug (strict standards messages are working, but they didn't show up on Special:RevisionMove). Still, I tried to fix the error in r67398 – please tell me if this is working.

#Comment by Siebrand (talk | contribs)   20:28, 24 June 2010

Could you please provide some explanation on a message on translatewiki.net? Thanks.

#Comment by Aaron Schulz (talk | contribs)   01:51, 6 July 2010

This should probably trigger the ArticleMergeComplete hook.

#Comment by Reedy (talk | contribs)   21:13, 12 January 2011

Is anyone going to deal with the ArticleMergeComplete hook?

#Comment by Tim Starling (talk | contribs)   05:07, 2 February 2011

There are lots of things here that need to be cleaned up, for example:

  • Overly long lines
  • Code duplication in HistoryPage::getStartBody()
  • Unnecessary code copied from SpecialRevisiondelete.php (see TODO)
  • Unnecessary patch to Article::updateRevisionOn(), with inelegant boolean parameter, could have just used a separate query.
  • Sets page_is_new incorrectly anyway.
  • Use of literal SQL "IN()" and even "page_id = ", instead of using Database's SQL construction facilities.
  • Use of cached functions like Title::exists() and Title::getLatestRevID() in code paths where consistency is essential. No apparent awareness of database locking.
  • Fails to check Database::selectRow() for false result.
  • Unnecessarily passes $dbw around as a formal parameter. Looks like something Brion would do ;) Also passes objects by reference.
  • Fails to maintain referential integrity when deleting pages, compare with Article::doDeleteArticle()

It looks harmless as long as nobody enables it, so we could leave it until after the deployment. But it needs to be either reverted or fixed before release.

#Comment by Church of emacs (talk | contribs)   09:01, 2 February 2011

Thanks Tim for that elaborate feedback. Unfortunately I don't have much spare time right now (exams *sigh*), so I doubt I can fix it before the release. Feel free to revert it.

#Comment by Reedy (talk | contribs)   09:47, 2 February 2011

I will probably have chance to try and sort *most* of this afternoon.

Which certainly needs doing, and could still mean we revert it for 1.17

#Comment by Catrope (talk | contribs)   13:26, 3 February 2011

Reverted in 1.17 in r81448

#Comment by Bryan (talk | contribs)   12:05, 26 March 2011

I think we should revert this also in trunk unless somebody is willing to take a look at it.

Status & tagging log