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 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
TourHooks
0.00% covered (danger)
0.00%
0 / 128
0.00% covered (danger)
0.00%
0 / 7
506
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 onBeforePageDisplay
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 onResourceLoaderRegisterModules
0.00% covered (danger)
0.00%
0 / 70
0.00% covered (danger)
0.00%
0 / 1
6
 growthTourDependenciesLoaded
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
 onGetPreferences
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
 onUserGetDefaultOptions
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
20
 onLocalUserCreated
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace GrowthExperiments;
4
5use MediaWiki\Auth\Hook\LocalUserCreatedHook;
6use MediaWiki\Config\Config;
7use MediaWiki\Hook\BeforePageDisplayHook;
8use MediaWiki\Preferences\Hook\GetPreferencesHook;
9use MediaWiki\ResourceLoader\Hook\ResourceLoaderRegisterModulesHook;
10use MediaWiki\ResourceLoader\ResourceLoader;
11use MediaWiki\User\Hook\UserGetDefaultOptionsHook;
12use MediaWiki\User\Options\UserOptionsLookup;
13use MediaWiki\User\Options\UserOptionsManager;
14
15class TourHooks implements
16    BeforePageDisplayHook,
17    ResourceLoaderRegisterModulesHook,
18    GetPreferencesHook,
19    UserGetDefaultOptionsHook,
20    LocalUserCreatedHook
21{
22
23    public const TOUR_COMPLETED_HELP_PANEL = 'growthexperiments-tour-help-panel';
24    public const TOUR_COMPLETED_HOMEPAGE_MENTORSHIP = 'growthexperiments-tour-homepage-mentorship';
25    public const TOUR_COMPLETED_HOMEPAGE_WELCOME = 'growthexperiments-tour-homepage-welcome';
26    public const TOUR_COMPLETED_HOMEPAGE_DISCOVERY = 'growthexperiments-tour-homepage-discovery';
27    public const TOUR_COMPLETED_NEWIMPACT_DISCOVERY = 'growthexperiments-tour-newimpact-discovery';
28
29    private UserOptionsLookup $userOptionsLookup;
30    private ExperimentUserManager $experimentUserManager;
31    private Config $config;
32    private UserOptionsManager $userOptionsManager;
33
34    /**
35     * @param UserOptionsLookup $userOptionsLookup
36     * @param ExperimentUserManager $experimentUserManager
37     * @param Config $config
38     * @param UserOptionsManager $userOptionsManager
39     */
40    public function __construct(
41        UserOptionsLookup $userOptionsLookup,
42        ExperimentUserManager $experimentUserManager,
43        Config $config,
44        UserOptionsManager $userOptionsManager
45    ) {
46        $this->userOptionsLookup = $userOptionsLookup;
47        $this->experimentUserManager = $experimentUserManager;
48        $this->config = $config;
49        $this->userOptionsManager = $userOptionsManager;
50    }
51
52    /** @inheritDoc */
53    public function onBeforePageDisplay( $out, $skin ): void {
54        // Show the discovery tour if the user isn't on WelcomeSurvey or Homepage.
55        // If they have already seen the welcome tour, don't show the discovery one.
56        if ( !$out->getTitle()->isSpecial( 'WelcomeSurvey' ) &&
57             !$out->getTitle()->isSpecial( 'Homepage' ) &&
58             HomepageHooks::isHomepageEnabled( $out->getUser() ) &&
59             !Util::isMobile( $skin ) &&
60             !$this->userOptionsLookup->getBoolOption( $out->getUser(), self::TOUR_COMPLETED_HOMEPAGE_WELCOME )
61        ) {
62            Util::maybeAddGuidedTour(
63                $out,
64                self::TOUR_COMPLETED_HOMEPAGE_DISCOVERY,
65                'ext.guidedTour.tour.homepage_discovery',
66                $this->userOptionsLookup
67            );
68        }
69    }
70
71    /**
72     * Register ResourceLoader modules which depend on other extensions.
73     * @inheritDoc
74     */
75    public function onResourceLoaderRegisterModules( ResourceLoader $resourceLoader ): void {
76        if ( !self::growthTourDependenciesLoaded() ) {
77            return;
78        }
79        $moduleTemplate = [
80            'localBasePath' => dirname( __DIR__ ) . '/modules',
81            'remoteExtPath' => 'GrowthExperiments/modules',
82            'dependencies' => 'ext.guidedTour'
83        ];
84        $modules = [
85            'ext.guidedTour.tour.helppanel' => $moduleTemplate + [
86                'packageFiles' => [
87                    'tours/helpPanelTour.js',
88                    'tours/tourUtils.js',
89                ],
90                'messages' => [
91                    'growthexperiments-tour-helpdesk-response-tip-title',
92                    'growthexperiments-tour-response-tip-text',
93                    'growthexperiments-tour-response-button-okay'
94                ],
95            ],
96            'ext.guidedTour.tour.homepage_mentor' => $moduleTemplate + [
97                'packageFiles' => [
98                    'tours/homepageMentor.js',
99                    'tours/tourUtils.js',
100                ],
101                'messages' => [
102                    'growthexperiments-tour-mentor-response-tip-personal-title',
103                    'growthexperiments-tour-mentor-response-tip-personal-text',
104                    'growthexperiments-tour-response-button-okay'
105                ],
106            ],
107            'ext.guidedTour.tour.homepage_welcome' => $moduleTemplate + [
108                'packageFiles' => [
109                    'tours/homepageWelcome.js',
110                    'tours/tourUtils.js',
111                    "ext.growthExperiments.Homepage.Logger/index.js",
112                    "utils/Utils.js"
113                ],
114                'messages' => [
115                    'growthexperiments-tour-welcome-title',
116                    'growthexperiments-tour-welcome-description',
117                    'growthexperiments-tour-welcome-description-c',
118                    'growthexperiments-tour-welcome-description-d',
119                    'growthexperiments-tour-response-button-okay',
120                ],
121            ],
122            'ext.guidedTour.tour.homepage_discovery' => $moduleTemplate + [
123                'packageFiles' => [
124                    'tours/homepageDiscovery.js',
125                    'tours/tourUtils.js',
126                ],
127                'messages' => [
128                    'growthexperiments-tour-discovery-title',
129                    'growthexperiments-tour-discovery-description',
130                    'growthexperiments-tour-response-button-okay'
131                ]
132            ],
133            'ext.guidedTour.tour.newimpact_discovery' => $moduleTemplate + [
134                'packageFiles' => [
135                    'tours/newImpactDiscovery.js',
136                    "ext.growthExperiments.Homepage.Logger/index.js",
137                    "utils/Utils.js"
138                ],
139                'messages' => [
140                    'growthexperiments-tour-newimpact-discovery-title',
141                    'growthexperiments-tour-newimpact-discovery-description',
142                    'growthexperiments-tour-newimpact-discovery-response-button-okay'
143                ]
144            ]
145        ];
146        $resourceLoader->register( $modules );
147    }
148
149    /**
150     * @return bool
151     */
152    public static function growthTourDependenciesLoaded() {
153        $extensionRegistry = \ExtensionRegistry::getInstance();
154        return $extensionRegistry->isLoaded( 'GuidedTour' ) &&
155               $extensionRegistry->isLoaded( 'Echo' ) &&
156               $extensionRegistry->isLoaded( 'EventLogging' );
157    }
158
159    /**
160     * Register tour state as hidden preferences
161     * @inheritDoc
162     */
163    public function onGetPreferences( $user, &$preferences ) {
164        if ( !self::growthTourDependenciesLoaded() ) {
165            return;
166        }
167        if ( HelpPanel::isHelpPanelEnabled() ) {
168            $preferences[self::TOUR_COMPLETED_HELP_PANEL] = [
169                'type' => 'api',
170            ];
171        }
172        if ( HomepageHooks::isHomepageEnabled() ) {
173            $preferences[self::TOUR_COMPLETED_HOMEPAGE_MENTORSHIP] = [
174                'type' => 'api',
175            ];
176            $preferences[self::TOUR_COMPLETED_HOMEPAGE_WELCOME] = [
177                'type' => 'api',
178            ];
179            $preferences[self::TOUR_COMPLETED_HOMEPAGE_DISCOVERY] = [
180                'type' => 'api',
181            ];
182            $preferences[self::TOUR_COMPLETED_NEWIMPACT_DISCOVERY] = [
183                'type' => 'api',
184            ];
185        }
186    }
187
188    /**
189     * Register default preferences for tours.
190     *
191     * Default is to set their visibility to true (seen), and in the LocalUserCreated
192     * hook we'll set these preferences back to false (unseen).
193     *
194     * @inheritDoc
195     */
196    public function onUserGetDefaultOptions( &$defaultOptions ) {
197        if ( !self::growthTourDependenciesLoaded() ) {
198            return;
199        }
200        if ( HelpPanel::isHelpPanelEnabled() ) {
201            $defaultOptions += [
202                self::TOUR_COMPLETED_HELP_PANEL => true
203            ];
204        }
205        if ( HomepageHooks::isHomepageEnabled() ) {
206            $defaultOptions += [
207                self::TOUR_COMPLETED_HOMEPAGE_MENTORSHIP => true,
208                self::TOUR_COMPLETED_HOMEPAGE_WELCOME => true,
209                self::TOUR_COMPLETED_HOMEPAGE_DISCOVERY => true,
210                // New impact is different from the tours above; no one has
211                // seen it yet, and we want all existing users with activated impact modules
212                // to see it, so its default value should be false.
213                self::TOUR_COMPLETED_NEWIMPACT_DISCOVERY => false,
214            ];
215        }
216    }
217
218    /** @inheritDoc */
219    public function onLocalUserCreated( $user, $autocreated ) {
220        if ( $user->isTemp() ) {
221            return;
222        }
223        // Always set the new impact module discovery tour to seen, whether the user
224        // is autocreated or local to the wiki, and whether homepage is enabled or not.
225        // The only users who should see this tour are existing user accounts in the local
226        // wiki who had the old impact module, and now can see the new impact module.
227        $this->userOptionsManager->setOption(
228            $user,
229            self::TOUR_COMPLETED_NEWIMPACT_DISCOVERY,
230            // If the new impact module isn't enabled yet, mark the tour
231            // as not seen. That way, when the module is eventually enabled,
232            // users will see it.
233            // If the new impact module is enabled, the user doesn't need to
234            // see this tour.
235            // When GEUseNewImpactModule is removed, this value can simply be 1, to
236            // indicate that it was seen.
237            (int)$this->config->get( 'GEUseNewImpactModule' )
238        );
239    }
240}