Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
91.76% covered (success)
91.76%
78 / 85
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
AbstractEditEventRegistrationHandler
91.76% covered (success)
91.76%
78 / 85
75.00% covered (warning)
75.00%
3 / 4
10.06
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
1
 validate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 checkPermissions
n/a
0 / 0
n/a
0 / 0
0
 execute
66.67% covered (warning)
66.67%
14 / 21
0.00% covered (danger)
0.00%
0 / 1
8.81
 getSuccessResponse
n/a
0 / 0
n/a
0 / 0
0
 getParamSettings
100.00% covered (success)
100.00%
56 / 56
100.00% covered (success)
100.00%
1 / 1
1
 createEventObject
n/a
0 / 0
n/a
0 / 0
0
1<?php
2
3declare( strict_types=1 );
4
5namespace MediaWiki\Extension\CampaignEvents\Rest;
6
7use MediaWiki\Extension\CampaignEvents\Event\EditEventCommand;
8use MediaWiki\Extension\CampaignEvents\Event\EventFactory;
9use MediaWiki\Extension\CampaignEvents\Event\EventRegistration;
10use MediaWiki\Extension\CampaignEvents\Event\InvalidEventDataException;
11use MediaWiki\Extension\CampaignEvents\MWEntity\CampaignsCentralUserLookup;
12use MediaWiki\Extension\CampaignEvents\MWEntity\ICampaignsAuthority;
13use MediaWiki\Extension\CampaignEvents\MWEntity\MWAuthorityProxy;
14use MediaWiki\Extension\CampaignEvents\MWEntity\UserNotGlobalException;
15use MediaWiki\Extension\CampaignEvents\Organizers\OrganizersStore;
16use MediaWiki\Extension\CampaignEvents\Permissions\PermissionChecker;
17use MediaWiki\Extension\CampaignEvents\Questions\EventQuestionsRegistry;
18use MediaWiki\Permissions\PermissionStatus;
19use MediaWiki\Rest\Handler;
20use MediaWiki\Rest\Response;
21use MediaWiki\Rest\TokenAwareHandlerTrait;
22use MediaWiki\Rest\Validator\Validator;
23use RuntimeException;
24use StatusValue;
25use Wikimedia\ParamValidator\ParamValidator;
26use Wikimedia\ParamValidator\TypeDef\TimestampDef;
27
28abstract class AbstractEditEventRegistrationHandler extends Handler {
29    use TokenAwareHandlerTrait;
30    use FailStatusUtilTrait;
31
32    protected EventFactory $eventFactory;
33    protected PermissionChecker $permissionChecker;
34    protected EditEventCommand $editEventCommand;
35    private OrganizersStore $organizersStore;
36    private CampaignsCentralUserLookup $centralUserLookup;
37    protected EventQuestionsRegistry $eventQuestionsRegistry;
38
39    /**
40     * @param EventFactory $eventFactory
41     * @param PermissionChecker $permissionChecker
42     * @param EditEventCommand $editEventCommand
43     * @param OrganizersStore $organizersStore
44     * @param CampaignsCentralUserLookup $centralUserLookup
45     * @param EventQuestionsRegistry $eventQuestionsRegistry
46     */
47    public function __construct(
48        EventFactory $eventFactory,
49        PermissionChecker $permissionChecker,
50        EditEventCommand $editEventCommand,
51        OrganizersStore $organizersStore,
52        CampaignsCentralUserLookup $centralUserLookup,
53        EventQuestionsRegistry $eventQuestionsRegistry
54    ) {
55        $this->eventFactory = $eventFactory;
56        $this->permissionChecker = $permissionChecker;
57        $this->editEventCommand = $editEventCommand;
58        $this->organizersStore = $organizersStore;
59        $this->centralUserLookup = $centralUserLookup;
60        $this->eventQuestionsRegistry = $eventQuestionsRegistry;
61    }
62
63    /**
64     * @inheritDoc
65     */
66    public function validate( Validator $restValidator ): void {
67        parent::validate( $restValidator );
68        $this->validateToken();
69    }
70
71    /**
72     * @param ICampaignsAuthority $performer
73     */
74    abstract protected function checkPermissions( ICampaignsAuthority $performer ): void;
75
76    /**
77     * @inheritDoc
78     */
79    public function execute() {
80        $body = $this->getValidatedBody();
81
82        $performer = new MWAuthorityProxy( $this->getAuthority() );
83        $this->checkPermissions( $performer );
84
85        try {
86            $event = $this->createEventObject( $body );
87        } catch ( InvalidEventDataException $e ) {
88            $this->exitWithStatus( $e->getStatus() );
89        }
90
91        $eventID = $event->getID();
92        if ( $eventID === null ) {
93            $organizerNames = [ $this->getAuthority()->getUser()->getName() ];
94        } else {
95            $organizers = $this->organizersStore->getEventOrganizers( $eventID );
96            $organizerNames = [];
97            foreach ( $organizers as $organizer ) {
98                $user = $organizer->getUser();
99                try {
100                    $organizerNames[] = $this->centralUserLookup->getUserName( $user );
101                } catch ( UserNotGlobalException $_ ) {
102                    // Should never happen.
103                    throw new RuntimeException( "Organizer in the database has no central account." );
104                }
105            }
106        }
107
108        $saveStatus = $this->editEventCommand->doEditIfAllowed( $event, $performer, $organizerNames );
109        if ( !$saveStatus->isOK() ) {
110            $httptStatus = $saveStatus instanceof PermissionStatus ? 403 : 400;
111            $this->exitWithStatus( $saveStatus, $httptStatus );
112        }
113
114        return $this->getSuccessResponse( $saveStatus );
115    }
116
117    /**
118     * @param StatusValue $saveStatus
119     * @return Response
120     */
121    abstract protected function getSuccessResponse( StatusValue $saveStatus ): Response;
122
123    /**
124     * @return array
125     */
126    public function getParamSettings(): array {
127        return [
128            'event_page' => [
129                static::PARAM_SOURCE => 'body',
130                ParamValidator::PARAM_TYPE => 'title',
131                ParamValidator::PARAM_REQUIRED => true,
132            ],
133            'chat_url' => [
134                static::PARAM_SOURCE => 'body',
135                ParamValidator::PARAM_TYPE => 'string',
136            ],
137            'tracking_tool_id' => [
138                static::PARAM_SOURCE => 'body',
139                ParamValidator::PARAM_TYPE => 'string',
140            ],
141            'tracking_tool_event_id' => [
142                static::PARAM_SOURCE => 'body',
143                ParamValidator::PARAM_TYPE => 'string',
144            ],
145            'timezone' => [
146                static::PARAM_SOURCE => 'body',
147                ParamValidator::PARAM_TYPE => 'string',
148                ParamValidator::PARAM_REQUIRED => true,
149            ],
150            'start_time' => [
151                static::PARAM_SOURCE => 'body',
152                ParamValidator::PARAM_TYPE => 'timestamp',
153                TimestampDef::PARAM_TIMESTAMP_FORMAT => TS_MW,
154                ParamValidator::PARAM_REQUIRED => true,
155            ],
156            'end_time' => [
157                static::PARAM_SOURCE => 'body',
158                ParamValidator::PARAM_TYPE => 'timestamp',
159                TimestampDef::PARAM_TIMESTAMP_FORMAT => TS_MW,
160                ParamValidator::PARAM_REQUIRED => true,
161            ],
162            /* TODO MVP: Re-add this
163            'type' => [
164                static::PARAM_SOURCE => 'body',
165                ParamValidator::PARAM_TYPE => EventRegistration::VALID_TYPES,
166                ParamValidator::PARAM_REQUIRED => true,
167            ],
168            */
169            'online_meeting' => [
170                static::PARAM_SOURCE => 'body',
171                ParamValidator::PARAM_TYPE => 'boolean',
172            ],
173            'inperson_meeting' => [
174                static::PARAM_SOURCE => 'body',
175                ParamValidator::PARAM_TYPE => 'boolean',
176            ],
177            'meeting_url' => [
178                static::PARAM_SOURCE => 'body',
179                ParamValidator::PARAM_TYPE => 'string',
180            ],
181            'meeting_country' => [
182                static::PARAM_SOURCE => 'body',
183                ParamValidator::PARAM_TYPE => 'string',
184            ],
185            'meeting_address' => [
186                static::PARAM_SOURCE => 'body',
187                ParamValidator::PARAM_TYPE => 'string',
188            ],
189        ] + $this->getTokenParamDefinition();
190    }
191
192    /**
193     * Creates an EventRegistration object with the data from the request body, with
194     * appropriate validation.
195     *
196     * @param array $body Request body data
197     * @return EventRegistration
198     * @throws InvalidEventDataException
199     */
200    abstract protected function createEventObject( array $body ): EventRegistration;
201}