From: daniel Date: Mon, 25 Jun 2012 14:09:08 +0000 (+0200) Subject: make ApiEditPage aware of content model and format. X-Git-Tag: 1.31.0-rc.0~22097^2^2~80^2~4 X-Git-Url: https://git.cyclocoop.org/%28%28?a=commitdiff_plain;h=436b2d37ade1bd25f117eddbd00c9cdff95e727e;p=lhc%2Fweb%2Fwiklou.git make ApiEditPage aware of content model and format. Change-Id: I2ec9a8b38b10eecf47a51855ae8010a91c8acc90 --- diff --git a/includes/api/ApiEditPage.php b/includes/api/ApiEditPage.php index 814f0d4e3a..905f40e9ea 100644 --- a/includes/api/ApiEditPage.php +++ b/includes/api/ApiEditPage.php @@ -54,6 +54,30 @@ class ApiEditPage extends ApiBase { $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); } + $contentHandler = $pageObj->getContentHandler(); + + // @todo ask handler whether direct editing is supported at all! make allowFlatEdit() method or some such + + if ( !isset( $params['contentformat'] ) || $params['contentformat'] == '' ) { + $contentFormat = $contentHandler->getDefaultFormat(); + $params['contentformat'] = ContentHandler::getContentFormatMimeType( $contentFormat ); + } else { + $contentFormat = ContentHandler::getContentFormatID( $params['contentformat'] ); + + if ( !is_int( $contentFormat ) ) { + $this->dieUsage( "Unknown format " . $params['contentformat'], 'badformat' ); + } + } + + if ( !$contentHandler->isSupportedFormat( $contentFormat ) ) { + $formatName = ContentHandler::getContentFormatMimeType( $contentFormat ); + $modelName = $contentHandler->getModelName(); + $name = $titleObj->getPrefixedDBkey(); + $model = $contentHandler->getModelID(); + + $this->dieUsage( "The requested format #$contentFormat ($formatName) is not supported for content model #$model ($modelName) used by $name", 'badformat' ); + } + $apiResult = $this->getResult(); if ( $params['redirect'] ) { @@ -99,32 +123,52 @@ class ApiEditPage extends ApiBase { $this->dieUsageMsg( $errors[0] ); } - $articleObj = Article::newFromTitle( $titleObj, $this->getContext() ); - $toMD5 = $params['text']; if ( !is_null( $params['appendtext'] ) || !is_null( $params['prependtext'] ) ) { - // For non-existent pages, Article::getContent() - // returns an interface message rather than '' - // We do want getContent()'s behavior for non-existent - // MediaWiki: pages, though - if ( $articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI ) { - $content = null; - $text = ''; - } else { - $content = $articleObj->getContentObject(); - $text = ContentHandler::getContentText( $content ); #FIXME: serialize?! get format from params?... + $content = $pageObj->getContent(); + + if ( !( $content instanceof TextContent ) ) { + // @todo: ContentHandler should have an isFlat() method or some such + // @todo: XXX: or perhaps there should be Content::append(), Content::prepend() and Content::supportsConcatenation() + $mode = $contentHandler->getModelName(); + $this->dieUsage( "Can't append to pages using content model $mode", 'appendnotsupported' ); + } + + if ( !$content ) { + # If this is a MediaWiki:x message, then load the messages + # and return the message value for x. + if ( $titleObj->getNamespace() == NS_MEDIAWIKI ) { + $text = $titleObj->getDefaultMessageText(); + if ( $text === false ) { + $text = ''; + } + + $content = ContentHandler::makeContent( $text, $this->getTitle() ); + } } if ( !is_null( $params['section'] ) ) { + if ( !$contentHandler->supportsSections() ) { + $modelName = $contentHandler->getModelName(); + $this->dieUsage( "Sections are not supported for this content model: $modelName.", 'sectionsnotsupported' ); + } + // Process the content for section edits $section = intval( $params['section'] ); - $sectionContent = $content->getSection( $section ); - $text = ContentHandler::getContentText( $sectionContent ); #FIXME: serialize?! get format from params?... - if ( $text === false || $text === null ) { + $content = $content->getSection( $section ); + + if ( !$content ) { $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); } } + + if ( !$content ) { + $text = ''; + } else { + $text = $content->serialize( $contentFormat ); + } + $params['text'] = $params['prependtext'] . $text . $params['appendtext']; $toMD5 = $params['prependtext'] . $params['appendtext']; } @@ -149,18 +193,21 @@ class ApiEditPage extends ApiBase { $this->dieUsageMsg( array( 'nosuchrevid', $params['undoafter'] ) ); } - if ( $undoRev->getPage() != $articleObj->getID() ) { + if ( $undoRev->getPage() != $pageObj->getID() ) { $this->dieUsageMsg( array( 'revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText() ) ); } - if ( $undoafterRev->getPage() != $articleObj->getID() ) { + if ( $undoafterRev->getPage() != $pageObj->getID() ) { $this->dieUsageMsg( array( 'revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText() ) ); } - $newtext = $articleObj->getUndoText( $undoRev, $undoafterRev ); - if ( $newtext === false ) { + $newContent = $contentHandler->getUndoContent( $undoRev, $undoafterRev ); + if ( !$newContent ) { $this->dieUsageMsg( 'undo-failure' ); } - $params['text'] = $newtext; + + $params['contentformat'] = $contentHandler->getDefaultFormat(); + $params['text'] = $newContent->serialize( $params['contentformat'] ); + // 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'] ) { @@ -177,6 +224,8 @@ class ApiEditPage extends ApiBase { // That interface kind of sucks, but it's workable $requestArray = array( 'wpTextbox1' => $params['text'], + 'format' => $contentFormat, + 'model' => $contentHandler->getModelID(), 'wpEditToken' => $params['token'], 'wpIgnoreBlankSummary' => '' ); @@ -194,7 +243,7 @@ class ApiEditPage extends ApiBase { if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) { $requestArray['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] ); } else { - $requestArray['wpEdittime'] = $articleObj->getTimestamp(); + $requestArray['wpEdittime'] = $pageObj->getTimestamp(); } if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) { @@ -242,8 +291,8 @@ class ApiEditPage extends ApiBase { // TODO: Make them not or check if they still do $wgTitle = $titleObj; - $handler = ContentHandler::getForTitle( $titleObj ); - $ep = $handler->createEditPage( $articleObj ); + $articleObject = new Article( $titleObj ); + $ep = new EditPage( $articleObject ); $ep->setContextTitle( $titleObj ); $ep->importFormData( $req ); @@ -262,7 +311,7 @@ class ApiEditPage extends ApiBase { } // Do the actual save - $oldRevId = $articleObj->getRevIdFetched(); + $oldRevId = $articleObject->getRevIdFetched(); $result = null; // Fake $wgRequest for some hooks inside EditPage // @todo FIXME: This interface SUCKS @@ -329,14 +378,15 @@ class ApiEditPage extends ApiBase { $r['result'] = 'Success'; $r['pageid'] = intval( $titleObj->getArticleID() ); $r['title'] = $titleObj->getPrefixedText(); - $newRevId = $articleObj->getLatest(); + $r['contentmodel'] = $titleObj->getContentModel(); + $newRevId = $articleObject->getLatest(); if ( $newRevId == $oldRevId ) { $r['nochange'] = ''; } else { $r['oldrevid'] = intval( $oldRevId ); $r['newrevid'] = intval( $newRevId ); $r['newtimestamp'] = wfTimestamp( TS_ISO_8601, - $articleObj->getTimestamp() ); + $pageObj->getTimestamp() ); } break; @@ -397,6 +447,10 @@ class ApiEditPage extends ApiBase { array( 'unknownerror', 'retval' ), array( 'code' => 'nosuchsection', 'info' => 'There is no section section.' ), array( 'code' => 'invalidsection', 'info' => 'The section parameter must be set to an integer or \'new\'' ), + array( 'code' => 'sectionsnotsupported', 'info' => 'Sections are not supported for this type of page.' ), + array( 'code' => 'editnotsupported', 'info' => 'Editing of this type of page is not supported using the text based edit API.' ), + array( 'code' => 'appendnotsupported', 'info' => 'This type of page can not be edited by appending or prepending text.' ), + array( 'code' => 'badformat', 'info' => 'The requested serialization format can not be applied to the page\'s content model' ), array( 'customcssprotected' ), array( 'customjsprotected' ), ) diff --git a/tests/phpunit/includes/api/ApiEditPageTest.php b/tests/phpunit/includes/api/ApiEditPageTest.php new file mode 100644 index 0000000000..3ed983b01a --- /dev/null +++ b/tests/phpunit/includes/api/ApiEditPageTest.php @@ -0,0 +1,104 @@ +doLogin(); + } + + function getTokens() { + return $this->getTokenList( self::$users['sysop'] ); + } + + function testEdit() { + $name = 'ApiEditPageTest_testEdit'; + + $tokenData = $this->getTokens(); + + if( !isset( $tokenData[0]['query']['pages'] ) ) { + $this->markTestIncomplete( "No edit token found" ); + } + + $keys = array_keys( $tokenData[0]['query']['pages'] ); + $key = array_pop( $keys ); + $pageinfo = $tokenData[0]['query']['pages'][$key]; + $session = $tokenData[2]; + + // ----------------------------------------------------------------------- + + $data = $this->doApiRequest( array( + 'action' => 'edit', + 'title' => $name, + 'text' => 'some text', + 'token' => $pageinfo['edittoken'] ), + $session, + false, + self::$users['sysop']->user ); + + $this->assertArrayHasKey( 'edit', $data[0] ); + $this->assertArrayHasKey( 'result', $data[0]['edit'] ); + $this->assertEquals( 'Success', $data[0]['edit']['result'] ); + + $this->assertArrayHasKey( 'new', $data[0]['edit'] ); + $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] ); + + $this->assertArrayHasKey( 'pageid', $data[0]['edit'] ); + $this->assertArrayHasKey( 'contentmodel', $data[0]['edit'] ); + $this->assertEquals( CONTENT_MODEL_WIKITEXT, $data[0]['edit']['contentmodel'] ); + + // ----------------------------------------------------------------------- + $data = $this->doApiRequest( array( + 'action' => 'edit', + 'title' => $name, + 'text' => 'some text', + 'token' => $pageinfo['edittoken'] ), + $session, + false, + self::$users['sysop']->user ); + + $this->assertEquals( 'Success', $data[0]['edit']['result'] ); + + $this->assertArrayNotHasKey( 'new', $data[0]['edit'] ); + $this->assertArrayHasKey( 'nochange', $data[0]['edit'] ); + + // ----------------------------------------------------------------------- + $data = $this->doApiRequest( array( + 'action' => 'edit', + 'title' => $name, + 'text' => 'different text', + 'token' => $pageinfo['edittoken'] ), + $session, + false, + self::$users['sysop']->user ); + + $this->assertEquals( 'Success', $data[0]['edit']['result'] ); + + $this->assertArrayNotHasKey( 'new', $data[0]['edit'] ); + $this->assertArrayNotHasKey( 'nochange', $data[0]['edit'] ); + + $this->assertArrayHasKey( 'oldrevid', $data[0]['edit'] ); + $this->assertArrayHasKey( 'newrevid', $data[0]['edit'] ); + $this->assertTrue( $data[0]['edit']['newrevid'] !== $data[0]['edit']['oldrevid'], "revision id should change after edit" ); + } + + function testEditAppend() { + $this->markTestIncomplete( "not yet implemented" ); + } + + function testEditSection() { + $this->markTestIncomplete( "not yet implemented" ); + } + + function testUndo() { + $this->markTestIncomplete( "not yet implemented" ); + } + + function testEditNonText() { + $this->markTestIncomplete( "not yet implemented" ); + } +}