1<?php
2/**
3 * Matomo - free/libre analytics platform
4 *
5 * @link https://matomo.org
6 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7 *
8 */
9namespace Piwik\Plugins\Marketplace\Api;
10
11use Piwik\Http;
12
13/**
14 *
15 */
16class Service
17{
18    const CACHE_TIMEOUT_IN_SECONDS = 1200;
19    const HTTP_REQUEST_TIMEOUT = 60;
20
21    /**
22     * @var string
23     */
24    private $domain;
25
26    /**
27     * @var null|string
28     */
29    private $accessToken;
30
31    /**
32     * API version to use on the Marketplace
33     * @var string
34     */
35    private $version = '2.0';
36
37    public function __construct($domain)
38    {
39        $this->domain = $domain;
40    }
41
42    public function authenticate($accessToken)
43    {
44        if (empty($accessToken)) {
45            $this->accessToken = null;
46        } elseif (ctype_alnum($accessToken)) {
47            $this->accessToken = $accessToken;
48        }
49    }
50
51    /**
52     * The API version that will be used on the Marketplace.
53     * @return string eg 2.0
54     */
55    public function getVersion()
56    {
57        return $this->version;
58    }
59
60    /**
61     * Returns the currently set access token
62     * @return null|string
63     */
64    public function getAccessToken()
65    {
66        return $this->accessToken;
67    }
68
69    public function hasAccessToken()
70    {
71        return !empty($this->accessToken);
72    }
73
74    /**
75     * Downloads data from the given URL via a POST request. If a destination path is given, the downloaded data
76     * will be stored in the given path and returned otherwise.
77     *
78     * Make sure to call {@link authenticate()} to download paid plugins.
79     *
80     * @param string $url An absolute URL to the marketplace including domain.
81     * @param null|string $destinationPath
82     * @param null|int $timeout  Defaults to 60 seconds see {@link self::HTTP_REQUEST_METHOD}
83     * @return bool|string  Returns the downloaded data or true if a destination path was given.
84     * @throws \Exception
85     */
86    public function download($url, $destinationPath = null, $timeout = null)
87    {
88        $method = Http::getTransportMethod();
89
90        if (!isset($timeout)) {
91            $timeout = static::HTTP_REQUEST_TIMEOUT;
92        }
93
94        $post = null;
95        if ($this->accessToken) {
96            $post = array('access_token' => $this->accessToken);
97        }
98
99        $file = Http::ensureDestinationDirectoryExists($destinationPath);
100
101        $response = Http::sendHttpRequestBy($method,
102                                            $url,
103                                            $timeout,
104                                            $userAgent = null,
105                                            $destinationPath,
106                                            $file,
107                                            $followDepth = 0,
108                                            $acceptLanguage = false,
109                                            $acceptInvalidSslCertificate = false,
110                                            $byteRange = false, $getExtendedInfo = false, $httpMethod = 'POST',
111                                            $httpUsername = null, $httpPassword = null, $post);
112
113        return $response;
114    }
115
116    /**
117     * Executes the given API action on the Marketplace using the given params and returns the result.
118     *
119     * Make sure to call {@link authenticate()} to download paid plugins.
120     *
121     * @param string $action  eg 'plugins', 'plugins/$pluginName/info', ...
122     * @param array $params   eg array('sort' => 'alpha')
123     * @return mixed
124     * @throws Service\Exception
125     */
126    public function fetch($action, $params)
127    {
128        $endpoint = sprintf('%s/api/%s/', $this->domain, $this->version);
129
130        $query = Http::buildQuery($params);
131        $url   = sprintf('%s%s?%s', $endpoint, $action, $query);
132
133        $response = $this->download($url);
134
135        $result = json_decode($response, true);
136
137        if (is_null($result)) {
138            $message = sprintf('There was an error reading the response from the Marketplace: Please try again later.');
139            throw new Service\Exception($message, Service\Exception::HTTP_ERROR);
140        }
141
142        if (!empty($result['error'])) {
143            throw new Service\Exception($result['error'], Service\Exception::API_ERROR);
144        }
145
146        return $result;
147    }
148
149    /**
150     * Get the domain that is used in order to access the Marketplace. Eg http://plugins.piwik.org
151     * @return string
152     */
153    public function getDomain()
154    {
155        return $this->domain;
156    }
157
158}
159