PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.7.0
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.7.0
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.7.0, at app/Models/User.php

784 lines 24.3 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()->where(function ($spaceQuery) {
455 $spaceQuery->whereHas('members', function ($memberQuery) {
456 $memberQuery->where('user_id', $this->ID)
457 ->where('status', 'active');
458 })->orWhere('privacy', 'public');
459 })->get();
460 }
461
462 $spaceIds = $spaces->pluck('id')->toArray();
463
464 update_user_meta($this->ID, '_fcom_space_ids', $spaceIds);
465
466 return $spaces;
467 }
468
469 protected function getRolePermissions($roles)
470 {
471 if (!$roles) {
472 return apply_filters('fluent_community/user/permissions', [
473 'read' => true
474 ], $roles, $this);
475 }
476
477 $isAdmin = in_array('admin', $roles);
478 $isModerator = !!array_intersect($roles, ['admin', 'moderator']);
479
480 $permissions = [
481 'admin' => $isAdmin,
482 'super_admin' => Helper::isSuperAdmin(),
483 'community_admin' => $isAdmin,
484 'community_moderator' => $isModerator,
485 'delete_any_feed' => $isModerator,
486 'edit_any_feed' => $isModerator,
487 'delete_any_comment' => $isModerator,
488 'edit_any_comment' => $isModerator,
489 'read' => true
490 ];
491
492 if ($isAdmin || in_array('course_admin', $roles)) {
493 $permissions['course_creator'] = true;
494 $permissions['course_admin'] = true;
495 } else if (in_array('course_creator', $roles)) {
496 $permissions['course_creator'] = true;
497 }
498
499 return apply_filters('fluent_community/user/permissions', $permissions, $roles, $this);
500 }
501
502 public function getPermissions($cached = true)
503 {
504 static $permissions;
505
506 if ($permissions && $cached) {
507 return $permissions;
508 }
509
510 $roles = $this->getCommunityRoles();
511
512 $permissions = $this->getRolePermissions($roles);
513
514 return $permissions;
515 }
516
517 public function getSpacePermissions($space)
518 {
519 if (!$space) {
520 return [];
521 }
522
523 $role = $this->getSpaceRole($space);
524
525 $hasDocuments = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'document_library') == 'yes';
526 $hasMediaGallery = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'media_gallery') == 'yes';
527
528 $isRestrictedPost = Arr::get($space->settings, 'restricted_post_only') == 'yes';
529
530 $documentAccess = Arr::get($space->settings, 'document_access');
531 $mediaAccess = Arr::get($space->settings, 'media_access');
532
533 if (!$role) {
534 $permissions = [
535 'can_create_post' => false,
536 'registered' => true,
537 'can_comment' => false,
538 'can_view_posts' => true,
539 'can_view_members' => $space->canViewMembers($this),
540 'is_pending' => false,
541 'is_non_member' => true,
542 'can_view_info' => $space->privacy !== 'secret',
543 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in']),
544 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, ['everybody', 'logged_in'])
545 ];
546
547 if ($space->privacy === 'secret' || $space->privacy === 'private') {
548 $permissions['can_view_posts'] = false;
549 $permissions['can_view_members'] = false;
550 $permissions['can_view_documents'] = false;
551 $permissions['can_view_media'] = false;
552 }
553 } else if ($role == 'pending') {
554 $permissions = [
555 'can_create_post' => false,
556 'registered' => true,
557 'can_view_posts' => true,
558 'can_comment' => false,
559 'can_view_members' => $space->canViewMembers($this),
560 'is_pending' => true,
561 'can_view_info' => $space->privacy !== 'secret',
562 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in']),
563 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, ['everybody', 'logged_in'])
564 ];
565
566 if ($space->privacy === 'secret' || $space->privacy === 'private') {
567 $permissions['can_view_posts'] = false;
568 $permissions['can_view_members'] = false;
569 $permissions['can_view_documents'] = false;
570 $permissions['can_view_media'] = false;
571 }
572 } else if ($role == 'member' || $role == 'student') {
573 $permissions = [
574 'can_create_post' => $isRestrictedPost ? false : true,
575 'registered' => true,
576 'can_view_posts' => true,
577 'can_view_members' => $space->canViewMembers($this),
578 'can_comment' => true,
579 'can_view_info' => true,
580 'can_view_documents' => $hasDocuments,
581 'can_upload_documents' => $hasDocuments && Arr::get($space->settings, 'document_upload') == 'members_only',
582 'can_view_media' => $hasMediaGallery
583 ];
584 } else {
585 $isMod = in_array($role, ['admin', 'moderator']);
586 $isAdmin = $role === 'admin';
587 $permissions = [
588 'can_create_post' => $isRestrictedPost ? $isMod : true,
589 'can_view_posts' => true,
590 'can_view_members' => $isAdmin || $space->canViewMembers($this),
591 'registered' => true,
592 'community_admin' => $isAdmin,
593 'community_moderator' => $isMod,
594 'edit_any_feed' => $isMod,
595 'delete_any_feed' => $isMod,
596 'edit_any_comment' => $isMod,
597 'delete_any_comment' => $isMod,
598 'super_admin' => Helper::isSuperAdmin(),
599 'read' => true,
600 'can_remove_member' => $isAdmin,
601 'can_add_member' => $isAdmin,
602 'can_comment' => $isMod,
603 'can_view_info' => true,
604 'can_view_documents' => $hasDocuments,
605 'can_upload_documents' => $hasDocuments && $isMod,
606 'can_view_media' => $hasMediaGallery
607 ];
608 }
609
610 $permissions['is_member'] = in_array($role, ['admin', 'moderator', 'member', 'student']);
611
612 return apply_filters('fluent_community/user/space/permissions', $permissions, $space, $role, $this);
613 }
614
615 public function hasCommunityPermission($permission)
616 {
617 $permissions = $this->getPermissions();
618
619 if (isset($permissions[$permission])) {
620 return $permissions[$permission];
621 }
622
623 return false;
624 }
625
626 public function hasSpacePermission($permission, $space)
627 {
628 $permissions = $this->getSpacePermissions($space);
629
630 if (isset($permissions[$permission])) {
631 return $permissions[$permission];
632 }
633
634 return false;
635 }
636
637 public function verifyCommunityPermission($permission)
638 {
639 if (!$this->hasCommunityPermission($permission)) {
640 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
641 }
642
643 return true;
644 }
645
646 public function verifySpacePermission($permission, $space)
647 {
648 if (!$space || !$this->hasSpacePermission($permission, $space)) {
649 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
650 }
651
652 return true;
653 }
654
655 public function canEditFeed($feed, $throwException = false)
656 {
657 $result = $feed->user_id == $this->ID || $this->hasCommunityPermission('edit_any_feed') || $this->hasSpacePermission('edit_any_feed', $feed->space);
658
659 if (!$result && $throwException) {
660 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
661 }
662
663 return $result;
664 }
665
666 public function canDeleteFeed($feed, $throwException = false)
667 {
668 $result = $feed->user_id == $this->ID || $this->hasCommunityPermission('delete_any_feed') || $this->hasSpacePermission('delete_any_feed', $feed->space);
669
670 if (!$result && $throwException) {
671 throw new \Exception(esc_html__('You do not have permission to do this action', 'fluent-community'));
672 }
673 return $result;
674 }
675
676 public function can($permission, $space = null)
677 {
678 if ($space) {
679 return $this->hasSpacePermission($permission, $space);
680 }
681
682 return $this->hasCommunityPermission($permission);
683 }
684
685 public function hasPermissionOrInCurrentSpace($permission, $space = null)
686 {
687 if ($this->hasCommunityPermission($permission)) {
688 return true;
689 }
690
691 return $space && $this->hasSpacePermission($permission, $space);
692 }
693
694 public function getUnreadNotificationCount()
695 {
696 return NotificationSubscriber::where('user_id', $this->ID)
697 ->unread()
698 ->count();
699 }
700
701 public function getUnreadNotificationFeedIds()
702 {
703 $ids = Notification::whereHas('subscribers', function ($query) {
704 return $query->where('user_id', $this->ID)
705 ->unread();
706 })->pluck('feed_id')->toArray();
707
708 return array_values(array_unique($ids));
709 }
710
711 public function isVerified()
712 {
713 if ($this->xprofile) {
714 return (bool) $this->xprofile->is_verified;
715 }
716
717 return false;
718 }
719
720 public function syncXProfile($force = false, $useUserName = false)
721 {
722 $exist = XProfile::where('user_id', $this->ID)->first();
723
724 if (($exist && !$force) || ($exist && Utility::getPrivacySetting('enable_user_sync') === 'no')) {
725 return $exist;
726 }
727
728 $data = [
729 'user_id' => $this->ID,
730 'username' => ProfileHelper::generateUserName($this->ID, $useUserName),
731 'display_name' => $this->getDisplayName(),
732 'is_verified' => $this->isVerified() ? 1 : 0,
733 'short_description' => get_user_meta($this->ID, 'description', true),
734 'meta' => [
735 'website' => $this->user_url,
736 'cover_photo' => get_user_meta($this->ID, '_fluent_cover_photo', true),
737 'short_description_rendered' => wp_kses_post(FeedsHelper::mdToHtml(get_user_meta($this->ID, 'description', true)))
738 ]
739 ];
740
741 if ($exist) {
742 unset($data['avatar']);
743 unset($data['username']);
744
745 if (apply_filters('fluent/community/user_wp_user_registered_date', true, $this)) {
746 $data['created_at'] = $this->user_registered;
747 }
748
749 $data['meta'] = wp_parse_args($exist->meta, $data['meta']);
750 $exist->fill($data);
751 $exist->save();
752 return $exist;
753 }
754
755 $counter = 1;
756 $initialUserName = $data['username'];
757 while (XProfile::where('username', $initialUserName)->first()) {
758 $initialUserName = $data['username'] . '_' . $counter;
759 $counter++;
760 }
761
762 $data['username'] = $initialUserName;
763 $data['status'] = 'active';
764 if (apply_filters('fluent/community/user_wp_user_registered_date', true, $this)) {
765 $data['created_at'] = get_date_from_gmt($this->user_registered, 'Y-m-d H:i:s');
766 }
767
768 $xprofile = XProfile::create($data);
769 $this->load('xprofile');
770
771 return $xprofile;
772 }
773
774 public function getUserMeta($metaKey, $default = null)
775 {
776 return get_user_meta($this->ID, $metaKey, true) ?? $default;
777 }
778
779 public function getWpUser()
780 {
781 return get_user_by('ID', $this->ID);
782 }
783 }
784