Skip to content

Commit

Permalink
Enable users to watch category membership changes #2
Browse files Browse the repository at this point in the history
This is part of a chain that reverts:
e412ff5.

NOTE:
- The feature is disabled by default
- User settings default to hiding changes
- T109707 Touching a file on wikisource adds and
      removes it from a category... Even when page
      has no changes.... WTF? See linked issue,
      marked as stalled with a possible way forward
      for this patch.
      @see https://gerrit.wikimedia.org/r/#/c/235467/

Changes since version 1:
- T109604 - Page names in comment are no longer
      url encoded / have _'s
- T109638 & T110338 - Reserved username now used
      when we can't determine a username for the change
      (we could perhaps set the user and id to be blank
      in the RC table, but who knows what this might do)
- T109688 - History links are now disabled in RC....
      (could be fine for the introduction and worked
      on more in the future)
- Categorization changes are now always patrolled
- Touching on T109672 in this change emails will never
      be sent regarding categorization changes. (this
      can of course be changed in a followup)
- Added $wgRCWatchCategoryMembership defaulting to true
      for enabling / disabling the feature
- T109700 - for cases when no revision was retrieved
      for a category change set the bot flag to true.
      This means all changes caused by parser functions
      & Lua will be marked as bot, as will changes that
      cant find their revision due to slave lag..

Bug: T9148
Bug: T109604
Bug: T109638
Bug: T109688
Bug: T109700
Bug: T110338
Bug: T110340
Change-Id: I51c2c1254de862f24a26ef9dbbf027c6c83e9063
  • Loading branch information
addshore authored and legoktm committed Oct 20, 2015
1 parent 7b19f2e commit d40cd42
Show file tree
Hide file tree
Showing 25 changed files with 427 additions and 57 deletions.
8 changes: 8 additions & 0 deletions includes/DefaultSettings.php
Expand Up @@ -4539,6 +4539,7 @@
'gender' => 'unknown',
'hideminor' => 0,
'hidepatrolled' => 0,
'hidecategorization' => 1,
'imagesize' => 2,
'math' => 1,
'minordefault' => 0,
Expand Down Expand Up @@ -4570,6 +4571,7 @@
'watchlisthideminor' => 0,
'watchlisthideown' => 0,
'watchlisthidepatrolled' => 0,
'watchlisthidecategorization' => 1,
'watchmoves' => 0,
'watchrollback' => 0,
'wllimit' => 250,
Expand Down Expand Up @@ -6169,6 +6171,12 @@
'udp' => 'UDPRCFeedEngine',
);

/**
* Treat category membership changes as a RecentChange
* @since 1.27
*/
$wgRCWatchCategoryMembership = false;

/**
* Use RC Patrolling to check for vandalism
*/
Expand Down
16 changes: 16 additions & 0 deletions includes/Preferences.php
Expand Up @@ -892,6 +892,14 @@ static function rcPreferences( $user, IContextSource $context, &$defaultPreferen
'section' => 'rc/advancedrc',
);

if ( $config->get( 'RCWatchCategoryMembership' ) ) {
$defaultPreferences['hidecategorization'] = array(
'type' => 'toggle',
'label-message' => 'tog-hidecategorization',
'section' => 'rc/advancedrc',
);
}

if ( $user->useRCPatrol() ) {
$defaultPreferences['hidepatrolled'] = array(
'type' => 'toggle',
Expand Down Expand Up @@ -999,6 +1007,14 @@ static function watchlistPreferences( $user, IContextSource $context, &$defaultP
'label-message' => 'tog-watchlisthideliu',
);

if ( $config->get( 'RCWatchCategoryMembership' ) ) {
$defaultPreferences['watchlisthidecategorization'] = array(
'type' => 'toggle',
'section' => 'watchlist/advancedwatchlist',
'label-message' => 'tog-watchlisthidecategorization',
);
}

if ( $user->useRCPatrol() ) {
$defaultPreferences['watchlisthidepatrolled'] = array(
'type' => 'toggle',
Expand Down
1 change: 1 addition & 0 deletions includes/api/ApiFeedRecentChanges.php
Expand Up @@ -155,6 +155,7 @@ public function getAllowedParams() {
'hideliu' => false,
'hidepatrolled' => false,
'hidemyself' => false,
'hidecategorization' => false,

'tagfilter' => array(
ApiBase::PARAM_TYPE => 'string',
Expand Down
9 changes: 2 additions & 7 deletions includes/api/ApiQueryRecentChanges.php
Expand Up @@ -678,14 +678,9 @@ public function getAllowedParams() {
ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2
),
'type' => array(
ApiBase::PARAM_DFLT => 'edit|new|log',
ApiBase::PARAM_DFLT => 'edit|new|log|categorize',
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => array(
'edit',
'external',
'new',
'log'
)
ApiBase::PARAM_TYPE => RecentChange::getChangeTypes()
),
'toponly' => false,
'continue' => array(
Expand Down
10 changes: 3 additions & 7 deletions includes/api/ApiQueryWatchlist.php
Expand Up @@ -483,14 +483,10 @@ public function getAllowedParams() {
)
),
'type' => array(
ApiBase::PARAM_DFLT => 'edit|new|log',
ApiBase::PARAM_DFLT => 'edit|new|log|categorize',
ApiBase::PARAM_ISMULTI => true,
ApiBase::PARAM_TYPE => array(
'edit',
'external',
'new',
'log',
)
ApiBase::PARAM_HELP_MSG_PER_VALUE => array(),
ApiBase::PARAM_TYPE => RecentChange::getChangeTypes()
),
'owner' => array(
ApiBase::PARAM_TYPE => 'user'
Expand Down
8 changes: 7 additions & 1 deletion includes/api/i18n/en.json
Expand Up @@ -163,6 +163,7 @@
"apihelp-feedrecentchanges-param-hideliu": "Hide changes made by registered users.",
"apihelp-feedrecentchanges-param-hidepatrolled": "Hide patrolled changes.",
"apihelp-feedrecentchanges-param-hidemyself": "Hide changes made by the current user.",
"apihelp-feedrecentchanges-param-hidecategorization": "Hide category membership changes.",
"apihelp-feedrecentchanges-param-tagfilter": "Filter by tag.",
"apihelp-feedrecentchanges-param-target": "Show only changes on pages linked from this page.",
"apihelp-feedrecentchanges-param-showlinkedto": "Show changes on pages linked to the selected page instead.",
Expand Down Expand Up @@ -1211,7 +1212,12 @@
"apihelp-query+watchlist-paramvalue-prop-notificationtimestamp": "Adds timestamp of when the user was last notified about the edit.",
"apihelp-query+watchlist-paramvalue-prop-loginfo": "Adds log information where appropriate.",
"apihelp-query+watchlist-param-show": "Show only items that meet these criteria. For example, to see only minor edits done by logged-in users, set $1show=minor|!anon.",
"apihelp-query+watchlist-param-type": "Which types of changes to show:\n;edit:Regular page edits.\n;external:External changes.\n;new:Page creations.\n;log:Log entries.",
"apihelp-query+watchlist-param-type": "Which types of changes to show:",
"apihelp-query+watchlist-paramvalue-type-edit": "Regular page edits.",
"apihelp-query+watchlist-paramvalue-type-external": "External changes.",
"apihelp-query+watchlist-paramvalue-type-new": "Page creations.",
"apihelp-query+watchlist-paramvalue-type-log": "Log entries.",
"apihelp-query+watchlist-paramvalue-type-categorize": "Category membership changes.",
"apihelp-query+watchlist-param-owner": "Used along with $1token to access a different user's watchlist.",
"apihelp-query+watchlist-param-token": "A security token (available in the user's [[Special:Preferences#mw-prefsection-watchlist|preferences]]) to allow access to another user's watchlist.",
"apihelp-query+watchlist-example-simple": "List the top revision for recently changed pages on the current user's watchlist.",
Expand Down
6 changes: 6 additions & 0 deletions includes/api/i18n/qqq.json
Expand Up @@ -159,6 +159,7 @@
"apihelp-feedrecentchanges-param-hideliu": "{{doc-apihelp-param|feedrecentchanges|hideliu}}",
"apihelp-feedrecentchanges-param-hidepatrolled": "{{doc-apihelp-param|feedrecentchanges|hidepatrolled}}",
"apihelp-feedrecentchanges-param-hidemyself": "{{doc-apihelp-param|feedrecentchanges|hidemyself}}",
"apihelp-feedrecentchanges-param-hidecategorization": "{{doc-apihelp-param|feedrecentchanges|hidecategorization}}",
"apihelp-feedrecentchanges-param-tagfilter": "{{doc-apihelp-param|feedrecentchanges|tagfilter}}",
"apihelp-feedrecentchanges-param-target": "{{doc-apihelp-param|feedrecentchanges|target}}",
"apihelp-feedrecentchanges-param-showlinkedto": "{{doc-apihelp-param|feedrecentchanges|showlinkedto}}",
Expand Down Expand Up @@ -1131,6 +1132,11 @@
"apihelp-query+watchlist-paramvalue-prop-loginfo": "{{doc-apihelp-paramvalue|query+watchlist|prop|loginfo}}",
"apihelp-query+watchlist-param-show": "{{doc-apihelp-param|query+watchlist|show}}",
"apihelp-query+watchlist-param-type": "{{doc-apihelp-param|query+watchlist|type}}",
"apihelp-query+watchlist-paramvalue-type-edit": "{{doc-apihelp-paramvalue|query+watchlist|type|edit}}",
"apihelp-query+watchlist-paramvalue-type-external": "{{doc-apihelp-paramvalue|query+watchlist|type|external}}",
"apihelp-query+watchlist-paramvalue-type-new": "{{doc-apihelp-paramvalue|query+watchlist|type|new}}",
"apihelp-query+watchlist-paramvalue-type-log": "{{doc-apihelp-paramvalue|query+watchlist|type|log}}",
"apihelp-query+watchlist-paramvalue-type-categorize": "{{doc-apihelp-paramvalue|query+watchlist|type|categorize}}",
"apihelp-query+watchlist-param-owner": "{{doc-apihelp-param|query+watchlist|owner}}",
"apihelp-query+watchlist-param-token": "{{doc-apihelp-param|query+watchlist|token}}",
"apihelp-query+watchlist-example-simple": "{{doc-apihelp-example|query+watchlist}}",
Expand Down
5 changes: 3 additions & 2 deletions includes/changes/CategoryMembershipChange.php
Expand Up @@ -47,7 +47,8 @@ class CategoryMembershipChange {

/**
* @var int
* Number of pages this WikiPage is embedded by; set by CategoryMembershipChange::setRecursive()
* Number of pages this WikiPage is embedded by
* Set by CategoryMembershipChange::checkTemplateLinks()
*/
private $numTemplateLinks = 0;

Expand Down Expand Up @@ -239,7 +240,7 @@ private function getUser() {
* @param int $type may be CategoryMembershipChange::CATEGORY_ADDITION
* or CategoryMembershipChange::CATEGORY_REMOVAL
* @param array $params
* - prefixedUrl: result of Title::->getPrefixedURL()
* - prefixedText: result of Title::->getPrefixedText()
*
* @return string
*/
Expand Down
48 changes: 36 additions & 12 deletions includes/changes/ChangesList.php
Expand Up @@ -305,7 +305,11 @@ public function insertLog( &$s, $title, $logtype ) {
*/
public function insertDiffHist( &$s, &$rc, $unpatrolled ) {
# Diff link
if ( $rc->mAttribs['rc_type'] == RC_NEW || $rc->mAttribs['rc_type'] == RC_LOG ) {
if (
$rc->mAttribs['rc_type'] == RC_NEW ||
$rc->mAttribs['rc_type'] == RC_LOG ||
$rc->mAttribs['rc_type'] == RC_CATEGORIZE
) {
$diffLink = $this->message['diff'];
} elseif ( !self::userCan( $rc, Revision::DELETED_TEXT, $this->getUser() ) ) {
$diffLink = $this->message['diff'];
Expand All @@ -323,17 +327,22 @@ public function insertDiffHist( &$s, &$rc, $unpatrolled ) {
$query
);
}
$diffhist = $diffLink . $this->message['pipe-separator'];
# History link
$diffhist .= Linker::linkKnown(
$rc->getTitle(),
$this->message['hist'],
array(),
array(
'curid' => $rc->mAttribs['rc_cur_id'],
'action' => 'history'
)
);
if ( $rc->mAttribs['rc_type'] == RC_CATEGORIZE ) {
$diffhist = $diffLink . $this->message['pipe-separator'] . $this->message['hist'];
} else {
$diffhist = $diffLink . $this->message['pipe-separator'];
# History link
$diffhist .= Linker::linkKnown(
$rc->getTitle(),
$this->message['hist'],
array(),
array(
'curid' => $rc->mAttribs['rc_cur_id'],
'action' => 'history'
)
);
}

// @todo FIXME: Hard coded ". .". Is there a message for this? Should there be?
$s .= $this->msg( 'parentheses' )->rawParams( $diffhist )->escaped() .
' <span class="mw-changeslist-separator">. .</span> ';
Expand Down Expand Up @@ -630,4 +639,19 @@ public static function isUnpatrolled( $rc, User $user ) {

return false;
}

/**
* Determines whether a revision is linked to this change; this may not be the case
* when the categorization wasn't done by an edit but a conditional parser function
*
* @since 1.27
*
* @param RecentChange|RCCacheEntry $rcObj
* @return bool
*/
protected function isCategorizationWithoutRevision( $rcObj ) {
return intval( $rcObj->getAttribute( 'rc_type' ) ) === RC_CATEGORIZE
&& intval( $rcObj->getAttribute( 'rc_this_oldid' ) ) === 0;
}

}
48 changes: 38 additions & 10 deletions includes/changes/EnhancedChangesList.php
Expand Up @@ -405,6 +405,8 @@ protected function getLineData( array $block, RCCacheEntry $rcObj, array $queryP

if ( $rcObj->mAttribs['rc_type'] == RC_LOG ) {
$data['logEntry'] = $this->insertLogEntry( $rcObj );
} elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
$data['comment'] = $this->insertComment( $rcObj );
} else {
# User links
$data['userLink'] = $rcObj->userlink;
Expand Down Expand Up @@ -497,7 +499,7 @@ protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidd
/** @var $block0 RecentChange */
$block0 = $block[0];
$last = $block[count( $block ) - 1];
if ( !$allLogs ) {
if ( !$allLogs && $rcObj->mAttribs['rc_type'] != RC_CATEGORIZE ) {
if ( !ChangesList::userCan( $rcObj, Revision::DELETED_TEXT, $this->getUser() ) ) {
$links['total-changes'] = $nchanges[$n];
} elseif ( $isnew ) {
Expand Down Expand Up @@ -529,7 +531,7 @@ protected function getLogText( $block, $queryParams, $allLogs, $isnew, $namehidd
}

# History
if ( $allLogs ) {
if ( $allLogs || $rcObj->mAttribs['rc_type'] == RC_CATEGORIZE ) {
// don't show history link for logs
} elseif ( $namehidden || !$block0->getTitle()->exists() ) {
$links['history'] = $this->message['enhancedrc-history'];
Expand Down Expand Up @@ -605,15 +607,9 @@ protected function recentChangesBlockLine( $rcObj ) {
}

# Diff and hist links
if ( $type != RC_LOG ) {
if ( $type == RC_LOG && $type != RC_CATEGORIZE ) {
$query['action'] = 'history';
$data['historyLink'] = ' ' . $this->msg( 'parentheses' )
->rawParams( $rcObj->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
$rcObj->getTitle(),
$this->message['hist'],
array(),
$query
) )->escaped();
$data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
}
$data['separatorAfterLinks'] = ' <span class="mw-changeslist-separator">. .</span> ';

Expand All @@ -628,10 +624,15 @@ protected function recentChangesBlockLine( $rcObj ) {

if ( $type == RC_LOG ) {
$data['logEntry'] = $this->insertLogEntry( $rcObj );
} elseif ( $this->isCategorizationWithoutRevision( $rcObj ) ) {
$data['comment'] = $this->insertComment( $rcObj );
} else {
$data['userLink'] = $rcObj->userlink;
$data['userTalkLink'] = $rcObj->usertalklink;
$data['comment'] = $this->insertComment( $rcObj );
if ( $type == RC_CATEGORIZE ) {
$data['historyLink'] = $this->getDiffHistLinks( $rcObj, $query );
}
$data['rollback'] = $this->getRollback( $rcObj );
}

Expand Down Expand Up @@ -672,6 +673,33 @@ protected function recentChangesBlockLine( $rcObj ) {
return $line;
}

/**
* Returns value to be used in 'historyLink' element of $data param in
* EnhancedChangesListModifyBlockLineData hook.
*
* @since 1.27
*
* @param RCCacheEntry $rc
* @param array $query array of key/value pairs to append as a query string
* @return string HTML
*/
public function getDiffHistLinks( RCCacheEntry $rc, array $query ) {
$pageTitle = $rc->getTitle();
if ( $rc->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
// For categorizations we must swap the category title with the page title!
$pageTitle = Title::newFromID( $rc->getAttribute( 'rc_cur_id' ) );
}

$retVal = ' ' . $this->msg( 'parentheses' )
->rawParams( $rc->difflink . $this->message['pipe-separator'] . Linker::linkKnown(
$pageTitle,
$this->message['hist'],
array(),
$query
) )->escaped();
return $retVal;
}

/**
* If enhanced RC is in use, this function takes the previously cached
* RC lines, arranges them, and outputs the HTML
Expand Down
3 changes: 2 additions & 1 deletion includes/changes/OldChangesList.php
Expand Up @@ -87,7 +87,6 @@ private function formatChangeLine( RecentChange $rc, array &$classes, $watched )
// Regular entries
} else {
$unpatrolled = $this->showAsUnpatrolled( $rc );

$this->insertDiffHist( $html, $rc, $unpatrolled );
# M, N, b and ! (minor, new, bot and unpatrolled)
$html .= $this->recentChangesFlags(
Expand All @@ -113,6 +112,8 @@ private function formatChangeLine( RecentChange $rc, array &$classes, $watched )

if ( $rc->mAttribs['rc_type'] == RC_LOG ) {
$html .= $this->insertLogEntry( $rc );
} elseif ( $this->isCategorizationWithoutRevision( $rc ) ) {
$html .= $this->insertComment( $rc );
} else {
# User tool links
$this->insertUserRelatedLinks( $html, $rc );
Expand Down
9 changes: 9 additions & 0 deletions includes/changes/RCCacheEntryFactory.php
Expand Up @@ -209,6 +209,15 @@ private function buildDiffLink( RecentChange $cacheEntry, $showDiffLinks, $count
$diffLink = $diffMessage;
} elseif ( in_array( $cacheEntry->mAttribs['rc_type'], $logTypes ) ) {
$diffLink = $diffMessage;
} elseif ( $cacheEntry->getAttribute( 'rc_type' ) == RC_CATEGORIZE ) {
$rcCurId = $cacheEntry->getAttribute( 'rc_cur_id' );
$pageTitle = Title::newFromID( $rcCurId );
if ( $pageTitle === null ) {
wfDebugLog( 'RCCacheEntryFactory', 'Could not get Title for rc_cur_id: ' . $rcCurId );
return $diffMessage;
}
$diffUrl = htmlspecialchars( $pageTitle->getLinkURL( $queryParams ) );
$diffLink = "<a href=\"$diffUrl\" tabindex=\"$counter\">$diffMessage</a>";
} else {
$diffUrl = htmlspecialchars( $cacheEntry->getTitle()->getLinkURL( $queryParams ) );
$diffLink = "<a href=\"$diffUrl\" tabindex=\"$counter\">$diffMessage</a>";
Expand Down
24 changes: 15 additions & 9 deletions includes/changes/RecentChange.php
Expand Up @@ -324,15 +324,21 @@ public function save( $noudp = false ) {
$editor = $this->getPerformer();
$title = $this->getTitle();

if ( Hooks::run( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) {
# @todo FIXME: This would be better as an extension hook
$enotif = new EmailNotification();
$enotif->notifyOnPageChange( $editor, $title,
$this->mAttribs['rc_timestamp'],
$this->mAttribs['rc_comment'],
$this->mAttribs['rc_minor'],
$this->mAttribs['rc_last_oldid'],
$this->mExtra['pageStatus'] );
// Never send an RC notification email about categorization changes
if ( $this->mAttribs['rc_type'] != RC_CATEGORIZE ) {
if ( Hooks::run( 'AbortEmailNotification', array( $editor, $title, $this ) ) ) {
# @todo FIXME: This would be better as an extension hook
$enotif = new EmailNotification();
$enotif->notifyOnPageChange(
$editor,
$title,
$this->mAttribs['rc_timestamp'],
$this->mAttribs['rc_comment'],
$this->mAttribs['rc_minor'],
$this->mAttribs['rc_last_oldid'],
$this->mExtra['pageStatus']
);
}
}
}

Expand Down

0 comments on commit d40cd42

Please sign in to comment.