PluginProbe
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration / 2.2.0
FluentBoards – Project Management, Task Management, Goal Tracking, Kanban Board, and, Team Collaboration v2.2.0
2.2.0 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 All 43 releases
← All changes | app/Http/Policies/SingleBoardPolicy.php +230 -4 1.40 → 2.2.0 View file →
@@ -8,16 +8,18 @@
8 8 class SingleBoardPolicy extends BasePolicy
9 9 {
10 10 /**
11 11 * Check user permission for any method
12 - * @param \FluentBoards\Framework\Request\Request $request
13 - * @param int $board_id
12 + * @param \FluentBoards\Framework\Http\Request\Request $request
14 13 * @return bool
15 14 */
16 15 public function verifyRequest(Request $request)
17 16 {
17 + // Authorize the controller's URL target, never a query/body override.
18 + $routeParams = $request->get_url_params();
19 + $boardId = absint($routeParams['board_id'] ?? 0);
18 20
19 - return PermissionManager::userHasBoardPermission($request->board_id, $request->getMethod());
21 + return PermissionManager::userHasBoardPermission($boardId, $request->getMethod());
20 22 }
21 23
22 24 public function delete(Request $request)
23 25 {
@@ -23,11 +25,235 @@
23 25 {
24 26 return PermissionManager::isAdmin();
25 27 }
26 28
29 + /**
30 + * Task AI actions. `summarize` only reads content the member can already see,
31 + * so it is treated as a read for permission purposes — otherwise viewer-only
32 + * members would be denied an action the UI intentionally offers them. Every
33 + * other action writes to the task and keeps the normal write restrictions.
34 + */
35 + public function taskAssist(Request $request)
36 + {
37 + $routeParams = $request->get_url_params();
38 + $boardId = absint($routeParams['board_id'] ?? 0);
39 + $method = $request->get('action') === 'summarize' ? 'GET' : $request->getMethod();
40 +
41 + return PermissionManager::userHasBoardPermission($boardId, $method);
42 + }
43 +
44 + /**
45 + * Allow board role changes while reserving admin targets for global admins.
46 + */
27 47 public function makeManager(Request $request)
28 48 {
29 - return PermissionManager::isBoardManager($request->board_id);
49 + return $this->canManageBoardUser($request);
50 + }
51 +
52 + /**
53 + * Allow board role changes while reserving admin targets for global admins.
54 + */
55 + public function removeManager(Request $request)
56 + {
57 + return $this->canManageBoardUser($request);
58 + }
59 +
60 + /**
61 + * Allow board role changes while reserving admin targets for global admins.
62 + */
63 + public function makeViewer(Request $request)
64 + {
65 + return $this->canManageBoardUser($request);
66 + }
67 +
68 + /**
69 + * Allow board role changes while reserving admin targets for global admins.
70 + */
71 + public function makeMember(Request $request)
72 + {
73 + return $this->canManageBoardUser($request);
74 + }
75 +
76 + public function getInvitations(Request $request)
77 + {
78 + return $this->userIsBoardManager($request);
79 + }
80 +
81 + public function deleteInvitation(Request $request)
82 + {
83 + return $this->userIsBoardManager($request);
84 + }
85 +
86 + /**
87 + * Restrict board membership changes to board managers.
88 + */
89 + public function addMembersInBoard(Request $request)
90 + {
91 + return $this->userIsBoardManager($request);
92 + }
93 +
94 + /**
95 + * Allow members to leave; only global admins may remove admin targets.
96 + */
97 + public function removeUserFromBoard(Request $request)
98 + {
99 + $routeParams = $request->get_url_params();
100 + $boardId = absint($routeParams['board_id'] ?? 0);
101 + $targetUserId = absint($routeParams['user_id'] ?? 0);
102 + $currentUserId = get_current_user_id();
103 +
104 + if (!$boardId || !$targetUserId) {
105 + return false;
106 + }
107 +
108 + if ($currentUserId && $targetUserId === $currentUserId) {
109 + return PermissionManager::userHasPermission($boardId, $currentUserId);
110 + }
111 +
112 + return $this->canManageBoardUser($request);
113 + }
114 +
115 + /**
116 + * Restrict permanent task deletion to board managers.
117 + */
118 + public function deleteTask(Request $request)
119 + {
120 + return $this->userIsBoardManager($request);
121 + }
122 +
123 + /**
124 + * Restrict permanent bulk task deletion to board managers.
125 + */
126 + public function bulkDeleteTasks(Request $request)
127 + {
128 + return $this->userIsBoardManager($request);
129 + }
130 +
131 + /**
132 + * Restrict board background changes to board managers.
133 + */
134 + public function setBoardBackground(Request $request)
135 + {
136 + return $this->userIsBoardManager($request);
137 + }
138 +
139 + /**
140 + * Restrict board background uploads to board managers.
141 + */
142 + public function uploadBoardBackground(Request $request)
143 + {
144 + return $this->userIsBoardManager($request);
145 + }
146 +
147 + /**
148 + * Restrict public board exposure to board managers.
149 + */
150 + public function togglePublicAccess(Request $request)
151 + {
152 + return $this->userIsBoardManager($request);
153 + }
154 +
155 + /**
156 + * Restrict custom-field creation to board managers (Pro).
157 + */
158 + public function createCustomField(Request $request)
159 + {
160 + return $this->userIsBoardManager($request);
161 + }
162 +
163 + /**
164 + * Restrict custom-field edits to board managers (Pro).
165 + */
166 + public function updateCustomField(Request $request)
167 + {
168 + return $this->userIsBoardManager($request);
169 + }
170 +
171 + /**
172 + * Restrict custom-field deletion to board managers (Pro).
173 + */
174 + public function deleteCustomField(Request $request)
175 + {
176 + return $this->userIsBoardManager($request);
177 + }
178 +
179 + /**
180 + * Restrict custom-field reordering to board managers (Pro).
181 + */
182 + public function updateCustomFieldPosition(Request $request)
183 + {
184 + return $this->userIsBoardManager($request);
185 + }
186 +
187 + /**
188 + * Restrict stage default-assignee configuration to board managers (Pro).
189 + */
190 + public function setDefaultAssignees(Request $request)
191 + {
192 + return $this->userIsBoardManager($request);
193 + }
194 +
195 + /**
196 + * Restrict stage default-watcher configuration to board managers (Pro).
197 + */
198 + public function setDefaultWatchers(Request $request)
199 + {
200 + return $this->userIsBoardManager($request);
201 + }
202 +
203 + /**
204 + * Keep roadmap and board-level properties global-admin-only.
205 + */
206 + public function updateBoardProperties(Request $request)
207 + {
208 + return PermissionManager::isAdmin();
209 + }
210 +
211 + /**
212 + * Keep whole-board archival global-admin-only.
213 + */
214 + public function archiveBoard(Request $request)
215 + {
216 + return PermissionManager::isAdmin();
217 + }
218 +
219 + /**
220 + * Keep whole-board restoration global-admin-only.
221 + */
222 + public function restoreBoard(Request $request)
223 + {
224 + return PermissionManager::isAdmin();
225 + }
226 +
227 + /**
228 + * Managers can manage ordinary board users; global admins alone can manage admins.
229 + */
230 + private function canManageBoardUser(Request $request)
231 + {
232 + // Match controller route arguments; body/query IDs must not authorize another target.
233 + $routeParams = $request->get_url_params();
234 + $boardId = absint($routeParams['board_id'] ?? 0);
235 + $targetUserId = absint($routeParams['user_id'] ?? 0);
236 +
237 + if (!$boardId || !$targetUserId) {
238 + return false;
239 + }
240 +
241 + if (PermissionManager::isAdmin($targetUserId)) {
242 + return PermissionManager::isAdmin();
243 + }
244 +
245 + return PermissionManager::isBoardManager($boardId);
246 + }
247 +
248 + /**
249 + * Resolve board-manager access from the sanitized route board id.
250 + */
251 + private function userIsBoardManager(Request $request)
252 + {
253 + $routeParams = $request->get_url_params();
254 +
255 + return PermissionManager::isBoardManager(absint($routeParams['board_id'] ?? 0));
30 256 }
31 257
32 258
33 259 }