Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
82.86% |
58 / 70 |
|
66.67% |
4 / 6 |
CRAP | |
0.00% |
0 / 1 |
ApiInvalidateImageRecommendation | |
82.86% |
58 / 70 |
|
66.67% |
4 / 6 |
8.32 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
1 | |||
execute | |
66.67% |
22 / 33 |
|
0.00% |
0 / 1 |
3.33 | |||
needsToken | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
mustBePosted | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAllowedParams | |
100.00% |
27 / 27 |
|
100.00% |
1 / 1 |
1 | |||
isInternal | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\Api; |
4 | |
5 | use GrowthExperiments\NewcomerTasks\AddImage\AddImageSubmissionHandler; |
6 | use GrowthExperiments\NewcomerTasks\ConfigurationLoader\ConfigurationLoader; |
7 | use GrowthExperiments\NewcomerTasks\NewcomerTasksUserOptionsLookup; |
8 | use GrowthExperiments\NewcomerTasks\TaskSuggester\TaskSuggesterFactory; |
9 | use GrowthExperiments\NewcomerTasks\TaskType\ImageRecommendationBaseTaskType; |
10 | use GrowthExperiments\NewcomerTasks\TaskType\ImageRecommendationTaskTypeHandler; |
11 | use GrowthExperiments\NewcomerTasks\TaskType\SectionImageRecommendationTaskTypeHandler; |
12 | use MediaWiki\Api\ApiBase; |
13 | use MediaWiki\Api\ApiMain; |
14 | use MediaWiki\Api\ApiUsageException; |
15 | use MediaWiki\Logger\LoggerFactory; |
16 | use MediaWiki\ParamValidator\TypeDef\TitleDef; |
17 | use MediaWiki\Title\TitleFactory; |
18 | use Psr\Log\LoggerAwareTrait; |
19 | use Wikimedia\Assert\Assert; |
20 | use Wikimedia\ParamValidator\ParamValidator; |
21 | |
22 | /** |
23 | * Endpoint for invalidating image recommendation. |
24 | * |
25 | * This is used when the recommendation is determined to be invalid upon display (for example, |
26 | * when the article already has an image). See mw.libs.ge.AddImageArticleTarget. |
27 | */ |
28 | class ApiInvalidateImageRecommendation extends ApiBase { |
29 | use LoggerAwareTrait; |
30 | |
31 | private AddImageSubmissionHandler $imageSubmissionHandler; |
32 | private TaskSuggesterFactory $taskSuggesterFactory; |
33 | private NewcomerTasksUserOptionsLookup $newcomerTasksUserOptionsLookup; |
34 | private TitleFactory $titleFactory; |
35 | private ConfigurationLoader $configurationLoader; |
36 | |
37 | public function __construct( |
38 | ApiMain $mainModule, |
39 | string $moduleName, |
40 | ConfigurationLoader $configurationLoader, |
41 | AddImageSubmissionHandler $imageSubmissionHandler, |
42 | TaskSuggesterFactory $taskSuggesterFactory, |
43 | NewcomerTasksUserOptionsLookup $newcomerTasksUserOptionsLookup, |
44 | TitleFactory $titleFactory |
45 | ) { |
46 | parent::__construct( $mainModule, $moduleName ); |
47 | $this->configurationLoader = $configurationLoader; |
48 | $this->imageSubmissionHandler = $imageSubmissionHandler; |
49 | $this->taskSuggesterFactory = $taskSuggesterFactory; |
50 | $this->newcomerTasksUserOptionsLookup = $newcomerTasksUserOptionsLookup; |
51 | $this->titleFactory = $titleFactory; |
52 | |
53 | $this->setLogger( LoggerFactory::getInstance( 'GrowthExperiments' ) ); |
54 | } |
55 | |
56 | /** |
57 | * @inheritDoc |
58 | * @throws ApiUsageException |
59 | */ |
60 | public function execute() { |
61 | $params = $this->extractRequestParams(); |
62 | // This API is used by external clients for their own structured task workflows so |
63 | // include disabled task types. |
64 | $allTaskTypes = $this->configurationLoader->getTaskTypes() |
65 | + $this->configurationLoader->getDisabledTaskTypes(); |
66 | $taskType = $allTaskTypes[$params['tasktype']] ?? null; |
67 | if ( $taskType === null ) { |
68 | $this->logger->warning( |
69 | 'Task type {tasktype} was not found in {configpage}', |
70 | [ |
71 | 'tasktype' => $params['tasktype'], |
72 | 'configpage' => $this->getConfig()->get( 'GENewcomerTasksConfigTitle' ), |
73 | ] |
74 | ); |
75 | $this->dieWithError( |
76 | [ 'growthexperiments-homepage-imagesuggestiondata-not-in-config', $params['tasktype'] ], |
77 | 'not-in-config' |
78 | ); |
79 | } |
80 | |
81 | Assert::parameterType( ImageRecommendationBaseTaskType::class, $taskType, '$taskType' ); |
82 | '@phan-var ImageRecommendationBaseTaskType $taskType';/** @var ImageRecommendationBaseTaskType $taskType */ |
83 | $titleValue = $params['title']; |
84 | |
85 | $page = $this->titleFactory->newFromLinkTarget( $titleValue )->toPageIdentity(); |
86 | if ( $page->exists() ) { |
87 | $this->imageSubmissionHandler->invalidateRecommendation( |
88 | $taskType, |
89 | $page, |
90 | $this->getAuthority()->getUser()->getId(), |
91 | null, |
92 | $params['filename'], |
93 | $params['sectiontitle'], |
94 | $params['sectionnumber'], |
95 | ); |
96 | $this->getResult()->addValue( null, $this->getModuleName(), [ |
97 | 'status' => 'ok' |
98 | ] ); |
99 | } else { |
100 | $this->dieWithError( [ 'apierror-invalidtitle', $titleValue->getDBkey() ] ); |
101 | } |
102 | } |
103 | |
104 | /** |
105 | * @inheritDoc |
106 | */ |
107 | public function needsToken() { |
108 | return 'csrf'; |
109 | } |
110 | |
111 | /** |
112 | * @inheritDoc |
113 | */ |
114 | public function mustBePosted() { |
115 | return true; |
116 | } |
117 | |
118 | /** |
119 | * @inheritDoc |
120 | */ |
121 | public function getAllowedParams() { |
122 | return [ |
123 | 'tasktype' => [ |
124 | ParamValidator::PARAM_TYPE => [ |
125 | // Do not filter out non-existing task-types: during API structure tests |
126 | // none of the task types exist and an empty list would cause test failures. |
127 | ImageRecommendationTaskTypeHandler::TASK_TYPE_ID, |
128 | SectionImageRecommendationTaskTypeHandler::TASK_TYPE_ID, |
129 | ], |
130 | ParamValidator::PARAM_REQUIRED => false, |
131 | ParamValidator::PARAM_DEFAULT => ImageRecommendationTaskTypeHandler::TASK_TYPE_ID, |
132 | ], |
133 | 'title' => [ |
134 | ParamValidator::PARAM_REQUIRED => true, |
135 | ParamValidator::PARAM_TYPE => 'title', |
136 | TitleDef::PARAM_RETURN_OBJECT => true, |
137 | ], |
138 | 'filename' => [ |
139 | ParamValidator::PARAM_REQUIRED => true, |
140 | ParamValidator::PARAM_TYPE => 'string', |
141 | ], |
142 | 'sectiontitle' => [ |
143 | ParamValidator::PARAM_REQUIRED => false, |
144 | ParamValidator::PARAM_TYPE => 'string', |
145 | ], |
146 | 'sectionnumber' => [ |
147 | ParamValidator::PARAM_REQUIRED => false, |
148 | ParamValidator::PARAM_TYPE => 'integer', |
149 | ] |
150 | ]; |
151 | } |
152 | |
153 | /** @inheritDoc */ |
154 | public function isInternal() { |
155 | return true; |
156 | } |
157 | } |