00001 <?php
00010 class SpecialRevisionDelete extends UnlistedSpecialPage {
00011
00012 public function __construct() {
00013 parent::__construct( 'Revisiondelete', 'deleterevision' );
00014 $this->includable( false );
00015 }
00016
00017 public function execute( $par ) {
00018 global $wgOut, $wgUser, $wgRequest;
00019 if( wfReadOnly() ) {
00020 $wgOut->readOnlyPage();
00021 return;
00022 }
00023 if( !$wgUser->isAllowed( 'deleterevision' ) ) {
00024 $wgOut->permissionRequired( 'deleterevision' );
00025 return;
00026 }
00027 $this->skin =& $wgUser->getSkin();
00028 # Set title and such
00029 $this->setHeaders();
00030 $this->outputHeader();
00031 $this->wasPosted = $wgRequest->wasPosted();
00032 # Handle our many different possible input types
00033 $this->target = $wgRequest->getText( 'target' );
00034 $this->oldids = $wgRequest->getArray( 'oldid' );
00035 $this->artimestamps = $wgRequest->getArray( 'artimestamp' );
00036 $this->logids = $wgRequest->getArray( 'logid' );
00037 $this->oldimgs = $wgRequest->getArray( 'oldimage' );
00038 $this->fileids = $wgRequest->getArray( 'fileid' );
00039 # For reviewing deleted files...
00040 $this->file = $wgRequest->getVal( 'file' );
00041 # Only one target set at a time please!
00042 $i = (bool)$this->file + (bool)$this->oldids + (bool)$this->logids
00043 + (bool)$this->artimestamps + (bool)$this->fileids + (bool)$this->oldimgs;
00044 # No targets?
00045 if( $i == 0 ) {
00046 $wgOut->showErrorPage( 'notargettitle', 'notargettext' );
00047 return;
00048 }
00049 # Too many targets?
00050 if( $i !== 1 ) {
00051 $wgOut->showErrorPage( 'revdelete-toomanytargets-title', 'revdelete-toomanytargets-text' );
00052 return;
00053 }
00054 $this->page = Title::newFromUrl( $this->target );
00055 # If we have revisions, get the title from the first one
00056 # since they should all be from the same page. This allows
00057 # for more flexibility with page moves...
00058 if( count($this->oldids) > 0 ) {
00059 $rev = Revision::newFromId( $this->oldids[0] );
00060 $this->page = $rev ? $rev->getTitle() : $this->page;
00061 }
00062 # We need a target page!
00063 if( is_null($this->page) ) {
00064 $wgOut->addWikiMsg( 'undelete-header' );
00065 return;
00066 }
00067 # Logs must have a type given
00068 if( $this->logids && !strpos($this->page->getDBKey(),'/') ) {
00069 $wgOut->showErrorPage( 'revdelete-nologtype-title', 'revdelete-nologtype-text' );
00070 return;
00071 }
00072 # For reviewing deleted files...show it now if allowed
00073 if( $this->file ) {
00074 $oimage = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $this->page, $this->file );
00075 $oimage->load();
00076
00077 if( !$oimage->userCan(File::DELETED_FILE) ) {
00078 $wgOut->permissionRequired( 'suppressrevision' );
00079 } else {
00080 $this->showFile( $this->file );
00081 }
00082 return;
00083 }
00084 # Give a link to the logs/hist for this page
00085 if( !is_null($this->page) && $this->page->getNamespace() > -1 ) {
00086 $links = array();
00087
00088 $logtitle = SpecialPage::getTitleFor( 'Log' );
00089 $links[] = $this->skin->makeKnownLinkObj( $logtitle, wfMsgHtml( 'viewpagelogs' ),
00090 wfArrayToCGI( array( 'page' => $this->page->getPrefixedUrl() ) ) );
00091 # Give a link to the page history
00092 $links[] = $this->skin->makeKnownLinkObj( $this->page, wfMsgHtml( 'pagehist' ),
00093 wfArrayToCGI( array( 'action' => 'history' ) ) );
00094 # Link to deleted edits
00095 if( $wgUser->isAllowed('undelete') ) {
00096 $undelete = SpecialPage::getTitleFor( 'Undelete' );
00097 $links[] = $this->skin->makeKnownLinkObj( $undelete, wfMsgHtml( 'deletedhist' ),
00098 wfArrayToCGI( array( 'target' => $this->page->getPrefixedDBkey() ) ) );
00099 }
00100 # Logs themselves don't have histories or archived revisions
00101 $wgOut->setSubtitle( '<p>'.implode($links,' / ').'</p>' );
00102 }
00103 # Lock the operation and the form context
00104 $this->secureOperation();
00105 # Either submit or create our form
00106 if( $this->wasPosted ) {
00107 $this->submit( $wgRequest );
00108 } else if( $this->deleteKey == 'oldid' || $this->deleteKey == 'artimestamp' ) {
00109 $this->showRevs();
00110 } else if( $this->deleteKey == 'fileid' || $this->deleteKey == 'oldimage' ) {
00111 $this->showImages();
00112 } else if( $this->deleteKey == 'logid' ) {
00113 $this->showLogItems();
00114 }
00115 # Show relevant lines from the deletion log. This will show even if said ID
00116 # does not exist...might be helpful
00117 $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'delete' ) ) . "</h2>\n" );
00118 LogEventsList::showLogExtract( $wgOut, 'delete', $this->page->getPrefixedText() );
00119 if( $wgUser->isAllowed( 'suppressionlog' ) ){
00120 $wgOut->addHTML( "<h2>" . htmlspecialchars( LogPage::logName( 'suppress' ) ) . "</h2>\n" );
00121 LogEventsList::showLogExtract( $wgOut, 'suppress', $this->page->getPrefixedText() );
00122 }
00123 }
00124
00125 private function secureOperation() {
00126 global $wgUser;
00127 $this->deleteKey = '';
00128
00129 if( $this->oldids ) {
00130 $this->revisions = $this->oldids;
00131 $hide_content_name = array( 'revdelete-hide-text', 'wpHideText', Revision::DELETED_TEXT );
00132 $this->deleteKey = 'oldid';
00133 } else if( $this->artimestamps ) {
00134 $this->archrevs = $this->artimestamps;
00135 $hide_content_name = array( 'revdelete-hide-text', 'wpHideText', Revision::DELETED_TEXT );
00136 $this->deleteKey = 'artimestamp';
00137 } else if( $this->oldimgs ) {
00138 $this->ofiles = $this->oldimgs;
00139 $hide_content_name = array( 'revdelete-hide-image', 'wpHideImage', File::DELETED_FILE );
00140 $this->deleteKey = 'oldimage';
00141 } else if( $this->fileids ) {
00142 $this->afiles = $this->fileids;
00143 $hide_content_name = array( 'revdelete-hide-image', 'wpHideImage', File::DELETED_FILE );
00144 $this->deleteKey = 'fileid';
00145 } else if( $this->logids ) {
00146 $this->events = $this->logids;
00147 $hide_content_name = array( 'revdelete-hide-name', 'wpHideName', LogPage::DELETED_ACTION );
00148 $this->deleteKey = 'logid';
00149 }
00150
00151
00152 $this->checks = array(
00153 $hide_content_name,
00154 array( 'revdelete-hide-comment', 'wpHideComment', Revision::DELETED_COMMENT ),
00155 array( 'revdelete-hide-user', 'wpHideUser', Revision::DELETED_USER )
00156 );
00157 if( $wgUser->isAllowed('suppressrevision') ) {
00158 $this->checks[] = array( 'revdelete-hide-restricted', 'wpHideRestricted', Revision::DELETED_RESTRICTED );
00159 }
00160 }
00161
00165 private function showFile( $key ) {
00166 global $wgOut, $wgRequest;
00167 $wgOut->disable();
00168
00169 # We mustn't allow the output to be Squid cached, otherwise
00170 # if an admin previews a deleted image, and it's cached, then
00171 # a user without appropriate permissions can toddle off and
00172 # nab the image, and Squid will serve it
00173 $wgRequest->response()->header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
00174 $wgRequest->response()->header( 'Cache-Control: no-cache, no-store, max-age=0, must-revalidate' );
00175 $wgRequest->response()->header( 'Pragma: no-cache' );
00176
00177 $store = FileStore::get( 'deleted' );
00178 $store->stream( $key );
00179 }
00180
00184 private function showRevs() {
00185 global $wgOut, $wgUser;
00186 $UserAllowed = true;
00187
00188 $count = ($this->deleteKey=='oldid') ?
00189 count($this->revisions) : count($this->archrevs);
00190 $wgOut->addWikiMsg( 'revdelete-selected', $this->page->getPrefixedText(), $count );
00191
00192 $bitfields = 0;
00193 $wgOut->addHTML( "<ul>" );
00194
00195 $where = $revObjs = array();
00196 $dbr = wfGetDB( DB_MASTER );
00197
00198 $revisions = 0;
00199
00200 if( $this->deleteKey=='oldid' ) {
00201
00202 foreach( $this->revisions as $revid ) {
00203 $where[] = intval($revid);
00204 }
00205 $result = $dbr->select( array('revision','page'), '*',
00206 array(
00207 'rev_page' => $this->page->getArticleID(),
00208 'rev_id' => $where,
00209 'rev_page = page_id' ),
00210 __METHOD__ );
00211 while( $row = $dbr->fetchObject( $result ) ) {
00212 $revObjs[$row->rev_id] = new Revision( $row );
00213 }
00214 foreach( $this->revisions as $revid ) {
00215
00216 if( !isset($revObjs[$revid]) || $revObjs[$revid]->isCurrent() ) {
00217 continue;
00218 } else if( !$revObjs[$revid]->userCan(Revision::DELETED_RESTRICTED) ) {
00219
00220 if( !$this->wasPosted ) {
00221 $wgOut->permissionRequired( 'suppressrevision' );
00222 return;
00223 }
00224 $UserAllowed = false;
00225 }
00226 $revisions++;
00227 $wgOut->addHTML( $this->historyLine( $revObjs[$revid] ) );
00228 $bitfields |= $revObjs[$revid]->mDeleted;
00229 }
00230
00231 } else {
00232
00233 foreach( $this->archrevs as $timestamp ) {
00234 $where[] = $dbr->timestamp( $timestamp );
00235 }
00236 $result = $dbr->select( 'archive', '*',
00237 array(
00238 'ar_namespace' => $this->page->getNamespace(),
00239 'ar_title' => $this->page->getDBKey(),
00240 'ar_timestamp' => $where ),
00241 __METHOD__ );
00242 while( $row = $dbr->fetchObject( $result ) ) {
00243 $timestamp = wfTimestamp( TS_MW, $row->ar_timestamp );
00244 $revObjs[$timestamp] = new Revision( array(
00245 'page' => $this->page->getArticleId(),
00246 'id' => $row->ar_rev_id,
00247 'text' => $row->ar_text_id,
00248 'comment' => $row->ar_comment,
00249 'user' => $row->ar_user,
00250 'user_text' => $row->ar_user_text,
00251 'timestamp' => $timestamp,
00252 'minor_edit' => $row->ar_minor_edit,
00253 'text_id' => $row->ar_text_id,
00254 'deleted' => $row->ar_deleted,
00255 'len' => $row->ar_len) );
00256 }
00257 foreach( $this->archrevs as $timestamp ) {
00258 if( !isset($revObjs[$timestamp]) ) {
00259 continue;
00260 } else if( !$revObjs[$timestamp]->userCan(Revision::DELETED_RESTRICTED) ) {
00261
00262 if( !$this->wasPosted ) {
00263 $wgOut->permissionRequired( 'suppressrevision' );
00264 return;
00265 }
00266 $UserAllowed = false;
00267 }
00268 $revisions++;
00269 $wgOut->addHTML( $this->historyLine( $revObjs[$timestamp] ) );
00270 $bitfields |= $revObjs[$timestamp]->mDeleted;
00271 }
00272 }
00273 if( !$revisions ) {
00274 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
00275 return;
00276 }
00277
00278 $wgOut->addHTML( "</ul>" );
00279
00280 $this->addUsageText();
00281
00282
00283 if( !$UserAllowed ) return;
00284
00285 $items = array(
00286 Xml::inputLabel( wfMsg( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
00287 Xml::submitButton( wfMsg( 'revdelete-submit' ) )
00288 );
00289 $hidden = array(
00290 Xml::hidden( 'wpEditToken', $wgUser->editToken() ),
00291 Xml::hidden( 'target', $this->page->getPrefixedText() ),
00292 Xml::hidden( 'type', $this->deleteKey )
00293 );
00294 if( $this->deleteKey=='oldid' ) {
00295 foreach( $revObjs as $rev )
00296 $hidden[] = Xml::hidden( 'oldid[]', $rev->getId() );
00297 } else {
00298 foreach( $revObjs as $rev )
00299 $hidden[] = Xml::hidden( 'artimestamp[]', $rev->getTimestamp() );
00300 }
00301 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
00302 $wgOut->addHTML(
00303 Xml::openElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ),
00304 'id' => 'mw-revdel-form-revisions' ) ) .
00305 Xml::openElement( 'fieldset' ) .
00306 xml::element( 'legend', null, wfMsg( 'revdelete-legend' ) )
00307 );
00308
00309 $wgOut->addHTML( $this->buildCheckBoxes( $bitfields ) );
00310 foreach( $items as $item ) {
00311 $wgOut->addHTML( Xml::tags( 'p', null, $item ) );
00312 }
00313 foreach( $hidden as $item ) {
00314 $wgOut->addHTML( $item );
00315 }
00316 $wgOut->addHTML(
00317 Xml::closeElement( 'fieldset' ) .
00318 Xml::closeElement( 'form' ) . "\n"
00319 );
00320 }
00321
00325 private function showImages() {
00326 global $wgOut, $wgUser, $wgLang;
00327 $UserAllowed = true;
00328
00329 $count = ($this->deleteKey=='oldimage') ? count($this->ofiles) : count($this->afiles);
00330 $wgOut->addWikiMsg( 'revdelete-selected', $this->page->getPrefixedText(),
00331 $wgLang->formatNum($count) );
00332
00333 $bitfields = 0;
00334 $wgOut->addHTML( "<ul>" );
00335
00336 $where = $filesObjs = array();
00337 $dbr = wfGetDB( DB_MASTER );
00338
00339 $revisions = 0;
00340 if( $this->deleteKey=='oldimage' ) {
00341
00342 foreach( $this->ofiles as $timestamp ) {
00343 $where[] = $timestamp.'!'.$this->page->getDBKey();
00344 }
00345 $result = $dbr->select( 'oldimage', '*',
00346 array(
00347 'oi_name' => $this->page->getDBKey(),
00348 'oi_archive_name' => $where ),
00349 __METHOD__ );
00350 while( $row = $dbr->fetchObject( $result ) ) {
00351 $filesObjs[$row->oi_archive_name] = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
00352 $filesObjs[$row->oi_archive_name]->user = $row->oi_user;
00353 $filesObjs[$row->oi_archive_name]->user_text = $row->oi_user_text;
00354 }
00355
00356 foreach( $this->ofiles as $timestamp ) {
00357 $archivename = $timestamp.'!'.$this->page->getDBKey();
00358 if( !isset($filesObjs[$archivename]) ) {
00359 continue;
00360 } else if( !$filesObjs[$archivename]->userCan(File::DELETED_RESTRICTED) ) {
00361
00362 if( !$this->wasPosted ) {
00363 $wgOut->permissionRequired( 'suppressrevision' );
00364 return;
00365 }
00366 $UserAllowed = false;
00367 }
00368 $revisions++;
00369
00370 $wgOut->addHTML( $this->fileLine( $filesObjs[$archivename] ) );
00371 $bitfields |= $filesObjs[$archivename]->deleted;
00372 }
00373
00374 } else {
00375
00376 foreach( $this->afiles as $id ) {
00377 $where[] = intval($id);
00378 }
00379 $result = $dbr->select( 'filearchive', '*',
00380 array(
00381 'fa_name' => $this->page->getDBKey(),
00382 'fa_id' => $where ),
00383 __METHOD__ );
00384 while( $row = $dbr->fetchObject( $result ) ) {
00385 $filesObjs[$row->fa_id] = ArchivedFile::newFromRow( $row );
00386 }
00387
00388 foreach( $this->afiles as $fileid ) {
00389 if( !isset($filesObjs[$fileid]) ) {
00390 continue;
00391 } else if( !$filesObjs[$fileid]->userCan(File::DELETED_RESTRICTED) ) {
00392
00393 if( !$this->wasPosted ) {
00394 $wgOut->permissionRequired( 'suppressrevision' );
00395 return;
00396 }
00397 $UserAllowed = false;
00398 }
00399 $revisions++;
00400
00401 $wgOut->addHTML( $this->archivedfileLine( $filesObjs[$fileid] ) );
00402 $bitfields |= $filesObjs[$fileid]->deleted;
00403 }
00404 }
00405 if( !$revisions ) {
00406 $wgOut->showErrorPage( 'revdelete-nooldid-title', 'revdelete-nooldid-text' );
00407 return;
00408 }
00409
00410 $wgOut->addHTML( "</ul>" );
00411
00412 $this->addUsageText();
00413
00414 if( !$UserAllowed ) return;
00415
00416 $items = array(
00417 Xml::inputLabel( wfMsg( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
00418 Xml::submitButton( wfMsg( 'revdelete-submit' ) )
00419 );
00420 $hidden = array(
00421 Xml::hidden( 'wpEditToken', $wgUser->editToken() ),
00422 Xml::hidden( 'target', $this->page->getPrefixedText() ),
00423 Xml::hidden( 'type', $this->deleteKey )
00424 );
00425 if( $this->deleteKey=='oldimage' ) {
00426 foreach( $this->ofiles as $filename )
00427 $hidden[] = Xml::hidden( 'oldimage[]', $filename );
00428 } else {
00429 foreach( $this->afiles as $fileid )
00430 $hidden[] = Xml::hidden( 'fileid[]', $fileid );
00431 }
00432 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
00433 $wgOut->addHTML(
00434 Xml::openElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ),
00435 'id' => 'mw-revdel-form-filerevisions' ) ) .
00436 Xml::fieldset( wfMsg( 'revdelete-legend' ) )
00437 );
00438
00439 $wgOut->addHTML( $this->buildCheckBoxes( $bitfields ) );
00440 foreach( $items as $item ) {
00441 $wgOut->addHTML( "<p>$item</p>" );
00442 }
00443 foreach( $hidden as $item ) {
00444 $wgOut->addHTML( $item );
00445 }
00446
00447 $wgOut->addHTML(
00448 Xml::closeElement( 'fieldset' ) .
00449 Xml::closeElement( 'form' ) . "\n"
00450 );
00451 }
00452
00456 private function showLogItems() {
00457 global $wgOut, $wgUser, $wgMessageCache, $wgLang;
00458 $UserAllowed = true;
00459
00460 $wgOut->addWikiMsg( 'logdelete-selected', $wgLang->formatNum( count($this->events) ) );
00461
00462 $bitfields = 0;
00463 $wgOut->addHTML( "<ul>" );
00464
00465 $where = $logRows = array();
00466 $dbr = wfGetDB( DB_MASTER );
00467
00468 $logItems = 0;
00469 foreach( $this->events as $logid ) {
00470 $where[] = intval($logid);
00471 }
00472 list($log,$logtype) = explode( '/',$this->page->getDBKey(), 2 );
00473 $result = $dbr->select( 'logging', '*',
00474 array(
00475 'log_type' => $logtype,
00476 'log_id' => $where ),
00477 __METHOD__ );
00478 while( $row = $dbr->fetchObject( $result ) ) {
00479 $logRows[$row->log_id] = $row;
00480 }
00481 $wgMessageCache->loadAllMessages();
00482 foreach( $this->events as $logid ) {
00483
00484 if( !isset( $logRows[$logid] ) || $logRows[$logid]->log_type=='suppress' ) {
00485 continue;
00486 } else if( !LogEventsList::userCan( $logRows[$logid],Revision::DELETED_RESTRICTED) ) {
00487
00488 if( !$this->wasPosted ) {
00489 $wgOut->permissionRequired( 'suppressrevision' );
00490 return;
00491 }
00492 $UserAllowed = false;
00493 }
00494 $logItems++;
00495 $wgOut->addHTML( $this->logLine( $logRows[$logid] ) );
00496 $bitfields |= $logRows[$logid]->log_deleted;
00497 }
00498 if( !$logItems ) {
00499 $wgOut->showErrorPage( 'revdelete-nologid-title', 'revdelete-nologid-text' );
00500 return;
00501 }
00502
00503 $wgOut->addHTML( "</ul>" );
00504
00505 $this->addUsageText();
00506
00507 if( !$UserAllowed ) return;
00508
00509 $items = array(
00510 Xml::inputLabel( wfMsg( 'revdelete-log' ), 'wpReason', 'wpReason', 60 ),
00511 Xml::submitButton( wfMsg( 'revdelete-submit' ) ) );
00512 $hidden = array(
00513 Xml::hidden( 'wpEditToken', $wgUser->editToken() ),
00514 Xml::hidden( 'target', $this->page->getPrefixedText() ),
00515 Xml::hidden( 'type', $this->deleteKey ) );
00516 foreach( $this->events as $logid ) {
00517 $hidden[] = Xml::hidden( 'logid[]', $logid );
00518 }
00519
00520 $special = SpecialPage::getTitleFor( 'Revisiondelete' );
00521 $wgOut->addHTML(
00522 Xml::openElement( 'form', array( 'method' => 'post', 'action' => $special->getLocalUrl( 'action=submit' ),
00523 'id' => 'mw-revdel-form-logs' ) ) .
00524 Xml::fieldset( wfMsg( 'revdelete-legend' ) )
00525 );
00526
00527 $wgOut->addHTML( $this->buildCheckBoxes( $bitfields ) );
00528 foreach( $items as $item ) {
00529 $wgOut->addHTML( "<p>$item</p>" );
00530 }
00531 foreach( $hidden as $item ) {
00532 $wgOut->addHTML( $item );
00533 }
00534
00535 $wgOut->addHTML(
00536 Xml::closeElement( 'fieldset' ) .
00537 Xml::closeElement( 'form' ) . "\n"
00538 );
00539 }
00540
00541 private function addUsageText() {
00542 global $wgOut, $wgUser;
00543 $wgOut->addWikiMsg( 'revdelete-text' );
00544 if( $wgUser->isAllowed( 'suppressrevision' ) ) {
00545 $wgOut->addWikiMsg( 'revdelete-suppress-text' );
00546 }
00547 }
00548
00553 private function buildCheckBoxes( $bitfields ) {
00554 $html = '';
00555
00556 foreach( $this->checks as $item ) {
00557 list( $message, $name, $field ) = $item;
00558 $line = Xml::tags( 'div', null, Xml::checkLabel( wfMsg($message), $name, $name,
00559 $bitfields & $field ) );
00560 if( $field == Revision::DELETED_RESTRICTED ) $line = "<b>$line</b>";
00561 $html .= $line;
00562 }
00563 return $html;
00564 }
00565
00570 private function historyLine( $rev ) {
00571 global $wgLang, $wgUser;
00572
00573 $date = $wgLang->timeanddate( $rev->getTimestamp() );
00574 $difflink = $del = '';
00575
00576 if( $this->deleteKey=='oldid' ) {
00577 $tokenParams = '&unhide=1&token='.urlencode( $wgUser->editToken( $rev->getId() ) );
00578 $revlink = $this->skin->makeLinkObj( $this->page, $date, 'oldid='.$rev->getId() . $tokenParams );
00579 $difflink = '(' . $this->skin->makeKnownLinkObj( $this->page, wfMsgHtml('diff'),
00580 'diff=' . $rev->getId() . '&oldid=prev' . $tokenParams ) . ')';
00581
00582 } else {
00583 $undelete = SpecialPage::getTitleFor( 'Undelete' );
00584 $target = $this->page->getPrefixedText();
00585 $revlink = $this->skin->makeLinkObj( $undelete, $date,
00586 "target=$target×tamp=" . $rev->getTimestamp() );
00587 $difflink = '(' . $this->skin->makeKnownLinkObj( $undelete, wfMsgHtml('diff'),
00588 "target=$target&diff=prev×tamp=" . $rev->getTimestamp() ) . ')';
00589 }
00590
00591 if( $rev->isDeleted(Revision::DELETED_TEXT) ) {
00592 $revlink = '<span class="history-deleted">'.$revlink.'</span>';
00593 $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>';
00594 if( !$rev->userCan(Revision::DELETED_TEXT) ) {
00595 $revlink = '<span class="history-deleted">'.$date.'</span>';
00596 $difflink = '(' . wfMsgHtml('diff') . ')';
00597 }
00598 }
00599 $userlink = $this->skin->revUserLink( $rev );
00600 $comment = $this->skin->revComment( $rev );
00601
00602 return "<li>$difflink $revlink $userlink $comment{$del}</li>";
00603 }
00604
00609 private function fileLine( $file ) {
00610 global $wgLang, $wgTitle;
00611
00612 $target = $this->page->getPrefixedText();
00613 $date = $wgLang->timeanddate( $file->getTimestamp(), true );
00614
00615 $del = '';
00616 # Hidden files...
00617 if( $file->isDeleted(File::DELETED_FILE) ) {
00618 $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>';
00619 if( !$file->userCan(File::DELETED_FILE) ) {
00620 $pageLink = $date;
00621 } else {
00622 $pageLink = $this->skin->makeKnownLinkObj( $wgTitle, $date,
00623 "target=$target&file=$file->sha1.".$file->getExtension() );
00624 }
00625 $pageLink = '<span class="history-deleted">' . $pageLink . '</span>';
00626 # Regular files...
00627 } else {
00628 $url = $file->getUrlRel();
00629 $pageLink = "<a href=\"{$url}\">{$date}</a>";
00630 }
00631
00632 $data = wfMsg( 'widthheight',
00633 $wgLang->formatNum( $file->getWidth() ),
00634 $wgLang->formatNum( $file->getHeight() ) ) .
00635 ' (' . wfMsgExt( 'nbytes', 'parsemag', $wgLang->formatNum( $file->getSize() ) ) . ')';
00636 $data = htmlspecialchars( $data );
00637
00638 return "<li>$pageLink ".$this->fileUserTools( $file )." $data ".$this->fileComment( $file )."$del</li>";
00639 }
00640
00645 private function archivedfileLine( $file ) {
00646 global $wgLang;
00647
00648 $target = $this->page->getPrefixedText();
00649 $date = $wgLang->timeanddate( $file->getTimestamp(), true );
00650
00651 $undelete = SpecialPage::getTitleFor( 'Undelete' );
00652 $pageLink = $this->skin->makeKnownLinkObj( $undelete, $date, "target=$target&file={$file->getKey()}" );
00653
00654 $del = '';
00655 if( $file->isDeleted(File::DELETED_FILE) ) {
00656 $del = ' <tt>' . wfMsgHtml( 'deletedrev' ) . '</tt>';
00657 }
00658
00659 $data = wfMsg( 'widthheight',
00660 $wgLang->formatNum( $file->getWidth() ),
00661 $wgLang->formatNum( $file->getHeight() ) ) .
00662 ' (' . wfMsgExt( 'nbytes', 'parsemag', $wgLang->formatNum( $file->getSize() ) ) . ')';
00663 $data = htmlspecialchars( $data );
00664
00665 return "<li> $pageLink ".$this->fileUserTools( $file )." $data ".$this->fileComment( $file )."$del</li>";
00666 }
00667
00672 private function logLine( $row ) {
00673 global $wgLang;
00674
00675 $date = $wgLang->timeanddate( $row->log_timestamp );
00676 $paramArray = LogPage::extractParams( $row->log_params );
00677 $title = Title::makeTitle( $row->log_namespace, $row->log_title );
00678
00679 $logtitle = SpecialPage::getTitleFor( 'Log' );
00680 $loglink = $this->skin->makeKnownLinkObj( $logtitle, wfMsgHtml( 'log' ),
00681 wfArrayToCGI( array( 'page' => $title->getPrefixedUrl() ) ) );
00682
00683 if( !LogEventsList::userCan($row,LogPage::DELETED_ACTION) ) {
00684 $action = '<span class="history-deleted">' . wfMsgHtml('rev-deleted-event') . '</span>';
00685 } else {
00686 $action = LogPage::actionText( $row->log_type, $row->log_action, $title,
00687 $this->skin, $paramArray, true, true );
00688 if( $row->log_deleted & LogPage::DELETED_ACTION )
00689 $action = '<span class="history-deleted">' . $action . '</span>';
00690 }
00691
00692 $userLink = $this->skin->userLink( $row->log_user, User::WhoIs($row->log_user) );
00693 if( LogEventsList::isDeleted($row,LogPage::DELETED_USER) ) {
00694 $userLink = '<span class="history-deleted">' . $userLink . '</span>';
00695 }
00696
00697 $comment = $wgLang->getDirMark() . $this->skin->commentBlock( $row->log_comment );
00698 if( LogEventsList::isDeleted($row,LogPage::DELETED_COMMENT) ) {
00699 $comment = '<span class="history-deleted">' . $comment . '</span>';
00700 }
00701 return "<li>($loglink) $date $userLink $action $comment</li>";
00702 }
00703
00709 private function fileUserTools( $file ) {
00710 if( $file->userCan( Revision::DELETED_USER ) ) {
00711 $link = $this->skin->userLink( $file->user, $file->user_text ) .
00712 $this->skin->userToolLinks( $file->user, $file->user_text );
00713 } else {
00714 $link = wfMsgHtml( 'rev-deleted-user' );
00715 }
00716 if( $file->isDeleted( Revision::DELETED_USER ) ) {
00717 return '<span class="history-deleted">' . $link . '</span>';
00718 }
00719 return $link;
00720 }
00721
00729 private function fileComment( $file ) {
00730 if( $file->userCan( File::DELETED_COMMENT ) ) {
00731 $block = $this->skin->commentBlock( $file->description );
00732 } else {
00733 $block = ' ' . wfMsgHtml( 'rev-deleted-comment' );
00734 }
00735 if( $file->isDeleted( File::DELETED_COMMENT ) ) {
00736 return "<span class=\"history-deleted\">$block</span>";
00737 }
00738 return $block;
00739 }
00740
00744 private function submit( $request ) {
00745 global $wgUser, $wgOut;
00746 # Check edit token on submission
00747 if( $this->wasPosted && !$wgUser->matchEditToken( $request->getVal('wpEditToken') ) ) {
00748 $wgOut->addWikiMsg( 'sessionfailure' );
00749 return false;
00750 }
00751 $bitfield = $this->extractBitfield( $request );
00752 $comment = $request->getText( 'wpReason' );
00753 # Can the user set this field?
00754 if( $bitfield & Revision::DELETED_RESTRICTED && !$wgUser->isAllowed('suppressrevision') ) {
00755 $wgOut->permissionRequired( 'suppressrevision' );
00756 return false;
00757 }
00758 # If the save went through, go to success message. Otherwise
00759 # bounce back to form...
00760 if( $this->save( $bitfield, $comment, $this->page ) ) {
00761 $this->success();
00762 } else if( $request->getCheck( 'oldid' ) || $request->getCheck( 'artimestamp' ) ) {
00763 return $this->showRevs();
00764 } else if( $request->getCheck( 'logid' ) ) {
00765 return $this->showLogs();
00766 } else if( $request->getCheck( 'oldimage' ) || $request->getCheck( 'fileid' ) ) {
00767 return $this->showImages();
00768 }
00769 }
00770
00771 private function success() {
00772 global $wgOut;
00773
00774 $wgOut->setPagetitle( wfMsg( 'actioncomplete' ) );
00775
00776 $wrap = '<span class="success">$1</span>';
00777
00778 if( $this->deleteKey=='logid' ) {
00779 $wgOut->wrapWikiMsg( $wrap, 'logdelete-success' );
00780 $this->showLogItems();
00781 } else if( $this->deleteKey=='oldid' || $this->deleteKey=='artimestamp' ) {
00782 $wgOut->wrapWikiMsg( $wrap, 'revdelete-success' );
00783 $this->showRevs();
00784 } else if( $this->deleteKey=='fileid' ) {
00785 $wgOut->wrapWikiMsg( $wrap, 'revdelete-success' );
00786 $this->showImages();
00787 } else if( $this->deleteKey=='oldimage' ) {
00788 $wgOut->wrapWikiMsg( $wrap, 'revdelete-success' );
00789 $this->showImages();
00790 }
00791 }
00792
00798 private function extractBitfield( $request ) {
00799 $bitfield = 0;
00800 foreach( $this->checks as $item ) {
00801 list( , $name, $field ) = $item;
00802 if( $request->getCheck( $name ) ) {
00803 $bitfield |= $field;
00804 }
00805 }
00806 return $bitfield;
00807 }
00808
00809 private function save( $bitfield, $reason, $title ) {
00810 $dbw = wfGetDB( DB_MASTER );
00811
00812 if( $bitfield == Revision::DELETED_RESTRICTED ) {
00813 $bitfield = 0;
00814 }
00815 $deleter = new RevisionDeleter( $dbw );
00816
00817 if( isset($this->revisions) ) {
00818 return $deleter->setRevVisibility( $title, $this->revisions, $bitfield, $reason );
00819 } else if( isset($this->archrevs) ) {
00820 return $deleter->setArchiveVisibility( $title, $this->archrevs, $bitfield, $reason );
00821 } else if( isset($this->ofiles) ) {
00822 return $deleter->setOldImgVisibility( $title, $this->ofiles, $bitfield, $reason );
00823 } else if( isset($this->afiles) ) {
00824 return $deleter->setArchFileVisibility( $title, $this->afiles, $bitfield, $reason );
00825 } else if( isset($this->events) ) {
00826 return $deleter->setEventVisibility( $title, $this->events, $bitfield, $reason );
00827 }
00828 }
00829 }
00830
00835 class RevisionDeleter {
00836 function __construct( $db ) {
00837 $this->dbw = $db;
00838 }
00839
00846 function setRevVisibility( $title, $items, $bitfield, $comment ) {
00847 global $wgOut;
00848
00849 $userAllowedAll = $success = true;
00850 $revIDs = array();
00851 $revCount = 0;
00852
00853 foreach( $items as $revid ) {
00854 $where[] = intval($revid);
00855 }
00856 $result = $this->dbw->select( 'revision', '*',
00857 array(
00858 'rev_page' => $title->getArticleID(),
00859 'rev_id' => $where ),
00860 __METHOD__ );
00861 while( $row = $this->dbw->fetchObject( $result ) ) {
00862 $revObjs[$row->rev_id] = new Revision( $row );
00863 }
00864
00865 foreach( $items as $revid ) {
00866 if( !isset($revObjs[$revid]) || $revObjs[$revid]->isCurrent() ) {
00867 $success = false;
00868 continue;
00869 } else if( !$revObjs[$revid]->userCan(Revision::DELETED_RESTRICTED) ) {
00870 $userAllowedAll=false;
00871 continue;
00872 }
00873
00874 if( $revObjs[$revid]->mDeleted != $bitfield ) {
00875 $revCount++;
00876 $revIDs[]=$revid;
00877
00878 $this->updateRevision( $revObjs[$revid], $bitfield );
00879 $this->updateRecentChangesEdits( $revObjs[$revid], $bitfield, false );
00880 }
00881 }
00882
00883
00884 if( $revCount > 0 ) {
00885 $this->updateLog( $title, $revCount, $bitfield, $revObjs[$revid]->mDeleted,
00886 $comment, $title, 'oldid', $revIDs );
00887 $this->updatePage( $title );
00888 }
00889
00890 if( !$userAllowedAll ) {
00891
00892 $wgOut->permissionRequired( 'suppressrevision' );
00893 return false;
00894 }
00895
00896 return $success;
00897 }
00898
00905 function setArchiveVisibility( $title, $items, $bitfield, $comment ) {
00906 global $wgOut;
00907
00908 $userAllowedAll = $success = true;
00909 $count = 0;
00910 $Id_set = array();
00911
00912 foreach( $items as $timestamp ) {
00913 $where[] = $this->dbw->timestamp( $timestamp );
00914 }
00915 $result = $this->dbw->select( 'archive', '*',
00916 array(
00917 'ar_namespace' => $title->getNamespace(),
00918 'ar_title' => $title->getDBKey(),
00919 'ar_timestamp' => $where ),
00920 __METHOD__ );
00921 while( $row = $this->dbw->fetchObject( $result ) ) {
00922 $timestamp = wfTimestamp( TS_MW, $row->ar_timestamp );
00923 $revObjs[$timestamp] = new Revision( array(
00924 'page' => $title->getArticleId(),
00925 'id' => $row->ar_rev_id,
00926 'text' => $row->ar_text_id,
00927 'comment' => $row->ar_comment,
00928 'user' => $row->ar_user,
00929 'user_text' => $row->ar_user_text,
00930 'timestamp' => $timestamp,
00931 'minor_edit' => $row->ar_minor_edit,
00932 'text_id' => $row->ar_text_id,
00933 'deleted' => $row->ar_deleted,
00934 'len' => $row->ar_len) );
00935 }
00936
00937 foreach( $items as $timestamp ) {
00938
00939
00940
00941 if( !is_object($revObjs[$timestamp]) ) {
00942 $success = false;
00943 continue;
00944 } else if( !$revObjs[$timestamp]->userCan(Revision::DELETED_RESTRICTED) ) {
00945 $userAllowedAll=false;
00946 continue;
00947 }
00948
00949 if( $revObjs[$timestamp]->mDeleted != $bitfield ) {
00950 $Id_set[]=$timestamp;
00951 $count++;
00952
00953 $this->updateArchive( $revObjs[$timestamp], $title, $bitfield );
00954 }
00955 }
00956
00957 if( $count > 0 ) {
00958 $this->updateLog( $title, $count, $bitfield, $revObjs[$timestamp]->mDeleted,
00959 $comment, $title, 'artimestamp', $Id_set );
00960 }
00961
00962 if( !$userAllowedAll ) {
00963 $wgOut->permissionRequired( 'suppressrevision' );
00964 return false;
00965 }
00966
00967 return $success;
00968 }
00969
00976 function setOldImgVisibility( $title, $items, $bitfield, $comment ) {
00977 global $wgOut;
00978
00979 $userAllowedAll = $success = true;
00980 $count = 0;
00981 $set = array();
00982
00983 foreach( $items as $timestamp ) {
00984 $where[] = $timestamp.'!'.$title->getDBKey();
00985 }
00986 $result = $this->dbw->select( 'oldimage', '*',
00987 array(
00988 'oi_name' => $title->getDBKey(),
00989 'oi_archive_name' => $where ),
00990 __METHOD__ );
00991 while( $row = $this->dbw->fetchObject( $result ) ) {
00992 $filesObjs[$row->oi_archive_name] = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
00993 $filesObjs[$row->oi_archive_name]->user = $row->oi_user;
00994 $filesObjs[$row->oi_archive_name]->user_text = $row->oi_user_text;
00995 }
00996
00997 foreach( $items as $timestamp ) {
00998 $archivename = $timestamp.'!'.$title->getDBKey();
00999 if( !isset($filesObjs[$archivename]) ) {
01000 $success = false;
01001 continue;
01002 } else if( !$filesObjs[$archivename]->userCan(File::DELETED_RESTRICTED) ) {
01003 $userAllowedAll=false;
01004 continue;
01005 }
01006
01007 $transaction = true;
01008
01009 if( $filesObjs[$archivename]->deleted != $bitfield ) {
01010 $count++;
01011
01012 $this->dbw->begin();
01013 $this->updateOldFiles( $filesObjs[$archivename], $bitfield );
01014
01015 if( $filesObjs[$archivename]->deleted & File::DELETED_FILE ) {
01016 if( $bitfield & File::DELETED_FILE ) {
01017 # Leave it alone if we are not changing this...
01018 $set[]=$archivename;
01019 $transaction = true;
01020 } else {
01021 # We are moving this out
01022 $transaction = $this->makeOldImagePublic( $filesObjs[$archivename] );
01023 $set[]=$transaction;
01024 }
01025
01026 } else if( $bitfield & File::DELETED_FILE ) {
01027 $transaction = $this->makeOldImagePrivate( $filesObjs[$archivename] );
01028 $set[]=$transaction;
01029 } else {
01030 $set[]=$timestamp;
01031 }
01032
01033 if( $transaction==false ) {
01034 $this->dbw->rollback();
01035 return false;
01036 }
01037 $this->dbw->commit();
01038 }
01039 }
01040
01041
01042 if( $count > 0 ) {
01043 $this->updateLog( $title, $count, $bitfield, $filesObjs[$archivename]->deleted,
01044 $comment, $title, 'oldimage', $set );
01045 # Purge page/history
01046 $file = wfLocalFile( $title );
01047 $file->purgeCache();
01048 $file->purgeHistory();
01049 # Invalidate cache for all pages using this file
01050 $update = new HTMLCacheUpdate( $title, 'imagelinks' );
01051 $update->doUpdate();
01052 }
01053
01054 if( !$userAllowedAll ) {
01055 $wgOut->permissionRequired( 'suppressrevision' );
01056 return false;
01057 }
01058
01059 return $success;
01060 }
01061
01068 function setArchFileVisibility( $title, $items, $bitfield, $comment ) {
01069 global $wgOut;
01070
01071 $userAllowedAll = $success = true;
01072 $count = 0;
01073 $Id_set = array();
01074
01075
01076 foreach( $items as $id ) {
01077 $where[] = intval($id);
01078 }
01079 $result = $this->dbw->select( 'filearchive', '*',
01080 array( 'fa_name' => $title->getDBKey(),
01081 'fa_id' => $where ),
01082 __METHOD__ );
01083 while( $row = $this->dbw->fetchObject( $result ) ) {
01084 $filesObjs[$row->fa_id] = ArchivedFile::newFromRow( $row );
01085 }
01086
01087 foreach( $items as $fileid ) {
01088 if( !isset($filesObjs[$fileid]) ) {
01089 $success = false;
01090 continue;
01091 } else if( !$filesObjs[$fileid]->userCan(File::DELETED_RESTRICTED) ) {
01092 $userAllowedAll=false;
01093 continue;
01094 }
01095
01096 if( $filesObjs[$fileid]->deleted != $bitfield ) {
01097 $Id_set[]=$fileid;
01098 $count++;
01099
01100 $this->updateArchFiles( $filesObjs[$fileid], $bitfield );
01101 }
01102 }
01103
01104 if( $count > 0 ) {
01105 $this->updateLog( $title, $count, $bitfield, $comment,
01106 $filesObjs[$fileid]->deleted, $title, 'fileid', $Id_set );
01107 }
01108
01109 if( !$userAllowedAll ) {
01110 $wgOut->permissionRequired( 'suppressrevision' );
01111 return false;
01112 }
01113
01114 return $success;
01115 }
01116
01123 function setEventVisibility( $title, $items, $bitfield, $comment ) {
01124 global $wgOut;
01125
01126 $userAllowedAll = $success = true;
01127 $count = 0;
01128 $log_Ids = array();
01129
01130
01131 foreach( $items as $logid ) {
01132 $where[] = intval($logid);
01133 }
01134 list($log,$logtype) = explode( '/',$title->getDBKey(), 2 );
01135 $result = $this->dbw->select( 'logging', '*',
01136 array(
01137 'log_type' => $logtype,
01138 'log_id' => $where ),
01139 __METHOD__ );
01140 while( $row = $this->dbw->fetchObject( $result ) ) {
01141 $logRows[$row->log_id] = $row;
01142 }
01143
01144 foreach( $items as $logid ) {
01145 if( !isset($logRows[$logid]) ) {
01146 $success = false;
01147 continue;
01148 } else if( !LogEventsList::userCan($logRows[$logid], LogPage::DELETED_RESTRICTED)
01149 || $logRows[$logid]->log_type == 'suppress' ) {
01150
01151 $userAllowedAll=false;
01152 continue;
01153 }
01154
01155 if( $logRows[$logid]->log_deleted != $bitfield ) {
01156 $log_Ids[]=$logid;
01157 $count++;
01158
01159 $this->updateLogs( $logRows[$logid], $bitfield );
01160 $this->updateRecentChangesLog( $logRows[$logid], $bitfield, true );
01161 }
01162 }
01163
01164 if( $count > 0 ) {
01165 $this->updateLog( $title, $count, $bitfield, $logRows[$logid]->log_deleted,
01166 $comment, $title, 'logid', $log_Ids );
01167 }
01168
01169 if( !$userAllowedAll ) {
01170 $wgOut->permissionRequired( 'suppressrevision' );
01171 return false;
01172 }
01173
01174 return $success;
01175 }
01176
01183 function makeOldImagePrivate( $oimage ) {
01184 $transaction = new FSTransaction();
01185 if( !FileStore::lock() ) {
01186 wfDebug( __METHOD__.": failed to acquire file store lock, aborting\n" );
01187 return false;
01188 }
01189 $oldpath = $oimage->getArchivePath() . DIRECTORY_SEPARATOR . $oimage->archive_name;
01190
01191 if( file_exists( $oldpath ) ) {
01192
01193 if( $store = FileStore::get( 'deleted' ) ) {
01194 if( !$oimage->sha1 ) {
01195 $oimage->upgradeRow();
01196 }
01197 $key = $oimage->sha1 . '.' . $oimage->getExtension();
01198 $transaction->add( $store->insert( $key, $oldpath, FileStore::DELETE_ORIGINAL ) );
01199 } else {
01200 $group = null;
01201 $key = null;
01202 $transaction = false;
01203 }
01204 } else {
01205 wfDebug( __METHOD__." deleting already-missing '$oldpath'; moving on to database\n" );
01206 $group = null;
01207 $key = '';
01208 $transaction = new FSTransaction();
01209 }
01210
01211 if( $transaction === false ) {
01212
01213 wfDebug( __METHOD__.": import to file store failed, aborting\n" );
01214 throw new MWException( "Could not archive and delete file $oldpath" );
01215 return false;
01216 }
01217
01218 wfDebug( __METHOD__.": set db items, applying file transactions\n" );
01219 $transaction->commit();
01220 FileStore::unlock();
01221
01222 $m = explode('!',$oimage->archive_name,2);
01223 $timestamp = $m[0];
01224
01225 return $timestamp;
01226 }
01227
01234 function makeOldImagePublic( $oimage ) {
01235 $transaction = new FSTransaction();
01236 if( !FileStore::lock() ) {
01237 wfDebug( __METHOD__." could not acquire filestore lock\n" );
01238 return false;
01239 }
01240
01241 $store = FileStore::get( 'deleted' );
01242 if( !$store ) {
01243 wfDebug( __METHOD__.": skipping row with no file.\n" );
01244 return false;
01245 }
01246
01247 $key = $oimage->sha1.'.'.$oimage->getExtension();
01248 $destDir = $oimage->getArchivePath();
01249 if( !is_dir( $destDir ) ) {
01250 wfMkdirParents( $destDir );
01251 }
01252 $destPath = $destDir . DIRECTORY_SEPARATOR . $oimage->archive_name;
01253
01254
01255
01256 $useCount = $this->dbw->selectField( 'oldimage', '1',
01257 array( 'oi_sha1' => $oimage->sha1,
01258 'oi_deleted & '.File::DELETED_FILE => File::DELETED_FILE ),
01259 __METHOD__, array( 'FOR UPDATE' ) );
01260
01261
01262 if( !$useCount ) {
01263 $useCount = $this->dbw->selectField( 'filearchive', '1',
01264 array( 'fa_storage_group' => 'deleted', 'fa_storage_key' => $key ),
01265 __METHOD__, array( 'FOR UPDATE' ) );
01266 }
01267
01268 if( $useCount == 0 ) {
01269 wfDebug( __METHOD__.": nothing else using {$oimage->sha1}, will deleting after\n" );
01270 $flags = FileStore::DELETE_ORIGINAL;
01271 } else {
01272 $flags = 0;
01273 }
01274 $transaction->add( $store->export( $key, $destPath, $flags ) );
01275
01276 wfDebug( __METHOD__.": set db items, applying file transactions\n" );
01277 $transaction->commit();
01278 FileStore::unlock();
01279
01280 $m = explode('!',$oimage->archive_name,2);
01281 $timestamp = $m[0];
01282
01283 return $timestamp;
01284 }
01285
01291 function updateRevision( $rev, $bitfield ) {
01292 $this->dbw->update( 'revision',
01293 array( 'rev_deleted' => $bitfield ),
01294 array( 'rev_id' => $rev->getId(),
01295 'rev_page' => $rev->getPage() ),
01296 __METHOD__ );
01297 }
01298
01305 function updateArchive( $rev, $title, $bitfield ) {
01306 $this->dbw->update( 'archive',
01307 array( 'ar_deleted' => $bitfield ),
01308 array( 'ar_namespace' => $title->getNamespace(),
01309 'ar_title' => $title->getDBKey(),
01310 'ar_timestamp' => $this->dbw->timestamp( $rev->getTimestamp() ),
01311 'ar_rev_id' => $rev->getId() ),
01312 __METHOD__ );
01313 }
01314
01320 function updateOldFiles( $file, $bitfield ) {
01321 $this->dbw->update( 'oldimage',
01322 array( 'oi_deleted' => $bitfield ),
01323 array( 'oi_name' => $file->getName(),
01324 'oi_timestamp' => $this->dbw->timestamp( $file->getTimestamp() ) ),
01325 __METHOD__ );
01326 }
01327
01333 function updateArchFiles( $file, $bitfield ) {
01334 $this->dbw->update( 'filearchive',
01335 array( 'fa_deleted' => $bitfield ),
01336 array( 'fa_id' => $file->getId() ),
01337 __METHOD__ );
01338 }
01339
01345 function updateLogs( $row, $bitfield ) {
01346 $this->dbw->update( 'logging',
01347 array( 'log_deleted' => $bitfield ),
01348 array( 'log_id' => $row->log_id ),
01349 __METHOD__ );
01350 }
01351
01357 function updateRecentChangesEdits( $rev, $bitfield ) {
01358 $this->dbw->update( 'recentchanges',
01359 array( 'rc_deleted' => $bitfield,
01360 'rc_patrolled' => 1 ),
01361 array( 'rc_this_oldid' => $rev->getId(),
01362 'rc_timestamp' => $this->dbw->timestamp( $rev->getTimestamp() ) ),
01363 __METHOD__ );
01364 }
01365
01371 function updateRecentChangesLog( $row, $bitfield ) {
01372 $this->dbw->update( 'recentchanges',
01373 array( 'rc_deleted' => $bitfield,
01374 'rc_patrolled' => 1 ),
01375 array( 'rc_logid' => $row->log_id,
01376 'rc_timestamp' => $row->log_timestamp ),
01377 __METHOD__ );
01378 }
01379
01386 function updatePage( $title ) {
01387 $title->invalidateCache();
01388 $title->purgeSquid();
01389 $title->touchLinks();
01390
01391 wfRunHooks( 'ArticleRevisionVisiblitySet', array( &$title ) );
01392 }
01393
01404 function checkItem ( $desc, $field, $diff, $new, &$arr ) {
01405 if ( $diff & $field ) {
01406 $arr [ ( $new & $field ) ? 0 : 1 ][] = $desc;
01407 }
01408 }
01409
01422 function getChanges ( $n, $o ) {
01423 $diff = $n ^ $o;
01424 $ret = array ( 0 => array(), 1 => array(), 2 => array() );
01425
01426 $this->checkItem ( wfMsgForContent ( 'revdelete-content' ),
01427 Revision::DELETED_TEXT, $diff, $n, $ret );
01428 $this->checkItem ( wfMsgForContent ( 'revdelete-summary' ),
01429 Revision::DELETED_COMMENT, $diff, $n, $ret );
01430 $this->checkItem ( wfMsgForContent ( 'revdelete-uname' ),
01431 Revision::DELETED_USER, $diff, $n, $ret );
01432
01433
01434 if ( $diff & Revision::DELETED_RESTRICTED ) {
01435 if ( $n & Revision::DELETED_RESTRICTED )
01436 $ret[2][] = wfMsgForContent ( 'revdelete-restricted' );
01437 else
01438 $ret[2][] = wfMsgForContent ( 'revdelete-unrestricted' );
01439 }
01440
01441 return $ret;
01442 }
01443
01455 function getLogMessage ( $count, $nbitfield, $obitfield, $comment, $isForLog = false ) {
01456 global $wgContLang;
01457
01458 $s = '';
01459 $changes = $this->getChanges( $nbitfield, $obitfield );
01460
01461 if ( count ( $changes[0] ) ) {
01462 $s .= wfMsgForContent ( 'revdelete-hid', implode ( ', ', $changes[0] ) );
01463 }
01464
01465 if ( count ( $changes[1] ) ) {
01466 if ($s) $s .= '; ';
01467
01468 $s .= wfMsgForContent ( 'revdelete-unhid', implode ( ', ', $changes[1] ) );
01469 }
01470
01471 if ( count ( $changes[2] )) {
01472 if ($s)
01473 $s .= ' (' . $changes[2][0] . ')';
01474 else
01475 $s = $changes[2][0];
01476 }
01477
01478 $msg = $isForLog ? 'logdelete-log-message' : 'revdelete-log-message';
01479 $ret = wfMsgExt ( $msg, array( 'parsemag', 'content' ),
01480 $s, $wgContLang->formatNum( $count ) );
01481
01482 if ( $comment )
01483 $ret .= ": $comment";
01484
01485 return $ret;
01486
01487 }
01488
01500 function updateLog( $title, $count, $nbitfield, $obitfield, $comment, $target, $param, $items = array() ) {
01501
01502 $logtype = ( ($nbitfield | $obitfield) & Revision::DELETED_RESTRICTED ) ? 'suppress' : 'delete';
01503 $log = new LogPage( $logtype );
01504
01505 $reason = $this->getLogMessage ( $count, $nbitfield, $obitfield, $comment, $param == 'logid' );
01506
01507 if( $param == 'logid' ) {
01508 $params = array( implode( ',', $items) );
01509 $log->addEntry( 'event', $title, $reason, $params );
01510 } else {
01511
01512 $params = array( $param, implode( ',', $items) );
01513 $log->addEntry( 'revision', $title, $reason, $params );
01514 }
01515 }
01516 }