PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.22
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.22
2.0.15 2.0.12 2.0.10 2.0.4 2.0.1 2.0.0 1.95.3 1.95.2 1.95 1.91.6 trunk 1.11 1.12 1.13 1.20 1.21 1.22 1.23 1.30 1.31 1.32 1.35 1.40 1.41 1.45 All 41 releases
fluent-boards / app / Services / CommentService.php

CommentService.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.22, at app/Services/CommentService.php

328 lines 10.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBoards\App\Services;
4
5 use FluentBoards\App\Models\Comment;
6 use FluentBoards\App\Models\CommentImage;
7 use FluentBoards\App\Models\Task;
8 use FluentBoards\App\Models\TaskActivity;
9 use FluentBoardsPro\App\Services\AttachmentService;
10 use FluentBoardsPro\App\Services\RemoteUrlParser;
11
12 class CommentService
13 {
14 public function getComments($id, $per_page, $filter)
15 {
16 $task = Task::findOrFail($id);
17
18 $commentsQuery = $task->comments()->whereNull('parent_id')
19 ->with(['user']);
20
21 if ($filter == 'oldest') {
22 $commentsQuery = $commentsQuery->oldest();
23 } else { // latest or newest
24 $commentsQuery = $commentsQuery->latest();
25 }
26 $comments = $commentsQuery->paginate($per_page);
27
28 foreach ($comments as $comment) {
29 $comment->replies = $this->getReplies($comment);
30 $comment->replies_count = count($comment->replies);
31 $comment->load('images');
32 }
33
34 return $comments;
35 }
36
37 public function getTotal($id)
38 {
39 $task = Task::findOrFail($id);
40 $totalComment = Comment::where('task_id', $task->id)
41 ->type('comment')
42 ->count();
43 $totalReply = Comment::where('task_id', $task->id)
44 ->type('reply')
45 ->count();
46
47 return $totalComment + $totalReply;
48 }
49
50 public function getReplies($comment)
51 {
52 $replies = Comment::where('parent_id', $comment->id)->with(['user'])->get();
53 return $replies;
54 }
55
56 public function create($commentData, $id)
57 {
58 $comment = Comment::create($commentData);
59 do_action('fluent_boards/comment_created', $comment);
60 return $comment;
61 }
62
63 private function startsWithAt($word) {
64 return strpos($word, '@') === 0;
65 }
66
67 public function processMentionAndLink($commentDescription, $mentionData)
68 {
69 // Splitting a string by either a space (" ") or a new line ("\n")
70 $lines = preg_split('/\R/', $commentDescription); // \R matches any kind of line break
71
72 $mentionedUsernames = [];
73 foreach ($mentionData as $mentionedId) {
74 $user = get_userdata($mentionedId);
75 $mentionedUsernames[$user->user_login] = ['user_id' => $user->ID, 'display_name' => $user->display_name];
76 }
77
78 foreach ($lines as &$line) {
79 $words = preg_split('/[ ]+/', $line);
80 foreach ($words as $index => $word) {
81 if ($this->startsWithAt($word)) {
82 $username = substr($word, 1);
83 if (array_key_exists($username, $mentionedUsernames)) {
84 $words[$index] = '<a class="fbs_mention" href="' . fluent_boards_page_url() . 'member/' . $mentionedUsernames[$username]['user_id'] . '/tasks">' . $mentionedUsernames[$username]['display_name'] . '</a>';
85 }
86 } elseif ($this->isValidUrl(wp_kses_post($word))) {
87 $words[$index] = '<a class="fbs_link" target="_blank" href="'. esc_url($word). '">'. esc_url($word). '</a>';
88 }
89 }
90 // Rejoin the words in this line
91 $line = implode(' ', $words);
92 }
93
94 // Rejoin the lines, adding back the new line character
95 return implode("\n", $lines);
96
97 }
98
99 private function isValidUrl($url) {
100 if (filter_var($url, FILTER_VALIDATE_URL) === false) {
101 return false;
102 }
103
104 // Additional validation with a regular expression
105 $regex = "/\b(?:https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|]/i";
106
107 return preg_match($regex, $url);
108 }
109
110 public function checkIfCommentHaveLinks($comment)
111 {
112 $lines = preg_split('/\R/', $comment); // Split by any kind of line break
113 $commentHasLinks = false;
114
115 foreach ($lines as &$line) {
116 $words = preg_split('/[ ]+/', $line); // Split by spaces within each line
117 foreach ($words as $index => $word) {
118 $cleanWord = wp_kses_post($word);
119 if ($this->isValidUrl($cleanWord)) {
120 $commentHasLinks = true;
121 $words[$index] = '<a class="fbs_link" target="_blank" href="' . esc_url($cleanWord) . '">' . esc_url($cleanWord) . '</a>';
122 }
123 }
124 // Rejoin words in this line
125 $line = implode(' ', $words);
126 }
127
128 if ($commentHasLinks) {
129 return implode("\n", $lines); // Rejoin lines with new lines preserved
130 } else {
131 return $comment; // Return original comment if no links were found
132 }
133 }
134
135 public function attachCommentImages($comment, $imageIds)
136 {
137
138 foreach ($imageIds as $imageId)
139 {
140 $attachmentObject = CommentImage::findOrFail($imageId);
141 if($attachmentObject) {
142 if ($attachmentObject->object_id == $comment->id && $attachmentObject->object_type == Constant::COMMENT_IMAGE) {
143 continue;
144 }
145 $attachmentObject->object_id = $comment->id;
146 $attachmentObject->object_type = Constant::COMMENT_IMAGE;
147 $attachmentObject->save();
148 }
149 }
150 //if(in_array("banana", $imageIds))
151 $commentImages = CommentImage::where('object_id', $comment->id)->where('object_type', Constant::COMMENT_IMAGE)->get();
152
153 foreach ($commentImages as $commentImage) {
154 if(!in_array($commentImage->id, $imageIds)) {
155 $commentImage->delete();
156 }
157 }
158 }
159
160 public function update($commentData, $comment_id, $mentionData)
161 {
162 $comment = Comment::findOrFail($comment_id);
163
164 if ($comment->created_by != get_current_user_id()) {
165 return false;
166 }
167
168 $allMentionedIds = array_merge($comment->settings['mentioned_id'] ?? [], $mentionData ?? []);
169
170 if ($allMentionedIds) {
171 $processedDescription = $this->processMentionAndLink($commentData['description'], $allMentionedIds);
172 } else {
173 $processedDescription = $this->checkIfCommentHaveLinks($commentData['description']);
174 }
175
176 $oldComment = $comment->description;
177 $comment->description = $processedDescription;
178
179 if($comment->settings != null)
180 {
181 $tempSettings = $comment->settings;
182 $tempSettings['raw_description'] = $commentData['description'];
183 $tempSettings['mentioned_id'] = $allMentionedIds;
184 $comment->settings = $tempSettings;
185 } else {
186 $comment->settings = [
187 'raw_description' => $commentData['raw_description'],
188 'mentioned_id' => $allMentionedIds
189 ];
190 }
191 $comment->save();
192
193 if(!$comment->parent_id) {
194 do_action('fluent_boards/comment_updated', $comment->task_id, $oldComment, $comment->description);
195 }
196
197 return $comment;
198 }
199
200 public function delete($comment_id)
201 {
202 $comment = Comment::findOrFail($comment_id);
203 $taskId = $comment->task_id;
204
205 if ($comment->created_by != get_current_user_id()) {
206 return false;
207 }
208
209 $commentDescription = strip_tags($comment->description);
210
211 $deleted = $comment->delete();
212
213 if ($deleted) {
214 $this->relatedReplyDelete($comment_id);
215 $comment->images()->delete();
216 $task = Task::findOrFail($taskId);
217 $task->comments_count = $task->comments_count - 1;
218 $task->save();
219 }
220
221 do_action('fluent_boards/comment_deleted', $taskId, $commentDescription);
222 }
223
224 public function relatedReplyDelete($comment_id)
225 {
226 $replies = Comment::where('parent_id', $comment_id)
227 ->type('reply')
228 ->get();
229 foreach ($replies as $reply) {
230 $reply->delete();
231 }
232 }
233
234 public function updateReply($replyData, $id)
235 {
236 $reply = Comment::findOrFail($id);
237
238 if ($reply->created_by != get_current_user_id()) {
239 return false;
240 }
241
242 $oldReply = $reply->description;
243 $reply->description = $replyData['description'];
244 $reply->save();
245 // do_action('fluent_boards/task_comment_updated', $comment->task_id, $oldComment, $comment->description);
246
247 return $reply;
248 }
249
250 public function deleteReply($id)
251 {
252 $reply = Comment::findOrFail($id);
253 // $taskId = $reply->task_id;
254
255 if ($reply->created_by != get_current_user_id()) {
256 return false;
257 }
258
259 $reply->delete();
260
261 // do_action('fluent_boards/comment_deleted', $taskId);
262 }
263
264 /**
265 * Adds a task attachment to the specified task.
266 *
267 * @param int $taskId The ID of the task to which the attachment is added.
268 * @param string $title The title of the attachment.
269 * @param string $url The URL of the attachment.
270 *
271 * @return Attachment The updated list of task attachments.
272 * @throws \Exception
273 */
274 public function createCommentImage($data, $boardId)
275 {
276 /*
277 * I will refactor this function later- within March 2024 Last Week
278 */
279 $initialDataData = [
280 'type' => 'url',
281 'url' => '',
282 'name' => '',
283 'size' => 0,
284 ];
285
286 $attachData = array_merge($initialDataData, $data);
287 $UrlMeta = [];
288 if($attachData['type'] == 'url') {
289 $UrlMeta = RemoteUrlParser::parse($attachData['url']);
290 }
291 $attachment = new CommentImage();
292 $attachment->object_id = 0;
293 $attachment->object_type = Constant::COMMENT_IMAGE;
294 $attachment->attachment_type = $attachData['type'];
295 $attachment->title = $this->setTitle($attachData['type'], $attachData['name'], $UrlMeta);
296 $attachment->file_path = $attachData['type'] != 'url' ? $attachData['file'] : null;
297 $attachment->full_url = esc_url($attachData['url']);
298 $attachment->file_size = $attachData['size'];
299 $attachment->settings = $attachData['type'] == 'url' ? [
300 'meta' => $UrlMeta
301 ] : '';
302 $attachment->driver = 'local';
303 $attachment->save();
304
305 $attachment->public_url = $this->createPublicUrl($attachment, $boardId);
306
307 return $attachment;
308 }
309
310 private function createPublicUrl($attachment, $boardId)
311 {
312 return add_query_arg([
313 'fbs' => 1,
314 'fbs_type' => 'public_url',
315 'fbs_bid' => $boardId,
316 'fbs_comment_image' => $attachment->file_hash
317 ], site_url('/index.php'));
318 }
319
320 private function setTitle($type, $title, $UrlMeta)
321 {
322 if($type != 'url') {
323 return sanitize_file_name($title);
324 }
325 return $title ?? $UrlMeta['title'] ?? '';
326 }
327 }
328