Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 107 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
WelcomeSurveyHooks | |
0.00% |
0 / 107 |
|
0.00% |
0 / 12 |
2550 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
onSpecialPage_initList | |
0.00% |
0 / 10 |
|
0.00% |
0 / 1 |
6 | |||
onGetPreferences | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
isWelcomeSurveyEnabled | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
isEditing | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
30 | |||
userWasEditing | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
onSpecialPageBeforeExecute | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
110 | |||
onBeforePageDisplay | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
42 | |||
onLocalUserCreated | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 | |||
onCentralAuthPostLoginRedirect | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
42 | |||
onPostLoginRedirect | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
shouldShowWelcomeSurvey | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | // phpcs:disable MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName |
3 | |
4 | namespace GrowthExperiments; |
5 | |
6 | use GrowthExperiments\EventLogging\WelcomeSurveyLogger; |
7 | use GrowthExperiments\NewcomerTasks\CampaignConfig; |
8 | use GrowthExperiments\Specials\SpecialWelcomeSurvey; |
9 | use MediaWiki\Auth\Hook\LocalUserCreatedHook; |
10 | use MediaWiki\Config\Config; |
11 | use MediaWiki\Context\DerivativeContext; |
12 | use MediaWiki\Context\IContextSource; |
13 | use MediaWiki\Context\RequestContext; |
14 | use MediaWiki\Hook\PostLoginRedirectHook; |
15 | use MediaWiki\Logger\LoggerFactory; |
16 | use MediaWiki\Output\Hook\BeforePageDisplayHook; |
17 | use MediaWiki\Preferences\Hook\GetPreferencesHook; |
18 | use MediaWiki\Registration\ExtensionRegistry; |
19 | use MediaWiki\SpecialPage\Hook\SpecialPage_initListHook; |
20 | use MediaWiki\SpecialPage\Hook\SpecialPageBeforeExecuteHook; |
21 | use MediaWiki\SpecialPage\SpecialPageFactory; |
22 | use MediaWiki\Specials\SpecialCreateAccount; |
23 | use MediaWiki\Specials\SpecialUserLogin; |
24 | use MediaWiki\Title\Title; |
25 | use MediaWiki\Title\TitleFactory; |
26 | use MediaWiki\User\User; |
27 | |
28 | class WelcomeSurveyHooks implements |
29 | GetPreferencesHook, |
30 | LocalUserCreatedHook, |
31 | PostLoginRedirectHook, |
32 | SpecialPage_initListHook, |
33 | SpecialPageBeforeExecuteHook, |
34 | BeforePageDisplayHook |
35 | { |
36 | |
37 | private Config $config; |
38 | private TitleFactory $titleFactory; |
39 | private SpecialPageFactory $specialPageFactory; |
40 | private WelcomeSurveyFactory $welcomeSurveyFactory; |
41 | private CampaignConfig $campaignConfig; |
42 | |
43 | /** |
44 | * @param Config $config |
45 | * @param TitleFactory $titleFactory |
46 | * @param SpecialPageFactory $specialPageFactory |
47 | * @param WelcomeSurveyFactory $welcomeSurveyFactory |
48 | * @param CampaignConfig $campaignConfig |
49 | */ |
50 | public function __construct( |
51 | Config $config, |
52 | TitleFactory $titleFactory, |
53 | SpecialPageFactory $specialPageFactory, |
54 | WelcomeSurveyFactory $welcomeSurveyFactory, |
55 | CampaignConfig $campaignConfig |
56 | ) { |
57 | $this->config = $config; |
58 | $this->titleFactory = $titleFactory; |
59 | $this->specialPageFactory = $specialPageFactory; |
60 | $this->welcomeSurveyFactory = $welcomeSurveyFactory; |
61 | $this->campaignConfig = $campaignConfig; |
62 | } |
63 | |
64 | /** |
65 | * Register WelcomeSurvey special page. |
66 | * |
67 | * @param array &$list |
68 | */ |
69 | public function onSpecialPage_initList( &$list ) { |
70 | if ( $this->isWelcomeSurveyEnabled() ) { |
71 | $list[ 'WelcomeSurvey' ] = function () { |
72 | return new SpecialWelcomeSurvey( |
73 | $this->specialPageFactory, |
74 | $this->welcomeSurveyFactory, |
75 | new WelcomeSurveyLogger( |
76 | LoggerFactory::getInstance( 'GrowthExperiments' ) |
77 | ) |
78 | ); |
79 | }; |
80 | } |
81 | } |
82 | |
83 | /** |
84 | * Register preference to save the Welcome survey responses. |
85 | * |
86 | * @param User $user |
87 | * @param array &$preferences |
88 | */ |
89 | public function onGetPreferences( $user, &$preferences ) { |
90 | if ( $this->isWelcomeSurveyEnabled() ) { |
91 | $preferences[WelcomeSurvey::SURVEY_PROP] = [ |
92 | 'type' => 'api', |
93 | ]; |
94 | } |
95 | } |
96 | |
97 | private function isWelcomeSurveyEnabled() { |
98 | return $this->config->get( 'WelcomeSurveyEnabled' ); |
99 | } |
100 | |
101 | /** |
102 | * Check if a given title + query string means some kind of editor is open. |
103 | * @param Title|null $title |
104 | * @param array|null $query |
105 | * @return bool |
106 | */ |
107 | private function isEditing( ?Title $title, ?array $query = null ): bool { |
108 | return $title && $title->canExist() && ( |
109 | // normal editor, VE with some settings |
110 | ( $query['action'] ?? null ) === 'edit' |
111 | // VE |
112 | || ( $query['veaction'] ?? null ) === 'edit' |
113 | // mobile editor |
114 | || str_starts_with( $title->getFragment(), '/editor/' ) |
115 | ); |
116 | } |
117 | |
118 | /** |
119 | * True if the user started the registration process while in the middle of editing. |
120 | * @param string|null $returnTo returnto parameter. Read from URL if omitted. |
121 | * @param string|string[]|null $returnToQuery returntoquery parameter. Read from URL if omitted. |
122 | * @return bool |
123 | */ |
124 | private function userWasEditing( ?string $returnTo = null, $returnToQuery = null ): bool { |
125 | $context = RequestContext::getMain(); |
126 | $returnTo ??= $context->getRequest()->getText( 'returnto' ); |
127 | $returntoTitle = ( $returnTo !== '' ) ? $this->titleFactory->newFromText( $returnTo ) : null; |
128 | if ( $returnToQuery === null ) { |
129 | $returnToQuery = wfCgiToArray( $context->getRequest()->getText( 'returntoquery' ) ); |
130 | } elseif ( is_string( $returnToQuery ) ) { |
131 | $returnToQuery = wfCgiToArray( $returnToQuery ); |
132 | } |
133 | return $this->isEditing( $returntoTitle, $returnToQuery ); |
134 | } |
135 | |
136 | /** @inheritDoc */ |
137 | public function onSpecialPageBeforeExecute( $special, $subPage ) { |
138 | $context = $special->getContext(); |
139 | $user = $context->getUser(); |
140 | if ( $special instanceof SpecialUserLogin && $user->isAnon() ) { |
141 | $request = $context->getRequest(); |
142 | if ( $user->isAnon() && $request->getCookie( WelcomeSurveyLogger::INTERACTION_PHASE_COOKIE ) ) { |
143 | $welcomeSurveyLogger = new WelcomeSurveyLogger( LoggerFactory::getInstance( 'GrowthExperiments' ) ); |
144 | $welcomeSurveyLogger->initialize( $request, $user, Util::isMobile( $context->getSkin() ) ); |
145 | $welcomeSurveyLogger->logInteraction( WelcomeSurveyLogger::WELCOME_SURVEY_LOGGED_OUT ); |
146 | } |
147 | } elseif ( |
148 | $special instanceof SpecialCreateAccount |
149 | && $user->isAnon() && $this->userWasEditing() |
150 | && !Util::isMobile( $context->getSkin() ) |
151 | && $this->shouldShowWelcomeSurvey( $context ) |
152 | ) { |
153 | $context->getOutput()->addModules( 'ext.growthExperiments.MidEditSignup' ); |
154 | $context->getOutput()->addJsConfigVars( 'wgGEMidEditSignup', true ); |
155 | } |
156 | } |
157 | |
158 | /** @inheritDoc */ |
159 | public function onBeforePageDisplay( $out, $skin ): void { |
160 | if ( $out->getRequest()->getCookie( 'ge.midEditSignup' ) |
161 | && !Util::isMobile( $skin ) |
162 | // maybe the user filled out or dismissed the survey in another tab, don't show then |
163 | && $this->welcomeSurveyFactory->newWelcomeSurvey( $out->getContext() )->isUnfinished() |
164 | && ( |
165 | // Check if we are post-edit, somewhat relying on \MediaWiki\EditPage\EditPage internals. |
166 | // There isn't a good way to do that; between trying to check the dynamically named |
167 | // postedit cookie and looking for the JS variable Article::show() sets based on |
168 | // that cookie, this is the less painful one. |
169 | ( $out->getJsConfigVars()['wgPostEdit'] ?? false ) |
170 | // Also load the module if the editor is open, as some editors save without |
171 | // reloading the page. |
172 | || $this->isEditing( $out->getTitle(), $out->getRequest()->getQueryValues() ) |
173 | ) |
174 | ) { |
175 | $out->addModules( 'ext.growthExperiments.MidEditSignup' ); |
176 | } |
177 | } |
178 | |
179 | /** @inheritDoc */ |
180 | public function onLocalUserCreated( $user, $autocreated ) { |
181 | if ( $user->isTemp() ) { |
182 | return; |
183 | } |
184 | $context = new DerivativeContext( RequestContext::getMain() ); |
185 | $context->setUser( $user ); |
186 | if ( $autocreated || !$this->shouldShowWelcomeSurvey( $context ) ) { |
187 | return; |
188 | } |
189 | $welcomeSurvey = $this->welcomeSurveyFactory->newWelcomeSurvey( $context ); |
190 | $group = $welcomeSurvey->getGroup(); |
191 | $welcomeSurvey->saveGroup( $group ); |
192 | } |
193 | |
194 | /** @inheritDoc */ |
195 | public function onCentralAuthPostLoginRedirect( |
196 | string &$returnTo, string &$returnToQuery, bool $stickHTTPS, string $type, string &$injectedHtml |
197 | ) { |
198 | $context = RequestContext::getMain(); |
199 | if ( $type !== 'signup' |
200 | || !$this->shouldShowWelcomeSurvey( $context ) |
201 | ) { |
202 | return; |
203 | } |
204 | |
205 | $welcomeSurvey = $this->welcomeSurveyFactory->newWelcomeSurvey( $context ); |
206 | $group = $welcomeSurvey->getGroup(); |
207 | if ( $group === false ) { |
208 | return; |
209 | } |
210 | |
211 | if ( $this->userWasEditing( $returnTo, $returnToQuery ) ) { |
212 | return; |
213 | } |
214 | |
215 | $oldReturnTo = $returnTo; |
216 | $oldReturnToQuery = $returnToQuery; |
217 | $returnToQueryArray = $welcomeSurvey->getRedirectUrlQuery( $group, $oldReturnTo, $oldReturnToQuery ); |
218 | if ( $returnToQueryArray === false ) { |
219 | return; |
220 | } |
221 | |
222 | $returnTo = $this->specialPageFactory->getTitleForAlias( 'WelcomeSurvey' )->getPrefixedText(); |
223 | $returnToQuery = wfArrayToCgi( $returnToQueryArray ); |
224 | $injectedHtml = ''; |
225 | return false; |
226 | } |
227 | |
228 | /** @inheritDoc */ |
229 | public function onPostLoginRedirect( &$returnTo, &$returnToQuery, &$type ) { |
230 | $context = RequestContext::getMain(); |
231 | if ( $type !== 'signup' |
232 | // handled by onCentralAuthPostLoginRedirect |
233 | || ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) |
234 | || !$this->shouldShowWelcomeSurvey( $context ) |
235 | ) { |
236 | return; |
237 | } |
238 | |
239 | $welcomeSurvey = $this->welcomeSurveyFactory->newWelcomeSurvey( $context ); |
240 | $group = $welcomeSurvey->getGroup(); |
241 | $welcomeSurvey->saveGroup( $group ); |
242 | |
243 | if ( $this->userWasEditing( $returnTo, $returnToQuery ) ) { |
244 | return; |
245 | } |
246 | |
247 | $oldReturnTo = $returnTo; |
248 | $oldReturnToQuery = $returnToQuery; |
249 | |
250 | $returnTo = $this->specialPageFactory->getTitleForAlias( 'WelcomeSurvey' )->getPrefixedText(); |
251 | $returnToQuery = $welcomeSurvey->getRedirectUrlQuery( $group, $oldReturnTo, wfArrayToCgi( $oldReturnToQuery ) ); |
252 | $type = 'successredirect'; |
253 | return false; |
254 | } |
255 | |
256 | /** |
257 | * @param IContextSource $context |
258 | * @return bool |
259 | */ |
260 | private function shouldShowWelcomeSurvey( IContextSource $context ): bool { |
261 | return $this->isWelcomeSurveyEnabled() |
262 | && !$context->getUser()->isTemp() |
263 | && HomepageHooks::getGrowthFeaturesOptInOptOutOverride() !== HomepageHooks::GROWTH_FORCE_OPTOUT |
264 | && !VariantHooks::shouldCampaignSkipWelcomeSurvey( |
265 | VariantHooks::getCampaign( $context ), $this->campaignConfig |
266 | ); |
267 | } |
268 | |
269 | } |