Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
TranslatePage
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 5
552
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
 execute
0.00% covered (danger)
0.00%
0 / 114
0.00% covered (danger)
0.00%
0 / 1
272
 getTitle
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 showLanguageSelector
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
6
 doSubmit
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace MediaWiki\Extension\SecurePoll\Pages;
4
5use MediaWiki\Extension\SecurePoll\Exceptions\InvalidDataException;
6use MediaWiki\Extension\SecurePoll\SpecialSecurePoll;
7use MediaWiki\Extension\SecurePoll\TranslationRepo;
8use MediaWiki\Languages\LanguageNameUtils;
9use MediaWiki\Linker\Linker;
10use MediaWiki\MediaWikiServices;
11use MediaWiki\Title\Title;
12use MediaWiki\WikiMap\WikiMap;
13use Message;
14
15/**
16 * A SecurePoll subpage for translating election messages.
17 */
18class TranslatePage extends ActionPage {
19
20    /** @var bool|null */
21    public $isAdmin;
22
23    /** @var LanguageNameUtils */
24    private $languageNameUtils;
25
26    /** @var TranslationRepo */
27    private $translationRepo;
28
29    /**
30     * @param SpecialSecurePoll $specialPage
31     * @param LanguageNameUtils $languageNameUtils
32     * @param TranslationRepo $translationRepo
33     */
34    public function __construct(
35        SpecialSecurePoll $specialPage,
36        LanguageNameUtils $languageNameUtils,
37        TranslationRepo $translationRepo
38    ) {
39        parent::__construct( $specialPage );
40        $this->languageNameUtils = $languageNameUtils;
41        $this->translationRepo = $translationRepo;
42    }
43
44    /**
45     * Execute the subpage.
46     * @param array $params Array of subpage parameters.
47     */
48    public function execute( $params ) {
49        $out = $this->specialPage->getOutput();
50        $request = $this->specialPage->getRequest();
51        $out->enableOOUI();
52
53        if ( !count( $params ) ) {
54            $out->addWikiMsg( 'securepoll-too-few-params' );
55
56            return;
57        }
58
59        $electionId = intval( $params[0] );
60        $this->election = $this->context->getElection( $electionId );
61        if ( !$this->election ) {
62            $out->addWikiMsg( 'securepoll-invalid-election', $electionId );
63
64            return;
65        }
66        $this->initLanguage( $this->specialPage->getUser(), $this->election );
67        $out->setPageTitleMsg( $this->msg( 'securepoll-translate-title', $this->election->getMessage( 'title' ) ) );
68
69        $jumpUrl = $this->election->getProperty( 'jump-url' );
70        if ( $jumpUrl ) {
71            $jumpId = $this->election->getProperty( 'jump-id' );
72            if ( !$jumpId ) {
73                throw new InvalidDataException( 'Configuration error: no jump-id' );
74            }
75            $jumpUrl .= "/edit/$jumpId";
76            if ( count( $params ) > 1 ) {
77                $jumpUrl .= '/' . implode( '/', array_slice( $params, 1 ) );
78            }
79
80            $wiki = $this->election->getProperty( 'main-wiki' );
81            if ( $wiki ) {
82                $wiki = WikiMap::getWikiName( $wiki );
83            } else {
84                $wiki = $this->msg( 'securepoll-edit-redirect-otherwiki' )->text();
85            }
86
87            $out->addWikiMsg(
88                'securepoll-edit-redirect',
89                Message::rawParam( Linker::makeExternalLink( $jumpUrl, $wiki ) )
90            );
91
92            return;
93        }
94
95        $this->isAdmin = $this->election->isAdmin( $this->specialPage->getUser() );
96
97        $primary = $this->election->getLanguage();
98        $secondary = $request->getVal( 'secondary_lang' );
99        if ( $secondary !== null ) {
100            # Language selector submitted: redirect to the subpage
101            $out->redirect( $this->getTitle( $secondary )->getFullURL() );
102
103            return;
104        }
105
106        if ( !isset( $params[1] ) ) {
107            # No language selected, show the selector
108            $this->showLanguageSelector( $primary );
109            $sourceConfig = MediaWikiServices::getInstance()->getMainConfig()
110            ->get( 'SecurePollTranslationImportSourceUrl' );
111            $out->addJsConfigVars( 'SecurePollTranslationImportSourceUrl', $sourceConfig );
112
113            $out->addJsConfigVars( 'SecurePollSubPage', 'translate' );
114            $out->addModules( 'ext.securepoll.htmlform' );
115            return;
116        }
117
118        $secondary = $params[1];
119        $inLanguage = $this->specialPage->getLanguage()->getCode();
120        $primaryName = $this->languageNameUtils->getLanguageName( $primary, $inLanguage );
121        $secondaryName = $this->languageNameUtils->getLanguageName( $secondary, $inLanguage );
122        if ( $secondaryName === '' ) {
123            $out->addWikiMsg( 'securepoll-invalid-language', $secondary );
124            $this->showLanguageSelector( $primary );
125            return;
126        }
127
128        # Set a subtitle to return to the language selector
129        $this->specialPage->setSubtitle(
130            [
131                $this->getTitle(),
132                $this->msg(
133                    'securepoll-translate-title',
134                    $this->election->getMessage( 'title' )
135                )->text()
136            ]
137        );
138
139        # If the request was posted, do the submission
140        if ( $request->wasPosted() && $request->getVal( 'action' ) == 'submit' ) {
141            $this->doSubmit( $secondary );
142            return;
143        }
144
145        # Show the form
146        $action = $this->getTitle( $secondary )->getLocalURL( 'action=submit' );
147        $form = new \OOUI\FormLayout( [ 'method' => 'post', 'action' => $action ] );
148
149        $table = new \OOUI\Tag( 'table' );
150        $table->addClasses( [ 'mw-datatable', 'TablePager', 'securepoll-trans-table' ] )->appendContent(
151            ( new \OOUI\Tag( 'thead' ) )->appendContent( ( new \OOUI\Tag( 'tr' ) )->appendContent(
152                ( new \OOUI\Tag( 'th' ) )->appendContent( $this->msg( 'securepoll-header-trans-id' ) ),
153                ( new \OOUI\Tag( 'th' ) )->appendContent( $primaryName ),
154                ( new \OOUI\Tag( 'th' ) )->appendContent( $secondaryName )
155            ) )
156        );
157        $tbody = new \OOUI\Tag( 'tbody' );
158        $table->appendContent( $tbody );
159
160        $entities = array_merge( [ $this->election ], $this->election->getDescendants() );
161        foreach ( $entities as $entity ) {
162            $entityName = $entity->getType() . '(' . $entity->getId() . ')';
163            foreach ( $entity->getMessageNames() as $messageName ) {
164                $tbody->appendContent( ( new \OOUI\Tag( 'tr' ) )->appendContent(
165                    ( new \OOUI\Tag( 'td' ) )->addClasses( [ 'trans-id' ] )
166                            ->appendContent( "$entityName/$messageName" ),
167                    ( new \OOUI\Tag( 'td' ) )->addClasses( [ 'trans-origin' ] )->appendContent( new \OOUI\HtmlSnippet(
168                        nl2br( htmlspecialchars( $entity->getRawMessage( $messageName, $primary ) ) )
169                    ) ),
170                    ( new \OOUI\Tag( 'td' ) )->addClasses( [ 'trans-lang' ] )->appendContent(
171                        new \OOUI\MultilineTextInputWidget( [
172                            'name' => 'trans_' . $entity->getId() . '_' . $messageName,
173                            'value' => $entity->getRawMessage( $messageName, $secondary ),
174                            'classes' => [ 'securepoll-translate-box' ],
175                            'readonly' => !$this->isAdmin,
176                            'autosize' => true
177                        ] )
178                    ) )
179                );
180            }
181        }
182
183        $fields = new \OOUI\FieldsetLayout();
184
185        $fields->addItems( [ new \OOUI\Element( [ 'content' => [ $table ] ] ) ] );
186
187        if ( $this->isAdmin && $this->specialPage->getConfig()->get( 'SecurePollUseNamespace' ) ) {
188            $fields->addItems( [ new \OOUI\FieldLayout( new \OOUI\TextInputWidget( [
189                'name' => 'comment',
190                'maxlength' => 250,
191            ] ), [
192                'label' => $this->msg( 'securepoll-translate-label-comment' ),
193                'align' => 'top',
194            ] ) ] );
195        }
196
197        $fields->addItems( [ new \OOUI\FieldLayout( new \OOUI\ButtonInputWidget( [
198            'label' => $this->msg( 'securepoll-submit-translate' )->text(),
199            'flags' => [ 'primary', 'progressive' ],
200            'type' => 'submit',
201            'disabled' => !$this->isAdmin,
202        ] ) ) ] );
203
204        $form->appendContent( $fields );
205
206        $out->addHTML( $form );
207    }
208
209    /**
210     * @param string|false $lang
211     * @return Title
212     */
213    public function getTitle( $lang = false ) {
214        $subpage = 'translate/' . $this->election->getId();
215        if ( $lang !== false ) {
216            $subpage .= '/' . $lang;
217        }
218
219        return $this->specialPage->getPageTitle( $subpage );
220    }
221
222    /**
223     * Show a language selector to allow the user to choose the language to
224     * translate.
225     * @param string $selectedCode
226     */
227    public function showLanguageSelector( $selectedCode ) {
228        $languages = $this->languageNameUtils->getLanguageNames();
229        ksort( $languages );
230
231        $apiEndpoint = $this->specialPage->getConfig()->get( 'SecurePollTranslationImportSourceUrl' );
232
233        $form = new \OOUI\FormLayout( [
234            'action' => $this->getTitle( false )->getLocalURL(),
235            'method' => 'get',
236            'items' => [ new \OOUI\FieldsetLayout( [ 'items' => [
237                new \OOUI\HorizontalLayout( [
238                    'id' => 'sp-translation-selection',
239                    'items' => [
240                        new \OOUI\DropdownInputWidget( [
241                            'name' => 'secondary_lang',
242                            'value' => $selectedCode,
243                            'options' => array_map( static function ( $code, $name ) {
244                                return [
245                                    'label' => "$code - $name",
246                                    'data' => $code,
247                                ];
248                            }, array_keys( $languages ), $languages )
249                        ] ),
250                        new \OOUI\ButtonInputWidget( [
251                            'label' => $this->msg( 'securepoll-submit-select-lang' )->text(),
252                            'flags' => [ 'primary' ],
253                            'type' => 'submit',
254                        ] )
255                    ]
256                ] )
257            ] ] ) ]
258        ] );
259
260        if ( $apiEndpoint !== '' ) {
261            $form->addItems( [
262                new \OOUI\FieldLayout(
263                    new \OOUI\LabelWidget( [
264                        'label' => $this->msg( 'securepoll-subpage-translate-info', $apiEndpoint )->text()
265                    ] )
266                ),
267                new \OOUI\FieldLayout(
268                    new \OOUI\ButtonInputWidget( [
269                        'id' => 'import-trans-btn',
270                        'infusable' => true,
271                        'label' => $this->msg( 'securepoll-translate-import-button-label' )->text(),
272                        'flags' => [ 'primary', 'progressive' ],
273                        'disabled' => !$this->isAdmin
274                    ] )
275                )
276            ], 0 );
277        }
278        $this->specialPage->getOutput()->addHTML( $form );
279    }
280
281    /**
282     * Submit message text changes.
283     * @param string $secondary
284     */
285    public function doSubmit( $secondary ) {
286        $out = $this->specialPage->getOutput();
287
288        if ( !$this->isAdmin ) {
289            $out->addWikiMsg( 'securepoll-need-admin' );
290            return;
291        }
292
293        $request = $this->specialPage->getRequest();
294        $data = $request->getValues();
295
296        $this->translationRepo->setTranslation(
297            $this->election,
298            $data,
299            $secondary,
300            $this->specialPage->getContext()->getUser(),
301            $this->specialPage->getContext()->getRequest()->getText( 'comment' )
302        );
303
304        $out->redirect( $this->getTitle( $secondary )->getFullURL() );
305    }
306}