global $wgParser;
return $wgParser->getSection( $text, $section );
}
+
+ /**
+ * Get the text that needs to be saved in order to undo all revisions
+ * between $undo and $undoafter. Revisions must belong to the same page,
+ * must exist and must not be deleted
+ * @param $undo Revision
+ * @param $undoafter Revision Must be an earlier revision than $undo
+ * @return mixed string on success, false on failure
+ */
+ public function getUndoText( Revision $undo, Revision $undoafter = null ) {
+ $undo_text = $undo->getText();
+ $undoafter_text = $undoafter->getText();
+ $cur_text = $this->getContent();
+ if ( $cur_text == $undo_text ) {
+ # No use doing a merge if it's just a straight revert.
+ return $undoafter_text;
+ }
+ $undone_text = '';
+ if ( !wfMerge( $undo_text, $undoafter_text, $cur_text, $undone_text ) )
+ return false;
+ return $undone_text;
+ }
/**
* @return int The oldid of the article that is to be shown, 0 for the
$undorev->getPage() == $this->mArticle->getID() &&
!$undorev->isDeleted( Revision::DELETED_TEXT ) &&
!$oldrev->isDeleted( Revision::DELETED_TEXT ) ) {
- $undorev_text = $undorev->getText();
- $oldrev_text = $oldrev->getText();
- $currev_text = $text;
-
- if ( $currev_text != $undorev_text ) {
- $result = wfMerge( $undorev_text, $oldrev_text, $currev_text, $text );
+
+ $undotext = $this->mArticle->getUndoText( $undorev, $oldrev );
+ if ( $undotext === false ) {
+ # Warn the user that something went wrong
+ $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-failure">' . wfMsgNoTrans( 'undo-failure' ) . '</div>' );
} else {
- # No use doing a merge if it's just a straight revert.
- $text = $oldrev_text;
- $result = true;
- }
- if ( $result ) {
+ $text = $undotext;
# Inform the user of our success and set an automatic edit summary
$this->editFormPageTop .= $wgOut->parse( '<div class="mw-undo-success">' . wfMsgNoTrans( 'undo-success' ) . '</div>' );
$firstrev = $oldrev->getNext();
$this->undidRev = $undo;
}
$this->formtype = 'diff';
- } else {
- # Warn the user that something went wrong
- $this->editFormPageTop .= $wgOut->parse( '<div class="error mw-undo-failure">' . wfMsgNoTrans( 'undo-failure' ) . '</div>' );
}
} else {
// Failed basic sanity checks.
'missingparam' => array('code' => 'no$1', 'info' => "The \$1 parameter must be set"),
'invalidtitle' => array('code' => 'invalidtitle', 'info' => "Bad title ``\$1''"),
'nosuchpageid' => array('code' => 'nosuchpageid', 'info' => "There is no page with ID \$1"),
+ 'nosuchrevid' => array('code' => 'nosuchrevid', 'info' => "There is no revision with ID \$1"),
'invaliduser' => array('code' => 'invaliduser', 'info' => "Invalid username ``\$1''"),
'invalidexpiry' => array('code' => 'invalidexpiry', 'info' => "Invalid expiry time ``\$1''"),
'pastexpiry' => array('code' => 'pastexpiry', 'info' => "Expiry time ``\$1'' is in the past"),
'blankpage' => array('code' => 'emptypage', 'info' => "Creating new, empty pages is not allowed"),
'editconflict' => array('code' => 'editconflict', 'info' => "Edit conflict detected"),
'hashcheckfailed' => array('code' => 'badmd5', 'info' => "The supplied MD5 hash was incorrect"),
- 'missingtext' => array('code' => 'notext', 'info' => "One of the text, appendtext and prependtext parameters must be set"),
+ 'missingtext' => array('code' => 'notext', 'info' => "One of the text, appendtext, prependtext and undo parameters must be set"),
'emptynewsection' => array('code' => 'emptynewsection', 'info' => 'Creating empty new sections is not possible.'),
+ 'revwrongpage' => array('code' => 'revwrongpage', 'info' => "r\$1 is not a revision of ``\$2''"),
+ 'undo-failure' => array('code' => 'undofailure', 'info' => 'Undo failed due to conflicting intermediate edits'),
);
/**
$params = $this->extractRequestParams();
if(is_null($params['title']))
$this->dieUsageMsg(array('missingparam', 'title'));
- if(is_null($params['text']) && is_null($params['appendtext']) && is_null($params['prependtext']))
+ if(is_null($params['text']) && is_null($params['appendtext']) &&
+ is_null($params['prependtext']) &&
+ $params['undo'] == 0)
$this->dieUsageMsg(array('missingtext'));
if(is_null($params['token']))
$this->dieUsageMsg(array('missingparam', 'token'));
$params['text'] = $params['prependtext'] . $content . $params['appendtext'];
$toMD5 = $params['prependtext'] . $params['appendtext'];
}
+
+ if($params['undo'] > 0)
+ {
+ if($params['undoafter'] > 0)
+ {
+ if($params['undo'] < $params['undoafter'])
+ list($params['undo'], $params['undoafter']) =
+ array($params['undoafter'], $params['undo']);
+ $undoafterRev = Revision::newFromID($params['undoafter']);
+ }
+ $undoRev = Revision::newFromID($params['undo']);
+ if(is_null($undoRev) || $undoRev->isDeleted(Revision::DELETED_TEXT))
+ $this->dieUsageMsg(array('nosuchrevid', $params['undo']));
+ if($params['undoafter'] == 0)
+ $undoafterRev = $undoRev->getPrevious();
+ if(is_null($undoafterRev) || $undoafterRev->isDeleted(Revision::DELETED_TEXT))
+ $this->dieUsageMsg(array('nosuchrevid', $params['undoafter']));
+ if($undoRev->getPage() != $articleObj->getID())
+ $this->dieUsageMsg(array('revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText()));
+ if($undoafterRev->getPage() != $articleObj->getID())
+ $this->dieUsageMsg(array('revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText()));
+ $newtext = $articleObj->getUndoText($undoRev, $undoafterRev);
+ if($newtext === false)
+ $this->dieUsageMsg(array('undo-failure'));
+ $params['text'] = $newtext;
+ // If no summary was given and we only undid one rev,
+ // use an autosummary
+ if(is_null($params['summary']) && $titleObj->getNextRevisionID($undoafterRev->getID()) == $params['undo'])
+ $params['summary'] = wfMsgForContent('undo-summary', $params['undo'], $undoRev->getUserText());
+ }
# See if the MD5 hash checks out
- if(isset($params['md5']))
+ if(!is_null($params['md5']))
if(md5($toMD5) !== $params['md5'])
$this->dieUsageMsg(array('hashcheckfailed'));
# Run hooks
# Handle CAPTCHA parameters
global $wgRequest;
- if(isset($params['captchaid']))
+ if(!is_null($params['captchaid']))
$wgRequest->setVal( 'wpCaptchaId', $params['captchaid'] );
- if(isset($params['captchaword']))
+ if(!is_null($params['captchaword']))
$wgRequest->setVal( 'wpCaptchaWord', $params['captchaword'] );
$r = array();
if(!wfRunHooks('APIEditBeforeSave', array(&$ep, $ep->textbox1, &$r)))
'md5' => null,
'prependtext' => null,
'appendtext' => null,
+ 'undo' => array(
+ ApiBase :: PARAM_TYPE => 'integer'
+ ),
+ 'undoafter' => array(
+ ApiBase :: PARAM_TYPE => 'integer'
+ ),
);
}
'prependtext' => array( 'Add this text to the beginning of the page. Overrides text.',
'Don\'t use together with section: that won\'t do what you expect.'),
'appendtext' => 'Add this text to the end of the page. Overrides text',
+ 'undo' => 'Undo this revision. Overrides text, prependtext and appendtext',
+ 'undoafter' => 'Undo all revisions from undo to this one. If not set, just undo one revision',
);
}
protected function getExamples() {
return array (
"Edit a page (anonymous user):",
- " api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\"
+ " api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\",
+ "Prepend __NOTOC__ to a page (anonymous user):",
+ " api.php?action=edit&title=Test&summary=NOTOC&minor&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\",
+ "Undo r13579 through r13585 with autosummary(anonymous user):",
+ " api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\",
);
}