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.
Passed
Push — master ( aa0f10...08e6ad )
by
unknown
01:54
created

LeverPhp::parse()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace ViaWork\LeverPhp;
4
5
use Exception;
6
use GrahamCampbell\GuzzleFactory\GuzzleFactory;
7
use GuzzleHttp\Client as GuzzleClient;
8
use GuzzleHttp\Exception\ClientException;
9
use GuzzleHttp\HandlerStack;
10
use Illuminate\Support\LazyCollection;
11
use Psr\Http\Message\ResponseInterface;
12
use Spatie\GuzzleRateLimiterMiddleware\RateLimiterMiddleware;
13
use Spatie\GuzzleRateLimiterMiddleware\Store;
14
15
class LeverPhp
16
{
17
    const BACKOFF_TIME = 1500;
18
19
    private $leverKey = '';
20
21
    private $endpoint = '';
22
23
    private $client;
24
25
    private $options = [];
26
27
    /**
28
     * LeverPhp constructor.
29
     * @param string|null $leverKey
30
     * @param GuzzleClient|null $client
31
     * @param Store|null $store
32
     */
33
    public function __construct(string $leverKey = null, GuzzleClient $client = null, Store $store = null)
34
    {
35
        $this->leverKey = $leverKey;
36
37
        $stack = HandlerStack::create();
38
39
        $stack->push(DuplicateAggregatorMiddleware::buildQuery());
40
41
        $stack->push(RateLimiterMiddleware::perSecond(10, $store));
42
43
        $this->client = $client ?? GuzzleFactory::make(
44
                [
45
                    'base_uri' => 'https://api.lever.co/v1/',
46
                    'headers' => [
47
                        'Accept' => 'application/json',
48
                    ],
49
                    'auth' => [$leverKey, ''],
50
                    'handler' => $stack,
51
                ],
52
                self::BACKOFF_TIME
53
            );
54
    }
55
56
    private function reset()
57
    {
58
        $this->endpoint = '';
59
        $this->options = [];
60
    }
61
62
    private function post(array $body): ResponseInterface
63
    {
64
        try {
65
            $response = $this->client->post($this->endpoint, $this->options($body));
66
        } catch (ClientException $exception) {
67
            throw $exception;
68
        } finally {
69
            $this->reset();
70
        }
71
72
        return $response;
73
    }
74
75
    private function options($body)
76
    {
77
        if (isset($this->options['hasFiles'])) {
78
            $options = [];
79
80
            foreach ($body as $key => $item) {
81
82
                // TODO add support for files[] and automate filename and headers fields.
83
                if (in_array($key, ['file', 'files', 'resumeFile'])) {
84
                    $options[] = [
85
                        'name' => $key,
86
                        'contents' => $item['file'],
87
                        'filename' =>  $item['name'],
88
                        'headers' => ['Content-Type' => $item['type']],
89
                    ];
90
91
                    continue;
92
                }
93
94
                if (is_array($item)) {
95
                    foreach ($item as $subKey => $subItem) {
96
                        if (is_numeric($subKey)) {
97
                            $options[] = ['name' => $key.'[]', 'contents' => $subItem];
98
                        }
99
100
                        if (is_string($subKey)) {
101
                            $options[] = ['name' => "{$key}[{$subKey}]", 'contents' => $subItem];
102
                        }
103
                    }
104
                }
105
106
                if (is_string($item)) {
107
                    $options[] = ['name' => $key, 'contents' => $item];
108
                }
109
            }
110
111
            unset($this->options['hasFiles']);
112
113
            return array_merge(['multipart' => $options], $this->options);
114
        }
115
116
        return array_merge(['json' => $body], $this->options);
117
    }
118
119
    private function get(): ResponseInterface
120
    {
121
        try {
122
            $response = $this->client->get($this->endpoint, $this->options);
123
        } catch (ClientException $exception) {
124
            throw $exception;
125
        } finally {
126
            $this->reset();
127
        }
128
129
        return $response;
130
    }
131
132
    public function create(array $body): array
133
    {
134
        $response = $this->responseToArray($this->post($body));
135
136
        return $response['data'];
137
    }
138
139
    public function update(array $body): array
140
    {
141
        return $this->create($body);
142
    }
143
144
    /** @return LazyCollection|array */
145
    public function fetch()
146
    {
147
        $response = $this->responseToArray($this->get());
148
149
        if (! array_key_exists('hasNext', $response)) {
150
            return $response['data'];
151
        }
152
153
        return LazyCollection::make(function () use ($response) {
154
            do {
155
                foreach ($response['data'] as $item) {
156
                    yield $item;
157
                }
158
159
                $response['data'] = [];
160
161
                if (! empty($response['next'])) {
162
                    $response = $this->responseToArray(
163
                        $this->addParameter('offset', $response['next'])->get()
164
                    );
165
                }
166
            } while (count($response['data']) > 0);
167
        });
168
    }
169
170
    public function leverKey(): string
171
    {
172
        return $this->leverKey;
173
    }
174
175
    public function client(): GuzzleClient
176
    {
177
        return $this->client;
178
    }
179
180
    private function responseToArray(ResponseInterface $response): array
181
    {
182
        return json_decode($response->getBody()->getContents(), true);
183
    }
184
185
    public function expand($expandable)
186
    {
187
        return $this->addParameter('expand', $expandable);
188
    }
189
190
    public function performAs(string $userId)
191
    {
192
        return $this->addParameter('perform_as', $userId);
193
    }
194
195
    public function include($includable)
196
    {
197
        return $this->addParameter('include', $includable);
198
    }
199
200
    /**
201
     * @param string $field
202
     * @param string|array $value
203
     * @return $this
204
     */
205
    public function addParameter(string $field, $value)
206
    {
207
        if (! empty($field) && ! empty($value)) {
208
            $value = is_string($value) ? [$value] : $value;
209
210
            $this->options['query'][$field] = array_merge($this->options['query'][$field] ?? [], $value);
211
        }
212
213
        return $this;
214
    }
215
216
    public function opportunities(string $opportunityId = '')
217
    {
218
        $this->endpoint = 'opportunities'.(empty($opportunityId) ? '' : '/'.$opportunityId);
219
220
        return $this;
221
    }
222
223
    public function resumes(string $resumeId = '')
224
    {
225
        $this->endpoint .= '/resumes'.(empty($resumeId) ? '' : '/'.$resumeId);
226
227
        return $this;
228
    }
229
230
    public function download()
231
    {
232
        $this->endpoint .= '/download';
233
234
        return $this;
235
    }
236
237
    public function offers()
238
    {
239
        // TODO next release.
240
        // $regex = '/^opportunities\/[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/';
241
        // if (preg_match($regex, $this->endpoint) === 0){
242
        //     throw new Exception('Did not chain methods in correct order.');
243
        // }
244
245
        $this->endpoint .= '/offers';
246
247
        return $this;
248
    }
249
250
    public function postings(string $postingId = '')
251
    {
252
        $this->endpoint = 'postings'.(empty($postingId) ? '' : '/'.$postingId);
253
254
        return $this;
255
    }
256
257
    public function sendConfirmationEmail()
258
    {
259
        return $this->addParameter('send_confirmation_email', 'true');
260
    }
261
262
    public function apply(array $body): array
263
    {
264
        $this->endpoint .= '/apply';
265
266
        return $this->create($body);
267
    }
268
269
    public function state(string $state)
270
    {
271
        if (! in_array($state, ['published', 'internal', 'closed', 'draft', 'pending', 'rejected'])) {
272
            throw new Exception('Not a valid state');
273
        }
274
275
        return $this->addParameter('state', $state);
276
    }
277
278
    /**
279
     * @param array|string $team
280
     * @return $this
281
     */
282
    public function team($team)
283
    {
284
        return $this->addParameter('team', $team);
285
    }
286
287
    /**
288
     * @param array|string $department
289
     * @return $this
290
     */
291
    public function department($department)
292
    {
293
        return $this->addParameter('department', $department);
294
    }
295
296
    /**
297
     * @return $this
298
     */
299
    public function parse()
300
    {
301
        return $this->addParameter('parse', 'true');
302
    }
303
304
    public function hasFiles()
305
    {
306
        $this->options['hasFiles'] = true;
307
308
        return $this;
309
    }
310
}
311