Victor Vasiliev has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/52922


Change subject: Provide a JSON recent changes field.
......................................................................

Provide a JSON recent changes field.

This introduces a new configuration variable, $wgRCLiveFeeds, which
allows the user to configure multiple destinations to send the RC
notifications to. It also allows user to send the feed in different
formats, including the older IRC feed format and the new JSON format.

Change-Id: I270bde418a82985c94372ac4579100435b6ee026
---
M docs/hooks.txt
M includes/DefaultSettings.php
M includes/RecentChange.php
M includes/api/ApiQueryRecentChanges.php
4 files changed, 188 insertions(+), 32 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/22/52922/1

diff --git a/docs/hooks.txt b/docs/hooks.txt
index 28eedf4..c37a20e 100644
--- a/docs/hooks.txt
+++ b/docs/hooks.txt
@@ -1834,6 +1834,13 @@
 'RecentChange_save': Called at the end of RecentChange::save().
 $recentChange: RecentChange object
 
+'RecentChangeCustomFeed': Allows to provide custom live feeds for recent 
changes.
+Have to return false if it actually handled the request.
+$feedID: the ID string of the recent changes feed
+$engine: the name of the engine specified by user
+$feed: the feed parameters
+$change: RecentChange object
+
 'RedirectSpecialArticleRedirectParams': Lets you alter the set of parameter
 names such as "oldid" that are preserved when using redirecting special pages
 such as Special:MyPage and Special:MyTalk.
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 7aad30c..9c51a63 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -5118,11 +5118,15 @@
 /**
  * Send recent changes updates via UDP. The updates will be formatted for IRC.
  * Set this to the IP address of the receiver.
+ *
+ * @deprecated since 1.21, use $wgRCLiveFeeds
  */
 $wgRC2UDPAddress = false;
 
 /**
  * Port number for RC updates
+ *
+ * @deprecated since 1.21, use $wgRCLiveFeeds
  */
 $wgRC2UDPPort = false;
 
@@ -5131,22 +5135,59 @@
  * This can be used to identify the wiki. A script is available called
  * mxircecho.py which listens on a UDP port, and uses a prefix ending in a
  * tab to identify the IRC channel to send the log line to.
+ *
+ * @deprecated since 1.21, use $wgRCLiveFeeds
  */
 $wgRC2UDPPrefix = '';
 
 /**
  * If this is set to true, $wgLocalInterwiki will be prepended to links in the
  * IRC feed. If this is set to a string, that string will be used as the 
prefix.
+ *
+ * @deprecated since 1.21, use $wgRCLiveFeeds
  */
 $wgRC2UDPInterwikiPrefix = false;
 
 /**
  * Set to true to omit "bot" edits (by users with the bot permission) from the
  * UDP feed.
+ *
+ * @deprecated since 1.21, use $wgRCLiveFeeds
  */
 $wgRC2UDPOmitBots = false;
 
 /**
+ * Destinations to which notifications about recent changes
+ * should be sent. The format is 'id' => parameters.
+ *
+ * The two currently supported 'engine' parameter options are 'irc' and 'json',
+ * Both are used to send recent changes over UDP to the specified server.
+ * The common options are:
+ *   * 'address' -- the address to which the notices are to be sent.
+ *   * 'port' -- the UDP port number
+ *   * 'prefix' -- the string with which all notices should be prefixed
+ *   * 'omit_bots' -- whether the bot edits should be in the feed
+ *  The IRC-specific options are:
+ *   * 'interwiki_prefix' -- whether the titles should be prefixed with
+ *     $wgLocalInterwiki.
+ *  The JSON-specific options are:
+ *   * 'channel' -- if set, the 'channel' parameter is also set in JSON values.
+ *
+ *  By default, this contains a 'default' entry pointing to old $wgRC2UDP 
paramters
+ *  of IRC feed.
+ */
+$wgRCLiveFeeds = array(
+       'default' => array(
+               'engine' => 'irc',
+               'address' => &$wgRC2UDPAddress,
+               'port' => &$wgRC2UDPPort,
+               'prefix' => &$wgRC2UDPPrefix,
+               'interwiki_prefix' => &$wgRC2UDPInterwikiPrefix,
+               'omit_bots' => &$wgRC2UDPOmitBots,
+       ),
+);
+
+/**
  * Enable user search in Special:Newpages
  * This is really a temporary hack around an index install bug on some 
Wikipedias.
  * Kill it once fixed.
diff --git a/includes/RecentChange.php b/includes/RecentChange.php
index 6af7597..003e3ec 100644
--- a/includes/RecentChange.php
+++ b/includes/RecentChange.php
@@ -168,6 +168,31 @@
                );
        }
 
+       /**
+        * Generate a string representation of the recent change type.
+        *
+        * @param type Change type to represent
+        * @return string
+        */
+       public static function typeToString( $type ) {
+               switch ( $type ) {
+                       case RC_EDIT:
+                               return 'edit';
+                       case RC_NEW:
+                               return 'new';
+                       case RC_MOVE:
+                               return 'move';
+                       case RC_LOG:
+                               return 'log';
+                       case RC_EXTERNAL:
+                               return 'external';
+                       case RC_MOVE_OVER_REDIRECT:
+                               return 'move over redirect';
+                       default:
+                               return $type;
+               }
+       }
+
        # Accessors
 
        /**
@@ -282,10 +307,44 @@
        }
 
        public function notifyRC2UDP() {
-               global $wgRC2UDPAddress, $wgRC2UDPOmitBots;
-               # Notify external application via UDP
-               if ( $wgRC2UDPAddress && ( !$this->mAttribs['rc_bot'] || 
!$wgRC2UDPOmitBots ) ) {
-                       self::sendToUDP( $this->getIRCLine() );
+               $this->notifyLiveFeeds();
+       }
+
+       /**
+        * Notify all the feeds about the change.
+        */
+       public function notifyLiveFeeds() {
+               global $wgRCLiveFeeds;
+
+               foreach( $wgRCLiveFeeds as $feedID => $feed ) {
+                       $engine = $feed['engine'];
+
+                       if( $engine == 'irc' || $engine == 'json' ) {
+                               if( $engine == 'irc' ) {
+                                       $line = $this->getIRCLine( 
$feed['interwiki_prefix'] );
+                               }
+                               if( $engine == 'json' ) {
+                                       $line = $this->getJSON( $feed );
+                               }
+
+                               $prefix = isset( $feed['prefix'] ) ? 
$feed['prefix'] : '';
+                               $omitBots = isset( $feed['omit_bots'] ) ? 
$feed['omit_bots'] : false;
+
+                               if( $omitBots && $this->mAttribs['rc_bot'] ) {
+                                       return;
+                               }
+
+                               self::sendToUDP(
+                                       $line,
+                                       $feed['address'],
+                                       $prefix,
+                                       $feed['port']
+                               );
+                       } else {
+                               if( !wfRunHooks( 'RecentChangeCustomFeed', 
array( $feedID, $engine, $feed, $this ) ) ) {
+                                       throw new MWException( "Recent chanages 
feed {$feedID} has invalid engine specified" );
+                               }
+                       }
                }
        }
 
@@ -300,7 +359,7 @@
         */
        public static function sendToUDP( $line, $address = '', $prefix = '', 
$port = '' ) {
                global $wgRC2UDPAddress, $wgRC2UDPPrefix, $wgRC2UDPPort;
-               # Assume default for standard RC case
+               # Assume default for standard RC case (using b/c variables)
                $address = $address ? $address : $wgRC2UDPAddress;
                $prefix = $prefix ? $prefix : $wgRC2UDPPrefix;
                $port = $port ? $port : $wgRC2UDPPort;
@@ -721,10 +780,80 @@
        }
 
        /**
+        * Return the JSON representation of the change used for the live feed.
+        */
+       public function getJSON( $feed ) {
+               global $wgCanonicalServer, $wgScript, $wgArticlePath;
+
+               $packet = array();
+
+               if( isset( $feed['channel'] ) ) {
+                       $packet['channel'] = $feed['channel'];
+               }
+
+               // Usually, RC ID is exposed only for patrolling purposes,
+               // but there is no real reason not to expose it in other cases,
+               // and I can see how this may be potentially useful for clients.
+               $packet['id'] = $this->mAttribs['rc_id'];
+               $packet['type'] = self::typeToString( 
$this->mAttribs['rc_type'] );
+
+               // While sufficiently complex feed readers should be able to 
fetch NS
+               // information from the API, full_title is provided for those 
who do not care,
+               // allowing simplier client implementation
+               $packet['namespace'] = $this->getTitle()->getNamespace();
+               $packet['title'] = $this->getTitle()->getDBkey();
+               $packet['full_title'] = $this->getTitle()->getPrefixedText();
+
+               $packet['comment'] = $this->mAttribs['rc_comment'];
+               $packet['timestamp'] = wfTimestamp( TS_ISO_8601, 
$this->mAttribs['rc_timestamp'] );
+               $packet['user'] = $this->mAttribs['rc_user_text'];
+               $packet['bot'] = (bool)$this->mAttribs['rc_bot'];
+
+               $type = $this->mAttribs['rc_type'];
+               if( $type == RC_EDIT || $type == RC_NEW ) {
+                       global $wgUseRCPatrol, $wgUseNPPatrol;
+
+                       $packet['minor'] = $this->mAttribs['rc_minor'];
+                       if( $wgUseRCPatrol || ($type == RC_NEW && 
$wgUseNPPatrol) ) {
+                               $packet['patrolled'] = 
$this->mAttribs['rc_patrolled'];
+                       }
+               }
+
+               switch( $type ) {
+                       case RC_EDIT:
+                               $packet['old_len'] = 
$this->mAttribs['rc_old_len'];
+                               $packet['new_len'] = 
$this->mAttribs['rc_new_len'];
+                               $packet['old_revision'] = 
$this->mAttribs['rc_last_oldid'];
+                               $packet['new_revision'] = 
$this->mAttribs['rc_this_oldid'];
+                               break;
+
+                       case RC_NEW:
+                               $packet['len'] = $this->mAttribs['rc_new_len'];
+                               $packet['revision'] = 
$this->mAttribs['rc_this_oldid'];
+                               break;
+
+                       case RC_LOG:
+                               $packet['log_type'] = 
$this->mAttribs['rc_log_type'];
+                               $packet['log_action'] = 
$this->mAttribs['rc_log_action'];
+                               if( $this->mAttribs['rc_params'] ) {
+                                       $packet['log_params'] = unserialize( 
$this->mAttribs['rc_params'] );
+                               }
+                               $packet['log_action_comment'] = 
$this->mExtra['actionComment'];
+                               break;
+               }
+
+               $packet['url_server'] = $wgCanonicalServer;
+               $packet['url_script_path'] = $wgScript;
+               $packet['url_article_path'] = $wgArticlePath;
+
+               return json_encode( $packet );
+       }
+
+       /**
         * @return string
         */
-       public function getIRCLine() {
-               global $wgUseRCPatrol, $wgUseNPPatrol, 
$wgRC2UDPInterwikiPrefix, $wgLocalInterwiki,
+       public function getIRCLine( $interwikiPrefix = false ) {
+               global $wgUseRCPatrol, $wgUseNPPatrol, $wgLocalInterwiki,
                        $wgCanonicalServer, $wgScript;
 
                if ( $this->mAttribs['rc_type'] == RC_LOG ) {
@@ -782,10 +911,10 @@
                        $flag .= ( $this->mAttribs['rc_type'] == RC_NEW ? "N" : 
"" ) . ( $this->mAttribs['rc_minor'] ? "M" : "" ) . ( $this->mAttribs['rc_bot'] 
? "B" : "" );
                }
 
-               if ( $wgRC2UDPInterwikiPrefix === true && $wgLocalInterwiki !== 
false ) {
+               if ( $interwikiPrefix === true && $wgLocalInterwiki !== false ) 
{
                        $prefix = $wgLocalInterwiki;
-               } elseif ( $wgRC2UDPInterwikiPrefix ) {
-                       $prefix = $wgRC2UDPInterwikiPrefix;
+               } elseif ( $interwikiPrefix ) {
+                       $prefix = $interwikiPrefix;
                } else {
                        $prefix = false;
                }
diff --git a/includes/api/ApiQueryRecentChanges.php 
b/includes/api/ApiQueryRecentChanges.php
index 6acca67..2c1c382 100644
--- a/includes/api/ApiQueryRecentChanges.php
+++ b/includes/api/ApiQueryRecentChanges.php
@@ -328,28 +328,7 @@
                $type = intval( $row->rc_type );
 
                /* Determine what kind of change this was. */
-               switch ( $type ) {
-                       case RC_EDIT:
-                               $vals['type'] = 'edit';
-                               break;
-                       case RC_NEW:
-                               $vals['type'] = 'new';
-                               break;
-                       case RC_MOVE:
-                               $vals['type'] = 'move';
-                               break;
-                       case RC_LOG:
-                               $vals['type'] = 'log';
-                               break;
-                       case RC_EXTERNAL:
-                               $vals['type'] = 'external';
-                               break;
-                       case RC_MOVE_OVER_REDIRECT:
-                               $vals['type'] = 'move over redirect';
-                               break;
-                       default:
-                               $vals['type'] = $type;
-               }
+               $vals['type'] = RecentChange::typeToString( $type );
 
                /* Create a new entry in the result for the title. */
                if ( $this->fld_title ) {

-- 
To view, visit https://gerrit.wikimedia.org/r/52922
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I270bde418a82985c94372ac4579100435b6ee026
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Victor Vasiliev <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to