Merge "api: Split save action into separate API module"

This commit is contained in:
jenkins-bot 2013-07-11 23:11:22 +00:00 committed by Gerrit Code Review
commit 87f48b1d44
5 changed files with 191 additions and 121 deletions

View file

@ -101,46 +101,6 @@ class ApiVisualEditor extends ApiBase {
); );
} }
protected function saveWikitext( $title, $wikitext, $params ) {
$apiParams = array(
'action' => 'edit',
'title' => $title->getPrefixedDBkey(),
'text' => $wikitext,
'summary' => $params['summary'],
'basetimestamp' => $params['basetimestamp'],
'starttimestamp' => $params['starttimestamp'],
'token' => $params['token'],
);
if ( $params['minor'] ) {
$apiParams['minor'] = true;
}
// FIXME add some way that the user's preferences can be respected
$apiParams['watchlist'] = $params['watch'] ? 'watch' : 'unwatch';
if ( $params['captchaid'] ) {
$apiParams['captchaid'] = $params['captchaid'];
}
if ( $params['captchaword'] ) {
$apiParams['captchaword'] = $params['captchaword'];
}
$api = new ApiMain(
new DerivativeRequest(
$this->getRequest(),
$apiParams,
true // was posted
),
true // enable write
);
$api->execute();
return $api->getResultData();
}
protected function parseWikitext( $title ) { protected function parseWikitext( $title ) {
$apiParams = array( $apiParams = array(
'action' => 'parse', 'action' => 'parse',
@ -318,52 +278,6 @@ class ApiVisualEditor extends ApiBase {
$result = array( 'result' => 'success', 'content' => $content ); $result = array( 'result' => 'success', 'content' => $content );
} }
break; break;
case 'save':
$wikitext = $this->postHTML( $page, $params['html'], $parserParams );
if ( $wikitext === false ) {
$this->dieUsage( 'Error contacting the Parsoid server', 'parsoidserver' );
}
$saveresult = $this->saveWikitext( $page, $wikitext, $params );
$editStatus = $saveresult['edit']['result'];
// Error
if ( !isset( $saveresult['edit']['result'] ) || $editStatus !== 'Success' ) {
$result = array(
'result' => 'error',
'edit' => $saveresult['edit']
);
// Success
} else {
if ( isset( $saveresult['edit']['newrevid'] ) && $wgVisualEditorUseChangeTagging ) {
ChangeTags::addTags( 'visualeditor', null,
intval( $saveresult['edit']['newrevid'] ),
null
);
if ( $params['needcheck'] ) {
ChangeTags::addTags( 'visualeditor-needcheck', null,
intval( $saveresult['edit']['newrevid'] ),
null
);
}
}
// Return result of parseWikitext instead of saveWikitext so that the
// frontend can update the page rendering without a refresh.
$result = $this->parseWikitext( $page );
if ( $result === false ) {
$this->dieUsage( 'Error contacting the Parsoid server', 'parsoidserver' );
}
if ( isset( $saveresult['edit']['newrevid'] ) ) {
$result['newrevid'] = intval( $saveresult['edit']['newrevid'] );
}
$result['result'] = 'success';
}
break;
case 'diff': case 'diff':
$wikitext = $this->postHTML( $page, $params['html'], $parserParams ); $wikitext = $this->postHTML( $page, $params['html'], $parserParams );
@ -390,33 +304,18 @@ class ApiVisualEditor extends ApiBase {
), ),
'paction' => array( 'paction' => array(
ApiBase::PARAM_REQUIRED => true, ApiBase::PARAM_REQUIRED => true,
ApiBase::PARAM_TYPE => array( 'parse', 'parsefragment', 'serialize', 'save', 'diff' ), ApiBase::PARAM_TYPE => array( 'parse', 'parsefragment', 'serialize', 'diff' ),
),
'token' => array(
ApiBase::PARAM_REQUIRED => true,
), ),
'wikitext' => null, 'wikitext' => null,
'basetimestamp' => null, 'basetimestamp' => null,
'starttimestamp' => null, 'starttimestamp' => null,
'needcheck' => array(
ApiBase::PARAM_TYPE => 'boolean'
),
'oldid' => null, 'oldid' => null,
'minor' => null,
'watch' => null,
'html' => null, 'html' => null,
'summary' => null,
'captchaid' => null,
'captchaword' => null,
); );
} }
public function needsToken() { public function needsToken() {
return true; return false;
}
public function getTokenSalt() {
return '';
} }
public function mustBePosted() { public function mustBePosted() {
@ -435,20 +334,12 @@ class ApiVisualEditor extends ApiBase {
return array( return array(
'page' => 'The page to perform actions on.', 'page' => 'The page to perform actions on.',
'paction' => 'Action to perform', 'paction' => 'Action to perform',
'oldid' => 'The revision number to use. For paction=save, defauls to latest revision.' + 'oldid' => 'The revision number to use (defaults to latest version).',
' Required for other actions. Use 0 for new page.',
'minor' => 'Flag for minor edit.',
'html' => 'HTML to send to parsoid in exchange for wikitext', 'html' => 'HTML to send to parsoid in exchange for wikitext',
'summary' => 'Edit summary',
'basetimestamp' => 'When saving, set this to the timestamp of the revision that was' 'basetimestamp' => 'When saving, set this to the timestamp of the revision that was'
.' edited. Used to detect edit conflicts.', .' edited. Used to detect edit conflicts.',
'starttimestamp' => 'When saving, set this to the timestamp of when the page was loaded.' 'starttimestamp' => 'When saving, set this to the timestamp of when the page was loaded.'
.' Used to detect edit conflicts.', .' Used to detect edit conflicts.',
'token' => 'Edit token',
'needcheck' => 'When saving, set this parameter if the revision might have roundtrip'
. 'problems. This will result in the edit being tagged.',
'captchaid' => 'Captcha id (when saving with a captcha response).',
'captchaword' => 'Answer to the captcha (when saving with a captcha response).',
); );
} }

182
ApiVisualEditorEdit.php Normal file
View file

@ -0,0 +1,182 @@
<?php
/**
* Parsoid API wrapper.
*
* @file
* @ingroup Extensions
* @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
* @license The MIT License (MIT); see LICENSE.txt
*/
class ApiVisualEditorEdit extends ApiVisualEditor {
protected function saveWikitext( $title, $wikitext, $params ) {
$apiParams = array(
'action' => 'edit',
'title' => $title->getPrefixedDBkey(),
'text' => $wikitext,
'summary' => $params['summary'],
'basetimestamp' => $params['basetimestamp'],
'starttimestamp' => $params['starttimestamp'],
'token' => $params['token'],
);
if ( $params['minor'] ) {
$apiParams['minor'] = true;
}
// FIXME add some way that the user's preferences can be respected
$apiParams['watchlist'] = $params['watch'] ? 'watch' : 'unwatch';
if ( $params['captchaid'] ) {
$apiParams['captchaid'] = $params['captchaid'];
}
if ( $params['captchaword'] ) {
$apiParams['captchaword'] = $params['captchaword'];
}
$api = new ApiMain(
new DerivativeRequest(
$this->getRequest(),
$apiParams,
true // was posted
),
true // enable write
);
$api->execute();
return $api->getResultData();
}
public function execute() {
global $wgVisualEditorNamespaces, $wgVisualEditorUseChangeTagging,
$wgVisualEditorEditNotices;
$user = $this->getUser();
$params = $this->extractRequestParams();
$page = Title::newFromText( $params['page'] );
if ( !$page ) {
$this->dieUsageMsg( 'invalidtitle', $params['page'] );
}
if ( !in_array( $page->getNamespace(), $wgVisualEditorNamespaces ) ) {
$this->dieUsage( "VisualEditor is not enabled in namespace " .
$page->getNamespace(), 'novenamespace' );
}
$parserParams = array();
if ( isset( $params['oldid'] ) ) {
$parserParams['oldid'] = $params['oldid'];
}
$wikitext = $this->postHTML( $page, $params['html'], $parserParams );
if ( $wikitext === false ) {
$this->dieUsage( 'Error contacting the Parsoid server', 'parsoidserver' );
}
$saveresult = $this->saveWikitext( $page, $wikitext, $params );
$editStatus = $saveresult['edit']['result'];
// Error
if ( !isset( $saveresult['edit']['result'] ) || $editStatus !== 'Success' ) {
$result = array(
'result' => 'error',
'edit' => $saveresult['edit']
);
// Success
} else {
if ( isset( $saveresult['edit']['newrevid'] ) && $wgVisualEditorUseChangeTagging ) {
ChangeTags::addTags( 'visualeditor', null,
intval( $saveresult['edit']['newrevid'] ),
null
);
if ( $params['needcheck'] ) {
ChangeTags::addTags( 'visualeditor-needcheck', null,
intval( $saveresult['edit']['newrevid'] ),
null
);
}
}
// Return result of parseWikitext instead of saveWikitext so that the
// frontend can update the page rendering without a refresh.
$result = $this->parseWikitext( $page );
if ( $result === false ) {
$this->dieUsage( 'Error contacting the Parsoid server', 'parsoidserver' );
}
if ( isset( $saveresult['edit']['newrevid'] ) ) {
$result['newrevid'] = intval( $saveresult['edit']['newrevid'] );
}
$result['result'] = 'success';
}
$this->getResult()->addValue( null, $this->getModuleName(), $result );
}
public function getAllowedParams() {
return array(
'page' => array(
ApiBase::PARAM_REQUIRED => true,
),
'token' => array(
ApiBase::PARAM_REQUIRED => true,
),
'wikitext' => null,
'basetimestamp' => null,
'starttimestamp' => null,
'needcheck' => array(
ApiBase::PARAM_TYPE => 'boolean'
),
'oldid' => null,
'minor' => null,
'watch' => null,
'html' => null,
'summary' => null,
'captchaid' => null,
'captchaword' => null,
);
}
public function needsToken() {
return true;
}
public function getTokenSalt() {
return '';
}
public function mustBePosted() {
return true;
}
public function isWriteMode() {
return true;
}
public function getParamDescription() {
return array(
'page' => 'The page to perform actions on.',
'oldid' => 'The revision number to use. Defaults to latest revision. Use 0 for new page.',
'minor' => 'Flag for minor edit.',
'html' => 'HTML to send to Parsoid in exchange for wikitext',
'summary' => 'Edit summary',
'basetimestamp' => 'When saving, set this to the timestamp of the revision that was'
. ' edited. Used to detect edit conflicts.',
'starttimestamp' => 'When saving, set this to the timestamp of when the page was loaded.'
. ' Used to detect edit conflicts.',
'token' => 'Edit token',
'needcheck' => 'When saving, set this parameter if the revision might have roundtrip'
. ' problems. This will result in the edit being tagged.',
'captchaid' => 'Captcha ID (when saving with a captcha response).',
'captchaword' => 'Answer to the captcha (when saving with a captcha response).',
);
}
public function getDescription() {
return 'Save an HTML5 page to MediaWiki (converted to wikitext via the Parsoid service).';
}
}

View file

@ -732,7 +732,9 @@ $wgResourceModules += array(
); );
// Parsoid Wrapper API // Parsoid Wrapper API
$wgAutoloadClasses['ApiVisualEditor'] = $dir . 'ApiVisualEditor.php'; $wgAutoloadClasses['ApiVisualEditor'] = $dir . 'ApiVisualEditor.php';
$wgAutoloadClasses['ApiVisualEditorEdit'] = $dir . 'ApiVisualEditorEdit.php';
$wgAPIModules['visualeditor'] = 'ApiVisualEditor'; $wgAPIModules['visualeditor'] = 'ApiVisualEditor';
$wgAPIModules['visualeditoredit'] = 'ApiVisualEditorEdit';
// Integration Hooks // Integration Hooks
$wgAutoloadClasses['VisualEditorHooks'] = $dir . 'VisualEditor.hooks.php'; $wgAutoloadClasses['VisualEditorHooks'] = $dir . 'VisualEditor.hooks.php';

View file

@ -459,7 +459,7 @@ ve.init.mw.ViewPageTarget.prototype.onSaveError = function ( jqXHR, status, data
// "question" or "fancy" type of captcha. They all expose differently named properties in the // "question" or "fancy" type of captcha. They all expose differently named properties in the
// API for different things in the UI. At this point we only support the FancyCaptha which we // API for different things in the UI. At this point we only support the FancyCaptha which we
// very intuitively detect by the presence of a "url" property. // very intuitively detect by the presence of a "url" property.
editApi = data && data.visualeditor && data.visualeditor.edit; editApi = data && data.visualeditoredit && data.visualeditoredit.edit;
if ( editApi && editApi.captcha && editApi.captcha.url ) { if ( editApi && editApi.captcha && editApi.captcha.url ) {
this.captcha = { this.captcha = {
input: new ve.ui.TextInputWidget(), input: new ve.ui.TextInputWidget(),

View file

@ -314,7 +314,7 @@ ve.init.mw.Target.onTokenError = function ( jqXHR, status, error ) {
*/ */
ve.init.mw.Target.onSave = function ( response ) { ve.init.mw.Target.onSave = function ( response ) {
this.saving = false; this.saving = false;
var data = response.visualeditor; var data = response.visualeditoredit;
if ( !data && !response.error ) { if ( !data && !response.error ) {
ve.init.mw.Target.onSaveError.call( this, null, 'Invalid response from server', response ); ve.init.mw.Target.onSaveError.call( this, null, 'Invalid response from server', response );
} else if ( response.error ) { } else if ( response.error ) {
@ -506,7 +506,6 @@ ve.init.mw.Target.prototype.load = function () {
'action': 'visualeditor', 'action': 'visualeditor',
'paction': 'parse', 'paction': 'parse',
'page': this.pageName, 'page': this.pageName,
'token': this.editToken,
'format': 'json' 'format': 'json'
}; };
@ -574,8 +573,7 @@ ve.init.mw.Target.prototype.save = function ( doc, options ) {
var data = { var data = {
'format': 'json', 'format': 'json',
'action': 'visualeditor', 'action': 'visualeditoredit',
'paction': 'save',
'page': this.pageName, 'page': this.pageName,
'oldid': this.revid, 'oldid': this.revid,
'basetimestamp': this.baseTimeStamp, 'basetimestamp': this.baseTimeStamp,
@ -631,9 +629,7 @@ ve.init.mw.Target.prototype.showChanges = function ( doc ) {
'paction': 'diff', 'paction': 'diff',
'page': this.pageName, 'page': this.pageName,
'oldid': this.revid, 'oldid': this.revid,
'html': this.getHtml( doc ), 'html': this.getHtml( doc )
// TODO: API required editToken, though not relevant for diff
'token': this.editToken
}, },
'dataType': 'json', 'dataType': 'json',
'type': 'POST', 'type': 'POST',
@ -722,7 +718,6 @@ ve.init.mw.Target.prototype.serialize = function ( doc, callback ) {
'html': this.getHtml( doc ), 'html': this.getHtml( doc ),
'page': this.pageName, 'page': this.pageName,
'oldid': this.revid, 'oldid': this.revid,
'token': this.editToken,
'format': 'json' 'format': 'json'
}, },
'dataType': 'json', 'dataType': 'json',