Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.30% covered (warning)
80.30%
53 / 66
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
EmailUsersHandler
80.30% covered (warning)
80.30%
53 / 66
80.00% covered (warning)
80.00%
4 / 5
13.10
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
 run
63.89% covered (warning)
63.89%
23 / 36
0.00% covered (danger)
0.00%
0 / 1
11.01
 validate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 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%
23 / 23
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare( strict_types=1 );
4
5namespace MediaWiki\Extension\CampaignEvents\Rest;
6
7use MediaWiki\DAO\WikiAwareEntity;
8use MediaWiki\Extension\CampaignEvents\Event\Store\IEventLookup;
9use MediaWiki\Extension\CampaignEvents\Messaging\CampaignsUserMailer;
10use MediaWiki\Extension\CampaignEvents\MWEntity\MWAuthorityProxy;
11use MediaWiki\Extension\CampaignEvents\Participants\ParticipantsStore;
12use MediaWiki\Extension\CampaignEvents\Permissions\PermissionChecker;
13use MediaWiki\Rest\LocalizedHttpException;
14use MediaWiki\Rest\Response;
15use MediaWiki\Rest\SimpleHandler;
16use MediaWiki\Rest\TokenAwareHandlerTrait;
17use MediaWiki\Rest\Validator\Validator;
18use Wikimedia\Message\MessageValue;
19use Wikimedia\ParamValidator\ParamValidator;
20
21class EmailUsersHandler extends SimpleHandler {
22    use EventIDParamTrait;
23    use TokenAwareHandlerTrait;
24    use FailStatusUtilTrait;
25
26    private CampaignsUserMailer $userMailer;
27    private PermissionChecker $permissionChecker;
28    private ParticipantsStore $participantsStore;
29    private IEventLookup $eventLookup;
30
31    /**
32     * @param PermissionChecker $permissionChecker
33     * @param CampaignsUserMailer $userMailer
34     * @param ParticipantsStore $participantsStore
35     * @param IEventLookup $eventLookup
36     */
37    public function __construct(
38        PermissionChecker $permissionChecker,
39        CampaignsUserMailer $userMailer,
40        ParticipantsStore $participantsStore,
41        IEventLookup $eventLookup
42    ) {
43        $this->permissionChecker = $permissionChecker;
44        $this->userMailer = $userMailer;
45        $this->participantsStore = $participantsStore;
46        $this->eventLookup = $eventLookup;
47    }
48
49    /**
50     * @param int $eventId
51     * @return Response
52     */
53    public function run( int $eventId ): Response {
54        $event = $this->getRegistrationOrThrow( $this->eventLookup, $eventId );
55        $performer = new MWAuthorityProxy( $this->getAuthority() );
56        $params = $this->getValidatedBody() ?? [];
57
58        if ( !$this->permissionChecker->userCanEmailParticipants( $performer, $event ) ) {
59            // todo add more details to error message
60            return $this->getResponseFactory()->createHttpError( 403 );
61        }
62
63        $wikiID = $event->getPage()->getWikiId();
64        if ( $wikiID !== WikiAwareEntity::LOCAL ) {
65            throw new LocalizedHttpException(
66                MessageValue::new( 'campaignevents-rest-email-participants-nonlocal-error-message' )
67                    ->params( $wikiID ),
68                400
69            );
70        }
71
72        $userIds = $params['user_ids'] ? array_map( 'intval', $params['user_ids'] ) : [];
73        $participants = $this->participantsStore->getEventParticipants(
74            $eventId,
75            null,
76            null,
77            null,
78            $params['invert_users'] ? null : $userIds,
79            true,
80            $params['invert_users'] ? $userIds : null
81        );
82        if ( !$participants ) {
83            return $this->getResponseFactory()->createJson( [ 'sent' => 0 ] );
84        }
85        $result = $this->userMailer->sendEmail(
86            $this->getAuthority(),
87            $participants,
88            $params['subject'],
89            $params['message'],
90            $event
91        );
92
93        if ( !$result->isGood() ) {
94            $this->exitWithStatus( $result );
95        }
96        $resp = $this->getResponseFactory()->createJson( [ 'sent' => $result->getValue() ] );
97        $resp->setStatus( 202 );
98        return $resp;
99    }
100
101    /**
102     * @inheritDoc
103     */
104    public function validate( Validator $restValidator ): void {
105        parent::validate( $restValidator );
106        $this->validateToken();
107    }
108
109    /**
110     * @inheritDoc
111     */
112    public function getParamSettings(): array {
113        return $this->getIDParamSetting();
114    }
115
116    /**
117     * @return array
118     */
119    public function getBodyParamSettings(): array {
120        return [
121                'user_ids' => [
122                    static::PARAM_SOURCE => 'body',
123                    ParamValidator::PARAM_TYPE => 'array',
124                    ParamValidator::PARAM_REQUIRED => false,
125                ],
126                'invert_users' => [
127                    static::PARAM_SOURCE => 'body',
128                    ParamValidator::PARAM_TYPE => 'boolean',
129                    ParamValidator::PARAM_REQUIRED => false,
130                    ParamValidator::PARAM_DEFAULT => false,
131                ],
132                'message' => [
133                    static::PARAM_SOURCE => 'body',
134                    ParamValidator::PARAM_TYPE => 'string',
135                    ParamValidator::PARAM_REQUIRED => true,
136                ],
137                'subject' => [
138                    static::PARAM_SOURCE => 'body',
139                    ParamValidator::PARAM_TYPE => 'string',
140                    ParamValidator::PARAM_REQUIRED => true,
141                ]
142            ] + $this->getTokenParamDefinition();
143    }
144}