PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.0.12
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.0.12
2.1.0 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 All 42 releases
fluent-boards / app / Hooks / Handlers / ActivityHandler.php

ActivityHandler.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 2.0.12, at app/Hooks/Handlers/ActivityHandler.php

473 lines 16.0 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\Hooks\Handlers;
4
5 use FluentBoards\App\Models\Board;
6 use FluentBoards\App\Models\Stage;
7 use FluentBoards\App\Models\Task;
8 use FluentBoards\App\Models\User;
9 use FluentBoards\App\Services\Constant;
10 use FluentCrm\App\Models\Subscriber;
11 use FluentBoards\App\Models\Comment;
12 use FluentBoards\App\Services\Helper;
13
14 class ActivityHandler
15 {
16 public function createLogActivity($taskId, $action, $column, $oldValue = null, $newValue = null, $description = null, $settings = null )
17 {
18 $data = [
19 'object_type' => Constant::ACTIVITY_TASK,
20 'object_id' => $taskId,
21 'action' => $action, // action type: changed, updated, added, removed
22 'column' => $column,
23 'old_value' => $oldValue,
24 'new_value' => $newValue,
25 'description' => $description,
26 'settings' => $settings
27 ];
28 $userId = get_current_user_id();
29 if($userId == 0){
30 $task = Task::find($taskId);
31 $data['created_by'] = $task->created_by;
32 }
33
34 Helper::createActivity($data);
35 }
36 public function logMoveTaskToAnotherBoardActivity($task, $oldTask)
37 {
38 $old = $this->getBoardTitleById($oldTask->board_id);
39 $new = $this->getBoardTitleById($task->board_id);
40 $this->createLogActivity( $task->id,'changed', 'board', $old, $new);
41 }
42
43 public function logAssigneeAddedActivity($task, $newAssigneeId)
44 {
45 $currentUserId = get_current_user_id();
46 if($newAssigneeId == $currentUserId) {
47 $this->taskAssigneeJoin($task->id);
48 return;
49 }
50 $user = User::findOrFail($newAssigneeId);
51 $currentUserId = get_current_user_id();
52 if($currentUserId === $user->ID){
53 $this->taskAssigneeJoin($task->id);
54 } elseif ($user) {
55 $this->createLogActivity($task->id, 'added', 'assignee', null, $user->display_name);
56 }
57 }
58
59 public function logAssigneeRemovedActivity($task, $newAssigneeId)
60 {
61 $currentUserId = get_current_user_id();
62 if($newAssigneeId == $currentUserId) {
63 $this->taskAssigneeLeave($task->id);
64 return;
65 }
66 $user = User::findOrFail($newAssigneeId);
67 $currentUserId = get_current_user_id();
68 if($currentUserId === $user->ID){
69 $this->taskAssigneeLeave($task->id);
70 } else if($user) {
71 $this->createLogActivity($task->id, 'removed', 'assignee', null, $user->display_name);
72 }
73 }
74
75 public function logTaskCreationActivity($task)
76 {
77 $this->createLogActivity( $task->id,'created', 'task', null, $task->title, null );
78 }
79
80 public function logTaskContentUpdatedActivity($task, $col, $oldTask = null)
81 {
82 // Description autosaves are intentionally excluded to avoid flooding the activity feed.
83 if ($col === 'description') {
84 return;
85 }
86
87 $action = 'updated';
88 if($task->parent_id){
89 $this->createLogActivity( $task->parent_id, $action, 'subtask', $oldTask->title, $task->title );
90 }else{
91 $this->createLogActivity( $task->id, $action, $col, $oldTask->title, $task->title );
92 }
93 }
94
95 public function taskLabelActivity($task, $label, $action)
96 {
97 $column = 'label';
98 $settings = [
99 'bg_color' => $label->bg_color,
100 'color' => $label->color,
101 'title' => $label->title,
102 ];
103
104 $this->createLogActivity($task->id, $action, $column, null, null, null, $settings);
105 }
106
107 public function logDueDateActivity($task, $oldDate)
108 {
109 $column = 'Due Date';
110 $action = 'changed';
111
112 if($oldDate){
113 $new = gmdate("F j, Y, g:i a", strtotime($task->due_at));
114 $old = gmdate("F j, Y, g:i a", strtotime($oldDate));
115 if($new == $old)
116 return;
117 }
118 $newDueDate = $task->due_at;
119 $new = null;
120 if ($newDueDate) {
121 $new = gmdate("F j, Y, g:i a", strtotime($newDueDate));
122 if(str_contains($new, '12:00 am')){
123 $new = gmdate("F j, Y", strtotime($newDueDate));
124 }
125 }
126 $old = null;
127 if(!$oldDate){
128 $action = 'added';
129 }else{
130 $old = gmdate("F j, Y, g:i a", strtotime($oldDate));
131 if(str_contains($old, '12:00 am')){
132 $old = gmdate("F j, Y", strtotime($oldDate));
133 }
134 }
135
136 $this->createLogActivity($task->id, $action, $column, $old, $new);
137 }
138 public function logDueDateRemoveActivity($task)
139 {
140 $this->createLogActivity( $task->id, 'removed', 'Due Date', null);
141 }
142
143 public function logStartDateActivity($task, $oldDate)
144 {
145 $column = 'Start Date';
146 $action = 'changed';
147
148 if($oldDate){
149 $new = gmdate("F j, Y", strtotime($task->started_at));
150 $old = gmdate("F j, Y", strtotime($oldDate));
151 if($new == $old)
152 return;
153 }
154 $newStartDate = $task->started_at;
155 $new = null;
156 if ($newStartDate) {
157 $new = gmdate("F j, Y", strtotime($newStartDate));
158 }
159 $old = null;
160 if(!$oldDate){
161 $action = 'added';
162 }else{
163 $old = gmdate("F j, Y", strtotime($oldDate));
164 }
165
166 $this->createLogActivity($task->id, $action, $column, $old, $new);
167 }
168
169
170 public function logPriorityChangeActivity($task, $old)
171 {
172 $new = $task->priority;
173 $this->createLogActivity($task->id, 'changed', 'priority', $old, $new);
174 }
175
176 public function logCommentCreateActivity($comment)
177 {
178 if($comment->parent_id) {
179 // dd($comment);
180 $parent = Comment::findOrFail($comment->parent_id);
181 $parentDescription = $parent->description;
182 $this->createLogActivity($comment->task_id, 'added', 'a reply');
183 }else{
184 $commentPlainText = wp_strip_all_tags($comment->description);
185 $this->createLogActivity($comment->task_id, 'added', 'comment', null, $commentPlainText, null);
186 }
187 }
188 public function logCommentUpdateActivity($comment, $oldComment)
189 {
190 $taskId = $comment->task_id;
191 $newComment = $comment->settings['raw_description'] ?? $comment->description;
192
193 $this->createLogActivity($taskId, 'updated', 'comment', $oldComment, $newComment);
194 }
195 public function logCommentDeleteActivity($comment)
196 {
197 $commentDescription = wp_strip_all_tags($comment->settings['raw_description'] ?? $comment->description );
198 $taskId = $comment->task_id;
199
200 $this->createLogActivity($taskId, 'removed', 'comment', null, $commentDescription, null);
201 }
202
203 public function logSubtaskAddedActivity($parentTask, $subTask)
204 {
205 $this->createLogActivity($parentTask->id, 'added', 'subtask', null, $subTask->title);
206 }
207
208 public function logSubtaskCloneActivity($parentTask, $subTask)
209 {
210 $this->createLogActivity($parentTask->id, 'cloned', 'subtask', null, $subTask->title);
211 }
212 public function logSubtaskGroupAddedActivity($task_id, $subTaskGroup)
213 {
214 $this->createLogActivity($task_id, 'added', 'subtask group', null, $subTaskGroup->value);
215 }
216
217 public function logSubtaskDeletedActivity($id, $subTaskTitle)
218 {
219 $this->createLogActivity($id, 'removed', 'subtask', null, $subTaskTitle);
220 }
221
222 public function logSubtaskGroupDeletedActivity($task_id, $subTaskGroup)
223 {
224 $this->createLogActivity($task_id, 'removed', 'subtask group', null, $subTaskGroup->value);
225 }
226 public function logSubtaskGroupTitleUpdatedActivity($oldTitle, $group)
227 {
228 $this->createLogActivity($group->task_id, 'changed', 'subtask group title', $oldTitle, $group->value);
229 }
230 public function logTaskCompletedOrReopenActivity($task, $status)
231 {
232 if($status == 'closed'){
233 if($task->parent_id){
234 $this->createLogActivity($task->parent_id, 'closed', 'subtask', $task->title);
235 }else{
236 $this->createLogActivity($task->id, 'closed', 'task', $task->title);
237 }
238 }else{
239 if($task->parent_id){
240 $this->createLogActivity($task->parent_id, 'reopened', 'subtask', $task->title);
241 }else{
242 $this->createLogActivity($task->id, 'reopened', 'task', $task->title);
243 }
244 }
245 }
246
247 public function logTaskStageUpdatedActivity($task, $oldStageId, $stageContext = null)
248 {
249 $oldStage = $stageContext['source'] ?? null;
250 $newStage = $stageContext['target'] ?? null;
251
252 if (!$oldStage instanceof Stage || !$newStage instanceof Stage) {
253 $oldStage = Stage::findOrFail($oldStageId);
254 $newStage = Stage::findOrFail($task->stage_id);
255 }
256
257 if($oldStage && $newStage){
258 $this->createLogActivity($task->id, 'changed', 'stage', $oldStage->title, $newStage->title);
259 }
260 }
261
262 public function associateUserAddChangeRemoveActivity($oldAssociateId, $newAssociateId, $taskId)
263 {
264 $subsciber = new Subscriber();
265 $oldAssociateUser = $subsciber->find($oldAssociateId);
266 $newAssociateUser = $subsciber->find($newAssociateId);
267 $action = 'added';
268 $column = 'the associate email';
269 $old = null; $new = null;
270
271 if ($oldAssociateUser && $newAssociateUser) {
272 $old = $oldAssociateUser->email;
273 $new = $newAssociateUser->email;
274 $action = 'changed';
275 } elseif ($oldAssociateUser && !$newAssociateUser) {
276 $old = $oldAssociateUser->email;
277 $action = 'removed';
278 } else {
279 $new = $newAssociateUser->email;
280 }
281 $this->createLogActivity($taskId, $action, $column, $old, $new);
282 }
283
284 public function taskAssigneeJoin($id)
285 {
286 $this->createLogActivity($id, 'joined', 'task', null, null);
287 }
288
289 public function taskAssigneeLeave($id)
290 {
291 $this->createLogActivity($id, 'left', 'task', null, null);
292 }
293
294 public function labelManageForTaskActivity($id, $action)
295 {
296 $this->createLogActivity($id, $action, 'label', null, null);
297 }
298
299 private function getBoardTitleById($boardId)
300 {
301 return Board::findOrFail($boardId)->title; // it can be further optimized , we may limit multiple query here.
302 }
303
304 public function taskAddedFromFluentForms($task)
305 {
306 $taskActivity = [
307 'object_type' => Constant::ACTIVITY_TASK,
308 'object_id' => $task->id,
309 'action' => 'created', // action type: changed, updated, added, removed
310 'column' => 'task',
311 'old_value' => $task->title,
312 'new_value' => null,
313 'description' => " from Fluent Forms",
314 ];
315
316 $board = Board::find($task->board_id);
317 $settings = $board->settings ?? [];
318
319 if (isset($settings['tasks_count'])) {
320 if ($settings['tasks_count'] != 0) $settings['tasks_count'] += 1;
321 } else {
322 $settings['tasks_count'] = 1;
323 }
324 $board->settings = $settings;
325 $board->save();
326 $taskStage = $task->stage;
327 $settings = ['task_id' => $task->id];
328
329 $boardActivity = [
330 'object_type' => Constant::ACTIVITY_BOARD,
331 'object_id' => $task->board_id,
332 'action' => 'created', // action type: changed, updated, added, removed, created
333 'column' => 'task',
334 'old_value' => null,
335 'new_value' => $task->title,
336 'description' => 'on stage '. $taskStage->title . ' from Fluent Forms ',
337 'settings' => $settings
338 ];
339 if (intval($task->created_by) > 0) {
340 $taskActivity['created_by'] = intval($task->created_by);
341 $boardActivity['created_by'] = intval($task->created_by);
342
343 } else {
344 $taskActivity['description'] .= ' by '. $task['settings']['author']['name'] . " (" . $task['settings']['author']['email'] . ")";
345 $boardActivity['description'] .= ' by '. $task['settings']['author']['name'] . " (" . $task['settings']['author']['email'] . ")";
346 }
347 Helper::createActivity($taskActivity);
348 Helper::createActivity($boardActivity);
349
350 }
351 public function taskAttachmentAdded($attachment)
352 {
353 $this->createLogActivity($attachment->object_id , 'added', 'attachment', null, strlen($attachment->title) > 0 ? $attachment->title : $attachment->full_url);
354 }
355 public function taskAttachmentDeleted($attachment)
356 {
357 $this->createLogActivity($attachment->object_id , 'deleted', 'attachment', null, strlen($attachment->title) > 0 ? $attachment->title : $attachment->full_url);
358 }
359
360 public function taskArchived($task)
361 {
362 if(!$task->archived_at){
363 $this->createLogActivity($task->id, 'restored', 'task', $task->title);
364 }else{
365 $this->createLogActivity($task->id, 'archived', 'task', $task->title);
366 }
367 }
368
369 public function logRepeatTaskCreatedActivity($newTask, $parentTask)
370 {
371 $this->createLogActivity(
372 $newTask->id,
373 'created',
374 'repeat task',
375 $newTask->title,
376 $parentTask->title,
377 null,
378 $parentTask
379 );
380 }
381
382 public function logRepeatTaskSet($newTask)
383 {
384 $this->createLogActivity(
385 $newTask->id,
386 'set',
387 'Repeat Task',
388 null,
389 null,
390 );
391 }
392
393 public function logRepeatTaskUpdated($newTask)
394 {
395 $this->createLogActivity(
396 $newTask->id,
397 'updated',
398 'Repeat Task',
399 null,
400 null
401 );
402 }
403 public function taskMovedFromBoard($task, $oldBoard, $newBoard)
404 {
405 $this->createLogActivity($task->id, 'moved', 'board', $oldBoard->title, $newBoard->title);
406 }
407
408 public function logCustomFieldActivity($taskId, $customField, $oldValue, $newValue, $isNewCustomField)
409 {
410 // Format values for display in activity
411 $displayNewValue = $this->formatValueForDisplay($newValue, $customField->settings['custom_field_type']);
412
413 $action = 'changed';
414 $column = $customField->title;
415
416 // Ensure we have a value to display
417 if (empty($displayNewValue)) {
418 $displayNewValue = 'empty';
419 }
420
421 // Handle old value display logic
422 $displayOldValue = null;
423 if (!$isNewCustomField && $oldValue !== null && $oldValue !== '') {
424 // Format old value for display if it exists
425 $displayOldValue = $this->formatValueForDisplay($oldValue, $customField->settings['custom_field_type']);
426 }
427
428 $settings = [
429 'custom_field_id' => $customField->id,
430 'custom_field_title' => $customField->title,
431 'custom_field_type' => $customField->settings['custom_field_type']
432 ];
433
434 $this->createLogActivity($taskId, $action, $column, $displayOldValue, $displayNewValue, null, $settings);
435 }
436
437 /**
438 * Format custom field value for display in activity logs
439 */
440 private function formatValueForDisplay($value, $fieldType)
441 {
442 if ($value === null || $value === '') {
443 return 'empty';
444 }
445
446 switch ($fieldType) {
447 case 'checkbox':
448 return $value ? 'checked' : 'unchecked';
449 case 'date':
450 // If it's already formatted as Y-m-d H:i:s, convert to readable format
451 if (preg_match('/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/', $value)) {
452 return gmdate('M j, Y g:i A', strtotime($value));
453 }
454 return $value;
455 case 'select':
456 case 'text':
457 case 'textarea':
458 case 'number':
459 default:
460 return (string) $value;
461 }
462 }
463 public function taskCloned($originalTask, $clonedTask)
464 {
465 $this->createLogActivity(
466 $clonedTask->id,
467 'cloned',
468 'task',
469 'from ' . $originalTask->title,
470 );
471 }
472 }
473