Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
9.43% covered (danger)
9.43%
5 / 53
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
LiftWingClient
9.43% covered (danger)
9.43%
5 / 53
20.00% covered (danger)
20.00%
1 / 5
138.54
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 get
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
90
 getBaseUrl
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getHostHeader
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 createErrorResponse
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17 * @file
18 */
19
20namespace AutoModerator;
21
22use MediaWiki\Json\FormatJson;
23use MediaWiki\MediaWikiServices;
24use RuntimeException;
25
26class LiftWingClient {
27
28    /** @var string */
29    private $model;
30
31    /** @var string */
32    private $lang;
33
34    /** @var string */
35    private string $baseUrl;
36
37    /** @var ?string */
38    private ?string $hostHeader;
39
40    public function __construct(
41        string $model,
42        string $lang,
43        string $baseUrl,
44        string $hostHeader = null
45    ) {
46        $this->model = $model;
47        $this->lang = $lang;
48        $this->baseUrl = $baseUrl;
49        $this->hostHeader = $hostHeader;
50    }
51
52    /**
53     * Make a single call to LW revert risk model for one revid and return the decoded result.
54     *
55     * @param int $revId
56     *
57     * @return array Decoded response
58     */
59    public function get( $revId ) {
60        $url = $this->baseUrl . $this->model . ':predict';
61        $httpRequestFactory = MediaWikiServices::getInstance()->getHttpRequestFactory();
62        $req = $httpRequestFactory->create( $url, [
63            'method' => 'POST',
64            'postData' => json_encode( [
65                'rev_id' => (int)$revId,
66                'lang' => $this->lang,
67            ] ),
68        ] );
69        if ( $this->hostHeader ) {
70            $req->setHeader( 'Host', $this->hostHeader );
71        }
72        $response = $req->execute();
73        if ( !$response->isOK() ) {
74            $httpStatus = $req->getStatus();
75            $data = FormatJson::decode( $req->getContent(), true );
76            if ( !$data ) {
77                $data = [];
78                $message = 'url returned status for rev rev_id lang';
79                $data['error'] = strtr( $message, [
80                    'url' => $url,
81                    'status' => (string)$httpStatus,
82                    'rev_id' => (string)$revId,
83                    'lang' => $this->lang,
84                ] );
85            }
86            $errorMessage = $data['error'] ?? $data['detail'];
87            if ( ( $httpStatus >= 400 ) && ( $httpStatus <= 499 ) ) {
88                return $this->createErrorResponse( $httpStatus, $errorMessage, false );
89            } else {
90                $req = $httpRequestFactory->create( $url, [
91                    'method' => 'POST',
92                    'postData' => json_encode( [
93                        'rev_id' => (int)$revId,
94                        'lang' => $this->lang,
95                    ] ),
96                ] );
97                $response = $req->execute();
98                if ( !$response->isOK() ) {
99                    return $this->createErrorResponse( $httpStatus, $errorMessage, true );
100                }
101            }
102        }
103        $json = $req->getContent();
104        $data = FormatJson::decode( $json, true );
105        if ( !$data || !empty( $data['error'] ) ) {
106            throw new RuntimeException( "Bad response from Lift Wing endpoint [{$url}]: {$json}" );
107        }
108        return $data;
109    }
110
111    /**
112     * @return string
113     */
114    public function getBaseUrl(): string {
115        return $this->baseUrl;
116    }
117
118    /**
119     * @return ?string
120     */
121    public function getHostHeader(): ?string {
122        return $this->hostHeader;
123    }
124
125    /**
126     * @param int $httpStatus
127     * @param string $errorMessage
128     * @return array
129     */
130    public function createErrorResponse(
131        int $httpStatus,
132        string $errorMessage,
133        bool $allowRetries
134    ): array {
135        return [
136            "httpStatus" => $httpStatus,
137            "errorMessage" => $errorMessage,
138            "allowRetries" => $allowRetries
139        ];
140    }
141
142}