Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
88.00% covered (warning)
88.00%
66 / 75
71.43% covered (warning)
71.43%
5 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
UpdateEventRegistrationHandler
88.00% covered (warning)
88.00%
66 / 75
71.43% covered (warning)
71.43%
5 / 7
15.39
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 getParamSettings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBodyParamSettings
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 getSuccessResponse
33.33% covered (danger)
33.33%
3 / 9
0.00% covered (danger)
0.00%
0 / 1
5.67
 getExistingEvent
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 checkPermissions
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 createEventObject
91.89% covered (success)
91.89%
34 / 37
0.00% covered (danger)
0.00%
0 / 1
6.02
1<?php
2
3declare( strict_types=1 );
4
5namespace MediaWiki\Extension\CampaignEvents\Rest;
6
7use LogicException;
8use MediaWiki\Config\Config;
9use MediaWiki\DAO\WikiAwareEntity;
10use MediaWiki\Extension\CampaignEvents\Event\EditEventCommand;
11use MediaWiki\Extension\CampaignEvents\Event\EventFactory;
12use MediaWiki\Extension\CampaignEvents\Event\EventRegistration;
13use MediaWiki\Extension\CampaignEvents\Event\ExistingEventRegistration;
14use MediaWiki\Extension\CampaignEvents\Event\Store\IEventLookup;
15use MediaWiki\Extension\CampaignEvents\MWEntity\CampaignsCentralUserLookup;
16use MediaWiki\Extension\CampaignEvents\MWEntity\ICampaignsAuthority;
17use MediaWiki\Extension\CampaignEvents\MWEntity\WikiLookup;
18use MediaWiki\Extension\CampaignEvents\Organizers\OrganizersStore;
19use MediaWiki\Extension\CampaignEvents\Permissions\PermissionChecker;
20use MediaWiki\Extension\CampaignEvents\Questions\EventQuestionsRegistry;
21use MediaWiki\Extension\CampaignEvents\Questions\UnknownQuestionException;
22use MediaWiki\Rest\LocalizedHttpException;
23use MediaWiki\Rest\Response;
24use StatusValue;
25use Wikimedia\Message\MessageValue;
26use Wikimedia\ParamValidator\ParamValidator;
27
28class UpdateEventRegistrationHandler extends AbstractEditEventRegistrationHandler {
29    use EventIDParamTrait;
30
31    private IEventLookup $eventLookup;
32
33    public function __construct(
34        EventFactory $eventFactory,
35        PermissionChecker $permissionChecker,
36        EditEventCommand $editEventCommand,
37        OrganizersStore $organizersStore,
38        CampaignsCentralUserLookup $centralUserLookup,
39        EventQuestionsRegistry $eventQuestionsRegistry,
40        WikiLookup $wikiLookup,
41        Config $config,
42        IEventLookup $eventLookup
43    ) {
44        parent::__construct(
45            $eventFactory,
46            $permissionChecker,
47            $editEventCommand,
48            $organizersStore,
49            $centralUserLookup,
50            $eventQuestionsRegistry,
51            $wikiLookup,
52            $config
53        );
54        $this->eventLookup = $eventLookup;
55    }
56
57    /**
58     * @inheritDoc
59     */
60    public function getParamSettings(): array {
61        return $this->getIDParamSetting() + parent::getParamSettings();
62    }
63
64    /**
65     * @inheritDoc
66     */
67    public function getBodyParamSettings(): array {
68        return [
69            'status' => [
70                static::PARAM_SOURCE => 'body',
71                ParamValidator::PARAM_TYPE => EventRegistration::VALID_STATUSES,
72                ParamValidator::PARAM_REQUIRED => true,
73            ]
74        ] + parent::getBodyParamSettings();
75    }
76
77    /**
78     * @inheritDoc
79     */
80    protected function getSuccessResponse( StatusValue $saveStatus ): Response {
81        $warnings = $saveStatus->getMessages( 'warning' );
82        if ( !$warnings ) {
83            return $this->getResponseFactory()->createNoContent();
84        }
85        $respWarnings = [];
86        foreach ( $warnings as $msg ) {
87            // XXX There's no standard way to format warnings.
88            $respWarnings[] = [ 'key' => $msg->getKey(), 'params' => $msg->getParams() ];
89        }
90        return $this->getResponseFactory()->createJson( [
91            'warnings' => $respWarnings
92        ] );
93    }
94
95    /**
96     * @return ExistingEventRegistration
97     */
98    protected function getExistingEvent(): ExistingEventRegistration {
99        $id = $this->getValidatedParams()['id'];
100        $registration = $this->getRegistrationOrThrow( $this->eventLookup, $id );
101        $eventPageWikiID = $registration->getPage()->getWikiId();
102        if ( $eventPageWikiID !== WikiAwareEntity::LOCAL ) {
103            // TODO: This could redirect with a 3xx status code, but it's unclear how we may be able to obtain
104            // the REST endpoint URL for external wikis (T312568).
105            throw new LocalizedHttpException(
106                MessageValue::new( 'campaignevents-rest-edit-page-nonlocal' )->params( $eventPageWikiID ),
107                400
108            );
109        }
110        return $registration;
111    }
112
113    /**
114     * @inheritDoc
115     */
116    protected function checkPermissions( ICampaignsAuthority $performer ): void {
117        // Nothing to check now. Deeper check will happen in EditEventCommand.
118    }
119
120    /**
121     * @inheritDoc
122     */
123    protected function createEventObject( array $body ): EventRegistration {
124        $existingEvent = $this->getExistingEvent();
125        $meetingType = 0;
126        if ( $body['online_meeting'] ) {
127            $meetingType |= EventRegistration::MEETING_TYPE_ONLINE;
128        }
129        if ( $body['inperson_meeting'] ) {
130            $meetingType |= EventRegistration::MEETING_TYPE_IN_PERSON;
131        }
132
133        $participantQuestionNames = [];
134        $currentQuestionIDs = $existingEvent->getParticipantQuestions();
135        foreach ( $currentQuestionIDs as $questionID ) {
136            try {
137                $participantQuestionNames[] = $this->eventQuestionsRegistry->dbIDToName( $questionID );
138            } catch ( UnknownQuestionException $e ) {
139                // TODO This could presumably happen if a question is removed. Maybe we should just ignore it in
140                // that case.
141                throw new LogicException( 'Unknown question in the database', 0, $e );
142            }
143        }
144
145        $rawWikis = $body['wikis'] ?? [];
146        $allWikis = $this->wikiLookup->getAllWikis();
147        // Compare the counts, not the arrays, because order does not matter
148        $wikis = count( $rawWikis ) === count( $allWikis ) ? EventRegistration::ALL_WIKIS : $rawWikis;
149
150        return $this->eventFactory->newEvent(
151            $existingEvent->getID(),
152            $body['event_page'],
153            $body['chat_url'],
154            $wikis,
155            $body['tracking_tool_id'],
156            $body['tracking_tool_event_id'],
157            $body['status'],
158            $body['timezone'],
159            $body['start_time'],
160            $body['end_time'],
161            // TODO MVP Get this from the request body
162            EventRegistration::TYPE_GENERIC,
163            $meetingType,
164            $body['meeting_url'],
165            $body['meeting_country'],
166            $body['meeting_address'],
167            $participantQuestionNames,
168            $existingEvent->getCreationTimestamp(),
169            $existingEvent->getLastEditTimestamp(),
170            $existingEvent->getDeletionTimestamp(),
171            EventFactory::VALIDATE_SKIP_DATES_PAST
172        );
173    }
174}