MediaWiki  REL1_20
RevisionDelete.php
Go to the documentation of this file.
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 
00048         public function doQuery( $db ) {
00049                 $ids = array_map( 'intval', $this->ids );
00050                 $live = $db->select(
00051                         array( 'revision', 'page', 'user' ),
00052                         array_merge( Revision::selectFields(), Revision::selectUserFields() ),
00053                         array(
00054                                 'rev_page' => $this->title->getArticleID(),
00055                                 'rev_id'   => $ids,
00056                         ),
00057                         __METHOD__,
00058                         array( 'ORDER BY' => 'rev_id DESC' ),
00059                         array(
00060                                 'page' => Revision::pageJoinCond(),
00061                                 'user' => Revision::userJoinCond() )
00062                 );
00063 
00064                 if ( $live->numRows() >= count( $ids ) ) {
00065                         // All requested revisions are live, keeps things simple!
00066                         return $live;
00067                 }
00068 
00069                 // Check if any requested revisions are available fully deleted.
00070                 $archived = $db->select( array( 'archive' ), '*',
00071                         array(
00072                                 'ar_rev_id' => $ids
00073                         ),
00074                         __METHOD__,
00075                         array( 'ORDER BY' => 'ar_rev_id DESC' )
00076                 );
00077 
00078                 if ( $archived->numRows() == 0 ) {
00079                         return $live;
00080                 } elseif ( $live->numRows() == 0 ) {
00081                         return $archived;
00082                 } else {
00083                         // Combine the two! Whee
00084                         $rows = array();
00085                         foreach ( $live as $row ) {
00086                                 $rows[$row->rev_id] = $row;
00087                         }
00088                         foreach ( $archived as $row ) {
00089                                 $rows[$row->ar_rev_id] = $row;
00090                         }
00091                         krsort( $rows );
00092                         return new FakeResultWrapper( array_values( $rows ) );
00093                 }
00094         }
00095 
00096         public function newItem( $row ) {
00097                 if ( isset( $row->rev_id ) ) {
00098                         return new RevDel_RevisionItem( $this, $row );
00099                 } elseif ( isset( $row->ar_rev_id ) ) {
00100                         return new RevDel_ArchivedRevisionItem( $this, $row );
00101                 } else {
00102                         // This shouldn't happen. :)
00103                         throw new MWException( 'Invalid row type in RevDel_RevisionList' );
00104                 }
00105         }
00106 
00107         public function getCurrent() {
00108                 if ( is_null( $this->currentRevId ) ) {
00109                         $dbw = wfGetDB( DB_MASTER );
00110                         $this->currentRevId = $dbw->selectField(
00111                                 'page', 'page_latest', $this->title->pageCond(), __METHOD__ );
00112                 }
00113                 return $this->currentRevId;
00114         }
00115 
00116         public function getSuppressBit() {
00117                 return Revision::DELETED_RESTRICTED;
00118         }
00119 
00120         public function doPreCommitUpdates() {
00121                 $this->title->invalidateCache();
00122                 return Status::newGood();
00123         }
00124 
00125         public function doPostCommitUpdates() {
00126                 $this->title->purgeSquid();
00127                 // Extensions that require referencing previous revisions may need this
00128                 wfRunHooks( 'ArticleRevisionVisibilitySet', array( &$this->title ) );
00129                 return Status::newGood();
00130         }
00131 }
00132 
00136 class RevDel_RevisionItem extends RevDel_Item {
00137         var $revision;
00138 
00139         public function __construct( $list, $row ) {
00140                 parent::__construct( $list, $row );
00141                 $this->revision = new Revision( $row );
00142         }
00143 
00144         public function getIdField() {
00145                 return 'rev_id';
00146         }
00147 
00148         public function getTimestampField() {
00149                 return 'rev_timestamp';
00150         }
00151 
00152         public function getAuthorIdField() {
00153                 return 'rev_user';
00154         }
00155 
00156         public function getAuthorNameField() {
00157                 return 'user_name'; // see Revision::selectUserFields()
00158         }
00159 
00160         public function canView() {
00161                 return $this->revision->userCan( Revision::DELETED_RESTRICTED, $this->list->getUser() );
00162         }
00163 
00164         public function canViewContent() {
00165                 return $this->revision->userCan( Revision::DELETED_TEXT, $this->list->getUser() );
00166         }
00167 
00168         public function getBits() {
00169                 return $this->revision->getVisibility();
00170         }
00171 
00172         public function setBits( $bits ) {
00173                 $dbw = wfGetDB( DB_MASTER );
00174                 // Update revision table
00175                 $dbw->update( 'revision',
00176                         array( 'rev_deleted' => $bits ),
00177                         array(
00178                                 'rev_id' => $this->revision->getId(),
00179                                 'rev_page' => $this->revision->getPage(),
00180                                 'rev_deleted' => $this->getBits()
00181                         ),
00182                         __METHOD__
00183                 );
00184                 if ( !$dbw->affectedRows() ) {
00185                         // Concurrent fail!
00186                         return false;
00187                 }
00188                 // Update recentchanges table
00189                 $dbw->update( 'recentchanges',
00190                         array(
00191                                 'rc_deleted' => $bits,
00192                                 'rc_patrolled' => 1
00193                         ),
00194                         array(
00195                                 'rc_this_oldid' => $this->revision->getId(), // condition
00196                                 // non-unique timestamp index
00197                                 'rc_timestamp' => $dbw->timestamp( $this->revision->getTimestamp() ),
00198                         ),
00199                         __METHOD__
00200                 );
00201                 return true;
00202         }
00203 
00204         public function isDeleted() {
00205                 return $this->revision->isDeleted( Revision::DELETED_TEXT );
00206         }
00207 
00208         public function isHideCurrentOp( $newBits ) {
00209                 return ( $newBits & Revision::DELETED_TEXT )
00210                         && $this->list->getCurrent() == $this->getId();
00211         }
00212 
00218         protected function getRevisionLink() {
00219                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00220                         $this->revision->getTimestamp(), $this->list->getUser() ) );
00221 
00222                 if ( $this->isDeleted() && !$this->canViewContent() ) {
00223                         return $date;
00224                 }
00225                 return Linker::linkKnown(
00226                         $this->list->title,
00227                         $date,
00228                         array(),
00229                         array(
00230                                 'oldid' => $this->revision->getId(),
00231                                 'unhide' => 1
00232                         )
00233                 );
00234         }
00235 
00241         protected function getDiffLink() {
00242                 if ( $this->isDeleted() && !$this->canViewContent() ) {
00243                         return $this->list->msg( 'diff' )->escaped();
00244                 } else {
00245                         return
00246                                 Linker::linkKnown(
00247                                         $this->list->title,
00248                                         $this->list->msg( 'diff' )->escaped(),
00249                                         array(),
00250                                         array(
00251                                                 'diff' => $this->revision->getId(),
00252                                                 'oldid' => 'prev',
00253                                                 'unhide' => 1
00254                                         )
00255                                 );
00256                 }
00257         }
00258 
00259         public function getHTML() {
00260                 $difflink = $this->list->msg( 'parentheses' )
00261                         ->rawParams( $this->getDiffLink() )->escaped();
00262                 $revlink = $this->getRevisionLink();
00263                 $userlink = Linker::revUserLink( $this->revision );
00264                 $comment = Linker::revComment( $this->revision );
00265                 if ( $this->isDeleted() ) {
00266                         $revlink = "<span class=\"history-deleted\">$revlink</span>";
00267                 }
00268                 return "<li>$difflink $revlink $userlink $comment</li>";
00269         }
00270 }
00271 
00275 class RevDel_ArchiveList extends RevDel_RevisionList {
00276         public function getType() {
00277                 return 'archive';
00278         }
00279 
00280         public static function getRelationType() {
00281                 return 'ar_timestamp';
00282         }
00283 
00288         public function doQuery( $db ) {
00289                 $timestamps = array();
00290                 foreach ( $this->ids as $id ) {
00291                         $timestamps[] = $db->timestamp( $id );
00292                 }
00293                 return $db->select( 'archive', '*',
00294                                 array(
00295                                         'ar_namespace' => $this->title->getNamespace(),
00296                                         'ar_title'     => $this->title->getDBkey(),
00297                                         'ar_timestamp' => $timestamps
00298                                 ),
00299                                 __METHOD__,
00300                                 array( 'ORDER BY' => 'ar_timestamp DESC' )
00301                         );
00302         }
00303 
00304         public function newItem( $row ) {
00305                 return new RevDel_ArchiveItem( $this, $row );
00306         }
00307 
00308         public function doPreCommitUpdates() {
00309                 return Status::newGood();
00310         }
00311 
00312         public function doPostCommitUpdates() {
00313                 return Status::newGood();
00314         }
00315 }
00316 
00320 class RevDel_ArchiveItem extends RevDel_RevisionItem {
00321         public function __construct( $list, $row ) {
00322                 RevDel_Item::__construct( $list, $row );
00323                 $this->revision = Revision::newFromArchiveRow( $row,
00324                         array( 'page' => $this->list->title->getArticleID() ) );
00325         }
00326 
00327         public function getIdField() {
00328                 return 'ar_timestamp';
00329         }
00330 
00331         public function getTimestampField() {
00332                 return 'ar_timestamp';
00333         }
00334 
00335         public function getAuthorIdField() {
00336                 return 'ar_user';
00337         }
00338 
00339         public function getAuthorNameField() {
00340                 return 'ar_user_text';
00341         }
00342 
00343         public function getId() {
00344                 # Convert DB timestamp to MW timestamp
00345                 return $this->revision->getTimestamp();
00346         }
00347 
00348         public function setBits( $bits ) {
00349                 $dbw = wfGetDB( DB_MASTER );
00350                 $dbw->update( 'archive',
00351                         array( 'ar_deleted' => $bits ),
00352                         array(
00353                                 'ar_namespace'  => $this->list->title->getNamespace(),
00354                                 'ar_title'      => $this->list->title->getDBkey(),
00355                                 // use timestamp for index
00356                                 'ar_timestamp'  => $this->row->ar_timestamp,
00357                                 'ar_rev_id'     => $this->row->ar_rev_id,
00358                                 'ar_deleted'    => $this->getBits()
00359                         ),
00360                         __METHOD__ );
00361                 return (bool)$dbw->affectedRows();
00362         }
00363 
00364         protected function getRevisionLink() {
00365                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00366                         $this->revision->getTimestamp(), $this->list->getUser() ) );
00367 
00368                 if ( $this->isDeleted() && !$this->canViewContent() ) {
00369                         return $date;
00370                 }
00371 
00372                 return Linker::link(
00373                         SpecialPage::getTitleFor( 'Undelete' ),
00374                         $date,
00375                         array(),
00376                         array(
00377                                 'target' => $this->list->title->getPrefixedText(),
00378                                 'timestamp' => $this->revision->getTimestamp()
00379                         )
00380                 );
00381         }
00382 
00383         protected function getDiffLink() {
00384                 if ( $this->isDeleted() && !$this->canViewContent() ) {
00385                         return $this->list->msg( 'diff' )->escaped();
00386                 }
00387 
00388                 return Linker::link(
00389                         SpecialPage::getTitleFor( 'Undelete' ),
00390                         $this->list->msg( 'diff' )->escaped(),
00391                         array(),
00392                         array(
00393                                 'target' => $this->list->title->getPrefixedText(),
00394                                 'diff' => 'prev',
00395                                 'timestamp' => $this->revision->getTimestamp()
00396                         )
00397                 );
00398         }
00399 }
00400 
00401 
00406 class RevDel_ArchivedRevisionItem extends RevDel_ArchiveItem {
00407         public function __construct( $list, $row ) {
00408                 RevDel_Item::__construct( $list, $row );
00409 
00410                 $this->revision = Revision::newFromArchiveRow( $row,
00411                         array( 'page' => $this->list->title->getArticleID() ) );
00412         }
00413 
00414         public function getIdField() {
00415                 return 'ar_rev_id';
00416         }
00417 
00418         public function getId() {
00419                 return $this->revision->getId();
00420         }
00421 
00422         public function setBits( $bits ) {
00423                 $dbw = wfGetDB( DB_MASTER );
00424                 $dbw->update( 'archive',
00425                         array( 'ar_deleted' => $bits ),
00426                         array( 'ar_rev_id' => $this->row->ar_rev_id,
00427                                    'ar_deleted' => $this->getBits()
00428                         ),
00429                         __METHOD__ );
00430                 return (bool)$dbw->affectedRows();
00431         }
00432 }
00433 
00437 class RevDel_FileList extends RevDel_List {
00438         public function getType() {
00439                 return 'oldimage';
00440         }
00441 
00442         public static function getRelationType() {
00443                 return 'oi_archive_name';
00444         }
00445 
00446         var $storeBatch, $deleteBatch, $cleanupBatch;
00447 
00452         public function doQuery( $db ) {
00453                 $archiveNames = array();
00454                 foreach( $this->ids as $timestamp ) {
00455                         $archiveNames[] = $timestamp . '!' . $this->title->getDBkey();
00456                 }
00457                 return $db->select( 'oldimage', '*',
00458                         array(
00459                                 'oi_name'         => $this->title->getDBkey(),
00460                                 'oi_archive_name' => $archiveNames
00461                         ),
00462                         __METHOD__,
00463                         array( 'ORDER BY' => 'oi_timestamp DESC' )
00464                 );
00465         }
00466 
00467         public function newItem( $row ) {
00468                 return new RevDel_FileItem( $this, $row );
00469         }
00470 
00471         public function clearFileOps() {
00472                 $this->deleteBatch = array();
00473                 $this->storeBatch = array();
00474                 $this->cleanupBatch = array();
00475         }
00476 
00477         public function doPreCommitUpdates() {
00478                 $status = Status::newGood();
00479                 $repo = RepoGroup::singleton()->getLocalRepo();
00480                 if ( $this->storeBatch ) {
00481                         $status->merge( $repo->storeBatch( $this->storeBatch, FileRepo::OVERWRITE_SAME ) );
00482                 }
00483                 if ( !$status->isOK() ) {
00484                         return $status;
00485                 }
00486                 if ( $this->deleteBatch ) {
00487                         $status->merge( $repo->deleteBatch( $this->deleteBatch ) );
00488                 }
00489                 if ( !$status->isOK() ) {
00490                         // Running cleanupDeletedBatch() after a failed storeBatch() with the DB already
00491                         // modified (but destined for rollback) causes data loss
00492                         return $status;
00493                 }
00494                 if ( $this->cleanupBatch ) {
00495                         $status->merge( $repo->cleanupDeletedBatch( $this->cleanupBatch ) );
00496                 }
00497                 return $status;
00498         }
00499 
00500         public function doPostCommitUpdates() {
00501                 global $wgUseSquid;
00502                 $file = wfLocalFile( $this->title );
00503                 $file->purgeCache();
00504                 $file->purgeDescription();
00505                 $purgeUrls = array();
00506                 foreach ( $this->ids as $timestamp ) {
00507                         $archiveName = $timestamp . '!' . $this->title->getDBkey();
00508                         $file->purgeOldThumbnails( $archiveName );
00509                         $purgeUrls[] = $file->getArchiveUrl( $archiveName );
00510                 }
00511                 if ( $wgUseSquid ) {
00512                         // purge full images from cache
00513                         SquidUpdate::purge( $purgeUrls );
00514                 }
00515                 return Status::newGood();
00516         }
00517 
00518         public function getSuppressBit() {
00519                 return File::DELETED_RESTRICTED;
00520         }
00521 }
00522 
00526 class RevDel_FileItem extends RevDel_Item {
00527 
00531         var $file;
00532 
00533         public function __construct( $list, $row ) {
00534                 parent::__construct( $list, $row );
00535                 $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
00536         }
00537 
00538         public function getIdField() {
00539                 return 'oi_archive_name';
00540         }
00541 
00542         public function getTimestampField() {
00543                 return 'oi_timestamp';
00544         }
00545 
00546         public function getAuthorIdField() {
00547                 return 'oi_user';
00548         }
00549 
00550         public function getAuthorNameField() {
00551                 return 'oi_user_text';
00552         }
00553 
00554         public function getId() {
00555                 $parts = explode( '!', $this->row->oi_archive_name );
00556                 return $parts[0];
00557         }
00558 
00559         public function canView() {
00560                 return $this->file->userCan( File::DELETED_RESTRICTED, $this->list->getUser() );
00561         }
00562 
00563         public function canViewContent() {
00564                 return $this->file->userCan( File::DELETED_FILE, $this->list->getUser() );
00565         }
00566 
00567         public function getBits() {
00568                 return $this->file->getVisibility();
00569         }
00570 
00571         public function setBits( $bits ) {
00572                 # Queue the file op
00573                 # @todo FIXME: Move to LocalFile.php
00574                 if ( $this->isDeleted() ) {
00575                         if ( $bits & File::DELETED_FILE ) {
00576                                 # Still deleted
00577                         } else {
00578                                 # Newly undeleted
00579                                 $key = $this->file->getStorageKey();
00580                                 $srcRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
00581                                 $this->list->storeBatch[] = array(
00582                                         $this->file->repo->getVirtualUrl( 'deleted' ) . '/' . $srcRel,
00583                                         'public',
00584                                         $this->file->getRel()
00585                                 );
00586                                 $this->list->cleanupBatch[] = $key;
00587                         }
00588                 } elseif ( $bits & File::DELETED_FILE ) {
00589                         # Newly deleted
00590                         $key = $this->file->getStorageKey();
00591                         $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
00592                         $this->list->deleteBatch[] = array( $this->file->getRel(), $dstRel );
00593                 }
00594 
00595                 # Do the database operations
00596                 $dbw = wfGetDB( DB_MASTER );
00597                 $dbw->update( 'oldimage',
00598                         array( 'oi_deleted' => $bits ),
00599                         array(
00600                                 'oi_name' => $this->row->oi_name,
00601                                 'oi_timestamp' => $this->row->oi_timestamp,
00602                                 'oi_deleted' => $this->getBits()
00603                         ),
00604                         __METHOD__
00605                 );
00606                 return (bool)$dbw->affectedRows();
00607         }
00608 
00609         public function isDeleted() {
00610                 return $this->file->isDeleted( File::DELETED_FILE );
00611         }
00612 
00618         protected function getLink() {
00619                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00620                         $this->file->getTimestamp(), $this->list->getUser() ) );
00621 
00622                 if ( !$this->isDeleted() ) {
00623                         # Regular files...
00624                         return Html::rawElement( 'a', array( 'href' => $this->file->getUrl() ), $date );
00625                 }
00626 
00627                 # Hidden files...
00628                 if ( !$this->canViewContent() ) {
00629                         $link = $date;
00630                 } else {
00631                         $link = Linker::link(
00632                                 SpecialPage::getTitleFor( 'Revisiondelete' ),
00633                                 $date,
00634                                 array(),
00635                                 array(
00636                                         'target' => $this->list->title->getPrefixedText(),
00637                                         'file'   => $this->file->getArchiveName(),
00638                                         'token'  => $this->list->getUser()->getEditToken(
00639                                                 $this->file->getArchiveName() )
00640                                 )
00641                         );
00642                 }
00643                 return '<span class="history-deleted">' . $link . '</span>';
00644         }
00649         protected function getUserTools() {
00650                 if( $this->file->userCan( Revision::DELETED_USER, $this->list->getUser() ) ) {
00651                         $link = Linker::userLink( $this->file->user, $this->file->user_text ) .
00652                                 Linker::userToolLinks( $this->file->user, $this->file->user_text );
00653                 } else {
00654                         $link = $this->list->msg( 'rev-deleted-user' )->escaped();
00655                 }
00656                 if( $this->file->isDeleted( Revision::DELETED_USER ) ) {
00657                         return '<span class="history-deleted">' . $link . '</span>';
00658                 }
00659                 return $link;
00660         }
00661 
00668         protected function getComment() {
00669                 if( $this->file->userCan( File::DELETED_COMMENT, $this->list->getUser() ) ) {
00670                         $block = Linker::commentBlock( $this->file->description );
00671                 } else {
00672                         $block = ' ' . $this->list->msg( 'rev-deleted-comment' )->escaped();
00673                 }
00674                 if( $this->file->isDeleted( File::DELETED_COMMENT ) ) {
00675                         return "<span class=\"history-deleted\">$block</span>";
00676                 }
00677                 return $block;
00678         }
00679 
00680         public function getHTML() {
00681                 $data =
00682                         $this->list->msg( 'widthheight' )->numParams(
00683                                 $this->file->getWidth(), $this->file->getHeight() )->text() .
00684                         ' (' . $this->list->msg( 'nbytes' )->numParams( $this->file->getSize() )->text() . ')';
00685 
00686                 return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' .
00687                         $data . ' ' . $this->getComment(). '</li>';
00688         }
00689 }
00690 
00694 class RevDel_ArchivedFileList extends RevDel_FileList {
00695         public function getType() {
00696                 return 'filearchive';
00697         }
00698 
00699         public static function getRelationType() {
00700                 return 'fa_id';
00701         }
00702 
00707         public function doQuery( $db ) {
00708                 $ids = array_map( 'intval', $this->ids );
00709                 return $db->select( 'filearchive', '*',
00710                         array(
00711                                 'fa_name' => $this->title->getDBkey(),
00712                                 'fa_id'   => $ids
00713                         ),
00714                         __METHOD__,
00715                         array( 'ORDER BY' => 'fa_id DESC' )
00716                 );
00717         }
00718 
00719         public function newItem( $row ) {
00720                 return new RevDel_ArchivedFileItem( $this, $row );
00721         }
00722 }
00723 
00727 class RevDel_ArchivedFileItem extends RevDel_FileItem {
00728         public function __construct( $list, $row ) {
00729                 RevDel_Item::__construct( $list, $row );
00730                 $this->file = ArchivedFile::newFromRow( $row );
00731         }
00732 
00733         public function getIdField() {
00734                 return 'fa_id';
00735         }
00736 
00737         public function getTimestampField() {
00738                 return 'fa_timestamp';
00739         }
00740 
00741         public function getAuthorIdField() {
00742                 return 'fa_user';
00743         }
00744 
00745         public function getAuthorNameField() {
00746                 return 'fa_user_text';
00747         }
00748 
00749         public function getId() {
00750                 return $this->row->fa_id;
00751         }
00752 
00753         public function setBits( $bits ) {
00754                 $dbw = wfGetDB( DB_MASTER );
00755                 $dbw->update( 'filearchive',
00756                         array( 'fa_deleted' => $bits ),
00757                         array(
00758                                 'fa_id' => $this->row->fa_id,
00759                                 'fa_deleted' => $this->getBits(),
00760                         ),
00761                         __METHOD__
00762                 );
00763                 return (bool)$dbw->affectedRows();
00764         }
00765 
00766         protected function getLink() {
00767                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00768                         $this->file->getTimestamp(), $this->list->getUser() ) );
00769 
00770                 # Hidden files...
00771                 if( !$this->canViewContent() ) {
00772                         $link = $date;
00773                 } else {
00774                         $undelete = SpecialPage::getTitleFor( 'Undelete' );
00775                         $key = $this->file->getKey();
00776                         $link = Linker::link( $undelete, $date, array(),
00777                                 array(
00778                                         'target' => $this->list->title->getPrefixedText(),
00779                                         'file' => $key,
00780                                         'token' => $this->list->getUser()->getEditToken( $key )
00781                                 )
00782                         );
00783                 }
00784                 if( $this->isDeleted() ) {
00785                         $link = '<span class="history-deleted">' . $link . '</span>';
00786                 }
00787                 return $link;
00788         }
00789 }
00790 
00794 class RevDel_LogList extends RevDel_List {
00795         public function getType() {
00796                 return 'logging';
00797         }
00798 
00799         public static function getRelationType() {
00800                 return 'log_id';
00801         }
00802 
00807         public function doQuery( $db ) {
00808                 $ids = array_map( 'intval', $this->ids );
00809                 return $db->select( 'logging', '*',
00810                         array( 'log_id' => $ids ),
00811                         __METHOD__,
00812                         array( 'ORDER BY' => 'log_id DESC' )
00813                 );
00814         }
00815 
00816         public function newItem( $row ) {
00817                 return new RevDel_LogItem( $this, $row );
00818         }
00819 
00820         public function getSuppressBit() {
00821                 return Revision::DELETED_RESTRICTED;
00822         }
00823 
00824         public function getLogAction() {
00825                 return 'event';
00826         }
00827 
00828         public function getLogParams( $params ) {
00829                 return array(
00830                         implode( ',', $params['ids'] ),
00831                         "ofield={$params['oldBits']}",
00832                         "nfield={$params['newBits']}"
00833                 );
00834         }
00835 }
00836 
00840 class RevDel_LogItem extends RevDel_Item {
00841         public function getIdField() {
00842                 return 'log_id';
00843         }
00844 
00845         public function getTimestampField() {
00846                 return 'log_timestamp';
00847         }
00848 
00849         public function getAuthorIdField() {
00850                 return 'log_user';
00851         }
00852 
00853         public function getAuthorNameField() {
00854                 return 'log_user_text';
00855         }
00856 
00857         public function canView() {
00858                 return LogEventsList::userCan( $this->row, Revision::DELETED_RESTRICTED, $this->list->getUser() );
00859         }
00860 
00861         public function canViewContent() {
00862                 return true; // none
00863         }
00864 
00865         public function getBits() {
00866                 return $this->row->log_deleted;
00867         }
00868 
00869         public function setBits( $bits ) {
00870                 $dbw = wfGetDB( DB_MASTER );
00871                 $dbw->update( 'recentchanges',
00872                         array(
00873                                 'rc_deleted' => $bits,
00874                                 'rc_patrolled' => 1
00875                         ),
00876                         array(
00877                                 'rc_logid' => $this->row->log_id,
00878                                 'rc_timestamp' => $this->row->log_timestamp // index
00879                         ),
00880                         __METHOD__
00881                 );
00882                 $dbw->update( 'logging',
00883                         array( 'log_deleted' => $bits ),
00884                         array(
00885                                 'log_id' => $this->row->log_id,
00886                                 'log_deleted' => $this->getBits()
00887                         ),
00888                         __METHOD__
00889                 );
00890                 return (bool)$dbw->affectedRows();
00891         }
00892 
00893         public function getHTML() {
00894                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00895                         $this->row->log_timestamp, $this->list->getUser() ) );
00896                 $title = Title::makeTitle( $this->row->log_namespace, $this->row->log_title );
00897                 $formatter = LogFormatter::newFromRow( $this->row );
00898                 $formatter->setContext( $this->list->getContext() );
00899                 $formatter->setAudience( LogFormatter::FOR_THIS_USER );
00900 
00901                 // Log link for this page
00902                 $loglink = Linker::link(
00903                         SpecialPage::getTitleFor( 'Log' ),
00904                         $this->list->msg( 'log' )->escaped(),
00905                         array(),
00906                         array( 'page' => $title->getPrefixedText() )
00907                 );
00908                 $loglink = $this->list->msg( 'parentheses' )->rawParams( $loglink )->escaped();
00909                 // User links and action text
00910                 $action = $formatter->getActionText();
00911                 // Comment
00912                 $comment = $this->list->getLanguage()->getDirMark() . Linker::commentBlock( $this->row->log_comment );
00913                 if( LogEventsList::isDeleted($this->row,LogPage::DELETED_COMMENT) ) {
00914                         $comment = '<span class="history-deleted">' . $comment . '</span>';
00915                 }
00916 
00917                 return "<li>$loglink $date $action $comment</li>";
00918         }
00919 }