Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ConfigDump
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 9
420
0.00% covered (danger)
0.00%
0 / 1
 execute
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
56
 addGlobals
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 addConcreteNamespaceMap
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 addReplicaGroup
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 addProfiles
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
 addUserTesting
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 addExpectedIndices
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getAllowedParams
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
2
 getExamplesMessages
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace CirrusSearch\Api;
4
5use CirrusSearch\Maintenance\ExpectedIndicesBuilder;
6use CirrusSearch\Profile\SearchProfileService;
7use CirrusSearch\SearchConfig;
8use CirrusSearch\UserTestingEngine;
9use MediaWiki\Api\ApiBase;
10use MediaWiki\Api\ApiResult;
11use MediaWiki\MediaWikiServices;
12use Wikimedia\ParamValidator\ParamValidator;
13
14/**
15 * Dumps CirrusSearch configuration for easy viewing.
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License along
28 * with this program; if not, write to the Free Software Foundation, Inc.,
29 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
30 * http://www.gnu.org/copyleft/gpl.html
31 */
32class ConfigDump extends ApiBase {
33    use ApiTrait;
34
35    /** @var string[] */
36    public static $PUBLICLY_SHAREABLE_CONFIG_VARS = [
37        'CirrusSearchDisableUpdate',
38        'CirrusSearchConnectionAttempts',
39        'CirrusSearchSlowSearch',
40        'CirrusSearchUseExperimentalHighlighter',
41        'CirrusSearchOptimizeIndexForExperimentalHighlighter',
42        'CirrusSearchNamespaceMappings',
43        'CirrusSearchExtraIndexes',
44        'CirrusSearchExtraIndexClusters',
45        'CirrusSearchFetchConfigFromApi',
46        'CirrusSearchUpdateShardTimeout',
47        'CirrusSearchClientSideUpdateTimeout',
48        'CirrusSearchSearchShardTimeout',
49        'CirrusSearchClientSizeSearchTimeout',
50        'CirrusSearchMaintenanceTimeout',
51        'CirrusSearchPrefixSearchStartsWithAnyWord',
52        'CirrusSearchPhraseSlop',
53        'CirrusSearchPhraseRescoreBoost',
54        'CirrusSearchPhraseRescoreWindowSize',
55        'CirrusSearchFunctionRescoreWindowSize',
56        'CirrusSearchMoreAccurateScoringMode',
57        'CirrusSearchPhraseSuggestUseText',
58        'CirrusSearchPhraseSuggestUseOpeningText',
59        'CirrusSearchIndexedRedirects',
60        'CirrusSearchLinkedArticlesToUpdate',
61        'CirrusSearchUnlikedArticlesToUpdate',
62        'CirrusSearchWeights',
63        'CirrusSearchBoostOpening',
64        'CirrusSearchNearMatchWeight',
65        'CirrusSearchStemmedWeight',
66        'CirrusSearchNamespaceWeights',
67        'CirrusSearchDefaultNamespaceWeight',
68        'CirrusSearchTalkNamespaceWeight',
69        'CirrusSearchLanguageWeight',
70        'CirrusSearchPreferRecentDefaultDecayPortion',
71        'CirrusSearchPreferRecentUnspecifiedDecayPortion',
72        'CirrusSearchPreferRecentDefaultHalfLife',
73        'CirrusSearchMoreLikeThisConfig',
74        'CirrusSearchInterwikiSources',
75        'CirrusSearchRefreshInterval',
76        'CirrusSearchFragmentSize',
77        'CirrusSearchIndexAllocation',
78        'CirrusSearchFullTextQueryBuilderProfile',
79        'CirrusSearchRescoreProfile',
80        'CirrusSearchPrefixSearchRescoreProfile',
81        'CirrusSearchSimilarityProfile',
82        'CirrusSearchCrossProjectProfiles',
83        'CirrusSearchCrossProjectOrder',
84        'CirrusSearchCrossProjectSearchBlockList',
85        'CirrusSearchExtraIndexBoostTemplates',
86        'CirrusSearchEnableCrossProjectSearch',
87        'CirrusSearchEnableAltLanguage',
88        'CirrusSearchEnableArchive',
89        'CirrusSearchUseIcuFolding',
90        'CirrusSearchUseIcuTokenizer',
91        'CirrusSearchPhraseSuggestProfiles',
92        'CirrusSearchCrossProjectBlockScorerProfiles',
93        'CirrusSearchSimilarityProfiles',
94        'CirrusSearchRescoreFunctionChains',
95        'CirrusSearchCompletionProfiles',
96        'CirrusSearchCompletionSettings',
97        'CirrusSearchCompletionSuggesterUseDefaultSort',
98        // All the config below was added when moving this data
99        // from CirrusSearch config to a static array in this class
100        'CirrusSearchDevelOptions',
101        'CirrusSearchPrefixIds',
102        'CirrusSearchMoreLikeThisFields',
103        'CirrusSearchMoreLikeThisTTL',
104        'CirrusSearchFiletypeAliases',
105        'CirrusSearchDefaultCluster',
106        'CirrusSearchClientSideConnectTimeout',
107        'CirrusSearchReplicaGroup',
108        'CirrusSearchExtraBackendLatency',
109        'CirrusSearchAllowLeadingWildcard',
110        'CirrusSearchClientSideSearchTimeout',
111        'CirrusSearchStripQuestionMarks',
112        'CirrusSearchFullTextQueryBuilderProfiles',
113        'CirrusSearchEnableRegex',
114        'CirrusSearchWikimediaExtraPlugin',
115        'CirrusSearchRegexMaxDeterminizedStates',
116        'CirrusSearchMaxIncategoryOptions',
117        'CirrusSearchEnablePhraseSuggest',
118        'CirrusSearchClusterOverrides',
119        'CirrusSearchRescoreProfiles',
120        'CirrusSearchRescoreFunctionScoreChains',
121        'CirrusSearchNumCrossProjectSearchResults',
122        'CirrusSearchLanguageToWikiMap',
123        'CirrusSearchWikiToNameMap',
124        'CirrusSearchIncLinksAloneW',
125        'CirrusSearchIncLinksAloneK',
126        'CirrusSearchIncLinksAloneA',
127        'CirrusSearchNewCrossProjectPage',
128        'CirrusSearchQueryStringMaxDeterminizedStates',
129        'CirrusSearchElasticQuirks',
130        'CirrusSearchPhraseSuggestMaxErrors',
131        'CirrusSearchPhraseSuggestReverseField',
132        'CirrusSearchBoostTemplates',
133        'CirrusSearchIgnoreOnWikiBoostTemplates',
134        'CirrusSearchIndexBaseName',
135        'CirrusSearchInterleaveConfig',
136        'CirrusSearchMaxPhraseTokens',
137        'LanguageCode',
138        'ContentNamespaces',
139        'NamespacesToBeSearchedDefault',
140        'CirrusSearchCategoryDepth',
141        'CirrusSearchCategoryMax',
142        'CirrusSearchCategoryEndpoint',
143        'CirrusSearchFallbackProfile',
144        'CirrusSearchFallbackProfiles',
145    ];
146
147    public function execute() {
148        $result = $this->getResult();
149        $props = array_flip( $this->extractRequestParams()[ 'prop' ] );
150        if ( isset( $props['globals'] ) ) {
151            $this->addGlobals( $result );
152        }
153        if ( isset( $props['namespacemap'] ) ) {
154            $this->addConcreteNamespaceMap( $result );
155        }
156        if ( isset( $props['profiles'] ) ) {
157            $this->addProfiles( $result );
158        }
159        if ( isset( $props['replicagroup'] ) ) {
160            $this->addReplicaGroup( $result );
161        }
162        if ( isset( $props['usertesting'] ) ) {
163            $this->addUserTesting( $result );
164        }
165        if ( isset( $props['expectedindices'] ) ) {
166            $this->addExpectedIndices( $result );
167        }
168    }
169
170    /**
171     * @param ApiResult $result
172     * @return void
173     */
174    protected function addGlobals( ApiResult $result ): void {
175        $config = $this->getConfig();
176        foreach ( self::$PUBLICLY_SHAREABLE_CONFIG_VARS as $key ) {
177            if ( $config->has( $key ) ) {
178                $result->addValue( null, $key, $config->get( $key ) );
179            }
180        }
181    }
182
183    /**
184     * Include a complete mapping from namespace id to index containing pages.
185     *
186     * Intended for external services/users that need to interact
187     * with elasticsearch or cirrussearch dumps directly.
188     *
189     * @param ApiResult $result Impl to write results to
190     */
191    private function addConcreteNamespaceMap( ApiResult $result ) {
192        $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
193        $conn = $this->getCirrusConnection();
194        $indexBaseName = $conn->getConfig()->get( SearchConfig::INDEX_BASE_NAME );
195        foreach ( $nsInfo->getValidNamespaces() as $ns ) {
196            $indexSuffix = $conn->getIndexSuffixForNamespace( $ns );
197            $indexName = $conn->getIndexName( $indexBaseName, $indexSuffix );
198            $result->addValue( 'CirrusSearchConcreteNamespaceMap', $ns, $indexName );
199        }
200    }
201
202    private function addReplicaGroup( ApiResult $result ) {
203        $result->addValue( null, 'CirrusSearchConcreteReplicaGroup',
204            $this->getCirrusConnection()->getConfig()->getClusterAssignment()->getCrossClusterName() );
205    }
206
207    /**
208     * Profile names and types
209     * @var string[]
210     */
211    private static $PROFILES = [
212        'CirrusSearchPhraseSuggestProfiles' => SearchProfileService::PHRASE_SUGGESTER,
213        'CirrusSearchCrossProjectBlockScorerProfiles' => SearchProfileService::CROSS_PROJECT_BLOCK_SCORER,
214        'CirrusSearchSimilarityProfiles' => SearchProfileService::SIMILARITY,
215        'CirrusSearchRescoreFunctionChains' => SearchProfileService::RESCORE_FUNCTION_CHAINS,
216        'CirrusSearchCompletionProfiles' => SearchProfileService::COMPLETION,
217        'CirrusSearchFullTextQueryBuilderProfiles' => SearchProfileService::FT_QUERY_BUILDER,
218        'CirrusSearchRescoreProfiles' => SearchProfileService::RESCORE,
219    ];
220
221    /**
222     * Add data from profiles
223     * @param ApiResult $result
224     */
225    private function addProfiles( ApiResult $result ) {
226        $config = new SearchConfig();
227        $profileService = $config->getProfileService();
228        foreach ( self::$PROFILES as $var => $profileType ) {
229            $data = $profileService->listExposedProfiles( $profileType );
230            $this->getResult()->addValue( null, $var, $data, ApiResult::OVERRIDE );
231        }
232    }
233
234    /**
235     * @param ApiResult $result
236     * @return void
237     * @throws \CirrusSearch\NoActiveTestException
238     */
239    protected function addUserTesting( ApiResult $result ): void {
240        // UserTesting only automatically assigns test buckets during web requests.
241        // This api call is different from a typical search request though, this is
242        // used from non-search pages to find out what bucket to provide to a new
243        // autocomplete session.
244        $engine = UserTestingEngine::fromConfig( $this->getConfig() );
245        $status = $engine->decideTestByAutoenroll();
246        $result->addValue( null, 'CirrusSearchActiveUserTest',
247            $status->isActive() ? $status->getTrigger() : '' );
248    }
249
250    /**
251     * @param ApiResult $result
252     * @return void
253     */
254    protected function addExpectedIndices( ApiResult $result ): void {
255        $builder = new ExpectedIndicesBuilder( $this->getSearchConfig() );
256        $result->addValue( null, 'CirrusSearchExpectedIndices',
257            $builder->build( false, null ) );
258    }
259
260    public function getAllowedParams() {
261        return [
262            'prop' => [
263                ParamValidator::PARAM_DEFAULT => 'globals|namespacemap|profiles|replicagroup',
264                ParamValidator::PARAM_TYPE => [
265                    'globals',
266                    'namespacemap',
267                    'profiles',
268                    'replicagroup',
269                    'usertesting',
270                    'expectedindices'
271                ],
272                ParamValidator::PARAM_ISMULTI => true,
273            ],
274        ];
275    }
276
277    /**
278     * @see ApiBase::getExamplesMessages
279     * @return array
280     */
281    protected function getExamplesMessages() {
282        return [
283            'action=cirrus-config-dump' =>
284                'apihelp-cirrus-config-dump-example'
285        ];
286    }
287
288}