Index: trunk/phase3/includes/api/ApiEditPage.php |
— | — | @@ -1,11 +1,11 @@ |
2 | 2 | <?php |
3 | 3 | |
4 | | -/* |
| 4 | +/** |
5 | 5 | * Created on August 16, 2007 |
6 | 6 | * |
7 | 7 | * API for MediaWiki 1.8+ |
8 | 8 | * |
9 | | - * Copyright (C) 2007 Iker Labarga <Firstname><Lastname>@gmail.com |
| 9 | + * Copyright © 2007 Iker Labarga <Firstname><Lastname>@gmail.com |
10 | 10 | * |
11 | 11 | * This program is free software; you can redistribute it and/or modify |
12 | 12 | * it under the terms of the GNU General Public License as published by |
— | — | @@ -24,8 +24,8 @@ |
25 | 25 | */ |
26 | 26 | |
27 | 27 | if ( !defined( 'MEDIAWIKI' ) ) { |
28 | | - // Eclipse helper - will be ignored in production |
29 | | - require_once ( "ApiBase.php" ); |
| 28 | + // Eclipse helper - will be ignored in production |
| 29 | + require_once( "ApiBase.php" ); |
30 | 30 | } |
31 | 31 | |
32 | 32 | /** |
— | — | @@ -38,40 +38,48 @@ |
39 | 39 | class ApiEditPage extends ApiBase { |
40 | 40 | |
41 | 41 | public function __construct( $query, $moduleName ) { |
42 | | - parent :: __construct( $query, $moduleName ); |
| 42 | + parent::__construct( $query, $moduleName ); |
43 | 43 | } |
44 | 44 | |
45 | 45 | public function execute() { |
46 | 46 | global $wgUser; |
47 | 47 | $params = $this->extractRequestParams(); |
48 | | - |
49 | | - if ( is_null( $params['title'] ) ) |
| 48 | + |
| 49 | + if ( is_null( $params['title'] ) ) { |
50 | 50 | $this->dieUsageMsg( array( 'missingparam', 'title' ) ); |
| 51 | + } |
51 | 52 | |
52 | 53 | if ( is_null( $params['text'] ) && is_null( $params['appendtext'] ) && |
53 | 54 | is_null( $params['prependtext'] ) && |
54 | 55 | $params['undo'] == 0 ) |
| 56 | + { |
55 | 57 | $this->dieUsageMsg( array( 'missingtext' ) ); |
| 58 | + } |
56 | 59 | |
57 | 60 | $titleObj = Title::newFromText( $params['title'] ); |
58 | | - if ( !$titleObj || $titleObj->isExternal() ) |
| 61 | + if ( !$titleObj || $titleObj->isExternal() ) { |
59 | 62 | $this->dieUsageMsg( array( 'invalidtitle', $params['title'] ) ); |
60 | | - |
| 63 | + } |
| 64 | + |
61 | 65 | // Some functions depend on $wgTitle == $ep->mTitle |
62 | 66 | global $wgTitle; |
63 | 67 | $wgTitle = $titleObj; |
64 | 68 | |
65 | | - if ( $params['createonly'] && $titleObj->exists() ) |
| 69 | + if ( $params['createonly'] && $titleObj->exists() ) { |
66 | 70 | $this->dieUsageMsg( array( 'createonly-exists' ) ); |
67 | | - if ( $params['nocreate'] && !$titleObj->exists() ) |
| 71 | + } |
| 72 | + if ( $params['nocreate'] && !$titleObj->exists() ) { |
68 | 73 | $this->dieUsageMsg( array( 'nocreate-missing' ) ); |
| 74 | + } |
69 | 75 | |
70 | 76 | // Now let's check whether we're even allowed to do this |
71 | 77 | $errors = $titleObj->getUserPermissionsErrors( 'edit', $wgUser ); |
72 | | - if ( !$titleObj->exists() ) |
| 78 | + if ( !$titleObj->exists() ) { |
73 | 79 | $errors = array_merge( $errors, $titleObj->getUserPermissionsErrors( 'create', $wgUser ) ); |
74 | | - if ( count( $errors ) ) |
| 80 | + } |
| 81 | + if ( count( $errors ) ) { |
75 | 82 | $this->dieUsageMsg( $errors[0] ); |
| 83 | + } |
76 | 84 | |
77 | 85 | $articleObj = new Article( $titleObj ); |
78 | 86 | $toMD5 = $params['text']; |
— | — | @@ -81,103 +89,123 @@ |
82 | 90 | // returns an interface message rather than '' |
83 | 91 | // We do want getContent()'s behavior for non-existent |
84 | 92 | // MediaWiki: pages, though |
85 | | - if ( $articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI ) |
| 93 | + if ( $articleObj->getID() == 0 && $titleObj->getNamespace() != NS_MEDIAWIKI ) { |
86 | 94 | $content = ''; |
87 | | - else |
| 95 | + } else { |
88 | 96 | $content = $articleObj->getContent(); |
89 | | - |
90 | | - if ( !is_null( $params['section'] ) ) |
91 | | - { |
| 97 | + } |
| 98 | + |
| 99 | + if ( !is_null( $params['section'] ) ) { |
92 | 100 | // Process the content for section edits |
93 | 101 | global $wgParser; |
94 | 102 | $section = intval( $params['section'] ); |
95 | 103 | $content = $wgParser->getSection( $content, $section, false ); |
96 | | - if ( $content === false ) |
| 104 | + if ( $content === false ) { |
97 | 105 | $this->dieUsage( "There is no section {$section}.", 'nosuchsection' ); |
| 106 | + } |
98 | 107 | } |
99 | 108 | $params['text'] = $params['prependtext'] . $content . $params['appendtext']; |
100 | 109 | $toMD5 = $params['prependtext'] . $params['appendtext']; |
101 | 110 | } |
102 | | - |
103 | | - if ( $params['undo'] > 0 ) |
104 | | - { |
105 | | - if ( $params['undoafter'] > 0 ) |
106 | | - { |
107 | | - if ( $params['undo'] < $params['undoafter'] ) |
| 111 | + |
| 112 | + if ( $params['undo'] > 0 ) { |
| 113 | + if ( $params['undoafter'] > 0 ) { |
| 114 | + if ( $params['undo'] < $params['undoafter'] ) { |
108 | 115 | list( $params['undo'], $params['undoafter'] ) = |
109 | 116 | array( $params['undoafter'], $params['undo'] ); |
| 117 | + } |
110 | 118 | $undoafterRev = Revision::newFromID( $params['undoafter'] ); |
111 | 119 | } |
112 | 120 | $undoRev = Revision::newFromID( $params['undo'] ); |
113 | 121 | if ( is_null( $undoRev ) || $undoRev->isDeleted( Revision::DELETED_TEXT ) ) |
| 122 | + { |
114 | 123 | $this->dieUsageMsg( array( 'nosuchrevid', $params['undo'] ) ); |
| 124 | + } |
115 | 125 | |
116 | | - if ( $params['undoafter'] == 0 ) |
| 126 | + if ( $params['undoafter'] == 0 ) { |
117 | 127 | $undoafterRev = $undoRev->getPrevious(); |
| 128 | + } |
118 | 129 | if ( is_null( $undoafterRev ) || $undoafterRev->isDeleted( Revision::DELETED_TEXT ) ) |
| 130 | + { |
119 | 131 | $this->dieUsageMsg( array( 'nosuchrevid', $params['undoafter'] ) ); |
| 132 | + } |
120 | 133 | |
121 | | - if ( $undoRev->getPage() != $articleObj->getID() ) |
| 134 | + if ( $undoRev->getPage() != $articleObj->getID() ) { |
122 | 135 | $this->dieUsageMsg( array( 'revwrongpage', $undoRev->getID(), $titleObj->getPrefixedText() ) ); |
123 | | - if ( $undoafterRev->getPage() != $articleObj->getID() ) |
| 136 | + } |
| 137 | + if ( $undoafterRev->getPage() != $articleObj->getID() ) { |
124 | 138 | $this->dieUsageMsg( array( 'revwrongpage', $undoafterRev->getID(), $titleObj->getPrefixedText() ) ); |
125 | | - |
| 139 | + } |
| 140 | + |
126 | 141 | $newtext = $articleObj->getUndoText( $undoRev, $undoafterRev ); |
127 | | - if ( $newtext === false ) |
| 142 | + if ( $newtext === false ) { |
128 | 143 | $this->dieUsageMsg( array( 'undo-failure' ) ); |
| 144 | + } |
129 | 145 | $params['text'] = $newtext; |
130 | 146 | // If no summary was given and we only undid one rev, |
131 | 147 | // use an autosummary |
132 | 148 | if ( is_null( $params['summary'] ) && $titleObj->getNextRevisionID( $undoafterRev->getID() ) == $params['undo'] ) |
| 149 | + { |
133 | 150 | $params['summary'] = wfMsgForContent( 'undo-summary', $params['undo'], $undoRev->getUserText() ); |
| 151 | + } |
134 | 152 | } |
135 | 153 | |
136 | 154 | // See if the MD5 hash checks out |
137 | | - if ( !is_null( $params['md5'] ) && md5( $toMD5 ) !== $params['md5'] ) |
| 155 | + if ( !is_null( $params['md5'] ) && md5( $toMD5 ) !== $params['md5'] ) { |
138 | 156 | $this->dieUsageMsg( array( 'hashcheckfailed' ) ); |
139 | | - |
| 157 | + } |
| 158 | + |
140 | 159 | $ep = new EditPage( $articleObj ); |
141 | 160 | // EditPage wants to parse its stuff from a WebRequest |
142 | 161 | // That interface kind of sucks, but it's workable |
143 | | - $reqArr = array( 'wpTextbox1' => $params['text'], |
144 | | - 'wpEditToken' => $params['token'], |
145 | | - 'wpIgnoreBlankSummary' => '' |
| 162 | + $reqArr = array( |
| 163 | + 'wpTextbox1' => $params['text'], |
| 164 | + 'wpEditToken' => $params['token'], |
| 165 | + 'wpIgnoreBlankSummary' => '' |
146 | 166 | ); |
147 | 167 | |
148 | | - if ( !is_null( $params['summary'] ) ) |
| 168 | + if ( !is_null( $params['summary'] ) ) { |
149 | 169 | $reqArr['wpSummary'] = $params['summary']; |
| 170 | + } |
150 | 171 | |
151 | 172 | // Watch out for basetimestamp == '' |
152 | 173 | // wfTimestamp() treats it as NOW, almost certainly causing an edit conflict |
153 | 174 | if ( !is_null( $params['basetimestamp'] ) && $params['basetimestamp'] != '' ) |
| 175 | + { |
154 | 176 | $reqArr['wpEdittime'] = wfTimestamp( TS_MW, $params['basetimestamp'] ); |
155 | | - else |
| 177 | + } else { |
156 | 178 | $reqArr['wpEdittime'] = $articleObj->getTimestamp(); |
| 179 | + } |
157 | 180 | |
158 | 181 | if ( !is_null( $params['starttimestamp'] ) && $params['starttimestamp'] != '' ) |
| 182 | + { |
159 | 183 | $reqArr['wpStarttime'] = wfTimestamp( TS_MW, $params['starttimestamp'] ); |
160 | | - else |
| 184 | + } else { |
161 | 185 | $reqArr['wpStarttime'] = $reqArr['wpEdittime']; // Fake wpStartime |
| 186 | + } |
162 | 187 | |
163 | 188 | if ( $params['minor'] || ( !$params['notminor'] && $wgUser->getOption( 'minordefault' ) ) ) |
| 189 | + { |
164 | 190 | $reqArr['wpMinoredit'] = ''; |
| 191 | + } |
165 | 192 | |
166 | | - if ( $params['recreate'] ) |
| 193 | + if ( $params['recreate'] ) { |
167 | 194 | $reqArr['wpRecreate'] = ''; |
| 195 | + } |
168 | 196 | |
169 | | - if ( !is_null( $params['section'] ) ) |
170 | | - { |
| 197 | + if ( !is_null( $params['section'] ) ) { |
171 | 198 | $section = intval( $params['section'] ); |
172 | 199 | if ( $section == 0 && $params['section'] != '0' && $params['section'] != 'new' ) |
| 200 | + { |
173 | 201 | $this->dieUsage( "The section parameter must be set to an integer or 'new'", "invalidsection" ); |
| 202 | + } |
174 | 203 | $reqArr['wpSection'] = $params['section']; |
| 204 | + } else { |
| 205 | + $reqArr['wpSection'] = ''; |
175 | 206 | } |
176 | | - else |
177 | | - $reqArr['wpSection'] = ''; |
178 | 207 | |
179 | 208 | // Handle watchlist settings |
180 | | - switch ( $params['watchlist'] ) |
181 | | - { |
| 209 | + switch ( $params['watchlist'] ) { |
182 | 210 | case 'watch': |
183 | 211 | $watch = true; |
184 | 212 | break; |
— | — | @@ -185,23 +213,26 @@ |
186 | 214 | $watch = false; |
187 | 215 | break; |
188 | 216 | case 'preferences': |
189 | | - if ( $titleObj->exists() ) |
| 217 | + if ( $titleObj->exists() ) { |
190 | 218 | $watch = $wgUser->getOption( 'watchdefault' ) || $titleObj->userIsWatching(); |
191 | | - else |
| 219 | + } else { |
192 | 220 | $watch = $wgUser->getOption( 'watchcreations' ); |
| 221 | + } |
193 | 222 | break; |
194 | 223 | case 'nochange': |
195 | 224 | default: |
196 | 225 | $watch = $titleObj->userIsWatching(); |
197 | 226 | } |
198 | 227 | // Deprecated parameters |
199 | | - if ( $params['watch'] ) |
| 228 | + if ( $params['watch'] ) { |
200 | 229 | $watch = true; |
201 | | - elseif ( $params['unwatch'] ) |
| 230 | + } elseif ( $params['unwatch'] ) { |
202 | 231 | $watch = false; |
203 | | - |
204 | | - if ( $watch ) |
| 232 | + } |
| 233 | + |
| 234 | + if ( $watch ) { |
205 | 235 | $reqArr['wpWatchthis'] = ''; |
| 236 | + } |
206 | 237 | |
207 | 238 | $req = new FauxRequest( $reqArr, true ); |
208 | 239 | $ep->importFormData( $req ); |
— | — | @@ -209,22 +240,23 @@ |
210 | 241 | // Run hooks |
211 | 242 | // Handle CAPTCHA parameters |
212 | 243 | global $wgRequest; |
213 | | - if ( !is_null( $params['captchaid'] ) ) |
| 244 | + if ( !is_null( $params['captchaid'] ) ) { |
214 | 245 | $wgRequest->setVal( 'wpCaptchaId', $params['captchaid'] ); |
215 | | - if ( !is_null( $params['captchaword'] ) ) |
| 246 | + } |
| 247 | + if ( !is_null( $params['captchaword'] ) ) { |
216 | 248 | $wgRequest->setVal( 'wpCaptchaWord', $params['captchaword'] ); |
| 249 | + } |
217 | 250 | |
218 | 251 | $r = array(); |
219 | 252 | if ( !wfRunHooks( 'APIEditBeforeSave', array( $ep, $ep->textbox1, &$r ) ) ) |
220 | 253 | { |
221 | | - if ( count( $r ) ) |
222 | | - { |
223 | | - $r['result'] = "Failure"; |
| 254 | + if ( count( $r ) ) { |
| 255 | + $r['result'] = 'Failure'; |
224 | 256 | $this->getResult()->addValue( null, $this->getModuleName(), $r ); |
225 | 257 | return; |
| 258 | + } else { |
| 259 | + $this->dieUsageMsg( array( 'hookaborted' ) ); |
226 | 260 | } |
227 | | - else |
228 | | - $this->dieUsageMsg( array( 'hookaborted' ) ); |
229 | 261 | } |
230 | 262 | |
231 | 263 | // Do the actual save |
— | — | @@ -237,8 +269,7 @@ |
238 | 270 | |
239 | 271 | $retval = $ep->internalAttemptSave( $result, $wgUser->isAllowed( 'bot' ) && $params['bot'] ); |
240 | 272 | $wgRequest = $oldRequest; |
241 | | - switch( $retval ) |
242 | | - { |
| 273 | + switch( $retval ) { |
243 | 274 | case EditPage::AS_HOOK_ERROR: |
244 | 275 | case EditPage::AS_HOOK_ERROR_EXPECTED: |
245 | 276 | $this->dieUsageMsg( array( 'hookaborted' ) ); |
— | — | @@ -294,7 +325,7 @@ |
295 | 326 | case EditPage::AS_SUCCESS_NEW_ARTICLE: |
296 | 327 | $r['new'] = ''; |
297 | 328 | case EditPage::AS_SUCCESS_UPDATE: |
298 | | - $r['result'] = "Success"; |
| 329 | + $r['result'] = 'Success'; |
299 | 330 | $r['pageid'] = intval( $titleObj->getArticleID() ); |
300 | 331 | $r['title'] = $titleObj->getPrefixedText(); |
301 | 332 | // HACK: We create a new Article object here because getRevIdFetched() |
— | — | @@ -303,10 +334,9 @@ |
304 | 335 | // don't want to do. |
305 | 336 | $newArticle = new Article( $titleObj ); |
306 | 337 | $newRevId = $newArticle->getRevIdFetched(); |
307 | | - if ( $newRevId == $oldRevId ) |
| 338 | + if ( $newRevId == $oldRevId ) { |
308 | 339 | $r['nochange'] = ''; |
309 | | - else |
310 | | - { |
| 340 | + } else { |
311 | 341 | $r['oldrevid'] = intval( $oldRevId ); |
312 | 342 | $r['newrevid'] = intval( $newRevId ); |
313 | 343 | $r['newtimestamp'] = wfTimestamp( TS_ISO_8601, |
— | — | @@ -316,10 +346,10 @@ |
317 | 347 | |
318 | 348 | case EditPage::AS_END: |
319 | 349 | // This usually means some kind of race condition |
320 | | - // or DB weirdness occurred. Fall through to throw an unknown |
| 350 | + // or DB weirdness occurred. Fall through to throw an unknown |
321 | 351 | // error. |
322 | 352 | |
323 | | - // This needs fixing higher up, as Article::doEdit should be |
| 353 | + // This needs fixing higher up, as Article::doEdit should be |
324 | 354 | // used rather than Article::updateArticle, so that specific |
325 | 355 | // error conditions can be returned |
326 | 356 | default: |
— | — | @@ -339,10 +369,10 @@ |
340 | 370 | protected function getDescription() { |
341 | 371 | return 'Create and edit pages.'; |
342 | 372 | } |
343 | | - |
| 373 | + |
344 | 374 | public function getPossibleErrors() { |
345 | 375 | global $wgMaxArticleSize; |
346 | | - |
| 376 | + |
347 | 377 | return array_merge( parent::getPossibleErrors(), array( |
348 | 378 | array( 'missingparam', 'title' ), |
349 | 379 | array( 'missingtext' ), |
— | — | @@ -376,7 +406,7 @@ |
377 | 407 | } |
378 | 408 | |
379 | 409 | protected function getAllowedParams() { |
380 | | - return array ( |
| 410 | + return array( |
381 | 411 | 'title' => null, |
382 | 412 | 'section' => null, |
383 | 413 | 'text' => null, |
— | — | @@ -393,16 +423,16 @@ |
394 | 424 | 'captchaword' => null, |
395 | 425 | 'captchaid' => null, |
396 | 426 | 'watch' => array( |
397 | | - ApiBase :: PARAM_DFLT => false, |
398 | | - ApiBase :: PARAM_DEPRECATED => true, |
| 427 | + ApiBase::PARAM_DFLT => false, |
| 428 | + ApiBase::PARAM_DEPRECATED => true, |
399 | 429 | ), |
400 | 430 | 'unwatch' => array( |
401 | | - ApiBase :: PARAM_DFLT => false, |
402 | | - ApiBase :: PARAM_DEPRECATED => true, |
| 431 | + ApiBase::PARAM_DFLT => false, |
| 432 | + ApiBase::PARAM_DEPRECATED => true, |
403 | 433 | ), |
404 | 434 | 'watchlist' => array( |
405 | | - ApiBase :: PARAM_DFLT => 'preferences', |
406 | | - ApiBase :: PARAM_TYPE => array( |
| 435 | + ApiBase::PARAM_DFLT => 'preferences', |
| 436 | + ApiBase::PARAM_TYPE => array( |
407 | 437 | 'watch', |
408 | 438 | 'unwatch', |
409 | 439 | 'preferences', |
— | — | @@ -413,16 +443,16 @@ |
414 | 444 | 'prependtext' => null, |
415 | 445 | 'appendtext' => null, |
416 | 446 | 'undo' => array( |
417 | | - ApiBase :: PARAM_TYPE => 'integer' |
| 447 | + ApiBase::PARAM_TYPE => 'integer' |
418 | 448 | ), |
419 | 449 | 'undoafter' => array( |
420 | | - ApiBase :: PARAM_TYPE => 'integer' |
| 450 | + ApiBase::PARAM_TYPE => 'integer' |
421 | 451 | ), |
422 | 452 | ); |
423 | 453 | } |
424 | 454 | |
425 | 455 | protected function getParamDescription() { |
426 | | - return array ( |
| 456 | + return array( |
427 | 457 | 'title' => 'Page title', |
428 | 458 | 'section' => 'Section number. 0 for the top section, \'new\' for a new section', |
429 | 459 | 'text' => 'Page content', |
— | — | @@ -453,19 +483,19 @@ |
454 | 484 | 'undoafter' => 'Undo all revisions from undo to this one. If not set, just undo one revision', |
455 | 485 | ); |
456 | 486 | } |
457 | | - |
| 487 | + |
458 | 488 | public function getTokenSalt() { |
459 | 489 | return ''; |
460 | 490 | } |
461 | 491 | |
462 | 492 | protected function getExamples() { |
463 | | - return array ( |
464 | | - "Edit a page (anonymous user):", |
465 | | - " api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\", |
466 | | - "Prepend __NOTOC__ to a page (anonymous user):", |
467 | | - " api.php?action=edit&title=Test&summary=NOTOC&minor&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\", |
468 | | - "Undo r13579 through r13585 with autosummary(anonymous user):", |
469 | | - " api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\", |
| 493 | + return array( |
| 494 | + 'Edit a page (anonymous user):', |
| 495 | + ' api.php?action=edit&title=Test&summary=test%20summary&text=article%20content&basetimestamp=20070824123454&token=%2B\\', |
| 496 | + 'Prepend __NOTOC__ to a page (anonymous user):', |
| 497 | + ' api.php?action=edit&title=Test&summary=NOTOC&minor&prependtext=__NOTOC__%0A&basetimestamp=20070824123454&token=%2B\\', |
| 498 | + 'Undo r13579 through r13585 with autosummary (anonymous user):', |
| 499 | + ' api.php?action=edit&title=Test&undo=13585&undoafter=13579&basetimestamp=20070824123454&token=%2B\\', |
470 | 500 | ); |
471 | 501 | } |
472 | 502 | |