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.

NewYnabJobHandler   A
last analyzed

Complexity

Total Complexity 25

Size/Duplication

Total Lines 219
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 25
eloc 90
dl 0
loc 219
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A setImportJob() 0 5 1
A hasRefreshToken() 0 16 3
A getNextView() 0 5 1
A getAccessToken() 0 45 4
A configureJob() 0 5 1
A configurationComplete() 0 19 5
A getNextData() 0 18 4
A hasClientId() 0 16 3
A hasClientSecret() 0 16 3
1
<?php
2
/**
3
 * NewYnabJobHandler.php
4
 * Copyright (c) 2019 [email protected]
5
 *
6
 * This file is part of Firefly III (https://github.com/firefly-iii).
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
declare(strict_types=1);
23
24
namespace FireflyIII\Support\Import\JobConfiguration\Ynab;
25
26
use FireflyIII\Exceptions\FireflyException;
27
use FireflyIII\Models\ImportJob;
28
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
29
use GuzzleHttp\Client;
30
use GuzzleHttp\Exception\GuzzleException;
31
use Illuminate\Support\MessageBag;
32
use Log;
33
use RuntimeException;
34
35
/**
36
 * Class NewYnabJobHandler
37
 * @deprecated
38
 * @codeCoverageIgnore
39
 */
40
class NewYnabJobHandler implements YnabJobConfigurationInterface
0 ignored issues
show
Deprecated Code introduced by
The interface FireflyIII\Support\Impor...bConfigurationInterface has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

40
class NewYnabJobHandler implements /** @scrutinizer ignore-deprecated */ YnabJobConfigurationInterface

This interface has been deprecated. The supplier of the interface has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the interface will be removed and what other interface to use instead.

Loading history...
41
{
42
    /** @var ImportJob */
43
    private $importJob;
44
    /** @var ImportJobRepositoryInterface */
45
    private $repository;
46
47
    /**
48
     * Return true when this stage is complete.
49
     *
50
     * @return bool
51
     * @throws FireflyException
52
     */
53
    public function configurationComplete(): bool
54
    {
55
        if (!$this->hasRefreshToken()) {
56
            Log::debug('YNAB NewYnabJobHandler configurationComplete: stage is new, no refresh token, return false');
57
58
            return false;
59
        }
60
        if ($this->hasRefreshToken() && $this->hasClientId() && $this->hasClientSecret()) {
61
            Log::debug('YNAB NewYnabJobHandler configurationComplete: stage is new, has a refresh token, return true');
62
            // need to grab access token using refresh token
63
            $this->getAccessToken();
64
            $this->repository->setStatus($this->importJob, 'ready_to_run');
65
            $this->repository->setStage($this->importJob, 'get_budgets');
66
67
            return true;
68
        }
69
        Log::error('YNAB NewYnabJobHandler configurationComplete: something broke, return true');
70
71
        return true;
72
    }
73
74
    /**
75
     * Store the job configuration. There is never anything to store for this stage.
76
     *
77
     * @param array $data
78
     *
79
     * @return MessageBag
80
     */
81
    public function configureJob(array $data): MessageBag
82
    {
83
        Log::debug('YNAB NewYnabJobHandler configureJob: nothing to do.');
84
85
        return new MessageBag;
86
    }
87
88
    /**
89
     * Get data for config view.
90
     *
91
     * @return array
92
     * @throws \Psr\Container\NotFoundExceptionInterface
93
     * @throws \Psr\Container\ContainerExceptionInterface
94
     */
95
    public function getNextData(): array
96
    {
97
        $data = [];
98
        // here we update the job so it can redirect properly to YNAB
99
        if (!$this->hasRefreshToken() && $this->hasClientSecret() && $this->hasClientId()) {
100
            // update stage to make sure we catch the token.
101
            $this->repository->setStage($this->importJob, 'catch-auth-code');
102
            $clientId          = app('preferences')->get('ynab_client_id')->data;
103
            $callBackUri       = route('import.callback.ynab');
104
            $uri               = sprintf(
105
                'https://app.youneedabudget.com/oauth/authorize?client_id=%s&redirect_uri=%s&response_type=code&state=%s', $clientId, $callBackUri,
106
                $this->importJob->key
107
            );
108
            $data['token-url'] = $uri;
109
            Log::debug(sprintf('YNAB getNextData: URI to redirect to is %s', $uri));
110
        }
111
112
        return $data;
113
    }
114
115
    /**
116
     * Get the view for this stage.
117
     *
118
     * @return string
119
     */
120
    public function getNextView(): string
121
    {
122
        Log::debug('Return YNAB redirect view.');
123
124
        return 'import.ynab.redirect';
125
    }
126
127
    /**
128
     * Set the import job.
129
     *
130
     * @param ImportJob $importJob
131
     */
132
    public function setImportJob(ImportJob $importJob): void
133
    {
134
        $this->importJob  = $importJob;
135
        $this->repository = app(ImportJobRepositoryInterface::class);
136
        $this->repository->setUser($importJob->user);
137
    }
138
139
140
    /**
141
     * @throws \Psr\Container\NotFoundExceptionInterface
142
     * @throws \Psr\Container\ContainerExceptionInterface
143
     * @throws FireflyException
144
     */
145
    private function getAccessToken(): void
146
    {
147
        $clientId     = app('preferences')->get('ynab_client_id')->data;
148
        $clientSecret = app('preferences')->get('ynab_client_secret')->data;
149
        $refreshToken = app('preferences')->get('ynab_refresh_token')->data;
150
        $uri          = sprintf(
151
            'https://app.youneedabudget.com/oauth/token?client_id=%s&client_secret=%s&grant_type=refresh_token&refresh_token=%s', $clientId, $clientSecret,
152
            $refreshToken
153
        );
154
155
        $client = new Client();
156
        try {
157
            $res = $client->request('post', $uri);
158
        } catch (GuzzleException $e) {
159
            Log::error($e->getMessage());
160
            Log::error($e->getTraceAsString());
161
            throw new FireflyException($e->getMessage());
162
        }
163
        $statusCode = $res->getStatusCode();
164
        try {
165
            $content = trim($res->getBody()->getContents());
166
        } catch (RuntimeException $e) {
167
            Log::error($e->getMessage());
168
            Log::error($e->getTraceAsString());
169
            throw new FireflyException($e->getMessage());
170
        }
171
        $json = json_decode($content, true) ?? [];
172
        Log::debug(sprintf('Status code from YNAB is %d', $statusCode));
173
        Log::debug(sprintf('Body of result is %s', $content), $json);
174
175
        // store refresh token (if present?) as preference
176
        // store token in job:
177
        $configuration                         = $this->repository->getConfiguration($this->importJob);
178
        $configuration['access_token']         = $json['access_token'];
179
        $configuration['access_token_expires'] = (int)$json['created_at'] + (int)$json['expires_in'];
180
        $this->repository->setConfiguration($this->importJob, $configuration);
181
182
        // also store new refresh token:
183
        $refreshToken = (string)($json['refresh_token'] ?? '');
184
        if ('' !== $refreshToken) {
185
            app('preferences')->set('ynab_refresh_token', $refreshToken);
186
        }
187
188
189
        Log::debug('end of NewYnabJobHandler::getAccessToken()');
190
    }
191
192
    /**
193
     * Check if we have the client ID.
194
     *
195
     * @return bool
196
     */
197
    private function hasClientId(): bool
198
    {
199
        $clientId = app('preferences')->getForUser($this->importJob->user, 'ynab_client_id', null);
200
        if (null === $clientId) {
201
            Log::debug('user has no YNAB client ID');
202
203
            return false;
204
        }
205
        if ('' === (string)$clientId->data) {
206
            Log::debug('user has no YNAB client ID (empty)');
207
208
            return false;
209
        }
210
        Log::debug('user has a YNAB client ID');
211
212
        return true;
213
    }
214
215
    /**
216
     * Check if we have the client secret
217
     *
218
     * @return bool
219
     */
220
    private function hasClientSecret(): bool
221
    {
222
        $clientSecret = app('preferences')->getForUser($this->importJob->user, 'ynab_client_secret', null);
223
        if (null === $clientSecret) {
224
            Log::debug('user has no YNAB client secret');
225
226
            return false;
227
        }
228
        if ('' === (string)$clientSecret->data) {
229
            Log::debug('user has no YNAB client secret (empty)');
230
231
            return false;
232
        }
233
        Log::debug('user has a YNAB client secret');
234
235
        return true;
236
    }
237
238
    /**
239
     * @return bool
240
     * @throws \Psr\Container\NotFoundExceptionInterface
241
     * @throws \Psr\Container\ContainerExceptionInterface
242
     */
243
    private function hasRefreshToken(): bool
244
    {
245
        $preference = app('preferences')->get('ynab_refresh_token');
246
        if (null === $preference) {
247
            Log::debug('user has no YNAB refresh token.');
248
249
            return false;
250
        }
251
        if ('' === (string)$preference->data) {
252
            Log::debug('user has no YNAB refresh token (empty).');
253
254
            return false;
255
        }
256
        Log::debug(sprintf('user has YNAB refresh token: %s', $preference->data));
257
258
        return true;
259
    }
260
}
261