Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
63.64% |
35 / 55 |
|
33.33% |
1 / 3 |
CRAP | |
0.00% |
0 / 1 |
ActionApiImageRecommendationApiHandler | |
63.64% |
35 / 55 |
|
33.33% |
1 / 3 |
21.13 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
getApiRequest | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
2 | |||
getSuggestionDataFromApiResponse | |
82.05% |
32 / 39 |
|
0.00% |
0 / 1 |
11.70 |
1 | <?php |
2 | |
3 | namespace GrowthExperiments\NewcomerTasks\AddImage; |
4 | |
5 | use GrowthExperiments\NewcomerTasks\TaskType\ImageRecommendationTaskTypeHandler; |
6 | use GrowthExperiments\NewcomerTasks\TaskType\SectionImageRecommendationTaskTypeHandler; |
7 | use GrowthExperiments\NewcomerTasks\TaskType\TaskType; |
8 | use MediaWiki\Api\ApiRawMessage; |
9 | use MediaWiki\Http\HttpRequestFactory; |
10 | use MediaWiki\Language\RawMessage; |
11 | use MediaWiki\Logger\LoggerFactory; |
12 | use MediaWiki\Status\Status; |
13 | use MediaWiki\Title\Title; |
14 | use RuntimeException; |
15 | use StatusValue; |
16 | |
17 | /** |
18 | * Handler for the action=query&prop=growthimagesuggestiondata API. |
19 | * Uses a remote installation of this extension to proxy from ProductionApiImageRecommendationApiHandler. |
20 | * Documentation: https://en.wikipedia.org/wiki/Special:ApiHelp/query+growthimagesuggestiondata |
21 | * Configuration of constructor parameters: |
22 | * - $apiUrl: GEImageRecommendationServiceUrl (should point to api.php) |
23 | * - $accessToken: GEImageRecommendationServiceAccessToken |
24 | */ |
25 | class ActionApiImageRecommendationApiHandler implements ImageRecommendationApiHandler { |
26 | |
27 | private HttpRequestFactory $httpRequestFactory; |
28 | /** @var string api.php URL */ |
29 | private string $apiUrl; |
30 | /** @var string MediaWiki OAuth 2 access token for upstream wiki */ |
31 | private string $accessToken; |
32 | |
33 | /** |
34 | * @param HttpRequestFactory $httpRequestFactory |
35 | * @param string $apiUrl api.php URL |
36 | * @param string $accessToken |
37 | */ |
38 | public function __construct( |
39 | HttpRequestFactory $httpRequestFactory, |
40 | string $apiUrl, |
41 | string $accessToken |
42 | ) { |
43 | $this->httpRequestFactory = $httpRequestFactory; |
44 | $this->apiUrl = $apiUrl; |
45 | $this->accessToken = $accessToken; |
46 | } |
47 | |
48 | /** @inheritDoc */ |
49 | public function getApiRequest( Title $title, TaskType $taskType ) { |
50 | // Ideally we'd use Util::getApiUrl() + maybe handle continuation, but the |
51 | // RecommendationProvider/ApiHandler split prevents that. |
52 | $url = wfAppendQuery( $this->apiUrl, [ |
53 | 'action' => 'query', |
54 | 'prop' => 'growthimagesuggestiondata', |
55 | 'titles' => $title->getPrefixedText(), |
56 | 'gisdtasktype' => $taskType->getId(), |
57 | 'format' => 'json', |
58 | 'formatversion' => '2', |
59 | 'errorformat' => 'wikitext', |
60 | 'errorlang' => 'en', |
61 | ] ); |
62 | $request = $this->httpRequestFactory->create( $url, [], __METHOD__ ); |
63 | $request->setHeader( 'Authorization', 'Bearer ' . $this->accessToken ); |
64 | return $request; |
65 | } |
66 | |
67 | /** @inheritDoc */ |
68 | public function getSuggestionDataFromApiResponse( array $apiResponse, TaskType $taskType ) { |
69 | // based on Util::getApiUrl() |
70 | if ( isset( $apiResponse['errors'] ) ) { |
71 | $errorStatus = StatusValue::newGood(); |
72 | foreach ( $apiResponse['errors'] as $error ) { |
73 | $errorStatus->fatal( new ApiRawMessage( $error['text'], $error['code'] ) ); |
74 | } |
75 | return $errorStatus; |
76 | } |
77 | if ( isset( $apiResponse['warnings'] ) ) { |
78 | $warningStatus = StatusValue::newGood(); |
79 | foreach ( $apiResponse['warnings'] as $warning ) { |
80 | $warningStatus->warning( new RawMessage( $warning['module'] . ': ' . $warning['text'] ) ); |
81 | } |
82 | LoggerFactory::getInstance( 'GrowthExperiments' )->warning( |
83 | Status::wrap( $warningStatus )->getWikiText( false, false, 'en' ), |
84 | [ 'exception' => new RuntimeException ] |
85 | ); |
86 | } |
87 | |
88 | if ( isset( $apiResponse['query']['pages'][0]['growthimagesuggestiondataerrors'] ) ) { |
89 | $errorStatus = StatusValue::newGood(); |
90 | foreach ( $apiResponse['query']['pages'][0]['growthimagesuggestiondataerrors'] as $error ) { |
91 | $errorStatus->fatal( new ApiRawMessage( $error['text'], $error['code'] ) ); |
92 | } |
93 | return $errorStatus; |
94 | } |
95 | if ( !isset( $apiResponse['query']['pages'][0]['growthimagesuggestiondata'] ) ) { |
96 | // page not found or has no suggestions |
97 | return []; |
98 | } |
99 | $imageRecommendationArray = $apiResponse['query']['pages'][0]['growthimagesuggestiondata'][0]; |
100 | // $imageRecommendationArray is a serialized ImageRecommendation; the nice thing to do here |
101 | // would be to just deserialize it, but ServiceImageRecommendationProvider / ApiHandler are |
102 | // not structured right for that. |
103 | |
104 | $imageData = []; |
105 | foreach ( $imageRecommendationArray['images'] as $imageDataArray ) { |
106 | $imageDataArrayTaskTypeId = isset( $imageDataArray['sectionTitle'] ) ? |
107 | SectionImageRecommendationTaskTypeHandler::TASK_TYPE_ID : |
108 | ImageRecommendationTaskTypeHandler::TASK_TYPE_ID; |
109 | if ( $imageDataArrayTaskTypeId !== $taskType->getId() ) { |
110 | continue; |
111 | } |
112 | |
113 | $source = ImageRecommendationImage::SOURCE_ALIASES[ $imageDataArray['source'] ] |
114 | ?? $imageDataArray['source']; |
115 | $imageData[] = new ImageRecommendationData( |
116 | $imageDataArray['image'], |
117 | $source, |
118 | implode( ',', $imageDataArray['projects'] ?? [] ), |
119 | $imageRecommendationArray['datasetId'], |
120 | // the fallbacks are only needed until d78543cb reaches production |
121 | $imageDataArray['sectionNumber'] ?? null, |
122 | $imageDataArray['sectionTitle'] ?? null |
123 | ); |
124 | } |
125 | return $imageData; |
126 | } |
127 | |
128 | } |