Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.11% covered (warning)
85.11%
40 / 47
80.00% covered (warning)
80.00%
12 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
PermissionChecker
85.11% covered (warning)
85.11%
40 / 47
80.00% covered (warning)
80.00%
12 / 15
39.05
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
 userCanEnableRegistrations
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 userCanEnableRegistration
66.67% covered (warning)
66.67%
6 / 9
0.00% covered (danger)
0.00%
0 / 1
4.59
 userCanOrganizeEvents
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 userCanEditRegistration
72.73% covered (warning)
72.73%
8 / 11
0.00% covered (danger)
0.00%
0 / 1
6.73
 userCanDeleteRegistration
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 userCanDeleteRegistrations
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 userCanRegisterForEvent
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
 userCanCancelRegistration
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 userCanRemoveParticipants
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 userCanViewPrivateParticipants
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 userCanViewSensitiveEventData
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 userCanViewNonPIIParticipantsData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 userCanEmailParticipants
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 userCanUseInvitationLists
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare( strict_types=1 );
4
5namespace MediaWiki\Extension\CampaignEvents\Permissions;
6
7use MediaWiki\Extension\CampaignEvents\Event\ExistingEventRegistration;
8use MediaWiki\Extension\CampaignEvents\MWEntity\CampaignsCentralUserLookup;
9use MediaWiki\Extension\CampaignEvents\MWEntity\ICampaignsAuthority;
10use MediaWiki\Extension\CampaignEvents\MWEntity\ICampaignsPage;
11use MediaWiki\Extension\CampaignEvents\MWEntity\IPermissionsLookup;
12use MediaWiki\Extension\CampaignEvents\MWEntity\PageAuthorLookup;
13use MediaWiki\Extension\CampaignEvents\MWEntity\UserNotGlobalException;
14use MediaWiki\Extension\CampaignEvents\Organizers\OrganizersStore;
15
16class PermissionChecker {
17    public const SERVICE_NAME = 'CampaignEventsPermissionChecker';
18
19    public const ENABLE_REGISTRATIONS_RIGHT = 'campaignevents-enable-registration';
20    public const ORGANIZE_EVENTS_RIGHT = 'campaignevents-organize-events';
21    public const SEND_EVENTS_EMAIL_RIGHT = 'campaignevents-email-participants';
22
23    private OrganizersStore $organizersStore;
24    private PageAuthorLookup $pageAuthorLookup;
25    private CampaignsCentralUserLookup $centralUserLookup;
26    private IPermissionsLookup $permissionsLookup;
27
28    /**
29     * @param OrganizersStore $organizersStore
30     * @param PageAuthorLookup $pageAuthorLookup
31     * @param CampaignsCentralUserLookup $centralUserLookup
32     * @param IPermissionsLookup $permissionsLookup
33     */
34    public function __construct(
35        OrganizersStore $organizersStore,
36        PageAuthorLookup $pageAuthorLookup,
37        CampaignsCentralUserLookup $centralUserLookup,
38        IPermissionsLookup $permissionsLookup
39    ) {
40        $this->organizersStore = $organizersStore;
41        $this->pageAuthorLookup = $pageAuthorLookup;
42        $this->centralUserLookup = $centralUserLookup;
43        $this->permissionsLookup = $permissionsLookup;
44    }
45
46    /**
47     * NOTE: This should be kept in sync with the special page, which has its own ways of requiring named account,
48     * unblock, and rights.
49     * @param ICampaignsAuthority $performer
50     * @return bool
51     */
52    public function userCanEnableRegistrations( ICampaignsAuthority $performer ): bool {
53        return $performer->isNamed()
54            && $performer->hasRight( self::ENABLE_REGISTRATIONS_RIGHT )
55            && !$performer->isSitewideBlocked();
56    }
57
58    /**
59     * @param ICampaignsAuthority $performer
60     * @param ICampaignsPage $eventPage
61     * @return bool
62     */
63    public function userCanEnableRegistration( ICampaignsAuthority $performer, ICampaignsPage $eventPage ): bool {
64        if ( !$this->userCanEnableRegistrations( $performer ) ) {
65            return false;
66        }
67
68        $pageAuthor = $this->pageAuthorLookup->getAuthor( $eventPage );
69        if ( !$pageAuthor ) {
70            return false;
71        }
72
73        try {
74            $centralUser = $this->centralUserLookup->newFromAuthority( $performer );
75        } catch ( UserNotGlobalException $_ ) {
76            return false;
77        }
78        return $pageAuthor->equals( $centralUser );
79    }
80
81    /**
82     * @param string $username
83     * @return bool
84     */
85    public function userCanOrganizeEvents( string $username ): bool {
86        return $this->permissionsLookup->userIsNamed( $username ) &&
87            $this->permissionsLookup->userHasRight( $username, self::ORGANIZE_EVENTS_RIGHT ) &&
88            !$this->permissionsLookup->userIsSitewideBlocked( $username );
89    }
90
91    /**
92     * @param ICampaignsAuthority $performer
93     * @param ExistingEventRegistration $event
94     * @return bool
95     */
96    public function userCanEditRegistration( ICampaignsAuthority $performer, ExistingEventRegistration $event ): bool {
97        if (
98            !$event->isOnLocalWiki() ||
99            (
100                !$this->userCanEnableRegistrations( $performer ) &&
101                !$this->userCanOrganizeEvents( $performer->getName() )
102            )
103        ) {
104            return false;
105        }
106        try {
107            $centralUser = $this->centralUserLookup->newFromAuthority( $performer );
108        } catch ( UserNotGlobalException $_ ) {
109            return false;
110        }
111        $eventID = $event->getID();
112        if ( $eventID ) {
113            return $this->organizersStore->isEventOrganizer( $eventID, $centralUser );
114        }
115        return false;
116    }
117
118    /**
119     * @param ICampaignsAuthority $performer
120     * @param ExistingEventRegistration $event
121     * @return bool
122     */
123    public function userCanDeleteRegistration(
124        ICampaignsAuthority $performer,
125        ExistingEventRegistration $event
126    ): bool {
127        return $event->isOnLocalWiki() && (
128                $this->userCanDeleteRegistrations( $performer ) ||
129                $this->userCanEditRegistration( $performer, $event )
130            );
131    }
132
133    /**
134     * @param ICampaignsAuthority $performer
135     * @return bool
136     */
137    public function userCanDeleteRegistrations( ICampaignsAuthority $performer ): bool {
138        return $performer->isNamed() &&
139            $performer->hasRight( 'campaignevents-delete-registration' ) &&
140            !$performer->isSitewideBlocked();
141    }
142
143    /**
144     * NOTE: This should be kept in sync with the special page, which has its own ways of requiring named account
145     * and unblock.
146     * @param ICampaignsAuthority $performer
147     * @param ExistingEventRegistration $event
148     * @return bool
149     */
150    public function userCanRegisterForEvent( ICampaignsAuthority $performer, ExistingEventRegistration $event ): bool {
151        // TODO Do we need another user right for this?
152        return $event->isOnLocalWiki() && $performer->isNamed() && !$performer->isSitewideBlocked();
153    }
154
155    /**
156     * NOTE: This should be kept in sync with the special page, which has its own way of requiring a named account.
157     * @param ICampaignsAuthority $performer
158     * @return bool
159     */
160    public function userCanCancelRegistration( ICampaignsAuthority $performer ): bool {
161        // Note that blocked users can cancel their own registration, see T322380.
162        return $performer->isNamed();
163    }
164
165    /**
166     * @param ICampaignsAuthority $performer
167     * @param ExistingEventRegistration $event
168     * @return bool
169     */
170    public function userCanRemoveParticipants(
171        ICampaignsAuthority $performer,
172        ExistingEventRegistration $event
173    ): bool {
174        return $this->userCanEditRegistration( $performer, $event );
175    }
176
177    /**
178     * @param ICampaignsAuthority $performer
179     * @param ExistingEventRegistration $event
180     * @return bool
181     */
182    public function userCanViewPrivateParticipants(
183        ICampaignsAuthority $performer,
184        ExistingEventRegistration $event
185    ): bool {
186        return $this->userCanEditRegistration( $performer, $event );
187    }
188
189    /**
190     * @param ICampaignsAuthority $performer
191     * @return bool
192     */
193    public function userCanViewSensitiveEventData( ICampaignsAuthority $performer ): bool {
194        return !$performer->isSitewideBlocked();
195    }
196
197    /**
198     * @param ICampaignsAuthority $performer
199     * @param ExistingEventRegistration $event
200     * @return bool
201     */
202    public function userCanViewNonPIIParticipantsData(
203        ICampaignsAuthority $performer,
204        ExistingEventRegistration $event
205    ): bool {
206        return $this->userCanEditRegistration( $performer, $event );
207    }
208
209    /**
210     * @param ICampaignsAuthority $performer
211     * @param ExistingEventRegistration $event
212     * @return bool
213     */
214    public function userCanEmailParticipants( ICampaignsAuthority $performer, ExistingEventRegistration $event ): bool {
215        return $this->userCanEditRegistration( $performer, $event )
216            && $performer->hasRight( self::SEND_EVENTS_EMAIL_RIGHT );
217    }
218
219    public function userCanUseInvitationLists( ICampaignsAuthority $performer ): bool {
220        return $this->userCanOrganizeEvents( $performer->getName() ) ||
221            $this->userCanEnableRegistrations( $performer );
222    }
223}