Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
ConfigDump
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 10
462
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
 isInternal
0.00% covered (danger)
0.00%
0 / 1
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    protected function addGlobals( ApiResult $result ): void {
171        $config = $this->getConfig();
172        foreach ( self::$PUBLICLY_SHAREABLE_CONFIG_VARS as $key ) {
173            if ( $config->has( $key ) ) {
174                $result->addValue( null, $key, $config->get( $key ) );
175            }
176        }
177    }
178
179    /**
180     * Include a complete mapping from namespace id to index containing pages.
181     *
182     * Intended for external services/users that need to interact
183     * with elasticsearch or cirrussearch dumps directly.
184     *
185     * @param ApiResult $result Impl to write results to
186     */
187    private function addConcreteNamespaceMap( ApiResult $result ) {
188        $nsInfo = MediaWikiServices::getInstance()->getNamespaceInfo();
189        $conn = $this->getCirrusConnection();
190        $indexBaseName = $conn->getConfig()->get( SearchConfig::INDEX_BASE_NAME );
191        foreach ( $nsInfo->getValidNamespaces() as $ns ) {
192            $indexSuffix = $conn->getIndexSuffixForNamespace( $ns );
193            $indexName = $conn->getIndexName( $indexBaseName, $indexSuffix );
194            $result->addValue( 'CirrusSearchConcreteNamespaceMap', $ns, $indexName );
195        }
196    }
197
198    private function addReplicaGroup( ApiResult $result ) {
199        $result->addValue( null, 'CirrusSearchConcreteReplicaGroup',
200            $this->getCirrusConnection()->getConfig()->getClusterAssignment()->getCrossClusterName() );
201    }
202
203    /**
204     * Profile names and types
205     * @var string[]
206     */
207    private static $PROFILES = [
208        'CirrusSearchPhraseSuggestProfiles' => SearchProfileService::PHRASE_SUGGESTER,
209        'CirrusSearchCrossProjectBlockScorerProfiles' => SearchProfileService::CROSS_PROJECT_BLOCK_SCORER,
210        'CirrusSearchSimilarityProfiles' => SearchProfileService::SIMILARITY,
211        'CirrusSearchRescoreFunctionChains' => SearchProfileService::RESCORE_FUNCTION_CHAINS,
212        'CirrusSearchCompletionProfiles' => SearchProfileService::COMPLETION,
213        'CirrusSearchFullTextQueryBuilderProfiles' => SearchProfileService::FT_QUERY_BUILDER,
214        'CirrusSearchRescoreProfiles' => SearchProfileService::RESCORE,
215    ];
216
217    /**
218     * Add data from profiles
219     */
220    private function addProfiles( ApiResult $result ) {
221        $config = new SearchConfig();
222        $profileService = $config->getProfileService();
223        foreach ( self::$PROFILES as $var => $profileType ) {
224            $data = $profileService->listExposedProfiles( $profileType );
225            $this->getResult()->addValue( null, $var, $data, ApiResult::OVERRIDE );
226        }
227    }
228
229    /**
230     * @param ApiResult $result
231     * @return void
232     * @throws \CirrusSearch\NoActiveTestException
233     */
234    protected function addUserTesting( ApiResult $result ): void {
235        // UserTesting only automatically assigns test buckets during web requests.
236        // This api call is different from a typical search request though, this is
237        // used from non-search pages to find out what bucket to provide to a new
238        // autocomplete session.
239        $engine = UserTestingEngine::fromConfig( $this->getConfig() );
240        $status = $engine->decideTestByAutoenroll();
241        $result->addValue( null, 'CirrusSearchActiveUserTest',
242            $status->isActive() ? $status->getTrigger() : '' );
243    }
244
245    /**
246     * @param ApiResult $result
247     * @return void
248     */
249    protected function addExpectedIndices( ApiResult $result ): void {
250        $builder = new ExpectedIndicesBuilder( $this->getSearchConfig() );
251        $result->addValue( null, 'CirrusSearchExpectedIndices',
252            $builder->build( false, null ) );
253    }
254
255    /** @inheritDoc */
256    public function getAllowedParams() {
257        return [
258            'prop' => [
259                ParamValidator::PARAM_DEFAULT => 'globals|namespacemap|profiles|replicagroup',
260                ParamValidator::PARAM_TYPE => [
261                    'globals',
262                    'namespacemap',
263                    'profiles',
264                    'replicagroup',
265                    'usertesting',
266                    'expectedindices'
267                ],
268                ParamValidator::PARAM_ISMULTI => true,
269            ],
270        ];
271    }
272
273    /**
274     * Mark as internal. This isn't meant to be used by normal api users
275     * @return bool
276     */
277    public function isInternal() {
278        return true;
279    }
280
281    /**
282     * @see ApiBase::getExamplesMessages
283     * @return array
284     */
285    protected function getExamplesMessages() {
286        return [
287            'action=cirrus-config-dump' =>
288                'apihelp-cirrus-config-dump-example'
289        ];
290    }
291
292}