From 4841b891091c9d1e0b19daf03091e9ea1ac4a749 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Wed, 13 Nov 2024 12:45:39 -0600 Subject: [PATCH 01/15] scratch code for this issue --- app/Models/Asset.php | 9 +++++++++ app/Models/CustomFieldset.php | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index ce8b870eb..ecf1b1332 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -213,6 +213,15 @@ class Asset extends Depreciable $this->attributes['expected_checkin'] = $value; } + public function withValidator($validator) + { + foreach ($this->customFields as $field) { + if ($field->isEncrypted()) { + Crypt::decrypt($this->value); + } + } + } + /** * This handles the custom field validation for assets * diff --git a/app/Models/CustomFieldset.php b/app/Models/CustomFieldset.php index 71be28e8a..c286005bf 100644 --- a/app/Models/CustomFieldset.php +++ b/app/Models/CustomFieldset.php @@ -92,6 +92,10 @@ class CustomFieldset extends Model $rule[] = 'unique_undeleted'; } + if ($field->hasFormat() && $field->isEncrypted()) { + $rule[] = $rule.'-encrypted'; + } + array_push($rule, $field->attributes['format']); $rules[$field->db_column_name()] = $rule; From 3982201d0e96576d1c262b75258eee49a8b46b92 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Wed, 13 Nov 2024 21:38:09 -0600 Subject: [PATCH 02/15] this should work in theory - local is screwy though --- app/Models/Asset.php | 19 +++++++++++-------- app/Models/CustomFieldset.php | 19 +++++++++++++++---- app/Rules/AlphaEncrypted.php | 28 ++++++++++++++++++++++++++++ app/Rules/NumericEncrypted.php | 28 ++++++++++++++++++++++++++++ 4 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 app/Rules/AlphaEncrypted.php create mode 100644 app/Rules/NumericEncrypted.php diff --git a/app/Models/Asset.php b/app/Models/Asset.php index ecf1b1332..e0c0f45ef 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -12,11 +12,13 @@ use App\Presenters\Presentable; use App\Presenters\AssetPresenter; use Illuminate\Support\Facades\Auth; use Carbon\Carbon; +use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Validator; use Watson\Validating\ValidatingTrait; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; @@ -213,14 +215,15 @@ class Asset extends Depreciable $this->attributes['expected_checkin'] = $value; } - public function withValidator($validator) - { - foreach ($this->customFields as $field) { - if ($field->isEncrypted()) { - Crypt::decrypt($this->value); - } - } - } + // i don't think this will work the way we'd need it to + //public function withValidator(Validator $validator) + //{ + // foreach ($this->customFields as $field) { + // if ($field->field_encrypted) { + // return Crypt::decrypt($this->value); + // } + // } + //} /** * This handles the custom field validation for assets diff --git a/app/Models/CustomFieldset.php b/app/Models/CustomFieldset.php index c286005bf..1059c5d5f 100644 --- a/app/Models/CustomFieldset.php +++ b/app/Models/CustomFieldset.php @@ -2,6 +2,8 @@ namespace App\Models; +use App\Rules\AlphaEncrypted; +use App\Rules\NumericEncrypted; use Gate; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -92,13 +94,20 @@ class CustomFieldset extends Model $rule[] = 'unique_undeleted'; } - if ($field->hasFormat() && $field->isEncrypted()) { - $rule[] = $rule.'-encrypted'; - } - array_push($rule, $field->attributes['format']); $rules[$field->db_column_name()] = $rule; + + if ($field->format === 'NUMERIC' && $field->field_encrypted) { + $numericKey = array_search('numeric', $rules[$field->db_column_name()]); + $rules[$field->db_column_name()][$numericKey] = new NumericEncrypted; + } + + if ($field->format === 'ALPHA' && $field->field_encrypted) { + $alphaKey = array_search('alpha', $rules[$field->db_column_name()]); + $rules[$field->db_column_name()][$alphaKey] = new AlphaEncrypted; + } + // add not_array to rules for all fields but checkboxes if ($field->element != 'checkbox') { $rules[$field->db_column_name()][] = 'not_array'; @@ -113,6 +122,8 @@ class CustomFieldset extends Model } } + dump($rules); + return $rules; } } diff --git a/app/Rules/AlphaEncrypted.php b/app/Rules/AlphaEncrypted.php new file mode 100644 index 000000000..246d92f0b --- /dev/null +++ b/app/Rules/AlphaEncrypted.php @@ -0,0 +1,28 @@ +getMessage()); + } + } +} diff --git a/app/Rules/NumericEncrypted.php b/app/Rules/NumericEncrypted.php new file mode 100644 index 000000000..f36c4174e --- /dev/null +++ b/app/Rules/NumericEncrypted.php @@ -0,0 +1,28 @@ +getMessage()); + } + } +} From 25163d1756f31d77c42fb0961c506ee0e6c59562 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Wed, 13 Nov 2024 21:46:23 -0600 Subject: [PATCH 03/15] =?UTF-8?q?working=20except=20for=20null=20?= =?UTF-8?q?=F0=9F=A4=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Rules/AlphaEncrypted.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Rules/AlphaEncrypted.php b/app/Rules/AlphaEncrypted.php index 246d92f0b..5e0ffcbd5 100644 --- a/app/Rules/AlphaEncrypted.php +++ b/app/Rules/AlphaEncrypted.php @@ -19,7 +19,7 @@ class AlphaEncrypted implements ValidationRule $decrypted = Crypt::decrypt($value); dump($decrypted); if (!ctype_alpha($decrypted)) { - $fail($attribute.' is not numeric.'); + $fail($attribute.' is not alphabetic.'); } } catch (\Exception $e) { $fail($e->getMessage()); From 7e7cbc4cc8024c7a54304d69222e4a7be308ef0a Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Wed, 13 Nov 2024 21:54:25 -0600 Subject: [PATCH 04/15] seems to work just fine now, needs translations --- app/Rules/AlphaEncrypted.php | 6 +++--- app/Rules/NumericEncrypted.php | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/Rules/AlphaEncrypted.php b/app/Rules/AlphaEncrypted.php index 5e0ffcbd5..048c66371 100644 --- a/app/Rules/AlphaEncrypted.php +++ b/app/Rules/AlphaEncrypted.php @@ -17,12 +17,12 @@ class AlphaEncrypted implements ValidationRule { try { $decrypted = Crypt::decrypt($value); - dump($decrypted); - if (!ctype_alpha($decrypted)) { + if (!ctype_alpha($decrypted) && !is_null($decrypted)) { $fail($attribute.' is not alphabetic.'); } } catch (\Exception $e) { - $fail($e->getMessage()); + report($e); + $fail('something went wrong.'); } } } diff --git a/app/Rules/NumericEncrypted.php b/app/Rules/NumericEncrypted.php index f36c4174e..bef4aad5e 100644 --- a/app/Rules/NumericEncrypted.php +++ b/app/Rules/NumericEncrypted.php @@ -16,13 +16,15 @@ class NumericEncrypted implements ValidationRule */ public function validate(string $attribute, mixed $value, Closure $fail): void { + try { - $value = Crypt::decrypt($value); - if (!is_numeric($value)) { + $decrypted = Crypt::decrypt($value); + if (!is_numeric($decrypted) && !is_null($decrypted)) { $fail($attribute.' is not numeric.'); } } catch (\Exception $e) { - $fail($e->getMessage()); + report($e->getMessage()); + $fail('something went wrong'); } } } From 8c6869fd3466a4be722f108cc5f80fafe87d0404 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Wed, 13 Nov 2024 21:59:32 -0600 Subject: [PATCH 05/15] note and rm dump and comment --- app/Models/Asset.php | 10 ---------- app/Models/CustomFieldset.php | 4 ++-- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index e0c0f45ef..aa6a96d41 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -215,16 +215,6 @@ class Asset extends Depreciable $this->attributes['expected_checkin'] = $value; } - // i don't think this will work the way we'd need it to - //public function withValidator(Validator $validator) - //{ - // foreach ($this->customFields as $field) { - // if ($field->field_encrypted) { - // return Crypt::decrypt($this->value); - // } - // } - //} - /** * This handles the custom field validation for assets * diff --git a/app/Models/CustomFieldset.php b/app/Models/CustomFieldset.php index 1059c5d5f..d6bd7a1be 100644 --- a/app/Models/CustomFieldset.php +++ b/app/Models/CustomFieldset.php @@ -98,6 +98,8 @@ class CustomFieldset extends Model $rules[$field->db_column_name()] = $rule; + // these are to replace the standard 'numeric' and 'alpha' rules if the custom field is also encrypted. + // the values need to be decrypted first, because encrypted strings are alphanumeric if ($field->format === 'NUMERIC' && $field->field_encrypted) { $numericKey = array_search('numeric', $rules[$field->db_column_name()]); $rules[$field->db_column_name()][$numericKey] = new NumericEncrypted; @@ -122,8 +124,6 @@ class CustomFieldset extends Model } } - dump($rules); - return $rules; } } From 95cd7793343a65b08b1a6ef7b1d1d02df6fe7b43 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Thu, 14 Nov 2024 11:42:35 -0600 Subject: [PATCH 06/15] translations and attribute names --- app/Rules/AlphaEncrypted.php | 3 ++- app/Rules/NumericEncrypted.php | 3 ++- resources/lang/en-US/validation.php | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/Rules/AlphaEncrypted.php b/app/Rules/AlphaEncrypted.php index 048c66371..102e03dd6 100644 --- a/app/Rules/AlphaEncrypted.php +++ b/app/Rules/AlphaEncrypted.php @@ -16,9 +16,10 @@ class AlphaEncrypted implements ValidationRule public function validate(string $attribute, mixed $value, Closure $fail): void { try { + $attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute)); $decrypted = Crypt::decrypt($value); if (!ctype_alpha($decrypted) && !is_null($decrypted)) { - $fail($attribute.' is not alphabetic.'); + $fail(trans('validation.custom.alpha_encrypted', ['attribute' => $attributeName])); } } catch (\Exception $e) { report($e); diff --git a/app/Rules/NumericEncrypted.php b/app/Rules/NumericEncrypted.php index bef4aad5e..c4bf865f3 100644 --- a/app/Rules/NumericEncrypted.php +++ b/app/Rules/NumericEncrypted.php @@ -18,9 +18,10 @@ class NumericEncrypted implements ValidationRule { try { + $attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute)); $decrypted = Crypt::decrypt($value); if (!is_numeric($decrypted) && !is_null($decrypted)) { - $fail($attribute.' is not numeric.'); + $fail(trans('validation.custom.numeric_encrypted', ['attribute' => $attributeName])); } } catch (\Exception $e) { report($e->getMessage()); diff --git a/resources/lang/en-US/validation.php b/resources/lang/en-US/validation.php index 7d7840eb4..d054c8b43 100644 --- a/resources/lang/en-US/validation.php +++ b/resources/lang/en-US/validation.php @@ -187,6 +187,8 @@ return [ 'custom' => [ 'alpha_space' => 'The :attribute field contains a character that is not allowed.', + 'alpha_encrypted' => 'The :attribute field should be alphabetic characters.', + 'numeric_encrypted' => 'The :attribute field should be numeric characters.', 'email_array' => 'One or more email addresses is invalid.', 'hashed_pass' => 'Your current password is incorrect', 'dumbpwd' => 'That password is too common.', From 846580653664ff2b0b046abc8fc959bb44ce0ed3 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Thu, 14 Nov 2024 11:51:41 -0600 Subject: [PATCH 07/15] rm unnecessary imports --- app/Models/Asset.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/Models/Asset.php b/app/Models/Asset.php index aa6a96d41..ce8b870eb 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -12,13 +12,11 @@ use App\Presenters\Presentable; use App\Presenters\AssetPresenter; use Illuminate\Support\Facades\Auth; use Carbon\Carbon; -use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; -use Illuminate\Support\Facades\Validator; use Watson\Validating\ValidatingTrait; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; From 124f9c84c203ef30bcbee73665de5ae0bdfea804 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Thu, 14 Nov 2024 13:45:47 -0600 Subject: [PATCH 08/15] oops, something went wrong translation --- app/Rules/AlphaEncrypted.php | 2 +- app/Rules/NumericEncrypted.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Rules/AlphaEncrypted.php b/app/Rules/AlphaEncrypted.php index 102e03dd6..b39a5fedb 100644 --- a/app/Rules/AlphaEncrypted.php +++ b/app/Rules/AlphaEncrypted.php @@ -23,7 +23,7 @@ class AlphaEncrypted implements ValidationRule } } catch (\Exception $e) { report($e); - $fail('something went wrong.'); + $fail(trans('general.something_went_wrong')); } } } diff --git a/app/Rules/NumericEncrypted.php b/app/Rules/NumericEncrypted.php index c4bf865f3..4121ce517 100644 --- a/app/Rules/NumericEncrypted.php +++ b/app/Rules/NumericEncrypted.php @@ -25,7 +25,7 @@ class NumericEncrypted implements ValidationRule } } catch (\Exception $e) { report($e->getMessage()); - $fail('something went wrong'); + $fail(trans('general.something_went_wrong')); } } } From 22602c7997a98764ebb8b6473adc95d22d5d3569 Mon Sep 17 00:00:00 2001 From: spencerrlongg Date: Tue, 19 Nov 2024 08:59:47 -0600 Subject: [PATCH 09/15] use existing validation strings --- app/Rules/AlphaEncrypted.php | 2 +- app/Rules/NumericEncrypted.php | 2 +- resources/lang/en-US/validation.php | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/Rules/AlphaEncrypted.php b/app/Rules/AlphaEncrypted.php index b39a5fedb..f4ed1d6c3 100644 --- a/app/Rules/AlphaEncrypted.php +++ b/app/Rules/AlphaEncrypted.php @@ -19,7 +19,7 @@ class AlphaEncrypted implements ValidationRule $attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute)); $decrypted = Crypt::decrypt($value); if (!ctype_alpha($decrypted) && !is_null($decrypted)) { - $fail(trans('validation.custom.alpha_encrypted', ['attribute' => $attributeName])); + $fail(trans('validation.alpha', ['attribute' => $attributeName])); } } catch (\Exception $e) { report($e); diff --git a/app/Rules/NumericEncrypted.php b/app/Rules/NumericEncrypted.php index 4121ce517..f3cb3ba76 100644 --- a/app/Rules/NumericEncrypted.php +++ b/app/Rules/NumericEncrypted.php @@ -21,7 +21,7 @@ class NumericEncrypted implements ValidationRule $attributeName = trim(preg_replace('/_+|snipeit|\d+/', ' ', $attribute)); $decrypted = Crypt::decrypt($value); if (!is_numeric($decrypted) && !is_null($decrypted)) { - $fail(trans('validation.custom.numeric_encrypted', ['attribute' => $attributeName])); + $fail(trans('validation.numeric', ['attribute' => $attributeName])); } } catch (\Exception $e) { report($e->getMessage()); diff --git a/resources/lang/en-US/validation.php b/resources/lang/en-US/validation.php index d054c8b43..7d7840eb4 100644 --- a/resources/lang/en-US/validation.php +++ b/resources/lang/en-US/validation.php @@ -187,8 +187,6 @@ return [ 'custom' => [ 'alpha_space' => 'The :attribute field contains a character that is not allowed.', - 'alpha_encrypted' => 'The :attribute field should be alphabetic characters.', - 'numeric_encrypted' => 'The :attribute field should be numeric characters.', 'email_array' => 'One or more email addresses is invalid.', 'hashed_pass' => 'Your current password is incorrect', 'dumbpwd' => 'That password is too common.', From 1e513312eb32e56070b3750180c47601d2384800 Mon Sep 17 00:00:00 2001 From: akemidx Date: Tue, 19 Nov 2024 16:58:10 -0500 Subject: [PATCH 10/15] adding colon to password translation --- resources/lang/en-US/mail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/en-US/mail.php b/resources/lang/en-US/mail.php index 76c0c1773..626d50f4e 100644 --- a/resources/lang/en-US/mail.php +++ b/resources/lang/en-US/mail.php @@ -67,7 +67,7 @@ return [ 'name' => 'Name', 'new_item_checked' => 'A new item has been checked out under your name, details are below.', 'notes' => 'Notes', - 'password' => 'Password', + 'password' => 'Password:', 'password_reset' => 'Password Reset', 'read_the_terms' => 'Please read the terms of use below.', 'read_the_terms_and_click' => 'Please read the terms of use below, and click on the link at the bottom to confirm that you read and agree to the terms of use, and have received the asset.', From 59fe53842da8d0aa8ade15865e341606781b63f3 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 19 Nov 2024 16:11:23 -0800 Subject: [PATCH 11/15] Add tests around component check ins via api --- .../Checkins/Api/ComponentCheckinTest.php | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 tests/Feature/Checkins/Api/ComponentCheckinTest.php diff --git a/tests/Feature/Checkins/Api/ComponentCheckinTest.php b/tests/Feature/Checkins/Api/ComponentCheckinTest.php new file mode 100644 index 000000000..845ed8acc --- /dev/null +++ b/tests/Feature/Checkins/Api/ComponentCheckinTest.php @@ -0,0 +1,164 @@ +checkedOutToAsset()->create(); + + $this->actingAsForApi(User::factory()->create()) + ->postJson(route('api.components.checkin', $component->assets->first()->pivot->id)) + ->assertForbidden(); + } + + public function testHandlesNonExistentPivotId() + { + $this->actingAsForApi(User::factory()->checkinComponents()->create()) + ->postJson(route('api.components.checkin', 1000), [ + 'checkin_qty' => 1, + ]) + ->assertOk() + ->assertStatusMessageIs('error'); + } + + public function testHandlesNonExistentComponent() + { + $component = Component::factory()->checkedOutToAsset()->create(); + $pivotId = $component->assets->first()->pivot->id; + $component->delete(); + + $this->actingAsForApi(User::factory()->checkinComponents()->create()) + ->postJson(route('api.components.checkin', $pivotId), [ + 'checkin_qty' => 1, + ]) + ->assertOk() + ->assertStatusMessageIs('error'); + } + + public function testCannotCheckinMoreThanCheckedOut() + { + $component = Component::factory()->checkedOutToAsset()->create(); + + $pivot = $component->assets->first()->pivot; + $pivot->update(['assigned_qty' => 2]); + + $this->actingAsForApi(User::factory()->checkinComponents()->create()) + ->postJson(route('api.components.checkin', $component->assets->first()->pivot->id), [ + 'checkin_qty' => 3, + ]) + ->assertOk() + ->assertStatusMessageIs('error'); + } + + public function testCanCheckinComponent() + { + Event::fake([CheckoutableCheckedIn::class]); + + $user = User::factory()->checkinComponents()->create(); + + $component = Component::factory()->checkedOutToAsset()->create(); + $pivot = $component->assets->first()->pivot; + $pivot->update(['assigned_qty' => 3]); + + + $this->actingAsForApi($user) + ->postJson(route('api.components.checkin', $component->assets->first()->pivot->id), [ + 'checkin_qty' => 2, + 'note' => 'my note', + ]) + ->assertOk() + ->assertStatusMessageIs('success'); + + $this->assertEquals(1, $component->fresh()->assets->first()->pivot->assigned_qty); + + Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($user, $component) { + return $event->checkoutable->is($component) + && $event->checkedOutTo->is($component->assets->first()) + && $event->checkedInBy->is($user) + && $event->note === 'my note'; + }); + } + + public function testCheckingInEntireAssignedQuantityClearsThePivotRecordFromTheDatabase() + { + Event::fake([CheckoutableCheckedIn::class]); + + $user = User::factory()->checkinComponents()->create(); + + $component = Component::factory()->checkedOutToAsset()->create(); + $pivot = $component->assets->first()->pivot; + $pivot->update(['assigned_qty' => 3]); + + $this->actingAsForApi($user) + ->postJson(route('api.components.checkin', $component->assets->first()->pivot->id), [ + 'checkin_qty' => 3, + 'note' => 'my note', + ]) + ->assertOk() + ->assertStatusMessageIs('success'); + + $this->assertEmpty($component->fresh()->assets); + + Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($user, $component) { + return $event->checkoutable->is($component) + && $event->checkedOutTo->is($component->assets->first()) + && $event->checkedInBy->is($user) + && $event->note === 'my note'; + }); + } + + public function testAdheresToFullMultipleCompaniesSupportScoping() + { + $this->settings->enableMultipleFullCompanySupport(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $componentInCompanyA = Component::factory()->for($companyA)->checkedOutToAsset()->create(); + $userInCompanyB = User::factory()->for($companyB)->create(); + $pivotId = $componentInCompanyA->assets->first()->pivot->id; + + $this->actingAsForApi($userInCompanyB) + ->postJson(route('api.components.checkin', $pivotId), [ + 'checkin_qty' => 1, + ]) + ->assertOk() + ->assertStatusMessageIs('error'); + } + + public function testCheckinIsLogged() + { + $user = User::factory()->checkinComponents()->create(); + + $component = Component::factory()->checkedOutToAsset()->create(); + $pivot = $component->assets->first()->pivot; + $pivot->update(['assigned_qty' => 3]); + + $this->actingAsForApi($user) + ->postJson(route('api.components.checkin', $component->assets->first()->pivot->id), [ + 'checkin_qty' => 3, + 'note' => 'my note', + ]); + + $this->assertDatabaseHas('action_logs', [ + 'created_by' => $user->id, + 'action_type' => 'checkin from', + 'target_id' => $component->assets->first()->id, + 'target_type' => Asset::class, + 'note' => 'my note', + 'item_id' => $component->id, + 'item_type' => Component::class, + ]); + } +} From e8cad0df692ecba6967fb41763574ad8b08877c3 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 19 Nov 2024 16:13:30 -0800 Subject: [PATCH 12/15] Formatting --- app/Http/Controllers/Api/ComponentsController.php | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 8ee5b80e8..93ad101ff 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -309,9 +309,7 @@ class ComponentsController extends Controller public function checkin(Request $request, $component_asset_id) : JsonResponse { if ($component_assets = DB::table('components_assets')->find($component_asset_id)) { - if (is_null($component = Component::find($component_assets->component_id))) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/components/message.not_found'))); } @@ -320,7 +318,6 @@ class ComponentsController extends Controller $max_to_checkin = $component_assets->assigned_qty; if ($max_to_checkin > 1) { - $validator = Validator::make($request->all(), [ "checkin_qty" => "required|numeric|between:1,$max_to_checkin" ]); @@ -329,7 +326,6 @@ class ComponentsController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, 'Checkin quantity must be between 1 and '.$max_to_checkin)); } } - // Validation passed, so let's figure out what we have to do here. $qty_remaining_in_checkout = ($component_assets->assigned_qty - (int)$request->input('checkin_qty', 1)); @@ -339,28 +335,23 @@ class ComponentsController extends Controller $component_assets->assigned_qty = $qty_remaining_in_checkout; Log::debug($component_asset_id.' - '.$qty_remaining_in_checkout.' remaining in record '.$component_assets->id); - - DB::table('components_assets')->where('id', - $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]); + + DB::table('components_assets')->where('id', $component_asset_id)->update(['assigned_qty' => $qty_remaining_in_checkout]); // If the checked-in qty is exactly the same as the assigned_qty, // we can simply delete the associated components_assets record if ($qty_remaining_in_checkout == 0) { DB::table('components_assets')->where('id', '=', $component_asset_id)->delete(); } - $asset = Asset::find($component_assets->asset_id); event(new CheckoutableCheckedIn($component, $asset, auth()->user(), $request->input('note'), Carbon::now())); return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/components/message.checkin.success'))); - } return response()->json(Helper::formatStandardApiResponse('error', null, 'No matching checkouts for that component join record')); - - } } From da4c877ed8b75c8f9bc92218dd1d57b64c5d7a68 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Tue, 19 Nov 2024 16:13:53 -0800 Subject: [PATCH 13/15] Use === over == --- app/Http/Controllers/Api/ComponentsController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 93ad101ff..cd1e31f96 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -340,7 +340,7 @@ class ComponentsController extends Controller // If the checked-in qty is exactly the same as the assigned_qty, // we can simply delete the associated components_assets record - if ($qty_remaining_in_checkout == 0) { + if ($qty_remaining_in_checkout === 0) { DB::table('components_assets')->where('id', '=', $component_asset_id)->delete(); } From f932a4fc76a3a8102bb39baba971388a57b6d8b9 Mon Sep 17 00:00:00 2001 From: Marcus Moore Date: Wed, 20 Nov 2024 12:25:06 -0800 Subject: [PATCH 14/15] Always run validation on checkin --- app/Http/Controllers/Api/ComponentsController.php | 14 ++++++-------- .../Feature/Checkins/Api/ComponentCheckinTest.php | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index cd1e31f96..0f594f5e7 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -317,14 +317,12 @@ class ComponentsController extends Controller $max_to_checkin = $component_assets->assigned_qty; - if ($max_to_checkin > 1) { - $validator = Validator::make($request->all(), [ - "checkin_qty" => "required|numeric|between:1,$max_to_checkin" - ]); - - if ($validator->fails()) { - return response()->json(Helper::formatStandardApiResponse('error', null, 'Checkin quantity must be between 1 and '.$max_to_checkin)); - } + $validator = Validator::make($request->all(), [ + "checkin_qty" => "required|numeric|between:1,$max_to_checkin" + ]); + + if ($validator->fails()) { + return response()->json(Helper::formatStandardApiResponse('error', null, 'Checkin quantity must be between 1 and ' . $max_to_checkin)); } // Validation passed, so let's figure out what we have to do here. diff --git a/tests/Feature/Checkins/Api/ComponentCheckinTest.php b/tests/Feature/Checkins/Api/ComponentCheckinTest.php index 845ed8acc..0497a8135 100644 --- a/tests/Feature/Checkins/Api/ComponentCheckinTest.php +++ b/tests/Feature/Checkins/Api/ComponentCheckinTest.php @@ -52,7 +52,7 @@ class ComponentCheckinTest extends TestCase implements TestsFullMultipleCompanie $component = Component::factory()->checkedOutToAsset()->create(); $pivot = $component->assets->first()->pivot; - $pivot->update(['assigned_qty' => 2]); + $pivot->update(['assigned_qty' => 1]); $this->actingAsForApi(User::factory()->checkinComponents()->create()) ->postJson(route('api.components.checkin', $component->assets->first()->pivot->id), [ From 424316df9f75d9654e71c6fcebc4d6ca75d5bfc9 Mon Sep 17 00:00:00 2001 From: akemidx Date: Thu, 21 Nov 2024 14:32:22 -0500 Subject: [PATCH 15/15] fixing colon placements --- resources/lang/en-US/mail.php | 4 ++-- resources/views/notifications/FirstAdmin.blade.php | 4 ++-- resources/views/notifications/Welcome.blade.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/lang/en-US/mail.php b/resources/lang/en-US/mail.php index 626d50f4e..7663a0167 100644 --- a/resources/lang/en-US/mail.php +++ b/resources/lang/en-US/mail.php @@ -60,14 +60,14 @@ return [ 'item_checked_reminder' => 'This is a reminder that you currently have :count items checked out to you that you have not accepted or declined. Please click the link below to confirm your decision.', 'license_expiring_alert' => 'There is :count license expiring in the next :threshold days.|There are :count licenses expiring in the next :threshold days.', 'link_to_update_password' => 'Please click on the following link to update your :web password:', - 'login' => 'Login:', + 'login' => 'Login', 'login_first_admin' => 'Login to your new Snipe-IT installation using the credentials below:', 'low_inventory_alert' => 'There is :count item that is below minimum inventory or will soon be low.|There are :count items that are below minimum inventory or will soon be low.', 'min_QTY' => 'Min QTY', 'name' => 'Name', 'new_item_checked' => 'A new item has been checked out under your name, details are below.', 'notes' => 'Notes', - 'password' => 'Password:', + 'password' => 'Password', 'password_reset' => 'Password Reset', 'read_the_terms' => 'Please read the terms of use below.', 'read_the_terms_and_click' => 'Please read the terms of use below, and click on the link at the bottom to confirm that you read and agree to the terms of use, and have received the asset.', diff --git a/resources/views/notifications/FirstAdmin.blade.php b/resources/views/notifications/FirstAdmin.blade.php index b6d8e89db..83a5c8bf0 100644 --- a/resources/views/notifications/FirstAdmin.blade.php +++ b/resources/views/notifications/FirstAdmin.blade.php @@ -1,8 +1,8 @@ @component('mail::message') {{ trans('mail.hello') }} {{ $first_name }} {{$last_name}}, -{{ trans('mail.login') }} {{ $username }}
-{{ trans('mail.password') }} {{ $password }} +{{ trans('mail.login') }}: {{ $username }}
+{{ trans('mail.password') }}: {{ $password }} @component('mail::button', ['url' => $url]) Go To {{$snipeSettings->site_name}} diff --git a/resources/views/notifications/Welcome.blade.php b/resources/views/notifications/Welcome.blade.php index 82dcd3e15..e6e72ad2c 100644 --- a/resources/views/notifications/Welcome.blade.php +++ b/resources/views/notifications/Welcome.blade.php @@ -3,8 +3,8 @@ {{ trans('mail.admin_has_created', ['web' => $snipeSettings->site_name]) }} -{{ trans('mail.login') }} {{ $username }}
-{{ trans('mail.password') }} {{ $password }} +{{ trans('mail.login') }}: {{ $username }}
+{{ trans('mail.password') }}: {{ $password }} @component('mail::button', ['url' => $url]) Go To {{$snipeSettings->site_name}}