Stricter validation for uuid and integer

This commit is contained in:
Constantin Graf
2024-10-15 10:59:53 +02:00
committed by Constantin Graf
parent 2b1da883fb
commit 69d3ff4f7b
31 changed files with 187 additions and 122 deletions

View File

@@ -45,7 +45,7 @@ class CreateNewUser implements CreatesNewUsers
'string',
'email',
'max:255',
new UniqueEloquent(User::class, 'email', function (Builder $builder): Builder {
UniqueEloquent::make(User::class, 'email', function (Builder $builder): Builder {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
}),

View File

@@ -35,7 +35,7 @@ class UpdateUserProfileInformation implements UpdatesUserProfileInformation
'required',
'email',
'max:255',
(new UniqueEloquent(User::class, 'email'))->ignore($user->id)->query(function (Builder $query) {
UniqueEloquent::make(User::class, 'email')->ignore($user->id)->query(function (Builder $query) {
/** @var Builder<User> $query */
return $query->where('is_placeholder', '=', false);
}),

View File

@@ -71,10 +71,10 @@ class AddOrganizationMember implements AddsTeamMembers
'email' => [
'required',
'email',
(new ExistsEloquent(User::class, 'email', function (Builder $builder) {
ExistsEloquent::make(User::class, 'email', function (Builder $builder) {
/** @var Builder<User> $builder */
return $builder->where('is_placeholder', '=', false);
}))->withMessage(__('We were unable to find a registered user with this email address.')),
})->withMessage(__('We were unable to find a registered user with this email address.')),
],
'role' => [
'required',

View File

@@ -70,6 +70,7 @@ class OrganizationResource extends Resource
'nullable',
'integer',
'gt:0',
'max:2147483647',
])
->numeric(),
Forms\Components\DateTimePicker::make('created_at')

View File

@@ -29,6 +29,7 @@ class ProjectMemberResource extends Resource
'nullable',
'integer',
'gt:0',
'max:2147483647',
])
->numeric(),
Forms\Components\Select::make('user_id')

View File

@@ -45,6 +45,7 @@ class ProjectResource extends Resource
'nullable',
'integer',
'gt:0',
'max:2147483647',
])
->numeric(),
Forms\Components\Select::make('organization_id')

View File

@@ -20,6 +20,7 @@ class ClientIndexRequest extends FormRequest
'page' => [
'integer',
'min:1',
'max:2147483647',
],
'archived' => [
'string',

View File

@@ -29,10 +29,10 @@ class ClientStoreRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Client::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Client::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->withCustomTranslation('validation.client_name_already_exists'),
})->withCustomTranslation('validation.client_name_already_exists'),
],
];
}

View File

@@ -31,10 +31,10 @@ class ClientUpdateRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Client::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Client::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->ignore($this->client?->getKey())->withCustomTranslation('validation.client_name_already_exists'),
})->ignore($this->client?->getKey())->withCustomTranslation('validation.client_name_already_exists'),
],
'is_archived' => [
'boolean',

View File

@@ -29,10 +29,10 @@ class InvitationStoreRequest extends FormRequest
'email' => [
'required',
'email',
(new UniqueEloquent(OrganizationInvitation::class, 'email', function (Builder $builder): Builder {
UniqueEloquent::make(OrganizationInvitation::class, 'email', function (Builder $builder): Builder {
/** @var Builder<OrganizationInvitation> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->withCustomTranslation('validation.invitation_already_exists'),
})->withCustomTranslation('validation.invitation_already_exists'),
],
'role' => [
'required',

View File

@@ -31,6 +31,7 @@ class MemberUpdateRequest extends FormRequest
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -30,6 +30,7 @@ class OrganizationUpdateRequest extends FormRequest
'nullable',
'integer',
'min:0',
'max:2147483647',
],
'employees_can_see_billable_rates' => [
'boolean',

View File

@@ -20,6 +20,7 @@ class ProjectIndexRequest extends FormRequest
'page' => [
'integer',
'min:1',
'max:2147483647',
],
'archived' => [
'string',

View File

@@ -32,10 +32,10 @@ class ProjectStoreRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Project::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Project::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->withCustomTranslation('validation.project_name_already_exists'),
})->withCustomTranslation('validation.project_name_already_exists'),
],
'color' => [
'required',
@@ -51,20 +51,22 @@ class ProjectStoreRequest extends FormRequest
'nullable',
'integer',
'min:0',
'max:2147483647',
],
// ID of the client
'client_id' => [
'nullable',
new ExistsEloquent(Client::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Estimated time in seconds
'estimated_time' => [
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -32,10 +32,10 @@ class ProjectUpdateRequest extends FormRequest
'required',
'string',
'max:255',
(new UniqueEloquent(Project::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Project::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->ignore($this->project?->getKey())->withCustomTranslation('validation.project_name_already_exists'),
})->ignore($this->project?->getKey())->withCustomTranslation('validation.project_name_already_exists'),
],
'color' => [
'required',
@@ -52,21 +52,23 @@ class ProjectUpdateRequest extends FormRequest
],
'client_id' => [
'nullable',
new ExistsEloquent(Client::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
'billable_rate' => [
'nullable',
'integer',
'min:0',
'max:2147483647',
],
// Estimated time in seconds
'estimated_time' => [
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -26,16 +26,16 @@ class ProjectMemberStoreRequest extends FormRequest
return [
'member_id' => [
'required',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
'billable_rate' => [
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -25,6 +25,7 @@ class ProjectMemberUpdateRequest extends FormRequest
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -29,10 +29,10 @@ class TagStoreRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Tag::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Tag::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->withCustomTranslation('validation.tag_name_already_exists'),
})->withCustomTranslation('validation.tag_name_already_exists'),
],
];
}

View File

@@ -30,10 +30,10 @@ class TagUpdateRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Tag::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Tag::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}))->ignore($this->tag?->getKey())->withCustomTranslation('validation.tag_name_already_exists'),
})->ignore($this->tag?->getKey())->withCustomTranslation('validation.tag_name_already_exists'),
],
];
}

View File

@@ -27,8 +27,7 @@ class TaskIndexRequest extends FormRequest
{
return [
'project_id' => [
'uuid',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
$builder = $builder->whereBelongsTo($this->organization, 'organization');
@@ -37,7 +36,7 @@ class TaskIndexRequest extends FormRequest
}
return $builder;
}),
})->uuid(),
],
'done' => [
'string',

View File

@@ -31,23 +31,24 @@ class TaskStoreRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Task::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Task::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->where('project_id', '=', $this->input('project_id'));
}))->withCustomTranslation('validation.task_name_already_exists'),
})->withCustomTranslation('validation.task_name_already_exists'),
],
'project_id' => [
'required',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Estimated time in seconds
'estimated_time' => [
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -30,10 +30,10 @@ class TaskUpdateRequest extends FormRequest
'string',
'min:1',
'max:255',
(new UniqueEloquent(Task::class, 'name', function (Builder $builder): Builder {
UniqueEloquent::make(Task::class, 'name', function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->where('project_id', '=', $this->task->project_id);
}))->ignore($this->task?->getKey())->withCustomTranslation('validation.task_name_already_exists'),
})->ignore($this->task?->getKey())->withCustomTranslation('validation.task_name_already_exists'),
],
'is_done' => [
'boolean',
@@ -43,6 +43,7 @@ class TaskUpdateRequest extends FormRequest
'nullable',
'integer',
'min:0',
'max:2147483647',
],
];
}

View File

@@ -45,11 +45,10 @@ class TimeEntryAggregateRequest extends FormRequest
// Filter by member ID
'member_id' => [
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by multiple member IDs, member IDs are OR combined, but AND combined with the member_id parameter
'member_ids' => [
@@ -58,21 +57,19 @@ class TimeEntryAggregateRequest extends FormRequest
],
'member_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by user ID
'user_id' => [
'string',
'uuid',
new ExistsEloquent(User::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(User::class, null, function (Builder $builder): Builder {
/** @var Builder<User> $builder */
return $builder->belongsToOrganization($this->organization);
}),
})->uuid(),
],
// Filter by project IDs, project IDs are OR combined
'project_ids' => [
@@ -81,11 +78,10 @@ class TimeEntryAggregateRequest extends FormRequest
],
'project_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by client IDs, client IDs are OR combined
'client_ids' => [
@@ -94,11 +90,10 @@ class TimeEntryAggregateRequest extends FormRequest
],
'client_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Client::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by tag IDs, tag IDs are AND combined
'tag_ids' => [
@@ -107,11 +102,10 @@ class TimeEntryAggregateRequest extends FormRequest
],
'tag_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Tag::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Tag::class, null, function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by task IDs, task IDs are OR combined
'task_ids' => [
@@ -120,10 +114,9 @@ class TimeEntryAggregateRequest extends FormRequest
],
'task_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter only time entries that have a start date after the given timestamp in UTC (example: 2021-01-01T00:00:00Z)
'start' => [

View File

@@ -31,11 +31,10 @@ class TimeEntryIndexRequest extends FormRequest
// Filter by member ID
'member_id' => [
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by multiple member IDs, member IDs are OR combined, but AND combined with the member_id parameter
'member_ids' => [
@@ -44,11 +43,10 @@ class TimeEntryIndexRequest extends FormRequest
],
'member_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by client IDs, client IDs are OR combined
'client_ids' => [
@@ -57,11 +55,10 @@ class TimeEntryIndexRequest extends FormRequest
],
'client_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Client::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Client::class, null, function (Builder $builder): Builder {
/** @var Builder<Client> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by project IDs, project IDs are OR combined
'project_ids' => [
@@ -70,11 +67,10 @@ class TimeEntryIndexRequest extends FormRequest
],
'project_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by tag IDs, tag IDs are AND combined
'tag_ids' => [
@@ -83,11 +79,10 @@ class TimeEntryIndexRequest extends FormRequest
],
'tag_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Tag::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Tag::class, null, function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter by task IDs, task IDs are OR combined
'task_ids' => [
@@ -96,11 +91,10 @@ class TimeEntryIndexRequest extends FormRequest
],
'task_ids.*' => [
'string',
'uuid',
new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// Filter only time entries that have a start date after the given timestamp in UTC (example: 2021-01-01T00:00:00Z)
'start' => [
@@ -135,6 +129,7 @@ class TimeEntryIndexRequest extends FormRequest
'offset' => [
'integer',
'min:0',
'max:2147483647',
],
// Filter makes sure that only time entries of a whole date are returned
'only_full_dates' => [

View File

@@ -31,36 +31,33 @@ class TimeEntryStoreRequest extends FormRequest
'member_id' => [
'required',
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
'project_id' => [
'nullable',
'string',
'uuid',
'required_with:task_id',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// ID of the task that the time entry should belong to
'task_id' => [
'nullable',
'string',
'uuid',
new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
(new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
})->uuid(),
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization')
->where('project_id', $this->input('project_id'));
}))->withMessage(__('validation.task_belongs_to_project')),
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
],
// Start of time entry (ISO 8601 format, UTC timezone)
'start' => [
@@ -90,12 +87,10 @@ class TimeEntryStoreRequest extends FormRequest
'array',
],
'tags.*' => [
'string',
'uuid',
new ExistsEloquent(Tag::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Tag::class, null, function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
];
}

View File

@@ -42,37 +42,34 @@ class TimeEntryUpdateMultipleRequest extends FormRequest
// ID of the organization member that the time entry should belong to
'changes.member_id' => [
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// ID of the project that the time entry should belong to
'changes.project_id' => [
'nullable',
'string',
'uuid',
'required_with:task_id',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// ID of the task that the time entry should belong to
'changes.task_id' => [
'nullable',
'string',
'uuid',
new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
(new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
})->uuid(),
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization')
->where('project_id', $this->input('changes.project_id'));
}))->withMessage(__('validation.task_belongs_to_project')),
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
],
// Whether time entry is billable
'changes.billable' => [
@@ -91,11 +88,10 @@ class TimeEntryUpdateMultipleRequest extends FormRequest
],
'changes.tags.*' => [
'string',
'uuid',
new ExistsEloquent(Tag::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Tag::class, null, function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
];
}

View File

@@ -30,37 +30,34 @@ class TimeEntryUpdateRequest extends FormRequest
// ID of the organization member that the time entry should belong to
'member_id' => [
'string',
'uuid',
new ExistsEloquent(Member::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Member::class, null, function (Builder $builder): Builder {
/** @var Builder<Member> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// ID of the project that the time entry should belong to
'project_id' => [
'nullable',
'string',
'uuid',
'required_with:task_id',
new ExistsEloquent(Project::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Project::class, null, function (Builder $builder): Builder {
/** @var Builder<Project> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
// ID of the task that the time entry should belong to
'task_id' => [
'nullable',
'string',
'uuid',
new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
(new ExistsEloquent(Task::class, null, function (Builder $builder): Builder {
})->uuid(),
ExistsEloquent::make(Task::class, null, function (Builder $builder): Builder {
/** @var Builder<Task> $builder */
return $builder->whereBelongsTo($this->organization, 'organization')
->where('project_id', $this->input('project_id'));
}))->withMessage(__('validation.task_belongs_to_project')),
})->uuid()->withMessage(__('validation.task_belongs_to_project')),
],
// Start of time entry (ISO 8601 format, UTC timezone)
'start' => [
@@ -89,11 +86,10 @@ class TimeEntryUpdateRequest extends FormRequest
],
'tags.*' => [
'string',
'uuid',
new ExistsEloquent(Tag::class, null, function (Builder $builder): Builder {
ExistsEloquent::make(Tag::class, null, function (Builder $builder): Builder {
/** @var Builder<Tag> $builder */
return $builder->whereBelongsTo($this->organization, 'organization');
}),
})->uuid(),
],
];
}

View File

@@ -112,6 +112,7 @@ abstract class DefaultImporter implements ImporterContract
'billable_rate' => [
'nullable',
'integer',
'max:2147483647',
],
], beforeSave: function (Project $project): void {
if ($project->billable_rate === 0) {
@@ -125,6 +126,7 @@ abstract class DefaultImporter implements ImporterContract
'billable_rate' => [
'nullable',
'integer',
'max:2147483647',
],
], beforeSave: function (ProjectMember $projectMember): void {
if ($projectMember->billable_rate === 0) {

12
composer.lock generated
View File

@@ -3480,16 +3480,16 @@
},
{
"name": "korridor/laravel-model-validation-rules",
"version": "3.1.0",
"version": "3.2.0",
"source": {
"type": "git",
"url": "https://github.com/korridor/laravel-model-validation-rules.git",
"reference": "49370c70cc2b25d1b80252160ba3ab435828c95a"
"reference": "e7c27b976eefd383de10a5195e8c986815ac43a4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/korridor/laravel-model-validation-rules/zipball/49370c70cc2b25d1b80252160ba3ab435828c95a",
"reference": "49370c70cc2b25d1b80252160ba3ab435828c95a",
"url": "https://api.github.com/repos/korridor/laravel-model-validation-rules/zipball/e7c27b976eefd383de10a5195e8c986815ac43a4",
"reference": "e7c27b976eefd383de10a5195e8c986815ac43a4",
"shasum": ""
},
"require": {
@@ -3538,9 +3538,9 @@
],
"support": {
"issues": "https://github.com/korridor/laravel-model-validation-rules/issues",
"source": "https://github.com/korridor/laravel-model-validation-rules/tree/3.1.0"
"source": "https://github.com/korridor/laravel-model-validation-rules/tree/3.2.0"
},
"time": "2024-02-28T15:07:15+00:00"
"time": "2024-10-14T16:58:38+00:00"
},
{
"name": "lab404/laravel-impersonate",

View File

@@ -284,6 +284,60 @@ class ProjectEndpointTest extends ApiEndpointTestAbstract
$response->assertForbidden();
}
public function test_store_endpoint_highest_possible_billable_rate_can_be_stored_in_database(): void
{
// Arrange
$billableRate = 2147483647;
$data = $this->createUserWithPermission([
'projects:create',
]);
$projectFake = Project::factory()->forOrganization($data->organization)->make();
Passport::actingAs($data->user);
// Act
$response = $this->postJson(route('api.v1.projects.store', [$data->organization->getKey()]), [
'name' => $projectFake->name,
'color' => $projectFake->color,
'is_billable' => $projectFake->is_billable,
'billable_rate' => $billableRate,
]);
// Assert
$response->assertStatus(201);
$this->assertDatabaseHas(Project::class, [
'name' => $projectFake->name,
'color' => $projectFake->color,
'organization_id' => $projectFake->organization_id,
'is_billable' => $projectFake->is_billable,
'billable_rate' => $billableRate,
]);
}
public function test_store_endpoint_fails_if_billable_rate_is_too_high(): void
{
// Arrange
$billableRate = 2147483647 + 1;
$data = $this->createUserWithPermission([
'projects:create',
]);
$projectFake = Project::factory()->forOrganization($data->organization)->make();
Passport::actingAs($data->user);
// Act
$response = $this->postJson(route('api.v1.projects.store', [$data->organization->getKey()]), [
'name' => $projectFake->name,
'color' => $projectFake->color,
'is_billable' => $projectFake->is_billable,
'billable_rate' => $billableRate,
]);
// Assert
$response->assertStatus(422);
$response->assertJsonValidationErrors([
'billable_rate' => 'The billable rate field must not be greater than 2147483647.',
]);
}
public function test_store_endpoint_creates_new_project(): void
{
// Arrange

View File

@@ -958,6 +958,27 @@ class TimeEntryEndpointTest extends ApiEndpointTestAbstract
]);
}
public function test_store_endpoint_fails_gracefully_if_non_uuid_text_is_in_uuid_validated_field_in_body(): void
{
// Arrange
$data = $this->createUserWithPermission([
'time-entries:create:own',
]);
$timeEntryFake = TimeEntry::factory()->withTask($data->organization)->forOrganization($data->organization)->make();
Passport::actingAs($data->user);
// Act
$response = $this->postJson(route('api.v1.time-entries.store', [$data->organization->getKey()]), [
'member_id' => 'non-uuid-text',
'tags' => ['non-uuid-text', 1],
'project_id' => 'non-uuid-text',
'task_id' => 'non-uuid-text',
]);
// Assert
$response->assertStatus(422);
}
public function test_store_endpoints_sets_billable_rate(): void
{
// Arrange