Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 128
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 / 128
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 / 1
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 / 28
0.00% covered (danger)
0.00%
0 / 1
2
 setIndexedTagNameForMetadata
0.00% covered (danger)
0.00%
0 / 21
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    public function __construct(
49        ApiQuery $queryModule,
50        string $moduleName,
51        private readonly GadgetRepo $gadgetRepo,
52    ) {
53        parent::__construct( $queryModule, $moduleName, 'ga' );
54    }
55
56    public function execute() {
57        $params = $this->extractRequestParams();
58        $this->props = array_flip( $params['prop'] );
59        $this->categories = isset( $params['categories'] )
60            ? array_flip( $params['categories'] )
61            : false;
62        $this->neededIds = isset( $params['ids'] )
63            ? array_flip( $params['ids'] )
64            : false;
65        $this->listAllowed = isset( $params['allowedonly'] ) && $params['allowedonly'];
66        $this->listEnabled = isset( $params['enabledonly'] ) && $params['enabledonly'];
67
68        $this->getMain()->setCacheMode( $this->listAllowed || $this->listEnabled
69            ? 'anon-public-user-private' : 'public' );
70
71        $this->applyList( $this->getList() );
72    }
73
74    private function getList(): array {
75        $gadgets = $this->gadgetRepo->getStructuredList();
76
77        if ( !$gadgets ) {
78            return [];
79        }
80
81        $result = [];
82        foreach ( $gadgets as $section => $list ) {
83            if ( $this->categories && !isset( $this->categories[$section] ) ) {
84                continue;
85            }
86
87            foreach ( $list as $g ) {
88                if ( $this->isNeeded( $g ) ) {
89                    $result[] = $g;
90                }
91            }
92        }
93        return $result;
94    }
95
96    /**
97     * @param Gadget[] $gadgets
98     */
99    private function applyList( array $gadgets ): void {
100        $data = [];
101        $result = $this->getResult();
102
103        foreach ( $gadgets as $g ) {
104            $row = [];
105            if ( isset( $this->props['id'] ) ) {
106                $row['id'] = $g->getName();
107            }
108
109            if ( isset( $this->props['metadata'] ) ) {
110                $row['metadata'] = $this->fakeMetadata( $g );
111                $this->setIndexedTagNameForMetadata( $row['metadata'] );
112            }
113
114            if ( isset( $this->props['desc'] ) ) {
115                $row['desc'] = $g->getDescription();
116            }
117
118            $data[] = $row;
119        }
120
121        ApiResult::setIndexedTagName( $data, 'gadget' );
122        $result->addValue( 'query', $this->getModuleName(), $data );
123    }
124
125    private function isNeeded( Gadget $gadget ): bool {
126        $user = $this->getUser();
127
128        return ( $this->neededIds === false || isset( $this->neededIds[$gadget->getName()] ) )
129            && ( !$this->listAllowed || $gadget->isAllowed( $user ) )
130            && ( !$this->listEnabled || $gadget->isEnabled( $user ) );
131    }
132
133    private function fakeMetadata( Gadget $g ): array {
134        return [
135            'settings' => [
136                'actions' => $g->getRequiredActions(),
137                'categories' => $g->getRequiredCategories(),
138                'section' => $g->getSection(),
139                'contentModels' => $g->getRequiredContentModels(),
140                'default' => $g->isOnByDefault(),
141                'hidden' => $g->isHidden(),
142                'legacyscripts' => (bool)$g->getLegacyScripts(),
143                'namespaces' => $g->getRequiredNamespaces(),
144                'package' => $g->isPackaged(),
145                'requiresES6' => $g->requiresES6(),
146                'rights' => $g->getRequiredRights(),
147                'shared' => false,
148                'skins' => $g->getRequiredSkins(),
149                'supportsUrlLoad' => $g->supportsUrlLoad(),
150            ],
151            'module' => [
152                'datas' => $g->getJSONs(),
153                'dependencies' => $g->getDependencies(),
154                'messages' => $g->getMessages(),
155                'codexIcons' => $g->getCodexIcons(),
156                'peers' => $g->getPeers(),
157                'scripts' => $g->getScripts(),
158                'styles' => $g->getStyles(),
159                'vues' => $g->getVues(),
160            ]
161        ];
162    }
163
164    private function setIndexedTagNameForMetadata( array &$metadata ): void {
165        static $tagNames = [
166            'actions' => 'action',
167            'categories' => 'category',
168            'codexIcons' => 'codexIcon',
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            'vues' => 'vue',
180        ];
181
182        foreach ( $metadata as $data ) {
183            foreach ( $data as $key => $value ) {
184                if ( is_array( $value ) ) {
185                    $tag = $tagNames[$key] ?? $key;
186                    ApiResult::setIndexedTagName( $value, $tag );
187                }
188            }
189        }
190    }
191
192    /** @inheritDoc */
193    public function getAllowedParams() {
194        return [
195            'prop' => [
196                ParamValidator::PARAM_DEFAULT => 'id|metadata',
197                ParamValidator::PARAM_ISMULTI => true,
198                ParamValidator::PARAM_TYPE => [
199                    'id',
200                    'metadata',
201                    'desc',
202                ],
203                ApiBase::PARAM_HELP_MSG_PER_VALUE => [],
204            ],
205            'categories' => [
206                ParamValidator::PARAM_ISMULTI => true,
207                ParamValidator::PARAM_TYPE => 'string',
208            ],
209            'ids' => [
210                ParamValidator::PARAM_TYPE => 'string',
211                ParamValidator::PARAM_ISMULTI => true,
212            ],
213            'allowedonly' => false,
214            'enabledonly' => false,
215        ];
216    }
217
218    /**
219     * @see ApiBase::getExamplesMessages()
220     * @return array
221     */
222    protected function getExamplesMessages() {
223        $params = $this->getAllowedParams();
224        $allProps = implode( '|', $params['prop'][ParamValidator::PARAM_TYPE] );
225        return [
226            'action=query&list=gadgets&gaprop=id|desc'
227                => 'apihelp-query+gadgets-example-1',
228            "action=query&list=gadgets&gaprop=$allProps"
229                => 'apihelp-query+gadgets-example-2',
230            'action=query&list=gadgets&gacategories=foo'
231                => 'apihelp-query+gadgets-example-3',
232            'action=query&list=gadgets&gaids=foo|bar&gaprop=id|desc|metadata'
233                => 'apihelp-query+gadgets-example-4',
234            'action=query&list=gadgets&gaenabledonly'
235                => 'apihelp-query+gadgets-example-5',
236        ];
237    }
238}