Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
57.84% covered (warning)
57.84%
59 / 102
20.00% covered (danger)
20.00%
3 / 15
CRAP
0.00% covered (danger)
0.00%
0 / 1
SpecialClaimMentee
57.84% covered (warning)
57.84%
59 / 102
20.00% covered (danger)
20.00%
3 / 15
92.01
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 getGroupName
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 doesWrites
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDescription
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 preHtml
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
2
 execute
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 isListed
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 userCanExecute
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 displayRestrictionError
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
6
 getFormFields
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
3
 getDisplayFormat
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onSubmit
91.30% covered (success)
91.30%
21 / 23
0.00% covered (danger)
0.00%
0 / 1
7.03
 onSuccess
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
1
 setMentees
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 validateMentees
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace GrowthExperiments\Specials;
4
5use GrowthExperiments\Mentorship\ChangeMentorFactory;
6use GrowthExperiments\Mentorship\Provider\MentorProvider;
7use MediaWiki\Config\Config;
8use MediaWiki\Html\Html;
9use MediaWiki\Linker\Linker;
10use MediaWiki\Logger\LoggerFactory;
11use MediaWiki\SpecialPage\FormSpecialPage;
12use MediaWiki\Status\Status;
13use MediaWiki\User\User;
14use MediaWiki\User\UserIdentity;
15use Message;
16use PermissionsError;
17
18class SpecialClaimMentee extends FormSpecialPage {
19
20    /** @var User[] */
21    private array $mentees;
22
23    private ?User $newMentor;
24    private MentorProvider $mentorProvider;
25    private ChangeMentorFactory $changeMentorFactory;
26    private Config $wikiConfig;
27
28    /**
29     * @param MentorProvider $mentorProvider
30     * @param ChangeMentorFactory $changeMentorFactory
31     * @param Config $wikiConfig
32     */
33    public function __construct(
34        MentorProvider $mentorProvider,
35        ChangeMentorFactory $changeMentorFactory,
36        Config $wikiConfig
37    ) {
38        parent::__construct( 'ClaimMentee' );
39
40        $this->mentorProvider = $mentorProvider;
41        $this->changeMentorFactory = $changeMentorFactory;
42        $this->wikiConfig = $wikiConfig;
43    }
44
45    /** @inheritDoc */
46    protected function getGroupName() {
47        return 'growth-tools';
48    }
49
50    public function doesWrites() {
51        return true;
52    }
53
54    /**
55     * @inheritDoc
56     */
57    public function getDescription() {
58        return $this->msg( 'growthexperiments-homepage-claimmentee-title' );
59    }
60
61    protected function preHtml() {
62        return Html::element(
63            'p',
64            [],
65            $this->msg( 'growthexperiments-homepage-claimmentee-pretext' )->params(
66                $this->getUser()->getName()
67            )->text()
68        );
69    }
70
71    /**
72     * @inheritDoc
73     */
74    public function execute( $par ) {
75        $this->requireNamedUser();
76        $this->addHelpLink( 'Help:Growth/Tools/How to claim a mentee' );
77        parent::execute( $par );
78    }
79
80    /**
81     * @inheritDoc
82     */
83    public function isListed() {
84        return $this->userCanExecute( $this->getUser() );
85    }
86
87    /**
88     * @inheritDoc
89     */
90    public function userCanExecute( User $user ) {
91        return $this->mentorProvider->isMentor( $user );
92    }
93
94    /**
95     * @inheritDoc
96     */
97    public function displayRestrictionError() {
98        $signupTitle = $this->mentorProvider->getSignupTitle();
99
100        if ( $signupTitle === null ) {
101            throw new PermissionsError(
102                null,
103                [ 'growthexperiments-homepage-mentors-list-missing-or-misconfigured-generic' ]
104            );
105        }
106
107        throw new PermissionsError(
108            null,
109            [ [ 'growthexperiments-homepage-claimmentee-must-be-mentor',
110                $this->getUser()->getName(),
111                $signupTitle->getPrefixedText() ] ]
112        );
113    }
114
115    /**
116     * Get an HTMLForm descriptor array
117     * @return array
118     */
119    protected function getFormFields() {
120        $req = $this->getRequest();
121        $fields = [
122            'mentees' => [
123                'label-message' => 'growthexperiments-homepage-claimmentee-mentee',
124                'type'          => 'usersmultiselect',
125                'exists'        => true,
126                'required'      => true
127            ],
128            'reason' => [
129                'label-message' => 'growthexperiments-homepage-claimmentee-reason',
130                'type'          => 'text',
131            ],
132            'stage' => [ 'type' => 'hidden', 'default' => 2 ]
133        ];
134        $stage = $req->getInt( 'wpstage', 1 );
135        $this->setMentees( $req->getVal( 'wpmentees', '' ) );
136        if ( $stage >= 2 && $this->validateMentees() ) {
137            $fields['stage']['default'] = 3;
138            $fields['confirm'] = [
139                'label-message' => 'growthexperiments-claimmentee-confirm',
140                'type' => 'check',
141                'default' => false,
142            ];
143        }
144        return $fields;
145    }
146
147    /**
148     * @return string
149     */
150    protected function getDisplayFormat() {
151        return 'ooui';
152    }
153
154    /**
155     * @inheritDoc
156     */
157    public function onSubmit( array $data ) {
158        $this->setMentees( $data['mentees'] );
159
160        // Should be caught by exits => true, but just to be sure
161        if ( !$this->validateMentees() ) {
162            return Status::newFatal( 'growthexperiments-homepage-claimmentee-invalid-username' );
163        }
164
165        $this->newMentor = $this->getUser();
166
167        $status = Status::newGood();
168        $logger = LoggerFactory::getInstance( 'GrowthExperiments' );
169        foreach ( $this->mentees as $mentee ) {
170            $changementor = $this->changeMentorFactory->newChangeMentor(
171                $mentee,
172                $this->newMentor
173            );
174
175            if (
176                $data['confirm'] !== true
177                && $data['stage'] !== 3
178                && $changementor->wasMentorChanged()
179            ) {
180                return Status::newFatal(
181                    'growthexperiments-homepage-claimmentee-alreadychanged',
182                    $mentee,
183                    $this->newMentor
184                );
185            }
186
187            $status->merge( $changementor->execute( $this->newMentor, $data['reason'] ) );
188            if ( !$status->isOK() ) {
189                // Do not process next users if at least one failed
190                return $status;
191            }
192        }
193
194        return $status;
195    }
196
197    public function onSuccess() {
198        $mentees = array_map( static function ( UserIdentity $user ) {
199            return Linker::userLink( $user->getId(), $user->getName() );
200        }, $this->mentees );
201
202        $language = $this->getLanguage();
203
204        $this->getOutput()->addWikiMsg(
205            'growthexperiments-homepage-claimmentee-success',
206            Message::rawParam( $language->listToText( $mentees ) ),
207            $language->formatNum( count( $mentees ) ),
208            $this->getUser()->getName(),
209            $this->newMentor->getName(),
210            Message::rawParam( $this->getLinkRenderer()->makeLink(
211                $this->newMentor->getUserPage(), $this->newMentor->getName() ) )
212        );
213    }
214
215    private function setMentees( string $namesRaw = '' ) {
216        $names = explode( "\n", $namesRaw );
217        $this->mentees = [];
218
219        foreach ( $names as $name ) {
220            $user = User::newFromName( $name );
221            if ( $user !== false ) {
222                $this->mentees[] = $user;
223            }
224        }
225    }
226
227    private function validateMentees() {
228        foreach ( $this->mentees as $mentee ) {
229            if ( !( $mentee instanceof User && $mentee->isNamed() ) ) {
230                return false;
231            }
232        }
233        return true;
234    }
235}