Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
48.72% |
38 / 78 |
|
41.67% |
10 / 24 |
CRAP | |
0.00% |
0 / 1 |
TaskType | |
48.72% |
38 / 78 |
|
41.67% |
10 / 24 |
109.29 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
getId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getHandlerId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setHandlerId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getDifficulty | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getLearnMoreLink | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExcludedTemplates | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getExcludedCategories | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getName | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getDescription | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getShortDescription | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getLabel | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getTimeEstimate | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
getViewData | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
2 | |||
getIconData | |
28.57% |
2 / 7 |
|
0.00% |
0 / 1 |
3.46 | |||
toJsonArray | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
1 | |||
newFromJsonArray | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
1 | |||
getExcludedTemplatesTitleValues | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
getExcludedCategoriesTitleValues | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
shouldOpenInEditMode | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getDefaultEditSection | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSmallTaskCardImageCssClasses | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getQualityGateIds | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getSuggestionFilters | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\NewcomerTasks\TaskType; |
4 | |
5 | use GrowthExperiments\NewcomerTasks\TaskSuggester\QualityGateDecorator; |
6 | use MediaWiki\Json\JsonUnserializable; |
7 | use MediaWiki\Json\JsonUnserializableTrait; |
8 | use MediaWiki\Json\JsonUnserializer; |
9 | use MediaWiki\Linker\LinkTarget; |
10 | use MediaWiki\Title\TitleValue; |
11 | use Message; |
12 | use MessageLocalizer; |
13 | |
14 | /** |
15 | * Describes a type of suggested edit. |
16 | */ |
17 | class TaskType implements JsonUnserializable { |
18 | |
19 | use JsonUnserializableTrait; |
20 | |
21 | public const DIFFICULTY_EASY = 'easy'; |
22 | public const DIFFICULTY_MEDIUM = 'medium'; |
23 | public const DIFFICULTY_HARD = 'hard'; |
24 | public const DIFFICULTY_NUMERIC = [ |
25 | 1 => self::DIFFICULTY_EASY, |
26 | 2 => self::DIFFICULTY_MEDIUM, |
27 | 3 => self::DIFFICULTY_HARD |
28 | ]; |
29 | |
30 | public const DIFFICULTY_CLASSES = [ |
31 | self::DIFFICULTY_EASY, |
32 | self::DIFFICULTY_MEDIUM, |
33 | self::DIFFICULTY_HARD, |
34 | ]; |
35 | |
36 | /** Whether this is a task type generated by machine */ |
37 | protected const IS_MACHINE_SUGGESTION = false; |
38 | |
39 | /** @var string Task type ID, e.g. 'copyedit'. */ |
40 | protected $id; |
41 | |
42 | /** @var string TaskTypeHandler ID. */ |
43 | protected $handlerId; |
44 | |
45 | /** @var string Task type difficulty class, one of the DIFFICULTY_* constants. */ |
46 | protected $difficulty; |
47 | |
48 | /** @var string|null Page name to point the "learn more" link to. */ |
49 | protected $learnMoreLink; |
50 | |
51 | /** @var LinkTarget[] List of templates that prevent an article from being identified with this task type. */ |
52 | private $excludedTemplates; |
53 | |
54 | /** @var LinkTarget[] List of categories that prevent an article from being identified with this task type. */ |
55 | private $excludedCategories; |
56 | |
57 | /** |
58 | * @param string $id Task type ID, e.g. 'copyedit'. |
59 | * @param string $difficulty One of the DIFFICULTY_* constants. |
60 | * @param array $extraData Optional pieces of information |
61 | * - 'learnMoreLink' (string): Page title for the "learn more" link for this task type. |
62 | * @param LinkTarget[] $excludedTemplates List of templates that prevent an article from being identified with |
63 | * this task type. |
64 | * @param LinkTarget[] $excludedCategories List of cateogires that prevent an article from being identified with |
65 | * this task type. |
66 | */ |
67 | public function __construct( |
68 | $id, $difficulty, array $extraData = [], array $excludedTemplates = [], array $excludedCategories = [] |
69 | ) { |
70 | $this->id = $id; |
71 | $this->difficulty = $difficulty; |
72 | $this->learnMoreLink = $extraData['learnMoreLink'] ?? null; |
73 | $this->excludedTemplates = $excludedTemplates; |
74 | $this->excludedCategories = $excludedCategories; |
75 | } |
76 | |
77 | /** |
78 | * Task type ID, e.g. 'copyedit'. |
79 | * @return string |
80 | */ |
81 | public function getId() { |
82 | return $this->id; |
83 | } |
84 | |
85 | /** |
86 | * @return string |
87 | * @internal for use by TaskTypeHandlerRegistry only |
88 | */ |
89 | public function getHandlerId() { |
90 | return $this->handlerId; |
91 | } |
92 | |
93 | /** |
94 | * @param string $handlerId |
95 | * @internal for use by TaskTypeHandlerRegistry only |
96 | */ |
97 | public function setHandlerId( $handlerId ) { |
98 | $this->handlerId = $handlerId; |
99 | } |
100 | |
101 | /** |
102 | * One of the DIFFICULTY_* constants. |
103 | * @return string |
104 | */ |
105 | public function getDifficulty() { |
106 | return $this->difficulty; |
107 | } |
108 | |
109 | /** |
110 | * Page title for the "learn more" link for this task type. |
111 | * @return string|null |
112 | */ |
113 | public function getLearnMoreLink() { |
114 | return $this->learnMoreLink; |
115 | } |
116 | |
117 | /** |
118 | * @return LinkTarget[] |
119 | */ |
120 | public function getExcludedTemplates(): array { |
121 | return $this->excludedTemplates; |
122 | } |
123 | |
124 | /** |
125 | * @return LinkTarget[] |
126 | */ |
127 | public function getExcludedCategories(): array { |
128 | return $this->excludedCategories; |
129 | } |
130 | |
131 | /** |
132 | * Human-readable name of the task type. |
133 | * @param MessageLocalizer $messageLocalizer |
134 | * @return Message |
135 | */ |
136 | public function getName( MessageLocalizer $messageLocalizer ): Message { |
137 | return $messageLocalizer->msg( 'growthexperiments-homepage-suggestededits-tasktype-name-' |
138 | . $this->getId() ); |
139 | } |
140 | |
141 | /** |
142 | * Description of the task type. |
143 | * @param MessageLocalizer $messageLocalizer |
144 | * @return Message |
145 | */ |
146 | public function getDescription( MessageLocalizer $messageLocalizer ): Message { |
147 | return $messageLocalizer->msg( 'growthexperiments-homepage-suggestededits-tasktype-description-' |
148 | . $this->getId() ); |
149 | } |
150 | |
151 | /** |
152 | * Short description of the task type. |
153 | * @param MessageLocalizer $messageLocalizer |
154 | * @return Message |
155 | */ |
156 | public function getShortDescription( MessageLocalizer $messageLocalizer ): Message { |
157 | return $messageLocalizer->msg( |
158 | 'growthexperiments-homepage-suggestededits-tasktype-shortdescription-' . $this->getId() ); |
159 | } |
160 | |
161 | /** |
162 | * Label for the task type; typically either the name, or a combination of the name and |
163 | * the short description. |
164 | * @param MessageLocalizer $messageLocalizer |
165 | * @return Message |
166 | */ |
167 | public function getLabel( MessageLocalizer $messageLocalizer ): Message { |
168 | return $messageLocalizer->msg( |
169 | 'growthexperiments-homepage-suggestededits-tasktype-label-' . $this->getId() ); |
170 | } |
171 | |
172 | /** |
173 | * Time estimate for the task type. |
174 | * @param MessageLocalizer $messageLocalizer |
175 | * @return Message |
176 | */ |
177 | public function getTimeEstimate( MessageLocalizer $messageLocalizer ): Message { |
178 | return $messageLocalizer->msg( 'growthexperiments-homepage-suggestededits-tasktype-time-' |
179 | . $this->getId() ); |
180 | } |
181 | |
182 | /** |
183 | * Return an array (JSON-ish) representation of the task type. |
184 | * This is for the benefit of clients (contains details needed by a task UI) and cannot |
185 | * be used to recover the object. |
186 | * @param MessageLocalizer $messageLocalizer |
187 | * @return array |
188 | */ |
189 | public function getViewData( MessageLocalizer $messageLocalizer ) { |
190 | $viewData = [ |
191 | 'id' => $this->getId(), |
192 | 'difficulty' => $this->getDifficulty(), |
193 | 'messages' => [ |
194 | 'name' => $this->getName( $messageLocalizer )->text(), |
195 | 'description' => $this->getDescription( $messageLocalizer )->text(), |
196 | 'shortdescription' => $this->getShortDescription( $messageLocalizer )->text(), |
197 | 'label' => $this->getLabel( $messageLocalizer )->text(), |
198 | 'timeestimate' => $this->getTimeEstimate( $messageLocalizer )->text(), |
199 | ], |
200 | 'learnMoreLink' => $this->getLearnMoreLink(), |
201 | 'iconData' => $this->getIconData() |
202 | ]; |
203 | return $viewData; |
204 | } |
205 | |
206 | /** |
207 | * Get icon data that should be shown for the task type |
208 | * @return array |
209 | */ |
210 | public function getIconData(): array { |
211 | if ( static::IS_MACHINE_SUGGESTION ) { |
212 | return [ |
213 | // The following classes are used here: |
214 | // * robot-task-type-easy |
215 | // * robot-task-type-medium |
216 | 'icon' => 'robot-task-type-' . $this->getDifficulty(), |
217 | 'filterIcon' => 'robot', |
218 | 'descriptionMessageKey' => 'growthexperiments-homepage-suggestededits-tasktype-machine-description' |
219 | ]; |
220 | } |
221 | return []; |
222 | } |
223 | |
224 | /** @inheritDoc */ |
225 | protected function toJsonArray(): array { |
226 | return [ |
227 | 'id' => $this->getId(), |
228 | 'difficulty' => $this->getDifficulty(), |
229 | 'extraData' => [ 'learnMoreLink' => $this->getLearnMoreLink() ], |
230 | 'handlerId' => $this->getHandlerId(), |
231 | 'iconData' => $this->getIconData(), |
232 | 'excludedTemplates' => array_map( static function ( LinkTarget $excludedTemplate ) { |
233 | return [ $excludedTemplate->getNamespace(), $excludedTemplate->getDBkey() ]; |
234 | }, $this->getExcludedTemplates() ), |
235 | 'excludedCategories' => array_map( static function ( LinkTarget $excludedCategory ) { |
236 | return [ $excludedCategory->getNamespace(), $excludedCategory->getDBkey() ]; |
237 | }, $this->getExcludedCategories() ) |
238 | ]; |
239 | } |
240 | |
241 | /** @inheritDoc */ |
242 | public static function newFromJsonArray( JsonUnserializer $unserializer, array $json ) { |
243 | $excludedTemplates = array_map( static function ( array $excludedTemplate ) { |
244 | return new TitleValue( $excludedTemplate[0], $excludedTemplate[1] ); |
245 | }, $json['excludedTemplates'] ?? [] ); |
246 | $excludedCategories = array_map( static function ( array $excludedCategory ) { |
247 | return new TitleValue( $excludedCategory[0], $excludedCategory[1] ); |
248 | }, $json['excludedCategories'] ?? [] ); |
249 | $taskType = new static( |
250 | $json['id'], $json['difficulty'], $json['extraData'], $excludedTemplates, $excludedCategories |
251 | ); |
252 | $taskType->setHandlerId( $json['handlerId'] ); |
253 | return $taskType; |
254 | } |
255 | |
256 | /** |
257 | * @param array $config |
258 | * @return TitleValue[] |
259 | */ |
260 | public static function getExcludedTemplatesTitleValues( array $config ): array { |
261 | return array_map( static function ( array $excludedTemplate ) { |
262 | return new TitleValue( $excludedTemplate[0], $excludedTemplate[1] ); |
263 | }, $config['excludedTemplates'] ?? [] ); |
264 | } |
265 | |
266 | /** |
267 | * @param array $config |
268 | * @return TitleValue[] |
269 | */ |
270 | public static function getExcludedCategoriesTitleValues( array $config ): array { |
271 | return array_map( static function ( array $excludedCategory ) { |
272 | return new TitleValue( $excludedCategory[0], $excludedCategory[1] ); |
273 | }, $config['excludedCategories'] ?? [] ); |
274 | } |
275 | |
276 | /** |
277 | * Whether the corresponding article for the task type should be opened in edit mode |
278 | * @return bool |
279 | */ |
280 | public function shouldOpenInEditMode(): bool { |
281 | return false; |
282 | } |
283 | |
284 | /** |
285 | * Get the default edit section for the task type |
286 | * @return string |
287 | */ |
288 | public function getDefaultEditSection(): string { |
289 | return ''; |
290 | } |
291 | |
292 | /** |
293 | * Get CSS classes to add to the small task card image element. |
294 | * |
295 | * @return array |
296 | */ |
297 | public function getSmallTaskCardImageCssClasses(): array { |
298 | return [ 'mw-ge-small-task-card-image-skeleton' ]; |
299 | } |
300 | |
301 | /** |
302 | * The quality gate data for this task type. |
303 | * |
304 | * @see QualityGateDecorator and modules/ext.growthExperiments.Homepage.SuggestedEdits/QualityGate.js |
305 | * @return string[] An array of quality gate names that will be applied for the task type. |
306 | */ |
307 | public function getQualityGateIds(): array { |
308 | return []; |
309 | } |
310 | |
311 | /** |
312 | * Return the filters to apply to the recommendation |
313 | * |
314 | * @return array |
315 | */ |
316 | public function getSuggestionFilters(): array { |
317 | return []; |
318 | } |
319 | } |