PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / trunk
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration vtrunk
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 / Hooks / Handlers / TaskHandler.php

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

271 lines 8.6 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 DateTimeImmutable;
6 use Exception;
7 use FluentBoards\App\App;
8 use FluentBoards\App\Models\Activity;
9 use FluentBoards\App\Models\Meta;
10 use FluentBoards\App\Models\TaskMeta;
11 use FluentBoards\App\Models\Task;
12 use FluentBoards\App\Models\User;
13 use FluentBoards\App\Services\Constant;
14 use FluentBoards\App\Services\NotificationService;
15 use FluentCrm\App\Models\Subscriber;
16 use FluentBoards\App\Models\Relation;
17 use FluentCrm\App\Services\ContactsQuery;
18 use FluentCrm\App\Services\PermissionManager as CRMPermissionManager;
19
20 class TaskHandler
21 {
22 private $fileHandler;
23
24 public function __construct(FileHandler $fileHandler)
25 {
26 $this->fileHandler = $fileHandler;
27 }
28 public function taskDeleted($task)
29 {
30 // Delete all activities and comments related to this task
31 Activity::where('object_id', $task->id)->where('object_type', Constant::ACTIVITY_TASK)->delete();
32 Meta::where('object_id', $task->id)->where('object_type', Constant::REPEAT_TASK_META)->delete();
33 }
34
35 public function searchAssignees($options, $search, $includedIds)
36 {
37 $users = get_users([
38 'number' => 20,
39 'search' => $search,
40 ]);
41
42 $formattedUsers = [];
43
44 $pushedIds = [];
45
46 foreach ($users as $user) {
47 $pushedIds[] = $user->ID;
48
49 $formattedUsers[] = [
50 'id' => $user->ID,
51 'title' => $user->display_name . ' (' . $user->user_email . ')',
52 'photo' => get_avatar_url($user->user_email),
53 'left_side_value' => $user->display_name,
54 'right_side_value' => $user->user_email,
55 ];
56 }
57
58 if (!$includedIds) {
59 return $formattedUsers;
60 }
61
62 if (!is_array($includedIds)) {
63 $includedIds = [$includedIds];
64 }
65
66 $includedIds = array_diff(array_map('intval', $includedIds), $pushedIds);
67
68 if ($includedIds) {
69 $users = get_users([
70 'include' => $includedIds,
71 ]);
72
73 foreach ($users as $user) {
74 $formattedUsers[] = [
75 'id' => $user->ID,
76 'title' => $user->display_name . ' (' . $user->user_email . ')',
77 'photo' => get_avatar_url($user->user_email),
78 'left_side_value' => $user->display_name,
79 'right_side_value' => $user->user_email,
80 ];
81 }
82 }
83
84 return $formattedUsers;
85 }
86
87 public function searchNonBoardWordpressUsers()
88 {
89 $superAdmin = Relation::select('user_id')->distinct()->pluck('user_id');
90 $users = User::whereDoesntHave('boards')->whereNotIn('ID', $superAdmin)->get();
91
92 $formattedUsers = [];
93
94 foreach ($users as $user) {
95 $formattedUsers[] = [
96 'id' => $user->ID,
97 'photo' => $user->photo,
98 'title' => $user->display_name . ' (' . $user->user_email . ')',
99 'left_side_value' => $user->display_name,
100 'right_side_value' => $user->user_email,
101 ];
102 }
103
104 return $formattedUsers;
105 }
106
107 public function searchContact($options, $search, $includedIds)
108 {
109 if (!defined('FLUENTCRM')) {
110 return [];
111 }
112
113 // check if the use has permission to access contacts
114 $contactPermission = CRMPermissionManager::currentUserCan('fcrm_read_contacts');
115 if(!$contactPermission) {
116 return [];
117 }
118
119 $contactsQuery = new ContactsQuery([
120 'search' => $search,
121 'with' => [],
122 'limit' => 20,
123 'offset' => 0,
124 ]);
125 $subscribers = $contactsQuery->get();
126
127 $formattedSubscribers = [];
128
129 $pushedIs = [];
130 foreach ($subscribers as $subscriber) {
131 $pushedIs[] = $subscriber->id;
132 $formattedSubscribers[] = [
133 'id' => $subscriber->id,
134 'title' => $subscriber->full_name . ' (' . $subscriber->email . ')',
135 'photo' => $subscriber->photo,
136 'name' => $subscriber->full_name,
137 'email' => $subscriber->email,
138 ];
139 }
140
141 if (!is_array($includedIds)) {
142 $includedIds = [$includedIds];
143 }
144
145 if (!$includedIds) {
146 return $formattedSubscribers;
147 }
148
149 $remainingIds = array_diff($includedIds, $pushedIs);
150
151 if ($remainingIds) {
152 $remainingContacts = Subscriber::whereIn('id', $remainingIds)->get();
153 foreach ($remainingContacts as $subscriber) {
154 $formattedSubscribers[] = [
155 'id' => $subscriber->id,
156 'title' => $subscriber->full_name . ' (' . $subscriber->email . ')',
157 'photo' => $subscriber->photo,
158 'name' => $subscriber->full_name,
159 'email' => $subscriber->email,
160 ];
161 }
162 }
163
164 return $formattedSubscribers;
165 }
166
167
168
169 /**
170 * Delete an attachment file only after the owning database transaction commits.
171 *
172 * @param mixed $deletedAttachment
173 * @param int|null $boardId
174 * @return void
175 */
176 public function taskAttachmentDeleted($deletedAttachment, $boardId = null)
177 {
178 if ($deletedAttachment->attachment_type === 'url') {
179 return;
180 }
181
182 if ($boardId === null) {
183 $task = Task::find(absint($deletedAttachment->object_id));
184 $boardId = $task ? $task->board_id : null;
185 }
186
187 $dbInstance = App::getInstance('db');
188
189 if ($dbInstance->inTransaction()) {
190 $attachmentSnapshot = clone $deletedAttachment;
191 $dbInstance->afterCommit(function () use ($attachmentSnapshot, $boardId) {
192 try {
193 $this->fileHandler->deleteAttachmentFile($attachmentSnapshot, $boardId);
194 } catch (\Throwable $e) {
195 error_log(sprintf(
196 'FluentBoards: Failed to delete committed task attachment file: %s',
197 sanitize_text_field($e->getMessage())
198 ));
199 }
200 });
201
202 return;
203 }
204
205 try {
206 $this->fileHandler->deleteAttachmentFile($deletedAttachment, $boardId);
207 } catch (Exception $e) {
208 wp_send_json_error($e->getMessage());
209 }
210 }
211
212 /**
213 * Auto-watch newly created tasks when the board preference allows it.
214 */
215 public function onTaskCreated($task)
216 {
217 $userId = get_current_user_id();
218
219 if (!$userId) {
220 return;
221 }
222
223 if ($this->shouldAutoWatchForBoard($task->board_id, Constant::GLOBAL_EMAIL_NOTIFICATION_CREATING_TASK)) {
224 $task->watchers()->syncWithoutDetaching([$userId => ['object_type' => Constant::OBJECT_TYPE_USER_TASK_WATCH]]);
225 }
226 }
227
228 /**
229 * Auto-watch commented tasks when the board preference allows it.
230 */
231 public function onCommentCreated($comment)
232 {
233 $task = $comment->task;
234 $userId = get_current_user_id();
235
236 if (!$userId) {
237 return;
238 }
239
240 if ($this->shouldAutoWatchForBoard($task->board_id, Constant::GLOBAL_EMAIL_NOTIFICATION_COMMENTING)) {
241 $task->watchers()->syncWithoutDetaching([$userId => ['object_type' => Constant::OBJECT_TYPE_USER_TASK_WATCH]]);
242 }
243 }
244
245 /**
246 * Auto-watch assigned tasks when the board preference allows it.
247 */
248 public function onAssignAnotherUser($task, $assigneeId)
249 {
250 if ($this->shouldAutoWatchForBoard($task->board_id, Constant::GLOBAL_EMAIL_NOTIFICATION_ASSIGNING)) {
251 $task->watchers()->syncWithoutDetaching([$assigneeId => ['object_type' => Constant::OBJECT_TYPE_USER_TASK_WATCH]]);
252 }
253 }
254
255 /**
256 * Determine auto-watch behavior from the current user's board preference.
257 */
258 private function shouldAutoWatchForBoard($boardId, $preferenceKey)
259 {
260 return (new NotificationService())->isBoardAutoWatchEnabled($boardId, get_current_user_id(), $preferenceKey);
261 }
262
263 public function taskCloned($originalTask, $clonedTask)
264 {
265 Activity::where('object_id', $clonedTask->id)
266 ->where('object_type', Constant::ACTIVITY_TASK)
267 ->delete();
268 do_action('fluent_boards/task_cloned_activity', $originalTask, $clonedTask);
269 }
270 }
271