Start of "Bug 21991 - Move common query parameter (uc, rc) validation, token requiri...
[lhc/web/wiklou.git] / includes / api / ApiMove.php
1 <?php
2
3 /*
4 * Created on Oct 31, 2007
5 * API for MediaWiki 1.8+
6 *
7 * Copyright (C) 2007 Roan Kattouw <Firstname>.<Lastname>@home.nl
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 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 * http://www.gnu.org/copyleft/gpl.html
23 */
24
25 if ( !defined( 'MEDIAWIKI' ) ) {
26 // Eclipse helper - will be ignored in production
27 require_once ( "ApiBase.php" );
28 }
29
30
31 /**
32 * @ingroup API
33 */
34 class ApiMove extends ApiBase {
35
36 public function __construct( $main, $action ) {
37 parent :: __construct( $main, $action );
38 }
39
40 public function execute() {
41 global $wgUser;
42 $params = $this->extractRequestParams();
43 if ( is_null( $params['reason'] ) )
44 $params['reason'] = '';
45
46 $this->requireOnlyOneParameter( $params, 'from', 'fromid' );
47 if ( !isset( $params['to'] ) )
48 $this->dieUsageMsg( array( 'missingparam', 'to' ) );
49 if ( !$wgUser->matchEditToken( $params['token'] ) )
50 $this->dieUsageMsg( array( 'sessionfailure' ) );
51
52 if ( isset( $params['from'] ) )
53 {
54 $fromTitle = Title::newFromText( $params['from'] );
55 if ( !$fromTitle )
56 $this->dieUsageMsg( array( 'invalidtitle', $params['from'] ) );
57 }
58 else if ( isset( $params['fromid'] ) )
59 {
60 $fromTitle = Title::newFromID( $params['fromid'] );
61 if ( !$fromTitle )
62 $this->dieUsageMsg( array( 'nosuchpageid', $params['fromid'] ) );
63 }
64
65 if ( !$fromTitle->exists() )
66 $this->dieUsageMsg( array( 'notanarticle' ) );
67 $fromTalk = $fromTitle->getTalkPage();
68
69 $toTitle = Title::newFromText( $params['to'] );
70 if ( !$toTitle )
71 $this->dieUsageMsg( array( 'invalidtitle', $params['to'] ) );
72 $toTalk = $toTitle->getTalkPage();
73
74 if ( $toTitle->getNamespace() == NS_FILE
75 && !RepoGroup::singleton()->getLocalRepo()->findFile( $toTitle )
76 && wfFindFile( $toTitle ) )
77 {
78 if ( !$params['ignorewarnings'] && $wgUser->isAllowed( 'reupload-shared' ) ) {
79 $this->dieUsageMsg( array( 'sharedfile-exists' ) );
80 } elseif ( !$wgUser->isAllowed( 'reupload-shared' ) ) {
81 $this->dieUsageMsg( array( 'cantoverwrite-sharedfile' ) );
82 }
83 }
84
85 // Move the page
86 $hookErr = null;
87 $retval = $fromTitle->moveTo( $toTitle, true, $params['reason'], !$params['noredirect'] );
88 if ( $retval !== true )
89 $this->dieUsageMsg( reset( $retval ) );
90
91 $r = array( 'from' => $fromTitle->getPrefixedText(), 'to' => $toTitle->getPrefixedText(), 'reason' => $params['reason'] );
92 if ( !$params['noredirect'] || !$wgUser->isAllowed( 'suppressredirect' ) )
93 $r['redirectcreated'] = '';
94
95 // Move the talk page
96 if ( $params['movetalk'] && $fromTalk->exists() && !$fromTitle->isTalkPage() )
97 {
98 $retval = $fromTalk->moveTo( $toTalk, true, $params['reason'], !$params['noredirect'] );
99 if ( $retval === true )
100 {
101 $r['talkfrom'] = $fromTalk->getPrefixedText();
102 $r['talkto'] = $toTalk->getPrefixedText();
103 }
104 // We're not gonna dieUsage() on failure, since we already changed something
105 else
106 {
107 $parsed = $this->parseMsg( reset( $retval ) );
108 $r['talkmove-error-code'] = $parsed['code'];
109 $r['talkmove-error-info'] = $parsed['info'];
110 }
111 }
112
113 // Move subpages
114 if ( $params['movesubpages'] )
115 {
116 $r['subpages'] = $this->moveSubpages( $fromTitle, $toTitle,
117 $params['reason'], $params['noredirect'] );
118 $this->getResult()->setIndexedTagName( $r['subpages'], 'subpage' );
119 if ( $params['movetalk'] )
120 {
121 $r['subpages-talk'] = $this->moveSubpages( $fromTalk, $toTalk,
122 $params['reason'], $params['noredirect'] );
123 $this->getResult()->setIndexedTagName( $r['subpages-talk'], 'subpage' );
124 }
125 }
126
127 // Watch pages
128 if ( $params['watch'] || $wgUser->getOption( 'watchmoves' ) )
129 {
130 $wgUser->addWatch( $fromTitle );
131 $wgUser->addWatch( $toTitle );
132 }
133 else if ( $params['unwatch'] )
134 {
135 $wgUser->removeWatch( $fromTitle );
136 $wgUser->removeWatch( $toTitle );
137 }
138 $this->getResult()->addValue( null, $this->getModuleName(), $r );
139 }
140
141 public function moveSubpages( $fromTitle, $toTitle, $reason, $noredirect )
142 {
143 $retval = array();
144 $success = $fromTitle->moveSubpages( $toTitle, true, $reason, !$noredirect );
145 if ( isset( $success[0] ) )
146 return array( 'error' => $this->parseMsg( $success ) );
147 else
148 {
149 // At least some pages could be moved
150 // Report each of them separately
151 foreach ( $success as $oldTitle => $newTitle )
152 {
153 $r = array( 'from' => $oldTitle );
154 if ( is_array( $newTitle ) )
155 $r['error'] = $this->parseMsg( reset( $newTitle ) );
156 else
157 // Success
158 $r['to'] = $newTitle;
159 $retval[] = $r;
160 }
161 }
162 return $retval;
163 }
164
165 public function mustBePosted() {
166 return true;
167 }
168
169 public function isWriteMode() {
170 return true;
171 }
172
173 public function getAllowedParams() {
174 return array (
175 'from' => null,
176 'fromid' => array(
177 ApiBase::PARAM_TYPE => 'integer'
178 ),
179 'to' => null,
180 'token' => null,
181 'reason' => null,
182 'movetalk' => false,
183 'movesubpages' => false,
184 'noredirect' => false,
185 'watch' => false,
186 'unwatch' => false,
187 'ignorewarnings' => false
188 );
189 }
190
191 public function getParamDescription() {
192 return array (
193 'from' => 'Title of the page you want to move. Cannot be used together with fromid.',
194 'fromid' => 'Page ID of the page you want to move. Cannot be used together with from.',
195 'to' => 'Title you want to rename the page to.',
196 'token' => 'A move token previously retrieved through prop=info',
197 'reason' => 'Reason for the move (optional).',
198 'movetalk' => 'Move the talk page, if it exists.',
199 'movesubpages' => 'Move subpages, if applicable',
200 'noredirect' => 'Don\'t create a redirect',
201 'watch' => 'Add the page and the redirect to your watchlist',
202 'unwatch' => 'Remove the page and the redirect from your watchlist',
203 'ignorewarnings' => 'Ignore any warnings'
204 );
205 }
206
207 public function getDescription() {
208 return array(
209 'Move a page.'
210 );
211 }
212
213 public function getPossibleErrors() {
214 return array_merge( parent::getPossibleErrors(), array(
215 array( 'missingparam', 'to' ),
216 array( 'sessionfailure' ),
217 array( 'invalidtitle', 'from' ),
218 array( 'nosuchpageid', 'fromid' ),
219 array( 'notanarticle' ),
220 array( 'invalidtitle', 'to' ),
221 array( 'sharedfile-exists' ),
222 ) );
223 }
224
225 public function requiresToken() {
226 return true;
227 }
228
229 protected function getExamples() {
230 return array (
231 'api.php?action=move&from=Exampel&to=Example&token=123ABC&reason=Misspelled%20title&movetalk&noredirect'
232 );
233 }
234
235 public function getVersion() {
236 return __CLASS__ . ': $Id$';
237 }
238 }