PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 2.10.01
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v2.10.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
← All changes | app/Models/User.php +96 -48 2.6.02.10.01 View file →
@@ -18,8 +18,22 @@
18 18 *
19 19 * @package FluentCommunity\App\Models
20 20 *
21 21 * @version 1.0.0
22 + *
23 + * @property int $ID
24 + * @property string $user_login
25 + * @property string $user_pass
26 + * @property string $user_nicename
27 + * @property string $user_email
28 + * @property string $user_url
29 + * @property string $user_registered
30 + * @property string $user_activation_key
31 + * @property int $user_status
32 + * @property string $display_name
33 + * @property-read string $photo
34 + * @property-read XProfile|null $xprofile
35 + * @property string|null $username
22 36 */
23 37 class User extends Model
24 38 {
25 39 protected $table = 'users';
@@ -25,17 +39,17 @@
25 39 protected $table = 'users';
26 40
27 41 protected $primaryKey = 'ID';
28 42
29 - protected $hidden = ['user_pass', 'user_activation_key'];
43 + protected $hidden = [ 'user_pass', 'user_activation_key' ];
30 44
31 - protected $appends = ['photo'];
45 + protected $appends = [ 'photo' ];
32 46
33 47 public $timestamps = false;
34 48
35 49 protected $searchable = [
36 50 'display_name',
37 - 'user_email'
51 + 'user_email',
38 52 ];
39 53
40 54 public function scopeSearchBy($query, $search)
41 55 {
@@ -56,9 +70,9 @@
56 70 {
57 71 if ($search) {
58 72 $fields = [
59 73 'display_name',
60 - 'user_login'
74 + 'user_login',
61 75 ];
62 76 $query->where(function ($query) use ($fields, $search) {
63 77 $query->where(array_shift($fields), 'LIKE', "$search%");
64 78 foreach ($fields as $field) {
@@ -75,13 +89,13 @@
75 89 * @return string
76 90 */
77 91 public function getPhotoAttribute()
78 92 {
79 - if ($photo = get_user_meta($this->ID, '_fcom_user_photo', true)) {
93 + if ($photo = get_user_meta($this->ID, '_fcom_user_photo', true)) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
80 94 return $photo;
81 95 }
82 96
83 - if ($contact = $this->getContact()) {
97 + if ($contact = $this->getContact()) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
84 98 return $contact->photo;
85 99 }
86 100
87 101 if (empty($this->attributes['user_email'])) {
@@ -93,9 +107,9 @@
93 107 }
94 108 return '';
95 109 }
96 110
97 - if (Utility::getPrivacySetting('enable_gravatar') != 'yes') {
111 + if (Utility::getPrivacySetting('enable_gravatar') == 'no') {
98 112 return apply_filters('fluent_community/default_avatar', FLUENT_COMMUNITY_PLUGIN_URL . 'assets/images/placeholder.png', $this->ID);
99 113 }
100 114
101 115 $hash = md5(strtolower(trim($this->attributes['user_email'])));
@@ -194,9 +208,9 @@
194 208 'user_id' => $user->ID,
195 209 'created_at' => $user->user_registered,
196 210 'photo' => $this->photo,
197 211 'username' => $this->username,
198 - 'is_verified' => $this->isVerified()
212 + 'is_verified' => $this->isVerified(),
199 213 ];
200 214 }
201 215
202 216 public function spaces()
@@ -201,22 +215,35 @@
201 215
202 216 public function spaces()
203 217 {
204 218 return $this->belongsToMany(BaseSpace::class, 'fcom_space_user', 'user_id', 'space_id')
205 - ->withPivot(['role', 'status', 'created_at']);
219 + ->withPivot([ 'role', 'status', 'created_at' ]);
206 220 }
207 221
208 222 public function courses()
209 223 {
210 224 return $this->belongsToMany(Course::class, 'fcom_space_user', 'user_id', 'space_id')
211 - ->withPivot(['role', 'created_at']);
225 + ->withPivot([ 'role', 'created_at' ]);
212 226 }
213 227
228 + /**
229 + * @deprecated 2.8.2 Use notificationPreferences() - preferences no longer live
230 + * in fcom_notification_users.
231 + */
214 232 public function notificationSubscriptions()
215 233 {
216 234 return $this->hasMany(NotificationSubscription::class, 'user_id');
217 235 }
218 236
237 + /**
238 + * Explicit notification preference overrides across every channel.
239 + * Recipient selection for email fan-outs is driven off this relation.
240 + */
241 + public function notificationPreferences()
242 + {
243 + return $this->hasMany(NotificationPreference::class, 'user_id', 'ID');
244 + }
245 +
219 246 public function space_pivot()
220 247 {
221 248 return $this->belongsTo(SpaceUserPivot::class, 'ID', 'user_id')->withoutGlobalScopes();
222 249 }
@@ -233,8 +260,9 @@
233 260
234 261 public function community_role()
235 262 {
236 263 return $this->belongsTo(Meta::class, 'ID', 'object_id')
264 + ->where('object_type', 'user')
237 265 ->where('meta_key', '_user_community_roles');
238 266 }
239 267
240 268 public function updateCustomData($updateData, $removeSrc = false)
@@ -248,17 +276,17 @@
248 276 'last_name' => $lastName,
249 277 'display_name' => trim($firstName . ' ' . $lastName),
250 278 'description' => isset($updateData['short_description']) ? sanitize_textarea_field($updateData['short_description']) : '',
251 279 'user_url' => isset($updateData['website']) ? esc_url($updateData['website']) : '',
252 - 'ID' => $this->ID
280 + 'ID' => $this->ID,
253 281 ];
254 282
255 283 wp_update_user($userData);
256 284
257 - if ($contact = $this->getContact()) {
285 + if ($contact = $this->getContact()) { // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
258 286 $contact->fill(array_filter([
259 287 'first_name' => $firstName,
260 - 'last_name' => $lastName
288 + 'last_name' => $lastName,
261 289 ]));
262 290
263 291 $dirtyFields = $contact->getDirty();
264 292 if ($dirtyFields) {
@@ -271,8 +299,9 @@
271 299
272 300 return $this;
273 301 }
274 302
303 + // WP account real name (first + last, falling back to wp_users.display_name). Not the public community name — use getPublicDisplayName() for anything shown to other members.
275 304 public function getDisplayName()
276 305 {
277 306 $user = get_user_by('ID', $this->ID);
278 307 $name = '';
@@ -285,8 +314,19 @@
285 314
286 315 return $user->display_name;
287 316 }
288 317
318 + // Public community name (xprofile.display_name, falling back to wp_users.display_name). Use this for actor names in notifications/emails to avoid leaking the legal name.
319 + public function getPublicDisplayName()
320 + {
321 + $name = $this->xprofile ? $this->xprofile->display_name : '';
322 + if (!$name) {
323 + $name = $this->display_name;
324 + }
325 +
326 + return apply_filters('fluent_community/public_display_name', $name, $this);
327 + }
328 +
289 329 public function getCustomMeta($key, $default = null)
290 330 {
291 331 $exist = Meta::where('object_type', 'user')
292 332 ->where('object_id', $this->ID)
@@ -316,9 +356,9 @@
316 356 return Meta::create([
317 357 'object_type' => 'user',
318 358 'object_id' => $this->ID,
319 359 'meta_key' => $key, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
320 - 'value' => $value
360 + 'value' => $value,
321 361 ]);
322 362 }
323 363
324 364 public function isNotMemberOfAnySpace()
@@ -344,9 +384,9 @@
344 384 public function getJoinedSpaceIds()
345 385 {
346 386 $globalRoles = $this->getCommunityRoles();
347 387
348 - if (array_intersect($globalRoles, ['admin', 'moderator'])) {
388 + if (array_intersect($globalRoles, [ 'admin', 'moderator' ])) {
349 389 return BaseSpace::onlyMain()->pluck('id')->toArray();
350 390 }
351 391
352 392 return BaseSpace::onlyMain()->whereHas('members', function ($query) {
@@ -357,9 +397,9 @@
357 397
358 398 public function getCommunityRoles()
359 399 {
360 400 if (Helper::isSuperAdmin($this->ID)) {
361 - return ['admin'];
401 + return [ 'admin' ];
362 402 }
363 403
364 404 return (array)$this->getCustomMeta('_user_community_roles', []);
365 405 }
@@ -370,9 +410,9 @@
370 410 }
371 411
372 412 public function isCommunityModerator()
373 413 {
374 - return !!array_intersect(['moderator', 'admin'], $this->getCommunityRoles());
414 + return (bool)array_intersect([ 'moderator', 'admin' ], $this->getCommunityRoles());
375 415 }
376 416
377 417 public function hasCommunityModeratorAccess()
378 418 {
@@ -403,9 +443,9 @@
403 443 public function hasSpaceManageAccess()
404 444 {
405 445 $permissions = array_filter($this->getPermissions(true));
406 446
407 - return !!array_intersect(['community_admin', 'course_admin'], array_keys($permissions));
447 + return (bool)array_intersect([ 'community_admin', 'course_admin' ], array_keys($permissions));
408 448 }
409 449
410 450 public function getSpaceRole($space)
411 451 {
@@ -447,15 +487,17 @@
447 487 public function cacheAccessSpaces()
448 488 {
449 489 $globalRoles = $this->getCommunityRoles();
450 490
451 - if (array_intersect($globalRoles, ['admin', 'moderator'])) {
491 + if (array_intersect($globalRoles, [ 'admin', 'moderator' ])) {
452 492 $spaces = BaseSpace::onlyMain()->get();
453 493 } 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();
494 + $spaces = BaseSpace::onlyMain()->where(function ($spaceQuery) {
495 + $spaceQuery->whereHas('members', function ($memberQuery) {
496 + $memberQuery->where('user_id', $this->ID)
497 + ->where('status', 'active');
498 + })->orWhere('privacy', 'public');
499 + })->get();
458 500 }
459 501
460 502 $spaceIds = $spaces->pluck('id')->toArray();
461 503
@@ -467,14 +509,14 @@
467 509 protected function getRolePermissions($roles)
468 510 {
469 511 if (!$roles) {
470 512 return apply_filters('fluent_community/user/permissions', [
471 - 'read' => true
513 + 'read' => true,
472 514 ], $roles, $this);
473 515 }
474 516
475 517 $isAdmin = in_array('admin', $roles);
476 - $isModerator = !!array_intersect($roles, ['admin', 'moderator']);
518 + $isModerator = (bool)array_intersect($roles, [ 'admin', 'moderator' ]);
477 519
478 520 $permissions = [
479 521 'admin' => $isAdmin,
480 522 'super_admin' => Helper::isSuperAdmin(),
@@ -483,15 +525,15 @@
483 525 'delete_any_feed' => $isModerator,
484 526 'edit_any_feed' => $isModerator,
485 527 'delete_any_comment' => $isModerator,
486 528 'edit_any_comment' => $isModerator,
487 - 'read' => true
529 + 'read' => true,
488 530 ];
489 531
490 532 if ($isAdmin || in_array('course_admin', $roles)) {
491 533 $permissions['course_creator'] = true;
492 534 $permissions['course_admin'] = true;
493 - } else if (in_array('course_creator', $roles)) {
535 + } elseif (in_array('course_creator', $roles)) {
494 536 $permissions['course_creator'] = true;
495 537 }
496 538
497 539 return apply_filters('fluent_community/user/permissions', $permissions, $roles, $this);
@@ -498,19 +540,17 @@
498 540 }
499 541
500 542 public function getPermissions($cached = true)
501 543 {
502 - static $permissions;
544 + static $permissions = [];
503 545
504 - if ($permissions && $cached) {
505 - return $permissions;
546 + if ($cached && isset($permissions[$this->ID])) {
547 + return $permissions[$this->ID];
506 548 }
507 549
508 550 $roles = $this->getCommunityRoles();
509 551
510 - $permissions = $this->getRolePermissions($roles);
511 -
512 - return $permissions;
552 + return $permissions[$this->ID] = $this->getRolePermissions($roles);
513 553 }
514 554
515 555 public function getSpacePermissions($space)
516 556 {
@@ -520,12 +560,15 @@
520 560
521 561 $role = $this->getSpaceRole($space);
522 562
523 563 $hasDocuments = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'document_library') == 'yes';
564 + $hasMediaGallery = defined('FLUENT_COMMUNITY_PRO') && Arr::get($space->settings, 'media_gallery') == 'yes';
524 565
525 566 $isRestrictedPost = Arr::get($space->settings, 'restricted_post_only') == 'yes';
567 + $isVerifiedPostOnly = Arr::get($space->settings, 'verified_post_only') == 'yes';
526 568
527 569 $documentAccess = Arr::get($space->settings, 'document_access');
570 + $mediaAccess = Arr::get($space->settings, 'media_access');
528 571
529 572 if (!$role) {
530 573 $permissions = [
531 574 'can_create_post' => false,
@@ -535,9 +578,10 @@
535 578 'can_view_members' => $space->canViewMembers($this),
536 579 'is_pending' => false,
537 580 'is_non_member' => true,
538 581 'can_view_info' => $space->privacy !== 'secret',
539 - 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in'])
582 + 'can_view_documents' => $hasDocuments && in_array($documentAccess, [ 'everybody', 'logged_in' ]),
583 + 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, [ 'everybody', 'logged_in' ]),
540 584 ];
541 585
542 586 if ($space->privacy === 'secret' || $space->privacy === 'private') {
543 587 $permissions['can_view_posts'] = false;
@@ -542,10 +586,11 @@
542 586 if ($space->privacy === 'secret' || $space->privacy === 'private') {
543 587 $permissions['can_view_posts'] = false;
544 588 $permissions['can_view_members'] = false;
545 589 $permissions['can_view_documents'] = false;
590 + $permissions['can_view_media'] = false;
546 591 }
547 - } else if ($role == 'pending') {
592 + } elseif ($role == 'pending') {
548 593 $permissions = [
549 594 'can_create_post' => false,
550 595 'registered' => true,
551 596 'can_view_posts' => true,
@@ -552,9 +597,10 @@
552 597 'can_comment' => false,
553 598 'can_view_members' => $space->canViewMembers($this),
554 599 'is_pending' => true,
555 600 'can_view_info' => $space->privacy !== 'secret',
556 - 'can_view_documents' => $hasDocuments && in_array($documentAccess, ['everybody', 'logged_in'])
601 + 'can_view_documents' => $hasDocuments && in_array($documentAccess, [ 'everybody', 'logged_in' ]),
602 + 'can_view_media' => $hasMediaGallery && in_array($mediaAccess, [ 'everybody', 'logged_in' ]),
557 603 ];
558 604
559 605 if ($space->privacy === 'secret' || $space->privacy === 'private') {
560 606 $permissions['can_view_posts'] = false;
@@ -559,12 +605,13 @@
559 605 if ($space->privacy === 'secret' || $space->privacy === 'private') {
560 606 $permissions['can_view_posts'] = false;
561 607 $permissions['can_view_members'] = false;
562 608 $permissions['can_view_documents'] = false;
609 + $permissions['can_view_media'] = false;
563 610 }
564 - } else if ($role == 'member' || $role == 'student') {
611 + } elseif ($role == 'member' || $role == 'student') {
565 612 $permissions = [
566 - 'can_create_post' => $isRestrictedPost ? false : true,
613 + 'can_create_post' => $isRestrictedPost ? false : (!$isVerifiedPostOnly || $this->isVerified()),
567 614 'registered' => true,
568 615 'can_view_posts' => true,
569 616 'can_view_members' => $space->canViewMembers($this),
570 617 'can_comment' => true,
@@ -569,12 +616,13 @@
569 616 'can_view_members' => $space->canViewMembers($this),
570 617 'can_comment' => true,
571 618 'can_view_info' => true,
572 619 'can_view_documents' => $hasDocuments,
573 - 'can_upload_documents' => $hasDocuments && Arr::get($space->settings, 'document_upload') == 'members_only'
620 + 'can_upload_documents' => $hasDocuments && Arr::get($space->settings, 'document_upload') == 'members_only',
621 + 'can_view_media' => $hasMediaGallery,
574 622 ];
575 623 } else {
576 - $isMod = in_array($role, ['admin', 'moderator']);
624 + $isMod = in_array($role, [ 'admin', 'moderator' ]);
577 625 $isAdmin = $role === 'admin';
578 626 $permissions = [
579 627 'can_create_post' => $isRestrictedPost ? $isMod : true,
580 628 'can_view_posts' => true,
@@ -592,13 +640,14 @@
592 640 'can_add_member' => $isAdmin,
593 641 'can_comment' => $isMod,
594 642 'can_view_info' => true,
595 643 'can_view_documents' => $hasDocuments,
596 - 'can_upload_documents' => $hasDocuments && $isMod
644 + 'can_upload_documents' => $hasDocuments && $isMod,
645 + 'can_view_media' => $hasMediaGallery,
597 646 ];
598 647 }
599 648
600 - $permissions['is_member'] = in_array($role, ['admin', 'moderator', 'member', 'student']);
649 + $permissions['is_member'] = in_array($role, [ 'admin', 'moderator', 'member', 'student' ]);
601 650
602 651 return apply_filters('fluent_community/user/space/permissions', $permissions, $space, $role, $this);
603 652 }
604 653
@@ -723,18 +772,17 @@
723 772 'short_description' => get_user_meta($this->ID, 'description', true),
724 773 'meta' => [
725 774 'website' => $this->user_url,
726 775 '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 - ]
776 + 'short_description_rendered' => wp_kses_post(FeedsHelper::mdToHtml(get_user_meta($this->ID, 'description', true))),
777 + ],
729 778 ];
730 779
731 780 if ($exist) {
732 - unset($data['avatar']);
733 - unset($data['username']);
781 + $data = array_diff_key($data, [ 'avatar' => true, 'username' => true ]);
734 782
735 783 if (apply_filters('fluent/community/user_wp_user_registered_date', true, $this)) {
736 - $data['created_at'] = $this->user_registered;
784 + $data['created_at'] = get_date_from_gmt($this->user_registered, 'Y-m-d H:i:s');
737 785 }
738 786
739 787 $data['meta'] = wp_parse_args($exist->meta, $data['meta']);
740 788 $exist->fill($data);
@@ -745,9 +793,9 @@
745 793 $counter = 1;
746 794 $initialUserName = $data['username'];
747 795 while (XProfile::where('username', $initialUserName)->first()) {
748 796 $initialUserName = $data['username'] . '_' . $counter;
749 - $counter++;
797 + ++$counter;
750 798 }
751 799
752 800 $data['username'] = $initialUserName;
753 801 $data['status'] = 'active';