Passed
Push — 2.6.0 ( ...f22176 )
by steve
18:56
created

UserInvite::getToken()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
ccs 0
cts 2
cp 0
crap 2
1
<?php
2
3
namespace neon\user\models;
4
5
use Carbon\Carbon;
6
use neon\core\helpers\Hash;
7
use neon\core\helpers\Html;
8
use neon\core\db\ActiveRecord;
9
use neon\user\interfaces\iUserInvite;
10
use neon\user\models\User;
11
12
/**
13
 * User Invite model
14
 *
15
 * @property string $token
16
 * @property string $user_id
17
 * @property integer $created_at
18
 * @property integer $updated_at
19
 * @property integer $expires_at
20
 */
21
class UserInvite extends ActiveRecord
22
{
23
	/**
24
	 * @var integer  time limit after which the token will expire (default 7 days)
25
	 */
26
	public $userInviteTokenExpire = 604800;
27
28
	/**
29
	 * @inheritdoc
30
	 */
31
	public static $blame = true;
32
33
	/**
34
	 * @inheritdoc
35
	 */
36
	public static $timestamps = true;
37
38
	/**
39
	 * @var string
40
	 */
41
	public static $invalidTokenMessage = 'This invitation is invalid';
42
43
	/**
44
	 * @var string
45
	 */
46
	public static $userAlreadyRegisteredMessage = 'You have already finished registering your account';
47
48
	/**
49
	 * @var string
50
	 */
51
	public static $tokenExpiredOnMessage = 'This invite expired on {{expired_at}}. Contact {{admin}} to request a new one.';
52
		
53
	/**
54
	 * @var string
55
	 */
56
	public static $successfulRegistrationMessage = 'Your account is now registered. You can login at any time with the password you set.';
57
	/**
58
	 * @inheritdoc
59
	 */
60
	public static function tableName()
61
	{
62
		return '{{%user_invite}}';
63
	}
64
65
	/**
66
	 * @inheritdoc
67
	 */
68
	public function rules()
69
	{
70
		$rules = [
71
			['user_id', 'string'],
72
			[['token', 'user_id'], 'required']
73
		];
74
		return $rules;
75
	}
76
77
	/**
78
	 * Generates a new user invite token
79
	 */
80
	public function generateUserInviteToken()
81
	{
82
		$this->token = neon()->security->generateRandomString();
83
		$this->expires_at = date('Y-m-d H:i:g', time() + $this->userInviteTokenExpire);
0 ignored issues
show
Documentation Bug introduced by
The property $expires_at was declared of type integer, but date('Y-m-d H:i:g', time...>userInviteTokenExpire) is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
84
	}
85
86
	/**
87
	 * Get the invite token
88
	 * @return string
89
	 */
90
	public function getToken()
91
	{
92
		return $this->token;
93
	}
94
95
	/**
96
	 * Get a human readable string of time until the invite token expires
97
	 * for e.g. '24 hours'
98
	 * @return string
99
	 */
100
	public function inviteTokenExpiresIn()
101
	{
102
		return Carbon::now()->diffForHumans($this->expires_at, true);
0 ignored issues
show
Bug introduced by
true of type true is incompatible with the type array|integer expected by parameter $syntax of Carbon\Carbon::diffForHumans(). ( Ignorable by Annotation )

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

102
		return Carbon::now()->diffForHumans($this->expires_at, /** @scrutinizer ignore-type */ true);
Loading history...
103
	}
104
105
	/**
106
	 * Get hold of an invitation by its token
107
	 * @param string $token invite token
108
	 * @param boolean $ignoreExpiry whether to ignore the token expiry
109
	 * @return null|UserInvite
110
	 */
111
	public static function findInviteByInviteToken($token, $ignoreExpiry = false)
112
	{
113
		if (!$ignoreExpiry && self::hasInviteTokenExpired($token))
114
			return null;
115
		
116
		return self::findOne(['token' => $token]);
117
	}
118
119
	/**
120
	 * Finds out if invite token is valid
121
	 * @param string $token invite token
122
	 * @return boolean
123
	 */
124
	public static function isInviteTokenValid($token)
125
	{
126
		if (empty($token)) { return false; }
127
128
		$invite = self::getInvite($token);
129
		if (!$invite) { return false; }
130
131
		if (!User::findOne(['uuid' => $invite->user_id, 'status' => User::STATUS_PENDING])) { return false; }
132
133
		return !self::hasInviteTokenExpired($token);
134
	}
135
136
	/**
137
	 * @param string $token
138
	 * @return UserInvite|null
139
	 */
140
	public static function getInvite($token)
141
	{
142
		static $_invite;
143
		if ($_invite === null){
144
			$_invite = self::findOne(['token' => $token]);
145
		}
146
		return $_invite;
147
	}
148
149
	/**
150
	 * Check if the invite token has expired
151
	 * @param string $token invite token
152
	 * @return boolean - true if expired
153
	 */
154
	public static function hasInviteTokenExpired($token)
155
	{
156
		$invite = self::getInvite($token);
157
		if (!$invite) return false;
158
		return strtotime($invite->expires_at) <= time();
159
	}
160
161
	/**
162
	 * Get a useful message about when the invite expired and who to contact about it
163
	 * @param  string  $token
164
	 * @return string
165
	 */
166
	public static function getInvalidInviteMessage($token)
167
	{
168
		// If the invite does not exist
169
		if (!($invite = self::getInvite($token))) {
170
			return self::$invalidTokenMessage;
171
		}
172
		// if the associated user does not exist - then we are invalid
173
		if (!($user = User::findOne(['uuid' => $invite->user_id]))) {
174
			return self::$invalidTokenMessage;
175
		}
176
		// If the user has already registered return the appropriate message
177
		if ($user->status !== \neon\user\models\User::STATUS_PENDING) {
178
			return self::$userAlreadyRegisteredMessage;
179
		}
180
		// If the invitation has passed it's expiration date return the appropriate message
181
		if (self::hasInviteTokenExpired($token)) {
182
			$inviter = User::findOne(['id' => $invite->created_by]);
0 ignored issues
show
Bug Best Practice introduced by
The property created_by does not exist on neon\user\models\UserInvite. Since you implemented __get, consider adding a @property annotation.
Loading history...
183
			$admin = $inviter ? $inviter->getName() : 'unknown';
0 ignored issues
show
introduced by
$inviter is of type neon\user\models\User, thus it always evaluated to true.
Loading history...
184
			return strtr(self::$tokenExpiredOnMessage, [
185
				'{{expired_at}}' => date('Y-m-d H:i', strtotime($invite->expires_at)),
186
				'{{admin}}' => $admin
187
			]);
188
		}
189
		// Otherwise return the generic message
190
		return self::$invalidTokenMessage;
191
	}
192
}