PluginProbe
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses / 1.0.90
FluentCommunity – Ultra-Fast High-Performance Social Network, Community, LMS & Online Courses v1.0.90
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 / FeedsHelper.php

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

266 lines 7.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\Services;
4
5 use FluentCommunity\App\Functions\Utility;
6 use FluentCommunity\App\Models\Feed;
7 use FluentCommunity\App\Models\Reaction;
8 use FluentCommunity\App\Models\Term;
9 use FluentCommunity\App\Models\User;
10 use FluentCommunity\App\Models\XProfile;
11 use FluentCommunity\Framework\Support\Arr;
12
13 class FeedsHelper
14 {
15 public static function getSpaceSlugsByUserId($userId)
16 {
17 if (!$userId) {
18 $userId = get_current_user_id();
19 }
20
21 if (!$userId) {
22 return [];
23 }
24
25 $user = User::find($userId);
26
27 return $user->spaces()->pluck('slug')->toArray();
28 }
29
30 public static function getLastFeedId()
31 {
32 $lastItem = Feed::where('status', 'published')
33 ->byUserAccess(get_current_user_id())
34 ->orderBy('id', 'DESC')
35 ->first();
36
37 if ($lastItem) {
38 return $lastItem->id;
39 }
40
41 return 1;
42 }
43
44 public static function mdToHtml($text, $options = [])
45 {
46 if (!$text) {
47 return '';
48 }
49 $text = str_replace('&#x20;', '', $text); // hide markdown empty content
50
51 $html = (new \FluentCommunity\App\Services\Parsedown([
52 ]))
53 ->setBreaksEnabled(true)
54 ->text($text);
55
56 if (!Arr::get($options, 'disable_link_process')) {
57 // add nofollow to all links. But check if nofollow is already there
58 $html = self::addNoFollowToLinks($html);
59 }
60
61 return $html;
62 }
63
64 public static function addNoFollowToLinks($html)
65 {
66 if(!$html) {
67 return '';
68 }
69
70 $current_domain = parse_url(home_url(), PHP_URL_HOST);
71
72 // Regular expression to match <a> tags
73 $pattern = '/<a\s[^>]*href=("|\')(https?:\/\/(?!'. preg_quote($current_domain, '/') .').*?)("|\')\s?([^>]*)>/i';
74
75 // Callback function to modify each matched <a> tag
76 $callback = function($matches) {
77 $url = $matches[2];
78 $attr = $matches[4];
79
80 // Remove existing rel attribute if present
81 $attr = preg_replace('/\srel=("|\').*?("|\')/i', '', $attr);
82
83 // Add nofollow
84 return '<a href="' . $url . '" rel="nofollow" ' . trim($attr) . '>';
85 };
86
87 // Perform the replacement
88 return preg_replace_callback($pattern, $callback, $html);
89 }
90
91 public static function findFirstUrl($html)
92 {
93 // use regular expression to find the first URL in a href tag
94 // do not take the url which contains /u/ in it
95 $pattern = '/<a\s+(?:[^>]*?\s+)?href=([\'"])(?!.*\/u\/)(.*?)\1/';
96 preg_match($pattern, $html, $matches);
97
98 if (isset($matches[2])) {
99 return $matches[2];
100 }
101
102 return '';
103 }
104
105 public static function extractHashTags($text, $limit = 5)
106 {
107 // Extract hashtag including - and _
108 preg_match_all('/#([a-zA-Z0-9_-]+)/', $text, $matches);
109
110 $tags = array_unique($matches[1]);
111
112 if (!$tags) {
113 return [];
114 }
115
116 $tags = array_slice($tags, 0, $limit);
117
118 $lowerCaseTags = array_map('strtolower', $tags);
119
120 $terms = Term::whereIn('slug', $lowerCaseTags)
121 ->where('taxonomy_name', 'hashtag')
122 ->get();
123
124 $termIds = [];
125
126 foreach ($terms as $term) {
127 $termIds[$term->slug] = $term->id;
128 }
129
130 if (count($termIds) == count($tags)) {
131 return array_values($termIds);
132 }
133
134 $excepts = array_diff($tags, array_keys($termIds));
135
136 foreach ($excepts as $except) {
137 $term = Term::create([
138 'taxonomy_name' => 'hashtag',
139 'slug' => strtolower($except),
140 'title' => $except
141 ]);
142
143 $termIds[$term->slug] = $term->id;
144 }
145
146 return array_values($termIds);
147 }
148
149 public static function getMentions($text, $spaceId = null)
150 {
151 // the mention may have . or _ or - in the username
152 preg_match_all('/@([a-zA-Z0-9_.-]+)/', $text, $matches);
153 $mentions = array_unique($matches[1]);
154
155 if (!$mentions) {
156 return null;
157 }
158
159 if ($spaceId) {
160 $xProfiles = XProfile::whereIn('username', $mentions)
161 ->whereHas('spaces', function ($query) use ($spaceId) {
162 $query->where('space_id', $spaceId);
163 })
164 ->get();
165 } else {
166 $xProfiles = XProfile::whereIn('username', $mentions)
167 ->get();
168 }
169
170 if ($xProfiles->isEmpty()) {
171 return null;
172 }
173
174 $userMentions = [];
175
176 $userIds = [];
177
178 foreach ($xProfiles as $xProfile) {
179 $userIds[] = $xProfile->user_id;
180 $html = '<a data-user_name="' . $xProfile->username . '" class="fcom_mention fcom_route" href="' . Helper::baseUrl('u/' . $xProfile->username . '/') . '">' . $xProfile->display_name . '</a>';
181 $userMentions['@' . $xProfile->username] = $html;
182 }
183
184 $users = User::whereIn('ID', $userIds)->get();
185
186 return [
187 'users' => $users,
188 'text' => strtr($text, $userMentions)
189 ];
190 }
191
192 public static function getLikedIdsByUserFeedId($feedId, $userId)
193 {
194 return Reaction::select('object_id')
195 ->where('object_type', 'comment')
196 ->where('parent_id', $feedId)
197 ->where('user_id', $userId)
198 ->get()
199 ->pluck('object_id')
200 ->toArray();
201 }
202
203 public static function castSurveyVote($newVoteIndexes, Feed $feed, $userId)
204 {
205 $surveyConfig = Arr::get($feed->meta, 'survey_config', []);
206
207 $slugs = array_map(function ($item) {
208 return $item['slug'];
209 }, $surveyConfig['options']);
210
211 $newVoteIndexes = array_filter(array_intersect($slugs, $newVoteIndexes));
212
213 $previousVotes = Reaction::where('type', 'survey_vote')
214 ->where('user_id', $userId)
215 ->where('object_id', $feed->id)
216 ->get();
217
218 $removedIndexes = [];
219 $alreadyIndexes = [];
220
221 foreach ($previousVotes as $previousVote) {
222 if (!in_array($previousVote->object_type, $newVoteIndexes)) {
223 // This vote need to be deleted
224 $removedIndexes[] = $previousVote->object_type;
225 $previousVote->delete();
226 } else {
227 $alreadyIndexes[] = $previousVote->object_type;
228 }
229 }
230
231 $newSyncIndexes = array_diff($newVoteIndexes, $alreadyIndexes);
232
233 foreach ($newSyncIndexes as $newSyncIndex) {
234 Reaction::create([
235 'user_id' => $userId,
236 'object_id' => $feed->id,
237 'type' => 'survey_vote',
238 'object_type' => $newSyncIndex
239 ]);
240 }
241
242 foreach ($surveyConfig['options'] as $index => $option) {
243 $slug = $option['slug'];
244
245 if (in_array($slug, $removedIndexes)) {
246 $newCount = (int)Arr::get($option, 'vote_counts', 0) - 1;
247 $option['vote_counts'] = $newCount > 0 ? $newCount : 0;
248 } else if (in_array($slug, $newSyncIndexes)) {
249 $newCount = (int)Arr::get($option, 'vote_counts', 0) + 1;
250 $option['vote_counts'] = $newCount > 0 ? $newCount : 0;
251 }
252
253 $surveyConfig['options'][$index] = $option;
254 }
255
256 $meta = $feed->meta;
257 $meta['survey_config'] = $surveyConfig;
258 $feed->meta = $meta;
259 $feed->save();
260
261 Utility::forgetCache('survey_cast_' . $feed->id . '_' . $userId);
262
263 return $feed;
264 }
265 }
266