GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — master ( cd4897...6c84a1 )
by Freek
01:09
created

Client::rpcEndpointRequest()   A

Complexity

Conditions 3
Paths 5

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nc 5
nop 2
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\Dropbox;
4
5
use Exception;
6
use GuzzleHttp\Psr7\StreamWrapper;
7
use GuzzleHttp\Client as GuzzleClient;
8
use Psr\Http\Message\ResponseInterface;
9
use GuzzleHttp\Exception\ClientException;
10
use Spatie\Dropbox\Exceptions\BadRequest;
11
12
class Client
13
{
14
    const THUMBNAIL_FORMAT_JPEG = 'jpeg';
15
    const THUMBNAIL_FORMAT_PNG = 'png';
16
17
    const THUMBNAIL_SIZE_XS = 'w32h32';
18
    const THUMBNAIL_SIZE_S = 'w64h64';
19
    const THUMBNAIL_SIZE_M = 'w128h128';
20
    const THUMBNAIL_SIZE_L = 'w640h480';
21
    const THUMBNAIL_SIZE_XL = 'w1024h768';
22
23
    /** @var string */
24
    protected $accessToken;
25
26
    /** @var \GuzzleHttp\Client */
27
    protected $client;
28
29
    public function __construct(string $accessToken, GuzzleClient $client = null)
30
    {
31
        $this->accessToken = $accessToken;
32
33
        $this->client = $client ?? new GuzzleClient([
34
                'headers' => [
35
                    'Authorization' => "Bearer {$this->accessToken}",
36
                ],
37
            ]);
38
    }
39
40
    /**
41
     * Copy a file or folder to a different location in the user's Dropbox.
42
     *
43
     * If the source path is a folder all its contents will be copied.
44
     *
45
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-copy
46
     */
47 View Code Duplication
    public function copy(string $fromPath, string $toPath): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
48
    {
49
        $parameters = [
50
            'from_path' => $this->normalizePath($fromPath),
51
            'to_path' => $this->normalizePath($toPath),
52
        ];
53
54
        return $this->rpcEndpointRequest('files/copy', $parameters);
55
    }
56
57
    /**
58
     * Create a folder at a given path.
59
     *
60
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-create_folder
61
     */
62
    public function createFolder(string $path): array
63
    {
64
        $parameters = [
65
            'path' => $this->normalizePath($path),
66
        ];
67
68
        $object = $this->rpcEndpointRequest('files/create_folder', $parameters);
69
70
        $object['.tag'] = 'folder';
71
72
        return $object;
73
    }
74
75
    /**
76
     * Create a shared link with custom settings.
77
     *
78
     * If no settings are given then the default visibility is RequestedVisibility.public.
79
     * The resolved visibility, though, may depend on other aspects such as team and
80
     * shared folder settings). Only for paid users.
81
     *
82
     * @link https://www.dropbox.com/developers/documentation/http/documentation#sharing-create_shared_link_with_settings
83
     */
84 View Code Duplication
    public function createSharedLinkWithSettings(string $path, array $settings = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
85
    {
86
        $parameters = [
87
            'path' => $this->normalizePath($path),
88
            'settings' => $settings,
89
        ];
90
91
        return $this->rpcEndpointRequest('sharing/create_shared_link_with_settings', $parameters);
92
    }
93
94
    /**
95
     * List shared links.
96
     *
97
     * For empty path returns a list of all shared links. For non-empty path
98
     * returns a list of all shared links with access to the given path.
99
     *
100
     * @link https://www.dropbox.com/developers/documentation/http/documentation#sharing-list_shared_links
101
     */
102 View Code Duplication
    public function listSharedLinks(string $path): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
103
    {
104
        $parameters = [
105
            'path' => $this->normalizePath($path),
106
        ];
107
108
        $body = $this->rpcEndpointRequest('sharing/list_shared_links', $parameters);
109
110
        return $body['links'];
111
    }
112
113
    /**
114
     * Delete the file or folder at a given path.
115
     *
116
     * If the path is a folder, all its contents will be deleted too.
117
     * A successful response indicates that the file or folder was deleted.
118
     *
119
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-delete
120
     */
121
    public function delete(string $path): array
122
    {
123
        $parameters = [
124
            'path' => $this->normalizePath($path),
125
        ];
126
127
        return $this->rpcEndpointRequest('files/delete', $parameters);
128
    }
129
130
    /**
131
     * Download a file from a user's Dropbox.
132
     *
133
     * @param string $path
134
     *
135
     * @return resource
136
     *
137
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-download
138
     */
139
    public function download(string $path)
140
    {
141
        $arguments = [
142
            'path' => $this->normalizePath($path),
143
        ];
144
145
        $response = $this->contentEndpointRequest('files/download', $arguments);
146
147
        return StreamWrapper::getResource($response->getBody());
148
    }
149
150
    /**
151
     * Returns the metadata for a file or folder.
152
     *
153
     * Note: Metadata for the root folder is unsupported.
154
     *
155
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_metadata
156
     */
157
    public function getMetadata(string $path): array
158
    {
159
        $parameters = [
160
            'path' => $this->normalizePath($path),
161
        ];
162
163
        return $this->rpcEndpointRequest('files/get_metadata', $parameters);
164
    }
165
166
    /**
167
     * Get a temporary link to stream content of a file.
168
     *
169
     * This link will expire in four hours and afterwards you will get 410 Gone.
170
     * Content-Type of the link is determined automatically by the file's mime type.
171
     *
172
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_temporary_link
173
     */
174 View Code Duplication
    public function getTemporaryLink(string $path): string
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
175
    {
176
        $parameters = [
177
            'path' => $this->normalizePath($path),
178
        ];
179
180
        $body = $this->rpcEndpointRequest('files/get_temporary_link', $parameters);
181
182
        return $body['link'];
183
    }
184
185
    /**
186
     * Get a thumbnail for an image.
187
     *
188
     * This method currently supports files with the following file extensions:
189
     * jpg, jpeg, png, tiff, tif, gif and bmp.
190
     *
191
     * Photos that are larger than 20MB in size won't be converted to a thumbnail.
192
     *
193
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-get_thumbnail
194
     */
195
    public function getThumbnail(string $path, string $format = 'jpeg', string $size = 'w64h64'): string
196
    {
197
        $arguments = [
198
            'path' => $this->normalizePath($path),
199
            'format' => $format,
200
            'size' => $size,
201
        ];
202
203
        $response = $this->contentEndpointRequest('files/get_thumbnail', $arguments);
204
205
        return (string) $response->getBody();
206
    }
207
208
    /**
209
     * Starts returning the contents of a folder.
210
     *
211
     * If the result's ListFolderResult.has_more field is true, call
212
     * list_folder/continue with the returned ListFolderResult.cursor to retrieve more entries.
213
     *
214
     * Note: auth.RateLimitError may be returned if multiple list_folder or list_folder/continue calls
215
     * with same parameters are made simultaneously by same API app for same user. If your app implements
216
     * retry logic, please hold off the retry until the previous request finishes.
217
     *
218
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder
219
     */
220 View Code Duplication
    public function listFolder(string $path = '', bool $recursive = false): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
221
    {
222
        $parameters = [
223
            'path' => $this->normalizePath($path),
224
            'recursive' => $recursive,
225
        ];
226
227
        return $this->rpcEndpointRequest('files/list_folder', $parameters);
228
    }
229
230
    /**
231
     * Once a cursor has been retrieved from list_folder, use this to paginate through all files and
232
     * retrieve updates to the folder, following the same rules as documented for list_folder.
233
     *
234
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-list_folder-continue
235
     */
236
    public function listFolderContinue(string $cursor = ''): array
237
    {
238
        return $this->rpcEndpointRequest('files/list_folder/continue', compact('cursor'));
239
    }
240
241
    /**
242
     * Move a file or folder to a different location in the user's Dropbox.
243
     *
244
     * If the source path is a folder all its contents will be moved.
245
     *
246
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-move
247
     */
248 View Code Duplication
    public function move(string $fromPath, string $toPath): array
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
249
    {
250
        $parameters = [
251
            'from_path' => $this->normalizePath($fromPath),
252
            'to_path' => $this->normalizePath($toPath),
253
        ];
254
255
        return $this->rpcEndpointRequest('files/move', $parameters);
256
    }
257
258
    /**
259
     * Create a new file with the contents provided in the request.
260
     *
261
     * Do not use this to upload a file larger than 150 MB. Instead, create an upload session with upload_session/start.
262
     *
263
     * @link https://www.dropbox.com/developers/documentation/http/documentation#files-upload
264
     *
265
     * @param string $path
266
     * @param string|resource $contents
267
     * @param string|array $mode
268
     *
269
     * @return array
270
     */
271
    public function upload(string $path, $contents, $mode = 'add'): array
272
    {
273
        $arguments = [
274
            'path' => $this->normalizePath($path),
275
            'mode' => $mode,
276
        ];
277
278
        $response = $this->contentEndpointRequest('files/upload', $arguments, $contents);
279
280
        $metadata = json_decode($response->getBody(), true);
281
282
        $metadata['.tag'] = 'file';
283
284
        return $metadata;
285
    }
286
287
    /**
288
     * Get Account Info for current authenticated user.
289
     *
290
     * @link https://www.dropbox.com/developers/documentation/http/documentation#users-get_current_account
291
     *
292
     * @return array
293
     */
294
    public function getAccountInfo(): array
295
    {
296
        return $this->rpcEndpointRequest('users/get_current_account');
297
    }
298
299
    /**
300
     * Revoke current access token.
301
     *
302
     * @link https://www.dropbox.com/developers/documentation/http/documentation#auth-token-revoke
303
     */
304
    public function revokeToken()
305
    {
306
        $this->rpcEndpointRequest('auth/token/revoke');
307
    }
308
309
    protected function normalizePath(string $path): string
310
    {
311
        $path = trim($path, '/');
312
313
        return ($path === '') ? '' : '/'.$path;
314
    }
315
316
    /**
317
     * @param string $endpoint
318
     * @param array $arguments
319
     * @param string|resource $body
320
     *
321
     * @return \Psr\Http\Message\ResponseInterface
322
     *
323
     * @throws \Exception
324
     */
325
    public function contentEndpointRequest(string $endpoint, array $arguments, $body = ''): ResponseInterface
326
    {
327
        $headers['Dropbox-API-Arg'] = json_encode($arguments);
0 ignored issues
show
Coding Style Comprehensibility introduced by
$headers was never initialized. Although not strictly required by PHP, it is generally a good practice to add $headers = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
328
329
        if ($body !== '') {
330
            $headers['Content-Type'] = 'application/octet-stream';
331
        }
332
333
        try {
334
            $response = $this->client->post("https://content.dropboxapi.com/2/{$endpoint}", [
335
                'headers' => $headers,
336
                'body' => $body,
337
            ]);
338
        } catch (ClientException $exception) {
339
            throw $this->determineException($exception);
340
        }
341
342
        return $response;
343
    }
344
345
    public function rpcEndpointRequest(string $endpoint, array $parameters = null): array
346
    {
347
        try {
348
            $options = [];
349
350
            if ($parameters) {
351
                $options['json'] = $parameters;
352
            }
353
354
            $response = $this->client->post("https://api.dropboxapi.com/2/{$endpoint}", $options);
355
        } catch (ClientException $exception) {
356
            throw $this->determineException($exception);
357
        }
358
359
        $response = json_decode($response->getBody(), true);
360
361
        return $response ?? [];
362
    }
363
364
    protected function determineException(ClientException $exception): Exception
365
    {
366
        if (in_array($exception->getResponse()->getStatusCode(), [400, 409])) {
367
            return new BadRequest($exception->getResponse());
0 ignored issues
show
Bug introduced by
It seems like $exception->getResponse() can be null; however, __construct() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
368
        }
369
370
        return $exception;
371
    }
372
}
373