Index: trunk/phase3/docs/hooks.txt |
— | — | @@ -264,17 +264,6 @@ |
265 | 265 | $user: the User object about to be created (read-only, incomplete) |
266 | 266 | $message: out parameter: error message to display on abort |
267 | 267 | |
268 | | -'ActionBeforeFormDisplay': Modify the form shown for an action (added 1.18) |
269 | | -$action: String |
270 | | -$form: HTMLForm |
271 | | -$page: Article |
272 | | - |
273 | | -'ActionModifyFormFields': Modify the descriptor array which will be used to create an |
274 | | -action form |
275 | | -$action: String |
276 | | -$fields: Array |
277 | | -$page: Article |
278 | | - |
279 | 268 | 'AddNewAccount': after a user account is created |
280 | 269 | $user: the User object that was created. (Parameter added in 1.7) |
281 | 270 | $byEmail: true when account was created "by email" (added in 1.12) |
— | — | @@ -395,6 +384,12 @@ |
396 | 385 | $article: the article (object) being loaded from the database |
397 | 386 | $content: the content (string) of the article |
398 | 387 | |
| 388 | +'ArticleConfirmDelete': before writing the confirmation form for article |
| 389 | + deletion |
| 390 | +$article: the article (object) being deleted |
| 391 | +$output: the OutputPage object ($wgOut) |
| 392 | +&$reason: the reason (string) the article is being deleted |
| 393 | + |
399 | 394 | 'ArticleContentOnDiff': before showing the article content below a diff. |
400 | 395 | Use this to change the content in this area or how it is loaded. |
401 | 396 | $diffEngine: the DifferenceEngine |
Index: trunk/phase3/includes/Action.php |
— | — | @@ -1,440 +0,0 @@ |
2 | | -<?php |
3 | | -/** |
4 | | - * Actions are things which can be done to pages (edit, delete, rollback, etc). They |
5 | | - * are distinct from Special Pages because an action must apply to exactly one page. |
6 | | - * |
7 | | - * To add an action in an extension, create a subclass of Action, and add the key to |
8 | | - * $wgActions. There is also the deprecated UnknownAction hook |
9 | | - * |
10 | | - * |
11 | | - * This program is free software; you can redistribute it and/or modify |
12 | | - * it under the terms of the GNU General Public License as published by |
13 | | - * the Free Software Foundation; either version 2 of the License, or |
14 | | - * (at your option) any later version. |
15 | | - * |
16 | | - * This program is distributed in the hope that it will be useful, |
17 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | | - * GNU General Public License for more details. |
20 | | - * |
21 | | - * You should have received a copy of the GNU General Public License |
22 | | - * along with this program; if not, write to the Free Software |
23 | | - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
24 | | - * |
25 | | - * @file |
26 | | - */ |
27 | | -abstract class Action { |
28 | | - |
29 | | - // Page on which we're performing the action |
30 | | - // @var Article |
31 | | - protected $page; |
32 | | - |
33 | | - // RequestContext if specified; otherwise we'll use the Context from the Page |
34 | | - // @var RequestContext |
35 | | - protected $context; |
36 | | - |
37 | | - // The fields used to create the HTMLForm |
38 | | - // @var Array |
39 | | - protected $fields; |
40 | | - |
41 | | - /** |
42 | | - * Get the Action subclass which should be used to handle this action, false if |
43 | | - * the action is disabled, or null if it's not recognised |
44 | | - * @param $action String |
45 | | - * @return bool|null|string |
46 | | - */ |
47 | | - private final static function getClass( $action ){ |
48 | | - global $wgActions; |
49 | | - $action = strtolower( $action ); |
50 | | - |
51 | | - if( !isset( $wgActions[$action] ) ){ |
52 | | - return null; |
53 | | - } |
54 | | - |
55 | | - if( $wgActions[$action] === false ){ |
56 | | - return false; |
57 | | - } |
58 | | - |
59 | | - elseif( $wgActions[$action] === true ){ |
60 | | - return ucfirst( $action ) . 'Action'; |
61 | | - } |
62 | | - |
63 | | - else { |
64 | | - return $wgActions[$action]; |
65 | | - } |
66 | | - } |
67 | | - |
68 | | - /** |
69 | | - * Get an appropriate Action subclass for the given action |
70 | | - * @param $action String |
71 | | - * @param $page Article |
72 | | - * @return Action|false|null false if the action is disabled, null |
73 | | - * if it is not recognised |
74 | | - */ |
75 | | - public final static function factory( $action, Article $page ){ |
76 | | - $class = self::getClass( $action ); |
77 | | - if( $class ){ |
78 | | - $obj = new $class( $page ); |
79 | | - return $obj; |
80 | | - } |
81 | | - return null; |
82 | | - } |
83 | | - |
84 | | - /** |
85 | | - * Check if a given action is recognised, even if it's disabled |
86 | | - * |
87 | | - * @param $name String: name of an action |
88 | | - * @return Bool |
89 | | - */ |
90 | | - public final static function exists( $name ) { |
91 | | - return self::getClass( $name ) !== null; |
92 | | - } |
93 | | - |
94 | | - /** |
95 | | - * Get the RequestContext in use here |
96 | | - * @return RequestContext |
97 | | - */ |
98 | | - protected final function getContext(){ |
99 | | - if( $this->context instanceof RequestContext ){ |
100 | | - return $this->context; |
101 | | - } |
102 | | - return $this->page->getContext(); |
103 | | - } |
104 | | - |
105 | | - /** |
106 | | - * Get the WebRequest being used for this instance |
107 | | - * |
108 | | - * @return WebRequest |
109 | | - */ |
110 | | - protected final function getRequest() { |
111 | | - return $this->getContext()->request; |
112 | | - } |
113 | | - |
114 | | - /** |
115 | | - * Get the OutputPage being used for this instance |
116 | | - * |
117 | | - * @return OutputPage |
118 | | - */ |
119 | | - protected final function getOutput() { |
120 | | - return $this->getContext()->output; |
121 | | - } |
122 | | - |
123 | | - /** |
124 | | - * Shortcut to get the skin being used for this instance |
125 | | - * |
126 | | - * @return User |
127 | | - */ |
128 | | - protected final function getUser() { |
129 | | - return $this->getContext()->user; |
130 | | - } |
131 | | - |
132 | | - /** |
133 | | - * Shortcut to get the skin being used for this instance |
134 | | - * |
135 | | - * @return Skin |
136 | | - */ |
137 | | - protected final function getSkin() { |
138 | | - return $this->getContext()->skin; |
139 | | - } |
140 | | - |
141 | | - /** |
142 | | - * Shortcut to get the Title object from the page |
143 | | - * @return Title |
144 | | - */ |
145 | | - protected final function getTitle(){ |
146 | | - return $this->page->getTitle(); |
147 | | - } |
148 | | - |
149 | | - /** |
150 | | - * Protected constructor: use Action::factory( $action, $page ) to actually build |
151 | | - * these things in the real world |
152 | | - * @param Article $page |
153 | | - */ |
154 | | - protected function __construct( Article $page ){ |
155 | | - $this->page = $page; |
156 | | - } |
157 | | - |
158 | | - /** |
159 | | - * Return the name of the action this object responds to |
160 | | - * @return String lowercase |
161 | | - */ |
162 | | - public abstract function getName(); |
163 | | - |
164 | | - /** |
165 | | - * Get the permission required to perform this action. Often, but not always, |
166 | | - * the same as the action name |
167 | | - */ |
168 | | - public abstract function getRestriction(); |
169 | | - |
170 | | - /** |
171 | | - * Checks if the given user (identified by an object) can perform this action. Can be |
172 | | - * overridden by sub-classes with more complicated permissions schemes. Failures here |
173 | | - * must throw subclasses of ErrorPageError |
174 | | - * |
175 | | - * @param $user User: the user to check, or null to use the context user |
176 | | - * @throws ErrorPageError |
177 | | - */ |
178 | | - protected function checkCanExecute( User $user ) { |
179 | | - if( $this->requiresWrite() && wfReadOnly() ){ |
180 | | - throw new ReadOnlyError(); |
181 | | - } |
182 | | - |
183 | | - if( $this->getRestriction() !== null && !$user->isAllowed( $this->getRestriction() ) ){ |
184 | | - throw new PermissionsError( $this->getRestriction() ); |
185 | | - } |
186 | | - |
187 | | - if( $this->requiresUnblock() && $user->isBlocked() ){ |
188 | | - $block = $user->mBlock; |
189 | | - throw new UserBlockedError( $block ); |
190 | | - } |
191 | | - } |
192 | | - |
193 | | - /** |
194 | | - * Whether this action requires the wiki not to be locked |
195 | | - * @return Bool |
196 | | - */ |
197 | | - public function requiresWrite(){ |
198 | | - return true; |
199 | | - } |
200 | | - |
201 | | - /** |
202 | | - * Whether this action can still be executed by a blocked user |
203 | | - * @return Bool |
204 | | - */ |
205 | | - public function requiresUnblock(){ |
206 | | - return true; |
207 | | - } |
208 | | - |
209 | | - /** |
210 | | - * Set output headers for noindexing etc. This function will not be called through |
211 | | - * the execute() entry point, so only put UI-related stuff in here. |
212 | | - */ |
213 | | - protected function setHeaders() { |
214 | | - $out = $this->getOutput(); |
215 | | - $out->setRobotPolicy( "noindex,nofollow" ); |
216 | | - $out->setPageTitle( $this->getTitle()->getPrefixedText() ); |
217 | | - $this->getOutput()->setSubtitle( $this->getDescription() ); |
218 | | - $out->setArticleRelated( true ); |
219 | | - } |
220 | | - |
221 | | - /** |
222 | | - * Returns the name that goes in the \<h1\> page title |
223 | | - * |
224 | | - * Derived classes can override this, but usually it is easier to keep the |
225 | | - * default behaviour. Messages can be added at run-time, see |
226 | | - * MessageCache.php. |
227 | | - * |
228 | | - * @return String |
229 | | - */ |
230 | | - protected function getDescription() { |
231 | | - return wfMsg( strtolower( $this->getName() ) ); |
232 | | - } |
233 | | - |
234 | | - /** |
235 | | - * The basic pattern for actions is to display some sort of HTMLForm UI, maybe with |
236 | | - * some stuff underneath (history etc); to do some processing on submission of that |
237 | | - * form (delete, protect, etc) and to do something exciting on 'success', be that |
238 | | - * display something new or redirect to somewhere. Some actions have more exotic |
239 | | - * behaviour, but that's what subclassing is for :D |
240 | | - */ |
241 | | - public function show(){ |
242 | | - $this->setHeaders(); |
243 | | - |
244 | | - // This will throw exceptions if there's a problem |
245 | | - $this->checkCanExecute( $this->getUser() ); |
246 | | - |
247 | | - $form = $this->getForm(); |
248 | | - if( $form instanceof HTMLForm ){ |
249 | | - if( $form->show() ){ |
250 | | - $this->onSuccess(); |
251 | | - } |
252 | | - } else { |
253 | | - // You're using the wrong type of Action |
254 | | - throw new MWException( "Action::getFormFields() must produce a form. Use GetAction if you don't want one." ); |
255 | | - } |
256 | | - } |
257 | | - |
258 | | - /** |
259 | | - * Execute the action in a silent fashion: do not display anything or release any errors. |
260 | | - * @param $data Array values that would normally be in the POST request |
261 | | - * @param $captureErrors Bool whether to catch exceptions and just return false |
262 | | - * @return Bool whether execution was successful |
263 | | - */ |
264 | | - public function execute( array $data = null, $captureErrors = true ){ |
265 | | - try { |
266 | | - // Set a new context so output doesn't leak. |
267 | | - $this->context = clone $this->page->getContext(); |
268 | | - |
269 | | - // This will throw exceptions if there's a problem |
270 | | - $this->checkCanExecute( $this->getUser() ); |
271 | | - |
272 | | - $form = $this->getForm(); |
273 | | - if( $form instanceof HTMLForm ){ |
274 | | - // Great, so there's a form. Ignore it and go straight to the submission callback |
275 | | - $fields = array(); |
276 | | - foreach( $this->fields as $key => $params ){ |
277 | | - if( isset( $data[$key] ) ){ |
278 | | - $fields[$key] = $data[$key]; |
279 | | - } elseif( isset( $params['default'] ) ) { |
280 | | - $fields[$key] = $params['default']; |
281 | | - } else { |
282 | | - $fields[$key] = null; |
283 | | - } |
284 | | - } |
285 | | - $status = $this->onSubmit( $fields ); |
286 | | - if( $status === true ){ |
287 | | - // This might do permanent stuff |
288 | | - $this->onSuccess(); |
289 | | - return true; |
290 | | - } else { |
291 | | - return false; |
292 | | - } |
293 | | - } else { |
294 | | - // You're using the wrong type of Action |
295 | | - throw new MWException( "Action::getFormFields() must produce a form. Use GetAction if you don't want one." ); |
296 | | - } |
297 | | - } |
298 | | - catch ( ErrorPageError $e ){ |
299 | | - if( $captureErrors ){ |
300 | | - return false; |
301 | | - } else { |
302 | | - throw $e; |
303 | | - } |
304 | | - } |
305 | | - } |
306 | | - |
307 | | - /** |
308 | | - * Get an HTMLForm descriptor array, or false if you don't want a form |
309 | | - * @return Array |
310 | | - */ |
311 | | - protected abstract function getFormFields(); |
312 | | - |
313 | | - /** |
314 | | - * Add pre- or post-text to the form |
315 | | - * @return String |
316 | | - */ |
317 | | - protected function preText(){ return ''; } |
318 | | - protected function postText(){ return ''; } |
319 | | - |
320 | | - /** |
321 | | - * Play with the HTMLForm if you need to more substantially |
322 | | - * @param &$form HTMLForm |
323 | | - */ |
324 | | - protected function alterForm( HTMLForm &$form ){} |
325 | | - |
326 | | - /** |
327 | | - * Get the HTMLForm to control behaviour |
328 | | - * @return HTMLForm|null |
329 | | - */ |
330 | | - protected function getForm(){ |
331 | | - $this->fields = $this->getFormFields(); |
332 | | - |
333 | | - // Give hooks a chance to alter the form, adding extra fields or text etc |
334 | | - wfRunHooks( 'ActionModifyFormFields', array( $this->getName(), &$this->fields, $this->page ) ); |
335 | | - |
336 | | - if( $this->fields === false ){ |
337 | | - return null; |
338 | | - } |
339 | | - |
340 | | - $form = new HTMLForm( $this->fields, $this->getContext() ); |
341 | | - $form->setSubmitCallback( array( $this, 'onSubmit' ) ); |
342 | | - $form->addHiddenField( 'action', $this->getName() ); |
343 | | - |
344 | | - $form->addPreText( $this->preText() ); |
345 | | - $form->addPostText( $this->postText() ); |
346 | | - $this->alterForm( $form ); |
347 | | - |
348 | | - // Give hooks a chance to alter the form, adding extra fields or text etc |
349 | | - wfRunHooks( 'ActionBeforeFormDisplay', array( $this->getName(), &$form, $this->page ) ); |
350 | | - |
351 | | - return $form; |
352 | | - } |
353 | | - |
354 | | - /** |
355 | | - * Process the form on POST submission. If you return false from getFormFields(), |
356 | | - * this will obviously never be reached. If you don't want to do anything with the |
357 | | - * form, just return false here |
358 | | - * @param $data Array |
359 | | - * @return Bool|Array true for success, false for didn't-try, array of errors on failure |
360 | | - */ |
361 | | - public abstract function onSubmit( $data ); |
362 | | - |
363 | | - /** |
364 | | - * Do something exciting on successful processing of the form. This might be to show |
365 | | - * a confirmation message (watch, rollback, etc) or to redirect somewhere else (edit, |
366 | | - * protect, etc). |
367 | | - */ |
368 | | - public abstract function onSuccess(); |
369 | | - |
370 | | -} |
371 | | - |
372 | | -/** |
373 | | - * Actions generally fall into two groups: the show-a-form-then-do-something-with-the-input |
374 | | - * format (protect, delete, move, etc), and the just-do-something format (watch, rollback, |
375 | | - * patrol, etc). |
376 | | - */ |
377 | | -abstract class FormlessAction extends Action { |
378 | | - |
379 | | - /** |
380 | | - * Show something on GET request. This is displayed as the postText() of the HTMLForm |
381 | | - * if there is one; you can always use alterForm() to add pre text if you need it. If |
382 | | - * you call addPostText() from alterForm() as well as overriding this function, you |
383 | | - * might get strange ordering. |
384 | | - * @return String|null will be added to the HTMLForm if present, or just added to the |
385 | | - * output if not. Return null to not add anything |
386 | | - */ |
387 | | - public abstract function onView(); |
388 | | - |
389 | | - /** |
390 | | - * We don't want an HTMLForm |
391 | | - */ |
392 | | - protected function getFormFields(){ |
393 | | - return false; |
394 | | - } |
395 | | - |
396 | | - public function onSubmit( $data ){ |
397 | | - return false; |
398 | | - } |
399 | | - |
400 | | - public function onSuccess(){ |
401 | | - return false; |
402 | | - } |
403 | | - |
404 | | - public function show(){ |
405 | | - $this->setHeaders(); |
406 | | - |
407 | | - // This will throw exceptions if there's a problem |
408 | | - $this->checkCanExecute( $this->getUser() ); |
409 | | - $this->getOutput()->addHTML( $this->onView() ); |
410 | | - } |
411 | | - |
412 | | - /** |
413 | | - * Execute the action silently, not giving any output. Since these actions don't have |
414 | | - * forms, they probably won't have any data, but some (eg rollback) may do |
415 | | - * @param $data Array values that would normally be in the GET request |
416 | | - * @param $captureErrors Bool whether to catch exceptions and just return false |
417 | | - * @return Bool whether execution was successful |
418 | | - */ |
419 | | - public function execute( array $data = null, $captureErrors = true){ |
420 | | - try { |
421 | | - // Set a new context so output doesn't leak. |
422 | | - $this->context = clone $this->page->getContext(); |
423 | | - if( is_array( $data ) ){ |
424 | | - $this->context->setRequest( new FauxRequest( $data, false ) ); |
425 | | - } |
426 | | - |
427 | | - // This will throw exceptions if there's a problem |
428 | | - $this->checkCanExecute( $this->getUser() ); |
429 | | - |
430 | | - $this->onView(); |
431 | | - return true; |
432 | | - } |
433 | | - catch ( ErrorPageError $e ){ |
434 | | - if( $captureErrors ){ |
435 | | - return false; |
436 | | - } else { |
437 | | - throw $e; |
438 | | - } |
439 | | - } |
440 | | - } |
441 | | -} |
\ No newline at end of file |
Index: trunk/phase3/includes/ProtectionForm.php |
— | — | @@ -317,9 +317,9 @@ |
318 | 318 | } |
319 | 319 | |
320 | 320 | if( $wgRequest->getCheck( 'mwProtectWatch' ) && $wgUser->isLoggedIn() ) { |
321 | | - Action::factory( 'watch', $this->mArticle )->execute(); |
| 321 | + $this->mArticle->doWatch(); |
322 | 322 | } elseif( $this->mTitle->userIsWatching() ) { |
323 | | - Action::factory( 'unwatch', $this->mArticle )->execute(); |
| 323 | + $this->mArticle->doUnwatch(); |
324 | 324 | } |
325 | 325 | return $ok; |
326 | 326 | } |
Index: trunk/phase3/includes/Article.php |
— | — | @@ -2345,10 +2345,27 @@ |
2346 | 2346 | |
2347 | 2347 | /** |
2348 | 2348 | * User-interface handler for the "watch" action |
2349 | | - * @deprecated since 1.18 |
2350 | 2349 | */ |
2351 | 2350 | public function watch() { |
2352 | | - Action::factory( 'watch', $this )->show(); |
| 2351 | + global $wgOut; |
| 2352 | + |
| 2353 | + if ( $wgOut->getUser()->isAnon() ) { |
| 2354 | + $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' ); |
| 2355 | + return; |
| 2356 | + } |
| 2357 | + |
| 2358 | + if ( wfReadOnly() ) { |
| 2359 | + $wgOut->readOnlyPage(); |
| 2360 | + return; |
| 2361 | + } |
| 2362 | + |
| 2363 | + if ( $this->doWatch() ) { |
| 2364 | + $wgOut->setPagetitle( wfMsg( 'addedwatch' ) ); |
| 2365 | + $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
| 2366 | + $wgOut->addWikiMsg( 'addedwatchtext', $this->mTitle->getPrefixedText() ); |
| 2367 | + } |
| 2368 | + |
| 2369 | + $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); |
2353 | 2370 | } |
2354 | 2371 | |
2355 | 2372 | /** |
— | — | @@ -2357,27 +2374,64 @@ |
2358 | 2375 | * This is safe to be called multiple times |
2359 | 2376 | * |
2360 | 2377 | * @return bool true on successful watch operation |
2361 | | - * @deprecated since 1.18 |
2362 | 2378 | */ |
2363 | 2379 | public function doWatch() { |
2364 | | - return Action::factory( 'watch', $this )->execute(); |
| 2380 | + global $wgUser; |
| 2381 | + |
| 2382 | + if ( $wgUser->isAnon() ) { |
| 2383 | + return false; |
| 2384 | + } |
| 2385 | + |
| 2386 | + if ( wfRunHooks( 'WatchArticle', array( &$wgUser, &$this ) ) ) { |
| 2387 | + $wgUser->addWatch( $this->mTitle ); |
| 2388 | + return wfRunHooks( 'WatchArticleComplete', array( &$wgUser, &$this ) ); |
| 2389 | + } |
| 2390 | + |
| 2391 | + return false; |
2365 | 2392 | } |
2366 | 2393 | |
2367 | 2394 | /** |
2368 | 2395 | * User interface handler for the "unwatch" action. |
2369 | | - * @deprecated since 1.18 |
2370 | 2396 | */ |
2371 | 2397 | public function unwatch() { |
2372 | | - Action::factory( 'unwatch', $this )->show(); |
| 2398 | + global $wgOut; |
| 2399 | + |
| 2400 | + if ( $wgOut->getUser()->isAnon() ) { |
| 2401 | + $wgOut->showErrorPage( 'watchnologin', 'watchnologintext' ); |
| 2402 | + return; |
| 2403 | + } |
| 2404 | + |
| 2405 | + if ( wfReadOnly() ) { |
| 2406 | + $wgOut->readOnlyPage(); |
| 2407 | + return; |
| 2408 | + } |
| 2409 | + |
| 2410 | + if ( $this->doUnwatch() ) { |
| 2411 | + $wgOut->setPagetitle( wfMsg( 'removedwatch' ) ); |
| 2412 | + $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
| 2413 | + $wgOut->addWikiMsg( 'removedwatchtext', $this->mTitle->getPrefixedText() ); |
| 2414 | + } |
| 2415 | + |
| 2416 | + $wgOut->returnToMain( true, $this->mTitle->getPrefixedText() ); |
2373 | 2417 | } |
2374 | 2418 | |
2375 | 2419 | /** |
2376 | 2420 | * Stop watching a page |
2377 | 2421 | * @return bool true on successful unwatch |
2378 | | - * @deprecated since 1.18 |
2379 | 2422 | */ |
2380 | 2423 | public function doUnwatch() { |
2381 | | - return Action::factory( 'unwatch', $this )->execute(); |
| 2424 | + global $wgUser; |
| 2425 | + |
| 2426 | + if ( $wgUser->isAnon() ) { |
| 2427 | + return false; |
| 2428 | + } |
| 2429 | + |
| 2430 | + if ( wfRunHooks( 'UnwatchArticle', array( &$wgUser, &$this ) ) ) { |
| 2431 | + $wgUser->removeWatch( $this->mTitle ); |
| 2432 | + return wfRunHooks( 'UnwatchArticleComplete', array( &$wgUser, &$this ) ); |
| 2433 | + } |
| 2434 | + |
| 2435 | + return false; |
2382 | 2436 | } |
2383 | 2437 | |
2384 | 2438 | /** |
— | — | @@ -2609,28 +2663,229 @@ |
2610 | 2664 | * @param &$hasHistory Boolean: whether the page has a history |
2611 | 2665 | * @return mixed String containing deletion reason or empty string, or boolean false |
2612 | 2666 | * if no revision occurred |
2613 | | - * @deprecated since 1.18 |
2614 | 2667 | */ |
2615 | 2668 | public function generateReason( &$hasHistory ) { |
2616 | | - return DeleteAction::getAutoReason( $this ); |
| 2669 | + global $wgContLang; |
| 2670 | + |
| 2671 | + $dbw = wfGetDB( DB_MASTER ); |
| 2672 | + // Get the last revision |
| 2673 | + $rev = Revision::newFromTitle( $this->mTitle ); |
| 2674 | + |
| 2675 | + if ( is_null( $rev ) ) { |
| 2676 | + return false; |
| 2677 | + } |
| 2678 | + |
| 2679 | + // Get the article's contents |
| 2680 | + $contents = $rev->getText(); |
| 2681 | + $blank = false; |
| 2682 | + |
| 2683 | + // If the page is blank, use the text from the previous revision, |
| 2684 | + // which can only be blank if there's a move/import/protect dummy revision involved |
| 2685 | + if ( $contents == '' ) { |
| 2686 | + $prev = $rev->getPrevious(); |
| 2687 | + |
| 2688 | + if ( $prev ) { |
| 2689 | + $contents = $prev->getText(); |
| 2690 | + $blank = true; |
| 2691 | + } |
| 2692 | + } |
| 2693 | + |
| 2694 | + // Find out if there was only one contributor |
| 2695 | + // Only scan the last 20 revisions |
| 2696 | + $res = $dbw->select( 'revision', 'rev_user_text', |
| 2697 | + array( 'rev_page' => $this->getID(), $dbw->bitAnd( 'rev_deleted', Revision::DELETED_USER ) . ' = 0' ), |
| 2698 | + __METHOD__, |
| 2699 | + array( 'LIMIT' => 20 ) |
| 2700 | + ); |
| 2701 | + |
| 2702 | + if ( $res === false ) { |
| 2703 | + // This page has no revisions, which is very weird |
| 2704 | + return false; |
| 2705 | + } |
| 2706 | + |
| 2707 | + $hasHistory = ( $res->numRows() > 1 ); |
| 2708 | + $row = $dbw->fetchObject( $res ); |
| 2709 | + |
| 2710 | + if ( $row ) { // $row is false if the only contributor is hidden |
| 2711 | + $onlyAuthor = $row->rev_user_text; |
| 2712 | + // Try to find a second contributor |
| 2713 | + foreach ( $res as $row ) { |
| 2714 | + if ( $row->rev_user_text != $onlyAuthor ) { // Bug 22999 |
| 2715 | + $onlyAuthor = false; |
| 2716 | + break; |
| 2717 | + } |
| 2718 | + } |
| 2719 | + } else { |
| 2720 | + $onlyAuthor = false; |
| 2721 | + } |
| 2722 | + |
| 2723 | + // Generate the summary with a '$1' placeholder |
| 2724 | + if ( $blank ) { |
| 2725 | + // The current revision is blank and the one before is also |
| 2726 | + // blank. It's just not our lucky day |
| 2727 | + $reason = wfMsgForContent( 'exbeforeblank', '$1' ); |
| 2728 | + } else { |
| 2729 | + if ( $onlyAuthor ) { |
| 2730 | + $reason = wfMsgForContent( 'excontentauthor', '$1', $onlyAuthor ); |
| 2731 | + } else { |
| 2732 | + $reason = wfMsgForContent( 'excontent', '$1' ); |
| 2733 | + } |
| 2734 | + } |
| 2735 | + |
| 2736 | + if ( $reason == '-' ) { |
| 2737 | + // Allow these UI messages to be blanked out cleanly |
| 2738 | + return ''; |
| 2739 | + } |
| 2740 | + |
| 2741 | + // Replace newlines with spaces to prevent uglyness |
| 2742 | + $contents = preg_replace( "/[\n\r]/", ' ', $contents ); |
| 2743 | + // Calculate the maximum amount of chars to get |
| 2744 | + // Max content length = max comment length - length of the comment (excl. $1) |
| 2745 | + $maxLength = 255 - ( strlen( $reason ) - 2 ); |
| 2746 | + $contents = $wgContLang->truncate( $contents, $maxLength ); |
| 2747 | + // Remove possible unfinished links |
| 2748 | + $contents = preg_replace( '/\[\[([^\]]*)\]?$/', '$1', $contents ); |
| 2749 | + // Now replace the '$1' placeholder |
| 2750 | + $reason = str_replace( '$1', $contents, $reason ); |
| 2751 | + |
| 2752 | + return $reason; |
2617 | 2753 | } |
2618 | 2754 | |
2619 | 2755 | |
2620 | 2756 | /* |
2621 | 2757 | * UI entry point for page deletion |
2622 | | - * @deprecated since 1.18 |
2623 | 2758 | */ |
2624 | 2759 | public function delete() { |
2625 | | - return Action::factory( 'delete', $this )->show(); |
| 2760 | + global $wgOut, $wgRequest; |
| 2761 | + |
| 2762 | + $confirm = $wgRequest->wasPosted() && |
| 2763 | + $wgOut->getUser()->matchEditToken( $wgRequest->getVal( 'wpEditToken' ) ); |
| 2764 | + |
| 2765 | + $this->DeleteReasonList = $wgRequest->getText( 'wpDeleteReasonList', 'other' ); |
| 2766 | + $this->DeleteReason = $wgRequest->getText( 'wpReason' ); |
| 2767 | + |
| 2768 | + $reason = $this->DeleteReasonList; |
| 2769 | + |
| 2770 | + if ( $reason != 'other' && $this->DeleteReason != '' ) { |
| 2771 | + // Entry from drop down menu + additional comment |
| 2772 | + $reason .= wfMsgForContent( 'colon-separator' ) . $this->DeleteReason; |
| 2773 | + } elseif ( $reason == 'other' ) { |
| 2774 | + $reason = $this->DeleteReason; |
| 2775 | + } |
| 2776 | + |
| 2777 | + # Flag to hide all contents of the archived revisions |
| 2778 | + $suppress = $wgRequest->getVal( 'wpSuppress' ) && $wgOut->getUser()->isAllowed( 'suppressrevision' ); |
| 2779 | + |
| 2780 | + # This code desperately needs to be totally rewritten |
| 2781 | + |
| 2782 | + # Read-only check... |
| 2783 | + if ( wfReadOnly() ) { |
| 2784 | + $wgOut->readOnlyPage(); |
| 2785 | + |
| 2786 | + return; |
| 2787 | + } |
| 2788 | + |
| 2789 | + # Check permissions |
| 2790 | + $permission_errors = $this->mTitle->getUserPermissionsErrors( 'delete', $wgOut->getUser() ); |
| 2791 | + |
| 2792 | + if ( count( $permission_errors ) > 0 ) { |
| 2793 | + $wgOut->showPermissionsErrorPage( $permission_errors ); |
| 2794 | + |
| 2795 | + return; |
| 2796 | + } |
| 2797 | + |
| 2798 | + $wgOut->setPagetitle( wfMsg( 'delete-confirm', $this->mTitle->getPrefixedText() ) ); |
| 2799 | + |
| 2800 | + # Better double-check that it hasn't been deleted yet! |
| 2801 | + $dbw = wfGetDB( DB_MASTER ); |
| 2802 | + $conds = $this->mTitle->pageCond(); |
| 2803 | + $latest = $dbw->selectField( 'page', 'page_latest', $conds, __METHOD__ ); |
| 2804 | + if ( $latest === false ) { |
| 2805 | + $wgOut->showFatalError( |
| 2806 | + Html::rawElement( |
| 2807 | + 'div', |
| 2808 | + array( 'class' => 'error mw-error-cannotdelete' ), |
| 2809 | + wfMsgExt( 'cannotdelete', array( 'parse' ), $this->mTitle->getPrefixedText() ) |
| 2810 | + ) |
| 2811 | + ); |
| 2812 | + $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) ); |
| 2813 | + LogEventsList::showLogExtract( |
| 2814 | + $wgOut, |
| 2815 | + 'delete', |
| 2816 | + $this->mTitle->getPrefixedText() |
| 2817 | + ); |
| 2818 | + |
| 2819 | + return; |
| 2820 | + } |
| 2821 | + |
| 2822 | + # Hack for big sites |
| 2823 | + $bigHistory = $this->isBigDeletion(); |
| 2824 | + if ( $bigHistory && !$this->mTitle->userCan( 'bigdelete' ) ) { |
| 2825 | + global $wgLang, $wgDeleteRevisionsLimit; |
| 2826 | + |
| 2827 | + $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n", |
| 2828 | + array( 'delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) ); |
| 2829 | + |
| 2830 | + return; |
| 2831 | + } |
| 2832 | + |
| 2833 | + if ( $confirm ) { |
| 2834 | + $this->doDelete( $reason, $suppress ); |
| 2835 | + |
| 2836 | + if ( $wgRequest->getCheck( 'wpWatch' ) && $wgOut->getUser()->isLoggedIn() ) { |
| 2837 | + $this->doWatch(); |
| 2838 | + } elseif ( $this->mTitle->userIsWatching() ) { |
| 2839 | + $this->doUnwatch(); |
| 2840 | + } |
| 2841 | + |
| 2842 | + return; |
| 2843 | + } |
| 2844 | + |
| 2845 | + // Generate deletion reason |
| 2846 | + $hasHistory = false; |
| 2847 | + if ( !$reason ) { |
| 2848 | + $reason = $this->generateReason( $hasHistory ); |
| 2849 | + } |
| 2850 | + |
| 2851 | + // If the page has a history, insert a warning |
| 2852 | + if ( $hasHistory && !$confirm ) { |
| 2853 | + global $wgLang; |
| 2854 | + |
| 2855 | + $skin = $wgOut->getSkin(); |
| 2856 | + $revisions = $this->estimateRevisionCount(); |
| 2857 | + //FIXME: lego |
| 2858 | + $wgOut->addHTML( '<strong class="mw-delete-warning-revisions">' . |
| 2859 | + wfMsgExt( 'historywarning', array( 'parseinline' ), $wgLang->formatNum( $revisions ) ) . |
| 2860 | + wfMsgHtml( 'word-separator' ) . $skin->link( $this->mTitle, |
| 2861 | + wfMsgHtml( 'history' ), |
| 2862 | + array( 'rel' => 'archives' ), |
| 2863 | + array( 'action' => 'history' ) ) . |
| 2864 | + '</strong>' |
| 2865 | + ); |
| 2866 | + |
| 2867 | + if ( $bigHistory ) { |
| 2868 | + global $wgDeleteRevisionsLimit; |
| 2869 | + $wgOut->wrapWikiMsg( "<div class='error'>\n$1\n</div>\n", |
| 2870 | + array( 'delete-warning-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) ); |
| 2871 | + } |
| 2872 | + } |
| 2873 | + |
| 2874 | + return $this->confirmDelete( $reason ); |
2626 | 2875 | } |
2627 | 2876 | |
2628 | 2877 | /** |
2629 | 2878 | * @return bool whether or not the page surpasses $wgDeleteRevisionsLimit revisions |
2630 | | - * @deprecated since 1.18 |
2631 | 2879 | */ |
2632 | 2880 | public function isBigDeletion() { |
2633 | 2881 | global $wgDeleteRevisionsLimit; |
2634 | | - return $wgDeleteRevisionsLimit && $this->estimateRevisionCount() > $wgDeleteRevisionsLimit; |
| 2882 | + |
| 2883 | + if ( $wgDeleteRevisionsLimit ) { |
| 2884 | + $revCount = $this->estimateRevisionCount(); |
| 2885 | + |
| 2886 | + return $revCount > $wgDeleteRevisionsLimit; |
| 2887 | + } |
| 2888 | + |
| 2889 | + return false; |
2635 | 2890 | } |
2636 | 2891 | |
2637 | 2892 | /** |
— | — | @@ -2699,19 +2954,150 @@ |
2700 | 2955 | } |
2701 | 2956 | |
2702 | 2957 | /** |
| 2958 | + * Output deletion confirmation dialog |
| 2959 | + * FIXME: Move to another file? |
| 2960 | + * @param $reason String: prefilled reason |
| 2961 | + */ |
| 2962 | + public function confirmDelete( $reason ) { |
| 2963 | + global $wgOut; |
| 2964 | + |
| 2965 | + wfDebug( "Article::confirmDelete\n" ); |
| 2966 | + |
| 2967 | + $deleteBackLink = $wgOut->getSkin()->linkKnown( $this->mTitle ); |
| 2968 | + $wgOut->setSubtitle( wfMsgHtml( 'delete-backlink', $deleteBackLink ) ); |
| 2969 | + $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
| 2970 | + $wgOut->addWikiMsg( 'confirmdeletetext' ); |
| 2971 | + |
| 2972 | + wfRunHooks( 'ArticleConfirmDelete', array( $this, $wgOut, &$reason ) ); |
| 2973 | + |
| 2974 | + if ( $wgOut->getUser()->isAllowed( 'suppressrevision' ) ) { |
| 2975 | + $suppress = "<tr id=\"wpDeleteSuppressRow\"> |
| 2976 | + <td></td> |
| 2977 | + <td class='mw-input'><strong>" . |
| 2978 | + Xml::checkLabel( wfMsg( 'revdelete-suppress' ), |
| 2979 | + 'wpSuppress', 'wpSuppress', false, array( 'tabindex' => '4' ) ) . |
| 2980 | + "</strong></td> |
| 2981 | + </tr>"; |
| 2982 | + } else { |
| 2983 | + $suppress = ''; |
| 2984 | + } |
| 2985 | + $checkWatch = $wgOut->getUser()->getBoolOption( 'watchdeletion' ) || $this->mTitle->userIsWatching(); |
| 2986 | + |
| 2987 | + $form = Xml::openElement( 'form', array( 'method' => 'post', |
| 2988 | + 'action' => $this->mTitle->getLocalURL( 'action=delete' ), 'id' => 'deleteconfirm' ) ) . |
| 2989 | + Xml::openElement( 'fieldset', array( 'id' => 'mw-delete-table' ) ) . |
| 2990 | + Xml::tags( 'legend', null, wfMsgExt( 'delete-legend', array( 'parsemag', 'escapenoentities' ) ) ) . |
| 2991 | + Xml::openElement( 'table', array( 'id' => 'mw-deleteconfirm-table' ) ) . |
| 2992 | + "<tr id=\"wpDeleteReasonListRow\"> |
| 2993 | + <td class='mw-label'>" . |
| 2994 | + Xml::label( wfMsg( 'deletecomment' ), 'wpDeleteReasonList' ) . |
| 2995 | + "</td> |
| 2996 | + <td class='mw-input'>" . |
| 2997 | + Xml::listDropDown( 'wpDeleteReasonList', |
| 2998 | + wfMsgForContent( 'deletereason-dropdown' ), |
| 2999 | + wfMsgForContent( 'deletereasonotherlist' ), '', 'wpReasonDropDown', 1 ) . |
| 3000 | + "</td> |
| 3001 | + </tr> |
| 3002 | + <tr id=\"wpDeleteReasonRow\"> |
| 3003 | + <td class='mw-label'>" . |
| 3004 | + Xml::label( wfMsg( 'deleteotherreason' ), 'wpReason' ) . |
| 3005 | + "</td> |
| 3006 | + <td class='mw-input'>" . |
| 3007 | + Html::input( 'wpReason', $reason, 'text', array( |
| 3008 | + 'size' => '60', |
| 3009 | + 'maxlength' => '255', |
| 3010 | + 'tabindex' => '2', |
| 3011 | + 'id' => 'wpReason', |
| 3012 | + 'autofocus' |
| 3013 | + ) ) . |
| 3014 | + "</td> |
| 3015 | + </tr>"; |
| 3016 | + |
| 3017 | + # Disallow watching if user is not logged in |
| 3018 | + if ( $wgOut->getUser()->isLoggedIn() ) { |
| 3019 | + $form .= " |
| 3020 | + <tr> |
| 3021 | + <td></td> |
| 3022 | + <td class='mw-input'>" . |
| 3023 | + Xml::checkLabel( wfMsg( 'watchthis' ), |
| 3024 | + 'wpWatch', 'wpWatch', $checkWatch, array( 'tabindex' => '3' ) ) . |
| 3025 | + "</td> |
| 3026 | + </tr>"; |
| 3027 | + } |
| 3028 | + |
| 3029 | + $form .= " |
| 3030 | + $suppress |
| 3031 | + <tr> |
| 3032 | + <td></td> |
| 3033 | + <td class='mw-submit'>" . |
| 3034 | + Xml::submitButton( wfMsg( 'deletepage' ), |
| 3035 | + array( 'name' => 'wpConfirmB', 'id' => 'wpConfirmB', 'tabindex' => '5' ) ) . |
| 3036 | + "</td> |
| 3037 | + </tr>" . |
| 3038 | + Xml::closeElement( 'table' ) . |
| 3039 | + Xml::closeElement( 'fieldset' ) . |
| 3040 | + Html::hidden( 'wpEditToken', $wgOut->getUser()->editToken() ) . |
| 3041 | + Xml::closeElement( 'form' ); |
| 3042 | + |
| 3043 | + if ( $wgOut->getUser()->isAllowed( 'editinterface' ) ) { |
| 3044 | + $skin = $wgOut->getSkin(); |
| 3045 | + $title = Title::makeTitle( NS_MEDIAWIKI, 'Deletereason-dropdown' ); |
| 3046 | + $link = $skin->link( |
| 3047 | + $title, |
| 3048 | + wfMsgHtml( 'delete-edit-reasonlist' ), |
| 3049 | + array(), |
| 3050 | + array( 'action' => 'edit' ) |
| 3051 | + ); |
| 3052 | + $form .= '<p class="mw-delete-editreasons">' . $link . '</p>'; |
| 3053 | + } |
| 3054 | + |
| 3055 | + $wgOut->addHTML( $form ); |
| 3056 | + $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) ); |
| 3057 | + LogEventsList::showLogExtract( $wgOut, 'delete', |
| 3058 | + $this->mTitle->getPrefixedText() |
| 3059 | + ); |
| 3060 | + } |
| 3061 | + |
| 3062 | + /** |
2703 | 3063 | * Perform a deletion and output success or failure messages |
2704 | | - * @deprecated since 1.18 |
2705 | 3064 | */ |
2706 | 3065 | public function doDelete( $reason, $suppress = false ) { |
2707 | | - return DeleteAction::doDeleteArticle( |
2708 | | - $this, |
2709 | | - $this->getContext(), |
2710 | | - array( |
2711 | | - 'Suppress' => $suppress !== false, |
2712 | | - 'Reason' => $reason, |
2713 | | - ), |
2714 | | - true |
2715 | | - ); |
| 3066 | + global $wgOut; |
| 3067 | + |
| 3068 | + $id = $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE ); |
| 3069 | + |
| 3070 | + $error = ''; |
| 3071 | + if ( $this->doDeleteArticle( $reason, $suppress, $id, $error ) ) { |
| 3072 | + $deleted = $this->mTitle->getPrefixedText(); |
| 3073 | + |
| 3074 | + $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) ); |
| 3075 | + $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
| 3076 | + |
| 3077 | + $loglink = '[[Special:Log/delete|' . wfMsgNoTrans( 'deletionlog' ) . ']]'; |
| 3078 | + |
| 3079 | + $wgOut->addWikiMsg( 'deletedtext', $deleted, $loglink ); |
| 3080 | + $wgOut->returnToMain( false ); |
| 3081 | + } else { |
| 3082 | + if ( $error == '' ) { |
| 3083 | + $wgOut->showFatalError( |
| 3084 | + Html::rawElement( |
| 3085 | + 'div', |
| 3086 | + array( 'class' => 'error mw-error-cannotdelete' ), |
| 3087 | + wfMsgExt( 'cannotdelete', array( 'parse' ), $this->mTitle->getPrefixedText() ) |
| 3088 | + ) |
| 3089 | + ); |
| 3090 | + |
| 3091 | + $wgOut->addHTML( Xml::element( 'h2', null, LogPage::logName( 'delete' ) ) ); |
| 3092 | + |
| 3093 | + LogEventsList::showLogExtract( |
| 3094 | + $wgOut, |
| 3095 | + 'delete', |
| 3096 | + $this->mTitle->getPrefixedText() |
| 3097 | + ); |
| 3098 | + } else { |
| 3099 | + $wgOut->showFatalError( $error ); |
| 3100 | + } |
| 3101 | + } |
2716 | 3102 | } |
2717 | 3103 | |
2718 | 3104 | /** |
— | — | @@ -2727,19 +3113,143 @@ |
2728 | 3114 | * @param $id int article ID |
2729 | 3115 | * @param $commit boolean defaults to true, triggers transaction end |
2730 | 3116 | * @return boolean true if successful |
2731 | | - * |
2732 | | - * @deprecated since 1.18 |
2733 | 3117 | */ |
2734 | 3118 | public function doDeleteArticle( $reason, $suppress = false, $id = 0, $commit = true, &$error = '' ) { |
2735 | | - return DeleteAction::doDeleteArticle( |
2736 | | - $this, |
2737 | | - $this->getContext(), |
| 3119 | + global $wgDeferredUpdateList, $wgUseTrackbacks; |
| 3120 | + global $wgUser; |
| 3121 | + |
| 3122 | + wfDebug( __METHOD__ . "\n" ); |
| 3123 | + |
| 3124 | + if ( ! wfRunHooks( 'ArticleDelete', array( &$this, &$wgUser, &$reason, &$error ) ) ) { |
| 3125 | + return false; |
| 3126 | + } |
| 3127 | + $dbw = wfGetDB( DB_MASTER ); |
| 3128 | + $t = $this->mTitle->getDBkey(); |
| 3129 | + $id = $id ? $id : $this->mTitle->getArticleID( Title::GAID_FOR_UPDATE ); |
| 3130 | + |
| 3131 | + if ( $t === '' || $id == 0 ) { |
| 3132 | + return false; |
| 3133 | + } |
| 3134 | + |
| 3135 | + $u = new SiteStatsUpdate( 0, 1, - (int)$this->isCountable( $this->getRawText() ), -1 ); |
| 3136 | + array_push( $wgDeferredUpdateList, $u ); |
| 3137 | + |
| 3138 | + // Bitfields to further suppress the content |
| 3139 | + if ( $suppress ) { |
| 3140 | + $bitfield = 0; |
| 3141 | + // This should be 15... |
| 3142 | + $bitfield |= Revision::DELETED_TEXT; |
| 3143 | + $bitfield |= Revision::DELETED_COMMENT; |
| 3144 | + $bitfield |= Revision::DELETED_USER; |
| 3145 | + $bitfield |= Revision::DELETED_RESTRICTED; |
| 3146 | + } else { |
| 3147 | + $bitfield = 'rev_deleted'; |
| 3148 | + } |
| 3149 | + |
| 3150 | + $dbw->begin(); |
| 3151 | + // For now, shunt the revision data into the archive table. |
| 3152 | + // Text is *not* removed from the text table; bulk storage |
| 3153 | + // is left intact to avoid breaking block-compression or |
| 3154 | + // immutable storage schemes. |
| 3155 | + // |
| 3156 | + // For backwards compatibility, note that some older archive |
| 3157 | + // table entries will have ar_text and ar_flags fields still. |
| 3158 | + // |
| 3159 | + // In the future, we may keep revisions and mark them with |
| 3160 | + // the rev_deleted field, which is reserved for this purpose. |
| 3161 | + $dbw->insertSelect( 'archive', array( 'page', 'revision' ), |
2738 | 3162 | array( |
2739 | | - 'Suppress' => $suppress !== false, |
2740 | | - 'Reason' => $reason, |
2741 | | - ), |
2742 | | - $commit |
| 3163 | + 'ar_namespace' => 'page_namespace', |
| 3164 | + 'ar_title' => 'page_title', |
| 3165 | + 'ar_comment' => 'rev_comment', |
| 3166 | + 'ar_user' => 'rev_user', |
| 3167 | + 'ar_user_text' => 'rev_user_text', |
| 3168 | + 'ar_timestamp' => 'rev_timestamp', |
| 3169 | + 'ar_minor_edit' => 'rev_minor_edit', |
| 3170 | + 'ar_rev_id' => 'rev_id', |
| 3171 | + 'ar_text_id' => 'rev_text_id', |
| 3172 | + 'ar_text' => '\'\'', // Be explicit to appease |
| 3173 | + 'ar_flags' => '\'\'', // MySQL's "strict mode"... |
| 3174 | + 'ar_len' => 'rev_len', |
| 3175 | + 'ar_page_id' => 'page_id', |
| 3176 | + 'ar_deleted' => $bitfield |
| 3177 | + ), array( |
| 3178 | + 'page_id' => $id, |
| 3179 | + 'page_id = rev_page' |
| 3180 | + ), __METHOD__ |
2743 | 3181 | ); |
| 3182 | + |
| 3183 | + # Delete restrictions for it |
| 3184 | + $dbw->delete( 'page_restrictions', array ( 'pr_page' => $id ), __METHOD__ ); |
| 3185 | + |
| 3186 | + # Now that it's safely backed up, delete it |
| 3187 | + $dbw->delete( 'page', array( 'page_id' => $id ), __METHOD__ ); |
| 3188 | + $ok = ( $dbw->affectedRows() > 0 ); // getArticleId() uses slave, could be laggy |
| 3189 | + |
| 3190 | + if ( !$ok ) { |
| 3191 | + $dbw->rollback(); |
| 3192 | + return false; |
| 3193 | + } |
| 3194 | + |
| 3195 | + # Fix category table counts |
| 3196 | + $cats = array(); |
| 3197 | + $res = $dbw->select( 'categorylinks', 'cl_to', array( 'cl_from' => $id ), __METHOD__ ); |
| 3198 | + |
| 3199 | + foreach ( $res as $row ) { |
| 3200 | + $cats [] = $row->cl_to; |
| 3201 | + } |
| 3202 | + |
| 3203 | + $this->updateCategoryCounts( array(), $cats ); |
| 3204 | + |
| 3205 | + # If using cascading deletes, we can skip some explicit deletes |
| 3206 | + if ( !$dbw->cascadingDeletes() ) { |
| 3207 | + $dbw->delete( 'revision', array( 'rev_page' => $id ), __METHOD__ ); |
| 3208 | + |
| 3209 | + if ( $wgUseTrackbacks ) |
| 3210 | + $dbw->delete( 'trackbacks', array( 'tb_page' => $id ), __METHOD__ ); |
| 3211 | + |
| 3212 | + # Delete outgoing links |
| 3213 | + $dbw->delete( 'pagelinks', array( 'pl_from' => $id ) ); |
| 3214 | + $dbw->delete( 'imagelinks', array( 'il_from' => $id ) ); |
| 3215 | + $dbw->delete( 'categorylinks', array( 'cl_from' => $id ) ); |
| 3216 | + $dbw->delete( 'templatelinks', array( 'tl_from' => $id ) ); |
| 3217 | + $dbw->delete( 'externallinks', array( 'el_from' => $id ) ); |
| 3218 | + $dbw->delete( 'langlinks', array( 'll_from' => $id ) ); |
| 3219 | + $dbw->delete( 'redirect', array( 'rd_from' => $id ) ); |
| 3220 | + } |
| 3221 | + |
| 3222 | + # If using cleanup triggers, we can skip some manual deletes |
| 3223 | + if ( !$dbw->cleanupTriggers() ) { |
| 3224 | + # Clean up recentchanges entries... |
| 3225 | + $dbw->delete( 'recentchanges', |
| 3226 | + array( 'rc_type != ' . RC_LOG, |
| 3227 | + 'rc_namespace' => $this->mTitle->getNamespace(), |
| 3228 | + 'rc_title' => $this->mTitle->getDBkey() ), |
| 3229 | + __METHOD__ ); |
| 3230 | + $dbw->delete( 'recentchanges', |
| 3231 | + array( 'rc_type != ' . RC_LOG, 'rc_cur_id' => $id ), |
| 3232 | + __METHOD__ ); |
| 3233 | + } |
| 3234 | + |
| 3235 | + # Clear caches |
| 3236 | + Article::onArticleDelete( $this->mTitle ); |
| 3237 | + |
| 3238 | + # Clear the cached article id so the interface doesn't act like we exist |
| 3239 | + $this->mTitle->resetArticleID( 0 ); |
| 3240 | + |
| 3241 | + # Log the deletion, if the page was suppressed, log it at Oversight instead |
| 3242 | + $logtype = $suppress ? 'suppress' : 'delete'; |
| 3243 | + $log = new LogPage( $logtype ); |
| 3244 | + |
| 3245 | + # Make sure logging got through |
| 3246 | + $log->addEntry( 'delete', $this->mTitle, $reason, array() ); |
| 3247 | + |
| 3248 | + if ( $commit ) { |
| 3249 | + $dbw->commit(); |
| 3250 | + } |
| 3251 | + |
| 3252 | + wfRunHooks( 'ArticleDeleteComplete', array( &$this, &$wgUser, $reason, $id ) ); |
| 3253 | + return true; |
2744 | 3254 | } |
2745 | 3255 | |
2746 | 3256 | /** |
Index: trunk/phase3/includes/Setup.php |
— | — | @@ -270,14 +270,6 @@ |
271 | 271 | $wgHiddenPrefs[] = 'enotifminoredits'; |
272 | 272 | } |
273 | 273 | |
274 | | -# $wgDisabledActions is deprecated as of 1.18 |
275 | | -foreach( $wgDisabledActions as $action ){ |
276 | | - $wgActions[$action] = false; |
277 | | -} |
278 | | -if( !$wgAllowPageInfo ){ |
279 | | - $wgActions['info'] = false; |
280 | | -} |
281 | | - |
282 | 274 | if ( !$wgHtml5Version && $wgHtml5 && $wgAllowRdfaAttributes ) { |
283 | 275 | # see http://www.w3.org/TR/rdfa-in-html/#document-conformance |
284 | 276 | if ( $wgMimeType == 'application/xhtml+xml' ) { |
Index: trunk/phase3/includes/EditPage.php |
— | — | @@ -1153,9 +1153,9 @@ |
1154 | 1154 | $dbw = wfGetDB( DB_MASTER ); |
1155 | 1155 | $dbw->begin(); |
1156 | 1156 | if ( $this->watchthis ) { |
1157 | | - Action::factory( 'watch', $this->mArticle )->execute(); |
| 1157 | + $this->mArticle->doWatch(); |
1158 | 1158 | } else { |
1159 | | - Action::factory( 'watch', $this->mArticle )->execute(); |
| 1159 | + $this->mArticle->doUnwatch(); |
1160 | 1160 | } |
1161 | 1161 | $dbw->commit(); |
1162 | 1162 | } |
Index: trunk/phase3/includes/api/ApiWatch.php |
— | — | @@ -59,11 +59,11 @@ |
60 | 60 | if ( $params['unwatch'] ) { |
61 | 61 | $res['unwatched'] = ''; |
62 | 62 | $res['message'] = wfMsgExt( 'removedwatchtext', array( 'parse' ), $title->getPrefixedText() ); |
63 | | - $success = Action::factory( 'unwatch', $article )->execute(); |
| 63 | + $success = $article->doUnwatch(); |
64 | 64 | } else { |
65 | 65 | $res['watched'] = ''; |
66 | 66 | $res['message'] = wfMsgExt( 'addedwatchtext', array( 'parse' ), $title->getPrefixedText() ); |
67 | | - $success = Action::factory( 'watch', $article )->execute(); |
| 67 | + $success = $article->doWatch(); |
68 | 68 | } |
69 | 69 | if ( !$success ) { |
70 | 70 | $this->dieUsageMsg( array( 'hookaborted' ) ); |
Index: trunk/phase3/includes/api/ApiDelete.php |
— | — | @@ -123,6 +123,11 @@ |
124 | 124 | * @return Title::getUserPermissionsErrors()-like array |
125 | 125 | */ |
126 | 126 | public static function delete( &$article, $token, &$reason = null ) { |
| 127 | + global $wgUser; |
| 128 | + if ( $article->isBigDeletion() && !$wgUser->isAllowed( 'bigdelete' ) ) { |
| 129 | + global $wgDeleteRevisionsLimit; |
| 130 | + return array( array( 'delete-toobig', $wgDeleteRevisionsLimit ) ); |
| 131 | + } |
127 | 132 | $title = $article->getTitle(); |
128 | 133 | $errors = self::getPermissionsError( $title, $token ); |
129 | 134 | if ( count( $errors ) ) { |
— | — | @@ -131,29 +136,22 @@ |
132 | 137 | |
133 | 138 | // Auto-generate a summary, if necessary |
134 | 139 | if ( is_null( $reason ) ) { |
135 | | - $reason = DeleteAction::getAutoReason( $article ); |
| 140 | + // Need to pass a throwaway variable because generateReason expects |
| 141 | + // a reference |
| 142 | + $hasHistory = false; |
| 143 | + $reason = $article->generateReason( $hasHistory ); |
136 | 144 | if ( $reason === false ) { |
137 | 145 | return array( array( 'cannotdelete' ) ); |
138 | 146 | } |
139 | 147 | } |
140 | 148 | |
141 | | - $action = Action::factory( 'delete', $article ); |
142 | | - $data = array( |
143 | | - 'Reason' => $reason, |
144 | | - 'Suppress' => false, // The thought of people doing this through the API is scary... |
145 | | - ); |
146 | | - |
147 | | - try { |
148 | | - $action->execute( $data, false ); |
| 149 | + $error = ''; |
| 150 | + // Luckily, Article.php provides a reusable delete function that does the hard work for us |
| 151 | + if ( $article->doDeleteArticle( $reason, false, 0, true, $error ) ) { |
| 152 | + return array(); |
| 153 | + } else { |
| 154 | + return array( array( 'cannotdelete', $article->mTitle->getPrefixedText() ) ); |
149 | 155 | } |
150 | | - catch ( ErrorPageError $e ){ |
151 | | - if( $e->msg == 'delete-toobig' ){ |
152 | | - global $wgDeleteRevisionsLimit; |
153 | | - return array( array( 'delete-toobig', $wgDeleteRevisionsLimit ) ); |
154 | | - } else { |
155 | | - array( array( 'cannotdelete', $article->mTitle->getPrefixedText() ) ); |
156 | | - } |
157 | | - } |
158 | 156 | } |
159 | 157 | |
160 | 158 | /** |
Index: trunk/phase3/includes/api/ApiBase.php |
— | — | @@ -645,9 +645,9 @@ |
646 | 646 | |
647 | 647 | $articleObj = new Article( $titleObj ); |
648 | 648 | if ( $value ) { |
649 | | - Action::factory( 'watch', $articleObj )->execute(); |
| 649 | + $articleObj->doWatch(); |
650 | 650 | } else { |
651 | | - Action::factory( 'unwatch', $articleObj )->execute(); |
| 651 | + $articleObj->doUnwatch(); |
652 | 652 | } |
653 | 653 | } |
654 | 654 | |
Index: trunk/phase3/includes/AutoLoader.php |
— | — | @@ -14,7 +14,6 @@ |
15 | 15 | |
16 | 16 | $wgAutoloadLocalClasses = array( |
17 | 17 | # Includes |
18 | | - 'Action' => 'includes/Action.php', |
19 | 18 | 'AjaxDispatcher' => 'includes/AjaxDispatcher.php', |
20 | 19 | 'AjaxResponse' => 'includes/AjaxResponse.php', |
21 | 20 | 'AlphabeticPager' => 'includes/Pager.php', |
— | — | @@ -52,6 +51,7 @@ |
53 | 52 | 'ConfEditorToken' => 'includes/ConfEditor.php', |
54 | 53 | 'ConstantDependency' => 'includes/CacheDependency.php', |
55 | 54 | 'CreativeCommonsRdf' => 'includes/Metadata.php', |
| 55 | + 'Credits' => 'includes/Credits.php', |
56 | 56 | 'CSSJanus' => 'includes/libs/CSSJanus.php', |
57 | 57 | 'CSSMin' => 'includes/libs/CSSMin.php', |
58 | 58 | 'DependencyWrapper' => 'includes/CacheDependency.php', |
— | — | @@ -274,12 +274,6 @@ |
275 | 275 | 'ZhClient' => 'includes/ZhClient.php', |
276 | 276 | 'ZipDirectoryReader' => 'includes/ZipDirectoryReader.php', |
277 | 277 | |
278 | | - # includes/actions |
279 | | - 'CreditsAction' => 'includes/actions/CreditsAction.php', |
280 | | - 'DeleteAction' => 'includes/actions/DeleteAction.php', |
281 | | - 'UnwatchAction' => 'includes/actions/WatchAction.php', |
282 | | - 'WatchAction' => 'includes/actions/WatchAction.php', |
283 | | - |
284 | 278 | # includes/api |
285 | 279 | 'ApiBase' => 'includes/api/ApiBase.php', |
286 | 280 | 'ApiBlock' => 'includes/api/ApiBlock.php', |
Index: trunk/phase3/includes/Wiki.php |
— | — | @@ -471,16 +471,9 @@ |
472 | 472 | return; |
473 | 473 | } |
474 | 474 | |
475 | | - $act = $this->getAction(); |
| 475 | + $action = $this->getAction(); |
476 | 476 | |
477 | | - $action = Action::factory( $this->getAction(), $article ); |
478 | | - if( $action instanceof Action ){ |
479 | | - $action->show(); |
480 | | - wfProfileOut( __METHOD__ ); |
481 | | - return; |
482 | | - } |
483 | | - |
484 | | - switch( $act ) { |
| 477 | + switch( $action ) { |
485 | 478 | case 'view': |
486 | 479 | $this->context->output->setSquidMaxage( $this->getVal( 'SquidMaxage' ) ); |
487 | 480 | $article->view(); |
— | — | @@ -491,6 +484,9 @@ |
492 | 485 | $raw->view(); |
493 | 486 | wfProfileOut( __METHOD__ . '-raw' ); |
494 | 487 | break; |
| 488 | + case 'watch': |
| 489 | + case 'unwatch': |
| 490 | + case 'delete': |
495 | 491 | case 'revert': |
496 | 492 | case 'rollback': |
497 | 493 | case 'protect': |
— | — | @@ -500,7 +496,7 @@ |
501 | 497 | case 'render': |
502 | 498 | case 'deletetrackback': |
503 | 499 | case 'purge': |
504 | | - $article->$act(); |
| 500 | + $article->$action(); |
505 | 501 | break; |
506 | 502 | case 'print': |
507 | 503 | $article->view(); |
— | — | @@ -521,6 +517,9 @@ |
522 | 518 | $rdf->show(); |
523 | 519 | } |
524 | 520 | break; |
| 521 | + case 'credits': |
| 522 | + Credits::showPage( $article ); |
| 523 | + break; |
525 | 524 | case 'submit': |
526 | 525 | if ( session_id() == '' ) { |
527 | 526 | // Send a cookie so anons get talk message notifications |
— | — | @@ -533,7 +532,7 @@ |
534 | 533 | $external = $this->context->request->getVal( 'externaledit' ); |
535 | 534 | $section = $this->context->request->getVal( 'section' ); |
536 | 535 | $oldid = $this->context->request->getVal( 'oldid' ); |
537 | | - if ( !$this->getVal( 'UseExternalEditor' ) || $act == 'submit' || $internal || |
| 536 | + if ( !$this->getVal( 'UseExternalEditor' ) || $action == 'submit' || $internal || |
538 | 537 | $section || $oldid || ( !$this->context->user->getOption( 'externaleditor' ) && !$external ) ) { |
539 | 538 | $editor = new EditPage( $article ); |
540 | 539 | $editor->submit(); |
— | — | @@ -562,7 +561,7 @@ |
563 | 562 | $special->execute( '' ); |
564 | 563 | break; |
565 | 564 | default: |
566 | | - if ( wfRunHooks( 'UnknownAction', array( $act, $article ) ) ) { |
| 565 | + if ( wfRunHooks( 'UnknownAction', array( $action, $article ) ) ) { |
567 | 566 | $this->context->output->showErrorPage( 'nosuchaction', 'nosuchactiontext' ); |
568 | 567 | } |
569 | 568 | } |
Index: trunk/phase3/includes/FileDeleteForm.php |
— | — | @@ -125,9 +125,9 @@ |
126 | 126 | if( $article->doDeleteArticle( $reason, $suppress, $id, false ) ) { |
127 | 127 | global $wgRequest; |
128 | 128 | if( $wgRequest->getCheck( 'wpWatch' ) && $wgUser->isLoggedIn() ) { |
129 | | - Action::factory( 'watch', $article )->execute(); |
| 129 | + $article->doWatch(); |
130 | 130 | } elseif( $title->userIsWatching() ) { |
131 | | - Action::factory( 'unwatch', $article )->execute(); |
| 131 | + $article->doUnwatch(); |
132 | 132 | } |
133 | 133 | $status = $file->delete( $reason, $suppress ); |
134 | 134 | if( $status->ok ) { |
Index: trunk/phase3/includes/DefaultSettings.php |
— | — | @@ -27,10 +27,12 @@ |
28 | 28 | } |
29 | 29 | |
30 | 30 | # Create a site configuration object. Not used for much in a default install |
31 | | -if ( !defined( 'MW_COMPILED' ) ) { |
32 | | - require_once( "$IP/includes/SiteConfiguration.php" ); |
| 31 | +if ( !defined( 'MW_PHP4' ) ) { |
| 32 | + if ( !defined( 'MW_COMPILED' ) ) { |
| 33 | + require_once( "$IP/includes/SiteConfiguration.php" ); |
| 34 | + } |
| 35 | + $wgConf = new SiteConfiguration; |
33 | 36 | } |
34 | | -$wgConf = new SiteConfiguration; |
35 | 37 | /** @endcond */ |
36 | 38 | |
37 | 39 | /** MediaWiki version number */ |
— | — | @@ -5022,38 +5024,6 @@ |
5023 | 5025 | /** @} */ # end special pages } |
5024 | 5026 | |
5025 | 5027 | /*************************************************************************//** |
5026 | | - * @name Actions |
5027 | | - * @{ |
5028 | | - */ |
5029 | | - |
5030 | | -/** |
5031 | | - * Array of allowed values for the title=foo&action=<action> parameter. Syntax is: |
5032 | | - * 'foo' => 'ClassName' Load the specified class which subclasses Action |
5033 | | - * 'foo' => true Load the class FooAction which subclasses Action |
5034 | | - * 'foo' => false The action is disabled; show an error message |
5035 | | - * Unsetting core actions will probably cause things to complain loudly. |
5036 | | - */ |
5037 | | -$wgActions = array( |
5038 | | - 'credits' => true, |
5039 | | - 'delete' => true, |
5040 | | - 'unwatch' => true, |
5041 | | - 'watch' => true, |
5042 | | -); |
5043 | | - |
5044 | | -/** |
5045 | | - * Array of disabled article actions, e.g. view, edit, dublincore, delete, etc. |
5046 | | - * @deprecated since 1.18; just set $wgActions['action'] = false instead |
5047 | | - */ |
5048 | | -$wgDisabledActions = array(); |
5049 | | - |
5050 | | -/** |
5051 | | - * Allow the "info" action, very inefficient at the moment |
5052 | | - */ |
5053 | | -$wgAllowPageInfo = false; |
5054 | | - |
5055 | | -/** @} */ # end actions } |
5056 | | - |
5057 | | -/*************************************************************************//** |
5058 | 5028 | * @name Robot (search engine crawler) policy |
5059 | 5029 | * See also $wgNoFollowLinks. |
5060 | 5030 | * @{ |
— | — | @@ -5318,10 +5288,18 @@ |
5319 | 5289 | * @{ |
5320 | 5290 | */ |
5321 | 5291 | |
| 5292 | +/** Allow the "info" action, very inefficient at the moment */ |
| 5293 | +$wgAllowPageInfo = false; |
| 5294 | + |
5322 | 5295 | /** Name of the external diff engine to use */ |
5323 | 5296 | $wgExternalDiffEngine = false; |
5324 | 5297 | |
5325 | 5298 | /** |
| 5299 | + * Array of disabled article actions, e.g. view, edit, dublincore, delete, etc. |
| 5300 | + */ |
| 5301 | +$wgDisabledActions = array(); |
| 5302 | + |
| 5303 | +/** |
5326 | 5304 | * Disable redirects to special pages and interwiki redirects, which use a 302 |
5327 | 5305 | * and have no "redirected from" link. Note this is only for articles with #Redirect |
5328 | 5306 | * in them. URL's containing a local interwiki prefix (or a non-canonical special |
Index: trunk/phase3/includes/specials/SpecialMovepage.php |
— | — | @@ -359,11 +359,8 @@ |
360 | 360 | $article = new Article( $nt ); |
361 | 361 | |
362 | 362 | # Disallow deletions of big articles |
363 | | - global $wgDeleteRevisionsLimit; |
364 | | - if ( $wgDeleteRevisionsLimit |
365 | | - && $this->estimateRevisionCount() > $wgDeleteRevisionsLimit |
366 | | - && !$nt->userCan( 'bigdelete' ) ) |
367 | | - { |
| 363 | + $bigHistory = $article->isBigDeletion(); |
| 364 | + if( $bigHistory && !$nt->userCan( 'bigdelete' ) ) { |
368 | 365 | global $wgDeleteRevisionsLimit; |
369 | 366 | $this->showForm( array('delete-toobig', $wgLang->formatNum( $wgDeleteRevisionsLimit ) ) ); |
370 | 367 | return; |
— | — | @@ -376,10 +373,7 @@ |
377 | 374 | } |
378 | 375 | |
379 | 376 | // This may output an error message and exit |
380 | | - Action::factory( 'delete', $article )->execute( |
381 | | - array( 'Reason' => wfMsgForContent( 'delete_and_move_reason' ) ), |
382 | | - false // Do not capture exceptions |
383 | | - ); |
| 377 | + $article->doDelete( wfMsgForContent( 'delete_and_move_reason' ) ); |
384 | 378 | } |
385 | 379 | |
386 | 380 | # don't allow moving to pages with # in |
Index: trunk/phase3/includes/Credits.php |
— | — | @@ -0,0 +1,238 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Formats credits for articles |
| 5 | + * |
| 6 | + * Copyright 2004, Evan Prodromou <evan@wikitravel.org>. |
| 7 | + * |
| 8 | + * This program is free software; you can redistribute it and/or modify |
| 9 | + * it under the terms of the GNU General Public License as published by |
| 10 | + * the Free Software Foundation; either version 2 of the License, or |
| 11 | + * (at your option) any later version. |
| 12 | + * |
| 13 | + * This program is distributed in the hope that it will be useful, |
| 14 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 15 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 16 | + * GNU General Public License for more details. |
| 17 | + * |
| 18 | + * You should have received a copy of the GNU General Public License |
| 19 | + * along with this program; if not, write to the Free Software |
| 20 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| 21 | + * |
| 22 | + * @file |
| 23 | + * @author <evan@wikitravel.org> |
| 24 | + */ |
| 25 | + |
| 26 | +class Credits { |
| 27 | + /** |
| 28 | + * This is largely cadged from PageHistory::history |
| 29 | + * @param $article Article object |
| 30 | + */ |
| 31 | + public static function showPage( Article $article ) { |
| 32 | + global $wgOut; |
| 33 | + |
| 34 | + wfProfileIn( __METHOD__ ); |
| 35 | + |
| 36 | + $wgOut->setPageTitle( $article->mTitle->getPrefixedText() ); |
| 37 | + $wgOut->setSubtitle( wfMsg( 'creditspage' ) ); |
| 38 | + $wgOut->setArticleFlag( false ); |
| 39 | + $wgOut->setArticleRelated( true ); |
| 40 | + $wgOut->setRobotPolicy( 'noindex,nofollow' ); |
| 41 | + |
| 42 | + if ( $article->mTitle->getArticleID() == 0 ) { |
| 43 | + $s = wfMsg( 'nocredits' ); |
| 44 | + } else { |
| 45 | + $s = self::getCredits( $article, -1 ); |
| 46 | + } |
| 47 | + |
| 48 | + $wgOut->addHTML( $s ); |
| 49 | + |
| 50 | + wfProfileOut( __METHOD__ ); |
| 51 | + } |
| 52 | + |
| 53 | + /** |
| 54 | + * Get a list of contributors of $article |
| 55 | + * @param $article Article object |
| 56 | + * @param $cnt Int: maximum list of contributors to show |
| 57 | + * @param $showIfMax Bool: whether to contributors if there more than $cnt |
| 58 | + * @return String: html |
| 59 | + */ |
| 60 | + public static function getCredits( Article $article, $cnt, $showIfMax = true ) { |
| 61 | + wfProfileIn( __METHOD__ ); |
| 62 | + $s = ''; |
| 63 | + |
| 64 | + if ( isset( $cnt ) && $cnt != 0 ) { |
| 65 | + $s = self::getAuthor( $article ); |
| 66 | + if ( $cnt > 1 || $cnt < 0 ) { |
| 67 | + $s .= ' ' . self::getContributors( $article, $cnt - 1, $showIfMax ); |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + wfProfileOut( __METHOD__ ); |
| 72 | + return $s; |
| 73 | + } |
| 74 | + |
| 75 | + /** |
| 76 | + * Get the last author with the last modification time |
| 77 | + * @param $article Article object |
| 78 | + */ |
| 79 | + protected static function getAuthor( Article $article ) { |
| 80 | + global $wgLang; |
| 81 | + |
| 82 | + $user = User::newFromId( $article->getUser() ); |
| 83 | + |
| 84 | + $timestamp = $article->getTimestamp(); |
| 85 | + if ( $timestamp ) { |
| 86 | + $d = $wgLang->date( $article->getTimestamp(), true ); |
| 87 | + $t = $wgLang->time( $article->getTimestamp(), true ); |
| 88 | + } else { |
| 89 | + $d = ''; |
| 90 | + $t = ''; |
| 91 | + } |
| 92 | + return wfMsgExt( 'lastmodifiedatby', 'parsemag', $d, $t, self::userLink( $user ), $user->getName() ); |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Get a list of contributors of $article |
| 97 | + * @param $article Article object |
| 98 | + * @param $cnt Int: maximum list of contributors to show |
| 99 | + * @param $showIfMax Bool: whether to contributors if there more than $cnt |
| 100 | + * @return String: html |
| 101 | + */ |
| 102 | + protected static function getContributors( Article $article, $cnt, $showIfMax ) { |
| 103 | + global $wgLang, $wgHiddenPrefs; |
| 104 | + |
| 105 | + $contributors = $article->getContributors(); |
| 106 | + |
| 107 | + $others_link = false; |
| 108 | + |
| 109 | + # Hmm... too many to fit! |
| 110 | + if ( $cnt > 0 && $contributors->count() > $cnt ) { |
| 111 | + $others_link = self::othersLink( $article ); |
| 112 | + if ( !$showIfMax ) |
| 113 | + return wfMsgExt( 'othercontribs', 'parsemag', $others_link, $contributors->count() ); |
| 114 | + } |
| 115 | + |
| 116 | + $real_names = array(); |
| 117 | + $user_names = array(); |
| 118 | + $anon_ips = array(); |
| 119 | + |
| 120 | + # Sift for real versus user names |
| 121 | + foreach ( $contributors as $user ) { |
| 122 | + $cnt--; |
| 123 | + if ( $user->isLoggedIn() ) { |
| 124 | + $link = self::link( $user ); |
| 125 | + if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) { |
| 126 | + $real_names[] = $link; |
| 127 | + } else { |
| 128 | + $user_names[] = $link; |
| 129 | + } |
| 130 | + } else { |
| 131 | + $anon_ips[] = self::link( $user ); |
| 132 | + } |
| 133 | + |
| 134 | + if ( $cnt == 0 ) { |
| 135 | + break; |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + if ( count( $real_names ) ) { |
| 140 | + $real = $wgLang->listToText( $real_names ); |
| 141 | + } else { |
| 142 | + $real = false; |
| 143 | + } |
| 144 | + |
| 145 | + # "ThisSite user(s) A, B and C" |
| 146 | + if ( count( $user_names ) ) { |
| 147 | + $user = wfMsgExt( |
| 148 | + 'siteusers', |
| 149 | + 'parsemag', |
| 150 | + $wgLang->listToText( $user_names ), count( $user_names ) |
| 151 | + ); |
| 152 | + } else { |
| 153 | + $user = false; |
| 154 | + } |
| 155 | + |
| 156 | + if ( count( $anon_ips ) ) { |
| 157 | + $anon = wfMsgExt( |
| 158 | + 'anonusers', |
| 159 | + 'parsemag', |
| 160 | + $wgLang->listToText( $anon_ips ), count( $anon_ips ) |
| 161 | + ); |
| 162 | + } else { |
| 163 | + $anon = false; |
| 164 | + } |
| 165 | + |
| 166 | + # This is the big list, all mooshed together. We sift for blank strings |
| 167 | + $fulllist = array(); |
| 168 | + foreach ( array( $real, $user, $anon, $others_link ) as $s ) { |
| 169 | + if ( $s ) { |
| 170 | + array_push( $fulllist, $s ); |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + # Make the list into text... |
| 175 | + $creds = $wgLang->listToText( $fulllist ); |
| 176 | + |
| 177 | + # "Based on work by ..." |
| 178 | + return strlen( $creds ) |
| 179 | + ? wfMsgExt( 'othercontribs', 'parsemag', $creds, count( $fulllist ) ) |
| 180 | + : ''; |
| 181 | + } |
| 182 | + |
| 183 | + /** |
| 184 | + * Get a link to $user's user page |
| 185 | + * @param $user User object |
| 186 | + * @return String: html |
| 187 | + */ |
| 188 | + protected static function link( User $user ) { |
| 189 | + global $wgUser, $wgHiddenPrefs; |
| 190 | + if ( !in_array( 'realname', $wgHiddenPrefs ) && !$user->isAnon() ) { |
| 191 | + $real = $user->getRealName(); |
| 192 | + } else { |
| 193 | + $real = false; |
| 194 | + } |
| 195 | + |
| 196 | + $skin = $wgUser->getSkin(); |
| 197 | + $page = $user->isAnon() ? |
| 198 | + SpecialPage::getTitleFor( 'Contributions', $user->getName() ) : |
| 199 | + $user->getUserPage(); |
| 200 | + |
| 201 | + return $skin->link( $page, htmlspecialchars( $real ? $real : $user->getName() ) ); |
| 202 | + } |
| 203 | + |
| 204 | + /** |
| 205 | + * Get a link to $user's user page |
| 206 | + * @param $user User object |
| 207 | + * @return String: html |
| 208 | + */ |
| 209 | + protected static function userLink( User $user ) { |
| 210 | + $link = self::link( $user ); |
| 211 | + if ( $user->isAnon() ) { |
| 212 | + return wfMsgExt( 'anonuser', array( 'parseinline', 'replaceafter' ), $link ); |
| 213 | + } else { |
| 214 | + global $wgHiddenPrefs; |
| 215 | + if ( !in_array( 'realname', $wgHiddenPrefs ) && $user->getRealName() ) { |
| 216 | + return $link; |
| 217 | + } else { |
| 218 | + return wfMsgExt( 'siteuser', 'parsemag', $link, $user->getName() ); |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + /** |
| 224 | + * Get a link to action=credits of $article page |
| 225 | + * @param $article Article object |
| 226 | + * @return String: html |
| 227 | + */ |
| 228 | + protected static function othersLink( Article $article ) { |
| 229 | + global $wgUser; |
| 230 | + $skin = $wgUser->getSkin(); |
| 231 | + return $skin->link( |
| 232 | + $article->getTitle(), |
| 233 | + wfMsgHtml( 'others' ), |
| 234 | + array(), |
| 235 | + array( 'action' => 'credits' ), |
| 236 | + array( 'known' ) |
| 237 | + ); |
| 238 | + } |
| 239 | +} |
Property changes on: trunk/phase3/includes/Credits.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 240 | + native |
Added: svn:keywords |
2 | 241 | + Author Date Id Revision |
Index: trunk/phase3/languages/messages/MessagesEn.php |
— | — | @@ -998,9 +998,8 @@ |
999 | 999 | 'unexpected' => 'Unexpected value: "$1"="$2".', |
1000 | 1000 | 'formerror' => 'Error: could not submit form', |
1001 | 1001 | 'badarticleerror' => 'This action cannot be performed on this page.', |
1002 | | -'cannotdelete' => 'The page or file "$1" could not be deleted. It may have already been deleted by someone else. The deletion log is provided below for convenience. |
1003 | | - |
1004 | | -$2', |
| 1002 | +'cannotdelete' => 'The page or file "$1" could not be deleted. |
| 1003 | +It may have already been deleted by someone else.', |
1005 | 1004 | 'badtitle' => 'Bad title', |
1006 | 1005 | 'badtitletext' => 'The requested page title was invalid, empty, or an incorrectly linked inter-language or inter-wiki title. |
1007 | 1006 | It may contain one or more characters which cannot be used in titles.', |
— | — | @@ -2784,7 +2783,7 @@ |
2785 | 2784 | 'delete-confirm' => 'Delete "$1"', |
2786 | 2785 | 'delete-backlink' => '← $1', # only translate this message to other languages if you have to change it |
2787 | 2786 | 'delete-legend' => 'Delete', |
2788 | | -'historywarning' => "'''Warning:''' The page you are about to delete has a $2 with approximately $1 {{PLURAL:$1|revision|revisions}}:", |
| 2787 | +'historywarning' => "'''Warning:''' The page you are about to delete has a history with approximately $1 {{PLURAL:$1|revision|revisions}}:", |
2789 | 2788 | 'confirmdeletetext' => 'You are about to delete a page along with all of its history. |
2790 | 2789 | Please confirm that you intend to do this, that you understand the consequences, and that you are doing this in accordance with [[{{MediaWiki:Policy-url}}|the policy]].', |
2791 | 2790 | 'actioncomplete' => 'Action complete', |
Index: trunk/extensions/LiquidThreads/LiquidThreads.php |
— | — | @@ -118,7 +118,7 @@ |
119 | 119 | $wgHooks['ArticleDeleteComplete'][] = 'LqtDeletionController::onArticleDeleteComplete'; |
120 | 120 | $wgHooks['ArticleRevisionUndeleted'][] = 'LqtDeletionController::onArticleRevisionUndeleted'; |
121 | 121 | $wgHooks['ArticleUndelete'][] = 'LqtDeletionController::onArticleUndelete'; |
122 | | -$wgHooks['ActionBeforeFormDisplay'][] = 'LqtDeletionController::onActionBeforeFormDisplay'; |
| 122 | +$wgHooks['ArticleConfirmDelete'][] = 'LqtDeletionController::onArticleConfirmDelete'; |
123 | 123 | $wgHooks['ArticleDelete'][] = 'LqtDeletionController::onArticleDelete'; |
124 | 124 | |
125 | 125 | // Moving |
Index: trunk/extensions/LiquidThreads/classes/DeletionController.php |
— | — | @@ -94,27 +94,22 @@ |
95 | 95 | return true; |
96 | 96 | } |
97 | 97 | |
98 | | - static function onActionBeforeFormDisplay( $action, HTMLForm &$form, $page ) { |
99 | | - if( $action != 'delete' ){ |
| 98 | + static function onArticleConfirmDelete( $article, $out, &$reason ) { |
| 99 | + if ( $article->getTitle()->getNamespace() != NS_LQT_THREAD ) { |
100 | 100 | return true; |
101 | 101 | } |
102 | 102 | |
103 | | - if ( $page->getTitle()->getNamespace() != NS_LQT_THREAD ) { |
104 | | - return true; |
105 | | - } |
| 103 | + $thread = Threads::withRoot( $article ); |
106 | 104 | |
107 | | - $thread = Threads::withRoot( $page ); |
108 | | - |
109 | 105 | if ( !$thread ) { |
110 | 106 | return true; |
111 | 107 | } |
112 | 108 | |
113 | 109 | if ( $thread->isTopmostThread() && count( $thread->replies() ) ) { |
114 | | - $form->addHeaderText( Html::rawElement( |
115 | | - 'strong', |
116 | | - array(), |
117 | | - wfMessage( 'lqt-delete-parent-warning' )->parse() |
118 | | - ) ); |
| 110 | + $out->wrapWikiMsg( |
| 111 | + '<strong>$1</strong>', |
| 112 | + 'lqt-delete-parent-warning' |
| 113 | + ); |
119 | 114 | } |
120 | 115 | |
121 | 116 | return true; |
Index: trunk/extensions/LiquidThreads/classes/Thread.php |
— | — | @@ -112,7 +112,7 @@ |
113 | 113 | NewMessages::writeMessageStateForUpdatedThread( $thread, $change_type, $wgUser ); |
114 | 114 | |
115 | 115 | if ( $wgUser->getOption( 'lqt-watch-threads', false ) ) { |
116 | | - Action::factory( 'watch', $thread->topmostThread()->root() )->execute(); |
| 116 | + $thread->topmostThread()->root()->doWatch(); |
117 | 117 | } |
118 | 118 | |
119 | 119 | return $thread; |
Index: trunk/extensions/MultilingualLiquidThreads/LiquidThreads/LiquidThreads.php |
— | — | @@ -70,7 +70,7 @@ |
71 | 71 | $wgHooks['ArticleDeleteComplete'][] = 'LqtDeletionController::onArticleDeleteComplete'; |
72 | 72 | $wgHooks['ArticleRevisionUndeleted'][] = 'LqtDeletionController::onArticleRevisionUndeleted'; |
73 | 73 | $wgHooks['ArticleUndelete'][] = 'LqtDeletionController::onArticleUndelete'; |
74 | | -$wgHooks['ActionBeforeFormDisplay'][] = 'LqtDeletionController::onActionBeforeFormDisplay'; |
| 74 | +$wgHooks['ArticleConfirmDelete'][] = 'LqtDeletionController::onArticleConfirmDelete'; |
75 | 75 | $wgHooks['ArticleDelete'][] = 'LqtDeletionController::onArticleDelete'; |
76 | 76 | |
77 | 77 | // Moving |
Index: trunk/extensions/MultilingualLiquidThreads/LiquidThreads/classes/DeletionController.php |
— | — | @@ -93,25 +93,20 @@ |
94 | 94 | return true; |
95 | 95 | } |
96 | 96 | |
97 | | - static function onActionBeforeFormDisplay( $action, HTMLForm &$form, $page ) { |
98 | | - if( $action != 'delete' ){ |
| 97 | + static function onArticleConfirmDelete( $article, $out, &$reason ) { |
| 98 | + if ( $article->getTitle()->getNamespace() != NS_LQT_THREAD ) { |
99 | 99 | return true; |
100 | 100 | } |
101 | 101 | |
102 | | - if ( $page->getTitle()->getNamespace() != NS_LQT_THREAD ) { |
103 | | - return true; |
104 | | - } |
| 102 | + $thread = Threads::withRoot( $article ); |
105 | 103 | |
106 | | - $thread = Threads::withRoot( $page ); |
107 | | - |
108 | 104 | if ( !$thread ) return true; |
109 | 105 | |
110 | 106 | if ( $thread->isTopmostThread() && count( $thread->replies() ) ) { |
111 | | - $form->addHeaderText( Html::rawElement( |
112 | | - 'strong', |
113 | | - array(), |
114 | | - wfMessage( 'lqt-delete-parent-warning' )->parse() |
115 | | - ) ); |
| 107 | + $out->wrapWikiMsg( |
| 108 | + '<strong>$1</strong>', |
| 109 | + 'lqt-delete-parent-warning' |
| 110 | + ); |
116 | 111 | } |
117 | 112 | |
118 | 113 | return true; |
Index: trunk/extensions/MultilingualLiquidThreads/LiquidThreads/classes/Thread.php |
— | — | @@ -113,7 +113,7 @@ |
114 | 114 | NewMessages::writeMessageStateForUpdatedThread( $thread, $change_type, $wgUser ); |
115 | 115 | |
116 | 116 | if ( $wgUser->getOption( 'lqt-watch-threads', false ) ) { |
117 | | - Action::factory( 'watch', $thread->topmostThread()->root() )->execute(); |
| 117 | + $thread->topmostThread()->root()->doWatch(); |
118 | 118 | } |
119 | 119 | |
120 | 120 | return $thread; |
Index: trunk/extensions/PureWikiDeletion/PureWikiDeletion.php |
— | — | @@ -104,7 +104,8 @@ |
105 | 105 | return false; |
106 | 106 | } |
107 | 107 | if ( $summary == wfMsgForContent( 'autosumm-blank' ) ) { |
108 | | - $summary = DeleteAction::getAutoReason( $article ); |
| 108 | + $hasHistory = false; |
| 109 | + $summary = $article->generateReason( $hasHistory ); |
109 | 110 | } |
110 | 111 | } else { |
111 | 112 | $dbr = wfGetDB( DB_SLAVE ); |
Index: trunk/extensions/PureWikiDeletion/PureWikiDeletion.hooks.php |
— | — | @@ -55,7 +55,8 @@ |
56 | 56 | $blankRevId = $revision->getId(); |
57 | 57 | if ( $text == "" ) { |
58 | 58 | if ( $summary == wfMsgForContent( 'autosumm-blank' ) ) { |
59 | | - $summary = DeleteAction::getAutoReason( $article ); |
| 59 | + $hasHistory = false; |
| 60 | + $summary = $article->generateReason( $hasHistory ); |
60 | 61 | } |
61 | 62 | $dbw = wfGetDB( DB_MASTER ); |
62 | 63 | $blank_row = array( |
Index: trunk/extensions/MetavidWiki/includes/articlepages/MV_DataPage.php |
— | — | @@ -61,18 +61,18 @@ |
62 | 62 | } |
63 | 63 | |
64 | 64 | if ( $confirm ) { |
65 | | - $this->doDeleteArticle( $reason ); |
| 65 | + $this->doDelete( $reason ); |
66 | 66 | if ( $wgRequest->getCheck( 'wpWatch' ) ) { |
67 | | - Action::factory( 'watch', $this )->execute(); |
| 67 | + $this->doWatch(); |
68 | 68 | } elseif ( $this->mTitle->userIsWatching() ) { |
69 | | - Action::factory( 'watch', $this )->execute(); |
| 69 | + $this->doUnwatch(); |
70 | 70 | } |
71 | 71 | return; |
72 | 72 | } |
73 | 73 | |
74 | 74 | // Generate deletion reason |
75 | 75 | $hasHistory = false; |
76 | | - $reason = DeleteAction::getAutoReason( $this ); |
| 76 | + $reason = $this->generateReason( $hasHistory ); |
77 | 77 | |
78 | 78 | // If the page has a history, insert a warning |
79 | 79 | if ( $hasHistory && !$confirm ) { |
Index: trunk/extensions/ReplaceText/ReplaceTextJob.php |
— | — | @@ -42,7 +42,8 @@ |
43 | 43 | $create_redirect = $this->params['create_redirect']; |
44 | 44 | $this->title->moveTo( $new_title, true, $reason, $create_redirect ); |
45 | 45 | if ( $this->params['watch_page'] ) { |
46 | | - Action::factory( 'watch', new Article( $new_title ) )->execute(); |
| 46 | + $article = new Article( $new_title ); |
| 47 | + $article->doWatch(); |
47 | 48 | } |
48 | 49 | $wgUser = $actual_user; |
49 | 50 | } else { |