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