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.
Test Setup Failed
Push — action_getCatTree_order ( 77944b )
by
unknown
23:56
created

User::beforeSave()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 10
rs 9.4285
cc 3
eloc 6
nc 3
nop 1
1
<?php
2
3
namespace app\modules\user\models;
4
5
use app\modules\shop\models\Customer;
6
use app\properties\HasProperties;
7
use app\models\PropertyGroup;
8
use app\models\ObjectPropertyGroup;
9
10
use devgroup\TagDependencyHelper\ActiveRecordHelper;
11
use Yii;
12
use yii\base\NotSupportedException;
13
use yii\behaviors\TimestampBehavior;
14
use yii\caching\TagDependency;
15
use yii\db\ActiveRecord;
16
use yii\web\IdentityInterface;
17
18
/**
19
 * Class User
20
 * @package app\models
21
 *
22
 * @property integer $id
23
 * @property string $username
24
 * @property string $password_hash
25
 * @property string $password_reset_token
26
 * @property string $email
27
 * @property string $auth_key
28
 * @property integer $status
29
 * @property integer $create_time
30
 * @property integer $update_time
31
 * @property string $first_name
32
 * @property string $last_name
33
 * @property \app\modules\user\models\UserService[] $services
34
 * @property string $displayName  Display name for the user visual identification
35
 * Relations:
36
 */
37
class User extends ActiveRecord implements IdentityInterface
38
{
39
    const STATUS_DELETED = 0;
40
    const STATUS_ACTIVE = 10;
41
    const USER_GUEST = 0;
42
43
    public $confirmPassword;
44
    public $newPassword;
45
    public $password;
46
47
    /**
48
     * @inheritdoc
49
     */
50
    public function rules()
51
    {
52
        return [
53
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
54
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
55
56
            ['username', 'filter', 'filter' => 'trim'],
57
            ['username', 'required'],
58
            ['username', 'string', 'min' => 2, 'max' => 255],
59
            ['username', 'unique'],
60
61
            ['email', 'filter', 'filter' => 'trim'],
62
            ['email', 'required', 'except' => ['registerService']],
63
            ['email', 'email'],
64
            ['email', 'unique', 'message' => Yii::t('app', 'This email address has already been taken.')],
65
            ['email', 'exist', 'message' => Yii::t('app', 'There is no user with such email.'), 'on' => 'requestPasswordResetToken'],
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 133 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
66
67
            ['password', 'required', 'on' => ['adminSignup', 'changePassword']],
68
            ['password', 'string', 'min' => 8],
69
            [['first_name', 'last_name',], 'string', 'max' => 255],
70
71
            // change password
72
            [['newPassword', 'confirmPassword'], 'required'],
73
            [['newPassword', 'confirmPassword'], 'string', 'min' => 8],
74
            [['confirmPassword'], 'compare', 'compareAttribute' => 'newPassword'],
75
        ];
76
    }
77
78
    /**
79
     * @inheritdoc
80
     */
81
    public function scenarios()
82
    {
83
        return [
84
            'signup' => ['username', 'email', 'password', 'first_name', 'last_name'],
85
            'resetPassword' => ['password_hash', 'password_reset_token'],
86
            'requestPasswordResetToken' => ['email'],
87
88
            'registerService' => ['email', 'first_name', 'last_name'],
89
            'updateProfile' => ['email', 'first_name', 'last_name'],
90
            'completeRegistration' => ['first_name', 'last_name', 'username'],
91
            'changePassword' => ['password', 'newPassword', 'confirmPassword'],
92
            // admin
93
            'search' => ['id', 'username', 'email', 'status', 'create_time', 'first_name', 'last_name'],
94
            'admin' => ['username', 'status', 'email', 'password', 'first_name', 'last_name'],
95
            'adminSignup' => ['username', 'status', 'email', 'password', 'first_name', 'last_name', 'auth_key'],
96
            'passwordResetToken' => ['password_reset_token'],
97
        ];
98
    }
99
100
    /**
101
     * @inheritdoc
102
     */
103
    public static function tableName()
104
    {
105
        return '{{%user}}';
106
    }
107
108
    /**
109
     * @inheritdoc
110
     */
111
    public function attributeLabels()
112
    {
113
        return [
114
            'id' => Yii::t('app', 'ID'),
115
            'username' => Yii::t('app', 'Username'),
116
            'auth_key' => Yii::t('app', 'Auth Key'),
117
            'password' => Yii::t('app', 'Password'),
118
            'password_reset_token' => Yii::t('app', 'Password Reset Token'),
119
            'email' => Yii::t('app', 'E-mail'),
120
            'status' => Yii::t('app', 'Status'),
121
            'create_time' => Yii::t('app', 'Create Time'),
122
            'update_time' => Yii::t('app', 'Update Time'),
123
            'first_name' => Yii::t('app', 'First Name'),
124
            'last_name' => Yii::t('app', 'Last Name'),
125
            'newPassword' => Yii::t('app', 'New Password'),
126
            'confirmPassword' => Yii::t('app', 'Confirm Password'),
127
        ];
128
    }
129
130
    /**
131
     * @return array List of all possible statuses for User instance
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
132
     */
133
    public static function getStatuses()
134
    {
135
        return [
136
            self::STATUS_ACTIVE => Yii::t('app', 'Active'),
137
            self::STATUS_DELETED => Yii::t('app', 'Deleted'),
138
        ];
139
    }
140
141
    /**
142
     * @inheritdoc
143
     */
144
    public function behaviors()
145
    {
146
        return [
147
            [
148
                'class' => TimestampBehavior::className(),
149
                'createdAtAttribute' => 'create_time',
150
                'updatedAtAttribute' => 'update_time',
151
            ],
152
            [
153
                'class' => \devgroup\TagDependencyHelper\ActiveRecordHelper::className(),
154
            ],
155
            [
156
                'class' => HasProperties::className(),
157
            ],
158
        ];
159
    }
160
161
    /**
162
     * @inheritdoc
163
     */
164
    public static function findIdentityByAccessToken($token, $type = null)
165
    {
166
        // see https://github.com/yiisoft/yii2/issues/2689
167
        throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
168
    }
169
170
    /**
171
     * Finds an identity by the given ID.
172
     *
173
     * @param string|integer $id the ID to be looked for
174
     * @return IdentityInterface|null the identity object that matches the given ID.
175
     */
176
    public static function findIdentity($id)
177
    {
178
179
        if (is_numeric($id)) {
180
            $model = Yii::$app->cache->get("User:$id");
181 View Code Duplication
            if ($model === false) {
182
                $model = static::find()
183
                    ->with('services')
184
                    ->where('id=:id', [':id'=>$id])
185
                    ->one();
186
                if ($model !== null) {
187
                    Yii::$app->cache->set(
188
                        "User:$id",
189
                        $model,
190
                        3600,
191
                        new TagDependency([
192
                            'tags' => [
193
                                ActiveRecordHelper::getObjectTag($model->className(), $model->id)
194
                            ]
195
                        ])
196
                    );
197
                }
198
199
            }
200
            return $model;
201
        } else {
202
            return null;
203
        }
204
205
    }
206
207
    /**
208
     * Finds user by username
209
     *
210
     * @param string $username
211
     * @return null|User
0 ignored issues
show
Documentation introduced by
Should the return type not be array|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
212
     */
213
    public static function findByUsername($username)
214
    {
215
        return static::findOne(['username' => $username, 'status' => static::STATUS_ACTIVE]);
216
    }
217
218
    /**
219
     * Finds user by password reset token
220
     *
221
     * @param string $token password reset token
222
     * @return User|null
0 ignored issues
show
Documentation introduced by
Should the return type not be null|array|boolean? Also, consider making the array more specific, something like array<String>, or String[].

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

If the return type contains the type array, this check recommends the use of a more specific type like String[] or array<String>.

Loading history...
223
     */
224
    public static function findByPasswordResetToken($token)
225
    {
226
        if (static::isPasswordResetTokenValid($token) === false) {
227
            return null;
228
        }
229
230
        return static::findOne([
231
            'password_reset_token' => $token,
232
            'status' => self::STATUS_ACTIVE,
233
        ]);
234
    }
235
236
    /**
237
     * Finds out if password reset token is valid
238
     *
239
     * @param string $token password reset token
240
     * @return boolean
241
     */
242
    public static function isPasswordResetTokenValid($token)
243
    {
244
        if (empty($token) === true) {
245
            return false;
246
        }
247
        $expire = Yii::$app->modules['user']->passwordResetTokenExpire;
248
        $parts = explode('_', $token);
249
        $timestamp = (int) end($parts);
250
        return $timestamp + $expire >= time();
251
    }
252
253
    /**
254
     * @return int|string current user ID
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use integer.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
255
     */
256
    public function getId()
257
    {
258
        return $this->id;
259
    }
260
261
    /**
262
     * @return string current user auth key
263
     */
264
    public function getAuthKey()
265
    {
266
        return $this->auth_key;
267
    }
268
269
    /**
270
     * @param string $authKey
271
     * @return boolean if auth key is valid for current user
272
     */
273
    public function validateAuthKey($authKey)
274
    {
275
        return $this->getAuthKey() === $authKey;
276
    }
277
278
    /**
279
     * @param string $password password to validate
280
     * @return bool if password provided is valid for current user
281
     */
282
    public function validatePassword($password)
283
    {
284
        return Yii::$app->security->validatePassword($password, $this->password_hash);
285
    }
286
287
    /**
288
     * Generates password hash from password and sets it to the model
289
     *
290
     * @param string $password
291
     */
292
    public function setPassword($password)
293
    {
294
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
295
    }
296
297
    /**
298
     * Generates "remember me" authentication key
299
     */
300
    public function generateAuthKey()
301
    {
302
        $this->auth_key = Yii::$app->security->generateRandomString();
303
    }
304
305
    /**
306
     * Generates new password reset token
307
     */
308
    public function generatePasswordResetToken()
309
    {
310
        $this->password_reset_token = Yii::$app->security->generateRandomString() . '_' . time();
311
    }
312
313
    /**
314
     * Removes password reset token
315
     */
316
    public function removePasswordResetToken()
317
    {
318
        $this->password_reset_token = null;
319
    }
320
321
322
    /**
323
     * @param bool $insert
324
     * @param array $changedAttributes
325
     */
326
    public function afterSave($insert, $changedAttributes)
327
    {
328
        parent::afterSave($insert, $changedAttributes);
329
330
        // save bindings to property groups for properties support
331
332
        $ids = $this->getPropertyIdsForUsers();
333
334
        $currentGroups = array_keys($this->getPropertyGroups());
0 ignored issues
show
Documentation Bug introduced by
The method getPropertyGroups does not exist on object<app\modules\user\models\User>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
335
336
        $newIds = array_diff($ids, $currentGroups);
337
338
        foreach ($newIds as $group_id) {
339
            $this->addPropertyGroup($group_id, false);
0 ignored issues
show
Documentation Bug introduced by
The method addPropertyGroup does not exist on object<app\modules\user\models\User>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
340
        }
341
        $this->updatePropertyGroupsInformation();
0 ignored issues
show
Documentation Bug introduced by
The method updatePropertyGroupsInformation does not exist on object<app\modules\user\models\User>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
342
    }
343
344
    /**
345
     * Returns array of ids of propertyGroups for user model
346
     * @return array
347
     * @throws \Exception
348
     */
349
    private function getPropertyIdsForUsers()
350
    {
351
        return PropertyGroup::getDb()->cache(
352
            function ($db) {
353
                return PropertyGroup::find()
354
                    ->select('id')
355
                    ->where(['object_id' => $this->getObject()->id])
0 ignored issues
show
Documentation Bug introduced by
The method getObject does not exist on object<app\modules\user\models\User>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
356
                    ->asArray()
357
                    ->column($db);
358
            },
359
            86400,
360
            new TagDependency([
361
                'tags' => ActiveRecordHelper::getCommonTag(PropertyGroup::className())
362
            ])
363
        );
364
    }
365
366
367
    /**
368
     * Returns gravatar image link for user
369
     * @param int $size Avatar size in pixels
370
     * @return string
371
     */
372
    public function gravatar($size = 40)
373
    {
374
        $hash = md5(strtolower(trim($this->email)));
375
        return '//www.gravatar.com/avatar/' . $hash . '?s=' . $size;
376
    }
377
378
    /**
379
     * Relation to UserService model describing social services available exact user to login
380
     * @return \yii\db\ActiveQuery
381
     */
382
    public function getServices()
383
    {
384
        return $this->hasMany(UserService::className(), ['user_id' => 'id']);
385
    }
386
387
    /**
388
     * @return mixed|string Display name for the user visual identification
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
389
     */
390
    public function getDisplayName()
391
    {
392
        $name = trim($this->first_name . ' ' . $this->last_name);
393
        return $name ? $name : $this->username;
394
    }
395
396
    /**
397
     * @inheritdoc
398
     */
399
    public function beforeSave($insert)
400
    {
401
        if (!parent::beforeSave($insert)) {
402
            return false;
403
        }
404
        if ($insert) {
405
            $this->setPassword($this->password);
406
        }
407
        return true;
408
    }
409
}
410