Completed
Push — master ( 361e7c...d7e260 )
by Artem
03:39
created

AuthService   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 388
Duplicated Lines 0 %

Test Coverage

Coverage 69.89%

Importance

Changes 0
Metric Value
eloc 83
dl 0
loc 388
ccs 65
cts 93
cp 0.6989
rs 9.52
c 0
b 0
f 0
wmc 36

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A login() 0 7 2
A unsafeLogin() 0 7 2
A logout() 0 9 2
A disabled() 0 3 1
A register() 0 7 2
A retrieveByToken() 0 18 4
A setClient() 0 3 1
A setGuard() 0 3 1
A validatePasswordResetToken() 0 13 3
A handleFallback() 0 6 1
A handle() 0 11 2
A loadHandlers() 0 3 1
A getClient() 0 3 1
A forgot() 0 9 2
A ensure() 0 20 3
A setFallbackGuard() 0 3 1
A update() 0 15 3
A resetPassword() 0 15 3
1
<?php
2
3
namespace Slides\Connector\Auth;
4
5
use Illuminate\Support\Facades\DB;
6
use Illuminate\Contracts\Auth\Guard as GuardContract;
7
use Slides\Connector\Auth\Sync\User as RemoteUser;
8
9
/**
10
 * Class AuthService
11
 *
12
 * @package Slides\Connector\Auth
13
 */
14
class AuthService
15
{
16
    const HANDLER_USER_CREATE      = 'create';
17
    const HANDLER_USER_UPDATE      = 'update';
18
    const HANDLER_USER_DELETE      = 'delete';
19
    const HANDLER_USER_SYNC_CREATE = 'sync.create';
20
    const HANDLER_USER_SYNC_UPDATE = 'sync.update';
21
    const HANDLER_USER_SYNC_DELETE = 'sync.delete';
22
23
    /**
24
     * The class with handler methods
25
     *
26
     * @var object
27
     */
28
    protected $handlersContainer;
29
30
    /**
31
     * HTTP Client
32
     *
33
     * @var Client
34
     */
35
    protected $client;
36
37
    /**
38
     * The authentication guard.
39
     *
40
     * @var TokenGuard
41
     */
42
    protected $guard;
43
44
    /**
45
     * The fallback authentication guard.
46
     *
47
     * @var GuardContract
48
     */
49
    protected $fallbackGuard;
50
51
    /**
52
     * Checks whether a service is disabled
53
     *
54
     * @return bool
55
     */
56 10
    public function disabled(): bool
57
    {
58 10
        return !config('connector.auth.enabled', true);
59
    }
60
61
    /**
62
     * AuthService constructor.
63
     *
64
     * @param Client $client
65
     */
66 17
    public function __construct(Client $client)
67
    {
68 17
        $this->client = $client;
69 17
    }
70
71
    /**
72
     * Authenticate a user.
73
     *
74
     * @param string $email
75
     * @param string $password
76
     * @param bool $remember
77
     *
78
     * @return mixed
79
     *
80
     * @throws
81
     */
82 4
    public function login(string $email, string $password, bool $remember = false)
83
    {
84 4
        if($this->disabled()) {
85
            return $this->handleFallback('login', compact('email', 'password', 'remember'));
86
        }
87
88 4
        return $this->guard->login($email, $password, $remember);
89
    }
90
91
    /**
92
     * Authenticate a user without the password.
93
     *
94
     * Warning! This method has implemented temporarily to make able to login users
95
     * who use Social Auth on 24Templates. MUST NOT be used in any other cases.
96
     *
97
     * @param string $email
98
     * @param bool $remember
99
     *
100
     * @return mixed
101
     *
102
     * @throws
103
     */
104 2
    public function unsafeLogin(string $email, bool $remember = false)
105
    {
106 2
        if($this->disabled()) {
107
            return $this->handleFallback('unsafeLogin', compact('email', 'remember'));
108
        }
109
110 2
        return $this->guard->unsafeLogin($email, $remember);
111
    }
112
113
    /**
114
     * Logout a user.
115
     *
116
     * @return mixed
117
     *
118
     * @throws
119
     */
120
    public function logout()
121
    {
122
        if($this->disabled()) {
123
            return $this->handleFallback('logout');
124
        }
125
126
        $this->guard->logout();
127
128
        return null;
129
    }
130
131
    /**
132
     * Create a remote user.
133
     *
134
     * @param int $userId
135
     * @param string $name
136
     * @param string $email
137
     * @param string $password
138
     * @param string $country
139
     *
140
     * @return array
141
     */
142 2
    public function register(int $userId, string $name, string $email, string $password, string $country)
143
    {
144 2
        if($this->disabled()) {
145
            return [];
146
        }
147
148 2
        return $this->client->request('register', compact('userId', 'name', 'email', 'password', 'country'));
149
    }
150
151
    /**
152
     * Send an email with a password resetting link
153
     *
154
     * @param string $email
155
     *
156
     * @return bool
157
     *
158
     * @throws
159
     */
160 2
    public function forgot(string $email)
161
    {
162 2
        if($this->disabled()) {
163
            return $this->handleFallback('forgot', compact('email'));
164
        }
165
166 2
        $this->client->request('forgot', compact('email'));
167
168 2
        return $this->client->success(true);
169
    }
170
171
    /**
172
     * Checks whether password reset token is valid
173
     *
174
     * @param string $token
175
     * @param string $email
176
     *
177
     * @return string|false
178
     *
179
     * @throws
180
     */
181 2
    public function validatePasswordResetToken(string $token, string $email)
182
    {
183 2
        if($this->disabled()) {
184
            return $this->handleFallback('validateReset', compact('token', 'email'));
185
        }
186
187 2
        $response = $this->client->request('validateReset', compact('token', 'email'));
188
189 2
        if(!$this->client->success(true)) {
190 1
            return false;
191
        }
192
193 1
        return array_get($response, 'user.email');
194
    }
195
196
    /**
197
     * Checks whether password reset token is valid
198
     *
199
     * @param string $token
200
     * @param string $email
201
     * @param string $password
202
     * @param string $confirmation
203
     *
204
     * @return array|false
205
     *
206
     * @throws
207
     */
208 2
    public function resetPassword(string $token, string $email, string $password, string $confirmation)
209
    {
210 2
        $parameters = compact('token', 'email', 'password', 'confirmation');
211
212 2
        if($this->disabled()) {
213
            return $this->handleFallback('resetPassword', $parameters);
214
        }
215
216 2
        $response = $this->client->request('reset', $parameters);
217
218 2
        if(!$this->client->success(true)) {
219 1
            return false;
220
        }
221
222 1
        return $response;
223
    }
224
225
    /**
226
     * Update a remote user
227
     *
228
     * @param int $id Local user ID
229
     * @param string|null $name
230
     * @param string|null $email
231
     * @param string|null $password Raw password, in case if changed
232
     *
233
     * @return array|false
234
     */
235 2
    public function update(int $id, ?string $name, ?string $email, ?string $password)
236
    {
237 2
        if($this->disabled()) {
238
            return false;
239
        }
240
241 2
        $attributes = array_filter(compact('id', 'name', 'email', 'password'));
242
243 2
        $response = $this->client->request('update', compact('id', 'attributes'));
244
245 2
        if(!$this->client->success(true)) {
246 1
            return false;
247
        }
248
249 1
        return $response;
250
    }
251
252
    /**
253
     * Retrieve a remote user
254
     *
255
     * @return RemoteUser|null
256
     */
257
    public function retrieveByToken()
258
    {
259
        if($this->disabled()) {
260
            return null;
261
        }
262
263
        try {
264
            $response = $this->client->request('me');
265
        }
266
        catch(\Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException $e) {
267
            return null;
268
        }
269
270
        if(!$this->client->success(true)) {
271
            return null;
272
        }
273
274
        return RemoteUser::createFromResponse($response);
275
    }
276
277
    /**
278
     * Load handlers from the given container.
279
     *
280
     * @param $container
281
     *
282
     * @return void
283
     */
284 17
    public function loadHandlers($container)
285
    {
286 17
        $this->handlersContainer = $container;
287 17
    }
288
289
    /**
290
     * Run a handler
291
     *
292
     * @param string $key
293
     * @param array $parameters
294
     * @param \Closure|null $fallback
295
     *
296
     * @return mixed
297
     *
298
     * @throws \Exception
299
     */
300 7
    public function handle(string $key, array $parameters = [], \Closure $fallback = null)
301
    {
302 7
        $handler = camel_case(str_replace('.', ' ', $key));
303
304 7
        if(!method_exists($this->handlersContainer, $handler)) {
305 1
            throw new \InvalidArgumentException("Handler `{$handler}` cannot be found");
306
        }
307
308
        return $this->ensure(function() use ($handler, $parameters) {
309 6
            return call_user_func_array([$this->handlersContainer, $handler], $parameters);
310 6
        }, $fallback);
311
    }
312
313
    /**
314
     * Run a fallback handler
315
     *
316
     * @param string $key
317
     * @param array $parameters
318
     * @param \Closure|null $fallback
319
     *
320
     * @return mixed
321
     *
322
     * @throws \Exception
323
     */
324 2
    public function handleFallback(string $key, array $parameters = [], \Closure $fallback = null)
325
    {
326 2
        $key = 'fallback' . studly_case($key);
327 2
        $parameters = array_merge(['guard' => $this->fallbackGuard], $parameters);
328
329 2
        return $this->handle($key, $parameters, $fallback);
330
    }
331
332
    /**
333
     * Performs a callback logic within database transaction.
334
     *
335
     * @param \Closure $callback
336
     * @param \Closure|null $fallback The callback which should fired when exception throws.
337
     *
338
     * @return mixed
339
     *
340
     * @throws \Exception
341
     */
342 6
    protected function ensure(\Closure $callback, \Closure $fallback = null)
343
    {
344 6
        DB::beginTransaction();
345
346
        try {
347 6
            $output = $callback();
348
        }
349 3
        catch(\Exception $e) {
350 2
            DB::rollBack();
351
352 2
            if(is_null($fallback)) {
353
                throw $e;
354
            }
355
356 2
            $output = $fallback($e);
357
        }
358
359 5
        DB::commit();
360
361 5
        return $output;
362
    }
363
364
    /**
365
     * Set authentication guard.
366
     *
367
     * @param \Slides\Connector\Auth\TokenGuard $guard
368
     */
369 17
    public function setGuard(TokenGuard $guard): void
370
    {
371 17
        $this->guard = $guard;
372 17
    }
373
374
    /**
375
     * Set fallback authentication guard.
376
     *
377
     * @param GuardContract $guard
378
     */
379
    public function setFallbackGuard(GuardContract $guard): void
380
    {
381
        $this->fallbackGuard = $guard;
382
    }
383
384
    /**
385
     * Set HTTP Client.
386
     *
387
     * @param Client $client
388
     */
389
    public function setClient(Client $client): void
390
    {
391
        $this->client = $client;
392
    }
393
394
    /**
395
     * Get HTTP client.
396
     *
397
     * @return Client
398
     */
399 17
    public function getClient(): Client
400
    {
401 17
        return $this->client;
402
    }
403
}