Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.83% covered (success)
95.83%
46 / 48
83.33% covered (warning)
83.33%
5 / 6
CRAP
0.00% covered (danger)
0.00%
0 / 1
UpdateGrantIdHandler
95.83% covered (success)
95.83%
46 / 48
83.33% covered (warning)
83.33%
5 / 6
12
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
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
 run
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 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
 tryUpdateGrantId
91.30% covered (success)
91.30%
21 / 23
0.00% covered (danger)
0.00%
0 / 1
6.02
1<?php
2
3declare( strict_types=1 );
4
5namespace MediaWiki\Extension\WikimediaCampaignEvents\Rest;
6
7use MediaWiki\Extension\CampaignEvents\Event\Store\IEventLookup;
8use MediaWiki\Extension\CampaignEvents\MWEntity\MWAuthorityProxy;
9use MediaWiki\Extension\CampaignEvents\Permissions\PermissionChecker;
10use MediaWiki\Extension\CampaignEvents\Rest\EventIDParamTrait;
11use MediaWiki\Extension\WikimediaCampaignEvents\Grants\Exception\FluxxRequestException;
12use MediaWiki\Extension\WikimediaCampaignEvents\Grants\Exception\InvalidGrantIDException;
13use MediaWiki\Extension\WikimediaCampaignEvents\Grants\GrantIDLookup;
14use MediaWiki\Extension\WikimediaCampaignEvents\Grants\GrantsStore;
15use MediaWiki\Rest\LocalizedHttpException;
16use MediaWiki\Rest\Response;
17use MediaWiki\Rest\SimpleHandler;
18use MediaWiki\Rest\TokenAwareHandlerTrait;
19use MediaWiki\Rest\Validator\Validator;
20use RuntimeException;
21use Wikimedia\Message\MessageValue;
22use Wikimedia\ParamValidator\ParamValidator;
23
24class UpdateGrantIdHandler extends SimpleHandler {
25    use EventIDParamTrait;
26    use TokenAwareHandlerTrait;
27
28    private IEventLookup $eventLookup;
29    private PermissionChecker $permissionChecker;
30    private GrantsStore $grantsStore;
31    private GrantIDLookup $grantIDLookup;
32
33    public function __construct(
34        IEventLookup $eventLookup,
35        GrantIDLookup $grantIDLookup,
36        PermissionChecker $permissionChecker,
37        GrantsStore $grantsStore
38    ) {
39        $this->eventLookup = $eventLookup;
40        $this->grantIDLookup = $grantIDLookup;
41        $this->permissionChecker = $permissionChecker;
42        $this->grantsStore = $grantsStore;
43    }
44
45    /**
46     * @inheritDoc
47     */
48    public function validate( Validator $restValidator ): void {
49        parent::validate( $restValidator );
50        $this->validateToken();
51    }
52
53    protected function run( int $eventID ): Response {
54        $registration = $this->getRegistrationOrThrow( $this->eventLookup, $eventID );
55
56        $body = $this->getValidatedBody();
57        $grantID = $body['grant_id'] ?? null;
58
59        $performer = new MWAuthorityProxy( $this->getAuthority() );
60        if ( !$this->permissionChecker->userCanEditRegistration( $performer, $registration ) ) {
61            throw new LocalizedHttpException(
62                MessageValue::new( 'wikimediacampaignevents-rest-grant-id-edit-permission-denied' ),
63                403
64            );
65        }
66
67        $this->tryUpdateGrantId( $grantID, $eventID );
68
69        return $this->getResponseFactory()->createNoContent();
70    }
71
72    /**
73     * @inheritDoc
74     */
75    public function getParamSettings(): array {
76        return $this->getIDParamSetting();
77    }
78
79    /**
80     * @inheritDoc
81     */
82    public function getBodyParamSettings(): array {
83        return [
84                'grant_id' => [
85                    ParamValidator::PARAM_REQUIRED => true,
86                    ParamValidator::PARAM_TYPE => 'string',
87                    static::PARAM_SOURCE => 'body'
88                ],
89            ] + $this->getTokenParamDefinition();
90    }
91
92    private function tryUpdateGrantId( string $grantID, int $eventID ): void {
93        // TODO Avoid duplicating EventRegistrationFormHandler.
94        $pattern = "/^\d+-\d+$/";
95        if ( !preg_match( $pattern, $grantID ) ) {
96            throw new LocalizedHttpException(
97                MessageValue::new( 'wikimediacampaignevents-rest-grant-id-edit-invalid' ),
98                400
99            );
100        }
101
102        try {
103            $this->grantIDLookup->doLookup( $grantID );
104        } catch ( InvalidGrantIDException $_ ) {
105            throw new LocalizedHttpException(
106                MessageValue::new( 'wikimediacampaignevents-rest-grant-id-edit-invalid' ),
107                400
108            );
109        } catch ( FluxxRequestException $_ ) {
110            throw new LocalizedHttpException(
111                MessageValue::new( 'wikimediacampaignevents-rest-grant-id-edit-api-error' ),
112                503
113            );
114        }
115
116        $previousGrantID = $this->grantsStore->getGrantID( $eventID );
117        if ( $grantID !== $previousGrantID ) {
118            try {
119                $grantAgreementAt = $this->grantIDLookup->getAgreementAt( $grantID );
120            } catch ( FluxxRequestException | InvalidGrantIDException $e ) {
121                throw new RuntimeException( "Could not retrieve agreement_at: $e" );
122            }
123            $this->grantsStore->updateGrantID( $grantID, $eventID, $grantAgreementAt );
124        }
125    }
126}