Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.86% covered (success)
98.86%
173 / 175
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImportPreviewPage
98.86% covered (success)
98.86%
173 / 175
83.33% covered (warning)
83.33%
5 / 6
13
0.00% covered (danger)
0.00%
0 / 1
 getHtml
98.33% covered (success)
98.33%
118 / 120
0.00% covered (danger)
0.00%
0 / 1
3
 buildShowChangesButtonHtml
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 buildEditSummaryHtml
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
5
 buildImportIdentityFormSnippet
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 buildCategoriesSnippet
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 wasEdited
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace FileImporter\Html;
4
5use FileImporter\Data\ImportPlan;
6use FileImporter\Services\CategoryExtractor;
7use MediaWiki\EditPage\EditPage;
8use MediaWiki\Html\Html;
9use MediaWiki\Linker\Linker;
10use MediaWiki\MediaWikiServices;
11use MediaWiki\Registration\ExtensionRegistry;
12use OOUI\ButtonInputWidget;
13use OOUI\ButtonWidget;
14use OOUI\TextInputWidget;
15
16/**
17 * Page displaying the preview of the import before it has happened.
18 *
19 * @license GPL-2.0-or-later
20 * @author Addshore
21 */
22class ImportPreviewPage extends SpecialPageHtmlFragment {
23
24    public const ACTION_BUTTON = 'action';
25    public const ACTION_EDIT_TITLE = 'edittitle';
26    public const ACTION_EDIT_INFO = 'editinfo';
27    public const ACTION_SUBMIT = 'submit';
28    public const ACTION_VIEW_DIFF = 'viewdiff';
29
30    public function getHtml( ImportPlan $importPlan ): string {
31        // TODO: Inject
32        if ( ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) {
33            $config = $this->getContext()->getConfig();
34            $sourceEditingEnabled = $config->get( 'FileImporterSourceWikiTemplating' );
35            $sourceDeletionEnabled = $config->get( 'FileImporterSourceWikiDeletion' );
36        } else {
37            $sourceEditingEnabled = false;
38            $sourceDeletionEnabled = false;
39        }
40
41        $text = $importPlan->getFileInfoText();
42        $title = $importPlan->getTitle();
43
44        $details = $importPlan->getDetails();
45        $textRevisionsCount = count( $details->getTextRevisions()->toArray() );
46        $fileRevisionsCount = count( $details->getFileRevisions()->toArray() );
47        $categoriesSnippet = $this->buildCategoriesSnippet( $importPlan );
48
49        return Html::openElement(
50            'form',
51            [
52                'action' => $this->getPageTitle()->getLocalURL(),
53                'method' => 'POST',
54            ]
55        ) .
56        Html::hidden( 'wpUnicodeCheck', EditPage::UNICODE_CHECK ) .
57        ( new HelpBanner( $this ) )->getHtml() .
58        $this->msg( 'fileimporter-previewnote' )->parseAsBlock() .
59        Html::rawElement(
60            'div',
61            [ 'class' => 'mw-importfile-header' ],
62            Html::element(
63                'h2',
64                [],
65                $title->getText()
66            ) .
67            new ButtonInputWidget(
68                [
69                    'classes' => [ 'mw-importfile-rightAlign' ],
70                    'label' => $this->msg( 'fileimporter-edittitle' )->plain(),
71                    'type' => 'submit',
72                    'name' => self::ACTION_BUTTON,
73                    'value' => self::ACTION_EDIT_TITLE
74                ]
75            )
76        ) .
77        Linker::makeExternalImage( $details->getImageDisplayUrl(), $title->getPrefixedText() ) .
78        Html::rawElement(
79            'div',
80            [ 'class' => 'mw-importfile-header' ],
81            Html::element(
82                'h2',
83                [],
84                $this->msg( 'fileimporter-heading-fileinfo' )->plain()
85            ) .
86            new ButtonInputWidget(
87                [
88                    'classes' => [ 'mw-importfile-rightAlign' ],
89                    'label' => $this->msg( 'fileimporter-editinfo' )->plain(),
90                    'type' => 'submit',
91                    'name' => self::ACTION_BUTTON,
92                    'value' => self::ACTION_EDIT_INFO
93                ]
94            )
95        ) .
96        Html::rawElement(
97            'div',
98            [ 'class' => 'mw-importfile-parsedContent' ],
99            ( new TextRevisionSnippet( $this ) )->getHtml(
100                $details->getTextRevisions()->getLatest(),
101                $text
102            )
103        ) .
104        $categoriesSnippet .
105        Html::element( 'h2', [], $this->msg( 'fileimporter-heading-filehistory' )->plain() ) .
106        $this->msg(
107            'fileimporter-filerevisions',
108            [
109                $fileRevisionsCount,
110                $fileRevisionsCount,
111            ]
112        )->parseAsBlock() .
113        ( new SourceWikiCleanupSnippet(
114            $sourceEditingEnabled,
115            $sourceDeletionEnabled
116        ) )->getHtml( $importPlan, $this->getUser() ) .
117        Html::openElement( 'div', [ 'class' => 'mw-importfile-importOptions' ] ) .
118        $this->buildEditSummaryHtml( $importPlan ) .
119        $this->msg(
120            'fileimporter-textrevisions',
121            [
122                $textRevisionsCount,
123                $textRevisionsCount,
124            ]
125        )->parseAsBlock() .
126        Html::element(
127            'input',
128            [
129                'type' => 'hidden',
130                'name' => 'token',
131                'value' => $this->getUser()->getEditToken()
132            ]
133        ) .
134        new ButtonInputWidget(
135            [
136                'classes' => [ 'mw-importfile-import-submit' ],
137                'label' => $this->msg( 'fileimporter-import' )->plain(),
138                'type' => 'submit',
139                'flags' => [ 'primary', 'progressive' ],
140                'name' => self::ACTION_BUTTON,
141                'value' => self::ACTION_SUBMIT,
142                'infusable' => true
143            ]
144        ) .
145        ( $this->wasEdited( $importPlan ) ? $this->buildShowChangesButtonHtml() : '' ) .
146        new ButtonWidget(
147            [
148                'classes' => [ 'mw-importfile-import-cancel' ],
149                'label' => $this->msg( 'fileimporter-cancel' )->plain(),
150                'href' => $importPlan->getRequest()->getUrl()->getUrl()
151            ]
152        ) .
153        Html::element( 'span', [], $this->msg( 'fileimporter-import-wait' )->plain() ) .
154        $this->buildImportIdentityFormSnippet( $importPlan ) .
155        // End of mw-importfile-importOptions
156        Html::closeElement( 'div' ) .
157        Html::closeElement( 'form' );
158    }
159
160    private function buildShowChangesButtonHtml() {
161        return new ButtonInputWidget(
162            [
163                'classes' => [ 'mw-importfile-import-diff' ],
164                'label' => $this->msg( 'fileimporter-viewdiff' )->plain(),
165                'name' => self::ACTION_BUTTON,
166                'value' => self::ACTION_VIEW_DIFF,
167                'type' => 'submit',
168            ]
169        );
170    }
171
172    /**
173     * @return string
174     */
175    private function buildEditSummaryHtml( ImportPlan $importPlan ) {
176        $summary = $importPlan->getRequest()->getIntendedSummary();
177        if ( $summary === null ) {
178            $replacements = $importPlan->getNumberOfTemplateReplacements();
179            $summary = $replacements > 0
180                ? $this->msg(
181                    'fileimporter-auto-replacements-summary',
182                    $replacements
183                )->inContentLanguage()->text()
184                : null;
185        }
186        if ( $summary === null
187            && !$this->wasEdited( $importPlan )
188        ) {
189            return '';
190        }
191
192        return Html::element(
193            'p',
194            [],
195            $this->msg( 'fileimporter-editsummary' )->plain()
196        ) .
197        new TextInputWidget(
198            [
199                'name' => 'intendedRevisionSummary',
200                'classes' => [ 'mw-importfile-import-summary' ],
201                'value' => $summary,
202                'infusable' => true
203            ]
204        );
205    }
206
207    /**
208     * @return string
209     */
210    private function buildImportIdentityFormSnippet( ImportPlan $importPlan ) {
211        return ( new ImportIdentityFormSnippet( [
212            'clientUrl' => $importPlan->getRequest()->getUrl(),
213            'intendedFileName' => $importPlan->getFileName(),
214            'intendedWikitext' => $importPlan->getFileInfoText(),
215            'actionStats' => json_encode( $importPlan->getActionStats() ),
216            'validationWarnings' => json_encode( $importPlan->getValidationWarnings() ),
217            'importDetailsHash' => $importPlan->getDetails()->getOriginalHash(),
218        ] ) )->getHtml();
219    }
220
221    /**
222     * @return string HTML snippet for a box showing the categories, or empty string if there are
223     * no categories.
224     */
225    private function buildCategoriesSnippet( ImportPlan $importPlan ) {
226        /** @var CategoryExtractor $categoryExtractor */
227        $categoryExtractor = MediaWikiServices::getInstance()
228            ->getService( 'FileImporterCategoryExtractor' );
229        [ $visibleCategories, $hiddenCategories ] = $categoryExtractor->getCategoriesGrouped(
230            $importPlan->getFileInfoText(),
231            $importPlan->getTitle(),
232            $this->getUser()
233        );
234        return ( new CategoriesSnippet(
235            $visibleCategories,
236            $hiddenCategories
237        ) )->getHtml();
238    }
239
240    /**
241     * @return bool
242     */
243    private function wasEdited( ImportPlan $importPlan ) {
244        return $importPlan->wasFileInfoTextChanged() ||
245            $importPlan->getNumberOfTemplateReplacements() > 0;
246    }
247
248}