diff options
Diffstat (limited to 'includes/revisiondelete')
-rw-r--r-- | includes/revisiondelete/RevisionDelete.php | 86 | ||||
-rw-r--r-- | includes/revisiondelete/RevisionDeleteAbstracts.php | 50 | ||||
-rw-r--r-- | includes/revisiondelete/RevisionDeleteUser.php | 2 | ||||
-rw-r--r-- | includes/revisiondelete/RevisionDeleter.php | 149 |
4 files changed, 242 insertions, 45 deletions
diff --git a/includes/revisiondelete/RevisionDelete.php b/includes/revisiondelete/RevisionDelete.php index f4c07968..71850877 100644 --- a/includes/revisiondelete/RevisionDelete.php +++ b/includes/revisiondelete/RevisionDelete.php @@ -41,6 +41,19 @@ class RevDel_RevisionList extends RevDel_List { return 'rev_id'; } + public static function getRestriction() { + return 'deleterevision'; + } + + public static function getRevdelConstant() { + return Revision::DELETED_TEXT; + } + + public static function suggestTarget( $target, array $ids ) { + $rev = Revision::newFromId( $ids[0] ); + return $rev ? $rev->getTitle() : $target; + } + /** * @param $db DatabaseBase * @return mixed @@ -52,7 +65,7 @@ class RevDel_RevisionList extends RevDel_List { array_merge( Revision::selectFields(), Revision::selectUserFields() ), array( 'rev_page' => $this->title->getArticleID(), - 'rev_id' => $ids, + 'rev_id' => $ids, ), __METHOD__, array( 'ORDER BY' => 'rev_id DESC' ), @@ -242,8 +255,7 @@ class RevDel_RevisionItem extends RevDel_Item { if ( $this->isDeleted() && !$this->canViewContent() ) { return $this->list->msg( 'diff' )->escaped(); } else { - return - Linker::linkKnown( + return Linker::linkKnown( $this->list->title, $this->list->msg( 'diff' )->escaped(), array(), @@ -293,7 +305,7 @@ class RevDel_ArchiveList extends RevDel_RevisionList { return $db->select( 'archive', '*', array( 'ar_namespace' => $this->title->getNamespace(), - 'ar_title' => $this->title->getDBkey(), + 'ar_title' => $this->title->getDBkey(), 'ar_timestamp' => $timestamps ), __METHOD__, @@ -350,12 +362,12 @@ class RevDel_ArchiveItem extends RevDel_RevisionItem { $dbw->update( 'archive', array( 'ar_deleted' => $bits ), array( - 'ar_namespace' => $this->list->title->getNamespace(), - 'ar_title' => $this->list->title->getDBkey(), + 'ar_namespace' => $this->list->title->getNamespace(), + 'ar_title' => $this->list->title->getDBkey(), // use timestamp for index - 'ar_timestamp' => $this->row->ar_timestamp, - 'ar_rev_id' => $this->row->ar_rev_id, - 'ar_deleted' => $this->getBits() + 'ar_timestamp' => $this->row->ar_timestamp, + 'ar_rev_id' => $this->row->ar_rev_id, + 'ar_deleted' => $this->getBits() ), __METHOD__ ); return (bool)$dbw->affectedRows(); @@ -442,6 +454,14 @@ class RevDel_FileList extends RevDel_List { return 'oi_archive_name'; } + public static function getRestriction() { + return 'deleterevision'; + } + + public static function getRevdelConstant() { + return File::DELETED_FILE; + } + var $storeBatch, $deleteBatch, $cleanupBatch; /** @@ -450,14 +470,14 @@ class RevDel_FileList extends RevDel_List { */ public function doQuery( $db ) { $archiveNames = array(); - foreach( $this->ids as $timestamp ) { + foreach ( $this->ids as $timestamp ) { $archiveNames[] = $timestamp . '!' . $this->title->getDBkey(); } return $db->select( 'oldimage', OldLocalFile::selectFields(), array( - 'oi_name' => $this->title->getDBkey(), + 'oi_name' => $this->title->getDBkey(), 'oi_archive_name' => $archiveNames ), __METHOD__, @@ -635,8 +655,8 @@ class RevDel_FileItem extends RevDel_Item { array(), array( 'target' => $this->list->title->getPrefixedText(), - 'file' => $this->file->getArchiveName(), - 'token' => $this->list->getUser()->getEditToken( + 'file' => $this->file->getArchiveName(), + 'token' => $this->list->getUser()->getEditToken( $this->file->getArchiveName() ) ) ); @@ -648,13 +668,13 @@ class RevDel_FileItem extends RevDel_Item { * @return string HTML */ protected function getUserTools() { - if( $this->file->userCan( Revision::DELETED_USER, $this->list->getUser() ) ) { + if ( $this->file->userCan( Revision::DELETED_USER, $this->list->getUser() ) ) { $link = Linker::userLink( $this->file->user, $this->file->user_text ) . Linker::userToolLinks( $this->file->user, $this->file->user_text ); } else { $link = $this->list->msg( 'rev-deleted-user' )->escaped(); } - if( $this->file->isDeleted( Revision::DELETED_USER ) ) { + if ( $this->file->isDeleted( Revision::DELETED_USER ) ) { return '<span class="history-deleted">' . $link . '</span>'; } return $link; @@ -667,12 +687,12 @@ class RevDel_FileItem extends RevDel_Item { * @return string HTML */ protected function getComment() { - if( $this->file->userCan( File::DELETED_COMMENT, $this->list->getUser() ) ) { + if ( $this->file->userCan( File::DELETED_COMMENT, $this->list->getUser() ) ) { $block = Linker::commentBlock( $this->file->description ); } else { $block = ' ' . $this->list->msg( 'rev-deleted-comment' )->escaped(); } - if( $this->file->isDeleted( File::DELETED_COMMENT ) ) { + if ( $this->file->isDeleted( File::DELETED_COMMENT ) ) { return "<span class=\"history-deleted\">$block</span>"; } return $block; @@ -685,7 +705,7 @@ class RevDel_FileItem extends RevDel_Item { ' (' . $this->list->msg( 'nbytes' )->numParams( $this->file->getSize() )->text() . ')'; return '<li>' . $this->getLink() . ' ' . $this->getUserTools() . ' ' . - $data . ' ' . $this->getComment(). '</li>'; + $data . ' ' . $this->getComment() . '</li>'; } } @@ -712,7 +732,7 @@ class RevDel_ArchivedFileList extends RevDel_FileList { ArchivedFile::selectFields(), array( 'fa_name' => $this->title->getDBkey(), - 'fa_id' => $ids + 'fa_id' => $ids ), __METHOD__, array( 'ORDER BY' => 'fa_id DESC' ) @@ -771,7 +791,7 @@ class RevDel_ArchivedFileItem extends RevDel_FileItem { $this->file->getTimestamp(), $this->list->getUser() ) ); # Hidden files... - if( !$this->canViewContent() ) { + if ( !$this->canViewContent() ) { $link = $date; } else { $undelete = SpecialPage::getTitleFor( 'Undelete' ); @@ -784,7 +804,7 @@ class RevDel_ArchivedFileItem extends RevDel_FileItem { ) ); } - if( $this->isDeleted() ) { + if ( $this->isDeleted() ) { $link = '<span class="history-deleted">' . $link . '</span>'; } return $link; @@ -803,6 +823,28 @@ class RevDel_LogList extends RevDel_List { return 'log_id'; } + public static function getRestriction() { + return 'deletelogentry'; + } + + public static function getRevdelConstant() { + return LogPage::DELETED_ACTION; + } + + public static function suggestTarget( $target, array $ids ) { + $result = wfGetDB( DB_SLAVE )->select( 'logging', + 'log_type', + array( 'log_id' => $ids ), + __METHOD__, + array( 'DISTINCT' ) + ); + if ( $result->numRows() == 1 ) { + // If there's only one type, the target can be set to include it. + return SpecialPage::getTitleFor( 'Log', $result->current()->log_type ); + } + return SpecialPage::getTitleFor( 'Log' ); + } + /** * @param $db DatabaseBase * @return mixed @@ -913,7 +955,7 @@ class RevDel_LogItem extends RevDel_Item { $action = $formatter->getActionText(); // Comment $comment = $this->list->getLanguage()->getDirMark() . Linker::commentBlock( $this->row->log_comment ); - if( LogEventsList::isDeleted( $this->row, LogPage::DELETED_COMMENT ) ) { + if ( LogEventsList::isDeleted( $this->row, LogPage::DELETED_COMMENT ) ) { $comment = '<span class="history-deleted">' . $comment . '</span>'; } diff --git a/includes/revisiondelete/RevisionDeleteAbstracts.php b/includes/revisiondelete/RevisionDeleteAbstracts.php index b2108de6..803467e6 100644 --- a/includes/revisiondelete/RevisionDeleteAbstracts.php +++ b/includes/revisiondelete/RevisionDeleteAbstracts.php @@ -37,13 +37,45 @@ abstract class RevDel_List extends RevisionListBase { * Get the DB field name associated with the ID list. * This used to populate the log_search table for finding log entries. * Override this function. - * @return null + * @return string|null */ public static function getRelationType() { return null; } /** + * Get the user right required for this list type + * Override this function. + * @since 1.22 + * @return string|null + */ + public static function getRestriction() { + return null; + } + + /** + * Get the revision deletion constant for this list type + * Override this function. + * @since 1.22 + * @return int|null + */ + public static function getRevdelConstant() { + return null; + } + + /** + * Suggest a target for the revision deletion + * Optionally override this function. + * @since 1.22 + * @param Title|null $target User-supplied target + * @param array $ids + * @return Title|null + */ + public static function suggestTarget( $target, array $ids ) { + return $target; + } + + /** * Set the visibility for the revisions in this list. Logging and * transactions are done here. * @@ -68,11 +100,11 @@ abstract class RevDel_List extends RevisionListBase { for ( $this->reset(); $this->current(); $this->next() ) { $item = $this->current(); - unset( $missing[ $item->getId() ] ); + unset( $missing[$item->getId()] ); $oldBits = $item->getBits(); // Build the actual new rev_deleted bitfield - $newBits = SpecialRevisionDelete::extractBitfield( $bitPars, $oldBits ); + $newBits = RevisionDeleter::extractBitfield( $bitPars, $oldBits ); if ( $oldBits == $newBits ) { $status->warning( 'revdelete-no-change', $item->formatDate(), $item->formatTime() ); @@ -94,14 +126,14 @@ abstract class RevDel_List extends RevisionListBase { } if ( !$item->canView() ) { // Cannot access this revision - $msg = ($opType == 'show') ? + $msg = ( $opType == 'show' ) ? 'revdelete-show-no-access' : 'revdelete-modify-no-access'; $status->error( $msg, $item->formatDate(), $item->formatTime() ); $status->failCount++; continue; } // Cannot just "hide from Sysops" without hiding any fields - if( $newBits == Revision::DELETED_RESTRICTED ) { + if ( $newBits == Revision::DELETED_RESTRICTED ) { $status->warning( 'revdelete-only-restricted', $item->formatDate(), $item->formatTime() ); $status->failCount++; continue; @@ -113,9 +145,9 @@ abstract class RevDel_List extends RevisionListBase { if ( $ok ) { $idsForLog[] = $item->getId(); $status->successCount++; - if( $item->getAuthorId() > 0 ) { + if ( $item->getAuthorId() > 0 ) { $authorIds[] = $item->getAuthorId(); - } elseif( IP::isIPAddress( $item->getAuthorName() ) ) { + } elseif ( IP::isIPAddress( $item->getAuthorName() ) ) { $authorIPs[] = $item->getAuthorName(); } } else { @@ -189,7 +221,7 @@ abstract class RevDel_List extends RevisionListBase { protected function updateLog( $params ) { // Get the URL param's corresponding DB field $field = RevisionDeleter::getRelationType( $this->getType() ); - if( !$field ) { + if ( !$field ) { throw new MWException( "Bad log URL param type!" ); } // Put things hidden from sysops in the oversight log @@ -203,7 +235,7 @@ abstract class RevDel_List extends RevisionListBase { // Actually add the deletion log entry $log = new LogPage( $logType ); $logid = $log->addEntry( $this->getLogAction(), $params['title'], - $params['comment'], $logParams ); + $params['comment'], $logParams, $this->getUser() ); // Allow for easy searching of deletion log items for revision/log items $log->addRelations( $field, $params['ids'], $logid ); $log->addRelations( 'target_author_id', $params['authorIds'], $logid ); diff --git a/includes/revisiondelete/RevisionDeleteUser.php b/includes/revisiondelete/RevisionDeleteUser.php index c02e9c76..4505ee10 100644 --- a/includes/revisiondelete/RevisionDeleteUser.php +++ b/includes/revisiondelete/RevisionDeleteUser.php @@ -54,7 +54,7 @@ class RevisionDeleteUser { # The same goes for the sysop-restricted *_deleted bit. $delUser = Revision::DELETED_USER | Revision::DELETED_RESTRICTED; $delAction = LogPage::DELETED_ACTION | Revision::DELETED_RESTRICTED; - if( $op == '&' ) { + if ( $op == '&' ) { $delUser = "~{$delUser}"; $delAction = "~{$delAction}"; } diff --git a/includes/revisiondelete/RevisionDeleter.php b/includes/revisiondelete/RevisionDeleter.php index fe351c51..dbcb3d7d 100644 --- a/includes/revisiondelete/RevisionDeleter.php +++ b/includes/revisiondelete/RevisionDeleter.php @@ -22,11 +22,71 @@ */ /** - * Temporary b/c interface, collection of static functions. - * @ingroup SpecialPage + * General controller for RevDel, used by both SpecialRevisiondelete and + * ApiRevisionDelete. * @ingroup RevisionDelete */ class RevisionDeleter { + /** List of known revdel types, with their corresponding list classes */ + private static $allowedTypes = array( + 'revision' => 'RevDel_RevisionList', + 'archive' => 'RevDel_ArchiveList', + 'oldimage' => 'RevDel_FileList', + 'filearchive' => 'RevDel_ArchivedFileList', + 'logging' => 'RevDel_LogList', + ); + + /** Type map to support old log entries */ + private static $deprecatedTypeMap = array( + 'oldid' => 'revision', + 'artimestamp' => 'archive', + 'oldimage' => 'oldimage', + 'fileid' => 'filearchive', + 'logid' => 'logging', + ); + + /** + * Lists the valid possible types for revision deletion. + * + * @since 1.22 + * @return array + */ + public static function getTypes() { + return array_keys( self::$allowedTypes ); + } + + /** + * Gets the canonical type name, if any. + * + * @since 1.22 + * @param string $typeName + * @return string|null + */ + public static function getCanonicalTypeName( $typeName ) { + if ( isset( self::$deprecatedTypeMap[$typeName] ) ) { + $typeName = self::$deprecatedTypeMap[$typeName]; + } + return isset( self::$allowedTypes[$typeName] ) ? $typeName : null; + } + + /** + * Instantiate the appropriate list class for a given list of IDs. + * + * @since 1.22 + * @param string $typeName RevDel type, see RevisionDeleter::getTypes() + * @param IContextSource $context + * @param Title $title + * @param array $ids + * @return RevDel_List + */ + public static function createList( $typeName, IContextSource $context, Title $title, array $ids ) { + $typeName = self::getCanonicalTypeName( $typeName ); + if ( !$typeName ) { + throw new MWException( __METHOD__ . ": Unknown RevDel type '$typeName'" ); + } + return new self::$allowedTypes[$typeName]( $context, $title, $ids ); + } + /** * Checks for a change in the bitfield for a certain option and updates the * provided array accordingly. @@ -39,8 +99,8 @@ class RevisionDeleter { * @param array $arr the array to update. */ protected static function checkItem( $desc, $field, $diff, $new, &$arr ) { - if( $diff & $field ) { - $arr[ ( $new & $field ) ? 0 : 1 ][] = $desc; + if ( $diff & $field ) { + $arr[( $new & $field ) ? 0 : 1][] = $desc; } } @@ -73,11 +133,12 @@ class RevisionDeleter { self::checkItem( 'revdelete-uname', Revision::DELETED_USER, $diff, $n, $ret ); // Restriction application to sysops - if( $diff & Revision::DELETED_RESTRICTED ) { - if( $n & Revision::DELETED_RESTRICTED ) + if ( $diff & Revision::DELETED_RESTRICTED ) { + if ( $n & Revision::DELETED_RESTRICTED ) { $ret[2][] = 'revdelete-restricted'; - else + } else { $ret[2][] = 'revdelete-unrestricted'; + } } return $ret; } @@ -85,20 +146,62 @@ class RevisionDeleter { /** Get DB field name for URL param... * Future code for other things may also track * other types of revision-specific changes. + * @param string $typeName * @return string One of log_id/rev_id/fa_id/ar_timestamp/oi_archive_name */ public static function getRelationType( $typeName ) { - if ( isset( SpecialRevisionDelete::$deprecatedTypeMap[$typeName] ) ) { - $typeName = SpecialRevisionDelete::$deprecatedTypeMap[$typeName]; + $typeName = self::getCanonicalTypeName( $typeName ); + if ( !$typeName ) { + return null; } - if ( isset( SpecialRevisionDelete::$allowedTypes[$typeName] ) ) { - $class = SpecialRevisionDelete::$allowedTypes[$typeName]['list-class']; - return call_user_func( array( $class, 'getRelationType' ) ); - } else { + return call_user_func( array( self::$allowedTypes[$typeName], 'getRelationType' ) ); + } + + /** + * Get the user right required for the RevDel type + * @since 1.22 + * @param string $typeName + * @return string User right + */ + public static function getRestriction( $typeName ) { + $typeName = self::getCanonicalTypeName( $typeName ); + if ( !$typeName ) { + return null; + } + return call_user_func( array( self::$allowedTypes[$typeName], 'getRestriction' ) ); + } + + /** + * Get the revision deletion constant for the RevDel type + * @since 1.22 + * @param string $typeName + * @return int RevDel constant + */ + public static function getRevdelConstant( $typeName ) { + $typeName = self::getCanonicalTypeName( $typeName ); + if ( !$typeName ) { return null; } + return call_user_func( array( self::$allowedTypes[$typeName], 'getRevdelConstant' ) ); + } + + /** + * Suggest a target for the revision deletion + * @since 1.22 + * @param string $typeName + * @param Title|null $title User-supplied target + * @param array $ids + * @return Title|null + */ + public static function suggestTarget( $typeName, $target, array $ids ) { + $typeName = self::getCanonicalTypeName( $typeName ); + if ( !$typeName ) { + return $target; + } + return call_user_func( array( self::$allowedTypes[$typeName], 'suggestTarget' ), $target, $ids ); } + /** * Checks if a revision still exists in the revision table. * If it doesn't, returns the corresponding ar_timestamp field @@ -124,4 +227,24 @@ class RevisionDeleter { return $timestamp; } + + /** + * Put together a rev_deleted bitfield + * @since 1.22 + * @param array $bitPars extractBitParams() params + * @param int $oldfield current bitfield + * @return array + */ + public static function extractBitfield( $bitPars, $oldfield ) { + // Build the actual new rev_deleted bitfield + $newBits = 0; + foreach ( $bitPars as $const => $val ) { + if ( $val == 1 ) { + $newBits |= $const; // $const is the *_deleted const + } elseif ( $val == -1 ) { + $newBits |= ( $oldfield & $const ); // use existing + } + } + return $newBits; + } } |