PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.0.96
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.0.96
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 / Services / ProfileHelper.php

ProfileHelper.php in FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses 1.0.96, at app/Services/ProfileHelper.php

297 lines 13.9 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\Services;
4
5 use FluentCommunity\App\Functions\Utility;
6 use FluentCommunity\App\Models\Meta;
7 use FluentCommunity\App\Models\User;
8 use FluentCommunity\App\Models\XProfile;
9
10 class ProfileHelper
11 {
12
13 public static function getProfile($userId = null)
14 {
15 if (!$userId) {
16 $userId = get_current_user_id();
17 }
18
19 return XProfile::where('user_id', $userId)->first();
20 }
21
22 public static function getXProfilePublicFields()
23 {
24 return ['user_id', 'total_points', 'is_verified', 'status', 'display_name', 'username', 'avatar', 'created_at', 'last_activity', 'short_description', 'meta'];
25 }
26
27 public static function socialLinkProviders()
28 {
29 return apply_filters('fluent_community/social_link_providers', [
30 'instagram' => [
31 'title' => 'Instagram',
32 'icon_svg' => '<svg viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6 0C7.6302 0 7.8336 0.00599997 8.4732 0.036C9.1122 0.066 9.5472 0.1662 9.93 0.315C10.326 0.4674 10.6596 0.6738 10.9932 1.0068C11.2983 1.30674 11.5344 1.66955 11.685 2.07C11.8332 2.4522 11.934 2.8878 11.964 3.5268C11.9922 4.1664 12 4.3698 12 6C12 7.6302 11.994 7.8336 11.964 8.4732C11.934 9.1122 11.8332 9.5472 11.685 9.93C11.5348 10.3307 11.2987 10.6936 10.9932 10.9932C10.6932 11.2982 10.3304 11.5343 9.93 11.685C9.5478 11.8332 9.1122 11.934 8.4732 11.964C7.8336 11.9922 7.6302 12 6 12C4.3698 12 4.1664 11.994 3.5268 11.964C2.8878 11.934 2.4528 11.8332 2.07 11.685C1.6694 11.5347 1.30652 11.2986 1.0068 10.9932C0.701644 10.6933 0.465559 10.3305 0.315 9.93C0.1662 9.5478 0.066 9.1122 0.036 8.4732C0.00779997 7.8336 0 7.6302 0 6C0 4.3698 0.00599997 4.1664 0.036 3.5268C0.066 2.8872 0.1662 2.4528 0.315 2.07C0.465142 1.66931 0.701282 1.30639 1.0068 1.0068C1.3066 0.701539 1.66946 0.465438 2.07 0.315C2.4528 0.1662 2.8872 0.066 3.5268 0.036C4.1664 0.00779997 4.3698 0 6 0ZM6 3C5.20435 3 4.44129 3.31607 3.87868 3.87868C3.31607 4.44129 3 5.20435 3 6C3 6.79565 3.31607 7.55871 3.87868 8.12132C4.44129 8.68393 5.20435 9 6 9C6.79565 9 7.55871 8.68393 8.12132 8.12132C8.68393 7.55871 9 6.79565 9 6C9 5.20435 8.68393 4.44129 8.12132 3.87868C7.55871 3.31607 6.79565 3 6 3ZM9.9 2.85C9.9 2.65109 9.82098 2.46032 9.68033 2.31967C9.53968 2.17902 9.34891 2.1 9.15 2.1C8.95109 2.1 8.76032 2.17902 8.61967 2.31967C8.47902 2.46032 8.4 2.65109 8.4 2.85C8.4 3.04891 8.47902 3.23968 8.61967 3.38033C8.76032 3.52098 8.95109 3.6 9.15 3.6C9.34891 3.6 9.53968 3.52098 9.68033 3.38033C9.82098 3.23968 9.9 3.04891 9.9 2.85ZM6 4.2C6.47739 4.2 6.93523 4.38964 7.27279 4.72721C7.61036 5.06477 7.8 5.52261 7.8 6C7.8 6.47739 7.61036 6.93523 7.27279 7.27279C6.93523 7.61036 6.47739 7.8 6 7.8C5.52261 7.8 5.06477 7.61036 4.72721 7.27279C4.38964 6.93523 4.2 6.47739 4.2 6C4.2 5.52261 4.38964 5.06477 4.72721 4.72721C5.06477 4.38964 5.52261 4.2 6 4.2Z" fill="currentColor"/></svg>',
33 'placeholder' => 'instagram @username',
34 'domain' => 'https://instagram.com/',
35 ],
36 'twitter' => [
37 'title' => 'Twitter/X',
38 'icon_svg' => '<svg viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.1024 0.125H10.7564L7.1429 4.255L11.3939 9.875H8.0654L5.4584 6.4665L2.47542 9.875H0.820422L4.68542 5.4575L0.607422 0.125H4.02042L6.3769 3.2405L9.1024 0.125ZM8.5219 8.885H9.4384L3.52242 1.063H2.53892L8.5219 8.885Z" fill="currentColor"/></svg>',
39 'placeholder' => 'twitter/X @username',
40 'domain' => 'https://x.com/',
41 ],
42 'youtube' => [
43 'title' => 'YouTube',
44 'icon_svg' => '<svg viewBox="0 0 12 10" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M11.7258 1.699C12 2.7682 12 5.0002 12 5.0002C12 5.0002 12 7.2322 11.7258 8.3014C11.5734 8.8924 11.1276 9.3574 10.563 9.5146C9.5376 9.8002 6 9.8002 6 9.8002C6 9.8002 2.4642 9.8002 1.437 9.5146C0.87 9.355 0.4248 8.8906 0.2742 8.3014C1.78814e-08 7.2322 0 5.0002 0 5.0002C0 5.0002 1.78814e-08 2.7682 0.2742 1.699C0.4266 1.108 0.8724 0.642995 1.437 0.485795C2.4642 0.200195 6 0.200195 6 0.200195C6 0.200195 9.5376 0.200195 10.563 0.485795C11.13 0.645395 11.5752 1.1098 11.7258 1.699ZM4.8 7.1002L8.4 5.0002L4.8 2.9002V7.1002Z" fill="currentColor"/></svg>',
45 'placeholder' => 'youtube @username',
46 'domain' => 'https://youtube.com/',
47 ],
48 'linkedin' => [
49 'title' => 'LinkedIn',
50 'icon_svg' => '<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.80061 9.8035H8.20161V7.2973C8.20161 6.6997 8.18961 5.9305 7.36761 5.9305C6.53421 5.9305 6.40701 6.5809 6.40701 7.2535V9.8035H4.80741V4.6501H6.34341V5.3521H6.36441C6.57921 4.9477 7.10121 4.5199 7.88121 4.5199C9.50121 4.5199 9.80121 5.5867 9.80121 6.9745V9.8035H9.80061ZM3.00141 3.9451C2.87934 3.94526 2.75845 3.92132 2.64565 3.87466C2.53285 3.828 2.43037 3.75954 2.34408 3.6732C2.2578 3.58686 2.1894 3.48433 2.14282 3.37151C2.09623 3.25868 2.07237 3.13776 2.07261 3.0157C2.07273 2.832 2.12732 2.65246 2.22947 2.49979C2.33163 2.34711 2.47677 2.22816 2.64653 2.15797C2.81629 2.08778 3.00305 2.06951 3.1832 2.10546C3.36334 2.14142 3.52878 2.22998 3.65859 2.35996C3.78841 2.48994 3.87676 2.65549 3.91248 2.83569C3.9482 3.01588 3.92969 3.20262 3.85928 3.37229C3.78887 3.54196 3.66973 3.68694 3.51692 3.7889C3.36412 3.89086 3.18451 3.94522 3.00081 3.9451H3.00141ZM3.80301 9.8035H2.19921V4.6501H3.80361V9.8035H3.80301ZM10.6016 0.600098H1.39701C0.955409 0.600098 0.599609 0.948098 0.599609 1.3783V10.6219C0.599609 11.0521 0.956009 11.4001 1.39641 11.4001H10.5992C11.0396 11.4001 11.3996 11.0521 11.3996 10.6219V1.3783C11.3996 0.948098 11.0396 0.600098 10.5992 0.600098H10.601H10.6016Z" fill="currentColor"/></svg>',
51 'placeholder' => 'linkedin username',
52 'domain' => 'https://linkedin.com/in/',
53 ],
54 'fb' => [
55 'title' => 'Facebook',
56 'icon_svg' => '<svg width="7" height="12" viewBox="0 0 7 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M4.2 6.9H5.7L6.3 4.5H4.2V3.3C4.2 2.682 4.2 2.1 5.4 2.1H6.3V0.0840001C6.1044 0.0582001 5.3658 0 4.5858 0C2.9568 0 1.8 0.9942 1.8 2.82V4.5H0V6.9H1.8V12H4.2V6.9Z" fill="currentColor"/></svg>',
57 'placeholder' => 'fb username',
58 'domain' => 'https://facebook.com/',
59 ],
60 ]);
61 }
62
63 public static function getReservedUserNames()
64 {
65 return [
66 'admin', 'administrator', 'me', 'moderator', 'mod', 'superuser', 'root', 'system', 'official', 'staff', 'support', 'helpdesk', 'user', 'guest', 'anonymous', 'everyone', 'anybody', 'someone', 'webmaster', 'postmaster', 'hostmaster', 'abuse', 'security', 'ssl', 'firewall', 'no-reply', 'noreply', 'mail', 'email', 'mailer', 'smtp', 'pop', 'imap', 'ftp', 'sftp', 'ssh', 'ceo', 'cfo', 'cto', 'founder', 'cofounder', 'owner', 'president', 'vicepresident', 'director', 'manager', 'supervisor', 'executive', 'info', 'contact', 'sales', 'marketing', 'support', 'billing', 'accounting', 'finance', 'hr', 'humanresources', 'legal', 'compliance', 'it', 'itsupport', 'customerservice', 'customersupport', 'dev', 'developer', 'api', 'sdk', 'app', 'bot', 'chatbot', 'sysadmin', 'devops', 'infosec', 'security', 'test', 'testing', 'beta', 'alpha', 'staging', 'production', 'development', 'home', 'about', 'contact', 'faq', 'help', 'news', 'blog', 'forum', 'community', 'events', 'calendar', 'shop', 'store', 'cart', 'checkout', 'social', 'follow', 'like', 'share', 'tweet', 'post', 'status', 'privacy', 'terms', 'copyright', 'trademark', 'legal', 'policy', 'all', 'none', 'null', 'undefined', 'true', 'false', 'default', 'example', 'sample', 'demo', 'temporary', 'delete', 'remove', 'profanity', 'explicit', 'offensive', 'yourappname', 'yourbrandname', 'yourdomain',
67 ];
68 }
69
70 public static function isUsernameAvailable($userName, $targetUserId = null)
71 {
72 $userName = strtolower($userName);
73 $reservedUserNames = self::getReservedUserNames();
74 if (in_array($userName, $reservedUserNames)) {
75 return false;
76 }
77
78 $user = get_user_by('login', $userName);
79
80 if ($user) {
81 if ($targetUserId && $user->ID != $targetUserId) {
82 return false;
83 }
84 }
85
86 $xProfile = XProfile::where('username', $userName)
87 ->when($targetUserId, function ($query) use ($targetUserId) {
88 return $query->where('user_id', '!=', $targetUserId);
89 })
90 ->exists();
91
92 if ($xProfile) {
93 return false;
94 }
95
96 return true;
97 }
98
99 public static function generateUserName($user, $useUserName = false)
100 {
101 if (!$user instanceof \WP_User) {
102 $user = get_user_by('ID', $user);
103 }
104
105 if ($useUserName) {
106 $userName = $user->user_login;
107 } else {
108 $firstName = $user->first_name;
109 if (!$firstName || strlen($firstName) < 3) {
110 $firstName = $user->last_name;
111 }
112
113 if (!$firstName || strlen($firstName) < 3) {
114 $firstName = $user->user_nicename;
115 }
116
117 if (!$firstName) {
118 $firstName = $user->display_name;
119 }
120
121 $userName = strtolower($firstName);
122 }
123
124 $userName = CustomSanitizer::sanitizeUserName($userName);
125 $userName = substr($userName, 0, 20);
126
127 if (!$userName) {
128 $userName = $user->user_nicename;
129 $userName = CustomSanitizer::sanitizeUserName($userName);
130 }
131
132 $finalUserName = $userName;
133 // loop until we find a unique username
134 $counter = 2;
135 while (!self::isUsernameAvailable($userName, $user->ID)) {
136 $userName = $finalUserName . $counter;
137 $counter++;
138 if ($counter % 100 === 0) {
139 $finalUserName = $finalUserName . $user->ID . '-';
140 }
141 }
142
143 return $userName;
144 }
145
146 public static function getUserAuthHash($userId = null)
147 {
148 if (!$userId) {
149 return '';
150 }
151
152 static $cached = [];
153
154 if (isset($cached[$userId])) {
155 return $cached[$userId];
156 }
157
158 $exist = Meta::byType('user')
159 ->byMetaKey('auth_hash')
160 ->byObjectId($userId)
161 ->first();
162
163 $validTil = strtotime('+1 day');
164
165 if ($exist) {
166 $hashes = (array)$exist->value;
167
168 $validHashes = array_filter($hashes, function ($hash) use ($validTil) {
169 return $hash['valid_til'] > $validTil;
170 });
171
172 if ($validHashes) {
173 $lastHash = end($validHashes);
174 return $lastHash['hash'] . '__' . $exist->id;
175 }
176 $newHash = md5(wp_generate_uuid4() . '_' . $userId . '_' . '_' . time() . '__' . $userId);
177
178 $hashes[] = [
179 'hash' => $newHash,
180 'valid_til' => strtotime('+2 days')
181 ];
182
183 // remove expired hashes
184 $hashes = array_filter($hashes, function ($hash) use ($validTil) {
185 return $hash['valid_til'] > time();
186 });
187
188 $exist->value = array_values($hashes);
189 $exist->save();
190
191 $cached[$userId] = $newHash . '__' . $exist->id;
192
193 return $cached[$userId];
194 }
195
196 $newHash = md5(wp_generate_uuid4() . '_' . $userId . '_' . '_' . time() . '__' . $userId);
197
198 $meta = Meta::create([
199 'object_type' => 'user',
200 'object_id' => $userId,
201 'meta_key' => 'auth_hash',
202 'value' => [
203 [
204 'hash' => $newHash,
205 'valid_til' => strtotime('+2 days')
206 ]
207 ]
208 ]);
209
210 $cached[$userId] = $newHash . '__' . $meta->id;
211
212 return $cached[$userId];
213 }
214
215 public static function signUserUrlWithAuthHash($url, $userId = null)
216 {
217 $hash = self::getUserAuthHash($userId);
218 if (!$hash) {
219 return $url;
220 }
221
222 return add_query_arg([
223 'fcom_action' => 'signed_url',
224 'fcom_url_hash' => $hash
225 ], $url);
226 }
227
228 public static function getSignedNotificationPrefUrl($userId)
229 {
230 $notificationPref = Helper::baseUrl('fcom_route?route=user_notification_settings&auth=yes');
231 return self::signUserUrlWithAuthHash($notificationPref, $userId);
232 }
233
234 /*
235 * Get WP User by URL Hash
236 * @param string $hash
237 * @return \WP_User|null
238 */
239 public static function getUserByUrlHash($hash)
240 {
241 $hashParts = explode('__', $hash);
242 if (count($hashParts) !== 2) {
243 return null;
244 }
245
246 $metaId = $hashParts[1];
247 $meta = Meta::where('object_type', 'user')
248 ->where('meta_key', 'auth_hash')
249 ->where('id', $metaId)
250 ->first();
251
252 if (!$meta) {
253 return null;
254 }
255
256 $hashes = (array)$meta->value;
257 $hash = $hashParts[0];
258
259 $validHash = array_filter($hashes, function ($hashData) use ($hash) {
260 return $hashData['hash'] == $hash;
261 });
262
263 if (!$validHash) {
264 return null;
265 }
266
267 return get_user_by('ID', $meta->object_id);
268 }
269
270 public static function canViewUserSpaces($targetUserId, $currentUser = null)
271 {
272 $status = Utility::getPrivacySetting('user_space_visibility', 'everybody');
273
274 if ($status == 'everybody') {
275 return true;
276 }
277
278 if ($status == 'logged_in') {
279 return !!$currentUser;
280 }
281
282 if (is_numeric($currentUser)) {
283 $currentUser = User::find($currentUser);
284 }
285
286 if (!$currentUser) {
287 return false;
288 }
289
290 if ($targetUserId == $currentUser->ID) {
291 return true;
292 }
293
294 return Helper::isModerator($currentUser);
295 }
296 }
297