Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 165
0.00% covered (danger)
0.00%
0 / 13
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialTranslatorSignup
0.00% covered (danger)
0.00%
0 / 165
0.00% covered (danger)
0.00%
0 / 13
1260
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 doesWrites
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getMessagePrefix
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 alterForm
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
2
 postHtml
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 getFormFields
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 1
156
 onSubmit
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 onSuccess
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 getOtherWikis
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
56
 getDisplayFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isUserUnsubscribed
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2/**
3 * Form for translators to register contact methods
4 *
5 * @file
6 * @author Niklas Laxström
7 * @author Amir E. Aharoni
8 * @author Santhosh Thottingal
9 * @author Siebrand Mazeland
10 * @copyright Copyright © 2012, Niklas Laxström
11 * @license GPL-2.0-or-later
12 */
13
14namespace MediaWiki\Extension\TranslationNotifications;
15
16use ExtensionRegistry;
17use HTMLForm;
18use LanguageCode;
19use MediaWiki\Extension\CentralAuth\User\CentralAuthUser;
20use MediaWiki\Extension\SiteMatrix\SiteMatrix;
21use MediaWiki\Html\Html;
22use MediaWiki\Languages\LanguageNameUtils;
23use MediaWiki\SpecialPage\FormSpecialPage;
24use MediaWiki\SpecialPage\SpecialPage;
25use MediaWiki\User\Options\UserOptionsManager;
26use MediaWiki\WikiMap\WikiMap;
27
28/**
29 * Form for translators to register contact methods
30 *
31 * @ingroup SpecialPage TranslateSpecialPage
32 */
33
34class SpecialTranslatorSignup extends FormSpecialPage {
35    /** @var UserOptionsManager */
36    private $userOptionsManager;
37
38    /** @var LanguageNameUtils */
39    private $languageNameUtils;
40
41    public function __construct(
42        UserOptionsManager $userOptionsManager,
43        LanguageNameUtils $languageNameUtils
44    ) {
45        parent::__construct( 'TranslatorSignup' );
46        $this->userOptionsManager = $userOptionsManager;
47        $this->languageNameUtils = $languageNameUtils;
48    }
49
50    public function doesWrites() {
51        return true;
52    }
53
54    protected function getGroupName(): string {
55        return 'translation';
56    }
57
58    /** @inheritDoc */
59    public function execute( $par ) {
60        $this->requireNamedUser();
61        parent::execute( $par );
62    }
63
64    protected function getMessagePrefix(): string {
65        return 'translationnotifications';
66    }
67
68    protected function alterForm( HTMLForm $form ): void {
69        $form->setWrapperLegend( false );
70        $form->setId( 'translationnotifications-form' );
71        $form->setSubmitID( 'translationnotifications-submit' );
72        $form->setSubmitTextMsg( 'translationnotifications-submit' );
73
74        $form->addButton( [
75            'name' => 'translationnotifications-unsubscribe',
76            'value' => 'unsubscribe',
77            'label-message' => 'translationnotifications-unsubscribe',
78            'attribs' => [ 'disabled' => $this->isUserUnsubscribed() ],
79            'flags' => 'destructive',
80        ] );
81        // Without the following code the translationnotifications-text appears on this page. See: T334371
82        $form->setHeaderHtml( '' );
83    }
84
85    protected function postHtml() {
86        $legalMsg = $this->getConfig()->get( 'TranslationNotificationsSignupLegalMessage' );
87        if ( $legalMsg ) {
88            // Show the legal text regarding the notifications.
89            // Do not show if value is empty or false.
90            return Html::warningBox( $this->msg( $legalMsg )->parseAsBlock() );
91        }
92        return '';
93    }
94
95    protected function getFormFields(): array {
96        $this->getOutput()->addModules( 'ext.translationnotifications.translatorsignup' );
97        $user = $this->getUser();
98
99        $m = [
100            'username' => [
101                'type' => 'info',
102                'label-message' => 'translationnotifications-username',
103                'default' => $user->getName(),
104                'section' => 'info',
105            ],
106        ];
107
108        if ( $user->isEmailConfirmed() ) {
109            if ( $this->userOptionsManager->getOption( $user, 'disablemail' ) ) {
110                $status = $this->msg( 'translationnotifications-email-disablemail' )->parse();
111            } else {
112                $status = $this->msg( 'translationnotifications-email-confirmed' )->parse();
113            }
114        } elseif ( trim( $user->getEmail() ) !== '' ) {
115            $confirmMail = $this->getLinkRenderer()->makeKnownLink(
116                SpecialPage::getTitleFor( 'Confirmemail' ),
117                $this->msg( 'emailconfirmlink' )->text()
118            );
119            $status = $this->msg( 'translationnotifications-email-unconfirmed' )
120                ->rawParams( $confirmMail )->parse();
121
122        } else {
123            $status = $this->msg( 'translationnotifications-email-notset' )->parse();
124        }
125
126        $m['emailstatus'] = [
127            'type' => 'info',
128            'label-message' => 'translationnotifications-emailstatus',
129            'default' => $status,
130            'section' => 'info',
131            'raw' => true,
132        ];
133
134        $languages = $this->languageNameUtils->getLanguageNames();
135        ksort( $languages );
136
137        $options = [];
138        foreach ( $languages as $code => $name ) {
139            $display = LanguageCode::bcp47( $code ) . ' - ' . $name;
140            $options[$display] = $code;
141        }
142
143        $options =
144            [ $this->msg( 'translationnotifications-nolang' )->plain() => '' ] + $options;
145
146        for ( $i = 1; $i < 4; $i++ ) {
147            $formatted = $this->getLanguage()->formatNum( $i );
148            $m["lang-$i"] = [
149                'type' => 'select',
150                'label-message' => [ 'translationnotifications-lang', $formatted ],
151                'section' => 'languages',
152                'options' => $options,
153                'default' => $this->userOptionsManager->getOption(
154                    $user,
155                    "translationnotifications-lang-$i"
156                ),
157            ];
158
159            if ( $i === 1 ) {
160                $m["lang-$i"]['default'] = $this->userOptionsManager->getOption(
161                    $user,
162                    "translationnotifications-lang-$i",
163                    $this->getLanguage()->getCode()
164                );
165                $m["lang-$i"]['required'] = true;
166            }
167        }
168
169        $config = $this->getConfig();
170        $contactMethods = $config->get( 'TranslationNotificationsContactMethods' );
171        foreach ( $contactMethods as $method => $value ) {
172            if ( $value === false ) {
173                continue;
174            }
175
176            // Give grep a chance to find the usages:
177            // translationnotifications-cmethod-email, translationnotifications-cmethod-talkpage,
178            // translationnotifications-cmethod-talkpage-elsewhere,
179            // translationnotifications-cmethod-feed
180            $m["cmethod-$method"] = [
181                'type' => 'check',
182                'label-message' => "translationnotifications-cmethod-$method",
183                'default' => $this->userOptionsManager->getOption(
184                    $user,
185                    "translationnotifications-cmethod-$method"
186                ),
187                'section' => 'contact',
188            ];
189
190            if ( $method === 'email' ) {
191                $m["cmethod-$method"]['disabled'] = !$user->canReceiveEmail();
192            }
193
194            $localInterwikis = $config->get( 'LocalInterwikis' );
195            if ( $method === 'talkpage-elsewhere' && count( $localInterwikis ) ) {
196                $m['cmethod-talkpage-elsewhere-loc'] = [
197                    'type' => 'select',
198                    'default' => $this->userOptionsManager->getOption(
199                        $user,
200                        'translationnotifications-cmethod-talkpage-elsewhere-loc'
201                    ),
202                    'section' => 'contact',
203                    'options' => $this->getOtherWikis(),
204                ];
205            }
206        }
207
208        $m['freq'] = [
209            'type' => 'radio',
210            'default' => $this->userOptionsManager->getOption(
211                $user,
212                'translationnotifications-freq',
213                'always'
214            ),
215            'section' => 'frequency',
216            'options' => [
217                $this->msg( 'translationnotifications-freq-always' )->escaped() => 'always',
218                $this->msg( 'translationnotifications-freq-week' )->escaped() => 'week',
219                $this->msg( 'translationnotifications-freq-month' )->escaped() => 'month',
220                $this->msg( 'translationnotifications-freq-weekly' )->escaped() => 'weekly',
221                $this->msg( 'translationnotifications-freq-monthly' )->escaped() => 'monthly',
222                $this->msg( 'translationnotifications-freq-none' )->escaped() => 'none',
223            ],
224        ];
225
226        return $m;
227    }
228
229    /**
230     * @param array $formData
231     * @return true
232     */
233    public function onSubmit( array $formData ) {
234        $user = $this->getUser()->getInstanceForUpdate();
235
236        if ( $this->getRequest()->getVal( 'translationnotifications-unsubscribe' ) !== null ) {
237            $this->userOptionsManager->setOption( $user, 'translationnotifications-freq', 'none' );
238
239            $user->saveSettings();
240            return true;
241        }
242
243        $this->userOptionsManager->setOption( $user, 'translationnotifications-lastactivity', wfTimestampNow() );
244        // @todo Needs input validation
245        foreach ( $formData as $key => $value ) {
246            $this->userOptionsManager->setOption( $user, "translationnotifications-$key", $value );
247        }
248        $user->saveSettings();
249        return true;
250    }
251
252    public function onSuccess() {
253        $out = $this->getOutput();
254        $out->addHTML(
255            Html::successBox(
256                $out->msg( 'translationnotifications-signup-success' )->plain()
257            )
258        );
259    }
260
261    /** @return array<string,string> */
262    protected function getOtherWikis(): array {
263        global $wgConf;
264        if ( !ExtensionRegistry::getInstance()->isLoaded( 'CentralAuth' ) ) {
265            return [];
266        }
267        $globalUser = CentralAuthUser::getInstance( $this->getUser() );
268        if ( !$globalUser->exists() ) {
269            return [];
270        }
271
272        $matrix = new SiteMatrix();
273        $wikis = [];
274        foreach ( $globalUser->listAttached() as $dbname ) {
275            // Skip inactive and special wikis
276            [ $site, $lang ] = $wgConf->siteFromDB( $dbname );
277            if ( $matrix->isClosed( $lang, $site )
278                || $matrix->isPrivate( $dbname )
279                || $matrix->isFishbowl( $dbname )
280            ) {
281                continue;
282            }
283
284            $wikis[WikiMap::getWikiName( $dbname )] = $dbname;
285        }
286
287        return $wikis;
288    }
289
290    protected function getDisplayFormat(): string {
291        return 'ooui';
292    }
293
294    private function isUserUnsubscribed(): bool {
295        $contactMethods = $this->getConfig()->get( 'TranslationNotificationsContactMethods' );
296        foreach ( $contactMethods as $method => $value ) {
297            if (
298                $this->userOptionsManager->getOption(
299                    $this->getUser(),
300                    "translationnotifications-cmethod-$method" )
301                ) {
302                return false;
303            }
304        }
305
306        return true;
307    }
308}