Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.99% covered (warning)
86.99%
107 / 123
57.14% covered (warning)
57.14%
4 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiQueryWatchlistRaw
86.99% covered (warning)
86.99%
107 / 123
57.14% covered (warning)
57.14%
4 / 7
30.85
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 executeGenerator
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 run
84.48% covered (warning)
84.48%
49 / 58
0.00% covered (danger)
0.00%
0 / 1
24.98
 getAllowedParams
100.00% covered (success)
100.00%
51 / 51
100.00% covered (success)
100.00%
1 / 1
1
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getHelpUrls
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * Copyright © 2008 Roan Kattouw <roan.kattouw@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 */
22
23use MediaWiki\Cache\GenderCache;
24use MediaWiki\ParamValidator\TypeDef\UserDef;
25use MediaWiki\Title\NamespaceInfo;
26use MediaWiki\Title\Title;
27use MediaWiki\Title\TitleValue;
28use Wikimedia\ParamValidator\ParamValidator;
29use Wikimedia\ParamValidator\TypeDef\IntegerDef;
30
31/**
32 * This query action allows clients to retrieve a list of pages
33 * on the logged-in user's watchlist.
34 *
35 * @ingroup API
36 */
37class ApiQueryWatchlistRaw extends ApiQueryGeneratorBase {
38
39    private WatchedItemQueryService $watchedItemQueryService;
40    private Language $contentLanguage;
41    private NamespaceInfo $namespaceInfo;
42    private GenderCache $genderCache;
43
44    /**
45     * @param ApiQuery $query
46     * @param string $moduleName
47     * @param WatchedItemQueryService $watchedItemQueryService
48     * @param Language $contentLanguage
49     * @param NamespaceInfo $namespaceInfo
50     * @param GenderCache $genderCache
51     */
52    public function __construct(
53        ApiQuery $query,
54        $moduleName,
55        WatchedItemQueryService $watchedItemQueryService,
56        Language $contentLanguage,
57        NamespaceInfo $namespaceInfo,
58        GenderCache $genderCache
59    ) {
60        parent::__construct( $query, $moduleName, 'wr' );
61        $this->watchedItemQueryService = $watchedItemQueryService;
62        $this->contentLanguage = $contentLanguage;
63        $this->namespaceInfo = $namespaceInfo;
64        $this->genderCache = $genderCache;
65    }
66
67    public function execute() {
68        $this->run();
69    }
70
71    public function executeGenerator( $resultPageSet ) {
72        $this->run( $resultPageSet );
73    }
74
75    /**
76     * @param ApiPageSet|null $resultPageSet
77     * @return void
78     */
79    private function run( $resultPageSet = null ) {
80        $params = $this->extractRequestParams();
81
82        $user = $this->getWatchlistUser( $params );
83
84        $prop = array_fill_keys( (array)$params['prop'], true );
85        $show = array_fill_keys( (array)$params['show'], true );
86        if ( isset( $show[WatchedItemQueryService::FILTER_CHANGED] )
87            && isset( $show[WatchedItemQueryService::FILTER_NOT_CHANGED] )
88        ) {
89            $this->dieWithError( 'apierror-show' );
90        }
91
92        $options = [];
93        if ( $params['namespace'] ) {
94            $options['namespaceIds'] = $params['namespace'];
95        }
96        if ( isset( $show[WatchedItemQueryService::FILTER_CHANGED] ) ) {
97            $options['filter'] = WatchedItemQueryService::FILTER_CHANGED;
98        }
99        if ( isset( $show[WatchedItemQueryService::FILTER_NOT_CHANGED] ) ) {
100            $options['filter'] = WatchedItemQueryService::FILTER_NOT_CHANGED;
101        }
102
103        if ( isset( $params['continue'] ) ) {
104            $cont = $this->parseContinueParamOrDie( $params['continue'], [ 'int', 'string' ] );
105            $options['startFrom'] = TitleValue::tryNew( $cont[0], $cont[1] );
106            $this->dieContinueUsageIf( !$options['startFrom'] );
107        }
108
109        if ( isset( $params['fromtitle'] ) ) {
110            $options['from'] = $this->parsePrefixedTitlePart( $params['fromtitle'] );
111        }
112
113        if ( isset( $params['totitle'] ) ) {
114            $options['until'] = $this->parsePrefixedTitlePart( $params['totitle'] );
115        }
116
117        $options['sort'] = WatchedItemStore::SORT_ASC;
118        if ( $params['dir'] === 'descending' ) {
119            $options['sort'] = WatchedItemStore::SORT_DESC;
120        }
121        $options['limit'] = $params['limit'] + 1;
122
123        $titles = [];
124        $count = 0;
125        $items = $this->watchedItemQueryService->getWatchedItemsForUser( $user, $options );
126
127        // Get gender information
128        if ( $items !== [] && $resultPageSet === null &&
129            $this->contentLanguage->needsGenderDistinction()
130        ) {
131            $usernames = [];
132            foreach ( $items as $item ) {
133                $linkTarget = $item->getTarget();
134                if ( $this->namespaceInfo->hasGenderDistinction( $linkTarget->getNamespace() ) ) {
135                    $usernames[] = $linkTarget->getText();
136                }
137            }
138            if ( $usernames !== [] ) {
139                $this->genderCache->doQuery( $usernames, __METHOD__ );
140            }
141        }
142
143        foreach ( $items as $item ) {
144            $ns = $item->getTarget()->getNamespace();
145            $dbKey = $item->getTarget()->getDBkey();
146            if ( ++$count > $params['limit'] ) {
147                // We've reached the one extra which shows that there are
148                // additional pages to be had. Stop here...
149                $this->setContinueEnumParameter( 'continue', $ns . '|' . $dbKey );
150                break;
151            }
152            $t = Title::makeTitle( $ns, $dbKey );
153
154            if ( $resultPageSet === null ) {
155                $vals = [];
156                ApiQueryBase::addTitleInfo( $vals, $t );
157                if ( isset( $prop['changed'] ) && $item->getNotificationTimestamp() !== null ) {
158                    $vals['changed'] = wfTimestamp( TS_ISO_8601, $item->getNotificationTimestamp() );
159                }
160                $fit = $this->getResult()->addValue( $this->getModuleName(), null, $vals );
161                if ( !$fit ) {
162                    $this->setContinueEnumParameter( 'continue', $ns . '|' . $dbKey );
163                    break;
164                }
165            } else {
166                $titles[] = $t;
167            }
168        }
169        if ( $resultPageSet === null ) {
170            $this->getResult()->addIndexedTagName( $this->getModuleName(), 'wr' );
171        } else {
172            $resultPageSet->populateFromTitles( $titles );
173        }
174    }
175
176    public function getAllowedParams() {
177        return [
178            'continue' => [
179                ApiBase::PARAM_HELP_MSG => 'api-help-param-continue',
180            ],
181            'namespace' => [
182                ParamValidator::PARAM_ISMULTI => true,
183                ParamValidator::PARAM_TYPE => 'namespace'
184            ],
185            'limit' => [
186                ParamValidator::PARAM_DEFAULT => 10,
187                ParamValidator::PARAM_TYPE => 'limit',
188                IntegerDef::PARAM_MIN => 1,
189                IntegerDef::PARAM_MAX => ApiBase::LIMIT_BIG1,
190                IntegerDef::PARAM_MAX2 => ApiBase::LIMIT_BIG2
191            ],
192            'prop' => [
193                ParamValidator::PARAM_ISMULTI => true,
194                ParamValidator::PARAM_TYPE => [
195                    'changed',
196                ],
197                ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
198            ],
199            'show' => [
200                ParamValidator::PARAM_ISMULTI => true,
201                ParamValidator::PARAM_TYPE => [
202                    WatchedItemQueryService::FILTER_CHANGED,
203                    WatchedItemQueryService::FILTER_NOT_CHANGED
204                ]
205            ],
206            'owner' => [
207                ParamValidator::PARAM_TYPE => 'user',
208                UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name' ],
209            ],
210            'token' => [
211                ParamValidator::PARAM_TYPE => 'string',
212                ParamValidator::PARAM_SENSITIVE => true,
213            ],
214            'dir' => [
215                ParamValidator::PARAM_DEFAULT => 'ascending',
216                ParamValidator::PARAM_TYPE => [
217                    'ascending',
218                    'descending'
219                ],
220            ],
221            'fromtitle' => [
222                ParamValidator::PARAM_TYPE => 'string'
223            ],
224            'totitle' => [
225                ParamValidator::PARAM_TYPE => 'string'
226            ],
227        ];
228    }
229
230    protected function getExamplesMessages() {
231        return [
232            'action=query&list=watchlistraw'
233                => 'apihelp-query+watchlistraw-example-simple',
234            'action=query&generator=watchlistraw&gwrshow=changed&prop=info'
235                => 'apihelp-query+watchlistraw-example-generator',
236        ];
237    }
238
239    public function getHelpUrls() {
240        return 'https://www.mediawiki.org/wiki/Special:MyLanguage/API:Watchlistraw';
241    }
242}