Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 162 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
SpecialEventDetails | |
0.00% |
0 / 162 |
|
0.00% |
0 / 5 |
380 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 138 |
|
0.00% |
0 / 1 |
240 | |||
outputErrorBox | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
createTab | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
2 | |||
getGroupName | |
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\DAO\WikiAwareEntity; |
8 | use MediaWiki\Extension\CampaignEvents\Event\ExistingEventRegistration; |
9 | use MediaWiki\Extension\CampaignEvents\Event\Store\EventNotFoundException; |
10 | use MediaWiki\Extension\CampaignEvents\Event\Store\IEventLookup; |
11 | use MediaWiki\Extension\CampaignEvents\FrontendModules\EventDetailsModule; |
12 | use MediaWiki\Extension\CampaignEvents\FrontendModules\EventDetailsParticipantsModule; |
13 | use MediaWiki\Extension\CampaignEvents\FrontendModules\FrontendModulesFactory; |
14 | use MediaWiki\Extension\CampaignEvents\MWEntity\CampaignsCentralUserLookup; |
15 | use MediaWiki\Extension\CampaignEvents\MWEntity\MWAuthorityProxy; |
16 | use MediaWiki\Extension\CampaignEvents\MWEntity\UserLinker; |
17 | use MediaWiki\Extension\CampaignEvents\MWEntity\UserNotGlobalException; |
18 | use MediaWiki\Extension\CampaignEvents\Organizers\OrganizersStore; |
19 | use MediaWiki\Extension\CampaignEvents\Participants\ParticipantsStore; |
20 | use MediaWiki\Extension\CampaignEvents\Permissions\PermissionChecker; |
21 | use MediaWiki\Extension\CampaignEvents\Utils; |
22 | use MediaWiki\Html\Html; |
23 | use MediaWiki\SpecialPage\SpecialPage; |
24 | use MediaWiki\WikiMap\WikiMap; |
25 | use OOUI\ButtonWidget; |
26 | use OOUI\HtmlSnippet; |
27 | use OOUI\IndexLayout; |
28 | use OOUI\MessageWidget; |
29 | use OOUI\TabPanelLayout; |
30 | use OOUI\Tag; |
31 | use Wikimedia\Message\IMessageFormatterFactory; |
32 | use Wikimedia\Message\MessageValue; |
33 | |
34 | class SpecialEventDetails extends SpecialPage { |
35 | public const PAGE_NAME = 'EventDetails'; |
36 | private const MODULE_STYLES = [ |
37 | 'oojs-ui.styles.icons-movement', |
38 | 'ext.campaignEvents.specialeventdetails.styles', |
39 | 'oojs-ui-widgets.styles' |
40 | ]; |
41 | |
42 | public const EVENT_DETAILS_PANEL = 'EventDetailsPanel'; |
43 | public const PARTICIPANTS_PANEL = 'ParticipantsPanel'; |
44 | public const EMAIL_PANEL = 'EmailPanel'; |
45 | public const STATS_PANEL = 'StatsPanel'; |
46 | |
47 | protected IEventLookup $eventLookup; |
48 | protected ?ExistingEventRegistration $event = null; |
49 | private ParticipantsStore $participantsStore; |
50 | private OrganizersStore $organizersStore; |
51 | private IMessageFormatterFactory $messageFormatterFactory; |
52 | private CampaignsCentralUserLookup $centralUserLookup; |
53 | private FrontendModulesFactory $frontendModulesFactory; |
54 | private PermissionChecker $permissionChecker; |
55 | |
56 | /** |
57 | * @param IEventLookup $eventLookup |
58 | * @param ParticipantsStore $participantsStore |
59 | * @param OrganizersStore $organizersStore |
60 | * @param IMessageFormatterFactory $messageFormatterFactory |
61 | * @param CampaignsCentralUserLookup $centralUserLookup |
62 | * @param FrontendModulesFactory $frontendModulesFactory |
63 | * @param PermissionChecker $permissionChecker |
64 | */ |
65 | public function __construct( |
66 | IEventLookup $eventLookup, |
67 | ParticipantsStore $participantsStore, |
68 | OrganizersStore $organizersStore, |
69 | IMessageFormatterFactory $messageFormatterFactory, |
70 | CampaignsCentralUserLookup $centralUserLookup, |
71 | FrontendModulesFactory $frontendModulesFactory, |
72 | PermissionChecker $permissionChecker |
73 | ) { |
74 | parent::__construct( self::PAGE_NAME ); |
75 | $this->eventLookup = $eventLookup; |
76 | $this->participantsStore = $participantsStore; |
77 | $this->organizersStore = $organizersStore; |
78 | $this->messageFormatterFactory = $messageFormatterFactory; |
79 | $this->centralUserLookup = $centralUserLookup; |
80 | $this->frontendModulesFactory = $frontendModulesFactory; |
81 | $this->permissionChecker = $permissionChecker; |
82 | } |
83 | |
84 | /** |
85 | * @inheritDoc |
86 | */ |
87 | public function execute( $par ) { |
88 | $this->setHeaders(); |
89 | if ( $par === null ) { |
90 | $this->outputErrorBox( 'campaignevents-event-details-no-event-id-provided' ); |
91 | return; |
92 | } |
93 | $eventID = (int)$par; |
94 | if ( (string)$eventID !== $par ) { |
95 | $this->outputErrorBox( 'campaignevents-event-details-invalid-id' ); |
96 | return; |
97 | } |
98 | try { |
99 | $this->event = $this->eventLookup->getEventByID( $eventID ); |
100 | } catch ( EventNotFoundException $_ ) { |
101 | $this->outputErrorBox( 'campaignevents-event-details-not-found' ); |
102 | return; |
103 | } |
104 | |
105 | if ( $this->event->getDeletionTimestamp() !== null ) { |
106 | $this->outputErrorBox( 'campaignevents-event-details-event-deleted' ); |
107 | return; |
108 | } |
109 | |
110 | $out = $this->getOutput(); |
111 | $language = $this->getLanguage(); |
112 | |
113 | $out->enableOOUI(); |
114 | $out->addModuleStyles( |
115 | array_merge( |
116 | self::MODULE_STYLES, |
117 | EventDetailsModule::MODULE_STYLES, |
118 | EventDetailsParticipantsModule::MODULE_STYLES, |
119 | UserLinker::MODULE_STYLES |
120 | ) |
121 | ); |
122 | |
123 | $this->addHelpLink( 'Extension:CampaignEvents' ); |
124 | |
125 | $out->addModules( [ 'ext.campaignEvents.specialeventdetails', 'oojs-ui-widgets' ] ); |
126 | |
127 | $eventID = $this->event->getID(); |
128 | $msgFormatter = $this->messageFormatterFactory->getTextFormatter( $language->getCode() ); |
129 | |
130 | try { |
131 | $centralUser = $this->centralUserLookup->newFromAuthority( new MWAuthorityProxy( $this->getAuthority() ) ); |
132 | $organizer = $this->organizersStore->getEventOrganizer( $eventID, $centralUser ); |
133 | $isParticipant = $this->participantsStore->userParticipatesInEvent( $eventID, $centralUser, true ); |
134 | } catch ( UserNotGlobalException $_ ) { |
135 | $organizer = null; |
136 | $isParticipant = false; |
137 | } |
138 | $isOrganizer = $organizer !== null; |
139 | $userCanEmailParticipants = false; |
140 | $wikiID = $this->event->getPage()->getWikiId(); |
141 | $isLocalWiki = $wikiID === WikiAwareEntity::LOCAL; |
142 | if ( $isLocalWiki ) { |
143 | $userCanEmailParticipants = $this->permissionChecker->userCanEmailParticipants( |
144 | new MWAuthorityProxy( $this->getAuthority() ), |
145 | $this->event->getID() |
146 | ); |
147 | } |
148 | $out->addJsConfigVars( [ |
149 | 'wgCampaignEventsEventID' => $eventID, |
150 | 'wgCampaignEventsShowEmailTab' => $userCanEmailParticipants, |
151 | ] ); |
152 | $out->setPageTitle( |
153 | $msgFormatter->format( |
154 | MessageValue::new( 'campaignevents-event-details-event' ) |
155 | ->params( $this->event->getName() ) |
156 | ) |
157 | ); |
158 | |
159 | if ( $isOrganizer ) { |
160 | // Special:MyEvents is not meaningful for participants, see T314879 |
161 | $backLink = new ButtonWidget( [ |
162 | 'framed' => false, |
163 | 'flags' => [ 'progressive' ], |
164 | 'label' => $msgFormatter->format( MessageValue::new( 'campaignevents-back-to-your-events' ) ), |
165 | 'href' => SpecialPage::getTitleFor( SpecialMyEvents::PAGE_NAME )->getLocalURL(), |
166 | 'icon' => 'arrowPrevious', |
167 | 'classes' => [ 'ext-campaignevents-eventdetails-back-btn' ] |
168 | ] ); |
169 | |
170 | $out->addHTML( $backLink ); |
171 | } |
172 | |
173 | $wikiName = WikiMap::getWikiName( Utils::getWikiIDString( $wikiID ) ); |
174 | if ( $isOrganizer && !$isLocalWiki ) { |
175 | $foreignDetailsURL = WikiMap::getForeignURL( |
176 | $wikiID, 'Special:' . self::PAGE_NAME . "/$eventID" |
177 | ); |
178 | |
179 | $messageWidget = new MessageWidget( [ |
180 | 'type' => 'notice', |
181 | 'label' => new HtmlSnippet( |
182 | $this->msg( 'campaignevents-event-details-page-nonlocal' ) |
183 | ->params( [ |
184 | $foreignDetailsURL, |
185 | $wikiName |
186 | ] )->parse() |
187 | ) |
188 | ] ); |
189 | $out->addHTML( $messageWidget ); |
190 | } |
191 | |
192 | $main = new IndexLayout( [ |
193 | 'infusable' => true, |
194 | 'expanded' => false, |
195 | 'framed' => false, |
196 | 'autoFocus' => false, |
197 | 'id' => 'ext-campaignevents-eventdetails-tabs' |
198 | ] ); |
199 | $eventDetailsModule = $this->frontendModulesFactory->newEventDetailsModule( $this->event, $language ); |
200 | $tabs = []; |
201 | $tabs[] = $this->createTab( |
202 | self::EVENT_DETAILS_PANEL, |
203 | $msgFormatter->format( MessageValue::new( 'campaignevents-event-details-tab-event-details' ) ), |
204 | $eventDetailsModule->createContent( |
205 | $this->getUser(), |
206 | $isOrganizer, |
207 | $isParticipant, |
208 | $wikiID, |
209 | $out |
210 | ) |
211 | ); |
212 | $eventParticipantsModule = $this->frontendModulesFactory->newEventDetailsParticipantsModule( |
213 | $language, |
214 | $this->getFullTitle()->getFullURL( [ 'tab' => self::STATS_PANEL ] ) |
215 | ); |
216 | $tabs[] = $this->createTab( |
217 | self::PARTICIPANTS_PANEL, |
218 | $msgFormatter->format( MessageValue::new( 'campaignevents-event-details-tab-participants' ) ), |
219 | $eventParticipantsModule->createContent( |
220 | $this->event, |
221 | $this->getUser(), |
222 | new MWAuthorityProxy( $this->getAuthority() ), |
223 | $isOrganizer, |
224 | $userCanEmailParticipants, |
225 | $isLocalWiki, |
226 | $out |
227 | ) |
228 | ); |
229 | if ( $userCanEmailParticipants ) { |
230 | $emailModule = $this->frontendModulesFactory->newEmailParticipantsModule(); |
231 | $tabs[] = $this->createTab( |
232 | self::EMAIL_PANEL, |
233 | $msgFormatter->format( MessageValue::new( 'campaignevents-event-details-tab-email' ) ), |
234 | $emailModule->createContent( $language ) |
235 | ); |
236 | } |
237 | |
238 | if ( $organizer && $isLocalWiki && $this->event->isPast() && $this->event->getParticipantQuestions() ) { |
239 | $statsModule = $this->frontendModulesFactory->newResponseStatisticsModule( $this->event, $language ); |
240 | $pageURL = $this->getPageTitle( (string)$this->event->getID() ) |
241 | ->getLocalURL( [ 'tab' => $this::STATS_PANEL ] ); |
242 | $tabs[] = $this->createTab( |
243 | self::STATS_PANEL, |
244 | $msgFormatter->format( MessageValue::new( 'campaignevents-event-details-tab-stats' ) ), |
245 | $statsModule->createContent( $organizer, $this->getContext(), $pageURL ) |
246 | ); |
247 | } |
248 | |
249 | $main->addTabPanels( $tabs ); |
250 | $selectedTab = $this->getRequest()->getRawVal( 'tab', self::EVENT_DETAILS_PANEL ); |
251 | $main->setTabPanel( $selectedTab ); |
252 | $out->addHTML( $main ); |
253 | } |
254 | |
255 | /** |
256 | * @param string $errorMsg |
257 | * @param mixed ...$msgParams |
258 | * @return void |
259 | */ |
260 | protected function outputErrorBox( string $errorMsg, ...$msgParams ): void { |
261 | $this->getOutput()->addHTML( Html::errorBox( |
262 | $this->msg( $errorMsg )->params( ...$msgParams )->parseAsBlock() |
263 | ) ); |
264 | } |
265 | |
266 | /** |
267 | * @param string $name |
268 | * @param string $label |
269 | * @param Tag $content |
270 | * @return TabPanelLayout |
271 | */ |
272 | private function createTab( string $name, string $label, Tag $content ): TabPanelLayout { |
273 | return new TabPanelLayout( |
274 | $name, |
275 | [ |
276 | 'id' => $name, |
277 | 'label' => $label, |
278 | 'expanded' => false, |
279 | 'tabItemConfig' => [ |
280 | 'href' => $this->getFullTitle()->getLinkURL( [ 'tab' => $name ] ) |
281 | ], |
282 | 'content' => $content |
283 | ] |
284 | ); |
285 | } |
286 | |
287 | /** |
288 | * @inheritDoc |
289 | */ |
290 | protected function getGroupName(): string { |
291 | return 'campaignevents'; |
292 | } |
293 | } |