Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialNotifyTranslators
0.00% covered (danger)
0.00%
0 / 121
0.00% covered (danger)
0.00%
0 / 11
420
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
 getMessagePrefix
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDisplayFormat
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 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 getFormFields
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 1
12
 getTranslatablePages
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 getSourceLanguage
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 onSubmit
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
42
 onSuccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace MediaWiki\Extension\TranslationNotifications;
5
6use ErrorPageError;
7use JobQueueGroup;
8use LogicException;
9use MediaWiki\Extension\Translate\MessageGroupProcessing\MessageGroups;
10use MediaWiki\Extension\Translate\PageTranslation\TranslatablePage;
11use MediaWiki\Extension\TranslationNotifications\Jobs\TranslationNotificationsSubmitJob;
12use MediaWiki\Extension\TranslationNotifications\Utilities\LanguageSet;
13use MediaWiki\Extension\TranslationNotifications\Utilities\NotificationMessageBuilder;
14use MediaWiki\HTMLForm\HTMLForm;
15use MediaWiki\Languages\LanguageNameUtils;
16use MediaWiki\SpecialPage\FormSpecialPage;
17use MediaWiki\Status\Status;
18use MediaWiki\Title\Title;
19use WikiPageMessageGroup;
20
21/**
22 * Form for translation managers to send a notification
23 * to registered translators.
24 *
25 * @author Amir E. Aharoni
26 * @author Santhosh Thottingal
27 * @author Niklas Laxström
28 * @author Siebrand Mazeland
29 * @copyright Copyright © 2012, Amir E. Aharoni, Santhosh Thottingal
30 * @license GPL-2.0-or-later
31 * @ingroup SpecialPage TranslateSpecialPage
32 */
33class SpecialNotifyTranslators extends FormSpecialPage {
34    public static string $right = 'translate-manage';
35    private LanguageNameUtils $languageNameUtils;
36    private JobQueueGroup $jobQueueGroup;
37
38    public function __construct(
39        LanguageNameUtils $languageNameUtils,
40        JobQueueGroup $jobQueueGroup
41    ) {
42        parent::__construct( 'NotifyTranslators', self::$right );
43        $this->languageNameUtils = $languageNameUtils;
44        $this->jobQueueGroup = $jobQueueGroup;
45    }
46
47    public function doesWrites(): bool {
48        return true;
49    }
50
51    protected function getGroupName(): string {
52        return 'translation';
53    }
54
55    protected function getMessagePrefix(): string {
56        return 'translationnotifications';
57    }
58
59    protected function getDisplayFormat(): string {
60        return 'ooui';
61    }
62
63    protected function alterForm( HTMLForm $form ): void {
64        $form->setId( 'notifytranslators-form' );
65        $form->setSubmitID( 'translationnotifications-send-notification-button' );
66        $form->setSubmitTextMsg( 'translationnotifications-send-notification-button' );
67    }
68
69    /**
70     * Get the form fields for use by the HTMLForm.
71     * We also set up the JavaScript needed on the form here.
72     *
73     * @return array
74     * @throws ErrorPageError if there is no translatable page on this wiki
75     */
76    protected function getFormFields(): array {
77        $this->getOutput()->addModules( 'ext.translationnotifications.notifytranslators' );
78
79        $formFields = [];
80
81        $pages = $this->getTranslatablePages();
82        if ( count( $pages ) === 0 ) {
83            throw new ErrorPageError( 'notifytranslators',
84                'translationnotifications-error-no-translatable-pages' );
85        }
86
87        $formFields['TranslatablePage'] = [
88            'name' => 'tpage',
89            'id' => 'mw-tns-group-selector',
90            'type' => 'select',
91            'label-message' => [ 'translationnotifications-translatablepage-title' ],
92            'options' => $pages,
93            'cssclass' => 'mw-tns-translatable-page-selector',
94            'default' => '',
95            'required' => true
96        ];
97
98        $languages = array_flip(
99            $this->languageNameUtils->getLanguageNames( $this->getLanguage()->getCode() )
100        );
101
102        $formFields['LanguageSet'] = [
103            'name' => 'notifiable-languages-options',
104            'type' => 'radio',
105            'default' => LanguageSet::ALL,
106            'label-message' => 'translationnotifications-requested-languages-label',
107            'options-messages' => [
108                'translationnotifications-languages-to-notify-all-label'
109                    => LanguageSet::ALL,
110                'translationnotifications-languages-to-notify-only-selected-label'
111                    => LanguageSet::SOME,
112                'translationnotifications-languages-to-notify-all-except-label'
113                    => LanguageSet::ALL_EXCEPT_SOME
114            ]
115        ];
116
117        // Selected languages input box
118        $formFields['SelectedLanguages'] = [
119            'type' => 'multiselect',
120            'dropdown' => true,
121            'label-message' => 'translationnotifications-languages-to-notify-label',
122            'help-message' => 'translationnotifications-languages-to-notify-label-help-message',
123            'options' => $languages,
124            'hide-if' => [ '===', 'LanguageSet', (string)LanguageSet::ALL ]
125        ];
126
127        // Priority dropdown
128        $priorityOptions = [];
129        $priorities = [ 'unset', 'high', 'medium', 'low' ];
130
131        foreach ( $priorities as $priority ) {
132            $priorityMessage =
133                NotificationMessageBuilder::getPriorityMessage( $priority )
134                    ->setContext( $this->getContext() )->text();
135            $priorityOptions[$priorityMessage] = $priority;
136        }
137
138        $formFields['Priority'] = [
139            'type' => 'select',
140            'label-message' => [ 'translationnotifications-priority' ],
141            'options' => $priorityOptions,
142            'default' => 'unset',
143        ];
144
145        // Deadline date input box with datepicker
146        $formFields['DeadlineDate'] = [
147            'type' => 'date',
148            'min' => date( 'Y-m-d' ),
149            'label-message' => 'translationnotifications-deadline-label',
150            'help-message' => 'translationnotifications-deadline-help-message',
151        ];
152
153        // Custom text
154        $formFields['NotificationText'] = [
155            'type' => 'textarea',
156            'rows' => 20,
157            'label-message' => 'emailmessage',
158        ];
159
160        return $formFields;
161    }
162
163    protected function getTranslatablePages(): array {
164        $translatablePages = MessageGroups::getGroupsByType( WikiPageMessageGroup::class );
165        usort( $translatablePages, [ MessageGroups::class, 'groupLabelSort' ] );
166
167        $options = [
168            // Default value
169            '' => ''
170        ];
171        foreach ( $translatablePages as $page ) {
172            if ( MessageGroups::getPriority( $page ) === 'discouraged' ) {
173                continue;
174            }
175            $options[$page->getTitle()->getPrefixedText()] = $page->getId();
176        }
177
178        return $options;
179    }
180
181    private function getSourceLanguage( Title $title ): string {
182        $translatablePage = TranslatablePage::newFromTitle( $title );
183        return $translatablePage->getMessageGroup()->getSourceLanguage();
184    }
185
186    public function onSubmit( array $formData ): Status {
187        $group = MessageGroups::getGroup( $formData['TranslatablePage'] );
188        if ( !$group instanceof WikiPageMessageGroup ) {
189            throw new LogicException( 'Cannot send notification to non-translatable pages.' );
190        }
191
192        $translatablePageTitle = $group->getTitle();
193        $notificationText = $formData['NotificationText'];
194        $priority = $formData['Priority'];
195        $deadlineDate = $formData['DeadlineDate'];
196        $selectedLanguages = $formData['SelectedLanguages'];
197        $pageSourceLangCode = $this->getSourceLanguage( $translatablePageTitle );
198        $notificationLanguages = [];
199
200        // The default is not to specify any languages and to send the notification to speakers of
201        // all the languages except the source language. When no languages are specified,
202        // an empty string will be sent here and an appropriate message will be shown in the log.
203        if ( count( $selectedLanguages ) ) {
204            // Filter out the source language
205            foreach ( $selectedLanguages as $langCode ) {
206                if ( $langCode !== $pageSourceLangCode ) {
207                    $notificationLanguages[] = $langCode;
208                }
209            }
210
211            if ( $notificationLanguages === [] ) {
212                return Status::newFatal( 'translationnotifications-sourcelang-only' );
213            }
214        }
215        $languageSet = new LanguageSet( (int)$formData['LanguageSet'] );
216
217        $requestData = [
218            'notificationText' => $notificationText,
219            'priority' => $priority,
220            'deadlineDate' => $deadlineDate,
221            'selectedLanguages' => $selectedLanguages,
222            'languageSet' => $languageSet->jsonSerialize(),
223        ];
224
225        $job = TranslationNotificationsSubmitJob::newJob(
226            $translatablePageTitle,
227            $requestData,
228            $this->getUser()->getId(),
229            $this->getLanguage()->getCode()
230        );
231
232        $this->jobQueueGroup->push( $job );
233        return Status::newGood();
234    }
235
236    public function onSuccess(): void {
237        $this->getOutput()->addWikiMsg( 'translationnotifications-submit-ok' );
238    }
239}