Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
63.64% covered (warning)
63.64%
63 / 99
55.56% covered (warning)
55.56%
5 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiImport
64.29% covered (warning)
64.29%
63 / 98
55.56% covered (warning)
55.56%
5 / 9
53.47
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 execute
53.70% covered (warning)
53.70%
29 / 54
0.00% covered (danger)
0.00%
0 / 1
33.45
 getAllowedImportSources
55.56% covered (warning)
55.56%
5 / 9
0.00% covered (danger)
0.00%
0 / 1
5.40
 mustBePosted
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isWriteMode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getAllowedParams
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
1
 needsToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 getHelpUrls
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Copyright © 2009 Roan Kattouw <roan.kattouw@gmail.com>
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 */
8
9namespace MediaWiki\Api;
10
11use Exception;
12use MediaWiki\ChangeTags\ChangeTags;
13use MediaWiki\Import\ImportStreamSource;
14use MediaWiki\Import\WikiImporterFactory;
15use MediaWiki\MainConfigNames;
16use Wikimedia\ParamValidator\ParamValidator;
17
18/**
19 * API module that imports an XML file like Special:Import does
20 *
21 * @ingroup API
22 */
23class ApiImport extends ApiBase {
24
25    private WikiImporterFactory $wikiImporterFactory;
26
27    public function __construct(
28        ApiMain $main,
29        string $action,
30        WikiImporterFactory $wikiImporterFactory
31    ) {
32        parent::__construct( $main, $action );
33
34        $this->wikiImporterFactory = $wikiImporterFactory;
35    }
36
37    public function execute() {
38        $this->useTransactionalTimeLimit();
39        $params = $this->extractRequestParams();
40
41        $this->requireMaxOneParameter( $params, 'namespace', 'rootpage' );
42
43        $isUpload = false;
44        if ( isset( $params['interwikisource'] ) ) {
45            if ( !$this->getAuthority()->isAllowed( 'import' ) ) {
46                $this->dieWithError( 'apierror-cantimport' );
47            }
48            if ( !isset( $params['interwikipage'] ) ) {
49                $this->dieWithError( [ 'apierror-missingparam', 'interwikipage' ] );
50            }
51            $source = ImportStreamSource::newFromInterwiki(
52                $params['interwikisource'],
53                $params['interwikipage'],
54                $params['fullhistory'],
55                $params['templates']
56            );
57            $usernamePrefix = $params['interwikisource'];
58        } else {
59            $isUpload = true;
60            if ( !$this->getAuthority()->isAllowed( 'importupload' ) ) {
61                $this->dieWithError( 'apierror-cantimport-upload' );
62            }
63            $source = ImportStreamSource::newFromUpload( 'xml' );
64            $usernamePrefix = (string)$params['interwikiprefix'];
65            if ( $usernamePrefix === '' ) {
66                $encParamName = $this->encodeParamName( 'interwikiprefix' );
67                $this->dieWithError( [ 'apierror-missingparam', $encParamName ] );
68            }
69        }
70        if ( !$source->isOK() ) {
71            $this->dieStatus( $source );
72        }
73
74        // Check if user can add the log entry tags which were requested
75        if ( $params['tags'] ) {
76            $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $this->getAuthority() );
77            if ( !$ableToTag->isOK() ) {
78                $this->dieStatus( $ableToTag );
79            }
80        }
81
82        $importer = $this->wikiImporterFactory->getWikiImporter( $source->value, $this->getAuthority() );
83        if ( isset( $params['namespace'] ) ) {
84            $importer->setTargetNamespace( $params['namespace'] );
85        } elseif ( isset( $params['rootpage'] ) ) {
86            $statusRootPage = $importer->setTargetRootPage( $params['rootpage'] );
87            if ( !$statusRootPage->isGood() ) {
88                $this->dieStatus( $statusRootPage );
89            }
90        }
91        $importer->setUsernamePrefix( $usernamePrefix, $params['assignknownusers'] );
92        $reporter = new ApiImportReporter(
93            $importer,
94            $isUpload,
95            $params['interwikisource'],
96            $params['summary'],
97            $this
98        );
99        if ( $params['tags'] ) {
100            $reporter->setChangeTags( $params['tags'] );
101        }
102
103        try {
104            $importer->doImport();
105        } catch ( Exception $e ) {
106            $this->dieWithException( $e, [ 'wrap' => 'apierror-import-unknownerror' ] );
107        }
108
109        $resultData = $reporter->getData();
110        $result = $this->getResult();
111        ApiResult::setIndexedTagName( $resultData, 'page' );
112        $result->addValue( null, $this->getModuleName(), $resultData );
113    }
114
115    /**
116     * Returns a list of interwiki prefixes corresponding to each defined import
117     * source.
118     *
119     * @return array
120     * @since 1.27
121     */
122    public function getAllowedImportSources() {
123        $importSources = $this->getConfig()->get( MainConfigNames::ImportSources );
124        $this->getHookRunner()->onImportSources( $importSources );
125
126        $result = [];
127        foreach ( $importSources as $key => $value ) {
128            if ( is_int( $key ) ) {
129                $result[] = $value;
130            } else {
131                foreach ( $value as $subproject ) {
132                    $result[] = "$key:$subproject";
133                }
134            }
135        }
136        return $result;
137    }
138
139    /** @inheritDoc */
140    public function mustBePosted() {
141        return true;
142    }
143
144    /** @inheritDoc */
145    public function isWriteMode() {
146        return true;
147    }
148
149    /** @inheritDoc */
150    public function getAllowedParams() {
151        return [
152            'summary' => null,
153            'xml' => [
154                ParamValidator::PARAM_TYPE => 'upload',
155            ],
156            'interwikiprefix' => [
157                ParamValidator::PARAM_TYPE => 'string',
158            ],
159            'interwikisource' => [
160                ParamValidator::PARAM_TYPE => $this->getAllowedImportSources(),
161            ],
162            'interwikipage' => null,
163            'fullhistory' => false,
164            'templates' => false,
165            'namespace' => [
166                ParamValidator::PARAM_TYPE => 'namespace'
167            ],
168            'assignknownusers' => false,
169            'rootpage' => null,
170            'tags' => [
171                ParamValidator::PARAM_TYPE => 'tags',
172                ParamValidator::PARAM_ISMULTI => true,
173            ],
174        ];
175    }
176
177    /** @inheritDoc */
178    public function needsToken() {
179        return 'csrf';
180    }
181
182    /** @inheritDoc */
183    protected function getExamplesMessages() {
184        return [
185            'action=import&interwikisource=meta&interwikipage=Help:ParserFunctions&' .
186                'namespace=100&fullhistory=&token=123ABC'
187                => 'apihelp-import-example-import',
188        ];
189    }
190
191    /** @inheritDoc */
192    public function getHelpUrls() {
193        return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Import';
194    }
195}
196
197/** @deprecated class alias since 1.43 */
198class_alias( ApiImport::class, 'ApiImport' );