Parent5446 has uploaded a new change for review.

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


Change subject: Added API action=changetags for ChangeTags
......................................................................

Added API action=changetags for ChangeTags

Added new API module for action=changetags that allows users
to view the ChangeTags associated with a revision. It also
allows users with the new 'changetags' permission to add tags
via the API. Only tags in $wgApiChangeTags are allowed to be
added via the API.

Change-Id: I8ace1d47290664d39973f541be71b933e454b9c9
---
M RELEASE-NOTES-1.22
M includes/AutoLoader.php
M includes/ChangeTags.php
M includes/DefaultSettings.php
A includes/api/ApiChangeTags.php
M includes/api/ApiMain.php
6 files changed, 258 insertions(+), 35 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/50/64650/1

diff --git a/RELEASE-NOTES-1.22 b/RELEASE-NOTES-1.22
index cd7971b..7bb122f 100644
--- a/RELEASE-NOTES-1.22
+++ b/RELEASE-NOTES-1.22
@@ -80,6 +80,10 @@
   which can be cascading (previously 'sysop' was hard-coded as the only one).
 * XHTML5 support has been improved. If you set $wgMimeType = 
'application/xhtml+xml'
   MediaWiki will try outputting markup acording to XHTML5 rules.
+* Revision tags (as displayed on Special:Tags) can now be added to changes via 
the
+  API rather than just on the server-side. $wgApiChangeTags contains the tags 
that
+  are allowed to be changed, and the 'changetags' permission allows users to 
add
+  those tags.
 
 === Bug fixes in 1.22 ===
 * Disable Special:PasswordReset when $wgEnableEmail is false. Previously one
diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php
index 26d5b94..dbe79a1 100644
--- a/includes/AutoLoader.php
+++ b/includes/AutoLoader.php
@@ -332,6 +332,7 @@
        # includes/api
        'ApiBase' => 'includes/api/ApiBase.php',
        'ApiBlock' => 'includes/api/ApiBlock.php',
+       'ApiChangeTags' => 'includes/api/ApiChangeTags.php',
        'ApiComparePages' => 'includes/api/ApiComparePages.php',
        'ApiCreateAccount' => 'includes/api/ApiCreateAccount.php',
        'ApiDelete' => 'includes/api/ApiDelete.php',
diff --git a/includes/ChangeTags.php b/includes/ChangeTags.php
index 5478396..90f7a40 100644
--- a/includes/ChangeTags.php
+++ b/includes/ChangeTags.php
@@ -74,50 +74,61 @@
        }
 
        /**
+        * Get tags to a change given its rc_id, rev_id and/or log_id
+        *
+        * @param int $rc_id Recent changes ID to get tags for
+        * @param int $rev_id Revision ID to get tags for
+        * @param int $log_id Log entry ID to get tags for
+        *
+        * @exception MWException when $rc_id, $rev_id and $log_id are all null
+        * @return array Mapping of tag name to the its string parameter
+        */
+       static function getTags( $rc_id = null, $rev_id = null, $log_id = null, 
$fromMaster = false ) {
+               self::fetchTagIds( $rc_id, $rev_id, $log_id );
+
+               $res = wfGetDB( $fromMaster ? DB_MASTER : DB_SLAVE )->select(
+                       'change_tag',
+                       array( 'ct_tag', 'ct_params' ),
+                       array_filter( array(
+                               'ct_rc_id' => $rc_id,
+                               'ct_rev_id' => $rev_id,
+                               'ct_log_id' => $log_id
+                       ) ),
+                       __METHOD__
+               );
+
+               $tags = array();
+               foreach ( $res as $row ) {
+                       $tags[$row->ct_tag] = $row->ct_params;
+               }
+
+               return $tags;
+       }
+
+       /**
         * Add tags to a change given its rc_id, rev_id and/or log_id
         *
         * @param string|array $tags Tags to add to the change
-        * @param $rc_id int: rc_id of the change to add the tags to
-        * @param $rev_id int: rev_id of the change to add the tags to
-        * @param $log_id int: log_id of the change to add the tags to
+        * @param int $rc_id rc_id of the change to add the tags to
+        * @param int $rev_id rev_id of the change to add the tags to
+        * @param int $log_id log_id of the change to add the tags to
         * @param string $params params to put in the ct_params field of table 
'change_tag'
         *
-        * @throws MWException
-        * @return bool: false if no changes are made, otherwise true
-        *
         * @exception MWException when $rc_id, $rev_id and $log_id are all null
+        * @return bool: false if no changes are made, otherwise true
         */
        static function addTags( $tags, $rc_id = null, $rev_id = null, $log_id 
= null, $params = null ) {
                if ( !is_array( $tags ) ) {
                        $tags = array( $tags );
                }
-
                $tags = array_filter( $tags ); // Make sure we're submitting 
all tags...
 
-               if ( !$rc_id && !$rev_id && !$log_id ) {
-                       throw new MWException( "At least one of: RCID, revision 
ID, and log ID MUST be specified when adding a tag to a change!" );
-               }
-
-               $dbr = wfGetDB( DB_SLAVE );
-
-               // Might as well look for rcids and so on.
-               if ( !$rc_id ) {
-                       $dbr = wfGetDB( DB_MASTER ); // Info might be out of 
date, somewhat fractionally, on slave.
-                       if ( $log_id ) {
-                               $rc_id = $dbr->selectField( 'recentchanges', 
'rc_id', array( 'rc_logid' => $log_id ), __METHOD__ );
-                       } elseif ( $rev_id ) {
-                               $rc_id = $dbr->selectField( 'recentchanges', 
'rc_id', array( 'rc_this_oldid' => $rev_id ), __METHOD__ );
-                       }
-               } elseif ( !$log_id && !$rev_id ) {
-                       $dbr = wfGetDB( DB_MASTER ); // Info might be out of 
date, somewhat fractionally, on slave.
-                       $log_id = $dbr->selectField( 'recentchanges', 
'rc_logid', array( 'rc_id' => $rc_id ), __METHOD__ );
-                       $rev_id = $dbr->selectField( 'recentchanges', 
'rc_this_oldid', array( 'rc_id' => $rc_id ), __METHOD__ );
-               }
+               self::fetchTagIds( $rc_id, $rev_id, $log_id );
 
                $tsConds = array_filter( array( 'ts_rc_id' => $rc_id, 
'ts_rev_id' => $rev_id, 'ts_log_id' => $log_id ) );
 
                ## Update the summary row.
-               $prevTags = $dbr->selectField( 'tag_summary', 'ts_tags', 
$tsConds, __METHOD__ );
+               $prevTags = wfGetDB( DB_SLAVE )->selectField( 'tag_summary', 
'ts_tags', $tsConds, __METHOD__ );
                $prevTags = $prevTags ? $prevTags : '';
                $prevTags = array_filter( explode( ',', $prevTags ) );
                $newTags = array_unique( array_merge( $prevTags, $tags ) );
@@ -128,14 +139,6 @@
                        // No change.
                        return false;
                }
-
-               $dbw = wfGetDB( DB_MASTER );
-               $dbw->replace(
-                       'tag_summary',
-                       array( 'ts_rev_id', 'ts_rc_id', 'ts_log_id' ),
-                       array_filter( array_merge( $tsConds, array( 'ts_tags' 
=> implode( ',', $newTags ) ) ) ),
-                       __METHOD__
-               );
 
                // Insert the tags rows.
                $tagsRows = array();
@@ -151,12 +154,61 @@
                        );
                }
 
+               $dbw = wfGetDB( DB_MASTER );
+               $dbw->begin();
+               $dbw->replace(
+                       'tag_summary',
+                       array( 'ts_rev_id', 'ts_rc_id', 'ts_log_id' ),
+                       array_filter( array_merge( $tsConds, array( 'ts_tags' 
=> implode( ',', $newTags ) ) ) ),
+                       __METHOD__
+               );
                $dbw->insert( 'change_tag', $tagsRows, __METHOD__, array( 
'IGNORE' ) );
+               $dbw->commit();
 
                return true;
        }
 
        /**
+        * Given one or more of a rc/rev/log ID, fetch the remaining IDs for 
the change tag
+        * associated with the given ID.
+        *
+        * @param int &$rc_id Recent changes ID
+        * @param int &$rev_id Revision ID
+        * @param int &$log_id Log entry ID
+        * @param bool $force Force checking the database even if all three IDs 
are provided
+        *
+        * @return bool True if the IDs given matched something, false if 
invalid
+        */
+       static function fetchTagIds( &$rc_id = null, &$rev_id = null, &$log_id 
= null, $force = false ) {
+               if ( !$rc_id && !$rev_id && !$log_id ) {
+                       throw new MWException( "At least one of: RCID, revision 
ID, and log ID MUST be specified when adding a tag to a change!" );
+               } elseif ( !$force && $rc_id && $rev_id && $log_id ) {
+                       // If we already have all three and no force, skip the 
database query.
+                       return true;
+               }
+
+               // Info might be out of date, somewhat fractionally, on slave.
+               $res = wfGetDB( DB_MASTER )->selectRow(
+                       'recentchanges',
+                       array( 'rc_id', 'rc_logid', 'rc_this_oldid' ),
+                       array_filter( array(
+                               'rc_id' => $rc_id,
+                               'rc_this_oldid' => $rev_id,
+                               'rc_logid' => $log_id
+                       ) ),
+                       __METHOD__
+               );
+
+               if ( $res ) {
+                       $rc_id = $res->rc_id;
+                       $rev_id = $res->rc_this_oldid;
+                       $log_id = $res->rc_logid;
+               }
+
+               return (bool)$res;
+       }
+
+       /**
         * Applies all tags-related changes to a query.
         * Handles selecting tags, and filtering.
         * Needs $tables to be set up properly, so we can figure out which join 
conditions to use.
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 819e9a3..3194c2a 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -3899,6 +3899,7 @@
 $wgGroupPermissions['bot']['suppressredirect'] = true;
 $wgGroupPermissions['bot']['apihighlimits'] = true;
 $wgGroupPermissions['bot']['writeapi'] = true;
+$wgGroupPermissions['bot']['changetags'] = true;
 #$wgGroupPermissions['bot']['editprotected'] = true; // can edit all protected 
pages without cascade protection enabled
 
 // Most extra permission abilities go to this group
@@ -5996,6 +5997,14 @@
 $wgAPIRequestLog = false;
 
 /**
+ * Array of ChangeTags that can be added to changes via the API. All other
+ * ChangeTags can only be added on the server side by extensions.
+ * @see ChangeTags
+ * @since 1.22
+ */
+$wgApiChangeTags = array();
+
+/**
  * Set the timeout for the API help text cache. If set to 0, caching disabled
  */
 $wgAPICacheHelpTimeout = 60 * 60;
diff --git a/includes/api/ApiChangeTags.php b/includes/api/ApiChangeTags.php
new file mode 100644
index 0000000..83c42b3
--- /dev/null
+++ b/includes/api/ApiChangeTags.php
@@ -0,0 +1,156 @@
+<?php
+/**
+ * Recent changes tagging.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * API module that allows users to view/add ChangeTags for a specific
+ * revision/recent change/log entry.
+ *
+ * @see ChangeTags
+ * @since 1.22
+ * @ingroup API
+ */
+class ApiChangeTags extends ApiBase {
+       function execute() {
+               $params = $this->extractRequestParams();
+               $this->requireAtLeastOneParameter( $params, 'rcid', 'revid', 
'logid' );
+
+               // Try to get a match for each parameter.
+               $valid = ChangeTags::fetchTagIds( $params['rcid'], 
$params['revid'], $params['logid'], true );
+               if ( !$valid ) {
+                       $this->dieUsage( 'No valid revid, rcid, or logid was 
supplied.', 'invalid' );
+               }
+
+               // Get the title for permission checks.
+               $title = Revision::newFromId( $params['revid'] )->getTitle();
+
+               $wasPosted = $this->getRequest()->wasPosted();
+
+               if ( $wasPosted ) {
+                       // Need the changetags permission to change tags
+                       $permission = 'changetags';
+               } else {
+                       // Otherwise, anybody who can read the page can see the 
tags in the history anyway
+                       $permission = 'read';
+               }
+
+               $errors = $title->getUserPermissionsErrors( $permission, 
$this->getUser() );
+               if ( $errors ) {
+                       $this->dieUsageMsg( $errors[0] );
+               }
+
+               // Actually get/change the tags.
+               $currentTags = array();
+               if ( $wasPosted ) {
+                       ChangeTags::addTags( $params['tags'], $params['rcid'], 
$params['revid'], $params['logid'], $currentTags );
+               }
+
+               $currentTags = ChangeTags::getTags( $params['rcid'], 
$params['revid'], $params['logid'], $wasPosted );
+
+               $info = array(
+                       'rcid' => $params['rcid'],
+                       'revid' => $params['revid'],
+                       'logid' => $params['logid'],
+               );
+               foreach ( $currentTags as $tag => $params ) {
+                       $info[] = array( 'name' => $tag, '*' => $params );
+               }
+
+               $result = $this->getResult();
+               $result->setIndexedTagName( $info, 'tag' );
+               $this->getResult()->addValue( null, $this->getModuleName(), 
$info );
+       }
+
+       function getDescription() {
+               return 'Add change tags to a certain revision, recent change, 
or log entry.';
+       }
+
+       function getAllowedParams() {
+               global $wgApiChangeTags;
+
+               return array(
+                       'revid' => array(
+                               self::PARAM_TYPE => 'integer',
+                       ),
+                       'rcid' => array(
+                               self::PARAM_TYPE => 'integer',
+                       ),
+                       'logid' => array(
+                               self::PARAM_TYPE => 'integer',
+                       ),
+                       'tags' => array(
+                               self::PARAM_TYPE => array_intersect(
+                                       ChangeTags::listDefinedTags(),
+                                       $wgApiChangeTags
+                               ),
+                               self::PARAM_ISMULTI => true
+                       )
+               );
+       }
+
+       function getParamDescription() {
+               return array(
+                       'revid' => 'ID of the revision to add tags to',
+                       'rcid' => 'ID of the recent change to add tags to',
+                       'logid' => 'ID of the log entry to add tags to',
+                       'tags' => 'Tags to add to the specified object',
+               );
+       }
+
+       function getResultProperties() {
+               return array( '' => array(
+                       'revid' => array(
+                               self::PROP_TYPE => 'integer',
+                               self::PROP_NULLABLE => true,
+                       ),
+                       'rcid' => array(
+                               self::PROP_TYPE => 'integer',
+                               self::PROP_NULLABLE => true,
+                       ),
+                       'logid' => array(
+                               self::PROP_TYPE => 'integer',
+                               self::PROP_NULLABLE => true,
+                       ),
+                       'tags' => array(
+                               self::PROP_TYPE => 'string',
+                               self::PROP_LIST => true,
+                       )
+               ) );
+       }
+
+       function getPossibleErrors() {
+               return array_merge(
+                       parent::getPossibleErrors(),
+                       self::getRequireAtLeastOneParameterErrorMessages( 
'revid', 'rcid', 'logid' )
+               );
+       }
+
+       function getExamples() {
+               return array(
+                       'api.php?action=changetags&rcid=105',
+                       'api.php?action=changetags&rcid=107&logid=106&revid=32'
+               );
+       }
+
+       function getHelpUrls() {
+               return 'https://www.mediawiki.org/wiki/API:ChangeTags';
+       }
+}
\ No newline at end of file
diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php
index 5ddb3ab..c9ec787 100644
--- a/includes/api/ApiMain.php
+++ b/includes/api/ApiMain.php
@@ -84,6 +84,7 @@
                'userrights' => 'ApiUserrights',
                'options' => 'ApiOptions',
                'imagerotate' => 'ApiImageRotate',
+               'changetags' => 'ApiChangeTags'
        );
 
        /**

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

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

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

Reply via email to