Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
89.36% covered (warning)
89.36%
42 / 47
66.67% covered (warning)
66.67%
4 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
SetOrganizersHandler
89.36% covered (warning)
89.36%
42 / 47
66.67% covered (warning)
66.67%
4 / 6
14.24
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 validate
55.56% covered (warning)
55.56%
5 / 9
0.00% covered (danger)
0.00%
0 / 1
3.79
 validateEventWiki
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 run
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
5
 getParamSettings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBodyValidator
91.67% covered (success)
91.67%
11 / 12
0.00% covered (danger)
0.00%
0 / 1
2.00
1<?php
2
3declare( strict_types=1 );
4
5namespace MediaWiki\Extension\CampaignEvents\Rest;
6
7use MediaWiki\DAO\WikiAwareEntity;
8use MediaWiki\Extension\CampaignEvents\Event\EditEventCommand;
9use MediaWiki\Extension\CampaignEvents\Event\ExistingEventRegistration;
10use MediaWiki\Extension\CampaignEvents\Event\Store\IEventLookup;
11use MediaWiki\Extension\CampaignEvents\MWEntity\CampaignsCentralUserLookup;
12use MediaWiki\Extension\CampaignEvents\MWEntity\MWAuthorityProxy;
13use MediaWiki\ParamValidator\TypeDef\UserDef;
14use MediaWiki\Permissions\PermissionStatus;
15use MediaWiki\Rest\LocalizedHttpException;
16use MediaWiki\Rest\Response;
17use MediaWiki\Rest\SimpleHandler;
18use MediaWiki\Rest\TokenAwareHandlerTrait;
19use MediaWiki\Rest\Validator\BodyValidator;
20use MediaWiki\Rest\Validator\JsonBodyValidator;
21use MediaWiki\Rest\Validator\UnsupportedContentTypeBodyValidator;
22use MediaWiki\Rest\Validator\Validator;
23use Wikimedia\Message\MessageValue;
24use Wikimedia\ParamValidator\ParamValidator;
25
26class SetOrganizersHandler extends SimpleHandler {
27    use EventIDParamTrait;
28    use FailStatusUtilTrait;
29    use TokenAwareHandlerTrait;
30
31    private IEventLookup $eventLookup;
32    private EditEventCommand $editEventCommand;
33    private CampaignsCentralUserLookup $centralUserLookup;
34
35    /**
36     * @param IEventLookup $eventLookup
37     * @param EditEventCommand $editEventCommand
38     * @param CampaignsCentralUserLookup $centralUserLookup
39     */
40    public function __construct(
41        IEventLookup $eventLookup,
42        EditEventCommand $editEventCommand,
43        CampaignsCentralUserLookup $centralUserLookup
44    ) {
45        $this->eventLookup = $eventLookup;
46        $this->editEventCommand = $editEventCommand;
47        $this->centralUserLookup = $centralUserLookup;
48    }
49
50    /**
51     * @inheritDoc
52     */
53    public function validate( Validator $restValidator ): void {
54        parent::validate( $restValidator );
55        $this->validateToken();
56        // XXX JsonBodyValidator does not validate parameters, see T305973
57        $organizerNames = $this->getValidatedBody()['organizer_usernames'] ?? [];
58        foreach ( $organizerNames as $name ) {
59            if ( !$this->centralUserLookup->isValidLocalUsername( $name ) ) {
60                throw new LocalizedHttpException(
61                    MessageValue::new( 'paramvalidator-baduser' )->plaintextParams( 'organizer_usernames', $name ),
62                    400
63                );
64            }
65        }
66    }
67
68    /**
69     * @param ExistingEventRegistration $event
70     */
71    private function validateEventWiki( ExistingEventRegistration $event ): void {
72        $wikiID = $event->getPage()->getWikiId();
73        if ( $wikiID !== WikiAwareEntity::LOCAL ) {
74            throw new LocalizedHttpException(
75                MessageValue::new( 'campaignevents-rest-set-organizers-nonlocal-error-message' )
76                    ->params( $wikiID ),
77                400
78            );
79        }
80    }
81
82    /**
83     * @param int $eventID
84     * @return Response
85     */
86    protected function run( int $eventID ): Response {
87        $event = $this->getRegistrationOrThrow( $this->eventLookup, $eventID );
88        $this->validateEventWiki( $event );
89        $body = $this->getValidatedBody() ?? [];
90        $organizers = $body['organizer_usernames'];
91        if ( !is_array( $organizers ) || !$organizers ) {
92            throw new LocalizedHttpException(
93                MessageValue::new( 'campaignevents-rest-set-organizers-empty-list' ),
94                400
95            );
96        }
97
98        $performer = new MWAuthorityProxy( $this->getAuthority() );
99        $saveStatus = $this->editEventCommand->doEditIfAllowed( $event, $performer, $organizers );
100        // Note that no warnings (e.g., from tracking tools) are expected here
101        if ( !$saveStatus->isGood() ) {
102            $httptStatus = $saveStatus instanceof PermissionStatus ? 403 : 400;
103            $this->exitWithStatus( $saveStatus, $httptStatus );
104        }
105
106        return $this->getResponseFactory()->createNoContent();
107    }
108
109    /**
110     * @inheritDoc
111     */
112    public function getParamSettings(): array {
113        return $this->getIDParamSetting();
114    }
115
116    /**
117     * @inheritDoc
118     */
119    public function getBodyValidator( $contentType ): BodyValidator {
120        if ( $contentType !== 'application/json' ) {
121            return new UnsupportedContentTypeBodyValidator( $contentType );
122        }
123
124        return new JsonBodyValidator( [
125            'organizer_usernames' => [
126                ParamValidator::PARAM_REQUIRED => true,
127                ParamValidator::PARAM_TYPE => 'user',
128                UserDef::PARAM_ALLOWED_USER_TYPES => [ 'name' ],
129                static::PARAM_SOURCE => 'body',
130                ParamValidator::PARAM_ISMULTI => true,
131                ParamValidator::PARAM_DEFAULT => [],
132            ],
133        ] + $this->getTokenParamDefinition() );
134    }
135
136}