Reject non-scalar ids with 422 instead of 500 (#10)
`group_id: [14]` — a one-element array of a REAL group id — returned a 500. The reporter's analysis was right: `exists` given an array validates that EVERY element exists, which is multi-select behaviour, so an array of one valid id passed the rule and reached the controller. findOrFail() then returned a Collection and ->nextTicketNumber() on it fatalled. What hid it is that the rule looked like it was working: `['a','b']` was correctly rejected by `exists` with a clean 422. Only arrays made of valid ids got through. Adding `integer` ahead of `exists` fixes the reported field, but the hole was a property of `exists`, not of group_id — so every id on the endpoint had it. Fixed all nine sites across both controllers: store()'s group_id and priority_id, update()'s priority_id/project_id/group_id, and storeAgent/storeProject/storeEmailConnection's group_id (plus user_id, which fed straight into an access check). Tests pin the reported repro, the equivalent on priority_id, and both shapes that must keep behaving: a nonexistent id still 422s (so the exists check cannot be dropped later while the array tests still pass) and a normal scalar create still succeeds. Verified the array test FAILS with the rules reverted — it reproduces the 500 rather than merely passing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RDA3fQbsa3gaHCFoV1Q8Gg
This commit is contained in:
@@ -292,8 +292,10 @@ class TicketingSettingsController extends Controller
|
||||
$this->requireAgentAccess();
|
||||
|
||||
$validated = $request->validate([
|
||||
'user_id' => 'required|exists:users,id',
|
||||
'group_id' => 'required|exists:ticketing_groups,id',
|
||||
'user_id' => 'required|integer|exists:users,id',
|
||||
// `integer` before `exists`: an array value passes `exists` element-wise,
|
||||
// so [14] would reach the code below as an array. See TicketController::store().
|
||||
'group_id' => 'required|integer|exists:ticketing_groups,id',
|
||||
'role' => 'required|in:agent,manager',
|
||||
]);
|
||||
|
||||
@@ -374,7 +376,9 @@ class TicketingSettingsController extends Controller
|
||||
$this->requireAgentAccess();
|
||||
|
||||
$validated = $request->validate([
|
||||
'group_id' => 'required|exists:ticketing_groups,id',
|
||||
// `integer` before `exists`: an array value passes `exists` element-wise,
|
||||
// so [14] would reach the code below as an array. See TicketController::store().
|
||||
'group_id' => 'required|integer|exists:ticketing_groups,id',
|
||||
'name' => 'required|string|max:100',
|
||||
'description' => 'nullable|string',
|
||||
'status' => 'required|in:active,archived',
|
||||
@@ -427,7 +431,9 @@ class TicketingSettingsController extends Controller
|
||||
$this->requireAgentAccess();
|
||||
|
||||
$validated = $request->validate([
|
||||
'group_id' => 'required|exists:ticketing_groups,id',
|
||||
// `integer` before `exists`: an array value passes `exists` element-wise,
|
||||
// so [14] would reach the code below as an array. See TicketController::store().
|
||||
'group_id' => 'required|integer|exists:ticketing_groups,id',
|
||||
'type' => 'required|in:gmail,imap',
|
||||
'active' => 'boolean',
|
||||
'config.host' => 'nullable|string|max:255',
|
||||
|
||||
Reference in New Issue
Block a user