MediaWiki  master
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(
00458                         'oldimage',
00459                         OldLocalFile::selectFields(),
00460                         array(
00461                                 'oi_name'         => $this->title->getDBkey(),
00462                                 'oi_archive_name' => $archiveNames
00463                         ),
00464                         __METHOD__,
00465                         array( 'ORDER BY' => 'oi_timestamp DESC' )
00466                 );
00467         }
00468 
00469         public function newItem( $row ) {
00470                 return new RevDel_FileItem( $this, $row );
00471         }
00472 
00473         public function clearFileOps() {
00474                 $this->deleteBatch = array();
00475                 $this->storeBatch = array();
00476                 $this->cleanupBatch = array();
00477         }
00478 
00479         public function doPreCommitUpdates() {
00480                 $status = Status::newGood();
00481                 $repo = RepoGroup::singleton()->getLocalRepo();
00482                 if ( $this->storeBatch ) {
00483                         $status->merge( $repo->storeBatch( $this->storeBatch, FileRepo::OVERWRITE_SAME ) );
00484                 }
00485                 if ( !$status->isOK() ) {
00486                         return $status;
00487                 }
00488                 if ( $this->deleteBatch ) {
00489                         $status->merge( $repo->deleteBatch( $this->deleteBatch ) );
00490                 }
00491                 if ( !$status->isOK() ) {
00492                         // Running cleanupDeletedBatch() after a failed storeBatch() with the DB already
00493                         // modified (but destined for rollback) causes data loss
00494                         return $status;
00495                 }
00496                 if ( $this->cleanupBatch ) {
00497                         $status->merge( $repo->cleanupDeletedBatch( $this->cleanupBatch ) );
00498                 }
00499                 return $status;
00500         }
00501 
00502         public function doPostCommitUpdates() {
00503                 $file = wfLocalFile( $this->title );
00504                 $file->purgeCache();
00505                 $file->purgeDescription();
00506                 return Status::newGood();
00507         }
00508 
00509         public function getSuppressBit() {
00510                 return File::DELETED_RESTRICTED;
00511         }
00512 }
00513 
00517 class RevDel_FileItem extends RevDel_Item {
00518 
00522         var $file;
00523 
00524         public function __construct( $list, $row ) {
00525                 parent::__construct( $list, $row );
00526                 $this->file = RepoGroup::singleton()->getLocalRepo()->newFileFromRow( $row );
00527         }
00528 
00529         public function getIdField() {
00530                 return 'oi_archive_name';
00531         }
00532 
00533         public function getTimestampField() {
00534                 return 'oi_timestamp';
00535         }
00536 
00537         public function getAuthorIdField() {
00538                 return 'oi_user';
00539         }
00540 
00541         public function getAuthorNameField() {
00542                 return 'oi_user_text';
00543         }
00544 
00545         public function getId() {
00546                 $parts = explode( '!', $this->row->oi_archive_name );
00547                 return $parts[0];
00548         }
00549 
00550         public function canView() {
00551                 return $this->file->userCan( File::DELETED_RESTRICTED, $this->list->getUser() );
00552         }
00553 
00554         public function canViewContent() {
00555                 return $this->file->userCan( File::DELETED_FILE, $this->list->getUser() );
00556         }
00557 
00558         public function getBits() {
00559                 return $this->file->getVisibility();
00560         }
00561 
00562         public function setBits( $bits ) {
00563                 # Queue the file op
00564                 # @todo FIXME: Move to LocalFile.php
00565                 if ( $this->isDeleted() ) {
00566                         if ( $bits & File::DELETED_FILE ) {
00567                                 # Still deleted
00568                         } else {
00569                                 # Newly undeleted
00570                                 $key = $this->file->getStorageKey();
00571                                 $srcRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
00572                                 $this->list->storeBatch[] = array(
00573                                         $this->file->repo->getVirtualUrl( 'deleted' ) . '/' . $srcRel,
00574                                         'public',
00575                                         $this->file->getRel()
00576                                 );
00577                                 $this->list->cleanupBatch[] = $key;
00578                         }
00579                 } elseif ( $bits & File::DELETED_FILE ) {
00580                         # Newly deleted
00581                         $key = $this->file->getStorageKey();
00582                         $dstRel = $this->file->repo->getDeletedHashPath( $key ) . $key;
00583                         $this->list->deleteBatch[] = array( $this->file->getRel(), $dstRel );
00584                 }
00585 
00586                 # Do the database operations
00587                 $dbw = wfGetDB( DB_MASTER );
00588                 $dbw->update( 'oldimage',
00589                         array( 'oi_deleted' => $bits ),
00590                         array(
00591                                 'oi_name' => $this->row->oi_name,
00592                                 'oi_timestamp' => $this->row->oi_timestamp,
00593                                 'oi_deleted' => $this->getBits()
00594                         ),
00595                         __METHOD__
00596                 );
00597                 return (bool)$dbw->affectedRows();
00598         }
00599 
00600         public function isDeleted() {
00601                 return $this->file->isDeleted( File::DELETED_FILE );
00602         }
00603 
00609         protected function getLink() {
00610                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00611                         $this->file->getTimestamp(), $this->list->getUser() ) );
00612 
00613                 if ( !$this->isDeleted() ) {
00614                         # Regular files...
00615                         return Html::rawElement( 'a', array( 'href' => $this->file->getUrl() ), $date );
00616                 }
00617 
00618                 # Hidden files...
00619                 if ( !$this->canViewContent() ) {
00620                         $link = $date;
00621                 } else {
00622                         $link = Linker::link(
00623                                 SpecialPage::getTitleFor( 'Revisiondelete' ),
00624                                 $date,
00625                                 array(),
00626                                 array(
00627                                         'target' => $this->list->title->getPrefixedText(),
00628                                         'file'   => $this->file->getArchiveName(),
00629                                         'token'  => $this->list->getUser()->getEditToken(
00630                                                 $this->file->getArchiveName() )
00631                                 )
00632                         );
00633                 }
00634                 return '<span class="history-deleted">' . $link . '</span>';
00635         }
00640         protected function getUserTools() {
00641                 if( $this->file->userCan( Revision::DELETED_USER, $this->list->getUser() ) ) {
00642                         $link = Linker::userLink( $this->file->user, $this->file->user_text ) .
00643                                 Linker::userToolLinks( $this->file->user, $this->file->user_text );
00644                 } else {
00645                         $link = $this->list->msg( 'rev-deleted-user' )->escaped();
00646                 }
00647                 if( $this->file->isDeleted( Revision::DELETED_USER ) ) {
00648                         return '<span class="history-deleted">' . $link . '</span>';
00649                 }
00650                 return $link;
00651         }
00652 
00659         protected function getComment() {
00660                 if( $this->file->userCan( File::DELETED_COMMENT, $this->list->getUser() ) ) {
00661                         $block = Linker::commentBlock( $this->file->description );
00662                 } else {
00663                         $block = ' ' . $this->list->msg( 'rev-deleted-comment' )->escaped();
00664                 }
00665                 if( $this->file->isDeleted( File::DELETED_COMMENT ) ) {
00666                         return "<span class=\"history-deleted\">$block</span>";
00667                 }
00668                 return $block;
00669         }
00670 
00671         public function getHTML() {
00672                 $data =
00673                         $this->list->msg( 'widthheight' )->numParams(
00674                                 $this->file->getWidth(), $this->file->getHeight() )->text() .
00675                         ' (' . $this->list->msg( 'nbytes' )->numParams( $this->file->getSize() )->text() . ')';
00676 
00677                 return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' .
00678                         $data . ' ' . $this->getComment(). '</li>';
00679         }
00680 }
00681 
00685 class RevDel_ArchivedFileList extends RevDel_FileList {
00686         public function getType() {
00687                 return 'filearchive';
00688         }
00689 
00690         public static function getRelationType() {
00691                 return 'fa_id';
00692         }
00693 
00698         public function doQuery( $db ) {
00699                 $ids = array_map( 'intval', $this->ids );
00700                 return $db->select(
00701                         'filearchive',
00702                         ArchivedFile::selectFields(),
00703                         array(
00704                                 'fa_name' => $this->title->getDBkey(),
00705                                 'fa_id'   => $ids
00706                         ),
00707                         __METHOD__,
00708                         array( 'ORDER BY' => 'fa_id DESC' )
00709                 );
00710         }
00711 
00712         public function newItem( $row ) {
00713                 return new RevDel_ArchivedFileItem( $this, $row );
00714         }
00715 }
00716 
00720 class RevDel_ArchivedFileItem extends RevDel_FileItem {
00721         public function __construct( $list, $row ) {
00722                 RevDel_Item::__construct( $list, $row );
00723                 $this->file = ArchivedFile::newFromRow( $row );
00724         }
00725 
00726         public function getIdField() {
00727                 return 'fa_id';
00728         }
00729 
00730         public function getTimestampField() {
00731                 return 'fa_timestamp';
00732         }
00733 
00734         public function getAuthorIdField() {
00735                 return 'fa_user';
00736         }
00737 
00738         public function getAuthorNameField() {
00739                 return 'fa_user_text';
00740         }
00741 
00742         public function getId() {
00743                 return $this->row->fa_id;
00744         }
00745 
00746         public function setBits( $bits ) {
00747                 $dbw = wfGetDB( DB_MASTER );
00748                 $dbw->update( 'filearchive',
00749                         array( 'fa_deleted' => $bits ),
00750                         array(
00751                                 'fa_id' => $this->row->fa_id,
00752                                 'fa_deleted' => $this->getBits(),
00753                         ),
00754                         __METHOD__
00755                 );
00756                 return (bool)$dbw->affectedRows();
00757         }
00758 
00759         protected function getLink() {
00760                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00761                         $this->file->getTimestamp(), $this->list->getUser() ) );
00762 
00763                 # Hidden files...
00764                 if( !$this->canViewContent() ) {
00765                         $link = $date;
00766                 } else {
00767                         $undelete = SpecialPage::getTitleFor( 'Undelete' );
00768                         $key = $this->file->getKey();
00769                         $link = Linker::link( $undelete, $date, array(),
00770                                 array(
00771                                         'target' => $this->list->title->getPrefixedText(),
00772                                         'file' => $key,
00773                                         'token' => $this->list->getUser()->getEditToken( $key )
00774                                 )
00775                         );
00776                 }
00777                 if( $this->isDeleted() ) {
00778                         $link = '<span class="history-deleted">' . $link . '</span>';
00779                 }
00780                 return $link;
00781         }
00782 }
00783 
00787 class RevDel_LogList extends RevDel_List {
00788         public function getType() {
00789                 return 'logging';
00790         }
00791 
00792         public static function getRelationType() {
00793                 return 'log_id';
00794         }
00795 
00800         public function doQuery( $db ) {
00801                 $ids = array_map( 'intval', $this->ids );
00802                 return $db->select( 'logging', '*',
00803                         array( 'log_id' => $ids ),
00804                         __METHOD__,
00805                         array( 'ORDER BY' => 'log_id DESC' )
00806                 );
00807         }
00808 
00809         public function newItem( $row ) {
00810                 return new RevDel_LogItem( $this, $row );
00811         }
00812 
00813         public function getSuppressBit() {
00814                 return Revision::DELETED_RESTRICTED;
00815         }
00816 
00817         public function getLogAction() {
00818                 return 'event';
00819         }
00820 
00821         public function getLogParams( $params ) {
00822                 return array(
00823                         implode( ',', $params['ids'] ),
00824                         "ofield={$params['oldBits']}",
00825                         "nfield={$params['newBits']}"
00826                 );
00827         }
00828 }
00829 
00833 class RevDel_LogItem extends RevDel_Item {
00834         public function getIdField() {
00835                 return 'log_id';
00836         }
00837 
00838         public function getTimestampField() {
00839                 return 'log_timestamp';
00840         }
00841 
00842         public function getAuthorIdField() {
00843                 return 'log_user';
00844         }
00845 
00846         public function getAuthorNameField() {
00847                 return 'log_user_text';
00848         }
00849 
00850         public function canView() {
00851                 return LogEventsList::userCan( $this->row, Revision::DELETED_RESTRICTED, $this->list->getUser() );
00852         }
00853 
00854         public function canViewContent() {
00855                 return true; // none
00856         }
00857 
00858         public function getBits() {
00859                 return $this->row->log_deleted;
00860         }
00861 
00862         public function setBits( $bits ) {
00863                 $dbw = wfGetDB( DB_MASTER );
00864                 $dbw->update( 'recentchanges',
00865                         array(
00866                                 'rc_deleted' => $bits,
00867                                 'rc_patrolled' => 1
00868                         ),
00869                         array(
00870                                 'rc_logid' => $this->row->log_id,
00871                                 'rc_timestamp' => $this->row->log_timestamp // index
00872                         ),
00873                         __METHOD__
00874                 );
00875                 $dbw->update( 'logging',
00876                         array( 'log_deleted' => $bits ),
00877                         array(
00878                                 'log_id' => $this->row->log_id,
00879                                 'log_deleted' => $this->getBits()
00880                         ),
00881                         __METHOD__
00882                 );
00883                 return (bool)$dbw->affectedRows();
00884         }
00885 
00886         public function getHTML() {
00887                 $date = htmlspecialchars( $this->list->getLanguage()->userTimeAndDate(
00888                         $this->row->log_timestamp, $this->list->getUser() ) );
00889                 $title = Title::makeTitle( $this->row->log_namespace, $this->row->log_title );
00890                 $formatter = LogFormatter::newFromRow( $this->row );
00891                 $formatter->setContext( $this->list->getContext() );
00892                 $formatter->setAudience( LogFormatter::FOR_THIS_USER );
00893 
00894                 // Log link for this page
00895                 $loglink = Linker::link(
00896                         SpecialPage::getTitleFor( 'Log' ),
00897                         $this->list->msg( 'log' )->escaped(),
00898                         array(),
00899                         array( 'page' => $title->getPrefixedText() )
00900                 );
00901                 $loglink = $this->list->msg( 'parentheses' )->rawParams( $loglink )->escaped();
00902                 // User links and action text
00903                 $action = $formatter->getActionText();
00904                 // Comment
00905                 $comment = $this->list->getLanguage()->getDirMark() . Linker::commentBlock( $this->row->log_comment );
00906                 if( LogEventsList::isDeleted( $this->row, LogPage::DELETED_COMMENT ) ) {
00907                         $comment = '<span class="history-deleted">' . $comment . '</span>';
00908                 }
00909 
00910                 return "<li>$loglink $date $action $comment</li>";
00911         }
00912 }