Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
81.44% |
79 / 97 |
|
71.43% |
5 / 7 |
CRAP | |
0.00% |
0 / 1 |
AbstractStructuredMentorWriter | |
81.44% |
79 / 97 |
|
71.43% |
5 / 7 |
20.07 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getMentorData | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
serializeMentor | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
doSaveMentorData | n/a |
0 / 0 |
n/a |
0 / 0 |
0 | |||||
saveMentorData | |
75.00% |
12 / 16 |
|
0.00% |
0 / 1 |
4.25 | |||
addMentor | |
100.00% |
24 / 24 |
|
100.00% |
1 / 1 |
4 | |||
removeMentor | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
2 | |||
changeMentor | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
2 | |||
touchList | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
12 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\Mentorship\Provider; |
4 | |
5 | use GrowthExperiments\Mentorship\Mentor; |
6 | use GrowthExperiments\Mentorship\MentorshipSummaryCreator; |
7 | use MediaWiki\User\UserFactory; |
8 | use MediaWiki\User\UserIdentity; |
9 | use MediaWiki\User\UserIdentityLookup; |
10 | use Psr\Log\LoggerAwareTrait; |
11 | use StatusValue; |
12 | use Wikimedia\Rdbms\IDBAccessObject; |
13 | |
14 | /** |
15 | * This class writes to the structured mentor list and allows to add/remove |
16 | * mentors from the structured mentor list. |
17 | * |
18 | * Use StructuredMentorProvider to read the mentor list. |
19 | * |
20 | * This class uses WikiPageConfigWriter under the hood. |
21 | */ |
22 | abstract class AbstractStructuredMentorWriter implements IMentorWriter { |
23 | use LoggerAwareTrait; |
24 | |
25 | /** |
26 | * Change tag to tag structured mentor list edits with |
27 | * |
28 | * @note Keep in sync with extension.json (GrowthMentorList provider of |
29 | * CommunityConfiguration). |
30 | */ |
31 | public const CHANGE_TAG = 'mentor list change'; |
32 | public const CONFIG_KEY = 'Mentors'; |
33 | |
34 | protected MentorProvider $mentorProvider; |
35 | protected UserIdentityLookup $userIdentityLookup; |
36 | protected UserFactory $userFactory; |
37 | |
38 | /** |
39 | * @param MentorProvider $mentorProvider |
40 | * @param UserIdentityLookup $userIdentityLookup |
41 | * @param UserFactory $userFactory |
42 | */ |
43 | public function __construct( |
44 | MentorProvider $mentorProvider, |
45 | UserIdentityLookup $userIdentityLookup, |
46 | UserFactory $userFactory |
47 | ) { |
48 | $this->mentorProvider = $mentorProvider; |
49 | $this->userIdentityLookup = $userIdentityLookup; |
50 | $this->userFactory = $userFactory; |
51 | } |
52 | |
53 | /** |
54 | * Get list of mentors |
55 | * |
56 | * @return array |
57 | */ |
58 | abstract protected function getMentorData(): array; |
59 | |
60 | /** |
61 | * Serialize a Mentor object to an array |
62 | * |
63 | * @param Mentor $mentor |
64 | * @return array |
65 | */ |
66 | public static function serializeMentor( Mentor $mentor ): array { |
67 | return [ |
68 | 'message' => $mentor->hasCustomIntroText() ? $mentor->getIntroText() : null, |
69 | 'weight' => $mentor->getWeight(), |
70 | ]; |
71 | } |
72 | |
73 | abstract protected function doSaveMentorData( |
74 | array $mentorData, |
75 | string $summary, |
76 | UserIdentity $performer, |
77 | bool $bypassWarnings |
78 | ): StatusValue; |
79 | |
80 | /** |
81 | * Save mentor data |
82 | * |
83 | * @param array $mentorData |
84 | * @param string $summary |
85 | * @param UserIdentity $performer |
86 | * @param bool $bypassWarnings |
87 | * @return StatusValue |
88 | */ |
89 | protected function saveMentorData( |
90 | array $mentorData, |
91 | string $summary, |
92 | UserIdentity $performer, |
93 | bool $bypassWarnings |
94 | ): StatusValue { |
95 | // check if $performer is not blocked from the mentor list page |
96 | if ( $this->isBlocked( $performer, IDBAccessObject::READ_LATEST ) ) { |
97 | return StatusValue::newFatal( 'growthexperiments-mentor-writer-error-blocked' ); |
98 | } |
99 | |
100 | // add 'username' key for readability (T331444) |
101 | foreach ( $mentorData as $mentorId => $_ ) { |
102 | $mentorUser = $this->userIdentityLookup->getUserIdentityByUserId( $mentorId ); |
103 | if ( !$mentorUser ) { |
104 | $this->logger->warning( 'Mentor list contains an invalid user for ID {userId}', [ |
105 | 'userId' => $mentorId, |
106 | ] ); |
107 | continue; |
108 | } |
109 | |
110 | $mentorData[$mentorId]['username'] = $mentorUser->getName(); |
111 | } |
112 | |
113 | return $this->doSaveMentorData( |
114 | $mentorData, |
115 | $summary, |
116 | $performer, |
117 | $bypassWarnings |
118 | ); |
119 | } |
120 | |
121 | /** |
122 | * @inheritDoc |
123 | */ |
124 | public function addMentor( |
125 | Mentor $mentor, |
126 | UserIdentity $performer, |
127 | string $summary, |
128 | bool $bypassWarnings = false |
129 | ): StatusValue { |
130 | $mentorUserIdentity = $mentor->getUserIdentity(); |
131 | if ( !$mentorUserIdentity->isRegistered() |
132 | || !$this->userFactory->newFromUserIdentity( $mentorUserIdentity )->isNamed() |
133 | ) { |
134 | return StatusValue::newFatal( |
135 | 'growthexperiments-mentor-writer-error-anonymous-user', |
136 | $mentorUserIdentity->getName() |
137 | ); |
138 | } |
139 | |
140 | $mentorData = $this->getMentorData(); |
141 | if ( array_key_exists( $mentorUserIdentity->getId(), $mentorData ) ) { |
142 | // we're trying to add someone who's already added |
143 | return StatusValue::newFatal( |
144 | 'growthexperiments-mentor-writer-error-already-added', |
145 | $mentorUserIdentity->getName() |
146 | ); |
147 | } |
148 | $mentorData[$mentorUserIdentity->getId()] = $this->serializeMentor( $mentor ); |
149 | |
150 | return $this->saveMentorData( |
151 | $mentorData, |
152 | MentorshipSummaryCreator::createAddSummary( |
153 | $performer, |
154 | $mentorUserIdentity, |
155 | $summary |
156 | ), |
157 | $performer, |
158 | $bypassWarnings |
159 | ); |
160 | } |
161 | |
162 | /** |
163 | * @inheritDoc |
164 | */ |
165 | public function removeMentor( |
166 | Mentor $mentor, |
167 | UserIdentity $performer, |
168 | string $summary, |
169 | bool $bypassWarnings = false |
170 | ): StatusValue { |
171 | $mentorUserIdentity = $mentor->getUserIdentity(); |
172 | |
173 | $mentorData = $this->getMentorData(); |
174 | if ( !array_key_exists( $mentorUserIdentity->getId(), $mentorData ) ) { |
175 | // we're trying to remove someone who isn't added |
176 | return StatusValue::newFatal( |
177 | 'growthexperiments-mentor-writer-error-not-in-the-list', |
178 | $mentorUserIdentity->getName() |
179 | ); |
180 | } |
181 | unset( $mentorData[$mentorUserIdentity->getId()] ); |
182 | |
183 | return $this->saveMentorData( |
184 | $mentorData, |
185 | MentorshipSummaryCreator::createRemoveSummary( |
186 | $performer, |
187 | $mentorUserIdentity, |
188 | $summary |
189 | ), |
190 | $performer, |
191 | $bypassWarnings |
192 | ); |
193 | } |
194 | |
195 | /** |
196 | * @inheritDoc |
197 | */ |
198 | public function changeMentor( |
199 | Mentor $mentor, |
200 | UserIdentity $performer, |
201 | string $summary, |
202 | bool $bypassWarnings = false |
203 | ): StatusValue { |
204 | $mentorUserIdentity = $mentor->getUserIdentity(); |
205 | |
206 | $mentorData = $this->getMentorData(); |
207 | if ( !array_key_exists( $mentorUserIdentity->getId(), $mentorData ) ) { |
208 | // we're trying to change someone who isn't added |
209 | return StatusValue::newFatal( |
210 | 'growthexperiments-mentor-writer-error-not-in-the-list', |
211 | $mentorUserIdentity->getName() |
212 | ); |
213 | } |
214 | $mentorData[$mentorUserIdentity->getId()] = $this->serializeMentor( $mentor ); |
215 | |
216 | return $this->saveMentorData( |
217 | $mentorData, |
218 | MentorshipSummaryCreator::createChangeSummary( |
219 | $performer, |
220 | $mentorUserIdentity, |
221 | $summary |
222 | ), |
223 | $performer, |
224 | $bypassWarnings |
225 | ); |
226 | } |
227 | |
228 | /** |
229 | * @inheritDoc |
230 | */ |
231 | public function touchList( UserIdentity $performer, string $summary ): StatusValue { |
232 | $mentorData = $this->getMentorData(); |
233 | foreach ( $mentorData as $mentorId => $mentorArr ) { |
234 | $mentorUser = $this->userIdentityLookup->getUserIdentityByUserId( $mentorId ); |
235 | if ( !$mentorUser ) { |
236 | continue; |
237 | } |
238 | $mentorData[$mentorUser->getId()] = $this->serializeMentor( |
239 | $this->mentorProvider->newMentorFromUserIdentity( $mentorUser ) |
240 | ); |
241 | } |
242 | return $this->saveMentorData( |
243 | $mentorData, |
244 | $summary, |
245 | $performer, |
246 | true |
247 | ); |
248 | } |
249 | } |