Passed
Pull Request — master (#167)
by
unknown
03:17
created

GoogleDriveApp::getAndSaveAccessToken()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 12
nc 8
nop 3
dl 0
loc 22
rs 9.5555
c 1
b 0
f 0
1
<?php
2
3
namespace Quantum\Libraries\Storage\Adapters\GoogleDrive;
4
5
use Quantum\Libraries\Curl\HttpClient;
6
use Quantum\Http\Response;
7
use Exception;
8
9
class GoogleDriveApp
10
{
11
    /**
12
     * Authorization URL
13
     */
14
    const AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
15
16
    /**
17
     * Authorization scope
18
     */
19
    const AUTH_SCOPE = 'https://www.googleapis.com/auth/drive';
20
21
    /**
22
     * Token URL
23
     */
24
    const AUTH_TOKEN_URL = 'https://oauth2.googleapis.com/token';
25
26
    /**
27
     * URL for file metadata operations
28
     */
29
    const FILE_METADATA_URL = 'https://www.googleapis.com/drive/v3/files';
30
31
    /**
32
     * URL for file media operations
33
     */
34
    const FILE_MEDIA_URL = 'https://www.googleapis.com/upload/drive/v3/files';
35
36
    /**
37
     * Folder mimetype
38
     */
39
    const FOLDER_MIMETYPE = 'application/vnd.google-apps.folder';
40
41
    /**
42
     * @var HttpClient
43
     */
44
    private $httpClient;
45
46
    /**
47
     * @var string
48
     */
49
    private $appKey = null;
50
51
    /**
52
     * @var string
53
     */
54
    private $appSecret = null;
55
56
    /**
57
     * @var TokenServiceInterface
58
     */
59
    private $tokenService = null;
60
61
    /**
62
     * GoogleDriveApp constructor
63
     * @param string $appKey
64
     * @param string $appSecret
65
     * @param TokenServiceInterface $tokenService
66
     * @param HttpClient $httpClient
67
     */
68
    public function __construct(string $appKey, string $appSecret, TokenServiceInterface $tokenService, HttpClient $httpClient)
69
    {
70
        $this->appKey = $appKey;
71
        $this->appSecret = $appSecret;
72
        $this->tokenService = $tokenService;
73
        $this->httpClient = $httpClient;
74
    }
75
76
    public function getAuthUrl($redirectUrl, $accessType = "offline"): string
77
    {
78
        $params = [
79
            'client_id' => $this->appKey,
80
            'response_type' => 'code',
81
            'state' => csrf_token(),
82
            'scope' => self::AUTH_SCOPE,
83
            'redirect_uri' => $redirectUrl,
84
            'access_type' => $accessType,
85
        ];
86
87
        return self::AUTH_URL . '?' . http_build_query($params, '', '&');
88
    }
89
90
    public function getAndSaveAccessToken($code, $redirectUrl = '', $byRefresh = false): object
91
    {
92
        $codeKey = $byRefresh ? 'refresh_token' : 'code';
93
94
        $params = [
95
            $codeKey => $code,
96
            'grant_type' => $byRefresh ? 'refresh_token' : 'authorization_code',
97
            'client_id' => $this->appKey,
98
            'client_secret' => $this->appSecret,
99
        ];
100
101
        if(!$byRefresh){
102
            $params['redirect_uri'] = $redirectUrl;
103
        }
104
105
        $tokenUrl = self::AUTH_TOKEN_URL;
106
107
        $response = $this->sendRequest($tokenUrl, $params);
108
109
        $this->tokenService->saveTokens($response->access_token, !$byRefresh ? $response->refresh_token : null);
110
111
        return $response;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $response could return the type mixed|null which is incompatible with the type-hinted return object. Consider adding an additional type-check to rule them out.
Loading history...
112
    }
113
114
    public function sendRequest(string $uri, $data = null, array $headers = [], $method = 'POST')
115
    {
116
        $this->httpClient
117
            ->createRequest($uri)
118
            ->setMethod($method)
119
            ->setData($data)
120
            ->setHeaders($headers)
121
            ->start();
122
123
124
        $errors = $this->httpClient->getErrors();
125
        $responseBody = $this->httpClient->getResponseBody();
126
127
        if ($errors) {
128
            $code = $errors['code'];
129
130
            if ($code == 401) {
131
                $prevUrl = $this->httpClient->url();
132
                $prevData = $this->httpClient->getData();
133
                $prevHeaders = $this->httpClient->getRequestHeaders();
134
135
                $refreshToken = $this->tokenService->getRefreshToken();
136
137
                $response = $this->getAndSaveAccessToken($refreshToken , '', true);
138
139
                $prevHeaders['Authorization'] = 'Bearer ' . $response->access_token;
140
141
                $responseBody = $this->sendRequest($prevUrl, $prevData, $prevHeaders);
142
143
            } else {
144
                throw new Exception(json_encode($responseBody ?? $errors), E_ERROR);
145
            }
146
        }
147
148
        return $responseBody;
149
    }
150
151
    /**
152
     * Sends rpc request
153
     * @param string $endpoint
154
     * @param mixed $params
155
     * @return mixed|null
156
     * @throws Exception
157
     */
158
    public function rpcRequest(string $url, $params = [], $method = 'POST', $contentType = 'application/json')
159
    {
160
        try {
161
            $headers = [
162
                'Authorization' => 'Bearer ' . $this->tokenService->getAccessToken(),
163
                'Content-Type' => $contentType
164
            ];
165
            return $this->sendRequest($url, $params, $headers, $method);
166
        }catch (Exception $e){
167
            throw new Exception($e->getMessage(), (int)$e->getCode());
168
        }
169
    }
170
171
    /**
172
     * Gets file information
173
     * @param string $fileId
174
     * @param bool $media
175
     * @param mixed $params
176
     * @return mixed|null
177
     * @throws Exception
178
     */
179
    public function getFileInfo(string $fileId, $media = false, $params = []){
180
        $queryParam = $media ? '?alt=media' : '?fields=*';
181
        return $this->rpcRequest(GoogleDriveApp::FILE_METADATA_URL . '/' . $fileId . $queryParam, $params, 'GET');
182
    }
183
}