Completed
Push — master ( 97e3cb...a7be99 )
by Sherif
02:45
created

UserRepository::group()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 24
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 24
rs 8.6845
c 0
b 0
f 0
cc 4
eloc 12
nc 8
nop 6
1
<?php namespace App\Modules\V1\Acl\Repositories;
2
3
use App\Modules\V1\Core\AbstractRepositories\AbstractRepository;
4
use App\Modules\V1\Acl\Proxy\LoginProxy;
5
use Lcobucci\JWT\ValidationData;
6
use League\OAuth2\Server\Repositories\AccessTokenRepositoryInterface;
7
8
class UserRepository extends AbstractRepository
9
{
10
    /**
11
     * Return the model full namespace.
12
     * 
13
     * @return string
14
     */
15
    protected function getModel()
16
    {
17
        return 'App\Modules\V1\Acl\AclUser';
18
    }
19
20
    /**
21
     * The loginProxy implementation.
22
     * 
23
     * @var array
24
     */
25
    protected $loginProxy;
26
27
    /**
28
     * @var The accessTokenRepository implementation.
29
     */
30
    private $accessTokenRepository;
31
32
    public function __construct(LoginProxy $loginProxy, AccessTokenRepositoryInterface $accessTokenRepository)
33
    {        
34
        $this->loginProxy            = $loginProxy;
0 ignored issues
show
Documentation Bug introduced by
It seems like $loginProxy of type object<App\Modules\V1\Acl\Proxy\LoginProxy> is incompatible with the declared type array of property $loginProxy.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
35
        $this->accessTokenRepository = $accessTokenRepository;
0 ignored issues
show
Documentation Bug introduced by
It seems like $accessTokenRepository of type object<League\OAuth2\Ser...kenRepositoryInterface> is incompatible with the declared type object<App\Modules\V1\Acl\Repositories\The> of property $accessTokenRepository.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
36
        parent::__construct();
37
    }
38
39
    /**
40
     * Return the logged in user account.
41
     *
42
     * @param  array   $relations
43
     * @return boolean
44
     */
45
    public function account($relations = [])
46
    {
47
        $permissions = [];
48
        $user        = \Core::users()->find(\Auth::id(), $relations);
49
        foreach ($user->groups()->get() as $group)
50
        {
51
            $group->permissions->each(function ($permission) use (&$permissions){
52
                $permissions[$permission->model][$permission->id] = $permission->name;
53
            });
54
        }
55
        $user->permissions = $permissions;
56
57
       return $user;
58
    }
59
60
    /**
61
     * Check if the logged in user or the given user 
62
     * has the given permissions on the given model.
63
     * 
64
     * @param  string  $nameOfPermission
65
     * @param  string  $model            
66
     * @param  boolean $user
67
     * @return boolean
68
     */
69
    public function can($nameOfPermission, $model, $user = false )
0 ignored issues
show
Unused Code introduced by
The parameter $user is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
70
    {      
71
        $user        = $user = $this->find(\Auth::id(), ['groups.permissions']);
72
        $permissions = [];
73
74
        $user->groups->pluck('permissions')->each(function ($permission) use (&$permissions, $model){
75
            $permissions = array_merge($permissions, $permission->where('model', $model)->pluck('name')->toArray()); 
76
        });
77
        
78
        return in_array($nameOfPermission, $permissions);
79
    }
80
81
    /**
82
     * Check if the logged in user has the given group.
83
     * 
84
     * @param  string  $groupName
85
     * @param  integer $userId
86
     * @return boolean
87
     */
88
    public function hasGroup($groupName, $userId = false)
89
    {
90
        $userId = $userId ?: \Auth::id();
91
        $groups = $this->find($userId)->groups;
92
        return $groups->pluck('name')->search($groupName, true) === false ? false : true;
93
    }
94
95
    /**
96
     * Assign the given group ids to the given user.
97
     * 
98
     * @param  integer $user_id    
99
     * @param  array   $group_ids
100
     * @return object
101
     */
102
    public function assignGroups($user_id, $group_ids)
103
    {
104
        \DB::transaction(function () use ($user_id, $group_ids) {
105
            $user = $this->find($user_id);
106
            $user->groups()->detach();
107
            $user->groups()->attach($group_ids);
108
        });
109
110
        return $this->find($user_id);
111
    }
112
113
    /**
114
     * Handle a login request to the application.
115
     * 
116
     * @param  array   $credentials    
117
     * @param  boolean $adminLogin
118
     * @return object
119
     */
120
    public function login($credentials, $adminLogin = false)
121
    {
122
        if ( ! $user = $this->first(['email' => $credentials['email']])) 
123
        {
124
            \ErrorHandler::loginFailed();
125
        }
126
        else if ($adminLogin && $user->groups->pluck('name')->search('Admin', true) === false) 
127
        {
128
            \ErrorHandler::loginFailed();
129
        }
130 View Code Duplication
        else if ( ! $adminLogin && $user->groups->pluck('name')->search('Admin', true) !== false) 
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
131
        {
132
            \ErrorHandler::loginFailed();
133
        }
134
        else if ($user->blocked)
135
        {
136
            \ErrorHandler::userIsBlocked();
137
        }
138
139
        return $user;
140
    }
141
142
    /**
143
     * Handle a social login request of the none admin to the application.
144
     * 
145
     * @param  array   $credentials
146
     * @return array
147
     */
148
    public function loginSocial($credentials)
149
    {
150
        $access_token = $credentials['auth_code'] ? \Socialite::driver($credentials['type'])->getAccessToken($credentials['auth_code']) : $credentials['access_token'];
151
        $user         = \Socialite::driver($credentials['type'])->userFromToken($access_token);
152
153
        if ( ! $user->email)
154
        {
155
            \ErrorHandler::noSocialEmail();
156
        }
157
158
        if ( ! $registeredUser = $this->model->where('email', $user->email)->first()) 
159
        {
160
            $data = ['email' => $user->email, 'password' => ''];
161
            return $this->register($data);
162
        }
163
        else
164
        {
165
            if ( ! \Auth::attempt(['email' => $registeredUser->email, 'password' => '']))
166
            {
167
                \ErrorHandler::userAlreadyRegistered();
168
            }
169
170
            return $this->loginProxy->login(['email' => $registeredUser->email, 'password' => ''], 0);
0 ignored issues
show
Bug introduced by
The method login cannot be called on $this->loginProxy (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
171
        }
172
    }
173
    
174
    /**
175
     * Handle a registration request.
176
     * 
177
     * @param  array $credentials
178
     * @return array
179
     */
180
    public function register($credentials)
181
    {
182
        $this->model->create($credentials);
183
        return $this->loginProxy->login($credentials, 0);
0 ignored issues
show
Bug introduced by
The method login cannot be called on $this->loginProxy (of type array).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
184
    }
185
186
    /**
187
     * Block the user.
188
     *
189
     * @param  integer $user_id
190
     * @return object
191
     */
192
    public function block($user_id)
193
    {
194
        if ( ! $user = $this->find($user_id)) 
195
        {
196
            \ErrorHandler::notFound('user');
197
        }
198
        if ( ! $this->hasGroup('Admin'))
199
        {
200
            \ErrorHandler::noPermissions();
201
        }
202 View Code Duplication
        else if (\Auth::id() == $user_id)
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
203
        {
204
            \ErrorHandler::noPermissions();
205
        }
206
        else if ($user->groups->pluck('name')->search('Admin', true) !== false) 
207
        {
208
            \ErrorHandler::noPermissions();
209
        }
210
211
        $user->blocked = 1;
212
        $user->save();
213
        
214
        return $user;
215
    }
216
217
    /**
218
     * Unblock the user.
219
     *
220
     * @param  integer $user_id
221
     * @return object
222
     */
223
    public function unblock($user_id)
224
    {
225
        if ( ! $this->hasGroup('Admin'))
226
        {
227
            \ErrorHandler::noPermissions();
228
        }
229
230
        $user          = $this->find($user_id);
231
        $user->blocked = 0;
232
        $user->save();
233
234
        return $user;
235
    }
236
237
    /**
238
     * Send a reset link to the given user.
239
     *
240
     * @param  string  $email
241
     * @return void
242
     */
243
    public function sendReset($email)
244
    {
245
        if ( ! $user = $this->model->where('email', $email)->first())
246
        {
247
            \ErrorHandler::notFound('email');
248
        }
249
250
        $url   = $this->config['resetLink'];
251
        $token = \Password::getRepository()->create($user);
252
        
253
        \Mail::send('acl::resetpassword', ['user' => $user, 'url' => $url, 'token' => $token], function ($m) use ($user) {
254
            $m->to($user->email, $user->name)->subject('Your Password Reset Link');
255
        });
256
    }
257
258
    /**
259
     * Reset the given user's password.
260
     *
261
     * @param  array  $credentials
262
     * @return array
263
     */
264
    public function resetPassword($credentials)
265
    {
266
        $response = \Password::reset($credentials, function ($user, $password) {
267
            $user->password = $password;
268
            $user->save();
269
        });
270
271
        switch ($response) {
272
            case \Password::PASSWORD_RESET:
273
                return 'success';
274
                
275
            case \Password::INVALID_TOKEN:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
276
                \ErrorHandler::invalidResetToken('token');
277
278
            case \Password::INVALID_PASSWORD:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
279
                \ErrorHandler::invalidResetPassword('email');
280
281
            case \Password::INVALID_USER:
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
282
                \ErrorHandler::notFound('user');
283
284
            default:
285
                \ErrorHandler::generalError();
286
        }
287
    }
288
289
    /**
290
     * Change the logged in user password.
291
     *
292
     * @param  array  $credentials
293
     * @return void
294
     */
295
    public function changePassword($credentials)
296
    {
297
        $user = \Auth::user();
298
        if ( ! \Hash::check($credentials['old_password'], $user->password)) 
299
        {
300
            \ErrorHandler::invalidOldPassword();
301
        }
302
303
        $user->password = $credentials['password'];
304
        $user->save();
305
    }
306
307
    /**
308
     * Paginate all users in the given group based on the given conditions.
309
     * 
310
     * @param  string  $groupName
311
     * @param  array   $relations
312
     * @param  integer $perPage
313
     * @param  string  $sortBy
314
     * @param  boolean $desc
315
     * @return \Illuminate\Http\Response
316
     */
317
    public function group($conditions, $groupName, $relations, $perPage, $sortBy, $desc)
318
    {   
319
        unset($conditions['page']);
320
        $conditions = $this->constructConditions($conditions, $this->model);
321
        $sort       = $desc ? 'desc' : 'asc';
322
        $model      = call_user_func_array("{$this->getModel()}::with", array($relations));
323
324
        $model->whereHas('groups', function($q) use ($groupName){
325
            $q->where('name', $groupName);
326
        });
327
328
        
329
        if (count($conditions['conditionValues']))
330
        {
331
            $model->whereRaw($conditions['conditionString'], $conditions['conditionValues']);
332
        }
333
334
        if ($perPage) 
335
        {
336
            return $model->orderBy($sortBy, $sort)->paginate($perPage);
337
        }
338
339
        return $model->orderBy($sortBy, $sort)->get();
340
    }
341
342
    /**
343
     * Save the given data to the logged in user.
344
     *
345
     * @param  array $credentials
346
     * @return object
347
     */
348
    public function saveProfile($credentials) 
349
    {
350
        $user = \Auth::user();
351
        $user->save($credentials);
352
353
        return $user;
354
    }
355
356
    /**
357
     * Ensure access token hasn't expired or revoked.
358
     * 
359
     * @param  string $accessToken
360
     * @return boolean
361
     */
362
    public function accessTokenExpiredOrRevoked($accessToken)
363
    {
364
        $data = new ValidationData();
365
        $data->setCurrentTime(time());
366
367
        if ($accessToken->validate($data) === false || $this->accessTokenRepository->isAccessTokenRevoked($accessToken->getClaim('jti'))) 
0 ignored issues
show
Bug introduced by
The method validate cannot be called on $accessToken (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
Bug introduced by
The method getClaim cannot be called on $accessToken (of type string).

Methods can only be called on objects. This check looks for methods being called on variables that have been inferred to never be objects.

Loading history...
368
        {
369
            return true;
370
        }
371
372
        return false;
373
    }
374
}
375