mediawiki-extensions-Discus.../includes/ApiDiscussionToolsCompare.php
Ed Sanders aa03dc971e Add discussiontoolscompare API
For two given revisions, this API tells us which comments have
been added and which have been removed.

Can be used to highlight new comments, or check if the page
has been updated since we first loaded it.

Bug: T281624
Bug: T300504
Change-Id: Ia4d95ffe3b7cf2317cd8e7c0f034e09f64777ef3
2022-02-08 15:53:27 +00:00

156 lines
3.9 KiB
PHP

<?php
namespace MediaWiki\Extension\DiscussionTools;
use ApiBase;
use ApiMain;
use ApiParsoidTrait;
use MediaWiki\Revision\RevisionRecord;
use Title;
use Wikimedia\ParamValidator\ParamValidator;
class ApiDiscussionToolsCompare extends ApiBase {
use ApiDiscussionToolsTrait;
use ApiParsoidTrait;
/**
* @inheritDoc
*/
public function __construct( ApiMain $main, string $name ) {
parent::__construct( $main, $name );
}
/**
* @inheritDoc
*/
public function execute() {
$params = $this->extractRequestParams();
$this->requireOnlyOneParameter( $params, 'fromtitle', 'fromrev' );
$this->requireOnlyOneParameter( $params, 'totitle', 'torev' );
if ( $params['torev'] ) {
$toRev = $this->getValidRevision( null, $params['torev'] ?? null );
} else {
$toTitle = Title::newFromText( $params['totitle'] );
if ( !$toTitle ) {
$this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['totitle'] ) ] );
}
$toRev = $this->getValidRevision( $toTitle );
}
// When polling for new comments this is an important optimisation,
// as usually there is no new revision.
if ( $toRev->getId() === $params['fromrev'] ) {
$this->addResult( $toRev, $toRev );
return;
}
if ( $params['fromrev'] ) {
$fromRev = $this->getValidRevision( null, $params['fromrev'] ?? null );
} else {
$fromTitle = Title::newFromText( $params['fromtitle'] );
if ( !$fromTitle ) {
$this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['fromtitle'] ) ] );
}
$fromRev = $this->getValidRevision( $fromTitle );
}
if ( $fromRev->hasSameContent( $toRev ) ) {
$this->addResult( $fromRev, $toRev );
return;
}
$fromParser = $this->parseRevision( $fromRev );
$toParser = $this->parseRevision( $toRev );
$removedComments = [];
foreach ( $fromParser->getCommentItems() as $fromComment ) {
if ( !$toParser->findCommentById( $fromComment->getId() ) ) {
$removedComments[] = $fromComment->jsonSerializeForDiff();
}
}
$addedComments = [];
foreach ( $toParser->getCommentItems() as $toComment ) {
if ( !$fromParser->findCommentById( $toComment->getId() ) ) {
$addedComments[] = $toComment->jsonSerializeForDiff();
}
}
$this->addResult( $fromRev, $toRev, $removedComments, $addedComments );
}
/**
* Add the result object from revisions and comment lists
*
* @param RevisionRecord $fromRev From revision
* @param RevisionRecord $toRev To revision
* @param array $removedComments Removed comments
* @param array $addedComments Added comments
*/
protected function addResult(
RevisionRecord $fromRev, RevisionRecord $toRev, array $removedComments = [], array $addedComments = []
) {
$fromTitle = Title::newFromLinkTarget(
$fromRev->getPageAsLinkTarget()
);
$toTitle = Title::newFromLinkTarget(
$toRev->getPageAsLinkTarget()
);
$result = [
'fromrevid' => $fromRev->getId(),
'fromtitle' => $fromTitle->getPrefixedText(),
'torevid' => $toRev->getId(),
'totitle' => $toTitle->getPrefixedText(),
'removedcomments' => $removedComments,
'addedcomments' => $addedComments,
];
$this->getResult()->addValue( null, $this->getModuleName(), $result );
}
/**
* @inheritDoc
*/
public function getAllowedParams() {
return [
'fromtitle' => [
ApiBase::PARAM_HELP_MSG => 'apihelp-compare-param-fromtitle',
],
'fromrev' => [
ParamValidator::PARAM_TYPE => 'integer',
ApiBase::PARAM_HELP_MSG => 'apihelp-compare-param-fromrev',
],
'totitle' => [
ApiBase::PARAM_HELP_MSG => 'apihelp-compare-param-totitle',
],
'torev' => [
ParamValidator::PARAM_TYPE => 'integer',
ApiBase::PARAM_HELP_MSG => 'apihelp-compare-param-torev',
],
];
}
/**
* @inheritDoc
*/
public function needsToken() {
return false;
}
/**
* @inheritDoc
*/
public function isInternal() {
return true;
}
/**
* @inheritDoc
*/
public function isWriteMode() {
return false;
}
}