* @var Title
*/
protected $title;
- var $fileStatus;
+
+ /**
+ * @var Status
+ */
+ protected $fileStatus;
+
+ /**
+ * @var Status
+ */
+ protected $revisionStatus;
function __construct( $title ) {
if( is_null( $title ) ) {
* @return ResultWrapper
*/
function listRevisions() {
+ global $wgContentHandlerNoDB;
+
$dbr = wfGetDB( DB_SLAVE );
+
+ $fields = array(
+ 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text',
+ 'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1',
+ );
+
+ if ( !$wgContentHandlerNoDB ) {
+ $fields[] = 'ar_content_format';
+ $fields[] = 'ar_content_model';
+ }
+
$res = $dbr->select( 'archive',
- array(
- 'ar_minor_edit', 'ar_timestamp', 'ar_user', 'ar_user_text',
- 'ar_comment', 'ar_len', 'ar_deleted', 'ar_rev_id', 'ar_sha1'
- ),
+ $fields,
array( 'ar_namespace' => $this->title->getNamespace(),
'ar_title' => $this->title->getDBkey() ),
__METHOD__,
* @return Revision
*/
function getRevision( $timestamp ) {
+ global $wgContentHandlerNoDB;
+
$dbr = wfGetDB( DB_SLAVE );
+
+ $fields = array(
+ 'ar_rev_id',
+ 'ar_text',
+ 'ar_comment',
+ 'ar_user',
+ 'ar_user_text',
+ 'ar_timestamp',
+ 'ar_minor_edit',
+ 'ar_flags',
+ 'ar_text_id',
+ 'ar_deleted',
+ 'ar_len',
+ 'ar_sha1',
+ );
+
+ if ( !$wgContentHandlerNoDB ) {
+ $fields[] = 'ar_content_format';
+ $fields[] = 'ar_content_model';
+ }
+
$row = $dbr->selectRow( 'archive',
- array(
- 'ar_rev_id',
- 'ar_text',
- 'ar_comment',
- 'ar_user',
- 'ar_user_text',
- 'ar_timestamp',
- 'ar_minor_edit',
- 'ar_flags',
- 'ar_text_id',
- 'ar_deleted',
- 'ar_len',
- 'ar_sha1',
- ),
+ $fields,
array( 'ar_namespace' => $this->title->getNamespace(),
'ar_title' => $this->title->getDBkey(),
'ar_timestamp' => $dbr->timestamp( $timestamp ) ),
__METHOD__ );
if( $row ) {
- return Revision::newFromArchiveRow( $row, array( 'page' => $this->title->getArticleID() ) );
+ return Revision::newFromArchiveRow( $row, array( 'title' => $this->title ) );
} else {
return null;
}
if( $restoreFiles && $this->title->getNamespace() == NS_FILE ) {
$img = wfLocalFile( $this->title );
$this->fileStatus = $img->restore( $fileVersions, $unsuppress );
- if ( !$this->fileStatus->isOk() ) {
+ if ( !$this->fileStatus->isOK() ) {
return false;
}
$filesRestored = $this->fileStatus->successCount;
}
if( $restoreText ) {
- $textRestored = $this->undeleteRevisions( $timestamps, $unsuppress, $comment );
- if( $textRestored === false ) { // It must be one of UNDELETE_*
+ $this->revisionStatus = $this->undeleteRevisions( $timestamps, $unsuppress, $comment );
+ if( !$this->revisionStatus->isOK() ) {
return false;
}
+
+ $textRestored = $this->revisionStatus->getValue();
} else {
$textRestored = 0;
}
* @param $comment String
* @param $unsuppress Boolean: remove all ar_deleted/fa_deleted restrictions of seletected revs
*
- * @return Mixed: number of revisions restored or false on failure
+ * @return Status, containing the number of revisions restored on success
*/
private function undeleteRevisions( $timestamps, $unsuppress = false, $comment = '' ) {
+ global $wgContentHandlerNoDB;
+
if ( wfReadOnly() ) {
- return false;
+ throw new ReadOnlyError();
}
$restoreAll = empty( $timestamps );
$previousTimestamp = $dbw->selectField( 'revision', 'rev_timestamp',
array( 'rev_id' => $previousRevId ),
__METHOD__ );
+
if( $previousTimestamp === false ) {
wfDebug( __METHOD__.": existing page refers to a page_latest that does not exist\n" );
- return 0;
+
+ $status = Status::newGood( 0 );
+ $status->warning( 'undeleterevision-missing' );
+
+ return $status;
}
} else {
# Have to create a new article...
$oldones = "ar_timestamp IN ( {$oldts} )";
}
+ $fields = array(
+ 'ar_rev_id',
+ 'ar_text',
+ 'ar_comment',
+ 'ar_user',
+ 'ar_user_text',
+ 'ar_timestamp',
+ 'ar_minor_edit',
+ 'ar_flags',
+ 'ar_text_id',
+ 'ar_deleted',
+ 'ar_page_id',
+ 'ar_len',
+ 'ar_sha1');
+
+ if ( !$wgContentHandlerNoDB ) {
+ $fields[] = 'ar_content_format';
+ $fields[] = 'ar_content_model';
+ }
+
/**
* Select each archived revision...
*/
$result = $dbw->select( 'archive',
- /* fields */ array(
- 'ar_rev_id',
- 'ar_text',
- 'ar_comment',
- 'ar_user',
- 'ar_user_text',
- 'ar_timestamp',
- 'ar_minor_edit',
- 'ar_flags',
- 'ar_text_id',
- 'ar_deleted',
- 'ar_page_id',
- 'ar_len',
- 'ar_sha1' ),
+ $fields,
/* WHERE */ array(
'ar_namespace' => $this->title->getNamespace(),
'ar_title' => $this->title->getDBkey(),
$rev_count = $dbw->numRows( $result );
if( !$rev_count ) {
wfDebug( __METHOD__ . ": no revisions to restore\n" );
- return false; // ???
+
+ $status = Status::newGood( 0 );
+ $status->warning( "undelete-no-results" );
+ return $status;
}
$ret->seek( $rev_count - 1 ); // move to last
$row = $ret->fetchObject(); // get newest archived rev
$ret->seek( 0 ); // move back
+ // grab the content to check consistency with global state before restoring the page.
+ $revision = Revision::newFromArchiveRow( $row,
+ array(
+ 'title' => $article->getTitle(), // used to derive default content model
+ ) );
+
+ $m = $revision->getContentModel();
+
+ $user = User::newFromName( $revision->getRawUserText(), false );
+ $content = $revision->getContent( Revision::RAW );
+
+ //NOTE: article ID may not be known yet. prepareSave() should not modify the database.
+ $status = $content->prepareSave( $article, 0, -1, $user );
+
+ if ( !$status->isOK() ) {
+ return $status;
+ }
+
if( $makepage ) {
// Check the state of the newest to-be version...
if( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
- return false; // we can't leave the current revision like this!
+ return Status::newFatal( "undeleterevdel" );
}
// Safe to insert now...
$newid = $article->insertOn( $dbw );
if( $row->ar_timestamp > $previousTimestamp ) {
// Check the state of the newest to-be version...
if( !$unsuppress && ( $row->ar_deleted & Revision::DELETED_TEXT ) ) {
- return false; // we can't leave the current revision like this!
+ return Status::newFatal( "undeleterevdel" );
}
}
}
// unless we are specifically removing all restrictions...
$revision = Revision::newFromArchiveRow( $row,
array(
- 'page' => $pageId,
+ 'title' => $this->title,
'deleted' => $unsuppress ? 0 : $row->ar_deleted
) );
// Was anything restored at all?
if ( $restored == 0 ) {
- return 0;
+ return Status::newGood( 0 );
}
$created = (bool)$newid;
$update->doUpdate();
}
- return $restored;
+ return Status::newGood( $restored );
}
/**
* @return Status
*/
function getFileStatus() { return $this->fileStatus; }
+
+ /**
+ * @return Status
+ */
+ function getRevisionStatus() { return $this->revisionStatus; }
}
/**
private function showRevision( $timestamp ) {
if( !preg_match( '/[0-9]{14}/', $timestamp ) ) {
- return 0;
+ return;
}
$archive = new PageArchive( $this->mTargetObj );
- wfRunHooks( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) );
+ if ( !wfRunHooks( 'UndeleteForm::showRevision', array( &$archive, $this->mTargetObj ) ) ) {
+ return;
+ }
$rev = $archive->getRevision( $timestamp );
$out = $this->getOutput();
$t = $lang->userTime( $timestamp, $user );
$userLink = Linker::revUserTools( $rev );
- if( $this->mPreview ) {
+ $content = $rev->getContent( Revision::FOR_THIS_USER, $user );
+
+ $isText = ( $content instanceof TextContent );
+
+ if( $this->mPreview || $isText ) {
$openDiv = '<div id="mw-undelete-revision" class="mw-warning">';
} else {
$openDiv = '<div id="mw-undelete-revision">';
$out->addHTML( $this->msg( 'undelete-revision' )->rawParams( $link )->params(
$time )->rawParams( $userLink )->params( $d, $t )->parse() . '</div>' );
- wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) );
- if( $this->mPreview ) {
+ if ( !wfRunHooks( 'UndeleteShowRevision', array( $this->mTargetObj, $rev ) ) ) {
+ return;
+ }
+
+ if( $this->mPreview || !$isText ) {
+ // NOTE: non-text content has no source view, so always use rendered preview
+
// Hide [edit]s
$popts = $out->parserOptions();
$popts->setEditSection( false );
- $out->parserOptions( $popts );
- $out->addWikiTextTitleTidy( $rev->getText( Revision::FOR_THIS_USER, $user ), $this->mTargetObj, true );
+
+ $pout = $content->getParserOutput( $this->mTargetObj, $rev->getId(), $popts, true );
+ $out->addParserOutput( $pout );
}
+ if ( $isText ) {
+ // source view for textual content
+ $sourceView = Xml::element( 'textarea', array(
+ 'readonly' => 'readonly',
+ 'cols' => intval( $user->getOption( 'cols' ) ),
+ 'rows' => intval( $user->getOption( 'rows' ) ) ),
+ $content->getNativeData() . "\n" );
+
+ $previewButton = Xml::element( 'input', array(
+ 'type' => 'submit',
+ 'name' => 'preview',
+ 'value' => $this->msg( 'showpreview' )->text() ) );
+ } else {
+ $sourceView = '';
+ $previewButton = '';
+ }
+
+ $diffButton = Xml::element( 'input', array(
+ 'name' => 'diff',
+ 'type' => 'submit',
+ 'value' => $this->msg( 'showdiff' )->text() ) );
+
$out->addHTML(
- Xml::element( 'textarea', array(
- 'readonly' => 'readonly',
- 'cols' => intval( $user->getOption( 'cols' ) ),
- 'rows' => intval( $user->getOption( 'rows' ) ) ),
- $rev->getText( Revision::FOR_THIS_USER, $user ) . "\n" ) .
- Xml::openElement( 'div' ) .
+ $sourceView .
+ Xml::openElement( 'div', array(
+ 'style' => 'clear: both' ) ) .
Xml::openElement( 'form', array(
'method' => 'post',
'action' => $this->getTitle()->getLocalURL( array( 'action' => 'submit' ) ) ) ) .
'type' => 'hidden',
'name' => 'wpEditToken',
'value' => $user->getEditToken() ) ) .
- Xml::element( 'input', array(
- 'type' => 'submit',
- 'name' => 'preview',
- 'value' => $this->msg( 'showpreview' )->text() ) ) .
- Xml::element( 'input', array(
- 'name' => 'diff',
- 'type' => 'submit',
- 'value' => $this->msg( 'showdiff' )->text() ) ) .
+ $previewButton .
+ $diffButton .
Xml::closeElement( 'form' ) .
Xml::closeElement( 'div' ) );
}
* @return String: HTML
*/
function showDiff( $previousRev, $currentRev ) {
- $diffEngine = new DifferenceEngine( $this->getContext() );
+ $diffContext = clone $this->getContext();
+ $diffContext->setTitle( $currentRev->getTitle() );
+ $diffContext->setWikiPage( WikiPage::factory( $currentRev->getTitle() ) );
+
+ $diffEngine = $currentRev->getContentHandler()->createDifferenceEngine( $diffContext );
$diffEngine->showDiffStyle();
$this->getOutput()->addHTML(
"<div>" .
$this->diffHeader( $currentRev, 'n' ) .
"</td>\n" .
"</tr>" .
- $diffEngine->generateDiffBody(
- $previousRev->getText( Revision::FOR_THIS_USER, $this->getUser() ),
- $currentRev->getText( Revision::FOR_THIS_USER, $this->getUser() ) ) .
+ $diffEngine->generateContentDiffBody(
+ $previousRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ),
+ $currentRev->getContent( Revision::FOR_THIS_USER, $this->getUser() ) ) .
"</table>" .
"</div>\n"
);
private function formatRevisionRow( $row, $earliestLiveTime, $remaining ) {
$rev = Revision::newFromArchiveRow( $row,
- array( 'page' => $this->mTargetObj->getArticleID() ) );
+ array(
+ 'title' => $this->mTargetObj
+ ) );
+
$revTextSize = '';
$ts = wfTimestamp( TS_MW, $row->ar_timestamp );
// Build checkboxen...
$out->addHTML( $this->msg( 'undeletedpage' )->rawParams( $link )->parse() );
} else {
$out->setPageTitle( $this->msg( 'undelete-error' ) );
- $out->addWikiMsg( 'cannotundelete' );
- $out->addWikiMsg( 'undeleterevdel' );
}
- // Show file deletion warnings and errors
+ // Show revision undeletion warnings and errors
+ $status = $archive->getRevisionStatus();
+ if( $status && !$status->isGood() ) {
+ $out->addWikiText( '<div class="error">' . $status->getWikiText( 'cannotundelete', 'cannotundelete' ) . '</div>' );
+ }
+
+ // Show file undeletion warnings and errors
$status = $archive->getFileStatus();
if( $status && !$status->isGood() ) {
$out->addWikiText( '<div class="error">' . $status->getWikiText( 'undelete-error-short', 'undelete-error-long' ) . '</div>' );