#23 - wip
This commit is contained in:
		| @@ -5,7 +5,6 @@ declare(strict_types=1); | ||||
| namespace Toby\Http\Controllers; | ||||
|  | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Support\Arr; | ||||
| use Inertia\Response; | ||||
| use Toby\Http\Requests\VacationLimitRequest; | ||||
| use Toby\Http\Resources\VacationLimitResource; | ||||
| @@ -22,14 +21,14 @@ class VacationLimitController extends Controller | ||||
|  | ||||
|     public function update(VacationLimitRequest $request): RedirectResponse | ||||
|     { | ||||
|        foreach ($request->data() as $data) { | ||||
|            $limit = VacationLimit::query()->find($data["id"]); | ||||
|         $data = $request->data(); | ||||
|  | ||||
|            $limit->update(Arr::only($data, ["has_vacation", "days"])); | ||||
|        } | ||||
|         foreach ($request->vacationLimits() as $limit) { | ||||
|             $limit->update($data[$limit->id]); | ||||
|         } | ||||
|  | ||||
|        return redirect() | ||||
|            ->back() | ||||
|            ->with("success", __("Vacation limits have been updated")); | ||||
|         return redirect() | ||||
|             ->back() | ||||
|             ->with("success", __("Vacation limits have been updated")); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,6 +6,7 @@ namespace Toby\Http\Requests; | ||||
|  | ||||
| use Illuminate\Foundation\Http\FormRequest; | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Models\VacationLimit; | ||||
|  | ||||
| class VacationLimitRequest extends FormRequest | ||||
| { | ||||
| @@ -19,12 +20,19 @@ class VacationLimitRequest extends FormRequest | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public function vacationLimits(): Collection | ||||
|     { | ||||
|         return VacationLimit::query()->find($this->collect("items")->pluck("id")); | ||||
|     } | ||||
|  | ||||
|     public function data(): Collection | ||||
|     { | ||||
|         return $this->collect("items")->map(fn(array $item): array => [ | ||||
|             "id" => $item["id"], | ||||
|             "has_vacation" => $item["hasVacation"], | ||||
|             "days" => $item["days"], | ||||
|         return $this->collect("items")->mapWithKeys(fn(array $item): array => [ | ||||
|             $item["id"] => [ | ||||
|                 "has_vacation" => $item["hasVacation"], | ||||
|                 "days" => $item["days"], | ||||
|             ] | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,10 +6,12 @@ namespace Toby\Models; | ||||
|  | ||||
| use Illuminate\Database\Eloquent\Builder; | ||||
| use Illuminate\Database\Eloquent\Factories\HasFactory; | ||||
| use Illuminate\Database\Eloquent\Relations\HasMany; | ||||
| use Illuminate\Database\Eloquent\SoftDeletes; | ||||
| use Illuminate\Foundation\Auth\User as Authenticatable; | ||||
| use Illuminate\Notifications\Notifiable; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Enums\EmploymentForm; | ||||
|  | ||||
| /** | ||||
| @@ -19,6 +21,7 @@ use Toby\Enums\EmploymentForm; | ||||
|  * @property string $avatar | ||||
|  * @property EmploymentForm $employment_form | ||||
|  * @property Carbon $employment_date | ||||
|  * @property Collection $vacationLimits | ||||
|  */ | ||||
| class User extends Authenticatable | ||||
| { | ||||
| @@ -43,6 +46,11 @@ class User extends Authenticatable | ||||
|         "remember_token", | ||||
|     ]; | ||||
|  | ||||
|     public function vacationLimits(): HasMany | ||||
|     { | ||||
|         return $this->hasMany(VacationLimit::class); | ||||
|     } | ||||
|  | ||||
|     public function scopeSearch(Builder $query, ?string $text): Builder | ||||
|     { | ||||
|         if ($text === null) { | ||||
| @@ -53,4 +61,11 @@ class User extends Authenticatable | ||||
|             ->where("name", "LIKE", "%{$text}%") | ||||
|             ->orWhere("email", "LIKE", "%{$text}%"); | ||||
|     } | ||||
|  | ||||
|     public function saveAvatar(string $path): void | ||||
|     { | ||||
|         $this->avatar = $path; | ||||
|  | ||||
|         $this->save(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -6,20 +6,22 @@ namespace Toby\Observers; | ||||
|  | ||||
| use Illuminate\Support\Facades\Storage; | ||||
| use Toby\Helpers\UserAvatarGenerator; | ||||
| use Toby\Helpers\YearPeriodRetriever; | ||||
| use Toby\Models\User; | ||||
|  | ||||
| class UserObserver | ||||
| { | ||||
|     public function __construct( | ||||
|         protected UserAvatarGenerator $generator, | ||||
|         protected YearPeriodRetriever $yearPeriodRetriever, | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     public function created(User $user): void | ||||
|     { | ||||
|         $user->avatar = $this->generator->generateFor($user); | ||||
|         $user->saveAvatar($this->generator->generateFor($user)); | ||||
|  | ||||
|         $user->save(); | ||||
|         $user->vacationLimits()->create(["year_period_id" => $this->yearPeriodRetriever->current()->id]); | ||||
|     } | ||||
|  | ||||
|     public function updating(User $user): void | ||||
|   | ||||
							
								
								
									
										26
									
								
								app/Observers/YearPeriodObserver.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								app/Observers/YearPeriodObserver.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Toby\Observers; | ||||
|  | ||||
| use Toby\Helpers\UserAvatarGenerator; | ||||
| use Toby\Models\User; | ||||
| use Toby\Models\YearPeriod; | ||||
|  | ||||
| class YearPeriodObserver | ||||
| { | ||||
|     public function __construct( | ||||
|         protected UserAvatarGenerator $generator, | ||||
|     ) { | ||||
|     } | ||||
|  | ||||
|     public function created(YearPeriod $yearPeriod): void | ||||
|     { | ||||
|         $users = User::all(); | ||||
|  | ||||
|         foreach ($users as $user) { | ||||
|             $yearPeriod->vacationLimits()->updateOrCreate(["user_id" => $user->id]); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -8,7 +8,9 @@ use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\ServiceProvider; | ||||
| use Toby\Models\User; | ||||
| use Toby\Models\VacationLimit; | ||||
| use Toby\Models\YearPeriod; | ||||
| use Toby\Observers\UserObserver; | ||||
| use Toby\Observers\YearPeriodObserver; | ||||
| use Toby\Scopes\SelectedYearPeriodScope; | ||||
|  | ||||
| class AppServiceProvider extends ServiceProvider | ||||
| @@ -16,6 +18,7 @@ class AppServiceProvider extends ServiceProvider | ||||
|     public function boot(): void | ||||
|     { | ||||
|         User::observe(UserObserver::class); | ||||
|         YearPeriod::observe(YearPeriodObserver::class); | ||||
|  | ||||
|         Carbon::macro("toDisplayString", fn() => $this->translatedFormat("j F Y")); | ||||
|  | ||||
|   | ||||
| @@ -6,14 +6,23 @@ namespace Database\Seeders; | ||||
|  | ||||
| use Illuminate\Database\Seeder; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Collection; | ||||
| use Toby\Helpers\UserAvatarGenerator; | ||||
| use Toby\Models\User; | ||||
| use Toby\Models\VacationLimit; | ||||
| use Toby\Models\YearPeriod; | ||||
|  | ||||
| class DatabaseSeeder extends Seeder | ||||
| { | ||||
|     public function __construct(protected UserAvatarGenerator $avatarGenerator) | ||||
|     { | ||||
|     } | ||||
|  | ||||
|     public function run(): void | ||||
|     { | ||||
|         User::unsetEventDispatcher(); | ||||
|         YearPeriod::unsetEventDispatcher(); | ||||
|  | ||||
|         User::factory(14)->create(); | ||||
|         User::factory([ | ||||
|             "email" => env("LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE"), | ||||
| @@ -21,6 +30,8 @@ class DatabaseSeeder extends Seeder | ||||
|  | ||||
|         $users = User::all(); | ||||
|  | ||||
|         $this->generateAvatarsForUsers($users); | ||||
|  | ||||
|         YearPeriod::factory() | ||||
|             ->count(3) | ||||
|             ->sequence( | ||||
| @@ -38,4 +49,11 @@ class DatabaseSeeder extends Seeder | ||||
|             }) | ||||
|         ->create(); | ||||
|     } | ||||
|  | ||||
|     protected function generateAvatarsForUsers(Collection $users): void | ||||
|     { | ||||
|         foreach ($users as $user) { | ||||
|             $user->saveAvatar($this->avatarGenerator->generateFor($user)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -16,8 +16,8 @@ Route::middleware("auth")->group(function (): void { | ||||
|     Route::resource("users", UserController::class); | ||||
|     Route::post("users/{user}/restore", [UserController::class, "restore"])->withTrashed(); | ||||
|  | ||||
|     Route::get("/vacation-days", [VacationLimitController::class, "edit"])->name("vacation.days"); | ||||
|     Route::put("/vacation-days", [VacationLimitController::class, "update"]); | ||||
|     Route::get("/vacation-limits", [VacationLimitController::class, "edit"])->name("vacation.limits"); | ||||
|     Route::put("/vacation-limits", [VacationLimitController::class, "update"]); | ||||
|  | ||||
|     Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class)->name("year-periods.select"); | ||||
| }); | ||||
|   | ||||
| @@ -6,7 +6,6 @@ namespace Tests\Feature; | ||||
|  | ||||
| use Illuminate\Foundation\Testing\DatabaseMigrations; | ||||
| use Illuminate\Support\Carbon; | ||||
| use Illuminate\Support\Facades\Storage; | ||||
| use Inertia\Testing\AssertableInertia as Assert; | ||||
| use Tests\FeatureTestCase; | ||||
| use Toby\Enums\EmploymentForm; | ||||
| @@ -16,13 +15,6 @@ class UserTest extends FeatureTestCase | ||||
| { | ||||
|     use DatabaseMigrations; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         parent::setUp(); | ||||
|  | ||||
|         Storage::fake(); | ||||
|     } | ||||
|  | ||||
|     public function testAdminCanSeeUsersList(): void | ||||
|     { | ||||
|         User::factory()->count(10)->create(); | ||||
|   | ||||
							
								
								
									
										83
									
								
								tests/Feature/VacationLimitTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								tests/Feature/VacationLimitTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Tests\Feature; | ||||
|  | ||||
| use Illuminate\Foundation\Testing\DatabaseMigrations; | ||||
| use Inertia\Testing\AssertableInertia as Assert; | ||||
| use Tests\FeatureTestCase; | ||||
| use Toby\Models\User; | ||||
| use Toby\Models\VacationLimit; | ||||
|  | ||||
| class VacationLimitTest extends FeatureTestCase | ||||
| { | ||||
|     use DatabaseMigrations; | ||||
|  | ||||
|     public function testAdminCanSeeVacationLimits(): void | ||||
|     { | ||||
|         $admin = User::factory()->createQuietly(); | ||||
|  | ||||
|         User::factory(10)->create(); | ||||
|  | ||||
|         $this->actingAs($admin) | ||||
|             ->get("/vacation-limits") | ||||
|             ->assertOk() | ||||
|             ->assertInertia( | ||||
|                 fn(Assert $page) => $page | ||||
|                     ->component("VacationLimits") | ||||
|                     ->has("limits.data", 10) | ||||
|             ); | ||||
|     } | ||||
|  | ||||
|     public function testAdminCanUpdateVacationLimits(): void | ||||
|     { | ||||
|         $admin = User::factory()->createQuietly(); | ||||
|  | ||||
|         User::factory(3)->create(); | ||||
|  | ||||
|         [$limit1, $limit2, $limit3] = VacationLimit::all(); | ||||
|  | ||||
|         $data = [ | ||||
|             [ | ||||
|                 "id" => $limit1->id, | ||||
|                 "hasVacation" => true, | ||||
|                 "days" => 25, | ||||
|             ], | ||||
|             [ | ||||
|                 "id" => $limit2->id, | ||||
|                 "hasVacation" => false, | ||||
|                 "days" => null, | ||||
|             ], | ||||
|             [ | ||||
|                 "id" => $limit3->id, | ||||
|                 "hasVacation" => true, | ||||
|                 "days" => 20, | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|         $this->actingAs($admin) | ||||
|             ->put("/vacation-limits", [ | ||||
|                 "items" => $data | ||||
|             ]) | ||||
|             ->assertRedirect(); | ||||
|  | ||||
|         $this->assertDatabaseHas("vacation_limits", [ | ||||
|            "id" => $limit1->id, | ||||
|            "has_vacation" => true, | ||||
|            "days" => 25, | ||||
|         ]); | ||||
|  | ||||
|         $this->assertDatabaseHas("vacation_limits", [ | ||||
|             "id" => $limit2->id, | ||||
|             "has_vacation" => false, | ||||
|             "days" => null, | ||||
|         ]); | ||||
|  | ||||
|         $this->assertDatabaseHas("vacation_limits", [ | ||||
|             "id" => $limit3->id, | ||||
|             "has_vacation" => true, | ||||
|             "days" => 20, | ||||
|         ]); | ||||
|     } | ||||
| } | ||||
| @@ -7,16 +7,19 @@ namespace Tests\Unit; | ||||
| use Illuminate\Foundation\Testing\DatabaseMigrations; | ||||
| use Illuminate\Support\Facades\Storage; | ||||
| use Tests\TestCase; | ||||
| use Tests\Traits\InteractsWithYearPeriods; | ||||
| use Toby\Models\User; | ||||
|  | ||||
| class AvatarTest extends TestCase | ||||
| { | ||||
|     use DatabaseMigrations; | ||||
|     use InteractsWithYearPeriods; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         parent::setUp(); | ||||
|  | ||||
|         $this->createCurrentYearPeriod(); | ||||
|         Storage::fake(); | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										50
									
								
								tests/Unit/VacationLimitTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								tests/Unit/VacationLimitTest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| <?php | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace Tests\Unit; | ||||
|  | ||||
| use Illuminate\Foundation\Testing\DatabaseMigrations; | ||||
| use Tests\TestCase; | ||||
| use Tests\Traits\InteractsWithYearPeriods; | ||||
| use Toby\Models\User; | ||||
| use Toby\Models\YearPeriod; | ||||
|  | ||||
| class VacationLimitTest extends TestCase | ||||
| { | ||||
|     use DatabaseMigrations; | ||||
|     use InteractsWithYearPeriods; | ||||
|  | ||||
|     protected function setUp(): void | ||||
|     { | ||||
|         parent::setUp(); | ||||
|  | ||||
|         $this->createCurrentYearPeriod(); | ||||
|     } | ||||
|  | ||||
|     public function testWhenUserIsCreatedThenVacationLimitIsCreatedForCurrentYearPeriod(): void | ||||
|     { | ||||
|         $this->assertDatabaseCount("vacation_limits", 0); | ||||
|  | ||||
|         $currentYearPeriod = YearPeriod::current(); | ||||
|         $user = User::factory()->create(); | ||||
|  | ||||
|         $this->assertDatabaseCount("vacation_limits", 1); | ||||
|  | ||||
|         $this->assertDatabaseHas("vacation_limits", [ | ||||
|             "user_id" => $user->id, | ||||
|             "year_period_id" => $currentYearPeriod->id, | ||||
|         ]); | ||||
|     } | ||||
|  | ||||
|     public function testWhenYearPeriodIsCreatedThenVacationLimitsForThisYearPeriodAreCreated(): void | ||||
|     { | ||||
|         $this->assertDatabaseCount("vacation_limits", 0); | ||||
|  | ||||
|         User::factory(10)->createQuietly(); | ||||
|  | ||||
|         YearPeriod::factory()->create(); | ||||
|  | ||||
|         $this->assertDatabaseCount("vacation_limits", 10); | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user