User::getDetails()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 1
cts 1
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 1
1
<?php
2
3
namespace App;
4
5
/**
6
 * User basic class.
7
 *
8
 * @package App
9
 *
10
 * @copyright YetiForce S.A.
11
 * @license   YetiForce Public License 6.5 (licenses/LicenseEN.txt or yetiforce.com)
12
 * @author    Mariusz Krzaczkowski <[email protected]>
13
 * @author    Radosław Skrzypczak <[email protected]>
14
 */
15
class User
16
{
17
	protected static $currentUserId;
18
	protected static $currentUserRealId = false;
19
	protected static $currentUserCache = false;
20
	protected static $userModelCache = [];
21
	protected $privileges = [];
22
23
	protected static $userPrivilegesCache = [];
24
25
	protected static $userSharingCache = [];
26 5829
27
	/**
28 5829
	 * Get current user Id.
29
	 *
30
	 * @return int
31
	 */
32
	public static function getCurrentUserId()
33
	{
34
		return static::$currentUserId;
35
	}
36 11
37
	/**
38 11
	 * Set current user Id.
39 11
	 *
40 11
	 * @param int $userId
41
	 */
42
	public static function setCurrentUserId($userId)
43
	{
44
		if (!self::isExists($userId, false)) {
45
			throw new \App\Exceptions\AppException('User not exists: ' . $userId);
46
		}
47 5795
		static::$currentUserId = $userId;
48
		static::$currentUserCache = false;
49 5795
	}
50 5793
51
	/**
52 2
	 * Get real current user Id.
53
	 *
54
	 * @return int
55 2
	 */
56
	public static function getCurrentUserRealId()
57 2
	{
58
		if (static::$currentUserRealId) {
59 2
			return static::$currentUserRealId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::currentUserRealId returns the type true which is incompatible with the documented return type integer.
Loading history...
60
		}
61
		if (\App\Session::has('baseUserId') && \App\Session::get('baseUserId')) {
62
			$id = \App\Session::get('baseUserId');
63
		} else {
64
			$id = static::getCurrentUserId();
65
		}
66
		static::$currentUserRealId = $id;
67 5833
		return $id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $id also could return the type array|string which is incompatible with the documented return type integer.
Loading history...
68
	}
69 5833
70 5822
	/**
71
	 * Get current user model.
72 5785
	 *
73 2
	 * @return \self
0 ignored issues
show
Bug introduced by
The type self was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
74
	 */
75 5785
	public static function getCurrentUserModel()
76
	{
77
		if (static::$currentUserCache) {
78
			return static::$currentUserCache;
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::currentUserCache returns the type true which is incompatible with the documented return type self.
Loading history...
79
		}
80
		if (!static::$currentUserId) {
81
			static::$currentUserId = (int) \App\Session::get('authenticated_user_id');
82
		}
83
		return static::$currentUserCache = static::getUserModel(static::$currentUserId);
84
	}
85 5795
86
	/**
87 5795
	 * Get user model by id.
88 18
	 *
89
	 * @param int $userId
90 5783
	 *
91 5783
	 * @return \self
92 5781
	 */
93 5781
	public static function &getUserModel($userId)
94 5781
	{
95 5781
		if (isset(static::$userModelCache[$userId])) {
96
			return static::$userModelCache[$userId];
97 5783
		}
98
		$userModel = new self();
99
		if ($userId) {
100
			$userModel->privileges = static::getPrivilegesFile($userId)['_privileges'] ?? [];
101
			static::$userModelCache[$userId] = $userModel;
102
		}
103
		return $userModel;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userModel returns the type App\User which is incompatible with the documented return type self.
Loading history...
104
	}
105
106
	/**
107
	 * Get base privileges from file by id.
108
	 *
109 5796
	 * @param int $userId
110
	 *
111 5796
	 * @return array
112 19
	 */
113
	public static function getPrivilegesFile($userId): array
114 5781
	{
115 1
		if (isset(static::$userPrivilegesCache[$userId])) {
116
			return self::$userPrivilegesCache[$userId];
117 5780
		}
118
		if (!file_exists("user_privileges/user_privileges_{$userId}.php")) {
119 5780
			return [];
120 5780
		}
121 5780
		$privileges = require "user_privileges/user_privileges_{$userId}.php";
122 5780
123 5780
		$valueMap = [];
124 5780
		$valueMap['id'] = $userId;
125
		$valueMap['is_admin'] = (bool) $is_admin;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $is_admin seems to be never defined.
Loading history...
126
		$valueMap['user_info'] = $user_info;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user_info seems to be never defined.
Loading history...
127
		$valueMap['_privileges'] = $privileges;
128
		if (!$is_admin) {
129
			$valueMap['roleid'] = $current_user_roles;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $current_user_roles seems to be never defined.
Loading history...
130
			$valueMap['parent_role_seq'] = $current_user_parent_role_seq;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $current_user_parent_role_seq seems to be never defined.
Loading history...
131
			$valueMap['profiles'] = $current_user_profiles;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $current_user_profiles seems to be never defined.
Loading history...
132
			$valueMap['profile_global_permission'] = $profileGlobalPermission;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $profileGlobalPermission seems to be never defined.
Loading history...
133
			$valueMap['profile_tabs_permission'] = $profileTabsPermission;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $profileTabsPermission seems to be never defined.
Loading history...
134
			$valueMap['profile_action_permission'] = $profileActionPermission;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $profileActionPermission seems to be never defined.
Loading history...
135
			$valueMap['groups'] = $current_user_groups;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $current_user_groups seems to be never defined.
Loading history...
136
			$valueMap['subordinate_roles'] = $subordinate_roles;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subordinate_roles seems to be never defined.
Loading history...
137
			$valueMap['parent_roles'] = $parent_roles;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $parent_roles seems to be never defined.
Loading history...
138
			$valueMap['subordinate_roles_users'] = $subordinate_roles_users;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subordinate_roles_users seems to be never defined.
Loading history...
139 5780
			$sharingPrivileges = static::getSharingFile($userId);
140
			$valueMap['defaultOrgSharingPermission'] = $sharingPrivileges['defOrgShare'];
141 5780
			$valueMap['related_module_share'] = $sharingPrivileges['relatedModuleShare'];
142
		}
143
		self::$userPrivilegesCache[$userId] = $valueMap;
144
145
		return $valueMap;
146
	}
147
148
	/**
149 5780
	 * Clear user cache.
150
	 *
151 5780
	 * @param bool|int $userId
152 5778
	 */
153 5778
	public static function clearCache($userId = false)
154 5774
	{
155
		if ($userId) {
156
			unset(self::$userPrivilegesCache[$userId], self::$userSharingCache[$userId], static::$userModelCache[$userId]);
157 2
			if (static::$currentUserId === $userId) {
158 2
				static::$currentUserCache = false;
159
			}
160 5780
		} else {
161
			self::$userPrivilegesCache = self::$userSharingCache = static::$userModelCache = [];
162
			static::$currentUserCache = false;
163
		}
164
	}
165
166
	/**
167
	 * Get sharing privileges from file by id.
168
	 *
169
	 * @param int $userId
170
	 *
171 1
	 * @return array
172
	 */
173 1
	public static function getSharingFile($userId)
174 1
	{
175
		if (isset(self::$userSharingCache[$userId])) {
176 1
			return self::$userSharingCache[$userId];
177 1
		}
178
		if (!file_exists("user_privileges/sharing_privileges_{$userId}.php")) {
179 1
			return null;
180 1
		}
181
		$sharingPrivileges = require "user_privileges/sharing_privileges_{$userId}.php";
182 1
		self::$userSharingCache[$userId] = $sharingPrivileges;
183
184
		return $sharingPrivileges;
185
	}
186
187
	/**
188
	 * Get user id.
189
	 *
190 20
	 * @return int|null
191
	 */
192 20
	public function getId()
193
	{
194
		return $this->privileges['details']['record_id'] ?? null;
195
	}
196
197
	/**
198
	 * Get user id.
199
	 *
200 7
	 * @return int
201
	 */
202 7
	public function getName()
203
	{
204
		return $this->privileges['displayName'];
205
	}
206
207
	/**
208
	 * Get user detail.
209
	 *
210
	 * @param string $fieldName
211
	 *
212 5796
	 * @return mixed
213
	 */
214 5796
	public function getDetail($fieldName)
215
	{
216
		return $this->privileges['details'][$fieldName] ?? null;
217
	}
218
219
	/**
220
	 * Get user all details.
221
	 *
222
	 * @param string $fieldName
223
	 *
224 2
	 * @return mixed
225
	 */
226 2
	public function getDetails()
227
	{
228
		return $this->privileges['details'] ?? null;
229
	}
230
231
	/**
232
	 * Get user profiles.
233
	 *
234 19
	 * @return array
235
	 */
236 19
	public function getProfiles()
237
	{
238
		return $this->privileges['profiles'] ?? null;
239
	}
240
241
	/**
242
	 * Get user groups.
243
	 *
244 7
	 * @return array
245
	 */
246 7
	public function getGroups(): array
247
	{
248
		return $this->privileges['groups'] ?? [];
249
	}
250
251
	/**
252
	 * Get user group names.
253
	 *
254 5
	 * @return string[]
255
	 */
256
	public function getGroupNames()
257 5
	{
258 5
		return array_filter(\App\Fields\Owner::getInstance('CustomView')->getGroups(false), fn ($key) => \in_array($key, $this->getGroups()), ARRAY_FILTER_USE_KEY);
259
	}
260
261
	/**
262
	 * Get user role Id.
263
	 *
264
	 * @return string
265
	 */
266 6
	public function getRole(): string
267
	{
268 6
		return $this->privileges['details']['roleid'];
269
	}
270
271
	/**
272
	 * Get user role Id.
273
	 *
274
	 * @return string
275
	 */
276 8
	public function getRoleName(): string
277
	{
278 8
		return $this->privileges['roleName'];
279 6
	}
280
281 4
	/**
282
	 * Get user role instance.
283
	 *
284
	 * @return \Settings_Roles_Record_Model
285
	 */
286
	public function getRoleInstance()
287
	{
288
		if (!empty($this->privileges['roleInstance'])) {
289 2
			return $this->privileges['roleInstance'];
290
		}
291 2
		return $this->privileges['roleInstance'] = \Settings_Roles_Record_Model::getInstanceById($this->getRole());
0 ignored issues
show
Bug introduced by
$this->getRole() of type string is incompatible with the type integer expected by parameter $roleId of Settings_Roles_Record_Model::getInstanceById(). ( Ignorable by Annotation )

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

291
		return $this->privileges['roleInstance'] = \Settings_Roles_Record_Model::getInstanceById(/** @scrutinizer ignore-type */ $this->getRole());
Loading history...
292
	}
293
294
	/**
295
	 * Get user parent roles.
296
	 *
297
	 * @return array
298
	 */
299 1
	public function getParentRoles()
300
	{
301 1
		return $this->privileges['parent_roles'];
302
	}
303
304
	/**
305
	 * Get user parent roles seq.
306
	 *
307
	 * @return string
308
	 */
309 7
	public function getParentRolesSeq()
310
	{
311 7
		return $this->privileges['parent_role_seq'];
312
	}
313
314
	/**
315
	 * Function to check whether the user is an Admin user.
316
	 *
317
	 * @return bool true/false
318
	 */
319
	public function isAdmin()
320
	{
321 2
		return !empty($this->privileges['details']['is_admin']);
322
	}
323 2
324
	/**
325
	 * Function to check whether the user is an super user.
326
	 *
327
	 * @return bool
328
	 */
329
	public function isSuperUser(): bool
330
	{
331
		return !empty($this->privileges['details']['super_user']);
332
	}
333
334
	/**
335
	 * Get user parameters.
336
	 *
337
	 * @param string $key
338
	 *
339
	 * @return mixed
340
	 */
341
	public function get($key)
342
	{
343
		return $this->privileges[$key];
344
	}
345 1
346
	/**
347 1
	 * Check for existence of key.
348
	 *
349
	 * @param string $key
350
	 *
351
	 * @return bool
352
	 */
353
	public function has(string $key): bool
354
	{
355
		return \array_key_exists($key, $this->privileges);
356
	}
357 6
358
	/**
359 6
	 * Set user parameters.
360 4
	 *
361
	 * @param string $key
362 4
	 * @param mixed  $value
363 4
	 *
364
	 * @return mixed
365
	 */
366
	public function set(string $key, $value)
367
	{
368
		$this->privileges[$key] = $value;
369 4
		return $this;
370 4
	}
371 4
372 4
	/**
373
	 * Function checks if user is active.
374 4
	 *
375
	 * @return bool
376 4
	 */
377
	public function isActive()
378
	{
379
		return 'Active' === ($this->privileges['details']['status'] ?? null);
380
	}
381
382
	/**
383
	 * Function checks if user exists.
384 9
	 *
385
	 * @param int  $id     - User ID
386 9
	 * @param bool $active
387 9
	 *
388 5
	 * @return bool
389
	 */
390 7
	public static function isExists(int $id, bool $active = true): bool
391 7
	{
392
		$cacheKey = $active ? 'UserIsExists' : 'UserIsExistsInactive';
393
		if (Cache::has($cacheKey, $id)) {
394
			return Cache::get($cacheKey, $id);
395
		}
396
		$isExists = false;
397
		if (\App\Config::performance('ENABLE_CACHING_USERS')) {
398
			$users = PrivilegeFile::getUser('id');
399
			if (($active && isset($users[$id]) && 'Active' == $users[$id]['status'] && !$users[$id]['deleted']) || (!$active && isset($users[$id]))) {
400 7
				$isExists = true;
401 7
			}
402 7
		} else {
403 7
			$isExistsQuery = (new \App\Db\Query())->from('vtiger_users')->where(['id' => $id]);
404 7
			if ($active) {
405
				$isExistsQuery->andWhere(['status' => 'Active', 'deleted' => 0]);
406 7
			}
407
			$isExists = $isExistsQuery->exists();
408 7
		}
409
		Cache::save($cacheKey, $id, $isExists);
410
		return $isExists;
411
	}
412
413
	/**
414
	 * Function to get the user if of the active admin user.
415
	 *
416
	 * @return int - Active Admin User ID
417
	 */
418 8
	public static function getActiveAdminId()
419
	{
420 8
		$key = '';
421 5
		$cacheName = 'ActiveAdminId';
422
		if (Cache::has($cacheName, $key)) {
423 4
			return Cache::get($cacheName, $key);
424 4
		}
425
		$adminId = 1;
426 4
		if (\App\Config::performance('ENABLE_CACHING_USERS')) {
427
			$users = PrivilegeFile::getUser('id');
428
			foreach ($users as $id => $user) {
429
				if ('Active' === $user['status'] && 'on' === $user['is_admin']) {
430
					$adminId = $id;
431
					break;
432
				}
433
			}
434
		} else {
435
			$adminId = (new Db\Query())->select(['id'])
436
				->from('vtiger_users')
437
				->where(['is_admin' => 'on', 'status' => 'Active'])
438
				->orderBy(['id' => SORT_ASC])
439
				->scalar();
440
		}
441
		Cache::save($cacheName, $key, $adminId, Cache::LONG);
442
443
		return $adminId;
444
	}
445
446
	/**
447
	 * Function gets user ID by name.
448
	 *
449
	 * @param string $name
450
	 *
451 6
	 * @return int
452
	 */
453 6
	public static function getUserIdByName($name): ?int
454
	{
455
		if (Cache::has('UserIdByName', $name)) {
456 6
			return Cache::get('UserIdByName', $name);
457 6
		}
458 6
		$userId = (new Db\Query())->select(['id'])->from('vtiger_users')->where(['user_name' => $name])->scalar();
459
		return Cache::save('UserIdByName', $name, false !== $userId ? $userId : null, Cache::LONG);
0 ignored issues
show
Bug Best Practice introduced by
The expression return App\Cache::save('... null, App\Cache::LONG) returns the type boolean which is incompatible with the type-hinted return integer|null.
Loading history...
460
	}
461
462
	/**
463
	 * Function gets user ID by user full name.
464
	 *
465
	 * @param string $fullName
466
	 *
467
	 * @return int
468
	 */
469
	public static function getUserIdByFullName(string $fullName): int
470
	{
471
		$instance = \App\Fields\Owner::getInstance();
472
		$instance->showRoleName = false;
473
		$users = array_column($instance->initUsers(), 'id', 'fullName');
474
		return $users[$fullName] ?? 0;
475
	}
476
477
	/**
478
	 * Get user image details.
479
	 *
480
	 * @throws \App\Exceptions\AppException
481
	 *
482
	 * @return array|string[]
483
	 */
484
	public function getImage()
485
	{
486
		if (Cache::has('UserImageById', $this->getId())) {
487
			return Cache::get('UserImageById', $this->getId());
488
		}
489
		$image = Json::decode($this->getDetail('imagename'));
490
		if (empty($image) || !($imageData = current($image))) {
491
			return [];
492
		}
493
		$imageData['path'] = ROOT_DIRECTORY . \DIRECTORY_SEPARATOR . $imageData['path'];
494
		if (file_exists($imageData['path'])) {
495
			$imageData['url'] = "file.php?module=Users&action=MultiImage&field=imagename&record={$this->getId()}&key={$imageData['key']}";
496
		} else {
497
			$imageData = [];
498
		}
499
		Cache::save('UserImageById', $this->getId(), $imageData);
500
		return $imageData;
501
	}
502
503
	/**
504
	 * Gets member structure.
505
	 *
506
	 * @return array
507
	 */
508
	public function getMemberStructure(): array
509
	{
510
		$member[] = \App\PrivilegeUtil::MEMBER_TYPE_USERS . ":{$this->getId()}";
0 ignored issues
show
Comprehensibility Best Practice introduced by
$member was never initialized. Although not strictly required by PHP, it is generally a good practice to add $member = array(); before regardless.
Loading history...
511
		foreach ($this->getGroups() as $groupId) {
512
			$member[] = \App\PrivilegeUtil::MEMBER_TYPE_GROUPS . ":{$groupId}";
513
		}
514
		$member[] = \App\PrivilegeUtil::MEMBER_TYPE_ROLES . ":{$this->getRole()}";
515
		foreach (explode('::', $this->getParentRolesSeq()) as $role) {
516
			$member[] = \App\PrivilegeUtil::MEMBER_TYPE_ROLE_AND_SUBORDINATES . ":{$role}";
517
		}
518
		return $member;
519
	}
520
521
	/**
522
	 * Get user image details by id.
523
	 *
524
	 * @param int $userId
525
	 *
526
	 * @throws \App\Exceptions\AppException
527
	 *
528
	 * @return array|string[]
529
	 */
530
	public static function getImageById(int $userId)
531
	{
532
		if (Cache::has('UserImageById', $userId)) {
533
			return Cache::get('UserImageById', $userId);
534
		}
535
		$userModel = static::getUserModel($userId);
536
		if (empty($userModel)) {
537
			return [];
538
		}
539
		return $userModel->getImage();
540
	}
541
542
	/**
543
	 * Get number of users.
544
	 *
545
	 * @return int
546
	 */
547
	public static function getNumberOfUsers(): int
548
	{
549
		if (Cache::has('NumberOfUsers', '')) {
550
			return Cache::get('NumberOfUsers', '');
551
		}
552
		$count = (new Db\Query())->from('vtiger_users')->where(['status' => 'Active'])->count();
553
		Cache::save('NumberOfUsers', '', $count, Cache::LONG);
554
		return $count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $count could return the type string which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
555
	}
556
557
	/**
558
	 * Update users labels.
559
	 *
560
	 * @param int $fromUserId
561
	 *
562
	 * @return void
563
	 */
564
	public static function updateLabels(int $fromUserId = 0): void
565
	{
566
		$timeLimit = 180;
567
		$timeMax = $timeLimit + time();
568
		$query = (new \App\Db\Query())->select(['id'])->where(['>=', 'id', $fromUserId])->from('vtiger_users');
569
		$dataReader = $query->createCommand()->query();
570
		while ($row = $dataReader->read()) {
571
			if (time() >= $timeMax) {
572
				(new \App\BatchMethod(['method' => __METHOD__, 'params' => [$row['id'], microtime()]]))->save();
573
				break;
574
			}
575
			if (self::isExists($row['id'], false)) {
576
				$userRecordModel = \Users_Record_Model::getInstanceById($row['id'], 'Users');
577
				$userRecordModel->updateLabel();
578
			}
579
		}
580
	}
581
582
	/**
583
	 * The function gets the all users label.
584
	 *
585
	 * @return bool|array
586
	 */
587
	public static function getAllLabels()
588
	{
589
		return (new \App\Db\Query())->from('u_#__users_labels')->select(['id', 'label'])->createCommand()->queryAllByGroup();
590
	}
591
592
	/**
593
	 * Check the previous password.
594
	 *
595
	 * @param int    $userId
596
	 * @param string $password
597
	 *
598
	 * @return bool
599
	 */
600
	public static function checkPreviousPassword(int $userId, string $password): bool
601
	{
602
		return (new \App\Db\Query())->from('l_#__userpass_history')->where(['user_id' => $userId, 'pass' => Encryption::createHash($password)])->exists(\App\Db::getInstance('log'));
603
	}
604
}
605