Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 125
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ApiQueryGadgets
0.00% covered (danger)
0.00%
0 / 125
0.00% covered (danger)
0.00%
0 / 9
1122
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
56
 getList
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
56
 applyList
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
30
 isNeeded
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
42
 fakeMetadata
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
2
 setIndexedTagNameForMetadata
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
2
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21namespace MediaWiki\Extension\Gadgets\Api;
22
23use MediaWiki\Api\ApiBase;
24use MediaWiki\Api\ApiQuery;
25use MediaWiki\Api\ApiQueryBase;
26use MediaWiki\Api\ApiResult;
27use MediaWiki\Extension\Gadgets\Gadget;
28use MediaWiki\Extension\Gadgets\GadgetRepo;
29use Wikimedia\ParamValidator\ParamValidator;
30
31class ApiQueryGadgets extends ApiQueryBase {
32    private array $props;
33
34    /**
35     * @var array|bool
36     */
37    private $categories;
38
39    /**
40     * @var array|bool
41     */
42    private $neededIds;
43
44    private bool $listAllowed;
45
46    private bool $listEnabled;
47
48    private GadgetRepo $gadgetRepo;
49
50    public function __construct(
51        ApiQuery $queryModule,
52        string $moduleName,
53        GadgetRepo $gadgetRepo
54    ) {
55        parent::__construct( $queryModule, $moduleName, 'ga' );
56        $this->gadgetRepo = $gadgetRepo;
57    }
58
59    public function execute() {
60        $params = $this->extractRequestParams();
61        $this->props = array_flip( $params['prop'] );
62        $this->categories = isset( $params['categories'] )
63            ? array_flip( $params['categories'] )
64            : false;
65        $this->neededIds = isset( $params['ids'] )
66            ? array_flip( $params['ids'] )
67            : false;
68        $this->listAllowed = isset( $params['allowedonly'] ) && $params['allowedonly'];
69        $this->listEnabled = isset( $params['enabledonly'] ) && $params['enabledonly'];
70
71        $this->getMain()->setCacheMode( $this->listAllowed || $this->listEnabled
72            ? 'anon-public-user-private' : 'public' );
73
74        $this->applyList( $this->getList() );
75    }
76
77    private function getList(): array {
78        $gadgets = $this->gadgetRepo->getStructuredList();
79
80        if ( !$gadgets ) {
81            return [];
82        }
83
84        $result = [];
85        foreach ( $gadgets as $category => $list ) {
86            if ( $this->categories && !isset( $this->categories[$category] ) ) {
87                continue;
88            }
89
90            foreach ( $list as $g ) {
91                if ( $this->isNeeded( $g ) ) {
92                    $result[] = $g;
93                }
94            }
95        }
96        return $result;
97    }
98
99    private function applyList( array $gadgets ): void {
100        $data = [];
101        $result = $this->getResult();
102
103        /**
104         * @var $g Gadget
105         */
106        foreach ( $gadgets as $g ) {
107            $row = [];
108            if ( isset( $this->props['id'] ) ) {
109                $row['id'] = $g->getName();
110            }
111
112            if ( isset( $this->props['metadata'] ) ) {
113                $row['metadata'] = $this->fakeMetadata( $g );
114                $this->setIndexedTagNameForMetadata( $row['metadata'] );
115            }
116
117            if ( isset( $this->props['desc'] ) ) {
118                $row['desc'] = $g->getDescription();
119            }
120
121            $data[] = $row;
122        }
123
124        ApiResult::setIndexedTagName( $data, 'gadget' );
125        $result->addValue( 'query', $this->getModuleName(), $data );
126    }
127
128    private function isNeeded( Gadget $gadget ): bool {
129        $user = $this->getUser();
130
131        return ( $this->neededIds === false || isset( $this->neededIds[$gadget->getName()] ) )
132            && ( !$this->listAllowed || $gadget->isAllowed( $user ) )
133            && ( !$this->listEnabled || $gadget->isEnabled( $user ) );
134    }
135
136    private function fakeMetadata( Gadget $g ): array {
137        return [
138            'settings' => [
139                'actions' => $g->getRequiredActions(),
140                'categories' => $g->getRequiredCategories(),
141                'category' => $g->getCategory(),
142                'contentModels' => $g->getRequiredContentModels(),
143                'default' => $g->isOnByDefault(),
144                'hidden' => $g->isHidden(),
145                'legacyscripts' => (bool)$g->getLegacyScripts(),
146                'namespaces' => $g->getRequiredNamespaces(),
147                'package' => $g->isPackaged(),
148                'requiresES6' => $g->requiresES6(),
149                'rights' => $g->getRequiredRights(),
150                'shared' => false,
151                'skins' => $g->getRequiredSkins(),
152                'supportsUrlLoad' => $g->supportsUrlLoad(),
153            ],
154            'module' => [
155                'datas' => $g->getJSONs(),
156                'dependencies' => $g->getDependencies(),
157                'messages' => $g->getMessages(),
158                'peers' => $g->getPeers(),
159                'scripts' => $g->getScripts(),
160                'styles' => $g->getStyles(),
161            ]
162        ];
163    }
164
165    private function setIndexedTagNameForMetadata( array &$metadata ): void {
166        static $tagNames = [
167            'actions' => 'action',
168            'categories' => 'category',
169            'contentModels' => 'contentModel',
170            'datas' => 'data',
171            'dependencies' => 'dependency',
172            'messages' => 'message',
173            'namespaces' => 'namespace',
174            'peers' => 'peer',
175            'rights' => 'right',
176            'scripts' => 'script',
177            'skins' => 'skin',
178            'styles' => 'style',
179        ];
180
181        foreach ( $metadata as $data ) {
182            foreach ( $data as $key => $value ) {
183                if ( is_array( $value ) ) {
184                    $tag = $tagNames[$key] ?? $key;
185                    ApiResult::setIndexedTagName( $value, $tag );
186                }
187            }
188        }
189    }
190
191    public function getAllowedParams() {
192        return [
193            'prop' => [
194                ParamValidator::PARAM_DEFAULT => 'id|metadata',
195                ParamValidator::PARAM_ISMULTI => true,
196                ParamValidator::PARAM_TYPE => [
197                    'id',
198                    'metadata',
199                    'desc',
200                ],
201                ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
202            ],
203            'categories' => [
204                ParamValidator::PARAM_ISMULTI => true,
205                ParamValidator::PARAM_TYPE => 'string',
206            ],
207            'ids' => [
208                ParamValidator::PARAM_TYPE => 'string',
209                ParamValidator::PARAM_ISMULTI => true,
210            ],
211            'allowedonly' => false,
212            'enabledonly' => false,
213        ];
214    }
215
216    /**
217     * @see ApiBase::getExamplesMessages()
218     * @return array
219     */
220    protected function getExamplesMessages() {
221        $params = $this->getAllowedParams();
222        $allProps = implode( '|', $params['prop'][ParamValidator::PARAM_TYPE] );
223        return [
224            'action=query&list=gadgets&gaprop=id|desc'
225                => 'apihelp-query+gadgets-example-1',
226            "action=query&list=gadgets&gaprop=$allProps"
227                => 'apihelp-query+gadgets-example-2',
228            'action=query&list=gadgets&gacategories=foo'
229                => 'apihelp-query+gadgets-example-3',
230            'action=query&list=gadgets&gaids=foo|bar&gaprop=id|desc|metadata'
231                => 'apihelp-query+gadgets-example-4',
232            'action=query&list=gadgets&gaenabledonly'
233                => 'apihelp-query+gadgets-example-5',
234        ];
235    }
236}