mediawiki-extensions-Discus.../includes/ApiDiscussionToolsPreview.php
Bartosz Dziewoński 0ecc8a4c05 Improve detecting already signed comments
Previously, we required a signature at the end of the comment.
This was a pretty rough heuristic that did not correctly handle
many comments that we would consider entirely properly signed
in CommentParser (e.g. comments wrapped in formatting like
<small>…</small>, comments with a post-scriptum or in parentheses,
or comments generated by various templates).

Now we process the user input using the same code that adds reply
links, and only add a signature when we detect that there really
isn't a signature (including template-generated), or if the signature
is in the wrong place and would result in the reply link showing up
in the wrong place as well (not at the end of the comment).

Bug: T278442
Bug: T268558
Bug: T278355
Bug: T291421
Bug: T282983
Change-Id: I46b6110af328ebdf93b7dfc2bd941e04391a1599
2022-02-21 21:21:26 +00:00

118 lines
3.2 KiB
PHP

<?php
namespace MediaWiki\Extension\DiscussionTools;
use ApiBase;
use ApiMain;
use ApiParsoidTrait;
use Title;
use Wikimedia\ParamValidator\ParamValidator;
use Wikimedia\Parsoid\Utils\DOMCompat;
use Wikimedia\Parsoid\Utils\DOMUtils;
class ApiDiscussionToolsPreview extends ApiBase {
use ApiDiscussionToolsTrait;
use ApiParsoidTrait;
/** @var CommentParser */
private $commentParser;
/**
* @param ApiMain $main
* @param string $name
* @param CommentParser $commentParser
*/
public function __construct(
ApiMain $main,
$name,
CommentParser $commentParser
) {
parent::__construct( $main, $name );
$this->commentParser = $commentParser;
}
/**
* @inheritDoc
*/
public function execute() {
$params = $this->extractRequestParams();
$title = Title::newFromText( $params['page'] );
if ( !$title ) {
$this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['page'] ) ] );
}
if ( $params['type'] === 'topic' ) {
$this->requireAtLeastOneParameter( $params, 'sectiontitle' );
}
// Try without adding a signature
$result = $this->previewMessage( [
'type' => $params['type'],
'title' => $title,
'wikitext' => $params['wikitext'],
'sectiontitle' => $params['sectiontitle'],
] );
$resultHtml = $result->getResultData( [ 'parse', 'text' ] );
// Check if there was a signature in a proper place
$container = DOMCompat::getBody( DOMUtils::parseHTML( $resultHtml ) );
$threadItemSet = $this->commentParser->parse( $container, $title );
if ( !CommentUtils::isSingleCommentSignedBy( $threadItemSet, $this->getUser()->getName(), $container ) ) {
// If not, add the signature and re-render
$signature = $this->msg( 'discussiontools-signature-prefix' )->inContentLanguage()->text() . '~~~~';
// Drop opacity of signature in preview to make message body preview clearer.
// Extract any leading spaces outside the <span> markup to ensure accurate previews.
$signature = preg_replace_callback( '/^( *)(.+)$/', static function ( $matches ) {
list( , $leadingSpaces, $sig ) = $matches;
return $leadingSpaces . '<span style="opacity: 0.6;">' . $sig . '</span>';
}, $signature );
$result = $this->previewMessage( [
'type' => $params['type'],
'title' => $title,
'wikitext' => $params['wikitext'],
'sectiontitle' => $params['sectiontitle'],
'signature' => $signature,
] );
}
$this->getResult()->addValue( null, $this->getModuleName(), $result->serializeForApiResult() );
}
/**
* @inheritDoc
*/
public function getAllowedParams() {
return [
'type' => [
ParamValidator::PARAM_REQUIRED => true,
ParamValidator::PARAM_TYPE => [
'reply',
'topic',
],
ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
],
'page' => [
ParamValidator::PARAM_REQUIRED => true,
ApiBase::PARAM_HELP_MSG => 'apihelp-visualeditoredit-param-page',
],
'wikitext' => [
ParamValidator::PARAM_REQUIRED => true,
ParamValidator::PARAM_TYPE => 'text',
],
'sectiontitle' => [
ParamValidator::PARAM_TYPE => 'string',
ApiBase::PARAM_HELP_MSG => 'apihelp-edit-param-sectiontitle',
],
];
}
/**
* @inheritDoc
*/
public function isInternal() {
return true;
}
}