Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiDiscussionToolsTrait
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 2
182
0.00% covered (danger)
0.00%
0 / 1
 previewMessage
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
156
 getParsoidClient
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 requestRestbasePageHtml
n/a
0 / 0
n/a
0 / 0
0
 transformHTML
n/a
0 / 0
n/a
0 / 0
0
 getContext
n/a
0 / 0
n/a
0 / 0
0
1<?php
2
3namespace MediaWiki\Extension\DiscussionTools;
4
5use ApiMain;
6use ApiResult;
7use DerivativeContext;
8use DerivativeRequest;
9use IContextSource;
10use MediaWiki\Extension\VisualEditor\ParsoidClient;
11use MediaWiki\Extension\VisualEditor\VisualEditorParsoidClientFactory;
12use MediaWiki\Revision\RevisionRecord;
13use Title;
14use Wikimedia\Parsoid\Utils\DOMCompat;
15use Wikimedia\Parsoid\Utils\DOMUtils;
16
17/**
18 * Random methods we want to share between API modules.
19 *
20 * @property VisualEditorParsoidClientFactory $parsoidClientFactory
21 * @property CommentParser $commentParser
22 */
23trait ApiDiscussionToolsTrait {
24
25    /**
26     * Given parameters describing a reply or new topic, transform them into wikitext using Parsoid,
27     * then preview the wikitext using the legacy parser.
28     *
29     * @param string $type 'topic' or 'reply'
30     * @param Title $title Context title for wikitext transformations
31     * @param array $params Associative array with the following keys:
32     *  - `wikitext` (string|null) Content of the message, mutually exclusive with `html`
33     *  - `html` (string|null) Content of the message, mutually exclusive with `wikitext`
34     *  - `sectiontitle` (string) Content of the title, when `type` is 'topic'
35     *  - `signature` (string|null) Wikitext signature to add to the message
36     * @param array $originalParams Original params from the source API call
37     * @return ApiResult action=parse API result
38     */
39    protected function previewMessage(
40        string $type, Title $title, array $params, array $originalParams = []
41    ): ApiResult {
42        $wikitext = $params['wikitext'] ?? null;
43        $html = $params['html'] ?? null;
44        $signature = $params['signature'] ?? null;
45
46        switch ( $type ) {
47            case 'topic':
48                if ( $wikitext !== null ) {
49                    if ( $signature !== null ) {
50                        $wikitext = CommentModifier::appendSignatureWikitext( $wikitext, $signature );
51                    }
52                } else {
53                    $doc = DOMUtils::parseHTML( '' );
54                    $container = DOMUtils::parseHTMLToFragment( $doc, $html );
55                    if ( $signature !== null ) {
56                        CommentModifier::appendSignature( $container, $signature );
57                    }
58                    $html = DOMUtils::getFragmentInnerHTML( $container );
59                    $wikitext = $this->transformHTML( $title, $html )[ 'body' ];
60                }
61
62                if ( $params['sectiontitle'] ) {
63                    $wikitext = "== " . $params['sectiontitle'] . " ==\n" . $wikitext;
64                }
65
66                break;
67
68            case 'reply':
69                $doc = DOMUtils::parseHTML( '' );
70
71                if ( $wikitext !== null ) {
72                    $container = CommentModifier::prepareWikitextReply( $doc, $wikitext );
73                } else {
74                    $container = CommentModifier::prepareHtmlReply( $doc, $html );
75                }
76
77                if ( $signature !== null ) {
78                    CommentModifier::appendSignature( $container, $signature );
79                }
80                $list = CommentModifier::transferReply( $container );
81                $html = DOMCompat::getOuterHTML( $list );
82
83                $wikitext = $this->transformHTML( $title, $html )[ 'body' ];
84
85                break;
86        }
87
88        $apiParams = [
89            'action' => 'parse',
90            'title' => $title->getPrefixedText(),
91            'text' => $wikitext,
92            'pst' => '1',
93            'preview' => '1',
94            'disableeditsection' => '1',
95            'prop' => 'text|modules|jsconfigvars',
96        ];
97        if ( isset( $originalParams['useskin'] ) ) {
98            $apiParams['useskin'] = $originalParams['useskin'];
99        }
100        if ( isset( $originalParams['mobileformat'] ) && $originalParams['mobileformat'] ) {
101            $apiParams['mobileformat'] = '1';
102        }
103
104        $context = new DerivativeContext( $this->getContext() );
105        $context->setRequest(
106            new DerivativeRequest(
107                $context->getRequest(),
108                $apiParams,
109                /* was posted? */ true
110            )
111        );
112        $api = new ApiMain(
113            $context,
114            /* enable write? */ false
115        );
116
117        $api->execute();
118        return $api->getResult();
119    }
120
121    /**
122     * @see VisualEditorParsoidClientFactory
123     * @return ParsoidClient
124     */
125    protected function getParsoidClient(): ParsoidClient {
126        return $this->parsoidClientFactory->createParsoidClient(
127            $this->getContext()->getRequest()->getHeader( 'Cookie' )
128        );
129    }
130
131    /**
132     * @warning (T323357) - Calling this method writes to stash, so it should be called
133     *   only when we are fetching page HTML for editing.
134     *
135     * @param RevisionRecord $revision
136     * @return array
137     */
138    abstract protected function requestRestbasePageHtml( RevisionRecord $revision ): array;
139
140    /**
141     * @param Title $title
142     * @param string $html
143     * @param int|null $oldid
144     * @param string|null $etag
145     * @return array
146     */
147    abstract protected function transformHTML(
148        Title $title, string $html, int $oldid = null, string $etag = null
149    ): array;
150
151    /**
152     * @return IContextSource
153     */
154    abstract public function getContext();
155
156}