PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.6.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.6.01
2.10.0 2.10.01 2.9.1 2.9.0 2.8.1 2.8.0 2.7.7 2.7.5 2.7.0 2.6.01 2.6.0 2.5.0 2.4.01 trunk 1.0.90 1.0.91 1.0.92 1.0.93 1.0.94 1.0.95 1.0.96 1.0.97 1.0.98 1.0.99 1.1.0 All 77 releases
fluent-community / app / Models / User.php

User.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 2.6.01, at app/Models/User.php

774 lines 23.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCommunity\App\Models;
4
5 use FluentCommunity\App\Functions\Utility;
6 use FluentCommunity\App\Services\FeedsHelper;
7 use FluentCommunity\App\Services\Helper;
8 use FluentCommunity\App\Services\ProfileHelper;
9 use FluentCommunity\Framework\Support\Arr;
10 use FluentCommunity\Modules\Course\Model\Course;
11 use FluentCommunityPro\App\Models\Follow;
12 use FluentCrm\App\Models\Subscriber;
13
14 /**
15 * User Model - DB Model for WordPress Users Table
16 *
17 * Database Model
18 *
19 * @package FluentCommunity\App\Models
20 *
21 * @version 1.0.0
22 */
23 class User extends Model
24 {
25 protected $table = 'users';
26
27 protected $primaryKey = 'ID';
28
29 protected $hidden = ['user_pass', 'user_activation_key'];
30
31 protected $appends = ['photo'];
32
33 public $timestamps = false;
34
35 protected $searchable = [
36 'display_name',
37 'user_email'
38 ];
39
40 public function scopeSearchBy($query, $search)
41 {
42 if ($search) {
43 $fields = $this->searchable;
44 $query->where(function ($query) use ($fields, $search) {
45 $query->where(array_shift($fields), 'LIKE', "%$search%");
46 foreach ($fields as $field) {
47 $query->orWhere($field, 'LIKE', "$search%");
48 }
49 });
50 }
51
52 return $query;
53 }
54
55 public function scopeMentionBy($query, $search)
56 {
57 if ($search) {
58 $fields = [
59 'display_name',
60 'user_login'
61 ];
62 $query->where(function ($query) use ($fields, $search) {
63 $query->where(array_shift($fields), 'LIKE', "$search%");
64 foreach ($fields as $field) {
65 $query->orWhere($field, 'LIKE', "$search%");
66 }
67 });
68 }
69
70 return $query;
71 }
72
73 /**
74 * Accessor to get dynamic photo attribute
75 * @return string
76 */
77 public function getPhotoAttribute()
78 {
79 if ($photo = get_user_meta($this->ID, '_fcom_user_photo', true)) {
80 return $photo;
81 }
82
83 if ($contact = $this->getContact()) {
84 return $contact->photo;
85 }
86
87 if (empty($this->attributes['user_email'])) {
88 if (defined('FLUENTCRM')) {
89 $contact = Subscriber::where('user_id', $this->ID)->first();
90 if ($contact) {
91 return $contact->photo;
92 }
93 }
94 return '';
95 }
96
97 if (Utility::getPrivacySetting('enable_gravatar') != 'yes') {
98 return apply_filters('fluent_community/default_avatar', FLUENT_COMMUNITY_PLUGIN_URL . 'assets/images/placeholder.png', $this->ID);
99 }
100
101 $hash = md5(strtolower(trim($this->attributes['user_email'])));
102
103 /**
104 * Gravatar URL by Email
105 *
106 * @return string $gravatar url of the gravatar image
107 */
108 $name = $this->attributes['display_name'];
109
110 $fallback = '';
111 if ($name) {
112 $fallback = '&d=https%3A%2F%2Fui-avatars.com%2Fapi%2F' . urlencode($name) . '/128';
113 }
114
115 return apply_filters('fluent_crm/get_avatar',
116 "https://www.gravatar.com/avatar/{$hash}?s=128" . $fallback,
117 $this->attributes['user_email']
118 );
119 }
120
121 public function getIsVerifiedAttribute()
122 {
123 return $this->isVerified();
124 }
125
126 public function getContact()
127 {
128 if (!defined('FLUENTCRM')) {
129 return null;
130 }
131
132 if ($this->user_email) {
133 return Subscriber::where('user_id', $this->ID)
134 ->orWhere('email', $this->user_email)
135 ->first();
136 }
137
138 return Subscriber::where('user_id', $this->ID)
139 ->first();
140 }
141
142 public function xprofile()
143 {
144 return $this->belongsTo(XProfile::class, 'ID', 'user_id');
145 }
146
147 // Relationship: Users this user follows
148 public function follows()
149 {
150 return $this->hasMany(Follow::class, 'follower_id', 'ID');
151
152 }
153
154 // Relationship: Users following this user
155 public function followers()
156 {
157 return $this->hasMany(Follow::class, 'followed_id', 'ID');
158 }
159
160 public function usermeta()
161 {
162 return $this->hasMany(UserMeta::class, 'user_id', 'ID');
163 }
164
165 public function messages()
166 {
167 return $this->hasMany(\FluentMessaging\App\Models\Message::class, 'user_id', 'ID');
168 }
169
170 public function getGeneralData()
171 {
172 $user = get_user_by('ID', $this->ID);
173
174 $fullName = '';
175 if ($user->first_name || $user->last_name) {
176 $fullName = trim($user->first_name . ' ' . $user->last_name);
177 }
178
179 if (!$fullName) {
180 $fullName = $user->display_name;
181 }
182
183 $contact = $this->getContact();
184
185 return [
186 'is_contact' => (bool)$contact,
187 'first_name' => $user->first_name,
188 'last_name' => $user->last_name,
189 'full_name' => $fullName,
190 'display_name' => $fullName,
191 'bio' => $user->description,
192 'website' => $user->user_url,
193 'id' => $user->ID,
194 'user_id' => $user->ID,
195 'created_at' => $user->user_registered,
196 'photo' => $this->photo,
197 'username' => $this->username,
198 'is_verified' => $this->isVerified()
199 ];
200 }
201
202 public function spaces()
203 {
204 return $this->belongsToMany(BaseSpace::class, 'fcom_space_user', 'user_id', 'space_id')
205 ->withPivot(['role', 'status', 'created_at']);
206 }
207
208 public function courses()
209 {
210 return $this->belongsToMany(Course::class, 'fcom_space_user', 'user_id', 'space_id')
211 ->withPivot(['role', 'created_at']);
212 }
213
214 public function notificationSubscriptions()
215 {
216 return $this->hasMany(NotificationSubscription::class, 'user_id');
217 }
218
219 public function space_pivot()
220 {
221 return $this->belongsTo(SpaceUserPivot::class, 'ID', 'user_id')->withoutGlobalScopes();
222 }
223
224 public function notification_records()
225 {
226 return $this->hasMany(NotificationSubscriber::class, 'user_id', 'ID')->withoutGlobalScopes();
227 }
228
229 public function crm_contact()
230 {
231 return $this->belongsTo(Contact::class, 'ID', 'user_id')->withoutGlobalScopes();
232 }
233
234 public function community_role()
235 {
236 return $this->belongsTo(Meta::class, 'ID', 'object_id')
237 ->where('meta_key', '_user_community_roles');
238 }
239
240 public function updateCustomData($updateData, $removeSrc = false)
241 {
242 if (isset($updateData['first_name']) && Utility::getPrivacySetting('enable_user_sync') === 'yes') {
243 $firstName = sanitize_text_field($updateData['first_name']);
244 $lastName = sanitize_text_field($updateData['last_name']);
245
246 $userData = [
247 'first_name' => $firstName,
248 'last_name' => $lastName,
249 'display_name' => trim($firstName . ' ' . $lastName),
250 'description' => isset($updateData['short_description']) ? sanitize_textarea_field($updateData['short_description']) : '',
251 'user_url' => isset($updateData['website']) ? esc_url($updateData['website']) : '',
252 'ID' => $this->ID
253 ];
254
255 wp_update_user($userData);
256
257 if ($contact = $this->getContact()) {
258 $contact->fill(array_filter([
259 'first_name' => $firstName,
260 'last_name' => $lastName
261 ]));
262
263 $dirtyFields = $contact->getDirty();
264 if ($dirtyFields) {
265 $contact->save();
266 do_action('fluent_crm/contact_updated', $contact, $dirtyFields);
267 }
268
269 }
270 }
271
272 return $this;
273 }
274
275 public function getDisplayName()
276 {
277 $user = get_user_by('ID', $this->ID);
278 $name = '';
279 if ($user->first_name || $user->last_name) {
280 $name = trim($user->first_name . ' ' . $user->last_name);
281 }
282 if ($name) {
283 return $name;
284 }
285
286 return $user->display_name;
287 }
288
289 public function getCustomMeta($key, $default = null)
290 {
291 $exist = Meta::where('object_type', 'user')
292 ->where('object_id', $this->ID)
293 ->where('meta_key', $key)
294 ->first();
295
296 if ($exist && $exist->value) {
297 return $exist->value;
298 }
299
300 return $default;
301 }
302
303 public function updateCustomMeta($key, $value)
304 {
305 $exist = Meta::where('object_type', 'user')
306 ->where('object_id', $this->ID)
307 ->where('meta_key', $key)
308 ->first();
309
310 if ($exist) {
311 $exist->value = $value;
312 $exist->save();
313 return $exist;
314 }
315
316 return Meta::create([
317 'object_type' => 'user',
318 'object_id' => $this->ID,
319 'meta_key' => $key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
320 'value' => $value
321 ]);
322 }
323
324 public function isNotMemberOfAnySpace()
325 {
326 return $this->spaces()->count() == 0;
327 }
328
329 public function getSpaceIds($cached = true)
330 {
331 if ($cached) {
332 $ids = get_user_meta($this->ID, '_fcom_space_ids', true);
333 if (!$ids || !is_array($ids)) {
334 $ids = [];
335 }
336 return $ids;
337 }
338
339 $this->cacheAccessSpaces();
340
341 return get_user_meta($this->ID, '_fcom_space_ids', true);
342 }
343
344 public function getJoinedSpaceIds()
345 {
346 $globalRoles = $this->getCommunityRoles();
347
348 if (array_intersect($globalRoles, ['admin', 'moderator'])) {
349 return BaseSpace::onlyMain()->pluck('id')->toArray();
350 }
351
352 return BaseSpace::onlyMain()->whereHas('members', function ($query) {
353 $query->where('user_id', $this->ID)
354 ->where('status', 'active');
355 })->pluck('id')->toArray();
356 }
357
358 public function getCommunityRoles()
359 {
360 if (Helper::isSuperAdmin($this->ID)) {
361 return ['admin'];
362 }
363
364 return (array)$this->getCustomMeta('_user_community_roles', []);
365 }
366
367 public function isCommunityAdmin()
368 {
369 return in_array('admin', $this->getCommunityRoles());
370 }
371
372 public function isCommunityModerator()
373 {
374 return !!array_intersect(['moderator', 'admin'], $this->getCommunityRoles());
375 }
376
377 public function hasCommunityModeratorAccess()
378 {
379 $permissions = $this->getPermissions(true);
380
381 return Arr::isTrue($permissions, 'community_moderator');
382 }
383
384 public function hasCommunityAdminAccess()
385 {
386 $permissions = $this->getPermissions(true);
387
388 return Arr::isTrue($permissions, 'community_admin');
389 }
390
391 public function hasCourseCreatorAccess()
392 {
393 $permissions = $this->getPermissions(true);
394
395 return Arr::isTrue($permissions, 'course_creator');
396 }
397
398 public function isSpaceModerator()
399 {
400 return $this->hasCourseCreatorAccess() || $this->hasCommunityModeratorAccess();
401 }
402
403 public function hasSpaceManageAccess()
404 {
405 $permissions = array_filter($this->getPermissions(true));
406
407 return !!array_intersect(['community_admin', 'course_admin'], array_keys($permissions));
408 }
409
410 public function getSpaceRole($space)
411 {
412 $globalRoles = $this->getCommunityRoles();
413
414 if ($globalRoles) {
415 if (in_array('admin', $globalRoles)) {
416 return 'admin';
417 }
418 }
419
420 if ($space) {
421 $membership = $space->getMembership($this->ID);
422
423 if ($membership) {
424 $role = $membership->pivot->role;
425 $status = $membership->pivot->status;
426
427 if ($role != 'member') {
428 return $role;
429 }
430
431 if (!in_array('moderator', $globalRoles)) {
432 if ($status == 'pending') {
433 return 'pending';
434 }
435 return $role;
436 }
437 }
438 }
439
440 if (in_array('moderator', $globalRoles)) {
441 return 'moderator';
442 }
443
444 return '';
445 }
446
447 public function cacheAccessSpaces()
448 {
449 $globalRoles = $this->getCommunityRoles();
450
451 if (array_intersect($globalRoles, ['admin', 'moderator'])) {
452 $spaces = BaseSpace::onlyMain()->get();
453 } else {
454 $spaces = BaseSpace::onlyMain()->whereHas('members', function ($query) {
455 $query->where('user_id', $this->ID)
456 ->where('status', 'active');
457 })->orWhere('privacy', 'public')->get();
458 }
459
460 $spaceIds = $spaces->pluck('id')->toArray();
461
462 update_user_meta($this->ID, '_fcom_space_ids', $spaceIds);
463
464 return $spaces;
465 }
466
467 protected function getRolePermissions($roles)
468 {
469 if (!$roles) {
470 return apply_filters('fluent_community/user/permissions', [
471 'read' => true
472 ], $roles, $this);
473 }
474
475 $isAdmin = in_array('admin', $roles);
476 $isModerator = !!array_intersect($roles, ['admin', 'moderator']);
477
478 $permissions = [
479 'admin' => $isAdmin,
480 'super_admin' => Helper::isSuperAdmin(),
481 'community_admin' => $isAdmin,
482 'community_moderator' => $isModerator,
483 'delete_any_feed' => $isModerator,
484 'edit_any_feed' => $isModerator,
485 'delete_any_comment' => $isModerator,
486 'edit_any_comment' => $isModerator,
487 'read' => true
488 ];
489
490 if ($isAdmin || in_array('course_admin', $roles)) {
491 $permissions['course_creator'] = true;
492 $permissions['course_admin'] = true;
493 } else if (in_array('course_creator', $roles)) {
494 $permissions['course_creator'] = true;
495 }
496
497 return apply_filters('fluent_community/user/permissions', $permissions, $roles, $this);
498 }
499
500 public function getPermissions($cached = true)
501 {
502 static $permissions;
503
504 if ($permissions && $cached) {
505 return $permissions;
506 }
507
508 $roles = $this->getCommunityRoles();
509
510 $permissions = $this->getRolePermissions($roles);
511
512 return $permissions;
513 }
514
515 public function getSpacePermissions($space)
516 {
517 if (!$space) {
518 return [];
519 }
520
521 $role = $this->getSpaceRole($space);
522
523 $hasDocuments = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'document_library') == 'yes';
524
525 $isRestrictedPost = Arr::get($space->settings, 'restricted_post_only') == 'yes';
526
527 $documentAccess = Arr::get($space->settings, 'document_access');
528
529 if (!$role) {
530 $permissions = [
531 'can_create_post' => false,
532 'registered' => true,
533 'can_comment' => false,
534 'can_view_posts' => true,
535 'can_view_members' => $space->canViewMembers($this),
536 'is_pending' => false,
537 'is_non_member' => true,
538 'can_view_info' => $space->privacy !== 'secret',
539 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in'])
540 ];
541
542 if ($space->privacy === 'secret' || $space->privacy === 'private') {
543 $permissions['can_view_posts'] = false;
544 $permissions['can_view_members'] = false;
545 $permissions['can_view_documents'] = false;
546 }
547 } else if ($role == 'pending') {
548 $permissions = [
549 'can_create_post' => false,
550 'registered' => true,
551 'can_view_posts' => true,
552 'can_comment' => false,
553 'can_view_members' => $space->canViewMembers($this),
554 'is_pending' => true,
555 'can_view_info' => $space->privacy !== 'secret',
556 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in'])
557 ];
558
559 if ($space->privacy === 'secret' || $space->privacy === 'private') {
560 $permissions['can_view_posts'] = false;
561 $permissions['can_view_members'] = false;
562 $permissions['can_view_documents'] = false;
563 }
564 } else if ($role == 'member' || $role == 'student') {
565 $permissions = [
566 'can_create_post' => $isRestrictedPost ? false : true,
567 'registered' => true,
568 'can_view_posts' => true,
569 'can_view_members' => $space->canViewMembers($this),
570 'can_comment' => true,
571 'can_view_info' => true,
572 'can_view_documents' => $hasDocuments,
573 'can_upload_documents' => $hasDocuments && Arr::get($space->settings, 'document_upload') == 'members_only'
574 ];
575 } else {
576 $isMod = in_array($role, ['admin', 'moderator']);
577 $isAdmin = $role === 'admin';
578 $permissions = [
579 'can_create_post' => $isRestrictedPost ? $isMod : true,
580 'can_view_posts' => true,
581 'can_view_members' => $isAdmin || $space->canViewMembers($this),
582 'registered' => true,
583 'community_admin' => $isAdmin,
584 'community_moderator' => $isMod,
585 'edit_any_feed' => $isMod,
586 'delete_any_feed' => $isMod,
587 'edit_any_comment' => $isMod,
588 'delete_any_comment' => $isMod,
589 'super_admin' => Helper::isSuperAdmin(),
590 'read' => true,
591 'can_remove_member' => $isAdmin,
592 'can_add_member' => $isAdmin,
593 'can_comment' => $isMod,
594 'can_view_info' => true,
595 'can_view_documents' => $hasDocuments,
596 'can_upload_documents' => $hasDocuments && $isMod
597 ];
598 }
599
600 $permissions['is_member'] = in_array($role, ['admin', 'moderator', 'member', 'student']);
601
602 return apply_filters('fluent_community/user/space/permissions', $permissions, $space, $role, $this);
603 }
604
605 public function hasCommunityPermission($permission)
606 {
607 $permissions = $this->getPermissions();
608
609 if (isset($permissions[$permission])) {
610 return $permissions[$permission];
611 }
612
613 return false;
614 }
615
616 public function hasSpacePermission($permission, $space)
617 {
618 $permissions = $this->getSpacePermissions($space);
619
620 if (isset($permissions[$permission])) {
621 return $permissions[$permission];
622 }
623
624 return false;
625 }
626
627 public function verifyCommunityPermission($permission)
628 {
629 if (!$this->hasCommunityPermission($permission)) {
630 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
631 }
632
633 return true;
634 }
635
636 public function verifySpacePermission($permission, $space)
637 {
638 if (!$space || !$this->hasSpacePermission($permission, $space)) {
639 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
640 }
641
642 return true;
643 }
644
645 public function canEditFeed($feed, $throwException = false)
646 {
647 $result = $feed->user_id == $this->ID || $this->hasCommunityPermission('edit_any_feed') || $this->hasSpacePermission('edit_any_feed', $feed->space);
648
649 if (!$result && $throwException) {
650 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
651 }
652
653 return $result;
654 }
655
656 public function canDeleteFeed($feed, $throwException = false)
657 {
658 $result = $feed->user_id == $this->ID || $this->hasCommunityPermission('delete_any_feed') || $this->hasSpacePermission('delete_any_feed', $feed->space);
659
660 if (!$result && $throwException) {
661 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
662 }
663 return $result;
664 }
665
666 public function can($permission, $space = null)
667 {
668 if ($space) {
669 return $this->hasSpacePermission($permission, $space);
670 }
671
672 return $this->hasCommunityPermission($permission);
673 }
674
675 public function hasPermissionOrInCurrentSpace($permission, $space = null)
676 {
677 if ($this->hasCommunityPermission($permission)) {
678 return true;
679 }
680
681 return $space && $this->hasSpacePermission($permission, $space);
682 }
683
684 public function getUnreadNotificationCount()
685 {
686 return NotificationSubscriber::where('user_id', $this->ID)
687 ->unread()
688 ->count();
689 }
690
691 public function getUnreadNotificationFeedIds()
692 {
693 $ids = Notification::whereHas('subscribers', function ($query) {
694 return $query->where('user_id', $this->ID)
695 ->unread();
696 })->pluck('feed_id')->toArray();
697
698 return array_values(array_unique($ids));
699 }
700
701 public function isVerified()
702 {
703 if ($this->xprofile) {
704 return (bool) $this->xprofile->is_verified;
705 }
706
707 return false;
708 }
709
710 public function syncXProfile($force = false, $useUserName = false)
711 {
712 $exist = XProfile::where('user_id', $this->ID)->first();
713
714 if (($exist && !$force) || ($exist && Utility::getPrivacySetting('enable_user_sync') === 'no')) {
715 return $exist;
716 }
717
718 $data = [
719 'user_id' => $this->ID,
720 'username' => ProfileHelper::generateUserName($this->ID, $useUserName),
721 'display_name' => $this->getDisplayName(),
722 'is_verified' => $this->isVerified() ? 1 : 0,
723 'short_description' => get_user_meta($this->ID, 'description', true),
724 'meta' => [
725 'website' => $this->user_url,
726 'cover_photo' => get_user_meta($this->ID, '_fluent_cover_photo', true),
727 'short_description_rendered' => wp_kses_post(FeedsHelper::mdToHtml(get_user_meta($this->ID, 'description', true)))
728 ]
729 ];
730
731 if ($exist) {
732 unset($data['avatar']);
733 unset($data['username']);
734
735 if (apply_filters('fluent/community/user_wp_user_registered_date', true, $this)) {
736 $data['created_at'] = $this->user_registered;
737 }
738
739 $data['meta'] = wp_parse_args($exist->meta, $data['meta']);
740 $exist->fill($data);
741 $exist->save();
742 return $exist;
743 }
744
745 $counter = 1;
746 $initialUserName = $data['username'];
747 while (XProfile::where('username', $initialUserName)->first()) {
748 $initialUserName = $data['username'] . '_' . $counter;
749 $counter++;
750 }
751
752 $data['username'] = $initialUserName;
753 $data['status'] = 'active';
754 if (apply_filters('fluent/community/user_wp_user_registered_date', true, $this)) {
755 $data['created_at'] = get_date_from_gmt($this->user_registered, 'Y-m-d H:i:s');
756 }
757
758 $xprofile = XProfile::create($data);
759 $this->load('xprofile');
760
761 return $xprofile;
762 }
763
764 public function getUserMeta($metaKey, $default = null)
765 {
766 return get_user_meta($this->ID, $metaKey, true) ?? $default;
767 }
768
769 public function getWpUser()
770 {
771 return get_user_by('ID', $this->ID);
772 }
773 }
774