1 | <?php |
||||
2 | |||||
3 | namespace Spinen\Formio; |
||||
4 | |||||
5 | use Exception; |
||||
6 | use GuzzleHttp\Client as Guzzle; |
||||
7 | use GuzzleHttp\Exception\GuzzleException; |
||||
8 | use GuzzleHttp\Exception\RequestException; |
||||
9 | use Illuminate\Support\Arr; |
||||
10 | use Illuminate\Support\Str; |
||||
11 | use Psr\Http\Message\ResponseInterface; |
||||
12 | use Spinen\Formio\Contracts\FormioUser; |
||||
13 | use Spinen\Formio\Exceptions\TokenException; |
||||
14 | use Spinen\Formio\Exceptions\UserException; |
||||
15 | |||||
16 | /** |
||||
17 | * Class Client |
||||
18 | * |
||||
19 | * @package Spinen\Formio |
||||
20 | */ |
||||
21 | class Client |
||||
22 | { |
||||
23 | /** |
||||
24 | * Configs for the client |
||||
25 | * |
||||
26 | * @var array |
||||
27 | */ |
||||
28 | protected $configs; |
||||
29 | |||||
30 | /** |
||||
31 | * Guzzle instance |
||||
32 | * |
||||
33 | * @var Guzzle |
||||
34 | */ |
||||
35 | protected $guzzle; |
||||
36 | |||||
37 | /** |
||||
38 | * Token instance |
||||
39 | * |
||||
40 | * @var Token |
||||
41 | */ |
||||
42 | public $token; |
||||
43 | |||||
44 | /** |
||||
45 | * Client constructor. |
||||
46 | * |
||||
47 | * @param array $configs |
||||
48 | * @param Guzzle $guzzle |
||||
49 | * @param Token|null $token |
||||
50 | */ |
||||
51 | 15 | public function __construct(array $configs, Guzzle $guzzle, Token $token = null) |
|||
52 | { |
||||
53 | 15 | $this->setConfigs($configs); |
|||
54 | 15 | $this->guzzle = $guzzle; |
|||
55 | 15 | $this->token = $token ?? new Token(); |
|||
56 | } |
||||
57 | |||||
58 | /** |
||||
59 | * Add a user to Formio |
||||
60 | * |
||||
61 | * @param FormioUser $user |
||||
62 | * @param null $password |
||||
0 ignored issues
–
show
Documentation
Bug
introduced
by
![]() |
|||||
63 | * |
||||
64 | * @return Client |
||||
65 | * @throws UserException |
||||
66 | */ |
||||
67 | 3 | public function addUser(FormioUser $user, $password = null) |
|||
68 | { |
||||
69 | 3 | $user->formio_password = $password ?? $this->configs['user']['register']['default_password'] ?? Str::random(32); |
|||
0 ignored issues
–
show
|
|||||
70 | |||||
71 | try { |
||||
72 | 3 | $response = $this->guzzle->post( |
|||
73 | 3 | $this->uri($this->configs['user']['register']['path']), |
|||
74 | [ |
||||
75 | 'form_params' => [ |
||||
76 | 3 | 'data' => $user->getRegistrationData(), |
|||
77 | ], |
||||
78 | ] |
||||
79 | ); |
||||
80 | |||||
81 | 2 | if (!$user->save()) { |
|||
82 | 1 | throw new UserException("Unable to save the user's Formio password"); |
|||
83 | |||||
84 | // TODO: Rollback |
||||
85 | } |
||||
86 | |||||
87 | 1 | $this->parseUser($response); |
|||
88 | |||||
89 | 1 | return $this; |
|||
90 | 2 | } catch (RequestException $e) { |
|||
91 | // TODO: Figure out what to do with this error |
||||
92 | |||||
93 | 1 | throw $e; |
|||
94 | } |
||||
95 | } |
||||
96 | |||||
97 | /** |
||||
98 | * Build admin login |
||||
99 | * |
||||
100 | * @return array |
||||
101 | */ |
||||
102 | 2 | protected function getAdminLoginData() |
|||
103 | { |
||||
104 | return [ |
||||
105 | 2 | 'email' => $this->configs['admin']['username'], |
|||
106 | 2 | 'password' => $this->configs['admin']['password'], |
|||
107 | ]; |
||||
108 | } |
||||
109 | |||||
110 | /** |
||||
111 | * Login user to Formio |
||||
112 | * |
||||
113 | * If no user provided, then use the admin user |
||||
114 | * |
||||
115 | * @param FormioUser|null $user |
||||
116 | * |
||||
117 | * @return Client |
||||
118 | * @throws Exception |
||||
119 | */ |
||||
120 | 4 | public function login(FormioUser $user = null) |
|||
121 | { |
||||
122 | try { |
||||
123 | 4 | $this->parseUser( |
|||
124 | 4 | $this->guzzle->post( |
|||
125 | 4 | $this->uri( |
|||
126 | 4 | $user ? $this->configs['user']['login']['path'] : $this->configs['admin']['login']['path'] |
|||
127 | ), |
||||
128 | [ |
||||
129 | 'form_params' => [ |
||||
130 | 4 | 'data' => $user ? $user->getLoginData() : $this->getAdminLoginData(), |
|||
131 | ], |
||||
132 | ] |
||||
133 | ) |
||||
134 | ); |
||||
135 | |||||
136 | 3 | return $this; |
|||
137 | 1 | } catch (RequestException $e) { |
|||
138 | // TODO: Figure out what to do with this error |
||||
139 | |||||
140 | 1 | throw $e; |
|||
141 | } |
||||
142 | } |
||||
143 | |||||
144 | /** |
||||
145 | * Logout |
||||
146 | * |
||||
147 | * Since the Formio is stateless, just empty the Token |
||||
148 | * |
||||
149 | * @return $this |
||||
150 | */ |
||||
151 | 1 | public function logout() |
|||
152 | { |
||||
153 | 1 | $this->token = new Token(); |
|||
154 | |||||
155 | 1 | return $this; |
|||
156 | } |
||||
157 | |||||
158 | /** |
||||
159 | * Parse the user & JWT from the response into the token |
||||
160 | * |
||||
161 | * @param ResponseInterface $response |
||||
162 | */ |
||||
163 | 4 | protected function parseUser(ResponseInterface $response) |
|||
164 | { |
||||
165 | // TODO: Add some error checking to user parsing |
||||
166 | 4 | $this->token = $this->token->setUser(json_decode($response->getBody(), true)) |
|||
167 | ->setJwt( |
||||
168 | 4 | $response->getHeader('x-jwt-token')[0], |
|||
169 | 4 | $this->configs['jwt']['secret'], |
|||
170 | 4 | $this->configs['jwt']['algorithm'] |
|||
171 | ); |
||||
172 | } |
||||
173 | |||||
174 | /** |
||||
175 | * Make an API call to Formio |
||||
176 | * |
||||
177 | * @param $path |
||||
178 | * @param array|null $data |
||||
179 | * @param string|null $method |
||||
180 | * |
||||
181 | * @return array |
||||
182 | * @throws GuzzleException |
||||
183 | * @throws TokenException |
||||
184 | */ |
||||
185 | 5 | public function request($path, $data = [], $method = 'GET') |
|||
186 | { |
||||
187 | 5 | if (!$this->token) { |
|||
188 | 1 | throw new TokenException('Must be logged in before making a request'); |
|||
189 | } |
||||
190 | |||||
191 | 4 | if ($this->token->expired()) { |
|||
192 | 1 | throw new TokenException('Token expired ' . $this->token->expires_at->diffForHumans()); |
|||
193 | } |
||||
194 | |||||
195 | try { |
||||
196 | 3 | $response = $this->guzzle->request( |
|||
197 | $method, |
||||
0 ignored issues
–
show
It seems like
$method can also be of type null ; however, parameter $method of GuzzleHttp\Client::request() does only seem to accept string , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
198 | 3 | $this->uri($path), |
|||
199 | [ |
||||
200 | 'headers' => [ |
||||
201 | 3 | 'x-jwt-token' => $this->token->jwt, |
|||
202 | ], |
||||
203 | 'form_params' => [ |
||||
204 | 3 | 'data' => $data, |
|||
205 | ], |
||||
206 | ] |
||||
207 | ); |
||||
208 | |||||
209 | 2 | return json_decode($response->getBody(), true); |
|||
210 | 1 | } catch (GuzzleException $e) { |
|||
211 | // TODO: Figure out what to do with this error |
||||
212 | |||||
213 | 1 | throw $e; |
|||
214 | } |
||||
215 | } |
||||
216 | |||||
217 | /** |
||||
218 | * Set the configs |
||||
219 | * |
||||
220 | * @param array $configs |
||||
221 | * |
||||
222 | * @return $this |
||||
223 | */ |
||||
224 | 15 | public function setConfigs(array $configs) |
|||
225 | { |
||||
226 | 15 | $this->configs = $configs; |
|||
227 | |||||
228 | 15 | return $this; |
|||
229 | } |
||||
230 | |||||
231 | /** |
||||
232 | * SSO for User |
||||
233 | * |
||||
234 | * If the user already has a Formio password, then login the use. |
||||
235 | * Otherwise, make a Custom JWT. |
||||
236 | * |
||||
237 | * @param FormioUser $user |
||||
238 | * |
||||
239 | * @return Client |
||||
240 | * @throws Exception |
||||
241 | */ |
||||
242 | 2 | public function sso(FormioUser $user) |
|||
243 | { |
||||
244 | // If the user has a Formio password, then log them in |
||||
245 | 2 | if ($user->formio_password) { |
|||
0 ignored issues
–
show
|
|||||
246 | 1 | return $this->login($user); |
|||
247 | } |
||||
248 | |||||
249 | 1 | $this->token = $this->token->makeJwt( |
|||
250 | 1 | $this->configs['project']['id'], |
|||
251 | 1 | $this->configs['user']['form'], |
|||
252 | 1 | Arr::except($user->getRegistrationData(), 'password'), |
|||
253 | // TODO: Roles from the database? |
||||
254 | 1 | $this->configs['user']['roles'], |
|||
255 | 1 | $this->configs['jwt']['secret'], |
|||
256 | 1 | $this->configs['jwt']['algorithm'] |
|||
257 | ); |
||||
258 | |||||
259 | 1 | return $this; |
|||
260 | } |
||||
261 | |||||
262 | /** |
||||
263 | * URL to Formio |
||||
264 | * |
||||
265 | * If path is passed in, then append it to the end |
||||
266 | * |
||||
267 | * @param null $path |
||||
0 ignored issues
–
show
|
|||||
268 | * |
||||
269 | * @return string |
||||
270 | */ |
||||
271 | 10 | public function uri($path = null) |
|||
272 | { |
||||
273 | 10 | return rtrim($this->configs['url'], '/') . '/' . ltrim($path, '/'); |
|||
0 ignored issues
–
show
$path of type null is incompatible with the type string expected by parameter $string of ltrim() .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||
274 | } |
||||
275 | } |
||||
276 |