From 6542d207795031520604fb35167883822eb5766d Mon Sep 17 00:00:00 2001 From: Septianata Rizky Pratama Date: Sat, 5 Feb 2022 00:54:40 +0700 Subject: [PATCH] - Composer update - Create method update() on user UpdateRequest class - Modify feature tests - Create branch module on master page (WIP) --- app/Http/Controllers/BranchController.php | 29 +--- app/Http/Controllers/UserController.php | 8 +- app/Http/Requests/Branch/AbstractRequest.php | 27 ++++ app/Http/Requests/Branch/StoreRequest.php | 37 +++++ app/Http/Requests/Branch/UpdateRequest.php | 32 +++++ app/Http/Requests/User/UpdateRequest.php | 17 +++ .../Resources/DataTables/BranchResource.php | 46 ++++++ app/Policies/BranchPolicy.php | 109 +++++++++++++++ composer.lock | 8 +- resources/views/master/branch/index.blade.php | 91 ++++++++++++ routes/web.php | 6 +- tests/Feature/AchievementTest.php | 11 +- tests/Feature/Auth/RegistrationTest.php | 9 +- tests/Feature/DashboardTest.php | 5 +- tests/Feature/EducationTest.php | 21 ++- tests/Feature/MasterTest.php | 132 ++++++++++++++++++ tests/Feature/MonitoringTest.php | 9 +- tests/Feature/ProfileTest.php | 9 +- tests/Pest.php | 12 +- 19 files changed, 541 insertions(+), 77 deletions(-) create mode 100644 app/Http/Requests/Branch/AbstractRequest.php create mode 100644 app/Http/Requests/Branch/StoreRequest.php create mode 100644 app/Http/Requests/Branch/UpdateRequest.php create mode 100644 app/Http/Resources/DataTables/BranchResource.php create mode 100644 app/Policies/BranchPolicy.php create mode 100644 resources/views/master/branch/index.blade.php create mode 100644 tests/Feature/MasterTest.php diff --git a/app/Http/Controllers/BranchController.php b/app/Http/Controllers/BranchController.php index 3008ad6..2b4c7a4 100644 --- a/app/Http/Controllers/BranchController.php +++ b/app/Http/Controllers/BranchController.php @@ -7,10 +7,8 @@ use App\Http\Requests\Branch\UpdateRequest; use App\Http\Resources\DataTables\BranchResource; use App\Models\Branch; -use Illuminate\Auth\Events\Registered; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Event; use Yajra\DataTables\Facades\DataTables; class BranchController extends Controller @@ -46,11 +44,7 @@ public function datatable() return DataTables::eloquent(Branch::query()) ->setTransformer(fn ($model) => BranchResource::make($model)->resolve()) - ->orderColumn('branch_name', function ($query, $direction) { - $query->orderBy('branches.name', $direction); - })->filterColumn('branch_name', function ($query, $keyword) { - $query->where('branches.name', 'like', '%' . $keyword . '%'); - })->toJson(); + ->toJson(); } /** @@ -71,16 +65,7 @@ public function create() */ public function store(StoreRequest $request) { - /** @var \App\Models\Branch $branch */ - $branch = Branch::make($request->validated())->setBranchRelationValue( - $request->getBranch() - ); - - $branch->save(); - - $branch->syncRoles($request->input('role')); - - Event::dispatch(new Registered($branch)); + $request->store(); return redirect()->route('master.branch.index')->with([ 'alert' => [ @@ -109,8 +94,6 @@ public function show(Branch $branch) */ public function edit(Branch $branch) { - $branch->append('role'); - return view('master.branch.edit', compact('branch')); } @@ -123,13 +106,7 @@ public function edit(Branch $branch) */ public function update(UpdateRequest $request, Branch $branch) { - $branch = $branch->fill($request->validated())->setBranchRelationValue( - $request->getBranch() - ); - - $branch->save(); - - $branch->syncRoles($request->input('role')); + $branch = $request->update($branch); return redirect()->route('master.branch.edit', $branch)->with([ 'alert' => [ diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index d3160e6..7281aa7 100644 --- a/app/Http/Controllers/UserController.php +++ b/app/Http/Controllers/UserController.php @@ -120,13 +120,7 @@ public function edit(User $user) */ public function update(UpdateRequest $request, User $user) { - $user = $user->fill($request->validated())->setBranchRelationValue( - $request->getBranch() - ); - - $user->save(); - - $user->syncRoles($request->input('role')); + $user = $request->update($user)->syncRoles($request->input('role')); return redirect()->route('master.user.edit', $user)->with([ 'alert' => [ diff --git a/app/Http/Requests/Branch/AbstractRequest.php b/app/Http/Requests/Branch/AbstractRequest.php new file mode 100644 index 0000000..8db4047 --- /dev/null +++ b/app/Http/Requests/Branch/AbstractRequest.php @@ -0,0 +1,27 @@ +user()); + } + + /** + * {@inheritDoc} + */ + public function attributes() + { + return [ + 'name' => trans('Name'), + 'address' => trans('Address'), + ]; + } +} diff --git a/app/Http/Requests/Branch/StoreRequest.php b/app/Http/Requests/Branch/StoreRequest.php new file mode 100644 index 0000000..75feb5c --- /dev/null +++ b/app/Http/Requests/Branch/StoreRequest.php @@ -0,0 +1,37 @@ + 'required|string|max:255', + 'address' => 'required|string', + ]; + } + + /** + * Store a newly created resource in storage. + * + * @return \App\Models\Branch + */ + public function store(): Branch + { + /** @var \App\Models\Branch $branch */ + $branch = Branch::make($this->validated()); + + $branch->save(); + + return $branch; + } +} diff --git a/app/Http/Requests/Branch/UpdateRequest.php b/app/Http/Requests/Branch/UpdateRequest.php new file mode 100644 index 0000000..44979b7 --- /dev/null +++ b/app/Http/Requests/Branch/UpdateRequest.php @@ -0,0 +1,32 @@ + 'required|string|max:255', + 'address' => 'required|string', + ]; + } + + /** + * Update the specified resource in storage. + * + * @param \App\Models\Branch $branch + * @return \App\Models\Branch + */ + public function update(Branch $branch): Branch + { + $branch->update($this->validated()); + + return $branch; + } +} diff --git a/app/Http/Requests/User/UpdateRequest.php b/app/Http/Requests/User/UpdateRequest.php index 44a9417..a13baef 100644 --- a/app/Http/Requests/User/UpdateRequest.php +++ b/app/Http/Requests/User/UpdateRequest.php @@ -25,4 +25,21 @@ public function rules() 'role' => ['required', Rule::exists(Role::class, 'name')], ]; } + + /** + * Update the specified resource in storage. + * + * @param \App\Models\User $user + * @return \App\Models\User + */ + public function update(User $user): User + { + $user = $user->fill($this->validated())->setBranchRelationValue( + $this->getBranch() + ); + + $user->save(); + + return $user; + } } diff --git a/app/Http/Resources/DataTables/BranchResource.php b/app/Http/Resources/DataTables/BranchResource.php new file mode 100644 index 0000000..76bdcf3 --- /dev/null +++ b/app/Http/Resources/DataTables/BranchResource.php @@ -0,0 +1,46 @@ +user()->can('view', $this->resource)) { + $elements[] = view('components.datatables.link-show', [ + 'url' => route('master.branch.show', $this->resource), + ])->render(); + } + + if ($request->user()->can('update', $this->resource)) { + $elements[] = view('components.datatables.link-edit', [ + 'url' => route('master.branch.edit', $this->resource), + ])->render(); + } + + if ($request->user()->can('delete', $this->resource)) { + $elements[] = view('components.datatables.link-destroy', [ + 'url' => route('master.branch.destroy', $this->resource), + ])->render(); + } + + return [ + 'checkbox' => view('components.datatables.checkbox', [ + 'value' => $this->resource->getKey(), + ])->render(), + 'name' => $this->resource->name, + 'address' => $this->resource->address, + 'action' => view('components.datatables.button-group', compact('elements'))->render(), + ]; + } +} diff --git a/app/Policies/BranchPolicy.php b/app/Policies/BranchPolicy.php new file mode 100644 index 0000000..5981b45 --- /dev/null +++ b/app/Policies/BranchPolicy.php @@ -0,0 +1,109 @@ +hasRole(Role::ROLE_ADMIN)) { + return true; + } + } + + /** + * Determine whether the user can view any models. + * + * @param \App\Models\User $user + * @return \Illuminate\Auth\Access\Response|bool + */ + public function viewAny(User $user) + { + return $user->hasRole(Role::ROLE_STAFF); + } + + /** + * Determine whether the user can view the model. + * + * @param \App\Models\User $user + * @param \App\Models\Branch $branch + * @return \Illuminate\Auth\Access\Response|bool + */ + public function view(User $user, Branch $branch) + { + return $user->branch->is($branch); + } + + /** + * Determine whether the user can create models. + * + * @param \App\Models\User $user + * @return \Illuminate\Auth\Access\Response|bool + */ + public function create(User $user) + { + return false; + } + + /** + * Determine whether the user can update the model. + * + * @param \App\Models\User $user + * @param \App\Models\Branch $branch + * @return \Illuminate\Auth\Access\Response|bool + */ + public function update(User $user, Branch $branch) + { + return false; + } + + /** + * Determine whether the user can delete the model. + * + * @param \App\Models\User $user + * @param \App\Models\Branch $branch + * @return \Illuminate\Auth\Access\Response|bool + */ + public function delete(User $user, Branch $branch) + { + return false; + } + + /** + * Determine whether the user can restore the model. + * + * @param \App\Models\User $user + * @param \App\Models\Branch $branch + * @return \Illuminate\Auth\Access\Response|bool + */ + public function restore(User $user, Branch $branch) + { + return false; + } + + /** + * Determine whether the user can permanently delete the model. + * + * @param \App\Models\User $user + * @param \App\Models\Branch $branch + * @return \Illuminate\Auth\Access\Response|bool + */ + public function forceDelete(User $user, Branch $branch) + { + return false; + } +} diff --git a/composer.lock b/composer.lock index 3dc0c28..987e766 100644 --- a/composer.lock +++ b/composer.lock @@ -6348,12 +6348,12 @@ }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ "src/DeepCopy/deep_copy.php" - ] + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ diff --git a/resources/views/master/branch/index.blade.php b/resources/views/master/branch/index.blade.php new file mode 100644 index 0000000..c107e22 --- /dev/null +++ b/resources/views/master/branch/index.blade.php @@ -0,0 +1,91 @@ +@extends('layouts.admin') + +@section('style') + + +@endsection + +@section('script') + + + + + + +@endsection + +@section('content') +
+
+

@lang('List :name', ['name' => __('menu.branch')])

+ + +
+ +
+ @csrf + +
+
+
+
+
+ @can('create', \App\Models\Branch::class) + + @lang('Add :name', ['name' => __('menu.branch')]) + + @endcan +
+ +
+
+ + + + + + + + + +
@include('components.datatables.checkbox-all')@lang('Name')@lang('Address')@lang('Action')
+
+
+ + +
+
+
+
+
+
+@endsection diff --git a/routes/web.php b/routes/web.php index 0a311fd..05066f1 100755 --- a/routes/web.php +++ b/routes/web.php @@ -32,9 +32,13 @@ Route::post('/datatable', [UserController::class, 'datatable'])->name('datatable'); Route::delete('/multiple', [UserController::class, 'destroyMultiple'])->name('destroy-multiple'); }); + Route::resource('/user', UserController::class); + Route::prefix('/branch')->name('branch.')->group(function () { + Route::post('/datatable', [BranchController::class, 'datatable'])->name('datatable'); + Route::delete('/multiple', [BranchController::class, 'destroyMultiple'])->name('destroy-multiple'); + }); Route::resource('/branch', BranchController::class); - Route::resource('/user', UserController::class); }); Route::prefix('/education')->name('education.')->group(function () { diff --git a/tests/Feature/AchievementTest.php b/tests/Feature/AchievementTest.php index fb72eaf..0250296 100644 --- a/tests/Feature/AchievementTest.php +++ b/tests/Feature/AchievementTest.php @@ -1,32 +1,31 @@ user = User::factory()->forBranch()->create(); + $this->admin = pest_create_admin(); }); it('has achievement index page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('achievement.index')) ->assertOk(); }); it('has achievement dashboard-pencapaian page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('achievement.dashboard-pencapaian')) ->assertOk(); }); it('has achievement dashboard-growth-new-cin page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('achievement.dashboard-growth-new-cin')) ->assertOk(); }); it('has achievement dashboard-penutupan-cin page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('achievement.dashboard-penutupan-cin')) ->assertOk(); }); diff --git a/tests/Feature/Auth/RegistrationTest.php b/tests/Feature/Auth/RegistrationTest.php index a119056..ef081c1 100755 --- a/tests/Feature/Auth/RegistrationTest.php +++ b/tests/Feature/Auth/RegistrationTest.php @@ -19,16 +19,13 @@ public function test_registration_screen_can_be_rendered() public function test_new_users_can_register() { - Event::fake(); - - /** @var \App\Models\Branch $branch */ - $branch = Branch::first(); - /** @var \App\Models\User $user */ $user = User::factory()->make(); + Event::fake(); + $response = $this->post(route('register'), [ - 'branch_id' => $branch->getKey(), + 'branch_id' => Branch::value('id'), 'username' => $user->username, 'name' => $user->name, diff --git a/tests/Feature/DashboardTest.php b/tests/Feature/DashboardTest.php index c6ac601..84a6af0 100644 --- a/tests/Feature/DashboardTest.php +++ b/tests/Feature/DashboardTest.php @@ -1,14 +1,13 @@ user = User::factory()->forBranch()->create(); + $this->admin = pest_create_admin(); }); it('has dashboard page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('dashboard')) ->assertOk(); }); diff --git a/tests/Feature/EducationTest.php b/tests/Feature/EducationTest.php index dd6ad06..996b4f4 100644 --- a/tests/Feature/EducationTest.php +++ b/tests/Feature/EducationTest.php @@ -1,64 +1,63 @@ user = User::factory()->forBranch()->create(); + $this->admin = pest_create_admin(); }); it('has education index page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.index')) ->assertOk(); }); #region webinar-literasi-keuangan it('has education webinar-literasi-keuangan index page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.webinar-literasi-keuangan.index')) ->assertOk(); }); it('has education webinar-literasi-keuangan template-surat-penawaran-webinar page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.webinar-literasi-keuangan.template-surat-penawaran-webinar')) ->assertOk(); }); it('has education webinar-literasi-keuangan template-presentasi-webinar-literasi-keuangan page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.webinar-literasi-keuangan.template-presentasi-webinar-literasi-keuangan')) ->assertOk(); }); it('has education webinar-literasi-keuangan template-rundown-webinar-literasi-keuangan page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.webinar-literasi-keuangan.template-rundown-webinar-literasi-keuangan')) ->assertOk(); }); it('has education webinar-literasi-keuangan pemetaan-sekolah-kampus-potensi-webinar page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.webinar-literasi-keuangan.pemetaan-sekolah-kampus-potensi-webinar')) ->assertOk(); }); it('has education webinar-literasi-keuangan input-rencana-penyelenggaraan-webinar page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.webinar-literasi-keuangan.input-rencana-penyelenggaraan-webinar')) ->assertOk(); }); #endregion webinar-literasi-keuangan it('has education pembukaan-rekening-online page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.pembukaan-rekening-online')) ->assertOk(); }); it('has education employee-get-cin page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('education.employee-get-cin')) ->assertOk(); }); diff --git a/tests/Feature/MasterTest.php b/tests/Feature/MasterTest.php new file mode 100644 index 0000000..a4cc5fc --- /dev/null +++ b/tests/Feature/MasterTest.php @@ -0,0 +1,132 @@ +admin = pest_create_admin(); +}); + +it('has master index page', function () { + actingAs($this->admin) + ->get(route('master.index')) + ->assertOk(); +}); + +#region user +it('has user index page', function () { + actingAs($this->admin) + ->get(route('master.user.index')) + ->assertOk(); +}); + +it('has user create page', function () { + actingAs($this->admin) + ->get(route('master.user.create')) + ->assertOk(); +}); + +it('can store user', function () { + $data = User::factory()->raw(); + $data = array_merge($data, [ + 'branch_id' => Branch::value('id'), + 'password_confirmation' => $data['password'], + 'role' => Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF]), + ]); + + Event::fake(); + + actingAs($this->admin) + ->post(route('master.user.store'), $data) + ->assertRedirect(route('master.user.index')); + + assertDatabaseHas(User::class, Arr::only($data, 'username')); +}); + +it('has user show page', function () { + /** @var \App\Models\User $user */ + $user = User::factory() + ->forBranch() + ->create() + ->syncRoles(Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF])); + + actingAs($this->admin) + ->get(route('master.user.show', $user)) + ->assertOk(); +}); + +it('has user edit page', function () { + /** @var \App\Models\User $user */ + $user = User::factory() + ->forBranch() + ->create() + ->syncRoles(Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF])); + + actingAs($this->admin) + ->get(route('master.user.edit', $user)) + ->assertOk(); +}); + +it('can update user', function () { + /** @var \App\Models\User $user */ + $user = User::factory() + ->forBranch() + ->create() + ->syncRoles(Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF])); + + $data = User::factory()->raw(); + $data = array_merge($data, [ + 'branch_id' => Branch::value('id'), + 'password_confirmation' => $data['password'], + 'role' => Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF]), + ]); + + Event::fake(); + + actingAs($this->admin) + ->put(route('master.user.update', $user), $data) + ->assertRedirect(route('master.user.edit', User::firstWhere('username', $data['username']))); + + assertDatabaseHas(User::class, Arr::only($data, 'username')); +}); + +it('can destroy user', function () { + /** @var \App\Models\User $user */ + $user = User::factory() + ->forBranch() + ->create() + ->syncRoles(Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF])); + + actingAs($this->admin) + ->delete(route('master.user.destroy', $user)) + ->assertRedirect(route('master.user.index')); + + assertDatabaseMissing(User::class, $user->only('id')); +}); + +it('can destroy multiple user', function () { + /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\User> $users */ + $users = User::factory() + ->forBranch() + ->count(rand(1, 1)) + ->create() + ->map(fn (User $user) => $user->syncRoles(Arr::random([Role::ROLE_ADMIN, Role::ROLE_STAFF]))); + + actingAs($this->admin) + ->delete(route('master.user.destroy-multiple', [ + 'checkbox' => $users->pluck('id')->toArray(), + ])) + ->assertRedirect(route('master.user.index')); + + foreach ($users as $user) { + assertDatabaseMissing(User::class, $user->only('id')); + } +}); +#endregion user diff --git a/tests/Feature/MonitoringTest.php b/tests/Feature/MonitoringTest.php index d21b851..c442b17 100644 --- a/tests/Feature/MonitoringTest.php +++ b/tests/Feature/MonitoringTest.php @@ -1,27 +1,26 @@ user = User::factory()->forBranch()->create(); + $this->admin = pest_create_admin(); }); it('has monitoring index page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('monitoring.index')) ->assertOk(); }); #region daily achievement it('has monitoring daily achievement index page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('monitoring.daily-achievement.index')) ->assertOk(); }); it('has monitoring daily achievement create page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('monitoring.daily-achievement.create')) ->assertOk(); }); diff --git a/tests/Feature/ProfileTest.php b/tests/Feature/ProfileTest.php index ae0702c..da9e596 100644 --- a/tests/Feature/ProfileTest.php +++ b/tests/Feature/ProfileTest.php @@ -1,6 +1,5 @@ user = User::factory()->forBranch()->create(); - - $this->user->syncRoles(Role::ROLE_ADMIN); + $this->admin = pest_create_admin(); }); it('has profile edit page', function () { - actingAs($this->user) + actingAs($this->admin) ->get(route('profile.edit')) ->assertOk(); }); @@ -25,7 +22,7 @@ 'password_confirmation' => $data['password'], ]); - actingAs($this->user) + actingAs($this->admin) ->put(route('profile.edit'), $data) ->assertRedirect(route('profile.edit')); diff --git a/tests/Pest.php b/tests/Pest.php index 5d3a73b..96cb231 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -39,7 +39,15 @@ | */ -function something() +/** + * Create user data from factory with "admin" role. + * + * @return \App\Models\User + */ +function pest_create_admin(): App\Models\User { - // .. + return App\Models\User::factory() + ->forBranch() + ->create() + ->syncRoles(App\Models\Role::ROLE_ADMIN); }