* Use plural function for some more rev_del stuff
[lhc/web/wiklou.git] / includes / SpecialRevisiondelete.php
1 <?php
2
3 /**
4 * Not quite ready for production use yet; need to fix up the restricted mode,
5 * and provide for preservation across delete/undelete of images.
6 */
7
8 function wfSpecialRevisiondelete( $par = null ) {
9 global $wgOut, $wgRequest;
10
11 $target = $wgRequest->getText( 'target' );
12 // handle our many different possible input types
13 $oldid = $wgRequest->getIntArray( 'oldid' );
14 $logid = $wgRequest->getIntArray( 'logid' );
15 $arid = $wgRequest->getIntArray( 'arid' );
16 $fileid = $wgRequest->getIntArray( 'fileid' );
17
18 $page = Title::newFromUrl( $target, false );
19 if( is_null( $page ) ) {
20 $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
21 return;
22 }
23
24 $input_types = !is_null( $oldid ) + !is_null( $logid ) + !is_null( $arid ) + !is_null( $fileid );
25 if( $input_types > 1 || $input_types==0 ) {
26 //one target set at a time please!
27 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
28 return;
29 }
30
31 $form = new RevisionDeleteForm( $wgRequest, $oldid, $logid, $arid, $fileid );
32 if( $wgRequest->wasPosted() ) {
33 $form->submit( $wgRequest );
34 } else if( $oldid || $arid ) {
35 $form->showRevs( $wgRequest );
36 } else if( $logid ) {
37 $form->showEvents( $wgRequest );
38 } else if( $fileid ) {
39 $form->showImages( $wgRequest );
40 }
41 }
42
43 class RevisionDeleteForm {
44 /**
45 * @param Title $page
46 * @param int $oldid
47 */
48 function __construct( $request, $oldid, $logid, $arid, $fileid ) {
49 global $wgUser;
50
51 $target = $request->getText( 'target' );
52 $this->page = Title::newFromUrl( $target, false );
53
54 $this->revisions = $request->getIntArray( 'oldid', array() );
55 $this->events = $request->getIntArray( 'logid', array() );
56 $this->archrevs = $request->getIntArray( 'arid', array() );
57 $this->files = $request->getIntArray( 'fileid', array() );
58
59 $this->skin = $wgUser->getSkin();
60
61 // log events don't have text to hide, but hiding the page name is useful
62 if ( $fileid ) {
63 $hide_text_name = array( 'revdelete-hide-image', 'wpHideImage', Image::DELETED_FILE );
64 $this->deletetype='file';
65 } else if ( $logid ) {
66 $hide_text_name = array( 'revdelete-hide-name', 'wpHideName', LogViewer::DELETED_ACTION );
67 $this->deletetype='log';
68 } else {
69 $hide_text_name = array( 'revdelete-hide-text', 'wpHideText', Revision::DELETED_TEXT );
70 if ( $arid ) $this->deletetype='ar';
71 else $this->deletetype='old';
72 }
73 $this->checks = array(
74 $hide_text_name,
75 array( 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ),
76 array( 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER ),
77 array( 'revdelete-hide-restricted', 'wpHideRestricted', Revision::DELETED_RESTRICTED ) );
78 }
79
80 /**
81 * This sets any fields that are true to a bitfield to true on a given bitfield
82 * @param $bitfield, running bitfield
83 * @param $nbitfield, new bitfiled
84 */
85 function setBitfield( $bitfield, $nbitfield ) {
86 if ( $nbitfield & Revision::DELETED_TEXT) $bitfield |= Revision::DELETED_TEXT;
87 if ( $nbitfield & LogViewer::DELETED_ACTION) $bitfield |= LogViewer::DELETED_ACTION;
88 if ( $nbitfield & Image::DELETED_FILE) $bitfield |= Image::DELETED_FILE;
89 if ( $nbitfield & Revision::DELETED_COMMENT) $bitfield |= Revision::DELETED_COMMENT;
90 if ( $nbitfield & Revision::DELETED_USER) $bitfield |= Revision::DELETED_USER;
91 if ( $nbitfield & Revision::DELETED_RESTRICTED) $bitfield |= Revision::DELETED_RESTRICTED;
92 return $bitfield;
93 }
94
95 /**
96 * This lets a user set restrictions for live and archived revisions
97 * @param WebRequest $request
98 */
99 function showRevs( $request ) {
100 global $wgOut, $wgUser, $action;
101
102 $UserAllowed = true;
103 $wgOut->addWikiText( wfMsgExt( 'revdelete-selected', 'parseinline', $this->page->getPrefixedText(), count( $this->revisions) ) );
104
105 $bitfields = 0;
106 $wgOut->addHtml( "<ul>" );
107 if ( $this->deletetype=='old') {
108 foreach( $this->revisions as $revid ) {
109 $rev = Revision::newFromTitle( $this->page, $revid );
110 // Hiding top revisison is bad
111 if( !isset( $rev ) || $rev->isCurrent() ) {
112 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
113 return;
114 } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) {
115 // If a rev is hidden from sysops
116 if ( $action != 'submit') {
117 $wgOut->permissionRequired( 'hiderevision' ); return;
118 }
119 $UserAllowed=false;
120 }
121 $wgOut->addHtml( $this->historyLine( $rev ) );
122 $bitfields = $this->setBitfield( $bitfields, $rev->mDeleted );
123 }
124 } else if ( $this->deletetype=='ar') {
125 $archive = new PageArchive( $this->page );
126 foreach( $this->archrevs as $revid ) {
127 $rev = $archive->getRevision('', $revid );
128 if( !isset( $rev ) ) {
129 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
130 return;
131 } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) {
132 //if a rev is hidden from sysops
133 if ( $action != 'submit') {
134 $wgOut->permissionRequired( 'hiderevision' ); return;
135 }
136 $UserAllowed=false;
137 }
138 $wgOut->addHtml( $this->historyLine( $rev ) );
139 $bitfields = $this->setBitfield( $bitfields, $rev->mDeleted );
140 }
141 }
142 $wgOut->addHtml( "</ul>" );
143
144 $wgOut->addWikiText( wfMsgHtml( 'revdelete-text' ) );
145 //Normal sysops can always see what they did, but can't always change it
146 if ( !$UserAllowed ) return;
147
148 $items = array(
149 wfInputLabel( wfMsgHtml( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
150 wfSubmitButton( wfMsgHtml( 'revdelete-submit' ) ) );
151 $hidden = array(
152 wfHidden( 'wpEditToken', $wgUser->editToken() ),
153 wfHidden( 'target', $this->page->getPrefixedText() ),
154 wfHidden( 'type', $this->deletetype ) );
155 if( $this->deletetype=='old' ) {
156 foreach( $this->revisions as $revid ) {
157 $hidden[] = wfHidden( 'oldid[]', $revid );
158 }
159 } else if( $this->deletetype=='ar' ) {
160 foreach( $this->archrevs as $revid ) {
161 $hidden[] = wfHidden( 'arid[]', $revid );
162 }
163 }
164 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
165 $wgOut->addHtml( wfElement( 'form', array(
166 'method' => 'post',
167 'action' => $special->getLocalUrl( 'action=submit' ) ),
168 null ) );
169
170 $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' );
171 // FIXME: all items checked for just one rev are checked, even if not set for the others
172 foreach( $this->checks as $item ) {
173 list( $message, $name, $field ) = $item;
174 $wgOut->addHtml( '<div>' .
175 wfCheckLabel( wfMsgHtml( $message), $name, $name, $bitfields & $field ) .
176 '</div>' );
177 }
178 $wgOut->addHtml( '</fieldset>' );
179 foreach( $items as $item ) {
180 $wgOut->addHtml( '<p>' . $item . '</p>' );
181 }
182 foreach( $hidden as $item ) {
183 $wgOut->addHtml( $item );
184 }
185
186 $wgOut->addHtml( '</form>' );
187 }
188
189 /**
190 * This lets a user set restrictions for archived images
191 * @param WebRequest $request
192 */
193 function showImages( $request ) {
194 global $wgOut, $wgUser, $action;
195
196 $UserAllowed = true;
197 $wgOut->addWikiText( wfMsgExt( 'revdelete-selected', 'parseline', $this->page->getPrefixedText(), count( $this->files ) ) );
198
199 $bitfields = 0;
200 $wgOut->addHtml( "<ul>" );
201 foreach( $this->files as $fileid ) {
202 $file = new ArchivedFile( $this->page, $fileid );
203 if( !isset( $file->mId ) ) {
204 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
205 return;
206 } else if( !$file->userCan(Revision::DELETED_RESTRICTED) ) {
207 // If a rev is hidden from sysops
208 if ( $action != 'submit') {
209 $wgOut->permissionRequired( 'hiderevision' ); return;
210 }
211 $UserAllowed=false;
212 }
213 $wgOut->addHtml( $this->uploadLine( $file ) );
214 $bitfields = $this->setBitfield( $bitfields, $file->mDeleted );
215 }
216 $wgOut->addHtml( "</ul>" );
217
218 $wgOut->addWikiText( wfMsgHtml( 'revdelete-text' ) );
219 //Normal sysops can always see what they did, but can't always change it
220 if ( !$UserAllowed ) return;
221
222 $items = array(
223 wfInputLabel( wfMsgHtml( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
224 wfSubmitButton( wfMsgHtml( 'revdelete-submit' ) ) );
225 $hidden = array(
226 wfHidden( 'wpEditToken', $wgUser->editToken() ),
227 wfHidden( 'target', $this->page->getPrefixedText() ),
228 wfHidden( 'type', $this->deletetype ) );
229 foreach( $this->files as $fileid ) {
230 $hidden[] = wfHidden( 'fileid[]', $fileid );
231 }
232 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
233 $wgOut->addHtml( wfElement( 'form', array(
234 'method' => 'post',
235 'action' => $special->getLocalUrl( 'action=submit' ) ),
236 null ) );
237
238 $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' );
239 // FIXME: all items checked for just one file are checked, even if not set for the others
240 foreach( $this->checks as $item ) {
241 list( $message, $name, $field ) = $item;
242 $wgOut->addHtml( '<div>' .
243 wfCheckLabel( wfMsgHtml( $message), $name, $name, $bitfields & $field ) .
244 '</div>' );
245 }
246 $wgOut->addHtml( '</fieldset>' );
247 foreach( $items as $item ) {
248 $wgOut->addHtml( '<p>' . $item . '</p>' );
249 }
250 foreach( $hidden as $item ) {
251 $wgOut->addHtml( $item );
252 }
253
254 $wgOut->addHtml( '</form>' );
255 }
256
257 /**
258 * This lets a user set restrictions for log items
259 * @param WebRequest $request
260 */
261 function showEvents( $request ) {
262 global $wgOut, $wgUser, $action;
263
264 $UserAllowed = true;
265 $wgOut->addWikiText( wfMsgExt( 'logdelete-selected', 'parseinline', $this->page->getPrefixedText(), count( $this->events ) ) );
266
267 $bitfields = 0;
268 $wgOut->addHtml( "<ul>" );
269 foreach( $this->events as $logid ) {
270 $log = new LogViewer( $wgRequest );
271 $event = LogReader::newFromTitle( $this->page, $logid );
272 // Don't hide from oversight log!!!
273 if( !isset( $event ) || $event->log_type == 'oversight' ) {
274 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
275 return;
276 } else if( !$log->userCan($event, Revision::DELETED_RESTRICTED) ) {
277 // If an event is hidden from sysops
278 if ( $action != 'submit') {
279 $wgOut->permissionRequired( 'hiderevision' ); return;
280 }
281 $UserAllowed=false;
282 }
283 $wgOut->addHtml( $this->logLine( $log, $event ) );
284 $bitfields = $this->setBitfield( $bitfields, $event->log_deleted );
285 }
286 $wgOut->addHtml( "</ul>" );
287
288 $wgOut->addWikiText( wfMsgHtml( 'revdelete-text' ) );
289 //Normal sysops can always see what they did, but can't always change it
290 if ( !$UserAllowed ) return;
291
292 $items = array(
293 wfInputLabel( wfMsgHtml( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
294 wfSubmitButton( wfMsgHtml( 'revdelete-submit' ) ) );
295 $hidden = array(
296 wfHidden( 'wpEditToken', $wgUser->editToken() ),
297 wfHidden( 'target', $this->page->getPrefixedText() ),
298 wfHidden( 'type', $this->deletetype ) );
299 foreach( $this->events as $logid ) {
300 $hidden[] = wfHidden( 'logid[]', $logid );
301 }
302
303 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
304 $wgOut->addHtml( wfElement( 'form', array(
305 'method' => 'post',
306 'action' => $special->getLocalUrl( 'action=submit' ) ),
307 null ) );
308
309 $wgOut->addHtml( '<fieldset><legend>' . wfMsgHtml( 'revdelete-legend' ) . '</legend>' );
310 // FIXME: all items checked for just on event are checked, even if not set for the others
311 foreach( $this->checks as $item ) {
312 list( $message, $name, $field ) = $item;
313 $wgOut->addHtml( '<div>' .
314 wfCheckLabel( wfMsgHtml( $message), $name, $name, $bitfields & $field ) .
315 '</div>' );
316 }
317 $wgOut->addHtml( '</fieldset>' );
318 foreach( $items as $item ) {
319 $wgOut->addHtml( '<p>' . $item . '</p>' );
320 }
321 foreach( $hidden as $item ) {
322 $wgOut->addHtml( $item );
323 }
324
325 $wgOut->addHtml( '</form>' );
326 }
327
328 /**
329 * @param Revision $rev
330 * @returns string
331 */
332 function historyLine( $rev ) {
333 global $wgContLang;
334 $date = $wgContLang->timeanddate( $rev->getTimestamp() );
335
336 $difflink=''; $del = '';
337 if( $this->deletetype=='old' ) {
338 $difflink = '(' . $this->skin->makeKnownLinkObj( $this->page, wfMsgHtml('diff'),
339 '&diff=' . $rev->getId() . '&oldid=prev' ) . ')';
340 $revlink = $this->skin->makeLinkObj( $this->page, $date, 'oldid=' . $rev->getId() );
341 } else if( $this->deletetype=='ar' ) {
342 $undelete = SpecialPage::getTitleFor( 'Undelete' );
343 $target = $this->page->getPrefixedText();
344 $revlink = $this->skin->makeLinkObj( $undelete, $date, "target=$target&timestamp=" . $rev->getTimestamp() );
345 }
346
347 if ( $rev->isDeleted(Revision::DELETED_TEXT) ) {
348 $revlink = '<span class="history-deleted">'.$revlink.'</span>';
349 $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>';
350 if ( !$rev->userCan(Revision::DELETED_TEXT) ) {
351 $revlink = '<span class="history-deleted">'.$date.'</span>';
352 }
353 }
354
355 return
356 "<li> $difflink $revlink " . $this->skin->revUserLink( $rev ) . " " . $this->skin->revComment( $rev ) . "$del</li>";
357 }
358
359 /**
360 * @param Image $file
361 * @returns string
362 */
363 function uploadLine( $file ) {
364 global $wgContLang;
365
366 $target = $this->page->getPrefixedText();
367 $date = $wgContLang->timeanddate( $file->mTimestamp, true );
368
369 $del = '';
370 if ( $file->mGroup == 'deleted' ) {
371 $undelete = SpecialPage::getTitleFor( 'Undelete' );
372 $pageLink = $this->skin->makeKnownLinkObj( $undelete, $date, "target=$target&file=$file->mKey" );
373 } else {
374 $pageLink = $this->skin->makeKnownLinkObj( $this->page, $date, "file=$file->mKey" );
375 }
376 if ( $file->isDeleted(Image::DELETED_FILE) ) {
377 $pageLink = '<span class="history-deleted">' . $pageLink . '</span>';
378 $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>';
379 if ( !$file->userCan(Image::DELETED_FILE) ) {
380 $pageLink = '<span class="history-deleted">'.$date.'</span>';
381 }
382 }
383
384 $data = wfMsgHtml( 'widthheight',
385 $wgContLang->formatNum( $file->mWidth ),
386 $wgContLang->formatNum( $file->mHeight ) ) .
387 ' (' . wfMsgHtml( 'nbytes', $wgContLang->formatNum( $file->mSize ) ) . ')';
388
389 return
390 "<li> $pageLink " . $this->skin->fileUserLink( $file ) . " $data " . $this->skin->fileComment( $file ) . "$del</li>";
391 }
392
393 /**
394 * @param Revision $rev
395 * @returns string
396 */
397 function logLine( $log, $event ) {
398 global $wgContLang;
399
400 $date = $wgContLang->timeanddate( $event->log_timestamp );
401 $paramArray = LogPage::extractParams( $event->log_params );
402
403 if ( !LogViewer::userCan($event,LogViewer::DELETED_ACTION) ) {
404 $action = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>';
405 } else {
406 $action = LogPage::actionText( $event->log_type, $event->log_action, $this->page, $this->skin, $paramArray, true, true );
407 if( $event->log_deleted & LogViewer::DELETED_ACTION )
408 $action = '<span class="history-deleted">' . $action . '</span>';
409 }
410 return
411 "<li>$date" . " " . $this->skin->logUserLink( $event ) . " $action " . $this->skin->logComment( $event ) . "</li>";
412 }
413
414 /**
415 * @param WebRequest $request
416 */
417 function submit( $request ) {
418 $bitfield = $this->extractBitfield( $request );
419 $comment = $request->getText( 'wpReason' );
420
421 $target = $request->getText( 'target' );
422 $title = Title::newFromURL( $target, false );
423
424 if( $this->save( $bitfield, $comment, $title ) ) {
425 $this->success( $request );
426 } else if( $request->getCheck( 'oldid' ) || $request->getCheck( 'arid' ) ) {
427 return $this->showRevs( $request );
428 } else if( $request->getCheck( 'logid' ) ) {
429 return $this->showLogs( $request );
430 } else if( $request->getCheck( 'fileid' ) ) {
431 return $this->showImages( $request );
432 }
433 }
434
435 function success( $request ) {
436 global $wgOut;
437
438 $wgOut->setPagetitle( wfMsgHtml( 'actioncomplete' ) );
439
440 $target = $request->getText( 'target' );
441 $type = $request->getText( 'type' );
442
443 $title = Title::newFromURL( $target, false );
444 $name = $title->makeName( $title->getNamespace(), $title->getText() );
445
446 $logtitle = SpecialPage::getTitleFor( 'Log' );
447 $loglink = $this->skin->makeKnownLinkObj( $logtitle, wfMsgHtml( 'viewpagelogs' ),
448 wfArrayToCGI( array('page' => $name ) ) );
449 $histlink = $this->skin->makeKnownLinkObj( $title, wfMsgHtml( 'revhistory' ),
450 wfArrayToCGI( array('action' => 'history' ) ) );
451
452 if ( $title->getNamespace() > -1)
453 $wgOut->setSubtitle( '<p>'.$histlink.' / '.$loglink.'</p>' );
454
455 if( $type=='log' ) {
456 $wgOut->addWikiText( wfMsgHtml('logdelete-success', $target), false );
457 $this->showEvents( $request );
458 } else if( $type=='old' || $type=='ar' ) {
459 $wgOut->addWikiText( wfMsgHtml('revdelete-success', $target), false );
460 $this->showRevs( $request );
461 } else if ( $type=='file' ) {
462 $wgOut->addWikiText( wfMsgHtml('revdelete-success', $target), false );
463 $this->showImages( $request );
464 }
465 }
466
467 /**
468 * Put together a rev_deleted bitfield from the submitted checkboxes
469 * @param WebRequest $request
470 * @return int
471 */
472 function extractBitfield( $request ) {
473 $bitfield = 0;
474 foreach( $this->checks as $item ) {
475 list( /* message */ , $name, $field ) = $item;
476 if( $request->getCheck( $name ) ) {
477 $bitfield |= $field;
478 }
479 }
480 return $bitfield;
481 }
482
483 function save( $bitfield, $reason, $title ) {
484 $dbw = wfGetDB( DB_MASTER );
485 $deleter = new RevisionDeleter( $dbw );
486
487 if( $this->revisions ) {
488 return $deleter->setRevVisibility( $title, $this->revisions, $bitfield, $reason );
489 } else if( $this->events ) {
490 return $deleter->setEventVisibility( $title, $this->events, $bitfield, $reason );
491 } else if( $this->archrevs ) {
492 return $deleter->setArchiveVisibility( $title, $this->archrevs, $bitfield, $reason );
493 } else if( $this->files ) {
494 return $deleter->setFileVisibility( $title, $this->files, $bitfield, $reason );
495 }
496 }
497 }
498
499
500 class RevisionDeleter {
501 function __construct( $db ) {
502 $this->db = $db;
503 }
504
505 /**
506 * @param $title, the page these events apply to
507 * @param array $items list of revision ID numbers
508 * @param int $bitfield new rev_deleted value
509 * @param string $comment Comment for log records
510 */
511 function setRevVisibility( $title, $items, $bitfield, $comment ) {
512 global $wgOut;
513
514 $UserAllowedAll = true;
515 $pages_count = array(); $pages_revIds = array();
516 // To work!
517 foreach( $items as $revid ) {
518 $rev = Revision::newFromTitle( $title, $revid );
519 if( !isset( $rev ) || $rev->isCurrent() ) {
520 return false;
521 } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) {
522 $UserAllowedAll=false;
523 continue;
524 }
525 $pageid = $rev->getPage();
526 // For logging, maintain a count of revisions per page
527 if ( !isset($pages_count[$pageid]) ) {
528 $pages_count[$pageid]=0;
529 $pages_revIds[$pageid]=array();
530 }
531 // Which pages did we change anything about?
532 if ( $rev->mDeleted != $bitfield ) {
533 $pages_count[$pageid]++;
534 $pages_revIds[$pageid][]=$revid;
535
536 $this->updateRevision( $rev, $bitfield );
537 $this->updateRecentChangesEdits( $rev, $bitfield, false );
538 }
539 }
540
541 // Clear caches...
542 foreach( $pages_count as $pageid => $count ) {
543 //Don't log or touch if nothing changed
544 if ( $count > 0 ) {
545 $title = Title::newFromId( $pageid );
546 $this->updatePage( $title );
547 $this->updateLog( $title, $count, $bitfield, $comment, $title, 'old', $pages_revIds[$pageid] );
548 }
549 }
550 // Where all revs allowed to be set?
551 if ( !$UserAllowedAll ) {
552 //FIXME: still might be confusing???
553 $wgOut->permissionRequired( 'hiderevision' ); return false;
554 }
555
556 return true;
557 }
558
559 /**
560 * @param $title, the page these events apply to
561 * @param array $items list of revision ID numbers
562 * @param int $bitfield new rev_deleted value
563 * @param string $comment Comment for log records
564 */
565 function setArchiveVisibility( $title, $items, $bitfield, $comment ) {
566 global $wgOut;
567
568 $UserAllowedAll = true;
569 $count = 0; $Id_set = array();
570 // To work!
571 $archive = new PageArchive( $title );
572 foreach( $items as $revid ) {
573 $rev = $archive->getRevision( '', $revid );
574 if( !isset( $rev ) ) {
575 return false;
576 } else if( !$rev->userCan(Revision::DELETED_RESTRICTED) ) {
577 $UserAllowedAll=false;
578 continue;
579 }
580 // For logging, maintain a count of revisions
581 if ( $rev->mDeleted != $bitfield ) {
582 $Id_set[]=$revid;
583 $count++;
584 }
585 $this->updateArchive( $rev, $bitfield );
586 }
587
588 // Log if something was changed
589 if ( $count > 0 ) {
590 $this->updateLog( $title, $count, $bitfield, $comment, $title, 'ar', $Id_set );
591 }
592 // Where all revs allowed to be set?
593 if ( !$UserAllowedAll ) {
594 $wgOut->permissionRequired( 'hiderevision' ); return false;
595 }
596
597 return true;
598 }
599
600 /**
601 * @param $title, the page these events apply to
602 * @param array $items list of revision ID numbers
603 * @param int $bitfield new rev_deleted value
604 * @param string $comment Comment for log records
605 */
606 function setFileVisibility( $title, $items, $bitfield, $comment ) {
607 global $wgOut;
608
609 $UserAllowedAll = true;
610 $count = 0; $Id_set = array();
611 // To work!
612 foreach( $items as $fileid ) {
613 $file = new ArchivedFile( $title, $fileid );
614 if( !isset( $file ) ) {
615 return false;
616 } else if( !$file->userCan(Revision::DELETED_RESTRICTED) ) {
617 $UserAllowedAll=false;
618 continue;
619 }
620 // For logging, maintain a count of revisions
621 if ( $file->mDeleted != $bitfield ) {
622 $Id_set[]=$fileid;
623 $count++;
624 }
625 $this->updateFiles( $file, $bitfield );
626 }
627
628 // Log if something was changed
629 if ( $count > 0 ) {
630 $this->updateLog( $title, $count, $bitfield, $comment, $title, 'file', $Id_set );
631 }
632 // Where all revs allowed to be set?
633 if ( !$UserAllowedAll ) {
634 $wgOut->permissionRequired( 'hiderevision' ); return false;
635 }
636
637 return true;
638 }
639
640 /**
641 * @param $title, the page these events apply to
642 * @param array $items list of log ID numbers
643 * @param int $bitfield new log_deleted value
644 * @param string $comment Comment for log records
645 */
646 function setEventVisibility( $title, $items, $bitfield, $comment ) {
647 global $wgOut;
648
649 $UserAllowedAll = true;
650 $logs_count = array(); $logs_Ids = array();
651 // To work!
652 foreach( $items as $logid ) {
653 $event = LogReader::newFromTitle( $title, $logid );
654 if( !isset( $event ) ) {
655 return false;
656 } else if( !LogViewer::userCan($event, Revision::DELETED_RESTRICTED) || $event->log_type == 'oversight' ) {
657 // Don't hide from oversight log!!!
658 $UserAllowedAll=false;
659 continue;
660 }
661 $logtype = $event->log_type;
662 // For logging, maintain a count of events per log type
663 if( !isset( $logs_count[$logtype] ) ) {
664 $logs_count[$logtype]=0;
665 $logs_Ids[$logtype]=array();
666 }
667 // Which logs did we change anything about?
668 if ( $event->log_deleted != $bitfield ) {
669 $logs_Ids[$logtype][]=$logid;
670 $logs_count[$logtype]++;
671
672 $this->updateLogs( $event, $bitfield );
673 $this->updateRecentChangesLog( $event, $bitfield, true );
674 }
675 }
676 foreach( $logs_count as $logtype => $count ) {
677 //Don't log or touch if nothing changed
678 if ( $count > 0 ) {
679 $target = SpecialPage::getTitleFor( 'Log', $logtype );
680 $this->updateLog( $target, $count, $bitfield, $comment, $title, 'log', $logs_Ids[$logtype] );
681 }
682 }
683 // Where all revs allowed to be set?
684 if ( !$UserAllowedAll ) {
685 $wgOut->permissionRequired( 'hiderevision' ); return false;
686 }
687
688 return true;
689 }
690
691 /**
692 * Update the revision's rev_deleted field
693 * @param Revision $rev
694 * @param int $bitfield new rev_deleted bitfield value
695 */
696 function updateRevision( $rev, $bitfield ) {
697 $this->db->update( 'revision',
698 array( 'rev_deleted' => $bitfield ),
699 array( 'rev_id' => $rev->getId() ),
700 'RevisionDeleter::updateRevision' );
701 }
702
703 /**
704 * Update the revision's rev_deleted field
705 * @param Revision $rev
706 * @param int $bitfield new rev_deleted bitfield value
707 */
708 function updateArchive( $rev, $bitfield ) {
709 $this->db->update( 'archive',
710 array( 'ar_deleted' => $bitfield ),
711 array( 'ar_rev_id' => $rev->getId() ),
712 'RevisionDeleter::updateArchive' );
713 }
714
715 /**
716 * Update the images's fa_deleted field
717 * @param Revision $file
718 * @param int $bitfield new rev_deleted bitfield value
719 */
720 function updateFiles( $file, $bitfield ) {
721 $this->db->update( 'filearchive',
722 array( 'fa_deleted' => $bitfield ),
723 array( 'fa_id' => $file->mId ),
724 'RevisionDeleter::updateFiles' );
725 }
726
727 /**
728 * Update the logging log_deleted field
729 * @param Revision $rev
730 * @param int $bitfield new rev_deleted bitfield value
731 */
732 function updateLogs( $event, $bitfield ) {
733 $this->db->update( 'logging',
734 array( 'log_deleted' => $bitfield ),
735 array( 'log_id' => $event->log_id ),
736 'RevisionDeleter::updateLogs' );
737 }
738
739 /**
740 * Update the revision's recentchanges record if fields have been hidden
741 * @param Revision $event
742 * @param int $bitfield new rev_deleted bitfield value
743 */
744 function updateRecentChangesLog( $event, $bitfield ) {
745 $this->db->update( 'recentchanges',
746 array( 'rc_deleted' => $bitfield,
747 'rc_patrolled' => 1),
748 array( 'rc_logid' => $event->log_id ),
749 'RevisionDeleter::updateRecentChangesLog' );
750 }
751
752 /**
753 * Update the revision's recentchanges record if fields have been hidden
754 * @param Revision $rev
755 * @param int $bitfield new rev_deleted bitfield value
756 */
757 function updateRecentChangesEdits( $rev, $bitfield ) {
758 $this->db->update( 'recentchanges',
759 array( 'rc_deleted' => $bitfield,
760 'rc_patrolled' => 1),
761 array( 'rc_this_oldid' => $rev->getId() ),
762 'RevisionDeleter::updateRecentChangesEdits' );
763 }
764
765 /**
766 * Touch the page's cache invalidation timestamp; this forces cached
767 * history views to refresh, so any newly hidden or shown fields will
768 * update properly.
769 * @param Title $title
770 */
771 function updatePage( $title ) {
772 $title->invalidateCache();
773 }
774
775 /**
776 * Record a log entry on the action
777 * @param Title $title
778 * @param int $count the number of revisions altered for this page
779 * @param int $bitfield the new rev_deleted value
780 * @param string $comment
781 */
782 function updateLog( $title, $count, $bitfield, $comment, $target, $prefix, $items = array() ) {
783 // Put things hidden from sysops in the oversight log
784 $logtype = ( $bitfield & Revision::DELETED_RESTRICTED ) ? 'oversight' : 'delete';
785 // Add params for effected page and ids
786 $params = array( $target->getPrefixedText(), $prefix, implode( ',', $items) );
787 $log = new LogPage( $logtype );
788 if ( $prefix=='log' ) {
789 $reason = wfMsgExt('logdelete-logaction', array('parsemag'), $count, $bitfield, $target->getPrefixedText() );
790 if ($comment) $reason .= ": $comment";
791 $log->addEntry( 'event', $title, $reason, $params );
792 } else if ( $prefix=='old' ) {
793 $reason = wfMsgExt('revdelete-logaction', array('parsemag'), $count, $bitfield );
794 if ($comment) $reason .= ": $comment";
795 $log->addEntry( 'revision', $title, $reason, $params );
796 } else if ( $prefix=='file' ) {
797 $reason = wfMsgExt('revdelete-logaction', array('parsemag'), $count, $bitfield );
798 if ($comment) $reason .= ": $comment";
799 $log->addEntry( 'file', $title, $reason, $params );
800 }
801 }
802 }
803
804 ?>