diff --git a/AbuseFilter.class.php b/AbuseFilter.class.php index def6e57c7..0989fdeaf 100644 --- a/AbuseFilter.class.php +++ b/AbuseFilter.class.php @@ -2200,4 +2200,29 @@ class AbuseFilter { return $text; } + /* + * Get the history ID of the first change to a given filter + * + * @param $filterId integer: Filter id + * @return integer|bool + */ + public static function getFirstFilterChange( $filterID ) { + static $firstChanges = array(); + + if ( !isset( $firstChanges[ $filterID ] ) ) { + $dbr = wfGetDB( DB_SLAVE ); + $row = $dbr->selectRow( + 'abuse_filter_history', + 'afh_id', + array( + 'afh_filter' => $filterID, + ), + __METHOD__, + array( 'ORDER BY' => 'afh_timestamp ASC' ) + ); + $firstChanges[$filterID] = $row->afh_id; + } + + return $firstChanges[$filterID]; + } } diff --git a/AbuseFilter.i18n.php b/AbuseFilter.i18n.php index 9b2ea1a00..2f90c6a5e 100644 --- a/AbuseFilter.i18n.php +++ b/AbuseFilter.i18n.php @@ -478,6 +478,8 @@ For full details, see [[Special:AbuseFilter/history|the list]] of recent filter 'abusefilter-diff-pattern' => 'Filter conditions', 'abusefilter-diff-invalid' => 'Unable to fetch the requested versions', 'abusefilter-diff-backhistory' => 'Back to filter history', + 'abusefilter-diff-prev' => 'Older change', + 'abusefilter-diff-next' => 'Newer change', // Import interface 'abusefilter-import-intro' => 'You can use this interface to import filters from other wikis. @@ -929,6 +931,8 @@ This is also used in {{msg-mw|Abusefilter-revert-preview-intro}}. When changing * $2 is a link to a username. * $3 is a raw username, which can be used for GENDER.', 'abusefilter-diff-info' => "Header for the box containing the basic information about a user account, displayed on the 'user profile' tab of the [[Special:Preferences|user preferences]] special page.", + 'abusefilter-diff-prev' => 'Link to the diff view for the previous change to this filter', + 'abusefilter-diff-next' => 'Link to the diff view for the next change to this filter', 'abusefilter-import-intro' => "Do not ''translate'' {{int:abusefilter-edit-export}}, {{int:abusefilter-tools-subtitle}}, and {{int:abusefilter-import-submit}} unless you absolute must substitute any of them.", 'abusefilter-group-default' => 'The name for the default filter group. Most filters will be in this group.', ); diff --git a/Views/AbuseFilterViewDiff.php b/Views/AbuseFilterViewDiff.php index 0195e22d2..6382dba2b 100644 --- a/Views/AbuseFilterViewDiff.php +++ b/Views/AbuseFilterViewDiff.php @@ -3,6 +3,7 @@ class AbuseFilterViewDiff extends AbuseFilterView { var $mOldVersion = null; var $mNewVersion = null; + var $mNextHistoryId = null; var $mFilter = null; function show() { @@ -16,7 +17,7 @@ class AbuseFilterViewDiff extends AbuseFilterView { } foreach ( $links as $msg => $title ) { - $links[$msg] = Linker::link( $title, $this->msg( $msg )->parse() ); + $links[$msg] = Linker::link( $title, $this->msg( $msg )->escaped() ); } $backlinks = $this->getLanguage()->pipeList( $links ); @@ -24,6 +25,33 @@ class AbuseFilterViewDiff extends AbuseFilterView { if ( $show ) { $out->addHTML( $this->formatDiff() ); + + // Next and previous change links + $links = array(); + if ( AbuseFilter::getFirstFilterChange( $this->mFilter ) != $this->mOldVersion['meta']['history_id'] ) { + // Create a "previous change" link if this isn't the first change of the given filter + $links[] = Linker::link( + $this->getTitle( + 'history/' . $this->mFilter . '/diff/prev/' . $this->mOldVersion['meta']['history_id'] + ), + $this->getLanguage()->getArrow( 'backwards' ) . ' ' . $this->msg( 'abusefilter-diff-prev' )->escaped() + ); + } + + if ( !is_null( $this->mNextHistoryId ) ) { + // Create a "next change" link if this isn't the last change of the given filter + $links[] = Linker::link( + $this->getTitle( + 'history/' . $this->mFilter . '/diff/prev/' . $this->mNextHistoryId + ), + $this->msg( 'abusefilter-diff-next' )->escaped() . ' ' . $this->getLanguage()->getArrow( 'forwards' ) + ); + } + + if ( count( $links ) > 0 ) { + $backlinks = $this->getLanguage()->pipeList( $links ); + $out->addHTML( Xml::tags( 'p', null, $backlinks ) ); + } } } @@ -47,9 +75,35 @@ class AbuseFilterViewDiff extends AbuseFilterView { return false; } + $this->mNextHistoryId = $this->getNextHistoryId( $this->mNewVersion['meta']['history_id'] , 'next' ); + return true; } + /** + * Get the history ID of the next change + * + * @param $historyId Integer: History id to find next change of + * @return Integer|Null: Id of the next change or null if there isn't one + */ + function getNextHistoryId( $historyId ) { + $dbr = wfGetDB( DB_SLAVE ); + $row = $dbr->selectRow( + 'abuse_filter_history', + 'afh_id', + array( + 'afh_filter' => $this->mFilter, + 'afh_id > ' . $dbr->addQuotes( $historyId ), + ), + __METHOD__, + array( 'ORDER BY' => 'afh_timestamp ASC' ) + ); + if ( $row ) { + return $row->afh_id; + } + return null; + } + function loadSpec( $spec, $otherSpec ) { static $dependentSpecs = array( 'prev', 'next' ); static $cache = array(); @@ -106,7 +160,7 @@ class AbuseFilterViewDiff extends AbuseFilterView { 'afh_id>' . $dbr->addQuotes( $other['meta']['history_id'] ), ), __METHOD__, - array( 'ORDER BY' => 'afh_timestamp DESC' ) + array( 'ORDER BY' => 'afh_timestamp ASC' ) ); if ( $other && !$row ) { diff --git a/Views/AbuseFilterViewHistory.php b/Views/AbuseFilterViewHistory.php index 07d68d382..05adad9e8 100644 --- a/Views/AbuseFilterViewHistory.php +++ b/Views/AbuseFilterViewHistory.php @@ -158,9 +158,13 @@ class AbuseFilterHistoryPager extends TablePager { $formatted = Linker::link( $title, $value ); break; case 'afh_id': - $title = $this->mPage->getTitle( - 'history/' . $row->afh_filter . "/diff/prev/$value" ); - $formatted = Linker::link( $title, $this->msg( 'abusefilter-history-diff' )->parse() ); + $formatted = ''; + if ( AbuseFilter::getFirstFilterChange( $row->afh_filter ) != $value ) { + // Set a link to a diff with the previous version if this isn't the first edit to the filter + $title = $this->mPage->getTitle( + 'history/' . $row->afh_filter . "/diff/prev/$value" ); + $formatted = Linker::link( $title, $this->msg( 'abusefilter-history-diff' )->parse() ); + } break; default: $formatted = "Unable to format $name";