PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 1.5.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v1.5.0
2.5.0 2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 All 34 releases
fluent-booking / app / Services / Integrations / FluentBoards / Bootstrap.php

Bootstrap.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 1.5.0, at app/Services/Integrations/FluentBoards/Bootstrap.php

440 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Services\Integrations\FluentBoards;
4
5 use FluentBooking\App\App;
6 use FluentBoards\App\Models\Label;
7 use FluentBoards\App\Models\Stage;
8 use FluentBoards\App\Models\Task;
9 use FluentBoards\App\Models\Board;
10 use FluentBoards\App\Models\User;
11 use FluentBoards\App\Services\Constant;
12 use FluentBoards\App\Services\NotificationService;
13 use FluentBoards\App\Services\TaskService;
14 use FluentBooking\Framework\Support\Arr;
15 use FluentBooking\App\Http\Controllers\IntegrationManagerController;
16
17 class Bootstrap extends IntegrationManagerController
18 {
19 public $hasGlobalMenu = false;
20
21 public $disableGlobalSettings = 'yes';
22
23 public function __construct()
24 {
25 parent::__construct(
26 __('FluentBoards', 'fluent-booking'),
27 'fluentboards',
28 'fluent_booking_fluentboards_configurations',
29 'fluentboards_feeds',
30 10
31 );
32
33 $this->logo = App::getInstance('url.assets') . 'images/fluentboards.png';
34
35 $this->description = __('Connect FluentBoards with Fluent Booking and create tasks with booking fields.', 'fluent-booking');
36
37 $this->registerAdminHooks();
38 }
39
40 public function pushIntegration($integrations, $calendarEventId)
41 {
42 $integrations[$this->integrationKey] = [
43 'title' => $this->title . ' ' . __('Integration', 'fluent-booking'),
44 'logo' => $this->logo,
45 'is_active' => $this->isConfigured(),
46 'configure_title' => __('Configuration required!', 'fluent-booking'),
47 'global_configure_url' => '#',
48 'configure_message' => __('FluentBoards is not configured yet! Please configure your FluentBoards api first', 'fluent-booking'),
49 'configure_button_text' => __('Set FluentBoards', 'fluent-booking'),
50 ];
51
52 return $integrations;
53 }
54
55 public function isConfigured()
56 {
57 return true;
58 }
59
60 public function isEnabled()
61 {
62 return true;
63 }
64
65 public function getIntegrationDefaults($settings, $calendarEventId)
66 {
67 return [
68 'name' => '',
69 'board_config' => [
70 'board_id' => '',
71 'stage_id' => '',
72 'label_ids' => '',
73 'member_ids' => [],
74 'priority' => 'low'
75 ],
76 'task_title' => '',
77 'author_name' => '',
78 'email' => '',
79 'description' => '',
80 'position' => 'bottom',
81 'due_at_type' => 'booking',
82 'due_at_days' => 0,
83 'enabled' => true
84 ];
85 }
86
87 public function getSettingsFields($settings, $calendarEventId)
88 {
89 $fields = [
90 [
91 'key' => 'name',
92 'label' => __('Feed Name', 'fluent-booking'),
93 'required' => true,
94 'placeholder' => __('Your Feed Name', 'fluent-booking'),
95 'component' => 'text',
96 ],
97 [
98 'key' => 'board_config',
99 'label' => __('Fluent Boards Configuration', 'fluent-booking'),
100 'required' => true,
101 'component' => 'chained_select',
102 'primary_key' => 'board_id',
103 'fields_options' => [
104 'board_id' => [],
105 'stage_id' => [],
106 'label_ids' => [],
107 'member_ids' => [],
108 'priority' => []
109 ],
110 'options_labels' => [
111 'board_id' => [
112 'label' => __('Select Board', 'fluent-booking'),
113 'type' => 'select',
114 'placeholder' => __('Select Board', 'fluent-booking')
115 ],
116 'stage_id' => [
117 'label' => __('Select Stage', 'fluent-booking'),
118 'type' => 'select',
119 'placeholder' => __('Select Stage', 'fluent-booking')
120 ],
121 'label_ids' => [
122 'label' => __('Select Labels', 'fluent-booking'),
123 'type' => 'multi-select',
124 'placeholder' => __('Select Labels', 'fluent-booking')
125 ],
126 'member_ids' => [
127 'label' => __('Select Assignees', 'fluent-booking'),
128 'type' => 'multi-select',
129 'placeholder' => __('Select Assignees', 'fluent-booking')
130 ],
131 'priority' => [
132 'label' => __('Select Priority', 'fluent-booking'),
133 'type' => 'select',
134 'placeholder' => __('Priority', 'fluent-booking')
135 ]
136 ]
137 ],
138 [
139 'key' => 'task_title',
140 'label' => __('Task Title', 'fluent-booking'),
141 'required' => true,
142 'placeholder' => __('Task Title', 'fluent-booking'),
143 'component' => 'value_text'
144 ],
145 [
146 'key' => 'description',
147 'label' => __('Description', 'fluent-booking'),
148 'required' => false,
149 'placeholder' => __('Describe your task', 'fluent-booking'),
150 'component' => 'wp_editor',
151 ],
152 [
153 'key' => 'author_name',
154 'label' => __('Submitter Name', 'fluent-booking'),
155 'required' => true,
156 'placeholder' => __('Submitter Name', 'fluent-booking'),
157 'component' => 'value_text'
158 ],
159 [
160 'key' => 'email',
161 'label' => __('Submitter Email', 'fluent-booking'),
162 'required' => true,
163 'placeholder' => __('Submitter Email', 'fluent-booking'),
164 'component' => 'value_text'
165 ],
166 [
167 'key' => 'due_at_type',
168 'label' => __('Due Type', 'fluent-booking'),
169 'tips' => __('Choose “Booking Date” to set the due date relative to when the booking was made or “Meeting Date” to set it relative to the scheduled meeting date.', 'fluent-booking'),
170 'component' => 'radio_choice',
171 'options' => [
172 'booking' => __('Booking Date', 'fluent-booking'),
173 'meeting' => __('Meeting Date', 'fluent-booking')
174 ]
175 ],
176 [
177 'key' => 'due_at_days',
178 'label' => __('Due Date', 'fluent-booking'),
179 'tips' => __('Set the due date by entering a number relative to the booking or meeting date. Positive for days after and negative for days before the booking or meeting date.', 'fluent-booking'),
180 'component' => 'number'
181 ],
182 [
183 'key' => 'position',
184 'label' => __('Task Position', 'fluent-booking'),
185 'placeholder' => __('Position', 'fluent-booking'),
186 'component' => 'radio_choice',
187 'options' => [
188 'bottom' => __('Bottom', 'fluent-booking'),
189 'top' => __('Top', 'fluent-booking')
190 ]
191 ],
192 [
193 'require_list' => false,
194 'required' => true,
195 'key' => 'event_trigger',
196 'options' => $this->getEventTriggerOptions(),
197 'tips' => __('Select in which booking stage you want to trigger this feed', 'fluent-booking'),
198 'label' => __('Event Trigger', 'fluent-booking'),
199 'component' => 'checkbox-multiple-text',
200 'checkbox_label' => __('Event Trigger For This Feed', 'fluent-booking'),
201 ],
202 [
203 'require_list' => false,
204 'key' => 'enabled',
205 'label' => __('Status', 'fluent-booking'),
206 'component' => 'checkbox-single',
207 'checkbox_label' => __('Enable This feed', 'fluent-booking'),
208 ]
209 ];
210
211 return [
212 'fields' => $fields,
213 'button_require_list' => false,
214 'integration_title' => $this->title,
215 ];
216 }
217
218 public function getMergeFields($list, $listId, $slotId)
219 {
220 return [];
221 }
222
223 public function getEventTriggerOptions()
224 {
225 return [
226 'after_booking_scheduled' => __('Booking Confirmed', 'fluent-booking'),
227 'booking_schedule_completed' => __('Booking Completed', 'fluent-booking'),
228 'booking_schedule_cancelled' => __('Booking Cancelled', 'fluent-booking'),
229 ];
230 }
231
232 public function getConfigFieldOptions($settings, $calendarEventId)
233 {
234 $boardId = Arr::get($settings, 'board_config.board_id');
235
236 $data = [
237 'board_id' => $this->getBoards(),
238 'stage_id' => $boardId ? $this->getStages($boardId) : [],
239 'label_ids' => $boardId ? $this->getBoardLabels($boardId) : [],
240 'member_ids' => $boardId ? $this->getBoardMembers($boardId) : [],
241 'priority' => $this->getBoardPriorities()
242 ];
243
244 $data = apply_filters('fluent_booking/fluent_board_config_field_options', $data, $boardId);
245
246 return $data;
247 }
248
249 private function getBoards()
250 {
251 $boards = Board::whereNull('archived_at')
252 ->select('id', 'title')
253 ->get();
254
255 $formattedBoards = $boards->mapWithKeys(function ($board) {
256 return [$board->id => $board->title];
257 })->toArray();
258
259 return $formattedBoards;
260 }
261
262 private function getStages($boardId)
263 {
264 $stages = Stage::where('board_id', $boardId)
265 ->whereNull('archived_at')
266 ->select('id', 'title')
267 ->get();
268
269 $formattedStages = $stages->mapWithKeys(function ($stage) {
270 return [$stage->id => $stage->title];
271 })->toArray();
272
273 return $formattedStages;
274 }
275
276 private function getBoardLabels($boardId)
277 {
278 $labels = Label::where('board_id', $boardId)
279 ->whereNull('archived_at')
280 ->orderBy('position', 'asc')
281 ->get(['id', 'title', 'slug']);
282
283 $formattedLabels = $labels->mapWithKeys(function ($label) {
284 return [$label->id => $label->title ?? $label->slug];
285 })->toArray();
286
287 return $formattedLabels;
288 }
289
290 private function getBoardMembers($boardId)
291 {
292 $board = Board::with(['users'])->findOrFail($boardId);
293
294 $formattedBoardUsers = $board->users->mapWithKeys(function ($user) {
295 return [$user->ID => "{$user->user_login} ({$user->user_email})"];
296 })->toArray();
297
298 return $formattedBoardUsers;
299 }
300
301 private function getBoardPriorities()
302 {
303 return [
304 'low' => __('Low', 'fluent-booking'),
305 'medium' => __('Medium', 'fluent-booking'),
306 'high' => __('High', 'fluent-booking')
307 ];
308 }
309
310 private function getLastPositionOfStageTask($boardId, $stageId)
311 {
312 $lastPosition = Task::query()
313 ->where('board_id', $boardId)
314 ->where('parent_id', null)
315 ->where('stage_id', $stageId)
316 ->whereNull('archived_at')
317 ->orderBy('position', 'desc')
318 ->pluck('position')
319 ->first();
320
321 return $lastPosition + 1;
322 }
323
324 private function convertDueDate($dueTime, $dueType, $bookingStartTime)
325 {
326 $timeStamp = strtotime($bookingStartTime);
327 $currentTime = strtotime(current_time('mysql'));
328
329 if ($dueType != 'meeting') {
330 $timeStamp = $currentTime;
331 $dueTime = max(0, $dueTime);
332 }
333
334 $adjustSign = $dueTime < 0 ? '-' : '+';
335 $dateAdjustment = $adjustSign . abs($dueTime) . ' day';
336 $dueDate = gmdate('Y-m-d H:i:s', strtotime($dateAdjustment, $timeStamp)); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
337
338 if (strtotime($dueDate) < $currentTime) {
339 return gmdate('Y-m-d H:i:s', $currentTime); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
340 }
341 return $dueDate;
342 }
343
344 public function notify($feed, $booking, $calendarEvent)
345 {
346 $validData = ['task_title', 'description', 'board_config', 'author_name', 'email', 'position', 'due_at_days', 'due_at_type'];
347 $data = Arr::only($feed['processedValues'], $validData);
348
349 $boardId = intval(Arr::get($data, 'board_config.board_id'));
350 $stageId = intval(Arr::get($data, 'board_config.stage_id'));
351 $priority = sanitize_text_field(Arr::get($data, 'board_config.priority'));
352 $assignees = array_map('intval', Arr::get($data, 'board_config.member_ids', []));
353 $boardLabels = array_map('intval', Arr::get($data, 'board_config.label_ids', []));
354 $taskTitle = sanitize_text_field(Arr::get($data, 'task_title'));
355 $description = wp_kses_post(Arr::get($data, 'description'));
356 $position = sanitize_text_field(Arr::get($data, 'position'));
357 $dueAtDays = intval(Arr::get($data, 'due_at_days'));
358 $dueAtType = sanitize_text_field(Arr::get($data, 'due_at_type'));
359 $authorName = sanitize_text_field(Arr::get($data, 'author_name'));
360 $authorEmail = sanitize_email(Arr::get($data, 'email'));
361
362 if (!$booking->id || !$boardId || !$stageId || !$taskTitle) {
363 return false;
364 }
365
366 $board = Board::find($boardId);
367 if (!$board) {
368 return false;
369 }
370
371 $data = [
372 'title' => $taskTitle,
373 'board_id' => $boardId,
374 'stage_id' => $stageId,
375 'priority' => $priority,
376 'description' => $description,
377 'position' => $this->getLastPositionOfStageTask($boardId, $stageId),
378 'due_at' => $this->convertDueDate($dueAtDays, $dueAtType, $booking->start_time),
379 'source' => 'FluentBooking'
380 ];
381
382 $data['started_at'] = $data['due_at'] ? gmdate('Y-m-d H:i:s', strtotime(current_time('mysql'))) : null; // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
383
384 $existingUser = User::where('user_email', $authorEmail)->first();
385 if ($existingUser) {
386 $data['created_by'] = $existingUser->ID;
387 }
388
389 if (!$existingUser) {
390 $data['settings']['author'] = [
391 'name' => $authorName,
392 'email' => $authorEmail,
393 'subtask_count' => 0,
394 'cover' => [
395 'backgroundColor' => ''
396 ]
397 ];
398 }
399
400 $task = (new Task())->createTask($data);
401 if (!$task) {
402 return false;
403 }
404
405 do_action('fluent_boards/task_added_from_fluent_booking', $task, $booking, $calendarEvent, $feed);
406
407 if ($position == 'top') {
408 $task->moveToNewPosition(1);
409 }
410
411 foreach ($assignees as $assignee) {
412 $task->addOrRemoveAssignee($assignee);
413 $task->load('assignees');
414 $task->updated_at = current_time('mysql');
415 $task->save();
416
417 $isEmailEnabled = (new NotificationService())->checkIfEmailEnable($assignee, Constant::BOARD_EMAIL_TASK_ASSIGN, $task->board_id);
418 if ($isEmailEnabled) {
419 (new TaskService())->sendMailAfterTaskModify('add_assignee', $assignee, $task->id);
420 }
421
422 do_action('fluent_boards/task_assignee_changed', $task, $assignee, 'added');
423 }
424
425 foreach ($boardLabels as $label) {
426 $task->labels()->syncWithoutDetaching([$label => ['object_type' => Constant::OBJECT_TYPE_TASK_LABEL]]);
427 }
428
429 $taskUrl = admin_url("admin.php?page=fluent-boards#/boards/$boardId/tasks/{$task->id}");
430
431 $this->addLog(
432 $feed['settings']['name'],
433 sprintf(__('Task has been created in FluentBoards. You can %s to view the task.', 'fluent-booking'), '<a target="_blank" href="' . $taskUrl . '">' . __('click here', 'fluent-booking') . '</a>'),
434 $booking->id,
435 'success'
436 );
437 return true;
438 }
439 }
440