PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.23
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.23
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 / Api / Classes / Tasks.php

Tasks.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.23, at app/Api/Classes/Tasks.php

522 lines 14.1 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\Api\Classes;
4
5 defined('ABSPATH') || exit;
6
7 use Exception;
8 use FluentBoards\App\Models\Label;
9 use FluentBoards\App\Models\Stage;
10 use FluentBoards\App\Models\Task;
11 use FluentBoards\App\Models\Board;
12 use FluentBoards\App\Services\BoardService;
13 use FluentBoards\App\Services\Helper;
14 use FluentBoards\App\Services\PermissionManager;
15 use FluentBoards\App\Services\TaskService;
16 use FluentBoardsPro\App\Models\TaskAttachment;
17 use FluentBoardsPro\App\Services\AttachmentService;
18 use FluentBoards\App\Services\Constant;
19
20
21
22 /**
23 * Contacts Class - PHP APi Wrapper
24 *
25 * Contacts API Wrapper Class that can be used as <code>FluentBoardsApi('tasks')</code> to get the class instance
26 *
27 * @package FluentBoards\App\Api\Classes
28 * @namespace FluentBoards\App\Api\Classes
29 *
30 * @version 1.0.0
31 */
32 class Tasks
33 {
34 private $instance = null;
35
36 private $allowedInstanceMethods = [
37 'all',
38 'get',
39 'find',
40 'first',
41 'paginate'
42 ];
43
44 public function __construct(Task $instance)
45 {
46 $this->instance = $instance;
47 }
48
49 /**
50 * Get Tasks by board
51 *
52 * Use:
53 * <code>FluentBoardsApi('tasks')->getTasksByBoard();</code>
54 *
55 * @param string|int $board_id
56 * @param array $with
57 * @return array|Task Model
58 */
59 public function getTasksByBoard($board_id, $with = [])
60 {
61 if (!$board_id) {
62 return [];
63 }
64
65 //checking if current user has access to board
66 if (!PermissionManager::userHasPermission($board_id)) {
67 return false;
68 }
69
70 $query = Task::query()
71 ->where('board_id', $board_id)
72 ->whereNull('parent_id')
73 ->whereNull('archived_at')
74 ->orderBy('due_at', 'ASC');
75
76 if (!empty($with)) {
77 $query->with($with);
78 }
79
80 $tasks = $query->get();
81
82 $tasks->transform(function ($task) {
83 $task->isOverdue = $task->isOverdue();
84 $task->isUpcoming = $task->upcoming();
85 $task->contact = Helper::crm_contact($task->crm_contact_id);
86 $task->is_watching = $task->isWatching();
87 return $task;
88 });
89
90 return $tasks;
91 }
92
93
94 /**
95 * Get Task by id
96 *
97 * Use:
98 * <code>FluentBoardsApi('tasks')->getTask($id);</code>
99 *
100 * @param int|string $id Task id
101 * @return false|Task Model
102 */
103 public function getTask($id)
104 {
105 if (!empty($id)) {
106 $task = Task::where('id', $id)->first();
107
108 //checking if current user has access to board
109 if (!PermissionManager::userHasPermission($task->board_id)) {
110 return false;
111 }
112 return $task;
113 }
114 return false;
115 }
116
117
118 /**
119 * Get Task Created by
120 *
121 * Use:
122 * <code>FluentBoardsApi('tasks')->getTasksCreatedBy($userId);</code>
123 *
124 * @param int|string $userId Task id
125 * @param array $with
126 * @return false|Task Model
127 */
128 public function getTasksCreatedBy($userId, $with = [])
129 {
130 if (!empty($userId)) {
131 $query = Task::where('created_by', $userId);
132
133 if (!empty($with)) {
134 $query->with($with);
135 }
136
137 $tasks = $query->get();
138
139 $permittedTasks = [];
140
141 foreach ($tasks as $task) {
142 //checking if current user has access to board
143 if (PermissionManager::userHasPermission($task->board_id)) {
144 $permittedTasks[] = $task;
145 }
146 }
147
148 return $permittedTasks;
149 }
150 return false;
151 }
152
153
154 public function create($data)
155 {
156 if (empty($data)) {
157 return false;
158 }
159
160 if (empty($data['title']) || empty($data['board_id']) || empty($data['stage_id'])) {
161 return false;
162 }
163
164 $taskData = Helper::sanitizeTask($data);
165
166 if(!empty($taskData['priority']) && !in_array($taskData['priority'], ['low', 'medium', 'high'])) {
167 $taskData['priority'] = 'low';
168 }
169 if(!empty($taskData['status']) && !in_array($taskData['status'], ['open', 'closed'])) {
170 $taskData['status'] = 'open';
171 }
172 if(!empty($data['crm_contact_id'])) {
173 $taskData['crm_contact_id'] = $data['crm_contact_id'];
174 }
175
176 if(!empty($data['contact_email']) && empty($data['crm_contact_id'])) {
177 // Find first if the contact exists
178 $contact = FluentCrmApi('contacts')->creteOrUpdate([
179 'email' => $data['contact_email'],
180 'first_name' => $data['contact_first_name'],
181 'last_name' => $data['contact_last_name'],
182 'status' => 'subscribed'
183 ]);
184 $taskData['crm_contact_id'] = $contact->id;
185 }
186
187 if(!empty($data['assignees']) && is_array($data['assignees'])) {
188 // check if the assignees are valid, they have to be wp user ids
189 $users = get_users(['include' => $data['assignees']]);
190 $taskData['assignees'] = array_map(function($user) {
191 return $user->ID;
192 }, $users);
193 // after successful task creation we have to add them as board members
194 }
195
196 if(!empty($data['labels']) && is_array($data['labels'])) {
197 $labelIds = [];
198 // check if the labels are valid, they have to be label ids
199 foreach ($data['labels'] as $label) {
200 if(is_numeric($label)) {
201 $labelModel = Label::where('id', $label)->where('board_id', $data['board_id'])->first();
202 if($labelModel) {
203 $labelId = $labelModel->id;
204 $labelIds[] = $labelId;
205 }
206 continue;
207 }
208 if(is_string($label)) {
209 $labelModel = Label::where('board_id', $data['board_id'])
210 ->where(function($query) use ($label) {
211 $query->where('title', $label)
212 ->orWhere('slug', $label);
213 })->first();
214 if($labelModel) {
215 $labelId = $labelModel->id;
216 $labelIds[] = $labelId;
217 }
218 }
219 }
220 $taskData['labels'] = $labelIds;
221 // we have to map the labels after task creation
222 }
223
224 $task = $this->instance->createTask($taskData);
225 // push assignees to board Members
226 $boardService = new BoardService();
227 if(!empty($taskData['assignees'])) {
228 foreach ($taskData['assignees'] as $assigneeId) {
229 $boardService->addMembersInBoard($data['board_id'], $assigneeId);
230 }
231 }
232
233 return $task;
234 }
235
236
237 public function createTask($data = [])
238 {
239 $defaultData = [
240 'title',
241 'board_id',
242 'stage_id',
243 'parent_id',
244 'status', // open | closed
245 'priority', // low | medium | high
246 'source',
247 'source_id',
248 'description',
249 'due_at',
250 'crm_contact_id',
251 // <or>
252 'contact_email',
253 'contact_first_name', // this is the full name
254 'contact_last_name', // this is the full name
255 'contact_status', // default subscribed
256 // </or>
257 'assignees', // WP User IDs / WP User Emails as an array
258 'labels', // array of label ids or titles [1, 'New']
259 ];
260
261 }
262
263 public function addAssignees($task_id, $assignees = [])
264 {
265 if(empty($task_id) || empty($assignees)) {
266 return false;
267 }
268
269 $task = Task::where('id', $task_id)->first();
270 $board = Board::findOrFail($task->board_id);
271
272 if(!PermissionManager::isBoardManager($task->board_id))
273 {
274 if(!PermissionManager::isAdmin())
275 {
276 return false;
277 }
278 }
279
280 if(!$task) {
281 return false;
282 }
283
284 $boardUsersIds = $board->users->pluck('ID')->toArray();
285
286 foreach($assignees as $assignee)
287 {
288 if(in_array($assignee, $boardUsersIds)) { //check if user is a board member
289 $task->assignees()
290 ->syncWithoutDetaching([
291 $assignee => [
292 'object_type' => Constant::OBJECT_TYPE_TASK_ASSIGNEE
293 ]
294 ]);
295 $task->watchers()
296 ->syncWithoutDetaching([
297 $assignee => [
298 'object_type' => Constant::OBJECT_TYPE_USER_TASK_WATCH
299 ]
300 ]);
301 }
302 }
303
304 return true;
305 }
306
307 public function removeAssignees($task_id, $assignees = [])
308 {
309 if(empty($task_id) || empty($assignees)) {
310 return false;
311 }
312
313 $task = Task::where('id', $task_id)->first();
314 if(!$task) {
315 return false;
316 }
317
318 if(!PermissionManager::isBoardManager($task->board_id))
319 {
320 if(!PermissionManager::isAdmin())
321 {
322 return false;
323 }
324 }
325
326 $task->assignees()->detach($assignees);
327
328 $task->watchers()->detach($assignees);
329
330 return true;
331 }
332
333
334
335 public function attachLabels($taskId, $labelIds = [])
336 {
337 // do code here
338 if(!$taskId)
339 {
340 return false;
341 }
342
343 $task = Task::findOrFail($taskId);
344 $board = Board::findOrFail($task->board_id);
345
346 if(!$task)
347 {
348 return false;
349 }
350
351 //checking if current user has access to board
352 if (!PermissionManager::userHasPermission($task->board_id)) {
353 return false;
354 }
355
356 $boardlabelIds = $board->labels->pluck('id')->toArray();
357
358 foreach ($labelIds as $labelId)
359 {
360 if(in_array($labelId, $boardlabelIds)) { //check if label is a board label
361 $task->labels()
362 ->syncWithoutDetaching([
363 $labelId => [
364 'object_type' => Constant::OBJECT_TYPE_TASK_LABEL
365 ]
366 ]);
367 }
368 }
369
370 return true;
371
372 }
373
374 public function removeLabels($taskId, $labelIds = [])
375 {
376 // do code here
377 if(!$taskId)
378 {
379 return false;
380 }
381
382 $task = Task::findOrFail($taskId);
383
384 if(!$task)
385 {
386 return false;
387 }
388
389 //checking if current user has access to board
390 if (!PermissionManager::userHasPermission($task->board_id)) {
391 return false;
392 }
393
394 $task->labels()->detach($labelIds);
395
396 return true;
397 }
398
399 /*
400 * Change the stage of a task
401 * @param int $taskId
402 * @param int $stageId - the new stage id
403 * @return Task
404 */
405 public function changeStage($task, $stageId)
406 {
407 // param can be either task object or task Id
408 if(is_numeric($task)) {
409 $task = Task::where('id', $task)->first();
410 }
411
412 if(!$task) {
413 return false;
414 }
415
416 //checking if current user has access to board
417 if (!PermissionManager::userHasPermission($task->board_id)) {
418 return false;
419 }
420
421 $stage = Stage::findOrFail($stageId);
422
423 if($stage->board_id != $task->board_id)
424 {
425 return false;
426 }
427
428 $taskService = new TaskService();
429 $position = $taskService->getLastPositionOfTasks($stageId);
430
431 $task->stage_id = $stageId;
432 $task->position = $position;
433 $task->save();
434
435 return $task;
436 }
437
438 public function updateProperty($taskId, $property, $value)
439 {
440 $taskService = new TaskService();
441 $task = Task::where('id', $taskId)->first();
442
443 if(!$task) {
444 return false;
445 }
446
447 $allowedColumns = ['title', 'description', 'due_at', 'priority', 'status', 'source', 'source_id', 'crm_contact_id'];
448
449 if(!in_array($property, $allowedColumns)) {
450 return false;
451 }
452
453 $taskService->updateTaskProperty($task, $property, $value);
454
455 return $task;
456
457 }
458
459 /**
460 * Create a task attachment
461 * @param int $boardId
462 * @param int $taskId
463 * @param array $data - ['title', 'url'] // url is required
464 * @throws Exception
465 */
466 public function createTaskAttachment(int $boardId, int $taskId, array $data = [])
467 {
468 // check if the user has permission to add attachment
469 if (!defined('FLUENT_BOARDS_PRO_VERSION') || !PermissionManager::userHasPermission($boardId) || empty($data) || empty($data['url'])) {
470 return false;
471 }
472
473 $task = Task::where('id', $taskId)->where('board_id', $boardId)->first();
474 if (!$task) {
475 return false;
476 }
477
478 $attachmentData = Helper::sanitizeTaskAttachment($data);
479 return (new AttachmentService())->addTaskAttachment($task->id, $attachmentData);
480 }
481
482
483 /**
484 * delete a task attachment
485 * @param $boardId
486 * @param $taskId
487 * @param $attachmentId
488 * @return bool
489 */
490 public function deleteTaskAttachment( int $boardId, int $taskId, int $attachmentId)
491 {
492 // check if the user has permission to delete attachment
493 if (!defined('FLUENT_BOARDS_PRO_VERSION') || !PermissionManager::userHasPermission($boardId)) {
494 return false;
495 }
496
497 $task = Task::where('id', $taskId)->where('board_id', $boardId)->first();
498 if (!$task) {
499 return false;
500 }
501
502 (new AttachmentService())->deleteTaskAttachment($task->id, $attachmentId);
503
504 return true;
505 }
506
507
508 public function getInstance()
509 {
510 return $this->instance;
511 }
512
513 public function __call($method, $params)
514 {
515 if (in_array($method, $this->allowedInstanceMethods)) {
516 return call_user_func_array([$this->instance, $method], $params);
517 }
518
519 throw new \Exception("Method {$method} does not exist.");
520 }
521 }
522