Merge "Make ChronologyProtector actually use cpPosTime cookies"
[lhc/web/wiklou.git] / includes / api / ApiImport.php
1 <?php
2 /**
3 *
4 *
5 * Created on Feb 4, 2009
6 *
7 * Copyright © 2009 Roan Kattouw "<Firstname>.<Lastname>@gmail.com"
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 * http://www.gnu.org/copyleft/gpl.html
23 *
24 * @file
25 */
26
27 /**
28 * API module that imports an XML file like Special:Import does
29 *
30 * @ingroup API
31 */
32 class ApiImport extends ApiBase {
33
34 public function execute() {
35 $this->useTransactionalTimeLimit();
36
37 $user = $this->getUser();
38 $params = $this->extractRequestParams();
39
40 $this->requireMaxOneParameter( $params, 'namespace', 'rootpage' );
41
42 $isUpload = false;
43 if ( isset( $params['interwikisource'] ) ) {
44 if ( !$user->isAllowed( 'import' ) ) {
45 $this->dieWithError( 'apierror-cantimport' );
46 }
47 if ( !isset( $params['interwikipage'] ) ) {
48 $this->dieWithError( [ 'apierror-missingparam', 'interwikipage' ] );
49 }
50 $source = ImportStreamSource::newFromInterwiki(
51 $params['interwikisource'],
52 $params['interwikipage'],
53 $params['fullhistory'],
54 $params['templates']
55 );
56 $usernamePrefix = $params['interwikisource'];
57 } else {
58 $isUpload = true;
59 if ( !$user->isAllowed( 'importupload' ) ) {
60 $this->dieWithError( 'apierror-cantimport-upload' );
61 }
62 $source = ImportStreamSource::newFromUpload( 'xml' );
63 $usernamePrefix = (string)$params['interwikiprefix'];
64 if ( $usernamePrefix === '' ) {
65 $encParamName = $this->encodeParamName( 'interwikiprefix' );
66 $this->dieWithError( [ 'apierror-missingparam', $encParamName ] );
67 }
68 }
69 if ( !$source->isOK() ) {
70 $this->dieStatus( $source );
71 }
72
73 // Check if user can add the log entry tags which were requested
74 if ( $params['tags'] ) {
75 $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user );
76 if ( !$ableToTag->isOK() ) {
77 $this->dieStatus( $ableToTag );
78 }
79 }
80
81 $importer = new WikiImporter( $source->value, $this->getConfig() );
82 if ( isset( $params['namespace'] ) ) {
83 $importer->setTargetNamespace( $params['namespace'] );
84 } elseif ( isset( $params['rootpage'] ) ) {
85 $statusRootPage = $importer->setTargetRootPage( $params['rootpage'] );
86 if ( !$statusRootPage->isGood() ) {
87 $this->dieStatus( $statusRootPage );
88 }
89 }
90 $importer->setUsernamePrefix( $usernamePrefix, $params['assignknownusers'] );
91 $reporter = new ApiImportReporter(
92 $importer,
93 $isUpload,
94 $params['interwikisource'],
95 $params['summary']
96 );
97 if ( $params['tags'] ) {
98 $reporter->setChangeTags( $params['tags'] );
99 }
100
101 try {
102 $importer->doImport();
103 } catch ( Exception $e ) {
104 $this->dieWithException( $e, [ 'wrap' => 'apierror-import-unknownerror' ] );
105 }
106
107 $resultData = $reporter->getData();
108 $result = $this->getResult();
109 ApiResult::setIndexedTagName( $resultData, 'page' );
110 $result->addValue( null, $this->getModuleName(), $resultData );
111 }
112
113 /**
114 * Returns a list of interwiki prefixes corresponding to each defined import
115 * source.
116 *
117 * @return array
118 * @since 1.27
119 */
120 public function getAllowedImportSources() {
121 $importSources = $this->getConfig()->get( 'ImportSources' );
122 Hooks::run( 'ImportSources', [ &$importSources ] );
123
124 $result = [];
125 foreach ( $importSources as $key => $value ) {
126 if ( is_int( $key ) ) {
127 $result[] = $value;
128 } else {
129 foreach ( $value as $subproject ) {
130 $result[] = "$key:$subproject";
131 }
132 }
133 }
134 return $result;
135 }
136
137 public function mustBePosted() {
138 return true;
139 }
140
141 public function isWriteMode() {
142 return true;
143 }
144
145 public function getAllowedParams() {
146 return [
147 'summary' => null,
148 'xml' => [
149 ApiBase::PARAM_TYPE => 'upload',
150 ],
151 'interwikiprefix' => [
152 ApiBase::PARAM_TYPE => 'string',
153 ],
154 'interwikisource' => [
155 ApiBase::PARAM_TYPE => $this->getAllowedImportSources(),
156 ],
157 'interwikipage' => null,
158 'fullhistory' => false,
159 'templates' => false,
160 'namespace' => [
161 ApiBase::PARAM_TYPE => 'namespace'
162 ],
163 'assignknownusers' => false,
164 'rootpage' => null,
165 'tags' => [
166 ApiBase::PARAM_TYPE => 'tags',
167 ApiBase::PARAM_ISMULTI => true,
168 ],
169 ];
170 }
171
172 public function needsToken() {
173 return 'csrf';
174 }
175
176 protected function getExamplesMessages() {
177 return [
178 'action=import&interwikisource=meta&interwikipage=Help:ParserFunctions&' .
179 'namespace=100&fullhistory=&token=123ABC'
180 => 'apihelp-import-example-import',
181 ];
182 }
183
184 public function getHelpUrls() {
185 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Import';
186 }
187 }
188
189 /**
190 * Import reporter for the API
191 * @ingroup API
192 */
193 class ApiImportReporter extends ImportReporter {
194 private $mResultArr = [];
195
196 /**
197 * @param Title $title
198 * @param Title $origTitle
199 * @param int $revisionCount
200 * @param int $successCount
201 * @param array $pageInfo
202 * @return void
203 */
204 public function reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo ) {
205 // Add a result entry
206 $r = [];
207
208 if ( $title === null ) {
209 # Invalid or non-importable title
210 $r['title'] = $pageInfo['title'];
211 $r['invalid'] = true;
212 } else {
213 ApiQueryBase::addTitleInfo( $r, $title );
214 $r['revisions'] = intval( $successCount );
215 }
216
217 $this->mResultArr[] = $r;
218
219 // Piggyback on the parent to do the logging
220 parent::reportPage( $title, $origTitle, $revisionCount, $successCount, $pageInfo );
221 }
222
223 public function getData() {
224 return $this->mResultArr;
225 }
226 }