Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 103 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
PreferenceHooks | |
0.00% |
0 / 103 |
|
0.00% |
0 / 4 |
702 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
arrayRenameKey | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
onGetPreferences | |
0.00% |
0 / 89 |
|
0.00% |
0 / 1 |
380 | |||
onLocalUserCreated | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | /** |
3 | * DiscussionTools preference hooks |
4 | * |
5 | * @file |
6 | * @ingroup Extensions |
7 | * @license MIT |
8 | */ |
9 | |
10 | namespace MediaWiki\Extension\DiscussionTools\Hooks; |
11 | |
12 | use MediaWiki\Auth\Hook\LocalUserCreatedHook; |
13 | use MediaWiki\Config\Config; |
14 | use MediaWiki\Config\ConfigFactory; |
15 | use MediaWiki\Html\Html; |
16 | use MediaWiki\Linker\LinkRenderer; |
17 | use MediaWiki\MediaWikiServices; |
18 | use MediaWiki\Preferences\Hook\GetPreferencesHook; |
19 | use MediaWiki\SpecialPage\SpecialPage; |
20 | use MediaWiki\User\User; |
21 | |
22 | class PreferenceHooks implements |
23 | LocalUserCreatedHook, |
24 | GetPreferencesHook |
25 | { |
26 | |
27 | private Config $config; |
28 | private LinkRenderer $linkRenderer; |
29 | |
30 | public function __construct( |
31 | ConfigFactory $configFactory, |
32 | LinkRenderer $linkRenderer |
33 | ) { |
34 | $this->config = $configFactory->makeConfig( 'discussiontools' ); |
35 | $this->linkRenderer = $linkRenderer; |
36 | } |
37 | |
38 | /** |
39 | * Rename a key in an array while preserving the order of associative array keys. |
40 | * |
41 | * @param array $array |
42 | * @param string $from |
43 | * @param string $to |
44 | * @return array Modified array |
45 | */ |
46 | private static function arrayRenameKey( array $array, string $from, string $to ): array { |
47 | $out = []; |
48 | foreach ( $array as $key => $value ) { |
49 | if ( $key === $from ) { |
50 | $key = $to; |
51 | } |
52 | $out[$key] = $value; |
53 | } |
54 | return $out; |
55 | } |
56 | |
57 | /** |
58 | * Handler for the GetPreferences hook, to add and hide user preferences as configured |
59 | * |
60 | * @param User $user |
61 | * @param array &$preferences |
62 | */ |
63 | public function onGetPreferences( $user, &$preferences ) { |
64 | if ( HookUtils::isFeatureAvailableToUser( $user ) ) { |
65 | $preferences['discussiontools-summary'] = [ |
66 | 'type' => 'info', |
67 | 'default' => wfMessage( 'discussiontools-preference-summary' )->parse(), |
68 | 'raw' => true, |
69 | 'section' => 'editing/discussion', |
70 | ]; |
71 | } |
72 | foreach ( HookUtils::FEATURES as $feature ) { |
73 | if ( |
74 | $feature === HookUtils::VISUALENHANCEMENTS_REPLY || |
75 | $feature === HookUtils::VISUALENHANCEMENTS_PAGEFRAME |
76 | ) { |
77 | // Feature is never user-configurable |
78 | continue; |
79 | } |
80 | if ( HookUtils::isFeatureAvailableToUser( $user, $feature ) ) { |
81 | $preferences["discussiontools-$feature"] = [ |
82 | 'type' => 'toggle', |
83 | // The following messages are used here: |
84 | // * discussiontools-preference-autotopicsub |
85 | // * discussiontools-preference-newtopictool |
86 | // * discussiontools-preference-replytool |
87 | // * discussiontools-preference-sourcemodetoolbar |
88 | // * discussiontools-preference-topicsubscription |
89 | // * discussiontools-preference-visualenhancements |
90 | 'label-message' => "discussiontools-preference-$feature", |
91 | // The following messages are used here: |
92 | // * discussiontools-preference-autotopicsub-help |
93 | // * discussiontools-preference-newtopictool-help |
94 | // * discussiontools-preference-replytool-help |
95 | // * discussiontools-preference-sourcemodetoolbar-help |
96 | // * discussiontools-preference-topicsubscription-help |
97 | // * discussiontools-preference-visualenhancements-help |
98 | 'help-message' => "discussiontools-preference-$feature-help", |
99 | 'section' => 'editing/discussion', |
100 | ]; |
101 | |
102 | // Option to enable/disable new topic tool on pages that haven't been created |
103 | // (it's inside this loop to place the options in a nice order) |
104 | if ( $feature === HookUtils::NEWTOPICTOOL ) { |
105 | $preferences["discussiontools-newtopictool-createpage"] = [ |
106 | 'type' => 'radio', |
107 | 'cssclass' => 'mw-htmlform-checkradio-indent', |
108 | 'label-message' => 'discussiontools-preference-newtopictool-createpage', |
109 | 'options-messages' => [ |
110 | 'discussiontools-preference-newtopictool-createpage-newtopictool' => 1, |
111 | 'discussiontools-preference-newtopictool-createpage-editor' => 0, |
112 | ], |
113 | 'disable-if' => [ '===', 'discussiontools-' . HookUtils::NEWTOPICTOOL, '' ], |
114 | 'section' => 'editing/discussion', |
115 | ]; |
116 | } |
117 | |
118 | // Make this option unavailable when a conflicting Convenient Discussions gadget exists |
119 | // (we can't use 'disable-if' or 'hide-if', because they don't let us change the labels). |
120 | if ( HookUtils::featureConflictsWithGadget( $user, $feature ) ) { |
121 | $preferences["discussiontools-$feature"]['disabled'] = true; |
122 | $preferences["discussiontools-$feature"]['help-message'] = |
123 | [ 'discussiontools-preference-gadget-conflict', 'Special:Preferences#mw-prefsection-gadgets' ]; |
124 | } |
125 | } |
126 | } |
127 | |
128 | if ( isset( $preferences['discussiontools-' . HookUtils::SOURCEMODETOOLBAR] ) && ( |
129 | isset( $preferences['discussiontools-' . HookUtils::REPLYTOOL] ) || |
130 | isset( $preferences['discussiontools-' . HookUtils::NEWTOPICTOOL] ) |
131 | ) ) { |
132 | // Disable this option when it would have no effect |
133 | // (both reply tool and new topic tool are disabled) |
134 | $preferences['discussiontools-' . HookUtils::SOURCEMODETOOLBAR]['disable-if'] = [ 'AND' ]; |
135 | |
136 | if ( isset( $preferences['discussiontools-' . HookUtils::REPLYTOOL] ) && |
137 | // GlobalPreferences extension would delete disabled fields, avoid referring to it. |
138 | !( $preferences['discussiontools-' . HookUtils::REPLYTOOL]['disabled'] ?? false ) |
139 | ) { |
140 | $preferences['discussiontools-' . HookUtils::SOURCEMODETOOLBAR]['disable-if'][] = [ |
141 | '===', 'discussiontools-' . HookUtils::REPLYTOOL, '' |
142 | ]; |
143 | } |
144 | if ( isset( $preferences['discussiontools-' . HookUtils::NEWTOPICTOOL] ) ) { |
145 | $preferences['discussiontools-' . HookUtils::SOURCEMODETOOLBAR]['disable-if'][] = [ |
146 | '===', 'discussiontools-' . HookUtils::NEWTOPICTOOL, '' |
147 | ]; |
148 | } |
149 | } |
150 | |
151 | if ( isset( $preferences['discussiontools-' . HookUtils::AUTOTOPICSUB] ) && |
152 | isset( $preferences['discussiontools-' . HookUtils::TOPICSUBSCRIPTION] ) |
153 | ) { |
154 | // Disable automatic subscriptions when subscriptions are disabled |
155 | $preferences['discussiontools-' . HookUtils::AUTOTOPICSUB]['disable-if'] = [ |
156 | '===', 'discussiontools-' . HookUtils::TOPICSUBSCRIPTION, '' |
157 | ]; |
158 | } |
159 | |
160 | $preferences['discussiontools-showadvanced'] = [ |
161 | 'type' => 'api', |
162 | ]; |
163 | $preferences['discussiontools-seenautotopicsubpopup'] = [ |
164 | 'type' => 'api', |
165 | ]; |
166 | |
167 | if ( !$this->config->get( 'DiscussionToolsBeta' ) ) { |
168 | // When out of beta, preserve the user preference in case we |
169 | // bring back the beta feature for a new sub-feature. (T272071) |
170 | $preferences['discussiontools-betaenable'] = [ |
171 | 'type' => 'api' |
172 | ]; |
173 | } |
174 | |
175 | $preferences['discussiontools-editmode'] = [ |
176 | 'type' => 'api', |
177 | 'validation-callback' => static function ( $value ) { |
178 | return in_array( $value, [ '', 'source', 'visual' ], true ); |
179 | }, |
180 | ]; |
181 | |
182 | // Add a link to Special:TopicSubscriptions to the Echo preferences matrix |
183 | $categoryMessage = wfMessage( 'echo-category-title-dt-subscription' )->numParams( 1 )->escaped(); |
184 | $categoryMessageExtra = $categoryMessage . |
185 | Html::element( 'br' ) . |
186 | wfMessage( 'parentheses' )->rawParams( |
187 | $this->linkRenderer->makeLink( |
188 | SpecialPage::getTitleFor( 'TopicSubscriptions' ), |
189 | wfMessage( 'discussiontools-topicsubscription-preferences-editsubscriptions' )->text() |
190 | ) |
191 | )->escaped(); |
192 | if ( isset( $preferences['echo-subscriptions']['rows'] ) ) { |
193 | $preferences['echo-subscriptions']['rows'] = static::arrayRenameKey( |
194 | $preferences['echo-subscriptions']['rows'], |
195 | $categoryMessage, |
196 | $categoryMessageExtra |
197 | ); |
198 | } |
199 | if ( isset( $preferences['echo-subscriptions']['tooltips'] ) ) { |
200 | $preferences['echo-subscriptions']['tooltips'] = static::arrayRenameKey( |
201 | // Phan insists that this key doesn't exist, even though we just checked with isset() |
202 | // @phan-suppress-next-line PhanTypeInvalidDimOffset, PhanTypeMismatchArgument |
203 | $preferences['echo-subscriptions']['tooltips'], |
204 | $categoryMessage, |
205 | $categoryMessageExtra |
206 | ); |
207 | } |
208 | } |
209 | |
210 | /** |
211 | * Handler for LocalUserCreated hook. |
212 | * @see https://www.mediawiki.org/wiki/Manual:Hooks/LocalUserCreated |
213 | * @param User $user User object for the created user |
214 | * @param bool $autocreated Whether this was an auto-creation |
215 | * @return bool|void True or no return value to continue or false to abort |
216 | */ |
217 | public function onLocalUserCreated( $user, $autocreated ) { |
218 | if ( $user->isTemp() ) { |
219 | // Temp users can't have preferences (and we don't let them have topic subscriptions anyway) |
220 | return; |
221 | } |
222 | |
223 | $userOptionsManager = MediaWikiServices::getInstance()->getUserOptionsManager(); |
224 | // We want new users to be created with email-subscriptions to our notifications enabled |
225 | $userOptionsManager->setOption( $user, 'echo-subscriptions-email-dt-subscription', true ); |
226 | // The auto topic subscription feature is disabled by default for existing users, but |
227 | // we enable it for new users (T294398). |
228 | // This can only occur when the feature is available for everyone; when it's in beta, |
229 | // the new user won't have the beta enabled, so it'll never be available here. |
230 | if ( HookUtils::isFeatureAvailableToUser( $user, HookUtils::AUTOTOPICSUB ) ) { |
231 | $userOptionsManager->setOption( $user, 'discussiontools-' . HookUtils::AUTOTOPICSUB, 1 ); |
232 | } |
233 | } |
234 | |
235 | } |