123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739 |
- <?php
- /**
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
- use MediaWiki\MediaWikiServices;
- use MediaWiki\Revision\MutableRevisionRecord;
- use MediaWiki\Revision\RevisionRecord;
- use MediaWiki\Revision\RevisionArchiveRecord;
- use MediaWiki\Revision\RevisionStore;
- use MediaWiki\Revision\SlotRecord;
- /**
- * @ingroup API
- */
- class ApiComparePages extends ApiBase {
- /** @var RevisionStore */
- private $revisionStore;
- /** @var \MediaWiki\Revision\SlotRoleRegistry */
- private $slotRoleRegistry;
- private $guessedTitle = false, $props;
- public function __construct( ApiMain $mainModule, $moduleName, $modulePrefix = '' ) {
- parent::__construct( $mainModule, $moduleName, $modulePrefix );
- $this->revisionStore = MediaWikiServices::getInstance()->getRevisionStore();
- $this->slotRoleRegistry = MediaWikiServices::getInstance()->getSlotRoleRegistry();
- }
- public function execute() {
- $params = $this->extractRequestParams();
- // Parameter validation
- $this->requireAtLeastOneParameter(
- $params, 'fromtitle', 'fromid', 'fromrev', 'fromtext', 'fromslots'
- );
- $this->requireAtLeastOneParameter(
- $params, 'totitle', 'toid', 'torev', 'totext', 'torelative', 'toslots'
- );
- $this->props = array_flip( $params['prop'] );
- // Cache responses publicly by default. This may be overridden later.
- $this->getMain()->setCacheMode( 'public' );
- // Get the 'from' RevisionRecord
- list( $fromRev, $fromRelRev, $fromValsRev ) = $this->getDiffRevision( 'from', $params );
- // Get the 'to' RevisionRecord
- if ( $params['torelative'] !== null ) {
- if ( !$fromRelRev ) {
- $this->dieWithError( 'apierror-compare-relative-to-nothing' );
- }
- if ( $params['torelative'] !== 'cur' && $fromRelRev instanceof RevisionArchiveRecord ) {
- // RevisionStore's getPreviousRevision/getNextRevision blow up
- // when passed an RevisionArchiveRecord for a deleted page
- $this->dieWithError( [ 'apierror-compare-relative-to-deleted', $params['torelative'] ] );
- }
- switch ( $params['torelative'] ) {
- case 'prev':
- // Swap 'from' and 'to'
- list( $toRev, $toRelRev, $toValsRev ) = [ $fromRev, $fromRelRev, $fromValsRev ];
- $fromRev = $this->revisionStore->getPreviousRevision( $toRelRev );
- $fromRelRev = $fromRev;
- $fromValsRev = $fromRev;
- if ( !$fromRev ) {
- $title = Title::newFromLinkTarget( $toRelRev->getPageAsLinkTarget() );
- $this->addWarning( [
- 'apiwarn-compare-no-prev',
- wfEscapeWikiText( $title->getPrefixedText() ),
- $toRelRev->getId()
- ] );
- // (T203433) Create an empty dummy revision as the "previous".
- // The main slot has to exist, the rest will be handled by DifferenceEngine.
- $fromRev = $this->revisionStore->newMutableRevisionFromArray( [
- 'title' => $title ?: Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __METHOD__ )
- ] );
- $fromRev->setContent(
- SlotRecord::MAIN,
- $toRelRev->getContent( SlotRecord::MAIN, RevisionRecord::RAW )
- ->getContentHandler()
- ->makeEmptyContent()
- );
- }
- break;
- case 'next':
- $toRev = $this->revisionStore->getNextRevision( $fromRelRev );
- $toRelRev = $toRev;
- $toValsRev = $toRev;
- if ( !$toRev ) {
- $title = Title::newFromLinkTarget( $fromRelRev->getPageAsLinkTarget() );
- $this->addWarning( [
- 'apiwarn-compare-no-next',
- wfEscapeWikiText( $title->getPrefixedText() ),
- $fromRelRev->getId()
- ] );
- // (T203433) The web UI treats "next" as "cur" in this case.
- // Avoid repeating metadata by making a MutableRevisionRecord with no changes.
- $toRev = MutableRevisionRecord::newFromParentRevision( $fromRelRev );
- }
- break;
- case 'cur':
- $title = $fromRelRev->getPageAsLinkTarget();
- $toRev = $this->revisionStore->getRevisionByTitle( $title );
- if ( !$toRev ) {
- $title = Title::newFromLinkTarget( $title );
- $this->dieWithError(
- [ 'apierror-missingrev-title', wfEscapeWikiText( $title->getPrefixedText() ) ], 'nosuchrevid'
- );
- }
- $toRelRev = $toRev;
- $toValsRev = $toRev;
- break;
- }
- } else {
- list( $toRev, $toRelRev, $toValsRev ) = $this->getDiffRevision( 'to', $params );
- }
- // Handle missing from or to revisions (should never happen)
- // @codeCoverageIgnoreStart
- if ( !$fromRev || !$toRev ) {
- $this->dieWithError( 'apierror-baddiff' );
- }
- // @codeCoverageIgnoreEnd
- // Handle revdel
- if ( !$fromRev->audienceCan(
- RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_THIS_USER, $this->getUser()
- ) ) {
- $this->dieWithError( [ 'apierror-missingcontent-revid', $fromRev->getId() ], 'missingcontent' );
- }
- if ( !$toRev->audienceCan(
- RevisionRecord::DELETED_TEXT, RevisionRecord::FOR_THIS_USER, $this->getUser()
- ) ) {
- $this->dieWithError( [ 'apierror-missingcontent-revid', $toRev->getId() ], 'missingcontent' );
- }
- // Get the diff
- $context = new DerivativeContext( $this->getContext() );
- if ( $fromRelRev && $fromRelRev->getPageAsLinkTarget() ) {
- $context->setTitle( Title::newFromLinkTarget( $fromRelRev->getPageAsLinkTarget() ) );
- } elseif ( $toRelRev && $toRelRev->getPageAsLinkTarget() ) {
- $context->setTitle( Title::newFromLinkTarget( $toRelRev->getPageAsLinkTarget() ) );
- } else {
- $guessedTitle = $this->guessTitle();
- if ( $guessedTitle ) {
- $context->setTitle( $guessedTitle );
- }
- }
- $de = new DifferenceEngine( $context );
- $de->setRevisions( $fromRev, $toRev );
- if ( $params['slots'] === null ) {
- $difftext = $de->getDiffBody();
- if ( $difftext === false ) {
- $this->dieWithError( 'apierror-baddiff' );
- }
- } else {
- $difftext = [];
- foreach ( $params['slots'] as $role ) {
- $difftext[$role] = $de->getDiffBodyForRole( $role );
- }
- }
- // Fill in the response
- $vals = [];
- $this->setVals( $vals, 'from', $fromValsRev );
- $this->setVals( $vals, 'to', $toValsRev );
- if ( isset( $this->props['rel'] ) ) {
- if ( !$fromRev instanceof MutableRevisionRecord ) {
- $rev = $this->revisionStore->getPreviousRevision( $fromRev );
- if ( $rev ) {
- $vals['prev'] = $rev->getId();
- }
- }
- if ( !$toRev instanceof MutableRevisionRecord ) {
- $rev = $this->revisionStore->getNextRevision( $toRev );
- if ( $rev ) {
- $vals['next'] = $rev->getId();
- }
- }
- }
- if ( isset( $this->props['diffsize'] ) ) {
- $vals['diffsize'] = 0;
- foreach ( (array)$difftext as $text ) {
- $vals['diffsize'] += strlen( $text );
- }
- }
- if ( isset( $this->props['diff'] ) ) {
- if ( is_array( $difftext ) ) {
- ApiResult::setArrayType( $difftext, 'kvp', 'diff' );
- $vals['bodies'] = $difftext;
- } else {
- ApiResult::setContentValue( $vals, 'body', $difftext );
- }
- }
- // Diffs can be really big and there's little point in having
- // ApiResult truncate it to an empty response since the diff is the
- // whole reason this module exists. So pass NO_SIZE_CHECK here.
- $this->getResult()->addValue( null, $this->getModuleName(), $vals, ApiResult::NO_SIZE_CHECK );
- }
- /**
- * Load a revision by ID
- *
- * Falls back to checking the archive table if appropriate.
- *
- * @param int $id
- * @return RevisionRecord|null
- */
- private function getRevisionById( $id ) {
- $rev = $this->revisionStore->getRevisionById( $id );
- if ( !$rev && $this->getPermissionManager()
- ->userHasAnyRight( $this->getUser(), 'deletedtext', 'undelete' )
- ) {
- // Try the 'archive' table
- $arQuery = $this->revisionStore->getArchiveQueryInfo();
- $row = $this->getDB()->selectRow(
- $arQuery['tables'],
- array_merge(
- $arQuery['fields'],
- [ 'ar_namespace', 'ar_title' ]
- ),
- [ 'ar_rev_id' => $id ],
- __METHOD__,
- [],
- $arQuery['joins']
- );
- if ( $row ) {
- $rev = $this->revisionStore->newRevisionFromArchiveRow( $row );
- // @phan-suppress-next-line PhanUndeclaredProperty
- $rev->isArchive = true;
- }
- }
- return $rev;
- }
- /**
- * Guess an appropriate default Title for this request
- *
- * @return Title|null
- */
- private function guessTitle() {
- if ( $this->guessedTitle !== false ) {
- return $this->guessedTitle;
- }
- $this->guessedTitle = null;
- $params = $this->extractRequestParams();
- foreach ( [ 'from', 'to' ] as $prefix ) {
- if ( $params["{$prefix}rev"] !== null ) {
- $rev = $this->getRevisionById( $params["{$prefix}rev"] );
- if ( $rev ) {
- $this->guessedTitle = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
- break;
- }
- }
- if ( $params["{$prefix}title"] !== null ) {
- $title = Title::newFromText( $params["{$prefix}title"] );
- if ( $title && !$title->isExternal() ) {
- $this->guessedTitle = $title;
- break;
- }
- }
- if ( $params["{$prefix}id"] !== null ) {
- $title = Title::newFromID( $params["{$prefix}id"] );
- if ( $title ) {
- $this->guessedTitle = $title;
- break;
- }
- }
- }
- return $this->guessedTitle;
- }
- /**
- * Guess an appropriate default content model for this request
- * @param string $role Slot for which to guess the model
- * @return string|null Guessed content model
- */
- private function guessModel( $role ) {
- $params = $this->extractRequestParams();
- $title = null;
- foreach ( [ 'from', 'to' ] as $prefix ) {
- if ( $params["{$prefix}rev"] !== null ) {
- $rev = $this->getRevisionById( $params["{$prefix}rev"] );
- if ( $rev && $rev->hasSlot( $role ) ) {
- return $rev->getSlot( $role, RevisionRecord::RAW )->getModel();
- }
- }
- }
- $guessedTitle = $this->guessTitle();
- if ( $guessedTitle ) {
- return $this->slotRoleRegistry->getRoleHandler( $role )->getDefaultModel( $guessedTitle );
- }
- if ( isset( $params["fromcontentmodel-$role"] ) ) {
- return $params["fromcontentmodel-$role"];
- }
- if ( isset( $params["tocontentmodel-$role"] ) ) {
- return $params["tocontentmodel-$role"];
- }
- if ( $role === SlotRecord::MAIN ) {
- if ( isset( $params['fromcontentmodel'] ) ) {
- return $params['fromcontentmodel'];
- }
- if ( isset( $params['tocontentmodel'] ) ) {
- return $params['tocontentmodel'];
- }
- }
- return null;
- }
- /**
- * Get the RevisionRecord for one side of the diff
- *
- * This uses the appropriate set of parameters to determine what content
- * should be diffed.
- *
- * Returns three values:
- * - A RevisionRecord holding the content
- * - The revision specified, if any, even if content was supplied
- * - The revision to pass to setVals(), if any
- *
- * @param string $prefix 'from' or 'to'
- * @param array $params
- * @return array [ RevisionRecord|null, RevisionRecord|null, RevisionRecord|null ]
- */
- private function getDiffRevision( $prefix, array $params ) {
- // Back compat params
- $this->requireMaxOneParameter( $params, "{$prefix}text", "{$prefix}slots" );
- $this->requireMaxOneParameter( $params, "{$prefix}section", "{$prefix}slots" );
- if ( $params["{$prefix}text"] !== null ) {
- $params["{$prefix}slots"] = [ SlotRecord::MAIN ];
- $params["{$prefix}text-main"] = $params["{$prefix}text"];
- $params["{$prefix}section-main"] = null;
- $params["{$prefix}contentmodel-main"] = $params["{$prefix}contentmodel"];
- $params["{$prefix}contentformat-main"] = $params["{$prefix}contentformat"];
- }
- $title = null;
- $rev = null;
- $suppliedContent = $params["{$prefix}slots"] !== null;
- // Get the revision and title, if applicable
- $revId = null;
- if ( $params["{$prefix}rev"] !== null ) {
- $revId = $params["{$prefix}rev"];
- } elseif ( $params["{$prefix}title"] !== null || $params["{$prefix}id"] !== null ) {
- if ( $params["{$prefix}title"] !== null ) {
- $title = Title::newFromText( $params["{$prefix}title"] );
- if ( !$title || $title->isExternal() ) {
- $this->dieWithError(
- [ 'apierror-invalidtitle', wfEscapeWikiText( $params["{$prefix}title"] ) ]
- );
- }
- } else {
- $title = Title::newFromID( $params["{$prefix}id"] );
- if ( !$title ) {
- $this->dieWithError( [ 'apierror-nosuchpageid', $params["{$prefix}id"] ] );
- }
- }
- $revId = $title->getLatestRevID();
- if ( !$revId ) {
- $revId = null;
- // Only die here if we're not using supplied text
- if ( !$suppliedContent ) {
- if ( $title->exists() ) {
- $this->dieWithError(
- [ 'apierror-missingrev-title', wfEscapeWikiText( $title->getPrefixedText() ) ], 'nosuchrevid'
- );
- } else {
- $this->dieWithError(
- [ 'apierror-missingtitle-byname', wfEscapeWikiText( $title->getPrefixedText() ) ],
- 'missingtitle'
- );
- }
- }
- }
- }
- if ( $revId !== null ) {
- $rev = $this->getRevisionById( $revId );
- if ( !$rev ) {
- $this->dieWithError( [ 'apierror-nosuchrevid', $revId ] );
- }
- $title = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
- // If we don't have supplied content, return here. Otherwise,
- // continue on below with the supplied content.
- if ( !$suppliedContent ) {
- $newRev = $rev;
- // Deprecated 'fromsection'/'tosection'
- if ( isset( $params["{$prefix}section"] ) ) {
- $section = $params["{$prefix}section"];
- $newRev = MutableRevisionRecord::newFromParentRevision( $rev );
- $content = $rev->getContent( SlotRecord::MAIN, RevisionRecord::FOR_THIS_USER,
- $this->getUser() );
- if ( !$content ) {
- $this->dieWithError(
- [ 'apierror-missingcontent-revid-role', $rev->getId(), SlotRecord::MAIN ], 'missingcontent'
- );
- }
- $content = $content ? $content->getSection( $section ) : null;
- if ( !$content ) {
- $this->dieWithError(
- [ "apierror-compare-nosuch{$prefix}section", wfEscapeWikiText( $section ) ],
- "nosuch{$prefix}section"
- );
- }
- $newRev->setContent( SlotRecord::MAIN, $content );
- }
- return [ $newRev, $rev, $rev ];
- }
- }
- // Override $content based on supplied text
- if ( !$title ) {
- $title = $this->guessTitle();
- }
- if ( $rev ) {
- $newRev = MutableRevisionRecord::newFromParentRevision( $rev );
- } else {
- $newRev = $this->revisionStore->newMutableRevisionFromArray( [
- 'title' => $title ?: Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __METHOD__ )
- ] );
- }
- foreach ( $params["{$prefix}slots"] as $role ) {
- $text = $params["{$prefix}text-{$role}"];
- if ( $text === null ) {
- // The SlotRecord::MAIN role can't be deleted
- if ( $role === SlotRecord::MAIN ) {
- $this->dieWithError( [ 'apierror-compare-maintextrequired', $prefix ] );
- }
- // These parameters make no sense without text. Reject them to avoid
- // confusion.
- foreach ( [ 'section', 'contentmodel', 'contentformat' ] as $param ) {
- if ( isset( $params["{$prefix}{$param}-{$role}"] ) ) {
- $this->dieWithError( [
- 'apierror-compare-notext',
- wfEscapeWikiText( "{$prefix}{$param}-{$role}" ),
- wfEscapeWikiText( "{$prefix}text-{$role}" ),
- ] );
- }
- }
- $newRev->removeSlot( $role );
- continue;
- }
- $model = $params["{$prefix}contentmodel-{$role}"];
- $format = $params["{$prefix}contentformat-{$role}"];
- if ( !$model && $rev && $rev->hasSlot( $role ) ) {
- $model = $rev->getSlot( $role, RevisionRecord::RAW )->getModel();
- }
- if ( !$model && $title && $role === SlotRecord::MAIN ) {
- // @todo: Use SlotRoleRegistry and do this for all slots
- $model = $title->getContentModel();
- }
- if ( !$model ) {
- $model = $this->guessModel( $role );
- }
- if ( !$model ) {
- $model = CONTENT_MODEL_WIKITEXT;
- $this->addWarning( [ 'apiwarn-compare-nocontentmodel', $model ] );
- }
- try {
- $content = ContentHandler::makeContent( $text, $title, $model, $format );
- } catch ( MWContentSerializationException $ex ) {
- $this->dieWithException( $ex, [
- 'wrap' => ApiMessage::create( 'apierror-contentserializationexception', 'parseerror' )
- ] );
- }
- if ( $params["{$prefix}pst"] ) {
- if ( !$title ) {
- $this->dieWithError( 'apierror-compare-no-title' );
- }
- $popts = ParserOptions::newFromContext( $this->getContext() );
- $content = $content->preSaveTransform( $title, $this->getUser(), $popts );
- }
- $section = $params["{$prefix}section-{$role}"];
- if ( $section !== null && $section !== '' ) {
- if ( !$rev ) {
- $this->dieWithError( "apierror-compare-no{$prefix}revision" );
- }
- $oldContent = $rev->getContent( $role, RevisionRecord::FOR_THIS_USER, $this->getUser() );
- if ( !$oldContent ) {
- $this->dieWithError(
- [ 'apierror-missingcontent-revid-role', $rev->getId(), wfEscapeWikiText( $role ) ],
- 'missingcontent'
- );
- }
- if ( !$oldContent->getContentHandler()->supportsSections() ) {
- $this->dieWithError( [ 'apierror-sectionsnotsupported', $content->getModel() ] );
- }
- try {
- $content = $oldContent->replaceSection( $section, $content, '' );
- } catch ( Exception $ex ) {
- // Probably a content model mismatch.
- $content = null;
- }
- if ( !$content ) {
- $this->dieWithError( [ 'apierror-sectionreplacefailed' ] );
- }
- }
- // Deprecated 'fromsection'/'tosection'
- if ( $role === SlotRecord::MAIN && isset( $params["{$prefix}section"] ) ) {
- $section = $params["{$prefix}section"];
- $content = $content->getSection( $section );
- if ( !$content ) {
- $this->dieWithError(
- [ "apierror-compare-nosuch{$prefix}section", wfEscapeWikiText( $section ) ],
- "nosuch{$prefix}section"
- );
- }
- }
- $newRev->setContent( $role, $content );
- }
- return [ $newRev, $rev, null ];
- }
- /**
- * Set value fields from a RevisionRecord object
- *
- * @param array &$vals Result array to set data into
- * @param string $prefix 'from' or 'to'
- * @param RevisionRecord|null $rev
- */
- private function setVals( &$vals, $prefix, $rev ) {
- if ( $rev ) {
- $title = Title::newFromLinkTarget( $rev->getPageAsLinkTarget() );
- if ( isset( $this->props['ids'] ) ) {
- $vals["{$prefix}id"] = $title->getArticleID();
- $vals["{$prefix}revid"] = $rev->getId();
- }
- if ( isset( $this->props['title'] ) ) {
- ApiQueryBase::addTitleInfo( $vals, $title, $prefix );
- }
- if ( isset( $this->props['size'] ) ) {
- $vals["{$prefix}size"] = $rev->getSize();
- }
- $anyHidden = false;
- if ( $rev->isDeleted( RevisionRecord::DELETED_TEXT ) ) {
- $vals["{$prefix}texthidden"] = true;
- $anyHidden = true;
- }
- if ( $rev->isDeleted( RevisionRecord::DELETED_USER ) ) {
- $vals["{$prefix}userhidden"] = true;
- $anyHidden = true;
- }
- if ( isset( $this->props['user'] ) ) {
- $user = $rev->getUser( RevisionRecord::FOR_THIS_USER, $this->getUser() );
- if ( $user ) {
- $vals["{$prefix}user"] = $user->getName();
- $vals["{$prefix}userid"] = $user->getId();
- }
- }
- if ( $rev->isDeleted( RevisionRecord::DELETED_COMMENT ) ) {
- $vals["{$prefix}commenthidden"] = true;
- $anyHidden = true;
- }
- if ( isset( $this->props['comment'] ) || isset( $this->props['parsedcomment'] ) ) {
- $comment = $rev->getComment( RevisionRecord::FOR_THIS_USER, $this->getUser() );
- if ( $comment !== null ) {
- if ( isset( $this->props['comment'] ) ) {
- $vals["{$prefix}comment"] = $comment->text;
- }
- $vals["{$prefix}parsedcomment"] = Linker::formatComment(
- $comment->text, $title
- );
- }
- }
- if ( $anyHidden ) {
- $this->getMain()->setCacheMode( 'private' );
- if ( $rev->isDeleted( RevisionRecord::DELETED_RESTRICTED ) ) {
- $vals["{$prefix}suppressed"] = true;
- }
- }
- // @phan-suppress-next-line PhanUndeclaredProperty
- if ( !empty( $rev->isArchive ) ) {
- $this->getMain()->setCacheMode( 'private' );
- $vals["{$prefix}archive"] = true;
- }
- }
- }
- public function getAllowedParams() {
- $slotRoles = $this->slotRoleRegistry->getKnownRoles();
- sort( $slotRoles, SORT_STRING );
- // Parameters for the 'from' and 'to' content
- $fromToParams = [
- 'title' => null,
- 'id' => [
- ApiBase::PARAM_TYPE => 'integer'
- ],
- 'rev' => [
- ApiBase::PARAM_TYPE => 'integer'
- ],
- 'slots' => [
- ApiBase::PARAM_TYPE => $slotRoles,
- ApiBase::PARAM_ISMULTI => true,
- ],
- 'text-{slot}' => [
- ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
- ApiBase::PARAM_TYPE => 'text',
- ],
- 'section-{slot}' => [
- ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
- ApiBase::PARAM_TYPE => 'string',
- ],
- 'contentformat-{slot}' => [
- ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
- ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
- ],
- 'contentmodel-{slot}' => [
- ApiBase::PARAM_TEMPLATE_VARS => [ 'slot' => 'slots' ], // fixed below
- ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
- ],
- 'pst' => false,
- 'text' => [
- ApiBase::PARAM_TYPE => 'text',
- ApiBase::PARAM_DEPRECATED => true,
- ],
- 'contentformat' => [
- ApiBase::PARAM_TYPE => ContentHandler::getAllContentFormats(),
- ApiBase::PARAM_DEPRECATED => true,
- ],
- 'contentmodel' => [
- ApiBase::PARAM_TYPE => ContentHandler::getContentModels(),
- ApiBase::PARAM_DEPRECATED => true,
- ],
- 'section' => [
- ApiBase::PARAM_DFLT => null,
- ApiBase::PARAM_DEPRECATED => true,
- ],
- ];
- $ret = [];
- foreach ( $fromToParams as $k => $v ) {
- if ( isset( $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] ) ) {
- $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] = 'fromslots';
- }
- $ret["from$k"] = $v;
- }
- foreach ( $fromToParams as $k => $v ) {
- if ( isset( $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] ) ) {
- $v[ApiBase::PARAM_TEMPLATE_VARS]['slot'] = 'toslots';
- }
- $ret["to$k"] = $v;
- }
- $ret = wfArrayInsertAfter(
- $ret,
- [ 'torelative' => [ ApiBase::PARAM_TYPE => [ 'prev', 'next', 'cur' ], ] ],
- 'torev'
- );
- $ret['prop'] = [
- ApiBase::PARAM_DFLT => 'diff|ids|title',
- ApiBase::PARAM_TYPE => [
- 'diff',
- 'diffsize',
- 'rel',
- 'ids',
- 'title',
- 'user',
- 'comment',
- 'parsedcomment',
- 'size',
- ],
- ApiBase::PARAM_ISMULTI => true,
- ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
- ];
- $ret['slots'] = [
- ApiBase::PARAM_TYPE => $slotRoles,
- ApiBase::PARAM_ISMULTI => true,
- ApiBase::PARAM_ALL => true,
- ];
- return $ret;
- }
- protected function getExamplesMessages() {
- return [
- 'action=compare&fromrev=1&torev=2'
- => 'apihelp-compare-example-1',
- ];
- }
- }
|