MediaWiki
REL1_23
|
00001 <?php 00033 class RevDel_RevisionList extends RevDel_List { 00034 var $currentRevId; 00035 00036 public function getType() { 00037 return 'revision'; 00038 } 00039 00040 public static function getRelationType() { 00041 return 'rev_id'; 00042 } 00043 00044 public static function getRestriction() { 00045 return 'deleterevision'; 00046 } 00047 00048 public static function getRevdelConstant() { 00049 return Revision::DELETED_TEXT; 00050 } 00051 00052 public static function suggestTarget( $target, array $ids ) { 00053 $rev = Revision::newFromId( $ids[0] ); 00054 return $rev ? $rev->getTitle() : $target; 00055 } 00056 00061 public function doQuery( $db ) { 00062 $ids = array_map( 'intval', $this->ids ); 00063 $live = $db->select( 00064 array( 'revision', 'page', 'user' ), 00065 array_merge( Revision::selectFields(), Revision::selectUserFields() ), 00066 array( 00067 'rev_page' => $this->title->getArticleID(), 00068 'rev_id' => $ids, 00069 ), 00070 __METHOD__, 00071 array( 'ORDER BY' => 'rev_id DESC' ), 00072 array( 00073 'page' => Revision::pageJoinCond(), 00074 'user' => Revision::userJoinCond() ) 00075 ); 00076 00077 if ( $live->numRows() >= count( $ids ) ) { 00078 // All requested revisions are live, keeps things simple! 00079 return $live; 00080 } 00081 00082 // Check if any requested revisions are available fully deleted. 00083 $archived = $db->select( array( 'archive' ), '*', 00084 array( 00085 'ar_rev_id' => $ids 00086 ), 00087 __METHOD__, 00088 array( 'ORDER BY' => 'ar_rev_id DESC' ) 00089 ); 00090 00091 if ( $archived->numRows() == 0 ) { 00092 return $live; 00093 } elseif ( $live->numRows() == 0 ) { 00094 return $archived; 00095 } else { 00096 // Combine the two! Whee 00097 $rows = array(); 00098 foreach ( $live as $row ) { 00099 $rows[$row->rev_id] = $row; 00100 } 00101 foreach ( $archived as $row ) { 00102 $rows[$row->ar_rev_id] = $row; 00103 } 00104 krsort( $rows ); 00105 return new FakeResultWrapper( array_values( $rows ) ); 00106 } 00107 } 00108 00109 public function newItem( $row ) { 00110 if ( isset( $row->rev_id ) ) { 00111 return new RevDel_RevisionItem( $this, $row ); 00112 } elseif ( isset( $row->ar_rev_id ) ) { 00113 return new RevDel_ArchivedRevisionItem( $this, $row ); 00114 } else { 00115 // This shouldn't happen. :) 00116 throw new MWException( 'Invalid row type in RevDel_RevisionList' ); 00117 } 00118 } 00119 00120 public function getCurrent() { 00121 if ( is_null( $this->currentRevId ) ) { 00122 $dbw = wfGetDB( DB_MASTER ); 00123 $this->currentRevId = $dbw->selectField( 00124 'page', 'page_latest', $this->title->pageCond(), __METHOD__ ); 00125 } 00126 return $this->currentRevId; 00127 } 00128 00129 public function getSuppressBit() { 00130 return Revision::DELETED_RESTRICTED; 00131 } 00132 00133 public function doPreCommitUpdates() { 00134 $this->title->invalidateCache(); 00135 return Status::newGood(); 00136 } 00137 00138 public function doPostCommitUpdates() { 00139 $this->title->purgeSquid(); 00140 // Extensions that require referencing previous revisions may need this 00141 wfRunHooks( 'ArticleRevisionVisibilitySet', array( &$this->title ) ); 00142 return Status::newGood(); 00143 } 00144 } 00145 00149 class RevDel_RevisionItem extends RevDel_Item { 00150 var $revision; 00151 00152 public function __construct( $list, $row ) { 00153 parent::__construct( $list, $row ); 00154 $this->revision = new Revision( $row ); 00155 } 00156 00157 public function getIdField() { 00158 return 'rev_id'; 00159 } 00160 00161 public function getTimestampField() { 00162 return 'rev_timestamp'; 00163 } 00164 00165 public function getAuthorIdField() { 00166 return 'rev_user'; 00167 } 00168 00169 public function getAuthorNameField() { 00170 return 'user_name'; // see Revision::selectUserFields() 00171 } 00172 00173 public function canView() { 00174 return $this->revision->userCan( Revision::DELETED_RESTRICTED, $this->list->getUser() ); 00175 } 00176 00177 public function canViewContent() { 00178 return $this->revision->userCan( Revision::DELETED_TEXT, $this->list->getUser() ); 00179 } 00180 00181 public function getBits() { 00182 return $this->revision->getVisibility(); 00183 } 00184 00185 public function setBits( $bits ) { 00186 $dbw = wfGetDB( DB_MASTER ); 00187 // Update revision table 00188 $dbw->update( 'revision', 00189 array( 'rev_deleted' => $bits ), 00190 array( 00191 'rev_id' => $this->revision->getId(), 00192 'rev_page' => $this->revision->getPage(), 00193 'rev_deleted' => $this->getBits() 00194 ), 00195 __METHOD__ 00196 ); 00197 if ( !$dbw->affectedRows() ) { 00198 // Concurrent fail! 00199 return false; 00200 } 00201 // Update recentchanges table 00202 $dbw->update( 'recentchanges', 00203 array( 00204 'rc_deleted' => $bits, 00205 'rc_patrolled' => 1 00206 ), 00207 array( 00208 'rc_this_oldid' => $this->revision->getId(), // condition 00209 // non-unique timestamp index 00210 'rc_timestamp' => $dbw->timestamp( $this->revision->getTimestamp() ), 00211 ), 00212 __METHOD__ 00213 ); 00214 return true; 00215 } 00216 00217 public function isDeleted() { 00218 return $this->revision->isDeleted( Revision::DELETED_TEXT ); 00219 } 00220 00221 public function isHideCurrentOp( $newBits ) { 00222 return ( $newBits & Revision::DELETED_TEXT ) 00223 && $this->list->getCurrent() == $this->getId(); 00224 } 00225 00231 protected function getRevisionLink() { 00232 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate( 00233 $this->revision->getTimestamp(), $this->list->getUser() ) ); 00234 00235 if ( $this->isDeleted() && !$this->canViewContent() ) { 00236 return $date; 00237 } 00238 return Linker::linkKnown( 00239 $this->list->title, 00240 $date, 00241 array(), 00242 array( 00243 'oldid' => $this->revision->getId(), 00244 'unhide' => 1 00245 ) 00246 ); 00247 } 00248 00254 protected function getDiffLink() { 00255 if ( $this->isDeleted() && !$this->canViewContent() ) { 00256 return $this->list->msg( 'diff' )->escaped(); 00257 } else { 00258 return Linker::linkKnown( 00259 $this->list->title, 00260 $this->list->msg( 'diff' )->escaped(), 00261 array(), 00262 array( 00263 'diff' => $this->revision->getId(), 00264 'oldid' => 'prev', 00265 'unhide' => 1 00266 ) 00267 ); 00268 } 00269 } 00270 00271 public function getHTML() { 00272 $difflink = $this->list->msg( 'parentheses' ) 00273 ->rawParams( $this->getDiffLink() )->escaped(); 00274 $revlink = $this->getRevisionLink(); 00275 $userlink = Linker::revUserLink( $this->revision ); 00276 $comment = Linker::revComment( $this->revision ); 00277 if ( $this->isDeleted() ) { 00278 $revlink = "<span class=\"history-deleted\">$revlink</span>"; 00279 } 00280 return "<li>$difflink $revlink $userlink $comment</li>"; 00281 } 00282 00283 public function getApiData( ApiResult $result ) { 00284 $rev = $this->revision; 00285 $user = $this->list->getUser(); 00286 $ret = array( 00287 'id' => $rev->getId(), 00288 'timestamp' => wfTimestamp( TS_ISO_8601, $rev->getTimestamp() ), 00289 ); 00290 $ret += $rev->isDeleted( Revision::DELETED_USER ) ? array( 'userhidden' => '' ) : array(); 00291 $ret += $rev->isDeleted( Revision::DELETED_COMMENT ) ? array( 'commenthidden' => '' ) : array(); 00292 $ret += $rev->isDeleted( Revision::DELETED_TEXT ) ? array( 'texthidden' => '' ) : array(); 00293 if ( $rev->userCan( Revision::DELETED_USER, $user ) ) { 00294 $ret += array( 00295 'userid' => $rev->getUser( Revision::FOR_THIS_USER ), 00296 'user' => $rev->getUserText( Revision::FOR_THIS_USER ), 00297 ); 00298 } 00299 if ( $rev->userCan( Revision::DELETED_COMMENT, $user ) ) { 00300 $ret += array( 00301 'comment' => $rev->getComment( Revision::FOR_THIS_USER ), 00302 ); 00303 } 00304 return $ret; 00305 } 00306 } 00307 00311 class RevDel_ArchiveList extends RevDel_RevisionList { 00312 public function getType() { 00313 return 'archive'; 00314 } 00315 00316 public static function getRelationType() { 00317 return 'ar_timestamp'; 00318 } 00319 00324 public function doQuery( $db ) { 00325 $timestamps = array(); 00326 foreach ( $this->ids as $id ) { 00327 $timestamps[] = $db->timestamp( $id ); 00328 } 00329 return $db->select( 'archive', '*', 00330 array( 00331 'ar_namespace' => $this->title->getNamespace(), 00332 'ar_title' => $this->title->getDBkey(), 00333 'ar_timestamp' => $timestamps 00334 ), 00335 __METHOD__, 00336 array( 'ORDER BY' => 'ar_timestamp DESC' ) 00337 ); 00338 } 00339 00340 public function newItem( $row ) { 00341 return new RevDel_ArchiveItem( $this, $row ); 00342 } 00343 00344 public function doPreCommitUpdates() { 00345 return Status::newGood(); 00346 } 00347 00348 public function doPostCommitUpdates() { 00349 return Status::newGood(); 00350 } 00351 } 00352 00356 class RevDel_ArchiveItem extends RevDel_RevisionItem { 00357 public function __construct( $list, $row ) { 00358 RevDel_Item::__construct( $list, $row ); 00359 $this->revision = Revision::newFromArchiveRow( $row, 00360 array( 'page' => $this->list->title->getArticleID() ) ); 00361 } 00362 00363 public function getIdField() { 00364 return 'ar_timestamp'; 00365 } 00366 00367 public function getTimestampField() { 00368 return 'ar_timestamp'; 00369 } 00370 00371 public function getAuthorIdField() { 00372 return 'ar_user'; 00373 } 00374 00375 public function getAuthorNameField() { 00376 return 'ar_user_text'; 00377 } 00378 00379 public function getId() { 00380 # Convert DB timestamp to MW timestamp 00381 return $this->revision->getTimestamp(); 00382 } 00383 00384 public function setBits( $bits ) { 00385 $dbw = wfGetDB( DB_MASTER ); 00386 $dbw->update( 'archive', 00387 array( 'ar_deleted' => $bits ), 00388 array( 00389 'ar_namespace' => $this->list->title->getNamespace(), 00390 'ar_title' => $this->list->title->getDBkey(), 00391 // use timestamp for index 00392 'ar_timestamp' => $this->row->ar_timestamp, 00393 'ar_rev_id' => $this->row->ar_rev_id, 00394 'ar_deleted' => $this->getBits() 00395 ), 00396 __METHOD__ ); 00397 return (bool)$dbw->affectedRows(); 00398 } 00399 00400 protected function getRevisionLink() { 00401 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate( 00402 $this->revision->getTimestamp(), $this->list->getUser() ) ); 00403 00404 if ( $this->isDeleted() && !$this->canViewContent() ) { 00405 return $date; 00406 } 00407 00408 return Linker::link( 00409 SpecialPage::getTitleFor( 'Undelete' ), 00410 $date, 00411 array(), 00412 array( 00413 'target' => $this->list->title->getPrefixedText(), 00414 'timestamp' => $this->revision->getTimestamp() 00415 ) 00416 ); 00417 } 00418 00419 protected function getDiffLink() { 00420 if ( $this->isDeleted() && !$this->canViewContent() ) { 00421 return $this->list->msg( 'diff' )->escaped(); 00422 } 00423 00424 return Linker::link( 00425 SpecialPage::getTitleFor( 'Undelete' ), 00426 $this->list->msg( 'diff' )->escaped(), 00427 array(), 00428 array( 00429 'target' => $this->list->title->getPrefixedText(), 00430 'diff' => 'prev', 00431 'timestamp' => $this->revision->getTimestamp() 00432 ) 00433 ); 00434 } 00435 } 00436 00441 class RevDel_ArchivedRevisionItem extends RevDel_ArchiveItem { 00442 public function __construct( $list, $row ) { 00443 RevDel_Item::__construct( $list, $row ); 00444 00445 $this->revision = Revision::newFromArchiveRow( $row, 00446 array( 'page' => $this->list->title->getArticleID() ) ); 00447 } 00448 00449 public function getIdField() { 00450 return 'ar_rev_id'; 00451 } 00452 00453 public function getId() { 00454 return $this->revision->getId(); 00455 } 00456 00457 public function setBits( $bits ) { 00458 $dbw = wfGetDB( DB_MASTER ); 00459 $dbw->update( 'archive', 00460 array( 'ar_deleted' => $bits ), 00461 array( 'ar_rev_id' => $this->row->ar_rev_id, 00462 'ar_deleted' => $this->getBits() 00463 ), 00464 __METHOD__ ); 00465 return (bool)$dbw->affectedRows(); 00466 } 00467 } 00468 00472 class RevDel_FileList extends RevDel_List { 00473 public function getType() { 00474 return 'oldimage'; 00475 } 00476 00477 public static function getRelationType() { 00478 return 'oi_archive_name'; 00479 } 00480 00481 public static function getRestriction() { 00482 return 'deleterevision'; 00483 } 00484 00485 public static function getRevdelConstant() { 00486 return File::DELETED_FILE; 00487 } 00488 00489 var $storeBatch, $deleteBatch, $cleanupBatch; 00490 00495 public function doQuery( $db ) { 00496 $archiveNames = array(); 00497 foreach ( $this->ids as $timestamp ) { 00498 $archiveNames[] = $timestamp . '!' . $this->title->getDBkey(); 00499 } 00500 return $db->select( 00501 'oldimage', 00502 OldLocalFile::selectFields(), 00503 array( 00504 'oi_name' => $this->title->getDBkey(), 00505 'oi_archive_name' => $archiveNames 00506 ), 00507 __METHOD__, 00508 array( 'ORDER BY' => 'oi_timestamp DESC' ) 00509 ); 00510 } 00511 00512 public function newItem( $row ) { 00513 return new RevDel_FileItem( $this, $row ); 00514 } 00515 00516 public function clearFileOps() { 00517 $this->deleteBatch = array(); 00518 $this->storeBatch = array(); 00519 $this->cleanupBatch = array(); 00520 } 00521 00522 public function doPreCommitUpdates() { 00523 $status = Status::newGood(); 00524 $repo = RepoGroup::singleton()->getLocalRepo(); 00525 if ( $this->storeBatch ) { 00526 $status->merge( $repo->storeBatch( $this->storeBatch, FileRepo::OVERWRITE_SAME ) ); 00527 } 00528 if ( !$status->isOK() ) { 00529 return $status; 00530 } 00531 if ( $this->deleteBatch ) { 00532 $status->merge( $repo->deleteBatch( $this->deleteBatch ) ); 00533 } 00534 if ( !$status->isOK() ) { 00535 // Running cleanupDeletedBatch() after a failed storeBatch() with the DB already 00536 // modified (but destined for rollback) causes data loss 00537 return $status; 00538 } 00539 if ( $this->cleanupBatch ) { 00540 $status->merge( $repo->cleanupDeletedBatch( $this->cleanupBatch ) ); 00541 } 00542 return $status; 00543 } 00544 00545 public function doPostCommitUpdates() { 00546 global $wgUseSquid; 00547 $file = wfLocalFile( $this->title ); 00548 $file->purgeCache(); 00549 $file->purgeDescription(); 00550 $purgeUrls = array(); 00551 foreach ( $this->ids as $timestamp ) { 00552 $archiveName = $timestamp . '!' . $this->title->getDBkey(); 00553 $file->purgeOldThumbnails( $archiveName ); 00554 $purgeUrls[] = $file->getArchiveUrl( $archiveName ); 00555 } 00556 if ( $wgUseSquid ) { 00557 // purge full images from cache 00558 SquidUpdate::purge( $purgeUrls ); 00559 } 00560 return Status::newGood(); 00561 } 00562 00563 public function getSuppressBit() { 00564 return File::DELETED_RESTRICTED; 00565 } 00566 } 00567 00571 class RevDel_FileItem extends RevDel_Item { 00572 00576 var $file; 00577 00578 public function __construct( $list, $row ) { 00579 parent::__construct( $list, $row ); 00580 $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row ); 00581 } 00582 00583 public function getIdField() { 00584 return 'oi_archive_name'; 00585 } 00586 00587 public function getTimestampField() { 00588 return 'oi_timestamp'; 00589 } 00590 00591 public function getAuthorIdField() { 00592 return 'oi_user'; 00593 } 00594 00595 public function getAuthorNameField() { 00596 return 'oi_user_text'; 00597 } 00598 00599 public function getId() { 00600 $parts = explode( '!', $this->row->oi_archive_name ); 00601 return $parts[0]; 00602 } 00603 00604 public function canView() { 00605 return $this->file->userCan( File::DELETED_RESTRICTED, $this->list->getUser() ); 00606 } 00607 00608 public function canViewContent() { 00609 return $this->file->userCan( File::DELETED_FILE, $this->list->getUser() ); 00610 } 00611 00612 public function getBits() { 00613 return $this->file->getVisibility(); 00614 } 00615 00616 public function setBits( $bits ) { 00617 # Queue the file op 00618 # @todo FIXME: Move to LocalFile.php 00619 if ( $this->isDeleted() ) { 00620 if ( $bits & File::DELETED_FILE ) { 00621 # Still deleted 00622 } else { 00623 # Newly undeleted 00624 $key = $this->file->getStorageKey(); 00625 $srcRel = $this->file->repo->getDeletedHashPath( $key ) . $key; 00626 $this->list->storeBatch[] = array( 00627 $this->file->repo->getVirtualUrl( 'deleted' ) . '/' . $srcRel, 00628 'public', 00629 $this->file->getRel() 00630 ); 00631 $this->list->cleanupBatch[] = $key; 00632 } 00633 } elseif ( $bits & File::DELETED_FILE ) { 00634 # Newly deleted 00635 $key = $this->file->getStorageKey(); 00636 $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key; 00637 $this->list->deleteBatch[] = array( $this->file->getRel(), $dstRel ); 00638 } 00639 00640 # Do the database operations 00641 $dbw = wfGetDB( DB_MASTER ); 00642 $dbw->update( 'oldimage', 00643 array( 'oi_deleted' => $bits ), 00644 array( 00645 'oi_name' => $this->row->oi_name, 00646 'oi_timestamp' => $this->row->oi_timestamp, 00647 'oi_deleted' => $this->getBits() 00648 ), 00649 __METHOD__ 00650 ); 00651 return (bool)$dbw->affectedRows(); 00652 } 00653 00654 public function isDeleted() { 00655 return $this->file->isDeleted( File::DELETED_FILE ); 00656 } 00657 00663 protected function getLink() { 00664 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate( 00665 $this->file->getTimestamp(), $this->list->getUser() ) ); 00666 00667 if ( !$this->isDeleted() ) { 00668 # Regular files... 00669 return Html::rawElement( 'a', array( 'href' => $this->file->getUrl() ), $date ); 00670 } 00671 00672 # Hidden files... 00673 if ( !$this->canViewContent() ) { 00674 $link = $date; 00675 } else { 00676 $link = Linker::link( 00677 SpecialPage::getTitleFor( 'Revisiondelete' ), 00678 $date, 00679 array(), 00680 array( 00681 'target' => $this->list->title->getPrefixedText(), 00682 'file' => $this->file->getArchiveName(), 00683 'token' => $this->list->getUser()->getEditToken( 00684 $this->file->getArchiveName() ) 00685 ) 00686 ); 00687 } 00688 return '<span class="history-deleted">' . $link . '</span>'; 00689 } 00690 00695 protected function getUserTools() { 00696 if ( $this->file->userCan( Revision::DELETED_USER, $this->list->getUser() ) ) { 00697 $uid = $this->file->getUser( 'id' ); 00698 $name = $this->file->getUser( 'text' ); 00699 $link = Linker::userLink( $uid, $name ) . Linker::userToolLinks( $uid, $name ); 00700 } else { 00701 $link = $this->list->msg( 'rev-deleted-user' )->escaped(); 00702 } 00703 if ( $this->file->isDeleted( Revision::DELETED_USER ) ) { 00704 return '<span class="history-deleted">' . $link . '</span>'; 00705 } 00706 return $link; 00707 } 00708 00715 protected function getComment() { 00716 if ( $this->file->userCan( File::DELETED_COMMENT, $this->list->getUser() ) ) { 00717 $block = Linker::commentBlock( $this->file->getDescription() ); 00718 } else { 00719 $block = ' ' . $this->list->msg( 'rev-deleted-comment' )->escaped(); 00720 } 00721 if ( $this->file->isDeleted( File::DELETED_COMMENT ) ) { 00722 return "<span class=\"history-deleted\">$block</span>"; 00723 } 00724 return $block; 00725 } 00726 00727 public function getHTML() { 00728 $data = 00729 $this->list->msg( 'widthheight' )->numParams( 00730 $this->file->getWidth(), $this->file->getHeight() )->text() . 00731 ' (' . $this->list->msg( 'nbytes' )->numParams( $this->file->getSize() )->text() . ')'; 00732 00733 return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' . 00734 $data . ' ' . $this->getComment() . '</li>'; 00735 } 00736 00737 public function getApiData( ApiResult $result ) { 00738 $file = $this->file; 00739 $user = $this->list->getUser(); 00740 $ret = array( 00741 'title' => $this->list->title->getPrefixedText(), 00742 'archivename' => $file->getArchiveName(), 00743 'timestamp' => wfTimestamp( TS_ISO_8601, $file->getTimestamp() ), 00744 'width' => $file->getWidth(), 00745 'height' => $file->getHeight(), 00746 'size' => $file->getSize(), 00747 ); 00748 $ret += $file->isDeleted( Revision::DELETED_USER ) ? array( 'userhidden' => '' ) : array(); 00749 $ret += $file->isDeleted( Revision::DELETED_COMMENT ) ? array( 'commenthidden' => '' ) : array(); 00750 $ret += $this->isDeleted() ? array( 'contenthidden' => '' ) : array(); 00751 if ( !$this->isDeleted() ) { 00752 $ret += array( 00753 'url' => $file->getUrl(), 00754 ); 00755 } elseif ( $this->canViewContent() ) { 00756 $ret += array( 00757 'url' => SpecialPage::getTitleFor( 'Revisiondelete' )->getLinkURL( 00758 array( 00759 'target' => $this->list->title->getPrefixedText(), 00760 'file' => $file->getArchiveName(), 00761 'token' => $user->getEditToken( $file->getArchiveName() ) 00762 ), 00763 false, PROTO_RELATIVE 00764 ), 00765 ); 00766 } 00767 if ( $file->userCan( Revision::DELETED_USER, $user ) ) { 00768 $ret += array( 00769 'userid' => $file->user, 00770 'user' => $file->user_text, 00771 ); 00772 } 00773 if ( $file->userCan( Revision::DELETED_COMMENT, $user ) ) { 00774 $ret += array( 00775 'comment' => $file->description, 00776 ); 00777 } 00778 return $ret; 00779 } 00780 } 00781 00785 class RevDel_ArchivedFileList extends RevDel_FileList { 00786 public function getType() { 00787 return 'filearchive'; 00788 } 00789 00790 public static function getRelationType() { 00791 return 'fa_id'; 00792 } 00793 00798 public function doQuery( $db ) { 00799 $ids = array_map( 'intval', $this->ids ); 00800 return $db->select( 00801 'filearchive', 00802 ArchivedFile::selectFields(), 00803 array( 00804 'fa_name' => $this->title->getDBkey(), 00805 'fa_id' => $ids 00806 ), 00807 __METHOD__, 00808 array( 'ORDER BY' => 'fa_id DESC' ) 00809 ); 00810 } 00811 00812 public function newItem( $row ) { 00813 return new RevDel_ArchivedFileItem( $this, $row ); 00814 } 00815 } 00816 00820 class RevDel_ArchivedFileItem extends RevDel_FileItem { 00821 public function __construct( $list, $row ) { 00822 RevDel_Item::__construct( $list, $row ); 00823 $this->file = ArchivedFile::newFromRow( $row ); 00824 } 00825 00826 public function getIdField() { 00827 return 'fa_id'; 00828 } 00829 00830 public function getTimestampField() { 00831 return 'fa_timestamp'; 00832 } 00833 00834 public function getAuthorIdField() { 00835 return 'fa_user'; 00836 } 00837 00838 public function getAuthorNameField() { 00839 return 'fa_user_text'; 00840 } 00841 00842 public function getId() { 00843 return $this->row->fa_id; 00844 } 00845 00846 public function setBits( $bits ) { 00847 $dbw = wfGetDB( DB_MASTER ); 00848 $dbw->update( 'filearchive', 00849 array( 'fa_deleted' => $bits ), 00850 array( 00851 'fa_id' => $this->row->fa_id, 00852 'fa_deleted' => $this->getBits(), 00853 ), 00854 __METHOD__ 00855 ); 00856 return (bool)$dbw->affectedRows(); 00857 } 00858 00859 protected function getLink() { 00860 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate( 00861 $this->file->getTimestamp(), $this->list->getUser() ) ); 00862 00863 # Hidden files... 00864 if ( !$this->canViewContent() ) { 00865 $link = $date; 00866 } else { 00867 $undelete = SpecialPage::getTitleFor( 'Undelete' ); 00868 $key = $this->file->getKey(); 00869 $link = Linker::link( $undelete, $date, array(), 00870 array( 00871 'target' => $this->list->title->getPrefixedText(), 00872 'file' => $key, 00873 'token' => $this->list->getUser()->getEditToken( $key ) 00874 ) 00875 ); 00876 } 00877 if ( $this->isDeleted() ) { 00878 $link = '<span class="history-deleted">' . $link . '</span>'; 00879 } 00880 return $link; 00881 } 00882 } 00883 00887 class RevDel_LogList extends RevDel_List { 00888 public function getType() { 00889 return 'logging'; 00890 } 00891 00892 public static function getRelationType() { 00893 return 'log_id'; 00894 } 00895 00896 public static function getRestriction() { 00897 return 'deletelogentry'; 00898 } 00899 00900 public static function getRevdelConstant() { 00901 return LogPage::DELETED_ACTION; 00902 } 00903 00904 public static function suggestTarget( $target, array $ids ) { 00905 $result = wfGetDB( DB_SLAVE )->select( 'logging', 00906 'log_type', 00907 array( 'log_id' => $ids ), 00908 __METHOD__, 00909 array( 'DISTINCT' ) 00910 ); 00911 if ( $result->numRows() == 1 ) { 00912 // If there's only one type, the target can be set to include it. 00913 return SpecialPage::getTitleFor( 'Log', $result->current()->log_type ); 00914 } 00915 return SpecialPage::getTitleFor( 'Log' ); 00916 } 00917 00922 public function doQuery( $db ) { 00923 $ids = array_map( 'intval', $this->ids ); 00924 return $db->select( 'logging', '*', 00925 array( 'log_id' => $ids ), 00926 __METHOD__, 00927 array( 'ORDER BY' => 'log_id DESC' ) 00928 ); 00929 } 00930 00931 public function newItem( $row ) { 00932 return new RevDel_LogItem( $this, $row ); 00933 } 00934 00935 public function getSuppressBit() { 00936 return Revision::DELETED_RESTRICTED; 00937 } 00938 00939 public function getLogAction() { 00940 return 'event'; 00941 } 00942 00943 public function getLogParams( $params ) { 00944 return array( 00945 implode( ',', $params['ids'] ), 00946 "ofield={$params['oldBits']}", 00947 "nfield={$params['newBits']}" 00948 ); 00949 } 00950 } 00951 00955 class RevDel_LogItem extends RevDel_Item { 00956 public function getIdField() { 00957 return 'log_id'; 00958 } 00959 00960 public function getTimestampField() { 00961 return 'log_timestamp'; 00962 } 00963 00964 public function getAuthorIdField() { 00965 return 'log_user'; 00966 } 00967 00968 public function getAuthorNameField() { 00969 return 'log_user_text'; 00970 } 00971 00972 public function canView() { 00973 return LogEventsList::userCan( $this->row, Revision::DELETED_RESTRICTED, $this->list->getUser() ); 00974 } 00975 00976 public function canViewContent() { 00977 return true; // none 00978 } 00979 00980 public function getBits() { 00981 return $this->row->log_deleted; 00982 } 00983 00984 public function setBits( $bits ) { 00985 $dbw = wfGetDB( DB_MASTER ); 00986 $dbw->update( 'recentchanges', 00987 array( 00988 'rc_deleted' => $bits, 00989 'rc_patrolled' => 1 00990 ), 00991 array( 00992 'rc_logid' => $this->row->log_id, 00993 'rc_timestamp' => $this->row->log_timestamp // index 00994 ), 00995 __METHOD__ 00996 ); 00997 $dbw->update( 'logging', 00998 array( 'log_deleted' => $bits ), 00999 array( 01000 'log_id' => $this->row->log_id, 01001 'log_deleted' => $this->getBits() 01002 ), 01003 __METHOD__ 01004 ); 01005 return (bool)$dbw->affectedRows(); 01006 } 01007 01008 public function getHTML() { 01009 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate( 01010 $this->row->log_timestamp, $this->list->getUser() ) ); 01011 $title = Title::makeTitle( $this->row->log_namespace, $this->row->log_title ); 01012 $formatter = LogFormatter::newFromRow( $this->row ); 01013 $formatter->setContext( $this->list->getContext() ); 01014 $formatter->setAudience( LogFormatter::FOR_THIS_USER ); 01015 01016 // Log link for this page 01017 $loglink = Linker::link( 01018 SpecialPage::getTitleFor( 'Log' ), 01019 $this->list->msg( 'log' )->escaped(), 01020 array(), 01021 array( 'page' => $title->getPrefixedText() ) 01022 ); 01023 $loglink = $this->list->msg( 'parentheses' )->rawParams( $loglink )->escaped(); 01024 // User links and action text 01025 $action = $formatter->getActionText(); 01026 // Comment 01027 $comment = $this->list->getLanguage()->getDirMark() . Linker::commentBlock( $this->row->log_comment ); 01028 if ( LogEventsList::isDeleted( $this->row, LogPage::DELETED_COMMENT ) ) { 01029 $comment = '<span class="history-deleted">' . $comment . '</span>'; 01030 } 01031 01032 return "<li>$loglink $date $action $comment</li>"; 01033 } 01034 01035 public function getApiData( ApiResult $result ) { 01036 $logEntry = DatabaseLogEntry::newFromRow( $this->row ); 01037 $user = $this->list->getUser(); 01038 $ret = array( 01039 'id' => $logEntry->getId(), 01040 'type' => $logEntry->getType(), 01041 'action' => $logEntry->getSubtype(), 01042 ); 01043 $ret += $logEntry->isDeleted( LogPage::DELETED_USER ) ? array( 'userhidden' => '' ) : array(); 01044 $ret += $logEntry->isDeleted( LogPage::DELETED_COMMENT ) ? array( 'commenthidden' => '' ) : array(); 01045 $ret += $logEntry->isDeleted( LogPage::DELETED_ACTION ) ? array( 'actionhidden' => '' ) : array(); 01046 01047 if ( LogEventsList::userCan( $this->row, LogPage::DELETED_ACTION, $user ) ) { 01048 ApiQueryLogEvents::addLogParams( 01049 $result, 01050 $ret, 01051 $logEntry->getParameters(), 01052 $logEntry->getType(), 01053 $logEntry->getSubtype(), 01054 $logEntry->getTimestamp(), 01055 $logEntry->isLegacy() 01056 ); 01057 } 01058 if ( LogEventsList::userCan( $this->row, LogPage::DELETED_USER, $user ) ) { 01059 $ret += array( 01060 'userid' => $this->row->log_user, 01061 'user' => $this->row->log_user_text, 01062 ); 01063 } 01064 if ( LogEventsList::userCan( $this->row, LogPage::DELETED_COMMENT, $user ) ) { 01065 $ret += array( 01066 'comment' => $this->row->log_comment, 01067 ); 01068 } 01069 return $ret; 01070 } 01071 }