]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/api/ApiMove.php
MediaWiki 1.30.2-scripts2
[autoinstalls/mediawiki.git] / includes / api / ApiMove.php
1 <?php
2 /**
3  *
4  *
5  * Created on Oct 31, 2007
6  *
7  * Copyright © 2007 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 to move pages
29  * @ingroup API
30  */
31 class ApiMove extends ApiBase {
32
33         public function execute() {
34                 $this->useTransactionalTimeLimit();
35
36                 $user = $this->getUser();
37                 $params = $this->extractRequestParams();
38
39                 $this->requireOnlyOneParameter( $params, 'from', 'fromid' );
40
41                 if ( isset( $params['from'] ) ) {
42                         $fromTitle = Title::newFromText( $params['from'] );
43                         if ( !$fromTitle || $fromTitle->isExternal() ) {
44                                 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['from'] ) ] );
45                         }
46                 } elseif ( isset( $params['fromid'] ) ) {
47                         $fromTitle = Title::newFromID( $params['fromid'] );
48                         if ( !$fromTitle ) {
49                                 $this->dieWithError( [ 'apierror-nosuchpageid', $params['fromid'] ] );
50                         }
51                 }
52
53                 if ( !$fromTitle->exists() ) {
54                         $this->dieWithError( 'apierror-missingtitle' );
55                 }
56                 $fromTalk = $fromTitle->getTalkPage();
57
58                 $toTitle = Title::newFromText( $params['to'] );
59                 if ( !$toTitle || $toTitle->isExternal() ) {
60                         $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['to'] ) ] );
61                 }
62                 $toTalk = $toTitle->getTalkPageIfDefined();
63
64                 if ( $toTitle->getNamespace() == NS_FILE
65                         && !RepoGroup::singleton()->getLocalRepo()->findFile( $toTitle )
66                         && wfFindFile( $toTitle )
67                 ) {
68                         if ( !$params['ignorewarnings'] && $user->isAllowed( 'reupload-shared' ) ) {
69                                 $this->dieWithError( 'apierror-fileexists-sharedrepo-perm' );
70                         } elseif ( !$user->isAllowed( 'reupload-shared' ) ) {
71                                 $this->dieWithError( 'apierror-cantoverwrite-sharedfile' );
72                         }
73                 }
74
75                 // Rate limit
76                 if ( $user->pingLimiter( 'move' ) ) {
77                         $this->dieWithError( 'apierror-ratelimited' );
78                 }
79
80                 // Check if the user is allowed to add the specified changetags
81                 if ( $params['tags'] ) {
82                         $ableToTag = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user );
83                         if ( !$ableToTag->isOK() ) {
84                                 $this->dieStatus( $ableToTag );
85                         }
86                 }
87
88                 // Move the page
89                 $toTitleExists = $toTitle->exists();
90                 $status = $this->movePage( $fromTitle, $toTitle, $params['reason'], !$params['noredirect'],
91                         $params['tags'] ?: [] );
92                 if ( !$status->isOK() ) {
93                         $this->dieStatus( $status );
94                 }
95
96                 $r = [
97                         'from' => $fromTitle->getPrefixedText(),
98                         'to' => $toTitle->getPrefixedText(),
99                         'reason' => $params['reason']
100                 ];
101
102                 // NOTE: we assume that if the old title exists, it's because it was re-created as
103                 // a redirect to the new title. This is not safe, but what we did before was
104                 // even worse: we just determined whether a redirect should have been created,
105                 // and reported that it was created if it should have, without any checks.
106                 // Also note that isRedirect() is unreliable because of T39209.
107                 $r['redirectcreated'] = $fromTitle->exists();
108
109                 $r['moveoverredirect'] = $toTitleExists;
110
111                 // Move the talk page
112                 if ( $params['movetalk'] && $toTalk && $fromTalk->exists() && !$fromTitle->isTalkPage() ) {
113                         $toTalkExists = $toTalk->exists();
114                         $status = $this->movePage(
115                                 $fromTalk,
116                                 $toTalk,
117                                 $params['reason'],
118                                 !$params['noredirect'],
119                                 $params['tags'] ?: []
120                         );
121                         if ( $status->isOK() ) {
122                                 $r['talkfrom'] = $fromTalk->getPrefixedText();
123                                 $r['talkto'] = $toTalk->getPrefixedText();
124                                 $r['talkmoveoverredirect'] = $toTalkExists;
125                         } else {
126                                 // We're not going to dieWithError() on failure, since we already changed something
127                                 $r['talkmove-errors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
128                         }
129                 }
130
131                 $result = $this->getResult();
132
133                 // Move subpages
134                 if ( $params['movesubpages'] ) {
135                         $r['subpages'] = $this->moveSubpages(
136                                 $fromTitle,
137                                 $toTitle,
138                                 $params['reason'],
139                                 $params['noredirect'],
140                                 $params['tags'] ?: []
141                         );
142                         ApiResult::setIndexedTagName( $r['subpages'], 'subpage' );
143
144                         if ( $params['movetalk'] ) {
145                                 $r['subpages-talk'] = $this->moveSubpages(
146                                         $fromTalk,
147                                         $toTalk,
148                                         $params['reason'],
149                                         $params['noredirect'],
150                                         $params['tags'] ?: []
151                                 );
152                                 ApiResult::setIndexedTagName( $r['subpages-talk'], 'subpage' );
153                         }
154                 }
155
156                 $watch = 'preferences';
157                 if ( isset( $params['watchlist'] ) ) {
158                         $watch = $params['watchlist'];
159                 } elseif ( $params['watch'] ) {
160                         $watch = 'watch';
161                 } elseif ( $params['unwatch'] ) {
162                         $watch = 'unwatch';
163                 }
164
165                 // Watch pages
166                 $this->setWatch( $watch, $fromTitle, 'watchmoves' );
167                 $this->setWatch( $watch, $toTitle, 'watchmoves' );
168
169                 $result->addValue( null, $this->getModuleName(), $r );
170         }
171
172         /**
173          * @param Title $from
174          * @param Title $to
175          * @param string $reason
176          * @param bool $createRedirect
177          * @param array $changeTags Applied to the entry in the move log and redirect page revision
178          * @return Status
179          */
180         protected function movePage( Title $from, Title $to, $reason, $createRedirect, $changeTags ) {
181                 $mp = new MovePage( $from, $to );
182                 $valid = $mp->isValidMove();
183                 if ( !$valid->isOK() ) {
184                         return $valid;
185                 }
186
187                 $user = $this->getUser();
188                 $permStatus = $mp->checkPermissions( $user, $reason );
189                 if ( !$permStatus->isOK() ) {
190                         return $permStatus;
191                 }
192
193                 // Check suppressredirect permission
194                 if ( !$user->isAllowed( 'suppressredirect' ) ) {
195                         $createRedirect = true;
196                 }
197
198                 return $mp->move( $user, $reason, $createRedirect, $changeTags );
199         }
200
201         /**
202          * @param Title $fromTitle
203          * @param Title $toTitle
204          * @param string $reason
205          * @param bool $noredirect
206          * @param array $changeTags Applied to the entry in the move log and redirect page revisions
207          * @return array
208          */
209         public function moveSubpages( $fromTitle, $toTitle, $reason, $noredirect, $changeTags = [] ) {
210                 $retval = [];
211
212                 $success = $fromTitle->moveSubpages( $toTitle, true, $reason, !$noredirect, $changeTags );
213                 if ( isset( $success[0] ) ) {
214                         $status = $this->errorArrayToStatus( $success );
215                         return [ 'errors' => $this->getErrorFormatter()->arrayFromStatus( $status ) ];
216                 }
217
218                 // At least some pages could be moved
219                 // Report each of them separately
220                 foreach ( $success as $oldTitle => $newTitle ) {
221                         $r = [ 'from' => $oldTitle ];
222                         if ( is_array( $newTitle ) ) {
223                                 $status = $this->errorArrayToStatus( $newTitle );
224                                 $r['errors'] = $this->getErrorFormatter()->arrayFromStatus( $status );
225                         } else {
226                                 // Success
227                                 $r['to'] = $newTitle;
228                         }
229                         $retval[] = $r;
230                 }
231
232                 return $retval;
233         }
234
235         public function mustBePosted() {
236                 return true;
237         }
238
239         public function isWriteMode() {
240                 return true;
241         }
242
243         public function getAllowedParams() {
244                 return [
245                         'from' => null,
246                         'fromid' => [
247                                 ApiBase::PARAM_TYPE => 'integer'
248                         ],
249                         'to' => [
250                                 ApiBase::PARAM_TYPE => 'string',
251                                 ApiBase::PARAM_REQUIRED => true
252                         ],
253                         'reason' => '',
254                         'movetalk' => false,
255                         'movesubpages' => false,
256                         'noredirect' => false,
257                         'watch' => [
258                                 ApiBase::PARAM_DFLT => false,
259                                 ApiBase::PARAM_DEPRECATED => true,
260                         ],
261                         'unwatch' => [
262                                 ApiBase::PARAM_DFLT => false,
263                                 ApiBase::PARAM_DEPRECATED => true,
264                         ],
265                         'watchlist' => [
266                                 ApiBase::PARAM_DFLT => 'preferences',
267                                 ApiBase::PARAM_TYPE => [
268                                         'watch',
269                                         'unwatch',
270                                         'preferences',
271                                         'nochange'
272                                 ],
273                         ],
274                         'ignorewarnings' => false,
275                         'tags' => [
276                                 ApiBase::PARAM_TYPE => 'tags',
277                                 ApiBase::PARAM_ISMULTI => true,
278                         ],
279                 ];
280         }
281
282         public function needsToken() {
283                 return 'csrf';
284         }
285
286         protected function getExamplesMessages() {
287                 return [
288                         'action=move&from=Badtitle&to=Goodtitle&token=123ABC&' .
289                                 'reason=Misspelled%20title&movetalk=&noredirect='
290                                 => 'apihelp-move-example-move',
291                 ];
292         }
293
294         public function getHelpUrls() {
295                 return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Move';
296         }
297 }