From 2f27c83411c686b6e2995a30cfabb8e13a3000d0 Mon Sep 17 00:00:00 2001 From: EwelinaLasowy Date: Wed, 13 Apr 2022 11:40:44 +0200 Subject: [PATCH 01/12] #118 - wip --- app/Eloquent/Models/Key.php | 37 ++++ .../Http/Controllers/KeysController.php | 23 +++ .../Http/Resources/KeyResource.php | 22 +++ database/factories/KeyFactory.php | 22 +++ .../2022_04_12_152528_create_keys_table.php | 25 +++ database/seeders/DatabaseSeeder.php | 8 + resources/js/Pages/Keys/Index.vue | 162 ++++++++++++++++++ resources/js/Shared/MainMenu.vue | 10 +- routes/web.php | 2 + 9 files changed, 310 insertions(+), 1 deletion(-) create mode 100644 app/Eloquent/Models/Key.php create mode 100644 app/Infrastructure/Http/Controllers/KeysController.php create mode 100644 app/Infrastructure/Http/Resources/KeyResource.php create mode 100644 database/factories/KeyFactory.php create mode 100644 database/migrations/2022_04_12_152528_create_keys_table.php create mode 100644 resources/js/Pages/Keys/Index.vue diff --git a/app/Eloquent/Models/Key.php b/app/Eloquent/Models/Key.php new file mode 100644 index 0000000..5488f19 --- /dev/null +++ b/app/Eloquent/Models/Key.php @@ -0,0 +1,37 @@ +belongsTo(User::class, "owner_id"); + } + + public function previousOwner(): BelongsTo + { + return $this->belongsTo(User::class, "previous_owner_id"); + } + + protected static function newFactory(): KeyFactory + { + return KeyFactory::new(); + } +} diff --git a/app/Infrastructure/Http/Controllers/KeysController.php b/app/Infrastructure/Http/Controllers/KeysController.php new file mode 100644 index 0000000..c7711d0 --- /dev/null +++ b/app/Infrastructure/Http/Controllers/KeysController.php @@ -0,0 +1,23 @@ +get(); + + return inertia("Keys/Index", [ + "keys" => KeyResource::collection($keys), + ]); + } +} diff --git a/app/Infrastructure/Http/Resources/KeyResource.php b/app/Infrastructure/Http/Resources/KeyResource.php new file mode 100644 index 0000000..0b5da33 --- /dev/null +++ b/app/Infrastructure/Http/Resources/KeyResource.php @@ -0,0 +1,22 @@ + $this->id, + "owner" => new UserResource($this->owner), + "previousOwner" => new UserResource($this->previousOwner), + "updatedAt" => $this->updated_at->toDatetimeString(), + ]; + } +} diff --git a/database/factories/KeyFactory.php b/database/factories/KeyFactory.php new file mode 100644 index 0000000..4a3007b --- /dev/null +++ b/database/factories/KeyFactory.php @@ -0,0 +1,22 @@ + User::factory(), + "previous_owner_id" => User::factory(), + ]; + } +} diff --git a/database/migrations/2022_04_12_152528_create_keys_table.php b/database/migrations/2022_04_12_152528_create_keys_table.php new file mode 100644 index 0000000..de8b97f --- /dev/null +++ b/database/migrations/2022_04_12_152528_create_keys_table.php @@ -0,0 +1,25 @@ +id(); + $table->foreignIdFor(User::class, "owner_id")->constrained("users")->cascadeOnDelete(); + $table->foreignIdFor(User::class, "previous_owner_id")->constrained("users")->cascadeOnDelete(); + $table->timestamps(); + }); + } + + public function down(): void + { + Schema::dropIfExists("keys"); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 581ecfd..5225924 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -8,6 +8,7 @@ use Illuminate\Database\Seeder; use Illuminate\Support\Carbon; use Toby\Domain\PolishHolidaysRetriever; use Toby\Domain\VacationDaysCalculator; +use Toby\Eloquent\Models\Key; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationLimit; use Toby\Eloquent\Models\VacationRequest; @@ -85,5 +86,12 @@ class DatabaseSeeder extends Seeder }) ->create(); } + + foreach ($users as $user) { + Key::factory() + ->for($user, "owner") + ->for($user, "previousOwner") + ->create(); + } } } diff --git a/resources/js/Pages/Keys/Index.vue b/resources/js/Pages/Keys/Index.vue new file mode 100644 index 0000000..607f5ad --- /dev/null +++ b/resources/js/Pages/Keys/Index.vue @@ -0,0 +1,162 @@ + + +s diff --git a/resources/js/Shared/MainMenu.vue b/resources/js/Shared/MainMenu.vue index 799caec..48e3f33 100644 --- a/resources/js/Shared/MainMenu.vue +++ b/resources/js/Shared/MainMenu.vue @@ -282,6 +282,7 @@ import { CalendarIcon, DocumentTextIcon, AdjustmentsIcon, + KeyIcon, } from '@heroicons/vue/outline' import { CheckIcon, ChevronDownIcon } from '@heroicons/vue/solid' @@ -337,7 +338,6 @@ const navigation = computed(() => can: props.auth.can.manageVacationLimits, }, { - name: 'Podsumowanie roczne', href: '/vacation/annual-summary', component: 'AnnualSummary', @@ -351,5 +351,13 @@ const navigation = computed(() => icon: UserGroupIcon, can: props.auth.can.manageUsers, }, + { + name: 'Klucze', + href: '/keys', + component: 'Keys/Index', + icon: KeyIcon, + can: true, + }, + ].filter(item => item.can)) diff --git a/routes/web.php b/routes/web.php index 7b103b0..a641d59 100644 --- a/routes/web.php +++ b/routes/web.php @@ -7,6 +7,7 @@ use Toby\Infrastructure\Http\Controllers\AnnualSummaryController; use Toby\Infrastructure\Http\Controllers\DashboardController; use Toby\Infrastructure\Http\Controllers\GoogleController; use Toby\Infrastructure\Http\Controllers\HolidayController; +use Toby\Infrastructure\Http\Controllers\KeysController; use Toby\Infrastructure\Http\Controllers\LogoutController; use Toby\Infrastructure\Http\Controllers\MonthlyUsageController; use Toby\Infrastructure\Http\Controllers\SelectYearPeriodController; @@ -28,6 +29,7 @@ Route::middleware("auth")->group(function (): void { Route::resource("holidays", HolidayController::class); Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class) ->name("year-periods.select"); + Route::resource("keys", KeysController::class); Route::prefix("/vacation")->as("vacation.")->group(function (): void { Route::get("/limits", [VacationLimitController::class, "edit"]) -- 2.52.0 From e3998238efd5fc93c85945a0eacade5e90f73aaf Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Thu, 14 Apr 2022 14:29:36 +0200 Subject: [PATCH 02/12] #118 - keys --- .../Providers/AuthServiceProvider.php | 3 + app/Domain/Policies/KeyPolicy.php | 26 ++ app/Eloquent/Models/Key.php | 12 +- app/Eloquent/Models/User.php | 5 + .../Http/Controllers/KeysController.php | 71 +++- .../Http/Requests/GiveKeyRequest.php | 23 ++ .../Http/Resources/KeyResource.php | 7 +- database/factories/KeyFactory.php | 3 +- .../2022_04_12_152528_create_keys_table.php | 5 +- database/seeders/DemoSeeder.php | 7 + resources/js/Pages/Keys.vue | 349 ++++++++++++++++++ resources/js/Pages/Keys/Index.vue | 162 -------- routes/web.php | 9 +- 13 files changed, 499 insertions(+), 183 deletions(-) create mode 100644 app/Domain/Policies/KeyPolicy.php create mode 100644 app/Infrastructure/Http/Requests/GiveKeyRequest.php create mode 100644 resources/js/Pages/Keys.vue delete mode 100644 resources/js/Pages/Keys/Index.vue diff --git a/app/Architecture/Providers/AuthServiceProvider.php b/app/Architecture/Providers/AuthServiceProvider.php index afa2b3b..cb5b112 100644 --- a/app/Architecture/Providers/AuthServiceProvider.php +++ b/app/Architecture/Providers/AuthServiceProvider.php @@ -7,7 +7,9 @@ namespace Toby\Architecture\Providers; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Gate; use Toby\Domain\Enums\Role; +use Toby\Domain\Policies\KeyPolicy; use Toby\Domain\Policies\VacationRequestPolicy; +use Toby\Eloquent\Models\Key; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationRequest; @@ -15,6 +17,7 @@ class AuthServiceProvider extends ServiceProvider { protected $policies = [ VacationRequest::class => VacationRequestPolicy::class, + Key::class => KeyPolicy::class, ]; public function boot(): void diff --git a/app/Domain/Policies/KeyPolicy.php b/app/Domain/Policies/KeyPolicy.php new file mode 100644 index 0000000..cb62986 --- /dev/null +++ b/app/Domain/Policies/KeyPolicy.php @@ -0,0 +1,26 @@ +role === Role::AdministrativeApprover; + } + + public function give(User $user, Key $key): bool + { + if ($key->user()->is($user)) { + return true; + } + + return $user->role === Role::AdministrativeApprover; + } +} diff --git a/app/Eloquent/Models/Key.php b/app/Eloquent/Models/Key.php index 5488f19..cb7ee23 100644 --- a/app/Eloquent/Models/Key.php +++ b/app/Eloquent/Models/Key.php @@ -11,8 +11,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; /** * @property int $id - * @property User $owner - * @property User $previousOwner + * @property User $user */ class Key extends Model { @@ -20,14 +19,9 @@ class Key extends Model protected $guarded = []; - public function owner(): BelongsTo + public function user(): BelongsTo { - return $this->belongsTo(User::class, "owner_id"); - } - - public function previousOwner(): BelongsTo - { - return $this->belongsTo(User::class, "previous_owner_id"); + return $this->belongsTo(User::class); } protected static function newFactory(): KeyFactory diff --git a/app/Eloquent/Models/User.php b/app/Eloquent/Models/User.php index d167dd5..4bf2891 100644 --- a/app/Eloquent/Models/User.php +++ b/app/Eloquent/Models/User.php @@ -74,6 +74,11 @@ class User extends Authenticatable return $this->hasMany(Vacation::class); } + public function keys(): HasMany + { + return $this->hasMany(Key::class); + } + public function hasRole(Role $role): bool { return $this->role === $role; diff --git a/app/Infrastructure/Http/Controllers/KeysController.php b/app/Infrastructure/Http/Controllers/KeysController.php index c7711d0..6fa2940 100644 --- a/app/Infrastructure/Http/Controllers/KeysController.php +++ b/app/Infrastructure/Http/Controllers/KeysController.php @@ -4,20 +4,83 @@ declare(strict_types=1); namespace Toby\Infrastructure\Http\Controllers; +use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\Request; use Inertia\Response; -use Toby\Eloquent\Helpers\YearPeriodRetriever; +use Symfony\Component\HttpFoundation\RedirectResponse; use Toby\Eloquent\Models\Key; +use Toby\Eloquent\Models\User; +use Toby\Infrastructure\Http\Requests\GiveKeyRequest; use Toby\Infrastructure\Http\Resources\KeyResource; +use Toby\Infrastructure\Http\Resources\SimpleUserResource; class KeysController extends Controller { - public function index(Request $request, YearPeriodRetriever $yearPeriodRetriever): Response + public function index(Request $request): Response { - $keys = Key::query()->get(); + $keys = Key::query() + ->oldest() + ->get(); - return inertia("Keys/Index", [ + $users = User::query() + ->where("id", "!=", $request->user()->id) + ->orderByProfileField("last_name") + ->orderByProfileField("first_name") + ->get(); + + return inertia("Keys", [ "keys" => KeyResource::collection($keys), + "users" => SimpleUserResource::collection($users), + "can" => [ + "manageKeys" => $request->user()->can("manage", Key::class), + ], ]); } + + /** + * @throws AuthorizationException + */ + public function store(Request $request): RedirectResponse + { + $this->authorize("manageKeys"); + + $request->user()->keys()->create(); + + return redirect() + ->back() + ->with("success", __("Key has been created.")); + } + + public function take(Key $key, Request $request): RedirectResponse + { + $key->user()->associate($request->user()); + + $key->save(); + + return redirect() + ->back() + ->with("success", __("Key has been taked.")); + } + + public function give(Key $key, GiveKeyRequest $request): RedirectResponse + { + $key->user()->associate($request->recipient()); + + $key->save(); + + return redirect() + ->back() + ->with("success", __("Key has been given.")); + } + + public function destroy(Key $key): RedirectResponse + { + $this->authorize("manageKeys"); + + $key->delete(); + + return redirect() + ->back() + ->with("success", __("Key has been deleted.")); + } } diff --git a/app/Infrastructure/Http/Requests/GiveKeyRequest.php b/app/Infrastructure/Http/Requests/GiveKeyRequest.php new file mode 100644 index 0000000..7505821 --- /dev/null +++ b/app/Infrastructure/Http/Requests/GiveKeyRequest.php @@ -0,0 +1,23 @@ + ["required", "exists:users,id"], + ]; + } + + public function recipient(): User + { + return User::find($this->get("user")); + } +} diff --git a/app/Infrastructure/Http/Resources/KeyResource.php b/app/Infrastructure/Http/Resources/KeyResource.php index 0b5da33..d6ee471 100644 --- a/app/Infrastructure/Http/Resources/KeyResource.php +++ b/app/Infrastructure/Http/Resources/KeyResource.php @@ -14,9 +14,12 @@ class KeyResource extends JsonResource { return [ "id" => $this->id, - "owner" => new UserResource($this->owner), - "previousOwner" => new UserResource($this->previousOwner), + "user" => new SimpleUserResource($this->user), "updatedAt" => $this->updated_at->toDatetimeString(), + "can" => [ + "give" => $request->user()->can("give", $this->resource), + "take" => !$this->user()->is($request->user()), + ], ]; } } diff --git a/database/factories/KeyFactory.php b/database/factories/KeyFactory.php index 4a3007b..52e1694 100644 --- a/database/factories/KeyFactory.php +++ b/database/factories/KeyFactory.php @@ -15,8 +15,7 @@ class KeyFactory extends Factory public function definition(): array { return [ - "owner_id" => User::factory(), - "previous_owner_id" => User::factory(), + "user_id" => User::factory(), ]; } } diff --git a/database/migrations/2022_04_12_152528_create_keys_table.php b/database/migrations/2022_04_12_152528_create_keys_table.php index de8b97f..1d3ee72 100644 --- a/database/migrations/2022_04_12_152528_create_keys_table.php +++ b/database/migrations/2022_04_12_152528_create_keys_table.php @@ -12,8 +12,9 @@ return new class() extends Migration { { Schema::create("keys", function (Blueprint $table): void { $table->id(); - $table->foreignIdFor(User::class, "owner_id")->constrained("users")->cascadeOnDelete(); - $table->foreignIdFor(User::class, "previous_owner_id")->constrained("users")->cascadeOnDelete(); + $table->foreignIdFor(User::class) + ->constrained() + ->cascadeOnDelete(); $table->timestamps(); }); } diff --git a/database/seeders/DemoSeeder.php b/database/seeders/DemoSeeder.php index 53454e2..41470ba 100644 --- a/database/seeders/DemoSeeder.php +++ b/database/seeders/DemoSeeder.php @@ -19,6 +19,7 @@ use Toby\Domain\States\VacationRequest\Rejected; use Toby\Domain\States\VacationRequest\WaitingForAdministrative; use Toby\Domain\States\VacationRequest\WaitingForTechnical; use Toby\Domain\VacationDaysCalculator; +use Toby\Eloquent\Models\Key; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationLimit; use Toby\Eloquent\Models\VacationRequest; @@ -328,5 +329,11 @@ class DemoSeeder extends Seeder $vacationRequestRejected->state = new Rejected($vacationRequestRejected); $vacationRequestRejected->save(); + + foreach ($users as $user) { + Key::factory() + ->for($user) + ->create(); + } } } diff --git a/resources/js/Pages/Keys.vue b/resources/js/Pages/Keys.vue new file mode 100644 index 0000000..fb1e025 --- /dev/null +++ b/resources/js/Pages/Keys.vue @@ -0,0 +1,349 @@ + + + diff --git a/resources/js/Pages/Keys/Index.vue b/resources/js/Pages/Keys/Index.vue deleted file mode 100644 index 607f5ad..0000000 --- a/resources/js/Pages/Keys/Index.vue +++ /dev/null @@ -1,162 +0,0 @@ - - -s diff --git a/routes/web.php b/routes/web.php index 950fdb1..f35e8f6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -34,10 +34,15 @@ Route::middleware(["auth", TrackUserLastActivity::class])->group(function (): vo ->except("show") ->whereNumber("holiday"); - Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class) + Route::get("/keys", [KeysController::class, "index"]); + Route::post("/keys", [KeysController::class, "store"]); + Route::delete("/keys/{key}", [KeysController::class, "destroy"]); + Route::post("/keys/{key}/take", [KeysController::class, "take"]); + Route::post("/keys/{key}/give", [KeysController::class, "give"]); + + Route::post("/year-periods/{yearPeriod}/select", SelectYearPeriodController::class) ->whereNumber("yearPeriod") ->name("year-periods.select"); - Route::resource("keys", KeysController::class); Route::prefix("/vacation")->as("vacation.")->group(function (): void { Route::get("/limits", [VacationLimitController::class, "edit"]) -- 2.52.0 From 734efa5554443c0cf2af75d5aabf5d9b626add0a Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Thu, 14 Apr 2022 14:41:43 +0200 Subject: [PATCH 03/12] #118 - fix --- app/Infrastructure/Http/Controllers/KeysController.php | 1 - resources/js/Pages/Keys.vue | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/Infrastructure/Http/Controllers/KeysController.php b/app/Infrastructure/Http/Controllers/KeysController.php index 6fa2940..5b3ba57 100644 --- a/app/Infrastructure/Http/Controllers/KeysController.php +++ b/app/Infrastructure/Http/Controllers/KeysController.php @@ -23,7 +23,6 @@ class KeysController extends Controller ->get(); $users = User::query() - ->where("id", "!=", $request->user()->id) ->orderByProfileField("last_name") ->orderByProfileField("first_name") ->get(); diff --git a/resources/js/Pages/Keys.vue b/resources/js/Pages/Keys.vue index fb1e025..ce16156 100644 --- a/resources/js/Pages/Keys.vue +++ b/resources/js/Pages/Keys.vue @@ -242,7 +242,7 @@ class="overflow-auto absolute z-10 py-1 mt-1 w-full max-w-lg max-h-60 text-base bg-white rounded-md focus:outline-none ring-1 ring-black ring-opacity-5 shadow-lg sm:text-sm" > props.users.data.filter(user => user.id !== keyToGive.value.user.id )) + function giveKey(key) { keyToGive.value = key + form.user = filteredUsers.value[0] giving.value = true } -- 2.52.0 From 7e0ecc36680375f7189fbaced37c427686ba175f Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Thu, 14 Apr 2022 14:42:24 +0200 Subject: [PATCH 04/12] #118 - fix menu --- resources/js/Shared/MainMenu.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/Shared/MainMenu.vue b/resources/js/Shared/MainMenu.vue index caab738..dc7305e 100644 --- a/resources/js/Shared/MainMenu.vue +++ b/resources/js/Shared/MainMenu.vue @@ -368,7 +368,7 @@ const navigation = computed(() => { name: 'Klucze', href: '/keys', - component: 'Keys/Index', + section: 'Keys', icon: KeyIcon, can: true, }, -- 2.52.0 From cb7e150717c145cc6964e19e740a1036e82fec44 Mon Sep 17 00:00:00 2001 From: EwelinaLasowy Date: Fri, 15 Apr 2022 11:01:23 +0200 Subject: [PATCH 05/12] #118 - fix to policies and added translations --- app/Architecture/Providers/AuthServiceProvider.php | 1 + app/Infrastructure/Http/Controllers/KeysController.php | 2 +- resources/js/Pages/Keys.vue | 3 +-- resources/lang/pl.json | 6 +++++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/Architecture/Providers/AuthServiceProvider.php b/app/Architecture/Providers/AuthServiceProvider.php index cb5b112..e57ef42 100644 --- a/app/Architecture/Providers/AuthServiceProvider.php +++ b/app/Architecture/Providers/AuthServiceProvider.php @@ -35,5 +35,6 @@ class AuthServiceProvider extends ServiceProvider Gate::define("manageVacationLimits", fn(User $user) => $user->role === Role::AdministrativeApprover); Gate::define("generateTimesheet", fn(User $user) => $user->role === Role::AdministrativeApprover); Gate::define("listMonthlyUsage", fn(User $user) => $user->role === Role::AdministrativeApprover); + Gate::define("manageKeys", fn(User $user) => $user->role === Role::AdministrativeApprover); } } diff --git a/app/Infrastructure/Http/Controllers/KeysController.php b/app/Infrastructure/Http/Controllers/KeysController.php index 5b3ba57..7e63a5a 100644 --- a/app/Infrastructure/Http/Controllers/KeysController.php +++ b/app/Infrastructure/Http/Controllers/KeysController.php @@ -58,7 +58,7 @@ class KeysController extends Controller return redirect() ->back() - ->with("success", __("Key has been taked.")); + ->with("success", __("Key has been taken.")); } public function give(Key $key, GiveKeyRequest $request): RedirectResponse diff --git a/resources/js/Pages/Keys.vue b/resources/js/Pages/Keys.vue index ce16156..f8b3807 100644 --- a/resources/js/Pages/Keys.vue +++ b/resources/js/Pages/Keys.vue @@ -75,7 +75,7 @@ - {{ DateTime.fromSQL(key.updatedAt).toRelative() }} + {{ key.updatedAt }} Date: Wed, 20 Apr 2022 08:44:41 +0200 Subject: [PATCH 06/12] #118 - wip --- app/Infrastructure/Http/Resources/KeyResource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Infrastructure/Http/Resources/KeyResource.php b/app/Infrastructure/Http/Resources/KeyResource.php index d6ee471..7eedbf7 100644 --- a/app/Infrastructure/Http/Resources/KeyResource.php +++ b/app/Infrastructure/Http/Resources/KeyResource.php @@ -15,7 +15,7 @@ class KeyResource extends JsonResource return [ "id" => $this->id, "user" => new SimpleUserResource($this->user), - "updatedAt" => $this->updated_at->toDatetimeString(), + "updatedAt" => $this->updated_at->toDisplayString(), "can" => [ "give" => $request->user()->can("give", $this->resource), "take" => !$this->user()->is($request->user()), -- 2.52.0 From 64032a7c730e0816c7e0fe1d2afe1efcf914897f Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Wed, 20 Apr 2022 12:44:27 +0200 Subject: [PATCH 07/12] #118 - tests --- resources/js/Pages/Keys.vue | 2 +- tests/Feature/KeysTest.php | 118 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/KeysTest.php diff --git a/resources/js/Pages/Keys.vue b/resources/js/Pages/Keys.vue index f8b3807..647c2e0 100644 --- a/resources/js/Pages/Keys.vue +++ b/resources/js/Pages/Keys.vue @@ -27,7 +27,7 @@ scope="col" class="py-3 px-4 text-xs font-semibold tracking-wider text-left text-gray-500 uppercase whitespace-nowrap" > - Nazwa + Klucz count(10)->create(); + $user = User::factory()->create(); + + $this->assertDatabaseCount("keys", 10); + + $this->actingAs($user) + ->get("/keys") + ->assertOk() + ->assertInertia( + fn(Assert $page) => $page + ->component("Keys") + ->has("keys.data", 10), + ); + } + + public function testAdminCanCreateKey(): void + { + $admin = User::factory()->admin()->create(); + + $this->assertDatabaseMissing("keys", [ + "user_id" => $admin->id, + ]); + + $this->actingAs($admin) + ->post("/keys") + ->assertSessionHasNoErrors() + ->assertRedirect(); + + $this->assertDatabaseHas("keys", [ + "user_id" => $admin->id, + ]); + } + + public function testUserCannotCreateKey(): void + { + $user = User::factory()->create(); + + $this->actingAs($user) + ->post("/keys") + ->assertForbidden(); + } + + public function testAdminCanDeleteKey(): void + { + $admin = User::factory()->admin()->create(); + + $key = Key::factory()->create(); + + $this->actingAs($admin) + ->delete("/keys/{$key->id}") + ->assertRedirect(); + } + + public function testUserCanTakeKeyFromAnotherUser(): void + { + $user = User::factory()->create(); + $userWithKey = User::factory()->create(); + + $key = Key::factory()->for($userWithKey)->create(); + + $this->assertDatabaseHas("keys", [ + "id" => $key->id, + "user_id" => $userWithKey->id, + ]); + + $this->actingAs($user) + ->post("/keys/{$key->id}/take") + ->assertRedirect(); + + $this->assertDatabaseHas("keys", [ + "id" => $key->id, + "user_id" => $user->id, + ]); + } + + public function testUserCanGiveTheirKeyToAnotherUser(): void + { + $userWithKey = User::factory()->create(); + $user = User::factory()->create(); + + $key = Key::factory()->for($userWithKey)->create(); + + $this->assertDatabaseHas("keys", [ + "id" => $key->id, + "user_id" => $userWithKey->id, + ]); + + $this->actingAs($userWithKey) + ->post("/keys/{$key->id}/give", [ + "user" => $user->id, + ]) + ->assertSessionhasNoErrors() + ->assertRedirect(); + + $this->assertDatabaseHas("keys", [ + "id" => $key->id, + "user_id" => $user->id, + ]); + } +} -- 2.52.0 From 624465e352786738be5d69a6acf50b14135f8ee8 Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Wed, 20 Apr 2022 12:50:48 +0200 Subject: [PATCH 08/12] #118 - fix --- .../Providers/AuthServiceProvider.php | 1 - .../Http/Controllers/KeysController.php | 26 ++++++++++++++----- database/seeders/DatabaseSeeder.php | 1 - resources/lang/pl.json | 8 +++--- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/Architecture/Providers/AuthServiceProvider.php b/app/Architecture/Providers/AuthServiceProvider.php index e57ef42..cb5b112 100644 --- a/app/Architecture/Providers/AuthServiceProvider.php +++ b/app/Architecture/Providers/AuthServiceProvider.php @@ -35,6 +35,5 @@ class AuthServiceProvider extends ServiceProvider Gate::define("manageVacationLimits", fn(User $user) => $user->role === Role::AdministrativeApprover); Gate::define("generateTimesheet", fn(User $user) => $user->role === Role::AdministrativeApprover); Gate::define("listMonthlyUsage", fn(User $user) => $user->role === Role::AdministrativeApprover); - Gate::define("manageKeys", fn(User $user) => $user->role === Role::AdministrativeApprover); } } diff --git a/app/Infrastructure/Http/Controllers/KeysController.php b/app/Infrastructure/Http/Controllers/KeysController.php index 7e63a5a..6482823 100644 --- a/app/Infrastructure/Http/Controllers/KeysController.php +++ b/app/Infrastructure/Http/Controllers/KeysController.php @@ -43,33 +43,45 @@ class KeysController extends Controller { $this->authorize("manageKeys"); - $request->user()->keys()->create(); + $key = $request->user()->keys()->create(); return redirect() ->back() - ->with("success", __("Key has been created.")); + ->with("success", __("Key no :number has been created.", [ + "number" => $key->id, + ])); } public function take(Key $key, Request $request): RedirectResponse { + $previousUser = $key->user; + $key->user()->associate($request->user()); $key->save(); return redirect() ->back() - ->with("success", __("Key has been taken.")); + ->with("success", __("Key no :number has been taken from :user.", [ + "number" => $key->id, + "user" => $previousUser->profile->full_name, + ])); } public function give(Key $key, GiveKeyRequest $request): RedirectResponse { - $key->user()->associate($request->recipient()); + $recipient = $request->recipient(); + + $key->user()->associate($recipient); $key->save(); return redirect() ->back() - ->with("success", __("Key has been given.")); + ->with("success", __("Key no :number has been given to :user.", [ + "number" => $key->id, + "user" => $recipient->profile->full_name, + ])); } public function destroy(Key $key): RedirectResponse @@ -80,6 +92,8 @@ class KeysController extends Controller return redirect() ->back() - ->with("success", __("Key has been deleted.")); + ->with("success", __("Key no :number has been deleted.", [ + "number" => $key->id, + ])); } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 5225924..5519dcb 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -90,7 +90,6 @@ class DatabaseSeeder extends Seeder foreach ($users as $user) { Key::factory() ->for($user, "owner") - ->for($user, "previousOwner") ->create(); } } diff --git a/resources/lang/pl.json b/resources/lang/pl.json index 108595e..7ef65e1 100644 --- a/resources/lang/pl.json +++ b/resources/lang/pl.json @@ -67,8 +67,8 @@ "The vacation request :title from user :requester has been :status.": "Wniosek urlopowy :title użytkownika :requester został :status.", "Vacation request :title has been created on your behalf": "Wniosek urlopowy :title został utworzony w Twoim imieniu", "The vacation request :title has been created correctly by user :creator on your behalf in the :appName.": "W systemie :appName został poprawnie utworzony wniosek urlopowy :title w Twoim imieniu przez użytkownika :creator.", - "Key has been created.": "Klucz został utworzony.", - "Key has been deleted.": "Klucz został usunięty.", - "Key has been taken.": "Klucz został zabrany.", - "Key has been given.": "Klucz został przekazany." + "Key no :number has been created.": "Klucz nr :number został utworzony.", + "Key no :number has been deleted.": "Klucz nr :number został usunięty.", + "Key no :number has been taken from :user.": "Klucz nr :number został zabrany od użytkownika :user.", + "Key no :number has been given to :user.": "Klucz nr :number został przekazany użytkownikowi :user." } -- 2.52.0 From 122798ec8da9250bbb13f3ba25489dff22e828ac Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Wed, 20 Apr 2022 14:38:00 +0200 Subject: [PATCH 09/12] #118 - fix --- app/Infrastructure/Http/Controllers/KeysController.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/Infrastructure/Http/Controllers/KeysController.php b/app/Infrastructure/Http/Controllers/KeysController.php index 6482823..096e540 100644 --- a/app/Infrastructure/Http/Controllers/KeysController.php +++ b/app/Infrastructure/Http/Controllers/KeysController.php @@ -41,7 +41,7 @@ class KeysController extends Controller */ public function store(Request $request): RedirectResponse { - $this->authorize("manageKeys"); + $this->authorize("manage", Key::class); $key = $request->user()->keys()->create(); @@ -68,8 +68,13 @@ class KeysController extends Controller ])); } + /** + * @throws AuthorizationException + */ public function give(Key $key, GiveKeyRequest $request): RedirectResponse { + $this->authorize("give", $key); + $recipient = $request->recipient(); $key->user()->associate($recipient); @@ -86,7 +91,7 @@ class KeysController extends Controller public function destroy(Key $key): RedirectResponse { - $this->authorize("manageKeys"); + $this->authorize("manage", Key::class); $key->delete(); -- 2.52.0 From 714cff4e4877f0979aa0727b4a239045f7204983 Mon Sep 17 00:00:00 2001 From: EwelinaLasowy Date: Wed, 20 Apr 2022 14:40:09 +0200 Subject: [PATCH 10/12] #118 - fix --- database/seeders/DatabaseSeeder.php | 2 +- resources/js/Pages/Keys.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 5519dcb..f5e0e51 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -89,7 +89,7 @@ class DatabaseSeeder extends Seeder foreach ($users as $user) { Key::factory() - ->for($user, "owner") + ->for($user) ->create(); } } diff --git a/resources/js/Pages/Keys.vue b/resources/js/Pages/Keys.vue index 647c2e0..5c158fa 100644 --- a/resources/js/Pages/Keys.vue +++ b/resources/js/Pages/Keys.vue @@ -248,7 +248,7 @@ as="template" :value="user" > -
  • +
  • -- 2.52.0 From ffd6ad26e77470146bdc12ecd875d0688d454407 Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Thu, 21 Apr 2022 08:02:49 +0200 Subject: [PATCH 11/12] Update resources/lang/pl.json Co-authored-by: Ewelina Lasowy <56546832+EwelinaLasowy@users.noreply.github.com> --- resources/lang/pl.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/lang/pl.json b/resources/lang/pl.json index 7ef65e1..a612ac1 100644 --- a/resources/lang/pl.json +++ b/resources/lang/pl.json @@ -69,6 +69,6 @@ "The vacation request :title has been created correctly by user :creator on your behalf in the :appName.": "W systemie :appName został poprawnie utworzony wniosek urlopowy :title w Twoim imieniu przez użytkownika :creator.", "Key no :number has been created.": "Klucz nr :number został utworzony.", "Key no :number has been deleted.": "Klucz nr :number został usunięty.", - "Key no :number has been taken from :user.": "Klucz nr :number został zabrany od użytkownika :user.", + "Key no :number has been taken from :user.": "Klucz nr :number został zabrany użytkownikowi :user.", "Key no :number has been given to :user.": "Klucz nr :number został przekazany użytkownikowi :user." } -- 2.52.0 From 9c5ae6976222c4fb95e944b4d84f3431bad3dc0b Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Thu, 21 Apr 2022 08:13:25 +0200 Subject: [PATCH 12/12] #118 - cr fix --- tests/Feature/{KeysTest.php => KeyTest.php} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename tests/Feature/{KeysTest.php => KeyTest.php} (98%) diff --git a/tests/Feature/KeysTest.php b/tests/Feature/KeyTest.php similarity index 98% rename from tests/Feature/KeysTest.php rename to tests/Feature/KeyTest.php index aa040fc..e9c3ddc 100644 --- a/tests/Feature/KeysTest.php +++ b/tests/Feature/KeyTest.php @@ -10,7 +10,7 @@ use Tests\FeatureTestCase; use Toby\Eloquent\Models\Key; use Toby\Eloquent\Models\User; -class KeysTest extends FeatureTestCase +class KeyTest extends FeatureTestCase { use DatabaseMigrations; -- 2.52.0