PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.0.10
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.0.10
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 / Services / Intergrations / FluentFormIntegration / Bootstrap.php

Bootstrap.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 2.0.10, at app/Services/Intergrations/FluentFormIntegration/Bootstrap.php

513 lines 19.3 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\Intergrations\FluentFormIntegration;
4
5 use FluentBoards\App\Hooks\Handlers\AdminMenuHandler;
6 use FluentBoards\App\Models\Label;
7 use FluentBoards\App\Models\Stage;
8 use FluentBoards\App\Models\User;
9 use FluentBoards\App\Services\Constant;
10 use FluentBoards\App\Services\NotificationService;
11 use FluentBoards\App\Services\TaskService;
12 use FluentBoardsPro\App\Models\TaskAttachment;
13 use FluentForm\App\Http\Controllers\IntegrationManagerController;
14 use FluentBoards\Framework\Support\Arr;
15 use FluentBoards\App\Models\Board;
16 use FluentBoards\App\Models\Task;
17 use FluentBoards\App\Services\Helper;
18 use FluentCrm\App\Models\Subscriber;
19 use FluentBoards\App\App;
20
21
22 class Bootstrap extends IntegrationManagerController
23 {
24 public $disableGlobalSettings = 'yes';
25
26 public function __construct($app)
27 {
28 parent::__construct(
29 $app,
30 'Fluent Boards',
31 'fluent_boards',
32 '_fluentform_fluent_boards_settings',
33 'fluentform_fluent_boards_feed',
34 30
35 );
36
37 $fluentBoards = App::getInstance();
38 $this->logo = $fluentBoards['url.assets'] . 'images/icon.png';
39
40 $this->description = 'Connect Fluent Boards with WP Fluent Forms and create a task when a form is submitted.';
41
42 $this->registerAdminHooks();
43
44 add_action('wp_ajax_fluentform_fluent_board_config', array($this, 'getBoardConfigOptions'));
45 // add_filter('fluentform/notifying_async_fluent_boards', '__return_false');
46 }
47
48 public function addGlobalMenu($setting)
49 {
50 return $setting;
51 }
52
53 public function pushIntegration($integrations, $formId)
54 {
55 $integrations[$this->integrationKey] = [
56 'title' => $this->title . ' Integration',
57 'logo' => $this->logo,
58 'disable_global_settings' => 'yes',
59 'category' => '',
60 'is_active' => $this->isConfigured()
61 ];
62
63 return $integrations;
64 }
65
66 public function isConfigured()
67 {
68 return true;
69 }
70
71 public function getIntegrationDefaults($settings, $formId)
72 {
73 return [
74 'name' => '',
75 'list_id' => '',
76 'board_config' => [
77 'board_id' => '',
78 'stage_id' => '',
79 'board_label_id' => [],
80 'member_ids' => [],
81 'crm_contact_id' => '',
82 'priority' => ''
83 ],
84 'task_title' => '',
85 'submitter_name' => '',
86 'submitter_email' => '',
87 'priority' => '',
88 'description' => '',
89 'position' => 'bottom',
90 'due_at_days' => '',
91 'create_crm_contact' => false,
92 'conditionals' => [
93 'conditions' => [],
94 'status' => false,
95 'type' => 'all'
96 ],
97
98
99 'enabled' => true
100 ];
101 }
102
103 public function getSettingsFields($settings, $formId)
104 {
105 $data = [
106 'fields' => [
107 [
108 'key' => 'board_config',
109 'label' => 'Fluent Boards Configuration',
110 'required' => true,
111 'component' => 'chained_select',
112 'primary_key' => 'board_id',
113 'fields_options' => [
114 'board_id' => [],
115 'stage_id' => [],
116 'board_label_id' => [],
117 'member_ids' => [],
118 'priority' => []
119 ],
120 'options_labels' => [
121 'board_id' => [
122 'label' => 'Select Board',
123 'type' => 'select',
124 'placeholder' => 'Select Board'
125 ],
126 'stage_id' => [
127 'label' => 'Select Stage',
128 'type' => 'select',
129 'placeholder' => 'Select Stage'
130 ],
131 'board_label_id' => [
132 'label' => 'Select Labels',
133 'type' => 'multi-select',
134 'placeholder' => 'Select Labels'
135 ],
136 'member_ids' => [
137 'label' => 'Select Assignees',
138 'type' => 'multi-select',
139 'placeholder' => 'Select Assignees'
140 ],
141 'priority' => [
142 'label' => 'Select Priority',
143 'type' => 'select',
144 'placeholder' => 'Priority'
145 ]
146 ],
147 'remote_url' => admin_url('admin-ajax.php?action=fluentform_fluent_board_config')
148 ],
149 [
150 'key' => 'task_title',
151 'label' => 'Task Title',
152 'required' => true,
153 'placeholder' => 'Task Title',
154 'component' => 'value_text'
155 ],
156 [
157 'key' => 'description',
158 'label' => 'Description',
159 'required' => false,
160 'placeholder' => 'Describe your task',
161 'component' => 'wp_editor',
162 ],
163
164 [
165 'key' => 'submitter_name',
166 'label' => 'Submitter Name',
167 'required' => true,
168 'placeholder' => 'Submitter Name',
169 'component' => 'value_text'
170 ],
171 [
172 'key' => 'submitter_email',
173 'label' => 'Submitter Email',
174 'required' => true,
175 'placeholder' => 'Submitter Email',
176 'component' => 'value_text'
177 ],
178 [
179 'key' => 'position',
180 'label' => 'Task Position',
181 'required' => true,
182 'placeholder' => 'Position',
183 'component' => 'radio_choice',
184 'options' => [
185 'bottom' => 'Bottom',
186 'top' => 'Top'
187 ]
188 ],
189 [
190 'key' => 'due_at_days',
191 'label' => 'Due Date',
192 'tips' => 'Days after form submission, values less than zero will set due date to null.',
193 'component' => 'number'
194 ],
195 [
196 'key' => 'conditionals',
197 'label' => 'Conditional Logics',
198 'tips' => 'Allow integration conditionally based on your submission values',
199 'component' => 'conditional_block'
200 ],
201 [
202 'key' => 'enabled',
203 'label' => 'Status',
204 'component' => 'checkbox-single',
205 'checkbox_label' => 'Enable This feed'
206 ]
207 ],
208 'button_require_list' => false,
209 'integration_title' => $this->title
210 ];
211 if (function_exists('fluentCrm')) {
212 $addToCrmField = [
213 'key' => 'create_crm_contact',
214 'label' => 'FluentCRM',
215 'tips' => "This will create a FluentCRM Contact, if submitter email doesn't exists",
216 'component' => 'checkbox-single',
217 'checkbox_label' => 'Create FluentCRM Contact',
218 ];
219 array_splice($data['fields'], 7, 0, [$addToCrmField]);
220 }
221 if (defined('FLUENT_BOARDS_PRO_VERSION')) {
222 $mapFilesField = [
223 'key' => 'map_files',
224 'label' => 'Files/Attachments',
225 'tips' => "This will map all the Files/Images from the form submission to the task.",
226 'component' => 'checkbox-single',
227 'checkbox_label' => 'Map Files/Attachments to Task',
228 ];
229 array_splice($data['fields'], -2, 0, [$mapFilesField]);
230 }
231 return $data;
232 }
233
234
235 public function getBoardConfigOptions()
236 {
237 $requestInfo = $this->app->request->get('settings');
238 $boardConfig = Arr::get($requestInfo, 'board_config');
239
240 $boardId = Arr::get($boardConfig, 'board_id');
241
242 $data = [
243 'board_id' => $this->getBoards(),
244 'stage_id' => [],
245 'board_label_id' => [],
246 'member_ids' => [],
247 'priority' => apply_filters('fluent_boards/task_priorities', (new AdminMenuHandler())->getDefaultPriorities()),
248 ];
249
250 if ($boardId) {
251 $data['stage_id'] = $this->getStages($boardId);
252 $data['board_label_id'] = $this->getBoardLabels($boardId);
253 $data['member_ids'] = $this->getBoardMembers($boardId);
254 }
255
256 wp_send_json_success([
257 'fields_options' => $data
258 ], 200);
259 }
260
261 private function getBoards()
262 {
263 $boards = Board::query()->whereNull('archived_at')->get()->toArray();
264
265 $formattedBoards = [];
266 foreach ($boards as $board) {
267 if (is_array($board)) {
268 $formattedBoards[$board['id']] = $board['title'];
269 }
270 }
271
272 return $formattedBoards;
273 }
274
275 private function getStages($boardId)
276 {
277 $stages = Stage::where('board_id', $boardId)->whereNull('archived_at')->get()->toArray();
278
279 $formattedStages = [];
280 foreach ($stages as $stage) {
281 if (is_array($stage)) {
282 $formattedStages[$stage['id']] = $stage['title'];
283 }
284 }
285
286 return $formattedStages;
287 }
288
289
290 /**
291 * Prepare Fluent Boards forms for feed field.
292 *
293 * @return array
294 */
295
296 /*
297 * Submission Broadcast Handler
298 */
299
300 public function notify($feed, $formData, $entry, $form)
301 {
302 if (function_exists('fluentBoards')) {
303 $feedData = $feed['processedValues'];
304 $taskName = trim(Arr::get($feedData, 'task_title'));
305 $boardId = Arr::get($feedData, 'board_config.board_id');
306 $stageId = Arr::get($feedData, 'board_config.stage_id');
307 $boardLabels = Arr::get($feedData, 'board_config.board_label_id');
308 $assignees = Arr::get($feedData, 'board_config.member_ids');
309 $priority = Arr::get($feedData, 'board_config.priority');
310 $description = Arr::get($feedData, 'description');
311 $position = Arr::get($feedData, 'position');
312 $crmContactId = Arr::get($feedData, 'board_config.crm_contact_id');
313 $submitterName = trim(Arr::get($feedData, 'submitter_name'));
314 $submitterEmail = Arr::get($feedData, 'submitter_email');
315 $due_at_days = Arr::get($feedData, 'due_at_days');
316 $mapFiles = Arr::get($feedData, 'map_files');
317 $watcher = Arr::get($feedData, 'watcher_id');
318 $crateCRMContact = Arr::get($feedData, 'create_crm_contact');
319
320 if (!$boardId) {
321 do_action('fluentform/integration_action_result', $feed, 'failed', 'Board is required');
322 return;
323 }
324 $board = Board::find($boardId);
325 if (!$board) {
326 do_action('fluentform/integration_action_result', $feed, 'failed', "Board doesn't exist");
327 return;
328 }
329 if (!$stageId) {
330 do_action('fluentform/integration_action_result', $feed, 'failed', "Stage is required");
331 return;
332 }
333 $stage = Stage::find($stageId);
334 if (!$stage) {
335 do_action('fluentform/integration_action_result', $feed, 'failed', "Stage doesn't exist");
336 return;
337 }
338 if (!$taskName) {
339 do_action('fluentform/integration_action_result', $feed, 'failed', "Task title is required");
340 return;
341 } else if (!is_string($taskName)) {
342 do_action('fluentform/integration_action_result', $feed, 'failed', "Invalid Task title is required");
343 return;
344 }
345
346 $data = [
347 'title' => $taskName,
348 'board_id' => $boardId,
349 'stage_id' => $stageId,
350 'priority' => $priority,
351 'description' => $description,
352 'crm_contact_id' => $crmContactId,
353 'position' => $this->getLastPositionOfStageTask($boardId, $stageId),
354 'due_at' => $this->dueDateConvertion($due_at_days, 'day'),
355 'source' => 'FluentForm'
356
357 ];
358
359 $formSubmitter = User::where('user_email', $submitterEmail)->first();
360 if (isset($formSubmitter['ID'])) {
361 $data['created_by'] = $formSubmitter->ID;
362 } else {
363 $data['settings']['author'] = [
364 'name' => sanitize_text_field($submitterName),
365 'email' => sanitize_email($submitterEmail),
366 'cover' => [
367 'backgroundColor' => ''
368 ],
369 'subtask_count' => 0
370 ];
371 }
372
373 if (function_exists('fluentCrm')) {
374 $crmConatct = Subscriber::where('email', $submitterEmail)->first();
375 if ($crmConatct) {
376 $data['crm_contact_id'] = $crmConatct->id;
377 } else {
378 if ($crateCRMContact) {
379 // create crm contact
380 }
381 }
382 }
383
384 $data = Helper::sanitizeTask($data);
385 $task = (new Task())->createTask($data);
386
387 if ($task->id) {
388 do_action('fluent_boards/task_added_from_fluent_form', $task);
389 if ($position == 'top') {
390 $task->moveToNewPosition(1);
391 }
392
393 if ($assignees) {
394 foreach ($assignees as $assignee) {
395 $operation = $task->addOrRemoveAssignee($assignee);
396 $task->load('assignees');
397 $task->updated_at = current_time('mysql');
398
399 $task->save();
400
401 if ($operation == 'added') {
402 if ((new NotificationService())->checkIfEmailEnable($assignee, Constant::BOARD_EMAIL_TASK_ASSIGN, $task->board_id)) {
403 (new TaskService())->sendMailAfterTaskModify('add_assignee', $assignee, $task->id);
404 }
405 do_action('fluent_boards/task_assignee_added', $task, $assignee);
406 }
407 }
408 }
409
410 if ($boardLabels) {
411 foreach ($boardLabels as $label) {
412 $task->labels()->syncWithoutDetaching([$label => ['object_type' => Constant::OBJECT_TYPE_TASK_LABEL]]);
413 }
414 }
415
416 if ($mapFiles && defined('FLUENT_BOARDS_PRO_VERSION')) {
417 $results = [];
418
419 // Loop through the array to find keys starting with 'image-upload' or 'file-upload'
420 foreach ($formData as $key => $value) {
421 if (preg_match('/^(image-upload|file-upload)/', $key)) {
422 foreach ($value as $file_url) {
423 $results[] = $file_url;
424 }
425 }
426 }
427
428
429 foreach ($results as $attachment) {
430 $urlMeta = [
431 'title' => 'Uploaded from FluentForm',
432 'type' => 'meta_data',
433 'url' => esc_url($attachment)
434 ];
435 $urlData['settings'] = ['meta' => $urlMeta];
436 // creating new attachment object
437 $attachment = new TaskAttachment();
438 $attachment->object_id = $task->id;
439 $attachment->object_type = \FluentBoards\App\Services\Constant::TASK_ATTACHMENT;
440 $attachment->attachment_type = 'url';
441 $attachment->title = 'Uploaded File from Fluent Form';
442 $attachment->full_url = $urlMeta['url'];
443 $attachment->settings = $urlData['settings'] ?? '';
444 $attachment->driver = 'local';
445 $attachment->save();
446 }
447 }
448
449 $successMessage = __('Fluent Boards feed has been successfully initialized and data has been pushed.', 'fluent-boards');
450 do_action('fluentform/integration_action_result', $feed, 'success', $successMessage);
451 } else {
452 $error = __('Error when submitting data to Fluent Board server.', 'fluent-boards');
453 do_action('fluentform/integration_action_result', $feed, 'failed', $error);
454 }
455 } else {
456 do_action('fluentform/integration_action_result', $feed, 'failed', "Fluent Board doesn't exists.");
457 }
458 }
459
460 public function getMergeFields($list, $listId, $formId)
461 {
462 return false;
463 }
464
465 private function getLastPositionOfStageTask($board_id, $stage_id)
466 {
467 $lastPosition = Task::query()
468 ->where('board_id', $board_id)
469 ->where('parent_id', null)
470 ->where('stage_id', $stage_id)
471 ->whereNull('archived_at')
472 ->orderBy('position', 'desc')
473 ->pluck('position')
474 ->first();
475
476 return $lastPosition + 1;
477 }
478
479 private function getBoardLabels($boardId)
480 {
481 $labels = Label::where('board_id', $boardId)->whereNull('archived_at')->orderBy('position', 'asc')->get();
482
483 $formattedLabels = [];
484 foreach ($labels as $label) {
485 $formattedLabels[$label['id']] = $label['title'] ?? $label['slug'];
486 }
487
488 return $formattedLabels;
489 }
490
491 private function getBoardMembers($boardId)
492 {
493 $board = Board::findOrFail($boardId);
494 $boardUsers = $board->users;
495 $formattedBoardUsers = [];
496 foreach ($boardUsers as $boardUser) {
497 $formattedBoardUsers[$boardUser['ID']] = $boardUser['user_login'] . " (" . $boardUser['user_email'] . ")";
498 }
499 return $formattedBoardUsers;
500 }
501
502 private function dueDateConvertion($due_time, $unit)
503 {
504 if ($due_time > 0) {
505 $currentTime = current_time('mysql');
506 $readyString = '+' . $due_time . ' ' . $unit;
507 return gmdate('Y-m-d H:i:s', strtotime($readyString, strtotime($currentTime)));
508 }
509 return null;
510 }
511
512 }
513