PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 1.95.2
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v1.95.2
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 / Http / Controllers / PublicBoardController.php

PublicBoardController.php in FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration 1.95.2, at app/Http/Controllers/PublicBoardController.php

269 lines 8.4 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\Http\Controllers;
4
5 use FluentBoards\App\Models\Board;
6 use FluentBoards\App\Models\Stage;
7 use FluentBoards\App\Models\Task;
8 use FluentBoards\App\Services\PublicAccessService;
9 use FluentBoards\Framework\Http\Request\Request;
10
11 class PublicBoardController extends Controller
12 {
13 public function find($board_id)
14 {
15 $board_id = absint($board_id);
16 $board = Board::findOrFail($board_id);
17
18 $board->background = maybe_unserialize($board->background);
19 $board->description = wp_kses_post($board->description ?? '');
20 $board->createdOn = $board->created_at ? $board->created_at->format('Y-m-d') : null;
21 $board->load(['stages', 'labels', 'users']);
22
23 $board->users = PublicAccessService::sanitizeUsers($board->users);
24 $board->isUserOnlyViewer = true;
25 $board->is_pinned = false;
26
27 $board->makeHidden([
28 'settings', 'currency', 'crm_contact_id',
29 'updated_at', 'created_by',
30 ]);
31
32 return [
33 'board' => $board
34 ];
35 }
36
37 public function getTasksByBoard($board_id)
38 {
39 $board_id = absint($board_id);
40 Board::findOrFail($board_id);
41
42 $stageIds = $this->getStageIdsByBoard($board_id);
43
44 $tasks = Task::with(['assignees', 'labels'])
45 ->where('board_id', $board_id)
46 ->whereNull('archived_at')
47 ->whereNull('parent_id')
48 ->whereIn('stage_id', $stageIds)
49 ->orderBy('due_at', 'ASC')
50 ->get();
51
52 $this->sanitizeTasks($tasks);
53
54 return [
55 'tasks' => $tasks,
56 ];
57 }
58
59 public function getTasksByBoardStage($board_id)
60 {
61 $board_id = absint($board_id);
62 Board::findOrFail($board_id);
63
64 $tasks = [];
65 $stageIds = $this->getStageIdsByBoard($board_id);
66 $stageTaskCounts = $this->getStageTaskCounts($board_id, $stageIds);
67 $paginationByStage = [];
68
69 foreach ($stageIds as $stageId) {
70 $stageTasks = Task::with(['assignees', 'labels'])
71 ->where('board_id', $board_id)
72 ->where('stage_id', $stageId)
73 ->whereNull('archived_at')
74 ->whereNull('parent_id')
75 ->orderBy('position', 'ASC')
76 ->limit(20)
77 ->get();
78
79 $this->sanitizeTasks($stageTasks);
80 $tasks = array_merge($tasks, $stageTasks->toArray());
81
82 $startCursor = $stageTasks->count() ? (float) $stageTasks->first()->position : null;
83 $endCursor = $stageTasks->count() ? (float) $stageTasks->last()->position : null;
84 $loadedCount = $stageTasks->count();
85 $hasMoreAfter = (int) ($stageTaskCounts[$stageId] ?? 0) > $loadedCount;
86
87 $paginationByStage[$stageId] = [
88 'stage_id' => (int) $stageId,
89 'total_count' => (int) ($stageTaskCounts[$stageId] ?? 0),
90 'limit' => 20,
91 'direction' => 'next',
92 'cursor' => null,
93 'has_more' => $hasMoreAfter,
94 'has_more_before' => false,
95 'has_more_after' => $hasMoreAfter,
96 'start_cursor' => $startCursor,
97 'end_cursor' => $endCursor,
98 ];
99 }
100
101 return [
102 'tasks' => $tasks,
103 'pagination_by_stage' => $paginationByStage
104 ];
105 }
106
107 public function getStageTasksPage(Request $request, $board_id)
108 {
109 $board_id = absint($board_id);
110 Board::findOrFail($board_id);
111
112 $stageId = $request->getSafe('stage_id', 'intval');
113 $limit = $request->getSafe('limit', 'intval', 20);
114 $direction = $request->getSafe('direction', 'sanitize_text_field', 'next');
115 $cursor = $request->getSafe('cursor', 'floatval');
116
117 if (!$stageId) {
118 return $this->sendError(esc_html__('Invalid Stage', 'fluent-boards'), 400);
119 }
120
121 if (!in_array($direction, ['next', 'prev'], true)) {
122 return $this->sendError(esc_html__('Invalid direction', 'fluent-boards'), 400);
123 }
124
125 $limit = max(1, min(100, $limit));
126
127 $stage = Stage::where('board_id', $board_id)
128 ->where('id', $stageId)
129 ->whereNull('archived_at')
130 ->first();
131
132 if (!$stage) {
133 return $this->sendError(esc_html__('Stage not found', 'fluent-boards'), 404);
134 }
135
136 $stageTasksQuery = $this->makeStageTasksQuery($board_id, $stageId);
137
138 if ($cursor !== null) {
139 if ($direction === 'prev') {
140 $stageTasksQuery->where('position', '<', $cursor);
141 } else {
142 $stageTasksQuery->where('position', '>', $cursor);
143 }
144 }
145
146 $stageTasks = $stageTasksQuery
147 ->orderBy('position', $direction === 'prev' ? 'DESC' : 'ASC')
148 ->limit($limit + 1)
149 ->get();
150
151 $hasMoreInDirection = $stageTasks->count() > $limit;
152 if ($hasMoreInDirection) {
153 $stageTasks = $stageTasks->slice(0, $limit)->values();
154 }
155
156 if ($direction === 'prev') {
157 $stageTasks = $stageTasks->sortBy('position')->values();
158 }
159
160 $this->sanitizeTasks($stageTasks);
161
162 $startCursor = $stageTasks->count() ? (float) $stageTasks->first()->position : null;
163 $endCursor = $stageTasks->count() ? (float) $stageTasks->last()->position : null;
164
165 $hasMoreBefore = false;
166 $hasMoreAfter = false;
167
168 if ($startCursor !== null) {
169 $hasMoreBefore = $this->makeStageTasksQuery($board_id, $stageId)
170 ->where('position', '<', $startCursor)
171 ->exists();
172 }
173
174 if ($endCursor !== null) {
175 $hasMoreAfter = $this->makeStageTasksQuery($board_id, $stageId)
176 ->where('position', '>', $endCursor)
177 ->exists();
178 }
179
180 return [
181 'tasks' => $stageTasks,
182 'pagination' => [
183 'stage_id' => (int) $stageId,
184 'limit' => (int) $limit,
185 'direction' => $direction,
186 'cursor' => $cursor !== null ? (float) $cursor : null,
187 'has_more' => $hasMoreInDirection,
188 'has_more_before' => $hasMoreBefore,
189 'has_more_after' => $hasMoreAfter,
190 'start_cursor' => $startCursor,
191 'end_cursor' => $endCursor,
192 ],
193 ];
194 }
195
196 private function getStageIdsByBoard($board_id)
197 {
198 return Stage::where('board_id', $board_id)
199 ->whereNull('archived_at')
200 ->pluck('id')
201 ->toArray();
202 }
203
204 private function getStageTaskCounts($board_id, array $stageIds)
205 {
206 if (!$stageIds) {
207 return [];
208 }
209
210 return Task::query()
211 ->selectRaw('stage_id, COUNT(*) as total_count')
212 ->where('board_id', $board_id)
213 ->whereNull('archived_at')
214 ->whereNull('parent_id')
215 ->whereIn('stage_id', $stageIds)
216 ->groupBy('stage_id')
217 ->pluck('total_count', 'stage_id')
218 ->map(function ($count) {
219 return (int) $count;
220 })
221 ->toArray();
222 }
223
224 private function makeStageTasksQuery($board_id, $stageId)
225 {
226 return Task::query()
227 ->with(['assignees', 'labels'])
228 ->where('board_id', $board_id)
229 ->where('stage_id', $stageId)
230 ->whereNull('archived_at')
231 ->whereNull('parent_id');
232 }
233
234 private function sanitizeTasks($tasks)
235 {
236 $sensitiveFields = [
237 'description',
238 'crm_contact_id',
239 'lead_value',
240 'created_by',
241 'source',
242 'source_id',
243 'settings',
244 'reminder_type',
245 'remind_at',
246 'slug',
247 'events',
248 'started_at',
249 'last_completed_at',
250 'comments_count',
251 'archived_at',
252 'parent_id',
253 'type',
254 ];
255
256 foreach ($tasks as $task) {
257 $task->setAppends([]);
258 $task->makeHidden($sensitiveFields);
259 $task->isOverdue = $task->isOverdue();
260 $task->isUpcoming = $task->upcoming();
261 $task->is_watching = false;
262 $task->contact = null;
263 $task->notifications = [];
264 $task->watchers = [];
265 $task->assignees = PublicAccessService::sanitizeUsers($task->assignees);
266 }
267 }
268 }
269