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