jenkins-bot has submitted this change and it was merged.

Change subject: Implements prop=listmembership
......................................................................


Implements prop=listmembership

Usage examples:

Watchlist (lsmid=0 or missing)
* 
http://localhost:8080/w/api.php?action=query&prop=listmembership&titles=Main_Page&lsmid=0

Specific list, e.g. #7
* 
http://localhost:8080/w/api.php?action=query&prop=listmembership&titles=Main_Page&lsmid=7

Obviously because this is a prop, generators can be used:
* 
http://localhost:8080/w/api.php?action=query&prop=listmembership&generator=allpages&lsmid=0

Bug: T95516
Change-Id: I90b6df0c7a9d69460921e9410284c312b3d09d7b
---
M Gather.php
M i18n/en.json
M i18n/qqq.json
A includes/api/ApiMixinListAccess.php
A includes/api/ApiQueryListMembership.php
M includes/api/ApiQueryListPages.php
M tests/phpunit/api/GatherTests.php
7 files changed, 357 insertions(+), 66 deletions(-)

Approvals:
  Yurik: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/Gather.php b/Gather.php
index 28eb272..3eff5f6 100644
--- a/Gather.php
+++ b/Gather.php
@@ -67,8 +67,10 @@
        'Gather\SpecialGatherLists' => 'specials/SpecialGatherLists',
        'Gather\SpecialGatherEditFeed' => 'specials/SpecialGatherEditFeed',
 
+       'Gather\api\ApiMixinListAccess' => 'api/ApiMixinListAccess',
        'Gather\api\ApiEditList' => 'api/ApiEditList',
        'Gather\api\ApiQueryLists' => 'api/ApiQueryLists',
+       'Gather\api\ApiQueryListMembership' => 'api/ApiQueryListMembership',
        'Gather\api\ApiQueryListPages' => 'api/ApiQueryListPages',
 
 );
@@ -104,6 +106,7 @@
 // Api
 $wgAPIModules['editlist'] = 'Gather\api\ApiEditList';
 $wgAPIListModules['lists'] = 'Gather\api\ApiQueryLists';
+$wgAPIPropModules['listmembership'] = 'Gather\api\ApiQueryListMembership';
 $wgAPIListModules['listpages'] = 'Gather\api\ApiQueryListPages';
 
 // Configuration
diff --git a/i18n/en.json b/i18n/en.json
index d98088b..165a5d5 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -116,5 +116,10 @@
        "gather-collection-more": "View more pages in this collection",
        "gather-add-to-another": "Show my other collections",
        "gather-watchstar-button-label": "Add to collection",
-       "gather-menu-guider": "Tap on the menu icon to take a look at your new 
collection."
+       "gather-menu-guider": "Tap on the menu icon to take a look at your new 
collection.",
+       "gather-api-help-param-listid": "List id; omit or set to 0 to use the 
watchlist.",
+       "gather-api-help-param-listowner": "User ID of the list owner. Only 
makes sense for watchlists.",
+       "gather-api-help-param-listtoken": "Watchlist token (see watchlist 
API); required when looking at someone else's watchlist.",
+       "apihelp-query+listmembership-description": "Returns which of a set of 
pages are in a given list.",
+       "apihelp-query+listmembership-example-1": "Check whether \"Page\" is on 
the watchlist."
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 4e888b0..4bf22cc 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -118,5 +118,10 @@
        "gather-collection-more": "Label for link at bottom of Gather 
collection when there are more than 50 items.",
        "gather-add-to-another": "Label for button at bottom of collection 
overlay for when you have more collections that you could potentially add to.",
        "gather-watchstar-button-label": "A label for the button to add to a 
collection.",
-       "gather-menu-guider": "Message that shows up in an overlay pointing at 
the menu button."
+       "gather-menu-guider": "Message that shows up in an overlay pointing at 
the menu button.",
+       "gather-api-help-param-listid": 
"{{doc-apihelp-param|lsm|id|listmembership|query+listmembership}}",
+       "gather-api-help-param-listowner": 
"{{doc-apihelp-param|lsm|owner|listmembership|query+listmembership}}",
+       "gather-api-help-param-listtoken": 
"{{doc-apihelp-param|lsm|token|listmembership|query+listmembership}}",
+       "apihelp-query+listmembership-description": 
"{{doc-apihelp-description|lsm|listmembership|query+listmembership}}",
+       "apihelp-query+listmembership-example-1": 
"{{doc-apihelp-example|lsm|listmembership|query+listmembership}}"
 }
diff --git a/includes/api/ApiMixinListAccess.php 
b/includes/api/ApiMixinListAccess.php
new file mode 100644
index 0000000..ddea2dc
--- /dev/null
+++ b/includes/api/ApiMixinListAccess.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * Copyright © 2015 Yuri Astrakhan "<Firstname><Lastname>@gmail.com",
+ *
+ * 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
+ */
+
+namespace Gather\api;
+
+use ApiBase;
+use DatabaseBase;
+
+/**
+ * Shared code for List's API
+ *
+ * @ingroup API
+ */
+class ApiMixinListAccess {
+
+       /**
+        * Get parameters used to identify a list with ownership
+        * @return array
+        */
+       public static function getListAccessParams() {
+               return array(
+                       'id' => array(
+                               ApiBase::PARAM_HELP_MSG => 
'gather-api-help-param-listid',
+                               ApiBase::PARAM_DFLT => 0,
+                               ApiBase::PARAM_TYPE => 'integer',
+                               ApiBase::PARAM_MIN => 0,
+                       ),
+                       'owner' => array(
+                               ApiBase::PARAM_HELP_MSG => 
'gather-api-help-param-listowner',
+                               ApiBase::PARAM_TYPE => 'user',
+                       ),
+                       'token' => array(
+                               ApiBase::PARAM_HELP_MSG => 
'gather-api-help-param-listtoken',
+                               ApiBase::PARAM_TYPE => 'string',
+                       ),
+               );
+       }
+
+       /**
+        * Ensure that current params make sense, specify an existing list, and 
the requesting user has
+        * access to it. Die if that's not the case.
+        * @param DatabaseBase $db
+        * @param ApiBase $module
+        * @param array $params module parameters
+        * @param bool $isWatchlist Will be set to true if the requested list 
is a watchlist
+        * @param int $ownerId Will be set to the user ID of the list's owner
+        * @throws \UsageException In case access is not allowed
+        */
+       public static function checkListAccess(
+               DatabaseBase $db, ApiBase $module, array $params, 
&$isWatchlist, &$ownerId
+       ) {
+               if ( is_null( $params['owner'] ) !== is_null( $params['token'] 
) ) {
+                       $p = $module->getModulePrefix();
+                       $module->dieUsage( "Both {$p}owner and {$p}token must 
be given or missing",
+                               'invalidparammix' );
+               }
+
+               if ( !$params['id'] ) {
+                       // If collection id is not given (or equals to 0), this 
is a watchlist access;
+                       // ApiBase::getWatchlistUser does all the necessary 
checks
+                       $isWatchlist = true;
+                       $ownerId = $module->getWatchlistUser( $params 
)->getId();
+                       return;
+               }
+
+               // Id was given, this could be public or private list, legacy 
watchlist or regular
+               // Allow access to any public list/watchlist, and to private 
with proper owner/self
+               $listRow = $db->selectRow( 'gather_list',
+                       array( 'gl_label', 'gl_user', 'gl_perm' ),
+                       array( 'gl_id' => $params['id'] ),
+                       __METHOD__ );
+               if ( $listRow === false ) {
+                       $module->dieUsage( 'List does not exist', 'badid' );
+               }
+
+               $listRow = ApiEditList::normalizeRow( $listRow );
+               if ( $params['owner'] !== null ) {
+                       // Caller supplied token: treat them as trusted, 
someone who could see even private
+                       // At the same time, owner param must match list's owner
+                       // TODO: if we allow non-matching owner, we could treat 
it as public-only,
+                       // but that might be unexpected behavior
+                       $user = $module->getWatchlistUser( $params );
+                       if ( $listRow->gl_user !== $user->getId() ) {
+                               $module->dieUsage( 'The owner supplied does not 
match the list\'s owner',
+                                       'permissiondenied' );
+                       }
+                       $showPrivate = true;
+               } else {
+                       $user = $module->getUser();
+                       $showPrivate =
+                               $user->isLoggedIn() && $listRow->gl_user === 
$user->getId() &&
+                               $user->isAllowed( 'viewmywatchlist' );
+               }
+
+               // Check if this is a public list (if required)
+               if ( !$showPrivate && $listRow->gl_perm !== 
ApiEditList::PERM_PUBLIC ) {
+                       $module->dieUsage( 'You have no rights to see this 
list', 'badid' );
+               }
+
+               // If true, this is actually a watchlist, and it is either 
public or belongs to current user
+               $isWatchlist = $listRow->gl_label === '';
+               $ownerId = $listRow->gl_user;
+       }
+}
diff --git a/includes/api/ApiQueryListMembership.php 
b/includes/api/ApiQueryListMembership.php
new file mode 100644
index 0000000..f26fcd8
--- /dev/null
+++ b/includes/api/ApiQueryListMembership.php
@@ -0,0 +1,137 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Yuri Astrakhan "<Firstname><Lastname>@gmail.com",
+ *
+ * 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
+ */
+
+namespace Gather\api;
+
+use ApiQueryBase;
+use ApiQuery;
+use LinkBatch;
+use ApiBase;
+
+/**
+ * A query prop module to show if pages belong to a specific list
+ *
+ * @ingroup API
+ */
+class ApiQueryListMembership extends ApiQueryBase {
+
+       public function __construct( ApiQuery $query, $moduleName ) {
+               parent::__construct( $query, $moduleName, 'lsm' );
+       }
+
+       public function execute() {
+               $titles = $this->getPageSet()->getGoodAndMissingTitles();
+               $titleLookup = 
$this->getPageSet()->getGoodAndMissingTitlesByNamespace();
+
+               if ( !count( $titles ) ) {
+                       # Nothing to do
+                       return;
+               }
+
+               $params = $this->extractRequestParams();
+               $db = $this->getDB();
+
+               // watchlist and gather_list_item tables are very similar, and 
have one identifying value -
+               // UserID for watchlists, and ListID for lists. CheckListAccess 
will tell us which table we
+               // should use. If userId is returned, use watchlist, otherwise 
the $params['id'] is valid,
+               // and should be used for the gather_list_item.
+               ApiMixinListAccess::checkListAccess( $db, $this, $params, 
$isWatchlist, $ownerId );
+
+               if ( $isWatchlist ) {
+                       $prefix = 'wl';
+                       $db = $this->selectNamedDB( 'watchlist', DB_SLAVE, 
'watchlist' );
+                       $this->addTables( 'watchlist' );
+                       $this->addWhereFld( 'wl_user', $ownerId );
+               } else {
+                       $prefix = 'gli';
+                       $this->addTables( 'gather_list_item' );
+                       $this->addWhereFld( 'gli_gl_id', $params['id'] );
+               }
+
+               $this->addFields( array( 'ns' => "{$prefix}_namespace", 'title' 
=> "{$prefix}_title" ) );
+
+               $lb = new LinkBatch( $titles );
+               $this->addWhere( $lb->constructSet( $prefix, $db ) );
+
+               if ( $params['continue'] !== null ) {
+                       $cont = explode( '|', $params['continue'] );
+                       $this->dieContinueUsageIf( count( $cont ) != 2 );
+                       $contNs = intval( $cont[0] );
+                       $this->dieContinueUsageIf( strval( $contNs ) !== 
$cont[0] );
+                       $contTitle = $db->addQuotes( $cont[1] );
+                       $this->addWhere( "{$prefix}_namespace > $contNs OR " .
+                                                        "({$prefix}_namespace 
= $contNs AND " . "{$prefix}_title >= $contTitle)" );
+               }
+
+               // Don't ORDER BY namespace if it's constant in the WHERE clause
+               if ( count( $titleLookup ) === 1 ) {
+                       $this->addOption( 'ORDER BY', "{$prefix}_title" );
+               } else {
+                       $this->addOption( 'ORDER BY', array( 
"{$prefix}_namespace", "{$prefix}_title" ) );
+               }
+
+               // NOTE: We never set listmembership=false because we don't 
really know which ones are not
+               // in the database. If we ran out of memory halfway and need to 
continue, next time we will
+               // skip those already done, so even though DB contains rows, we 
skipped them and gotten
+               // the next batch. In other words, the pages that at the end of 
this module do not have
+               // listmembership=true might still be true, but they were 
reported in the previous API call.
+
+               $result = $this->getResult();
+               foreach ( $this->select( __METHOD__ ) as $row ) {
+                       $ns = intval( $row->ns );
+                       if ( !isset( $titleLookup[$ns][$row->title] ) ) {
+                               wfDebug( __METHOD__ . " Unexpected DB row 
{$row->ns}:{$row->title}\n" );
+                               continue;
+                       }
+                       $fit = $result->addValue( array( 'query', 'pages', 
$titleLookup[$ns][$row->title] ),
+                               'listmembership', true );
+                       if ( !$fit ) {
+                               $this->setContinueEnumParameter( 'continue', 
$row->ns . '|' . $row->title );
+                               break;
+                       }
+               }
+       }
+
+       public function getCacheMode( $params ) {
+               return 'anon-public-user-private';
+       }
+
+       public function getAllowedParams() {
+               return array_merge( ApiMixinListAccess::getListAccessParams(), 
array(
+                       'continue' => array(
+                               ApiBase::PARAM_HELP_MSG => 
'api-help-param-continue',
+                       ),
+               ) );
+       }
+
+       protected function getExamplesMessages() {
+               return array(
+                       'action=query&prop=listmembership&titles=Page&lsmid=0'
+                       => 'apihelp-query+listmembership-example-1',
+               );
+       }
+
+       public function getHelpUrls() {
+               return '//www.mediawiki.org/wiki/Extension:Gather';
+       }
+}
diff --git a/includes/api/ApiQueryListPages.php 
b/includes/api/ApiQueryListPages.php
index 15ce75e..539afeb 100644
--- a/includes/api/ApiQueryListPages.php
+++ b/includes/api/ApiQueryListPages.php
@@ -62,60 +62,15 @@
         * @throws \UsageException
         */
        private function run( $resultPageSet = null ) {
-
                $params = $this->extractRequestParams();
-               $p = $this->getModulePrefix();
-
-               $useOwner = $params['owner'] !== null;
-               if ( $useOwner !== ( $params['token'] !== null ) ) {
-                       $this->dieUsage( "Both {$p}owner and {$p}token must be 
given or missing",
-                               'invalidparammix' );
-               }
-
                $isGenerator = $resultPageSet !== null;
 
-               if ( !$params['id'] ) {
-                       // If id is not given (or equals to 0), permissions the 
same as watchlistraw access
-                       $user = $this->getWatchlistUser( $params );
-                       $titles = $this->queryLegacyWatchlist( $params, 
$isGenerator, $user->getId() );
+               ApiMixinListAccess::checkListAccess( $this->getDB(), $this, 
$params, $isWatchlist, $ownerId );
+
+               if ( $isWatchlist ) {
+                       $titles = $this->queryLegacyWatchlist( $params, 
$isGenerator, $ownerId );
                } else {
-                       // Id was given, this could be public or private list, 
legacy watchlist or regular
-                       // Allow access to any public list/watchlist, and to 
private with proper owner/self
-                       $db = $this->getDB();
-                       $listRow = ApiEditList::normalizeRow( $db->selectRow( 
'gather_list',
-                               array( 'gl_label', 'gl_user', 'gl_perm' ),
-                               array( 'gl_id' => $params['id'] ), __METHOD__ ) 
);
-                       if ( $listRow === false ) {
-                               $this->dieUsage( "List does not exist", 'badid' 
);
-                       }
-                       if ( $useOwner ) {
-                               // Caller supplied token: treat them as 
trusted, someone who could see even private
-                               // At the same time, owner param must match 
list's owner
-                               // TODO: if we allow non-matching owner, we 
could treat it as public-only,
-                               // but that might be unexpected behavior
-                               $user = $this->getWatchlistUser( $params );
-                               if ( $listRow->gl_user !== $user->getId() ) {
-                                       $this->dieUsage( 'The owner supplied 
does not match the list\'s owner',
-                                               'permissiondenied' );
-                               }
-                               $showPrivate = true;
-                       } else {
-                               $user = $this->getUser();
-                               $showPrivate = $user->isLoggedIn() && 
$listRow->gl_user === $user->getId()
-                                       && $user->isAllowed( 'viewmywatchlist' 
);
-                       }
-
-                       // Check if this is a public list (if required)
-                       if ( !$showPrivate && $listRow->gl_perm !== 
ApiEditList::PERM_PUBLIC ) {
-                               $this->dieUsage( "You have no rights to see 
this list", 'badid' );
-                       }
-
-                       if ( $listRow->gl_label === '' ) {
-                               // This is actually a watchlist, and it is 
either public or belongs to current user
-                               $titles = $this->queryLegacyWatchlist( $params, 
$isGenerator, $listRow->gl_user );
-                       } else {
-                               $titles = $this->queryListItems( $params, 
$isGenerator );
-                       }
+                       $titles = $this->queryListItems( $params, $isGenerator 
);
                }
                if ( !$isGenerator ) {
                        $this->getResult()->addIndexedTagName( 
$this->modulePath, 'wr' );
@@ -244,14 +199,9 @@
        }
 
        public function getAllowedParams() {
-               return array(
+               return array_merge( ApiMixinListAccess::getListAccessParams(), 
array(
                        'continue' => array(
                                ApiBase::PARAM_HELP_MSG => 
'api-help-param-continue',
-                       ),
-                       'id' => array(
-                               ApiBase::PARAM_DFLT => 0,
-                               ApiBase::PARAM_TYPE => 'integer',
-                               ApiBase::PARAM_MIN => 0,
                        ),
                        'namespace' => array(
                                ApiBase::PARAM_ISMULTI => true,
@@ -264,12 +214,6 @@
                                ApiBase::PARAM_MAX => ApiBase::LIMIT_BIG1,
                                ApiBase::PARAM_MAX2 => ApiBase::LIMIT_BIG2,
                        ),
-                       'owner' => array(
-                               ApiBase::PARAM_TYPE => 'user',
-                       ),
-                       'token' => array(
-                               ApiBase::PARAM_TYPE => 'string',
-                       ),
                        'dir' => array(
                                ApiBase::PARAM_DFLT => 'ascending',
                                ApiBase::PARAM_TYPE => array(
@@ -278,7 +222,7 @@
                                ),
                                ApiBase::PARAM_HELP_MSG => 
'api-help-param-direction',
                        ),
-               );
+               ) );
        }
 
        protected function getExamplesMessages() {
diff --git a/tests/phpunit/api/GatherTests.php 
b/tests/phpunit/api/GatherTests.php
index 1d1db40..4d31495 100644
--- a/tests/phpunit/api/GatherTests.php
+++ b/tests/phpunit/api/GatherTests.php
@@ -175,7 +175,7 @@
                foreach ( array( $usr, $usr2 ) as $user ) {
                        $this->assertLists( 'ed-a0', $user, '{}',
                                '[{"id":0, "watchlist":true, 
"label":"Watchlist"}]' );
-                       $this->assertPages( 'ed-a1', $user, null, array(), 
array() );
+                       $this->assertPages( 'ed-a1', $user, null, array() );
                }
 
                $this->badUsePage( 'ed-a2', $usr, '"lspid": 9999999' );
@@ -239,10 +239,12 @@
 
                $expListsW2->count = 1;
                $expPagesW = array( $pageW, $pageTW );
+               $expPagesIn = array( 'Gather-ListW' );
 
                $this->assertPages( 'ed-c2', $usr, null, $expPagesW );
                $this->assertPages( 'ed-c3', $usr, 0, $expPagesW );
                $this->assertLists( 'ed-c4', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertIsIn( 'ed-c5', $usr, 0, $expPagesIn );
 
                //
                // Create Watchlist row
@@ -256,10 +258,15 @@
                $this->assertPages( 'ed-d2', $usr, 0, $expPagesW );
                $this->assertPages( 'ed-d3', $usr, $id0, $expPagesW );
                $this->assertLists( 'ed-d4', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertIsIn( 'ed-d4a', $usr, 0, $expPagesIn );
                $this->assertLists( 'ed-d5', $usr, $id0, $expListsW, 
$expListsW2 );
+               $this->assertIsIn( 'ed-d5a', $usr, $id0, $expPagesIn );
                $this->assertLists( 'ed-d6', $usrA, $id0, null );
+               $this->assertIsIn( 'ed-d6a', $usrA, $id0, null );
                $this->assertLists( 'ed-d7', $usr2, $id0, null );
+               $this->assertIsIn( 'ed-d7a', $usr2, $id0, null );
                $this->assertLists( 'ed-d7a', $usrS, $id0, null );
+               $this->assertIsIn( 'ed-d7a', $usrS, $id0, null );
                $this->badUsePage( 'ed-d8', $usrA, '"lspid": ' . $id0 );
                $this->badUsePage( 'ed-d9', $usr2, '"lspid": ' . $id0 );
                $this->badUsePage( 'ed-d10', $usrS, '"lspid": ' . $id0 );
@@ -301,12 +308,15 @@
 
                $expListsW2->count = 2;
                $expPagesW = array( $pageW, $pageWA, $pageTW, $pageTWA );
+               $expPagesIn = array( 'Gather-ListW', 'Gather-ListWA' );
 
                $this->assertPages( 'ed-e2', $usr, null, $expPagesW );
                $this->assertPages( 'ed-e3', $usr, 0, $expPagesW );
                $this->assertPages( 'ed-e4', $usr, $id0, $expPagesW );
                $this->assertLists( 'ed-e5', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertIsIn( 'ed-e5a', $usr, 0, $expPagesIn );
                $this->assertLists( 'ed-e6', $usr, $id0, $expListsW, 
$expListsW2 );
+               $this->assertIsIn( 'ed-e6a', $usr, $id0, $expPagesIn );
 
                //
                // Add Gather-ListWAB to the created watchlist with ID=0 and 
description change
@@ -320,12 +330,15 @@
                $expListsW2->count = 3;
                $expListsW2->description = 'y';
                $expPagesW = array( $pageW, $pageWA, $pageWAB, $pageTW, 
$pageTWA, $pageTWAB );
+               $expPagesIn = array( 'Gather-ListW', 'Gather-ListWA', 
'Gather-ListWAB' );
 
                $this->assertPages( 'ed-f2', $usr, null, $expPagesW );
                $this->assertPages( 'ed-f3', $usr, 0, $expPagesW );
                $this->assertPages( 'ed-f4', $usr, $id0, $expPagesW );
                $this->assertLists( 'ed-f5', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertIsIn( 'ed-f5a', $usr, 0, $expPagesIn );
                $this->assertLists( 'ed-f6', $usr, $id0, $expListsW, 
$expListsW2 );
+               $this->assertIsIn( 'ed-f6a', $usr, $id0, $expPagesIn );
 
                //
                // Create new list A
@@ -341,12 +354,17 @@
                        'count' => 0,
                ) );
                $expPagesA = array();
+               $expPagesIn = array();
 
                $this->assertPages( 'ed-i2', $usr, $idA, $expPagesA );
                $this->assertLists( 'ed-i3', $usr, $idA, $expListsA, 
$expListsA2 );
+               $this->assertIsIn( 'ed-i3a', $usr, $idA, $expPagesIn );
                $this->assertLists( 'ed-i4', $usrA, $idA, null );
+               $this->assertIsIn( 'ed-i4a', $usrA, $idA, null );
                $this->assertLists( 'ed-i5', $usr2, $idA, null );
+               $this->assertIsIn( 'ed-i5a', $usr2, $idA, null );
                $this->assertLists( 'ed-i6', $usrS, $idA, null );
+               $this->assertIsIn( 'ed-i6a', $usrS, $idA, null );
 
                $this->badUsePage( 'ed-ia1', $usrA, '"lspid": ' . $idA );
                $this->badUsePage( 'ed-ia2', $usr2, '"lspid": ' . $idA );
@@ -414,9 +432,13 @@
                $this->assertPages( 'ed-k2b', $usrA, $idA, $expPagesA );
                $this->assertPages( 'ed-k2c', $usrS, $idA, $expPagesA );
                $this->assertLists( 'ed-k3', $usr, $idA, $expListsA, 
$expListsA2 );
+               $this->assertIsIn( 'ed-k3a', $usr, $idA, $expPagesIn );
                $this->assertLists( 'ed-k4', $usrA, $idA, $expListsA, 
$expListsA2 );
+               $this->assertIsIn( 'ed-k4a', $usrA, $idA, $expPagesIn );
                $this->assertLists( 'ed-k5', $usr2, $idA, $expListsA, 
$expListsA2 );
+               $this->assertIsIn( 'ed-k5a', $usr2, $idA, $expPagesIn );
                $this->assertLists( 'ed-k6', $usrS, $idA, $expListsA, 
$expListsA2 );
+               $this->assertIsIn( 'ed-k6a', $usrS, $idA, $expPagesIn );
 
                $this->badUseEdit( 'ed-ka1', $usr, false, $idAs . ', 
"description": "x"' );
                $this->badUseEdit( 'ed-ka2', $usrA, false, $idAs . ', 
"description": "x"' );
@@ -457,6 +479,7 @@
                $this->badUsePage( 'ed-l3a', $usrS, '"lspid": ' . $idA );
                $this->badUsePage( 'ed-l4', $usrA, '"lspid": ' . $idA );
                $this->assertLists( 'ed-l5', $usr, $idA, null );
+               $this->assertIsIn( 'ed-l5a', $usr, $idA, null );
                $this->assertLists( 'ed-l6', $usrA, $idA, null );
                $this->assertLists( 'ed-l7', $usr2, $idA, null );
                $this->assertLists( 'ed-l7a', $usrS, $idA, null );
@@ -484,15 +507,20 @@
                ) );
                // Non-alphabetic order should be preserved
                $expPagesB = array( $pageB, $pageAB, $pageWAB );
+               $expPagesIn = array( 'Gather-ListB', 'Gather-ListAB', 
'Gather-ListWAB' );
 
                $this->assertPages( 'ed-n2', $usr, $idB, $expPagesB );
                $this->assertPages( 'ed-n3', $usr2, $idB, $expPagesB );
                $this->assertPages( 'ed-n3a', $usrS, $idB, $expPagesB );
                $this->assertPages( 'ed-n4', $usrA, $idB, $expPagesB );
                $this->assertLists( 'ed-n5', $usr, $idB, $expListsB, 
$expListsB2 );
+               $this->assertIsIn( 'ed-n5a', $usr, $idB, $expPagesIn );
                $this->assertLists( 'ed-n6', $usrA, $idB, $expListsB, 
$expListsB2 );
+               $this->assertIsIn( 'ed-n6a', $usrA, $idB, $expPagesIn );
                $this->assertLists( 'ed-n7', $usr2, $idB, $expListsB, 
$expListsB2 );
+               $this->assertIsIn( 'ed-n7a', $usr2, $idB, $expPagesIn );
                $this->assertLists( 'ed-n8', $usrS, $idB, $expListsB, 
$expListsB2 );
+               $this->assertIsIn( 'ed-n8a', $usrS, $idB, $expPagesIn );
                $this->badUseEdit( 'ed-na1', $usr, $token, '"label": "B", 
"mode": "hidelist"' );
                $this->badUseEdit( 'ed-na2', $usr, $token, '"label": "B", 
"mode": "showlist"' );
                $this->badUseEdit( 'ed-na3', $usrA, $tokenA, '"label": "B", 
"mode": "hidelist"' );
@@ -525,9 +553,13 @@
                $this->assertLists( 'ed-o4', $usr, $idB, $expListsB, 
$expListsB2 );
                $this->assertLists( 'ed-o4a', $usr, '{}', array( $expListsW, 
$expListsB ),
                        array( $expListsW2, $expListsB2 ) );
+               $this->assertIsIn( 'ed-o4b', $usr, $idB, $expPagesIn );
                $this->assertLists( 'ed-o5', $usrA, $idB, null );
+               $this->assertIsIn( 'ed-o5a', $usrA, $idB, null );
                $this->assertLists( 'ed-o6', $usr2, $idB, null );
+               $this->assertIsIn( 'ed-o6a', $usr2, $idB, null );
                $this->assertLists( 'ed-o7', $usrS, $idB, null );
+               $this->assertIsIn( 'ed-o7a', $usrS, $idB, null );
 
                $this->badUsePage( 'ed-oa1', $usrA, '"lspid": ' . $idB );
                $this->badUsePage( 'ed-oa2', $usr2, '"lspid": ' . $idB );
@@ -557,6 +589,7 @@
 
                $this->assertPages( 'ed-p2', $usr, $idB, $expPagesB );
                $this->assertLists( 'ed-p3', $usr, $idB, $expListsB, 
$expListsB2 );
+               $this->assertIsIn( 'ed-p3a', $usr, $idB, $expPagesIn );
        }
 
        public function testMultipleLists() {
@@ -1047,6 +1080,47 @@
                }
        }
 
+       /**
+        * @param $message
+        * @param User $u
+        * @param $params
+        * @param null|array|object $expected if null, expect empty, if object, 
expect one page,
+        *        if array, expect several pages
+        * @throws Exception
+        */
+       private function assertIsIn( $message, $u, $params, $expected ) {
+               if ( is_integer( $params ) ) {
+                       $params = '"lsmid":' . $params;
+               }
+               $params = array_merge( (array)$this->toArr( $message, $params, 
true ), array(
+                       'action' => 'query',
+                       'format' => 'json',
+                       'continue' => '',
+                       'generator' => 'allpages',
+                       'gapprefix' => 'Gather-List',
+                       'gaplimit' => 'max',
+                       'prop' => 'listmembership'
+               ) );
+
+               if ( $expected === null ) {
+                       $this->badUse( $message, $u, 'query', false, $params );
+                       return;
+               }
+
+               $res = $this->doApiRequest2( $message, $u, $params );
+
+               $found = array();
+               if ( isset( $res[0]['query']['pages'] ) ) {
+                       foreach ( $res[0]['query']['pages'] as $page ) {
+                               if ( array_key_exists( 'listmembership', $page 
) ) {
+                                       $this->assertEquals( true, 
$page['listmembership'], $message );
+                                       $found[] = $page['title'];
+                               }
+                       }
+               }
+               $this->assertArrayEquals( $expected, $found, false, false, 
$message );
+       }
+
        private function assertPages( $message, $u, $id, $expected ) {
                $params = $id === null ? '{}' : '"lspid":' . $id;
                $res = $this->getPages( $message, $u, $params );

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I90b6df0c7a9d69460921e9410284c312b3d09d7b
Gerrit-PatchSet: 13
Gerrit-Project: mediawiki/extensions/Gather
Gerrit-Branch: master
Gerrit-Owner: Yurik <yu...@wikimedia.org>
Gerrit-Reviewer: Aaron Schulz <asch...@wikimedia.org>
Gerrit-Reviewer: Anomie <bjor...@wikimedia.org>
Gerrit-Reviewer: Gergő Tisza <gti...@wikimedia.org>
Gerrit-Reviewer: Jdlrobson <jrob...@wikimedia.org>
Gerrit-Reviewer: Jhernandez <jhernan...@wikimedia.org>
Gerrit-Reviewer: Jkatz <jk...@wikimedia.org>
Gerrit-Reviewer: Robmoen <rm...@wikimedia.org>
Gerrit-Reviewer: Yurik <yu...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to