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