Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 106 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
AddImageFeedbackHandler | |
0.00% |
0 / 106 |
|
0.00% |
0 / 6 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
run | |
0.00% |
0 / 51 |
|
0.00% |
0 / 1 |
306 | |||
getParamSettings | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
2 | |||
getBodyParamSettings | |
0.00% |
0 / 38 |
|
0.00% |
0 / 1 |
2 | |||
validate | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
makeException | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\Rest\Handler; |
4 | |
5 | use GrowthExperiments\NewcomerTasks\AddImage\AddImageSubmissionHandler; |
6 | use GrowthExperiments\NewcomerTasks\ConfigurationLoader\ConfigurationLoader; |
7 | use GrowthExperiments\NewcomerTasks\TaskType\ImageRecommendationTaskType; |
8 | use GrowthExperiments\Util; |
9 | use MediaWiki\Api\ApiMessage; |
10 | use MediaWiki\ParamValidator\TypeDef\TitleDef; |
11 | use MediaWiki\Rest\LocalizedHttpException; |
12 | use MediaWiki\Rest\SimpleHandler; |
13 | use MediaWiki\Rest\TokenAwareHandlerTrait; |
14 | use MediaWiki\Rest\Validator\Validator; |
15 | use MediaWiki\Revision\RevisionLookup; |
16 | use MediaWiki\Title\TitleFactory; |
17 | use Wikimedia\Message\MessageValue; |
18 | use Wikimedia\ParamValidator\ParamValidator; |
19 | |
20 | /** |
21 | * Accept image recommendation feedback. Basically just a wrapper for AddImageSubmissionHandler. |
22 | */ |
23 | class AddImageFeedbackHandler extends SimpleHandler { |
24 | |
25 | use TokenAwareHandlerTrait; |
26 | |
27 | private TitleFactory $titleFactory; |
28 | private RevisionLookup $revisionLookup; |
29 | private ConfigurationLoader $configurationLoader; |
30 | private AddImageSubmissionHandler $addImageSubmissionHandler; |
31 | |
32 | /** |
33 | * @param TitleFactory $titleFactory |
34 | * @param RevisionLookup $revisionLookup |
35 | * @param ConfigurationLoader $configurationLoader |
36 | * @param AddImageSubmissionHandler $addImageSubmissionHandler |
37 | */ |
38 | public function __construct( |
39 | TitleFactory $titleFactory, |
40 | RevisionLookup $revisionLookup, |
41 | ConfigurationLoader $configurationLoader, |
42 | AddImageSubmissionHandler $addImageSubmissionHandler |
43 | ) { |
44 | $this->titleFactory = $titleFactory; |
45 | $this->revisionLookup = $revisionLookup; |
46 | $this->configurationLoader = $configurationLoader; |
47 | $this->addImageSubmissionHandler = $addImageSubmissionHandler; |
48 | } |
49 | |
50 | public function run() { |
51 | $authority = $this->getAuthority(); |
52 | $user = $authority->getUser(); |
53 | $title = $this->titleFactory->newFromLinkTarget( $this->getValidatedParams()['title'] ); |
54 | $data = $this->getValidatedBody() ?? []; |
55 | $editRevId = $data['editRevId']; |
56 | |
57 | if ( !$authority->isNamed() ) { |
58 | throw $this->makeException( 'rest-permission-denied-anon', [], 401 ); |
59 | } |
60 | if ( $data['accepted'] && !$editRevId ) { |
61 | throw $this->makeException( 'growthexperiments-addimage-feedback-accepted-editrevid' ); |
62 | } elseif ( !$data['accepted'] && $editRevId ) { |
63 | throw $this->makeException( 'growthexperiments-addimage-feedback-rejected-editrevid' ); |
64 | } |
65 | if ( $data['accepted'] && ( $data['caption'] ?? null ) === null ) { |
66 | throw $this->makeException( 'growthexperiments-addimage-feedback-accepted-caption' ); |
67 | } |
68 | |
69 | $editRev = null; |
70 | if ( $editRevId !== null ) { |
71 | $editRev = $this->revisionLookup->getRevisionById( $editRevId ); |
72 | if ( !$editRev ) { |
73 | throw $this->makeException( 'growthexperiments-addimage-feedback-revid-nonexistent', [ $editRev ] ); |
74 | } elseif ( $editRev->getPageId() !== $title->getArticleID() ) { |
75 | throw $this->makeException( |
76 | 'growthexperiments-addimage-feedback-invalid-revid-wrong-page', |
77 | [ $editRevId, $title->getPrefixedText() ] |
78 | ); |
79 | } |
80 | } |
81 | // The handler doesn't use the base revid so make things simple and just fake it. |
82 | if ( $editRev ) { |
83 | $baseRev = $this->revisionLookup->getPreviousRevision( $editRev ); |
84 | $baseRevId = $baseRev ? $baseRev->getId() : null; |
85 | } else { |
86 | $baseRevId = $title->getLatestRevID(); |
87 | } |
88 | |
89 | // TODO support section images |
90 | $allTaskTypes = $this->configurationLoader->getTaskTypes() |
91 | + $this->configurationLoader->getDisabledTaskTypes(); |
92 | $taskType = $allTaskTypes['image-recommendation'] ?? null; |
93 | if ( !( $taskType instanceof ImageRecommendationTaskType ) ) { |
94 | throw new LocalizedHttpException( |
95 | new MessageValue( 'growthexperiments-newcomertasks-invalid-tasktype', [ 'image-recommendation' ] ) |
96 | ); |
97 | } |
98 | |
99 | $status = $this->addImageSubmissionHandler->validate( |
100 | $taskType, $title->toPageIdentity(), $user, $baseRevId, $data |
101 | ); |
102 | if ( $status->isGood() ) { |
103 | $status->merge( $this->addImageSubmissionHandler->handle( |
104 | $taskType, $title->toPageIdentity(), $user, $baseRevId, $editRevId, $data |
105 | ), true ); |
106 | } |
107 | if ( !$status->isGood() ) { |
108 | Util::logStatus( $status ); |
109 | // This assumes that there's no more than one message in the status object |
110 | $msg = $status->getMessages()[0]; |
111 | $errorKey = ( new ApiMessage( $msg ) )->getApiCode(); |
112 | throw new LocalizedHttpException( |
113 | MessageValue::newFromSpecifier( $msg ), |
114 | $status->isOK() ? 400 : 500, |
115 | [ 'errorKey' => $errorKey ] |
116 | ); |
117 | } |
118 | |
119 | return [ 'success' => true ] + $status->getValue(); |
120 | } |
121 | |
122 | /** @inheritDoc */ |
123 | public function getParamSettings() { |
124 | return [ |
125 | 'title' => [ |
126 | self::PARAM_SOURCE => 'path', |
127 | ParamValidator::PARAM_TYPE => 'title', |
128 | ParamValidator::PARAM_REQUIRED => true, |
129 | TitleDef::PARAM_RETURN_OBJECT => true, |
130 | TitleDef::PARAM_MUST_EXIST => true, |
131 | ] |
132 | ]; |
133 | } |
134 | |
135 | /** |
136 | * @inheritDoc |
137 | * @return array[] |
138 | */ |
139 | public function getBodyParamSettings(): array { |
140 | return [ |
141 | 'editRevId' => [ |
142 | self::PARAM_SOURCE => 'body', |
143 | ParamValidator::PARAM_TYPE => 'integer', |
144 | ParamValidator::PARAM_REQUIRED => false, |
145 | ], |
146 | 'filename' => [ |
147 | self::PARAM_SOURCE => 'body', |
148 | ParamValidator::PARAM_TYPE => 'string', |
149 | ParamValidator::PARAM_REQUIRED => true, |
150 | ], |
151 | 'accepted' => [ |
152 | self::PARAM_SOURCE => 'body', |
153 | ParamValidator::PARAM_TYPE => 'boolean', |
154 | ParamValidator::PARAM_REQUIRED => true, |
155 | ], |
156 | 'reasons' => [ |
157 | self::PARAM_SOURCE => 'body', |
158 | ParamValidator::PARAM_TYPE => AddImageSubmissionHandler::REJECTION_REASONS, |
159 | ParamValidator::PARAM_ISMULTI => true, |
160 | ParamValidator::PARAM_REQUIRED => false, |
161 | ], |
162 | 'caption' => [ |
163 | self::PARAM_SOURCE => 'body', |
164 | ParamValidator::PARAM_TYPE => 'string', |
165 | ParamValidator::PARAM_REQUIRED => false, |
166 | ], |
167 | 'sectionTitle' => [ |
168 | self::PARAM_SOURCE => 'body', |
169 | ParamValidator::PARAM_TYPE => 'string', |
170 | ParamValidator::PARAM_REQUIRED => false, |
171 | ], |
172 | 'sectionNumber' => [ |
173 | self::PARAM_SOURCE => 'body', |
174 | ParamValidator::PARAM_TYPE => 'integer', |
175 | ParamValidator::PARAM_REQUIRED => false, |
176 | ] |
177 | ] + $this->getTokenParamDefinition(); |
178 | } |
179 | |
180 | /** |
181 | * @inheritDoc |
182 | */ |
183 | public function validate( Validator $restValidator ) { |
184 | parent::validate( $restValidator ); |
185 | $this->validateToken(); |
186 | } |
187 | |
188 | private function makeException( string $messageKey, array $params = [], int $errorCode = 400 ) { |
189 | return new LocalizedHttpException( new MessageValue( $messageKey, $params ), $errorCode ); |
190 | } |
191 | |
192 | } |