Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 289
0.00% covered (danger)
0.00%
0 / 8
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialCreateCollaborationHub
0.00% covered (danger)
0.00%
0 / 289
0.00% covered (danger)
0.00%
0 / 8
1056
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
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
 execute
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
42
 showForm
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
2
 getFormFields
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 1
90
 getOptions
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 doSubmit
0.00% covered (danger)
0.00%
0 / 93
0.00% covered (danger)
0.00%
0 / 1
132
 onSuccess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3/**
4 * Form to create Collaboration Hubs + migrations/imports/clones
5 * Based on code from MassMessage/SpecialMovePage
6 *
7 * @file
8 */
9
10class SpecialCreateCollaborationHub extends SpecialPage {
11    /** @var int */
12    protected $titleNs;
13
14    /** @var string */
15    protected $titleText;
16
17    /** @var string */
18    protected $displayName;
19
20    /** @var string */
21    protected $icon;
22
23    /** @var string */
24    protected $colour;
25
26    /** @var string */
27    protected $introduction;
28
29    /** @var bool */
30    protected $overwrite;
31
32    /**
33     * @param string $name
34     * @param string $right
35     */
36    public function __construct( $name = 'CreateCollaborationHub',
37        $right = 'createpage'
38    ) {
39        // Note: The right check is primarily for UI. There are
40        // additional checks later on.
41        parent::__construct( $name, $right );
42    }
43
44    public function doesWrites() {
45        return true;
46    }
47
48    /**
49     * @param string $par
50     */
51    public function execute( $par ) {
52        $user = $this->getUser();
53
54        // More thorough permissions checks in doSubmit, but for now...
55        if ( !$user->isAllowed( 'createpage' ) ) {
56            throw new PermissionsError( 'createpage' );
57        }
58        if ( !$user->isAllowed( 'editcontentmodel' ) ) {
59            throw new PermissionsError( 'editcontentmodel' );
60        }
61
62        $this->useTransactionalTimeLimit();
63
64        $this->checkReadOnly();
65        $this->setHeaders();
66        $this->outputHeader();
67
68        $request = $this->getRequest();
69        $out = $this->getContext()->getOutput();
70
71        if ( $request->getVal( 'confirm' ) ) {
72            $out->wrapWikiMsg(
73                "<div class=\"warningbox\">\n$1\n</div>",
74                'collaborationkit-createhub-confirmheader'
75            );
76        }
77
78        $this->titleText = $request->getText( 'titletext' );
79        $this->titleNs = $request->getInt( 'titlens', 0 );
80        $this->displayName = $request->getText( 'displayname' );
81        $this->icon = $request->getText( 'icon' );
82        $this->colour = $request->getText( 'colour' );
83        $this->introduction = $request->getText( 'introduction' );
84        $this->overwrite = $request->getBool( 'overwrite' );
85
86        if ( $request->getVal( 'action' ) == 'submit' && $request->wasPosted() ) {
87            $this->doSubmit();
88        } else {
89            $this->showForm();
90        }
91    }
92
93    /**
94     * Show the form
95     */
96    private function showForm() {
97        $out = $this->getOutput();
98
99        $out->addModules( [
100            'ext.CollaborationKit.hubtheme'
101        ] );
102        $out->addModuleStyles( [
103            'mediawiki.special',
104            'ext.CollaborationKit.edit.styles',
105            'ext.CollaborationKit.createhub.styles'
106        ] );
107        $out->addJsConfigVars(
108            'wgCollaborationKitColourList',
109            CollaborationHubContent::getThemeColours()
110        );
111        // For some reason we're not using the standard special page intro
112        // (formspecialpage didn't use it), so we gotta manually add our own...
113        $out->addWikiMsg( 'createcollaborationhub-text' );
114        $out->enableOOUI();
115
116        // Not actually correct for FormSpecialPage anymore, but still nice structure...
117        $fields = $this->getFormFields();
118
119        $fieldset1 = new OOUI\FieldsetLayout( [
120            'classes' => [
121                'mw-ck-hub-topform',
122                'ck-createcollaborationhub-setup'
123            ],
124            'items' => $fields[0],
125        ] );
126        $fieldset2 = new OOUI\FieldsetLayout( [
127            'classes' => [ 'ck-createcollaborationhub-block' ],
128            'items' => $fields[1],
129        ] );
130
131        $form = new OOUI\FormLayout( [
132            'method' => 'post',
133            'action' => $this->getPageTitle()->getLocalURL( 'action=submit' ),
134            'classes' => [ 'ck-createcollaborationhub' ],
135        ] );
136        $form->appendContent( $fieldset1, $fieldset2 );
137
138        $out->addHTML(
139            new OOUI\PanelLayout( [
140                'expanded' => false,
141                'padded' => false,
142                'framed' => false,
143                'content' => $form,
144            ] )
145        );
146    }
147
148    /**
149     * @return array
150     */
151    protected function getFormFields() {
152        $allowedNamespaces = $this->getConfig()
153            ->get( 'CollaborationListAllowedNamespaces' );
154        $excludeNamespaces = [];
155        foreach ( array_keys( $this->getLanguage()->getNamespaces() ) as $option ) {
156            if ( !isset( $allowedNamespaces[$option] ) || !$allowedNamespaces[$option] ) {
157                $excludeNamespaces[] = $option;
158            }
159        }
160
161        $titleInput = [
162            'namespace' => [
163                'classes' => [ 'mw-ck-namespace-input' ],
164                'name' => 'titlens',
165                'exclude' => $excludeNamespaces,
166                'required' => true
167            ],
168            'title' => [
169                'classes' => [ 'mw-ck-title-input' ],
170                'placeholder' => $this->msg( 'collaborationkit-createhub-title-placeholder' )->text(),
171                'name' => 'titletext',
172                'suggestions' => false,
173                'required' => true,
174                'value' => $this->titleText
175            ],
176            'infusable' => true
177        ];
178
179        // Our preference is the Project namespace
180        if ( $this->titleNs !== null && array_key_exists( $this->titleNs, $allowedNamespaces ) ) {
181            $titleInput['namespace']['value'] = $this->titleNs;
182        } elseif ( array_key_exists( NS_PROJECT, $allowedNamespaces ) ) {
183            $titleInput['namespace']['value'] = NS_PROJECT;
184        }
185
186        $fields = [ [], [] ];
187
188        $fields[0][] = new OOUI\FieldLayout(
189            new MediaWiki\Widget\ComplexTitleInputWidget( $titleInput ),
190            [
191                'label' => $this->msg( 'collaborationkit-createhub-title' )->text(),
192                'align' => 'top',
193                'classes' => [ 'mw-ck-title-input' ],
194                'helpInline' => true,
195                'help' => $this->msg( 'collaborationkit-createhub-title-help' )->text(),
196            ]
197        );
198
199        $fields[0][] = new OOUI\FieldLayout(
200            new OOUI\TextInputWidget( [
201                // Display name can be different from page title
202                'name' => 'displayname',
203                'value' => $this->displayName
204            ] ),
205            [
206                'classes' => [ 'mw-ck-display-input' ],
207                'label' => $this->msg( 'collaborationkit-hubedit-displayname' )->text(),
208                'helpInline' => true,
209                'help' => new OOUI\HtmlSnippet(
210                    $this->msg( 'collaborationkit-hubedit-displayname-help' )->parse()
211                ),
212                'align' => 'top',
213            ]
214        );
215        $fields[0][] = new OOUI\FieldLayout(
216            new OOUI\TextInputWidget( [
217                // Display name can be different from page title
218                'name' => 'icon',
219                'value' => $this->icon
220            ] ),
221            [
222                'classes' => [ 'mw-ck-hub-image-input' ],
223                'label' => $this->msg( 'collaborationkit-hubedit-image' )->text(),
224                'helpInline' => true,
225                'help' => new OOUI\HtmlSnippet( $this->msg( 'collaborationkit-hubedit-image-help' )->parse() ),
226                'align' => 'top',
227            ]
228        );
229
230        // Colours for the hub styles
231        $colours = [];
232        foreach ( CollaborationHubContent::getThemeColours() as $colour ) {
233            $colours['collaborationkit-' . $colour] = $colour;
234        }
235
236        $fields[0][] = new OOUI\FieldLayout(
237            new OOUI\DropdownInputWidget( [
238                // Display name can be different from page title
239                'name' => 'colour',
240                'options' => $this->getOptions( $colours ),
241                'value' => $this->colour
242            ] ),
243            [
244                'label' => $this->msg( 'collaborationkit-hubedit-colour' )->text(),
245                'align' => 'top',
246                'classes' => [ 'mw-ck-colour-input' ],
247            ]
248        );
249
250        $fields[1][] = new OOUI\FieldLayout(
251            new OOUI\MultilineTextInputWidget( [
252                'name' => 'introduction',
253                'rows' => 5,
254                'placeholder' => $this->msg( 'collaborationkit-hubedit-introduction-placeholder' )->text(),
255                'value' => $this->introduction
256            ] ),
257            [
258                'label' => $this->msg( 'collaborationkit-hubedit-introduction' )->text(),
259                'align' => 'top',
260                'classes' => [ 'mw-ck-introduction-input' ]
261            ]
262        );
263
264        // This form can be used to overwrite existing pages, but the user must
265        // confirm first.
266        if ( $this->getRequest()->getVal( 'confirm' ) ) {
267            $fields[1][] = new OOUI\FieldLayout(
268                new OOUI\CheckboxInputWidget( [
269                    'name' => 'overwrite',
270                    'value' => '1'
271                ] ),
272                [
273                    'label' => $this->msg( 'collaborationkit-createhub-confirm' )->text(),
274                    'classes' => [ 'mw-ck-confirm-input' ],
275                    'align' => 'inline',
276                ]
277            );
278        }
279
280        $fields[1][] = new OOUI\FieldLayout(
281            new OOUI\ButtonInputWidget( [
282                'name' => 'submit',
283                'value' => 'submit',
284                'label' => $this->msg( 'collaborationkit-createhub-submit' )->text(),
285                'flags' => [ 'primary', 'progressive' ],
286                'type' => 'submit',
287            ] ),
288            [
289                'align' => 'top',
290            ]
291        );
292
293        return $fields;
294    }
295
296    /**
297     * Build and return the associative array for the content source field.
298     * @param array $mapping
299     * @return array
300     */
301    protected function getOptions( $mapping ) {
302        $options = [];
303        foreach ( $mapping as $msgKey => $option ) {
304            $options[] = [
305                'data' => $option,
306                'label' => $this->msg( $msgKey )->text()
307            ];
308        }
309        return $options;
310    }
311
312    /**
313     * @return Status
314     */
315    public function doSubmit() {
316        $title = Title::makeTitleSafe( $this->titleNs, $this->titleText );
317        $user = $this->getUser();
318        $permissionManager = MediaWiki\MediaWikiServices::getInstance()->getPermissionManager();
319
320        if ( !$title ) {
321            return Status::newFatal( 'collaborationkit-createhub-invalidtitle' );
322        }
323
324        // TODO: Consider changing to getUserPermissionsErrors for
325        // better error message. Possibly as a first step in constructor
326        // as the non-title specific error.
327        if (
328            !$permissionManager->userCan( 'editcontentmodel', $user, $title ) ||
329            !$permissionManager->userCan( 'edit', $user, $title )
330        ) {
331            return Status::newFatal( 'collaborationkit-createhub-nopermission' );
332        }
333
334        $context = $this->getContext();
335        // If a page already exists at the title, ask the user before over-
336        // writing the page.
337        if ( $title->exists() && !$this->overwrite ) {
338            $this->getOutput()->redirect(
339                SpecialPage::getTitleFor( 'CreateCollaborationHub' )->getFullURL( [
340                    'titletext' => $this->titleText,
341                    'titlens' => $this->titleNs,
342                    'displayname' => $this->displayName,
343                    'icon' => $this->icon,
344                    'colour' => $this->colour,
345                    'introduction' => $this->introduction,
346                    'confirm' => 1
347                ] )
348            );
349
350            return Status::newGood();
351        }
352
353        // Create member list
354        $memberListTitle = Title::newFromText(
355            $title->getFullText()
356            . '/'
357            . $this->msg( 'collaborationkit-hub-pagetitle-members' )
358                ->inContentLanguage()
359                ->plain()
360        );
361        if ( !$memberListTitle ) {
362            return Status::newFatal( 'collaborationkit-createhub-invalidtitle' );
363        }
364        $memberResult = CollaborationListContentHandler::postMemberList(
365            $memberListTitle,
366            $this->msg( 'collaborationkit-createhub-editsummary' )
367                ->inContentLanguage()
368                ->plain(),
369            $context
370        );
371
372        if ( !$memberResult->isGood() ) {
373            return $memberResult;
374        }
375
376        // Create announcements page
377        $announcementsTitle = Title::newFromText( $title->getFullText()
378            . '/'
379            . $this->msg( 'collaborationkit-hub-pagetitle-announcements' )
380            ->inContentLanguage()
381            ->plain()
382        );
383        if ( !$announcementsTitle ) {
384            return Status::newFatal( 'collaborationkit-createhub-invalidtitle' );
385        }
386
387        $der = new DerivativeContext( $context );
388        $request = new DerivativeRequest(
389            $context->getRequest(),
390            [
391                'action' => 'edit',
392                'title' => $announcementsTitle->getFullText(),
393                'text' => "* " . $context
394                    ->msg( 'collaborationkit-hub-announcements-initial' )
395                    ->inContentLanguage()
396                    ->plain()
397                    . " ~~~~~",
398                'summary' => $context
399                    ->msg( 'collaborationkit-createhub-editsummary' )
400                    ->inContentLanguage()
401                    ->plain(),
402                'token' => $context->getUser()->getEditToken(),
403            ],
404            true // Treat data as POSTed
405        );
406        $der->setRequest( $request );
407        try {
408            $api = new ApiMain( $der, true );
409            $api->execute();
410        } catch ( ApiUsageException $e ) {
411            return Status::newFatal(
412                $context->msg( 'collaborationkit-hub-edit-apierror',
413                $e->getMessageObject() )
414            );
415        }
416
417        // Now, to create the hub itself
418        $result = CollaborationHubContentHandler::edit(
419            $title,
420            $this->displayName,
421            $this->icon,
422            $this->colour,
423            $this->introduction,
424            '',
425            [],
426            $this
427                ->msg( 'collaborationkit-createhub-editsummary' )
428                ->inContentLanguage()
429                ->plain(),
430            $context
431        );
432
433        if ( !$result->isGood() ) {
434            return $result;
435        }
436
437        // Once all the pages we want to create are created, we send them to
438        // the first one
439        $this->getOutput()->redirect( $title->getFullURL() );
440        return Status::newGood();
441    }
442
443    public function onSuccess() {
444        // No-op: We have already redirected.
445    }
446}