Skip to content

Commit 1c4ffe9

Browse files
authored
Merge pull request #195 from fleetbase/fix/prevent-empty-email-phone-on-user-update
fix: prevent empty email/phone on user update
2 parents 8428dcb + 75bdd18 commit 1c4ffe9

2 files changed

Lines changed: 101 additions & 0 deletions

File tree

‎src/Http/Controllers/Internal/v1/UserController.php‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Fleetbase\Exports\UserExport;
99
use Fleetbase\Http\Controllers\FleetbaseController;
1010
use Fleetbase\Http\Requests\CreateUserRequest;
11+
use Fleetbase\Http\Requests\UpdateUserRequest;
1112
use Fleetbase\Http\Requests\ExportRequest;
1213
use Fleetbase\Http\Requests\Internal\AcceptCompanyInvite;
1314
use Fleetbase\Http\Requests\Internal\InviteUserRequest;
@@ -57,6 +58,16 @@ class UserController extends FleetbaseController
5758
*/
5859
public $createRequest = CreateUserRequest::class;
5960

61+
/**
62+
* Update user request.
63+
*
64+
* Enforces that email and phone cannot be set to an empty string
65+
* and that uniqueness constraints are respected on update.
66+
*
67+
* @var UpdateUserRequest
68+
*/
69+
public $updateRequest = UpdateUserRequest::class;
70+
6071
/**
6172
* Creates a record with request payload.
6273
*
@@ -126,6 +137,11 @@ public function createRecord(Request $request)
126137
*/
127138
public function updateRecord(Request $request, string $id)
128139
{
140+
// Run the UpdateUserRequest validation rules before delegating to the
141+
// model trait. This prevents email/phone being set to an empty string
142+
// and enforces uniqueness constraints on partial (PATCH) updates.
143+
$this->validateRequest($request);
144+
129145
try {
130146
$record = $this->model->updateRecordFromRequest($request, $id, function (&$request, &$user) {
131147
// Assign role if set
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace Fleetbase\Http\Requests;
4+
5+
use Fleetbase\Rules\EmailDomainExcluded;
6+
use Fleetbase\Rules\ValidPhoneNumber;
7+
use Illuminate\Validation\Rule;
8+
9+
class UpdateUserRequest extends FleetbaseRequest
10+
{
11+
/**
12+
* Determine if the user is authorized to make this request.
13+
*
14+
* @return bool
15+
*/
16+
public function authorize()
17+
{
18+
return session('company');
19+
}
20+
21+
/**
22+
* Get the validation rules that apply to the request.
23+
*
24+
* Uses `sometimes` + `required` (the correct Laravel pattern for PATCH/PUT):
25+
* - If the field is present in the payload it must pass all rules, including
26+
* `required` which rejects empty strings and null.
27+
* - If the field is absent entirely it is skipped, allowing partial updates.
28+
*
29+
* @return array
30+
*/
31+
public function rules()
32+
{
33+
// Resolve the target user UUID from the route parameter so that the
34+
// uniqueness rules can correctly ignore the user's own current value.
35+
$userId = $this->route('id');
36+
37+
return [
38+
'name' => ['sometimes', 'required', 'string', 'min:2', 'max:100'],
39+
40+
// Email must be a valid address, must not be empty, and must remain
41+
// unique across non-deleted users — ignoring the current user's own row.
42+
'email' => [
43+
'sometimes',
44+
'required',
45+
'string',
46+
'email',
47+
'max:255',
48+
Rule::unique('users', 'email')
49+
->ignore($userId, 'uuid')
50+
->whereNull('deleted_at'),
51+
new EmailDomainExcluded(),
52+
],
53+
54+
// Phone is optional (some user types may not have one), but if it is
55+
// supplied it must be a valid E.164 number and must remain unique.
56+
// `nullable` allows explicit null to clear the field; `required_with`
57+
// is not used here because phone is genuinely optional on some accounts.
58+
'phone' => [
59+
'sometimes',
60+
'nullable',
61+
new ValidPhoneNumber(),
62+
Rule::unique('users', 'phone')
63+
->ignore($userId, 'uuid')
64+
->whereNull('deleted_at'),
65+
],
66+
];
67+
}
68+
69+
/**
70+
* Get the error messages for the defined validation rules.
71+
*
72+
* @return array
73+
*/
74+
public function messages()
75+
{
76+
return [
77+
'name.required' => 'Name cannot be empty.',
78+
'name.min' => 'Name must be at least 2 characters.',
79+
'email.required' => 'Email address cannot be empty.',
80+
'email.email' => 'A valid email address is required.',
81+
'email.unique' => 'An account with this email address already exists.',
82+
'phone.unique' => 'An account with this phone number already exists.',
83+
];
84+
}
85+
}

0 commit comments

Comments
 (0)