Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 78 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
SpecialGenerateInvitationList | |
0.00% |
0 / 78 |
|
0.00% |
0 / 10 |
272 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
getFormFields | |
0.00% |
0 / 39 |
|
0.00% |
0 / 1 |
6 | |||
alterForm | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
onSubmit | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 | |||
onSuccess | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
makePageMapFromInput | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
2 | |||
getDisplayFormat | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getGroupName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
doesWrites | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | declare( strict_types=1 ); |
4 | |
5 | namespace MediaWiki\Extension\CampaignEvents\Special; |
6 | |
7 | use MediaWiki\Extension\CampaignEvents\Invitation\InvitationListGenerator; |
8 | use MediaWiki\Extension\CampaignEvents\Invitation\WorklistParser; |
9 | use MediaWiki\Extension\CampaignEvents\MWEntity\MWAuthorityProxy; |
10 | use MediaWiki\Extension\CampaignEvents\Permissions\PermissionChecker; |
11 | use MediaWiki\HTMLForm\HTMLForm; |
12 | use MediaWiki\Message\Message; |
13 | use MediaWiki\SpecialPage\FormSpecialPage; |
14 | use MediaWiki\SpecialPage\SpecialPage; |
15 | use MediaWiki\Status\Status; |
16 | use MediaWiki\WikiMap\WikiMap; |
17 | use RuntimeException; |
18 | use StatusValue; |
19 | |
20 | class SpecialGenerateInvitationList extends FormSpecialPage { |
21 | use InvitationFeatureAccessTrait; |
22 | |
23 | public const PAGE_NAME = 'GenerateInvitationList'; |
24 | |
25 | private PermissionChecker $permissionChecker; |
26 | private InvitationListGenerator $invitationListGenerator; |
27 | private WorklistParser $worklistParser; |
28 | |
29 | /** @var int|null ID of the newly-generated list. Only set upon successful form submission. */ |
30 | private ?int $listID = null; |
31 | |
32 | public function __construct( |
33 | PermissionChecker $permissionChecker, |
34 | InvitationListGenerator $invitationListGenerator, |
35 | WorklistParser $worklistParser |
36 | ) { |
37 | parent::__construct( self::PAGE_NAME ); |
38 | $this->permissionChecker = $permissionChecker; |
39 | $this->invitationListGenerator = $invitationListGenerator; |
40 | $this->worklistParser = $worklistParser; |
41 | } |
42 | |
43 | /** |
44 | * @inheritDoc |
45 | */ |
46 | public function execute( $par ): void { |
47 | $this->setHeaders(); |
48 | $this->outputHeader(); |
49 | $mwAuthority = new MWAuthorityProxy( $this->getAuthority() ); |
50 | $isEnabledAndPermitted = $this->checkInvitationFeatureAccess( |
51 | $this->getOutput(), |
52 | $mwAuthority |
53 | ); |
54 | if ( $isEnabledAndPermitted ) { |
55 | parent::execute( $par ); |
56 | } |
57 | } |
58 | |
59 | /** |
60 | * @inheritDoc |
61 | */ |
62 | protected function getFormFields(): array { |
63 | return [ |
64 | 'InvitationListName' => [ |
65 | 'type' => 'text', |
66 | 'label-message' => 'campaignevents-generateinvitationlist-name-field-label', |
67 | 'placeholder-message' => 'campaignevents-generateinvitationlist-name-field-placeholder', |
68 | 'filter-callback' => fn ( $name ) => trim( (string)$name ), |
69 | 'required' => true |
70 | ], |
71 | 'EventPage' => [ |
72 | 'type' => 'title', |
73 | 'exists' => true, |
74 | 'namespace' => NS_EVENT, |
75 | 'label-message' => 'campaignevents-generateinvitationlist-event-page-field-label', |
76 | 'placeholder-message' => 'campaignevents-generateinvitationlist-event-page-field-placeholder', |
77 | 'required' => false, |
78 | 'validation-callback' => function ( string $eventPage ): StatusValue { |
79 | if ( !$eventPage ) { |
80 | return StatusValue::newGood(); |
81 | } |
82 | return $this->invitationListGenerator->validateEventPage( |
83 | $eventPage, |
84 | new MWAuthorityProxy( $this->getAuthority() ) |
85 | ); |
86 | }, |
87 | ], |
88 | 'ArticleList' => [ |
89 | 'type' => 'textarea', |
90 | 'label-message' => 'campaignevents-generateinvitationlist-article-list-field-label', |
91 | 'placeholder-message' => 'campaignevents-generateinvitationlist-article-list-field-placeholder', |
92 | 'help-message' => [ |
93 | 'campaignevents-generateinvitationlist-article-list-field-help', |
94 | Message::numParam( WorklistParser::ARTICLES_LIMIT ) |
95 | ], |
96 | 'rows' => 10, |
97 | 'required' => true, |
98 | 'validation-callback' => function ( $worklist ): StatusValue { |
99 | return $this->worklistParser->parseWorklist( self::makePageMapFromInput( $worklist ) ); |
100 | } |
101 | ] |
102 | ]; |
103 | } |
104 | |
105 | /** |
106 | * @inheritDoc |
107 | */ |
108 | protected function alterForm( HTMLForm $form ): void { |
109 | $form->setSubmitTextMsg( 'campaignevents-generateinvitationlist-submit-button-text' ); |
110 | } |
111 | |
112 | /** |
113 | * @inheritDoc |
114 | */ |
115 | public function onSubmit( array $data ) { |
116 | $eventPage = $data['EventPage'] !== '' ? $data['EventPage'] : null; |
117 | $worklistStatus = $this->worklistParser->parseWorklist( self::makePageMapFromInput( $data['ArticleList'] ) ); |
118 | if ( !$worklistStatus->isGood() ) { |
119 | // This shouldn't actually happen in practice thanks to validation-callback |
120 | return Status::wrap( $worklistStatus ); |
121 | } |
122 | |
123 | $invitationListStatus = $this->invitationListGenerator->createIfAllowed( |
124 | $data['InvitationListName'], |
125 | $eventPage, |
126 | $worklistStatus->getValue(), |
127 | new MWAuthorityProxy( $this->getAuthority() ) |
128 | ); |
129 | if ( $invitationListStatus->isGood() ) { |
130 | $this->listID = $invitationListStatus->getValue(); |
131 | } |
132 | return Status::wrap( $invitationListStatus ); |
133 | } |
134 | |
135 | /** |
136 | * @inheritDoc |
137 | */ |
138 | public function onSuccess(): void { |
139 | if ( $this->listID === null ) { |
140 | throw new RuntimeException( "List ID is unset" ); |
141 | } |
142 | $invitationListPage = SpecialPage::getTitleFor( SpecialInvitationList::PAGE_NAME, (string)$this->listID ); |
143 | $this->getOutput()->redirect( $invitationListPage->getLocalURL() ); |
144 | } |
145 | |
146 | /** |
147 | * @param string $rawWorklist |
148 | * @return array<string,string[]> Maps wiki ID to a list of page titles. |
149 | */ |
150 | private static function makePageMapFromInput( string $rawWorklist ): array { |
151 | $pageList = array_filter( |
152 | array_map( 'trim', explode( "\n", $rawWorklist ) ), |
153 | static fn ( $line ) => $line !== '' |
154 | ); |
155 | return [ WikiMap::getCurrentWikiId() => $pageList ]; |
156 | } |
157 | |
158 | /** |
159 | * @inheritDoc |
160 | */ |
161 | protected function getDisplayFormat(): string { |
162 | return 'ooui'; |
163 | } |
164 | |
165 | /** |
166 | * @inheritDoc |
167 | */ |
168 | protected function getGroupName(): string { |
169 | return 'campaignevents'; |
170 | } |
171 | |
172 | /** |
173 | * @inheritDoc |
174 | */ |
175 | public function doesWrites(): bool { |
176 | return true; |
177 | } |
178 | } |