Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiDiscussionToolsPreview
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 4
56
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
20
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isInternal
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace MediaWiki\Extension\DiscussionTools;
4
5use ApiBase;
6use ApiMain;
7use MediaWiki\Extension\VisualEditor\ApiParsoidTrait;
8use MediaWiki\Extension\VisualEditor\VisualEditorParsoidClientFactory;
9use SkinFactory;
10use Title;
11use Wikimedia\ParamValidator\ParamValidator;
12use Wikimedia\Parsoid\Utils\DOMCompat;
13use Wikimedia\Parsoid\Utils\DOMUtils;
14
15class ApiDiscussionToolsPreview extends ApiBase {
16    use ApiDiscussionToolsTrait;
17    use ApiParsoidTrait;
18
19    private CommentParser $commentParser;
20    private VisualEditorParsoidClientFactory $parsoidClientFactory;
21    private SkinFactory $skinFactory;
22
23    public function __construct(
24        ApiMain $main,
25        string $name,
26        VisualEditorParsoidClientFactory $parsoidClientFactory,
27        CommentParser $commentParser,
28        SkinFactory $skinFactory
29    ) {
30        parent::__construct( $main, $name );
31        $this->parsoidClientFactory = $parsoidClientFactory;
32        $this->commentParser = $commentParser;
33        $this->skinFactory = $skinFactory;
34    }
35
36    /**
37     * @inheritDoc
38     */
39    public function execute() {
40        $params = $this->extractRequestParams();
41        $title = Title::newFromText( $params['page'] );
42
43        if ( !$title ) {
44            $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['page'] ) ] );
45        }
46        if ( $params['type'] === 'topic' ) {
47            $this->requireAtLeastOneParameter( $params, 'sectiontitle' );
48        }
49
50        // Try without adding a signature
51        $result = $this->previewMessage(
52            $params['type'],
53            $title,
54            [
55                'wikitext' => $params['wikitext'],
56                'sectiontitle' => $params['sectiontitle']
57            ],
58            $params
59        );
60        $resultHtml = $result->getResultData( [ 'parse', 'text' ] );
61
62        // Check if there was a signature in a proper place
63        $container = DOMCompat::getBody( DOMUtils::parseHTML( $resultHtml ) );
64        $threadItemSet = $this->commentParser->parse( $container, $title->getTitleValue() );
65        if ( !CommentUtils::isSingleCommentSignedBy( $threadItemSet, $this->getUser()->getName(), $container ) ) {
66            // If not, add the signature and re-render
67            $signature = $this->msg( 'discussiontools-signature-prefix' )->inContentLanguage()->text() . '~~~~';
68            // Drop opacity of signature in preview to make message body preview clearer.
69            // Extract any leading spaces outside the <span> markup to ensure accurate previews.
70            $signature = preg_replace_callback( '/^( *)(.+)$/', static function ( $matches ) {
71                list( , $leadingSpaces, $sig ) = $matches;
72                return $leadingSpaces . '<span style="opacity: 0.6;">' . $sig . '</span>';
73            }, $signature );
74
75            $result = $this->previewMessage(
76                $params['type'],
77                $title,
78                [
79                    'wikitext' => $params['wikitext'],
80                    'sectiontitle' => $params['sectiontitle'],
81                    'signature' => $signature
82                ],
83                $params
84            );
85        }
86
87        $this->getResult()->addValue( null, $this->getModuleName(), $result->serializeForApiResult() );
88    }
89
90    /**
91     * @inheritDoc
92     */
93    public function getAllowedParams() {
94        return [
95            'type' => [
96                ParamValidator::PARAM_REQUIRED => true,
97                ParamValidator::PARAM_TYPE => [
98                    'reply',
99                    'topic',
100                ],
101                ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
102            ],
103            'page' => [
104                ParamValidator::PARAM_REQUIRED => true,
105                ApiBase::PARAM_HELP_MSG => 'apihelp-visualeditoredit-param-page',
106            ],
107            'wikitext' => [
108                ParamValidator::PARAM_REQUIRED => true,
109                ParamValidator::PARAM_TYPE => 'text',
110            ],
111            'sectiontitle' => [
112                ParamValidator::PARAM_TYPE => 'string',
113                ApiBase::PARAM_HELP_MSG => 'apihelp-edit-param-sectiontitle',
114            ],
115            'useskin' => [
116                ParamValidator::PARAM_TYPE => array_keys( $this->skinFactory->getInstalledSkins() ),
117                ApiBase::PARAM_HELP_MSG => 'apihelp-parse-param-useskin',
118            ],
119        ];
120    }
121
122    /**
123     * @inheritDoc
124     */
125    public function isInternal() {
126        return true;
127    }
128}