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