Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.00% covered (warning)
85.00%
34 / 40
77.78% covered (warning)
77.78%
7 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
PopupsContext
85.00% covered (warning)
85.00%
34 / 40
77.78% covered (warning)
77.78%
7 / 9
23.63
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 conflictsWithNavPopupsGadget
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 conflictsWithRefTooltipsGadget
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 showPreviewsOptInOnPreferencesPage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isReferencePreviewsEnabled
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getConfigBitmaskFromUser
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
4
 shouldSendModuleToUser
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
3
 areDependenciesMet
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 isTitleExcluded
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/*
3 * This file is part of the MediaWiki extension Popups.
4 *
5 * Popups is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * Popups is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with Popups.  If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @file
19 * @ingroup extensions
20 */
21namespace Popups;
22
23use ExtensionRegistry;
24use MediaWiki\Config\Config;
25use MediaWiki\SpecialPage\SpecialPageFactory;
26use MediaWiki\Title\Title;
27use MediaWiki\User\Options\UserOptionsLookup;
28use MediaWiki\User\User;
29
30/**
31 * Popups Module
32 *
33 * @package Popups
34 */
35class PopupsContext {
36
37    public const EXTENSION_NAME = 'popups';
38
39    /**
40     * Logger channel name
41     */
42    public const LOGGER_CHANNEL = 'popups';
43
44    /**
45     * User preference value for enabled Page Previews
46     */
47    public const PREVIEWS_ENABLED = true;
48
49    /**
50     * User preference value for disabled Page Previews
51     */
52    public const PREVIEWS_DISABLED = false;
53
54    /**
55     * User preference key to enable/disable Page Previews
56     */
57    public const PREVIEWS_OPTIN_PREFERENCE_NAME = 'popups';
58
59    /**
60     * User preference key to enable/disable Reference Previews. Named
61     * "mwe-popups-referencePreviews-enabled" in localStorage for anonymous users.
62     */
63    public const REFERENCE_PREVIEWS_PREFERENCE_NAME = 'popups-reference-previews';
64
65    /**
66     * Flags passed on to JS representing preferences
67     */
68    private const NAV_POPUPS_ENABLED = 1;
69    private const REF_TOOLTIPS_ENABLED = 2;
70    private const REFERENCE_PREVIEWS_ENABLED = 4;
71
72    /**
73     * @var Config
74     */
75    private $config;
76
77    /**
78     * @var PopupsContext
79     */
80    protected static $instance;
81
82    /**
83     * @var ExtensionRegistry
84     */
85    private $extensionRegistry;
86
87    /**
88     * @var PopupsGadgetsIntegration
89     */
90    private $gadgetsIntegration;
91
92    /**
93     * @var SpecialPageFactory
94     */
95    private $specialPageFactory;
96
97    /**
98     * @var UserOptionsLookup
99     */
100    private $userOptionsLookup;
101
102    /**
103     * @param Config $config Mediawiki configuration
104     * @param ExtensionRegistry $extensionRegistry MediaWiki extension registry
105     * @param PopupsGadgetsIntegration $gadgetsIntegration Gadgets integration helper
106     * @param SpecialPageFactory $specialPageFactory
107     * @param UserOptionsLookup $userOptionsLookup
108     */
109    public function __construct(
110        Config $config,
111        ExtensionRegistry $extensionRegistry,
112        PopupsGadgetsIntegration $gadgetsIntegration,
113        SpecialPageFactory $specialPageFactory,
114        UserOptionsLookup $userOptionsLookup
115    ) {
116        $this->config = $config;
117        $this->extensionRegistry = $extensionRegistry;
118        $this->gadgetsIntegration = $gadgetsIntegration;
119        $this->specialPageFactory = $specialPageFactory;
120        $this->userOptionsLookup = $userOptionsLookup;
121    }
122
123    /**
124     * @param User $user User whose gadgets settings are being checked
125     * @return bool
126     */
127    public function conflictsWithNavPopupsGadget( User $user ) {
128        return $this->gadgetsIntegration->conflictsWithNavPopupsGadget( $user );
129    }
130
131    /**
132     * @param User $user User whose gadgets settings are being checked
133     * @return bool
134     */
135    public function conflictsWithRefTooltipsGadget( User $user ) {
136        return $this->gadgetsIntegration->conflictsWithRefTooltipsGadget( $user );
137    }
138
139    /**
140     * Are Page previews visible on User Preferences Page
141     *
142     * @return bool
143     */
144    public function showPreviewsOptInOnPreferencesPage() {
145        return $this->config->get( 'PopupsHideOptInOnPreferencesPage' ) === false;
146    }
147
148    /**
149     * @param User $user User whose preferences are checked
150     * @return bool whether or not to show reference previews
151     */
152    public function isReferencePreviewsEnabled( User $user ) {
153        if ( !$this->config->get( 'PopupsReferencePreviews' ) ) {
154            return false;
155        }
156
157        return !$user->isNamed() || $this->userOptionsLookup->getBoolOption(
158            $user, self::REFERENCE_PREVIEWS_PREFERENCE_NAME
159        );
160    }
161
162    /**
163     * @param User $user User whose preferences are checked
164     * @return int
165     */
166    public function getConfigBitmaskFromUser( User $user ) {
167        return ( $this->conflictsWithNavPopupsGadget( $user ) ? self::NAV_POPUPS_ENABLED : 0 ) |
168            ( $this->conflictsWithRefTooltipsGadget( $user ) ? self::REF_TOOLTIPS_ENABLED : 0 ) |
169            ( $this->isReferencePreviewsEnabled( $user ) ? self::REFERENCE_PREVIEWS_ENABLED : 0 );
170    }
171
172    /**
173     * @param User $user User whose preferences are checked
174     * @return bool
175     */
176    public function shouldSendModuleToUser( User $user ) {
177        if ( !$user->isNamed() ) {
178            return true;
179        }
180
181        $shouldLoadPagePreviews = $this->userOptionsLookup->getBoolOption(
182            $user,
183            self::PREVIEWS_OPTIN_PREFERENCE_NAME
184        );
185        $shouldLoadReferencePreviews = $this->isReferencePreviewsEnabled( $user );
186
187        return $shouldLoadPagePreviews || $shouldLoadReferencePreviews;
188    }
189
190    /**
191     * @return bool
192     */
193    public function areDependenciesMet() {
194        if ( $this->config->get( 'PopupsGateway' ) === 'mwApiPlain' ) {
195            return $this->extensionRegistry->isLoaded( 'TextExtracts' )
196            && $this->extensionRegistry->isLoaded( 'PageImages' );
197        }
198
199        return true;
200    }
201
202    /**
203     * Whether popups code should be shipped to $title
204     *
205     * For example, if 'Special:UserLogin' is excluded, and the user is on 'Special:UserLogin',
206     * then the title is considered excluded.
207     *
208     * A title is also considered excluded if its root matches one of the page names
209     * from the config variable. For example, if 'User:A' is excluded, and the
210     * title is 'User:A/b', then this title is considered excluded.
211     *
212     * Language specific excluded titles affect all languages. For example, if "Main_Page" is
213     * excluded, "Bosh_Sahifa" (which is "Main_Page" in Uzbek) is considered excluded too.
214     *
215     * @param Title $title title being tested
216     * @return bool
217     */
218    public function isTitleExcluded( $title ) {
219        $excludedPages = $this->config->get( 'PopupsPageDisabled' );
220
221        $canonicalTitle = $title->getRootTitle();
222
223        if ( $title->isSpecialPage() ) {
224            // it's special page, translate it to canonical name
225            [ $name, $subpage ] = $this->specialPageFactory
226                ->resolveAlias( $canonicalTitle->getText() );
227
228            if ( $name !== null ) {
229                $canonicalTitle = Title::newFromText( $name, NS_SPECIAL );
230            }
231        }
232
233        foreach ( $excludedPages as $page ) {
234            $excludedTitle = Title::newFromText( $page );
235
236            if ( $canonicalTitle->equals( $excludedTitle ) ) {
237                return true;
238            }
239        }
240        return false;
241    }
242}