diff --git a/.env.ci b/.env.ci index 7508f67..b599841 100644 --- a/.env.ci +++ b/.env.ci @@ -7,9 +7,9 @@ APP_URL=http://127.0.0.1 LOG_CHANNEL=stack LOG_LEVEL=debug -DB_CONNECTION=mysql +DB_CONNECTION=pgsql DB_HOST=127.0.0.1 -DB_PORT=3306 +DB_PORT=5432 DB_DATABASE=toby DB_USERNAME=toby DB_PASSWORD=password diff --git a/.env.dusk.local b/.env.dusk.local index 3f4837b..48c004f 100644 --- a/.env.dusk.local +++ b/.env.dusk.local @@ -10,17 +10,17 @@ DUSK_DRIVER_URL=http://toby-selenium:4444/wd/hub LOG_CHANNEL=stack LOG_LEVEL=debug -DB_CONNECTION=mysql +DB_CONNECTION=pgsql DB_HOST=toby-db-test -DB_PORT=3306 +DB_PORT=5432 DB_DATABASE=toby DB_USERNAME=toby DB_PASSWORD=password BROADCAST_DRIVER=log CACHE_DRIVER=array -QUEUE_CONNECTION=sync -SESSION_DRIVER=file +QUEUE_CONNECTION=redis +SESSION_DRIVER=redis SESSION_LIFETIME=120 FILESYSTEM_DISK=local MAIL_MAILER=array diff --git a/.env.example b/.env.example index 661c459..fe3a597 100644 --- a/.env.example +++ b/.env.example @@ -7,33 +7,37 @@ APP_URL=http://localhost LOG_CHANNEL=stack LOG_LEVEL=debug -DB_CONNECTION=mysql +DB_CONNECTION=pgsql DB_HOST=toby-db-dev -DB_PORT=3306 +DB_PORT=5432 DB_DATABASE=toby DB_USERNAME=toby DB_PASSWORD=password DB_ROOT_PASSWORD=example -DOCKER_DEV_DB_EXTERNAL_PORT=3306 +EXTERNAL_WEBSERVER_PORT=80 + +DOCKER_DEV_DB_EXTERNAL_PORT=5432 DOCKER_DEV_DB_DATABASE=${DB_DATABASE} DOCKER_DEV_DB_USERNAME=${DB_USERNAME} DOCKER_DEV_DB_PASSWORD=${DB_PASSWORD} DOCKER_DEV_DB_ROOT_PASSWORD=${DB_ROOT_PASSWORD} -DOCKER_TEST_DB_EXTERNAL_PORT=3307 +DOCKER_TEST_DB_EXTERNAL_PORT=5433 DOCKER_TEST_DB_DATABASE=${DB_DATABASE} DOCKER_TEST_DB_USERNAME=${DB_USERNAME} DOCKER_TEST_DB_PASSWORD=${DB_PASSWORD} DOCKER_TEST_DB_ROOT_PASSWORD=${DB_ROOT_PASSWORD} -EXTERNAL_WEBSERVER_PORT= +REDIS_PORT=6379 +REDIS_HOST=toby-redis + XDG_CONFIG_HOME=/tmp BROADCAST_DRIVER=log CACHE_DRIVER=file -QUEUE_CONNECTION=sync -SESSION_DRIVER=file +QUEUE_CONNECTION=redis +SESSION_DRIVER=redis SESSION_LIFETIME=120 FILESYSTEM_DISK=local @@ -46,15 +50,13 @@ MAIL_PORT=${MAILHOG_PORT} MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS=null +MAIL_FROM_ADDRESS=hello@example.com MAIL_FROM_NAME="${APP_NAME}" DOCKER_INSTALL_XDEBUG=false GOOGLE_CLIENT_ID= GOOGLE_CLIENT_SECRET= -GOOGLE_REDIRECT= - +GOOGLE_REDIRECT=http://localhost/login/google/end GOOGLE_CALENDAR_ID= - LOCAL_EMAIL_FOR_LOGIN_VIA_GOOGLE= diff --git a/.github/workflows/test-and-lint-php.yml b/.github/workflows/test-and-lint-php.yml index d287df0..c4994a9 100644 --- a/.github/workflows/test-and-lint-php.yml +++ b/.github/workflows/test-and-lint-php.yml @@ -11,15 +11,15 @@ jobs: name: Test & lint PHP stuff runs-on: ubuntu-20.04 services: - mysql: - image: mysql:8.0 + pgsql: + image: postgres:13 env: - MYSQL_DATABASE: toby - MYSQL_USER: toby - MYSQL_PASSWORD: password - MYSQL_ALLOW_EMPTY_PASSWORD: 1 + POSTGRES_DB: toby + POSTGRES_USER: toby + POSTGRES_PASSWORD: password + PGPASSWORD: password ports: - - 3306:3306 + - 5432:5432 steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 113d45d..63cf7ed 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ /node_modules /public/hot /public/storage -/public/avatars /public/js/ /public/css/ /public/mix-manifest.json diff --git a/app/Eloquent/Helpers/UserAvatarGenerator.php b/app/Eloquent/Helpers/UserAvatarGenerator.php deleted file mode 100644 index f21f425..0000000 --- a/app/Eloquent/Helpers/UserAvatarGenerator.php +++ /dev/null @@ -1,49 +0,0 @@ -generateUuid()}.svg"; - - Storage::put($path, $this->generate($user)); - - return $path; - } - - protected function generate(User $user): SVG - { - return $this->generator->rounded() - ->background($this->getColor($user->fullName)) - ->color("#F4F8FD") - ->smooth() - ->fontSize(0.33) - ->generateSvg($user->fullName); - } - - protected function getColor(string $name): string - { - $colors = config("colors"); - - return $colors[strlen($name) % count($colors)]; - } - - protected function generateUuid(): string - { - return Str::uuid()->toString(); - } -} diff --git a/app/Eloquent/Models/User.php b/app/Eloquent/Models/User.php index eafa9aa..baf733b 100644 --- a/app/Eloquent/Models/User.php +++ b/app/Eloquent/Models/User.php @@ -13,6 +13,7 @@ use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; +use Rackbeat\UIAvatars\HasAvatar; use Toby\Domain\Enums\EmploymentForm; use Toby\Domain\Enums\Role; @@ -35,6 +36,7 @@ class User extends Authenticatable use HasFactory; use Notifiable; use SoftDeletes; + use HasAvatar; protected $guarded = []; @@ -75,16 +77,18 @@ class User extends Authenticatable } return $query - ->where("first_name", "LIKE", "%{$text}%") - ->orWhere("last_name", "LIKE", "%{$text}%") - ->orWhere("email", "LIKE", "%{$text}%"); + ->where("first_name", "ILIKE", $text) + ->orWhere("last_name", "ILIKE", $text) + ->orWhere("email", "ILIKE", $text); } - public function saveAvatar(string $path): void + public function getAvatar(): string { - $this->avatar = $path; + $colors = config("colors"); - $this->save(); + return $this->getAvatarGenerator() + ->backgroundColor($colors[strlen($this->fullname) % count($colors)]) + ->image(); } public function getFullNameAttribute(): string @@ -97,6 +101,11 @@ class User extends Authenticatable return $this->role === $role; } + protected function getAvatarNameKey(): string + { + return "fullName"; + } + protected static function newFactory(): UserFactory { return UserFactory::new(); diff --git a/app/Eloquent/Observers/UserObserver.php b/app/Eloquent/Observers/UserObserver.php index 1d8d3a6..33a76e5 100644 --- a/app/Eloquent/Observers/UserObserver.php +++ b/app/Eloquent/Observers/UserObserver.php @@ -4,37 +4,19 @@ declare(strict_types=1); namespace Toby\Eloquent\Observers; -use Illuminate\Support\Facades\Storage; -use Toby\Eloquent\Helpers\UserAvatarGenerator; use Toby\Eloquent\Helpers\YearPeriodRetriever; use Toby\Eloquent\Models\User; class UserObserver { public function __construct( - protected UserAvatarGenerator $generator, protected YearPeriodRetriever $yearPeriodRetriever, ) {} public function created(User $user): void { - $user->saveAvatar($this->generator->generateFor($user)); - $user->vacationLimits()->create([ "year_period_id" => $this->yearPeriodRetriever->current()->id, ]); } - - public function updating(User $user): void - { - if ($user->isDirty(["first_name", "last_name"])) { - Storage::delete($user->avatar); - $user->avatar = $this->generator->generateFor($user); - } - } - - public function forceDeleted(User $user): void - { - Storage::delete($user->avatar); - } } diff --git a/app/Eloquent/Observers/YearPeriodObserver.php b/app/Eloquent/Observers/YearPeriodObserver.php index e74cc3c..b7f370b 100644 --- a/app/Eloquent/Observers/YearPeriodObserver.php +++ b/app/Eloquent/Observers/YearPeriodObserver.php @@ -5,14 +5,12 @@ declare(strict_types=1); namespace Toby\Eloquent\Observers; use Toby\Domain\PolishHolidaysRetriever; -use Toby\Eloquent\Helpers\UserAvatarGenerator; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\YearPeriod; class YearPeriodObserver { public function __construct( - protected UserAvatarGenerator $generator, protected PolishHolidaysRetriever $polishHolidaysRetriever, ) {} diff --git a/app/Infrastructure/Http/Resources/UserResource.php b/app/Infrastructure/Http/Resources/UserResource.php index 5e3107f..2428f7f 100644 --- a/app/Infrastructure/Http/Resources/UserResource.php +++ b/app/Infrastructure/Http/Resources/UserResource.php @@ -18,7 +18,7 @@ class UserResource extends JsonResource "email" => $this->email, "role" => $this->role->label(), "position" => $this->position, - "avatar" => asset($this->avatar), + "avatar" => $this->getAvatar(), "deleted" => $this->trashed(), "employmentForm" => $this->employment_form->label(), "employmentDate" => $this->employment_date->toDisplayString(), diff --git a/composer.json b/composer.json index 9a9131f..0238916 100644 --- a/composer.json +++ b/composer.json @@ -17,10 +17,10 @@ "laravel/socialite": "^5.2", "laravel/telescope": "^4.6", "laravel/tinker": "^2.5", - "lasserafn/php-initial-avatar-generator": "^4.2", + "maatwebsite/excel": "^3.1", + "rackbeat/laravel-ui-avatars": "^1.0", "spatie/laravel-google-calendar": "^3.5", - "spatie/laravel-model-states": "^2.1", - "maatwebsite/excel": "^3.1" + "spatie/laravel-model-states": "^2.1" }, "require-dev": { "blumilksoftware/codestyle": "^0.10.0", diff --git a/config/cache.php b/config/cache.php index d520005..39e2bf3 100644 --- a/config/cache.php +++ b/config/cache.php @@ -21,6 +21,11 @@ return [ "driver" => "file", "path" => storage_path("framework/cache/data"), ], + "redis" => [ + "driver" => "redis", + "connection" => "cache", + "lock_connection" => "default", + ], ], "prefix" => env("CACHE_PREFIX", Str::slug(env("APP_NAME", "laravel"), "_") . "_cache"), ]; diff --git a/config/database.php b/config/database.php index c3831fc..0ab09ab 100644 --- a/config/database.php +++ b/config/database.php @@ -2,28 +2,46 @@ declare(strict_types=1); +use Illuminate\Support\Str; + return [ "default" => env("DB_CONNECTION", "mysql"), "connections" => [ - "mysql" => [ - "driver" => "mysql", + "pgsql" => [ + "driver" => "pgsql", "url" => env("DATABASE_URL"), "host" => env("DB_HOST", "127.0.0.1"), - "port" => env("DB_PORT", "3306"), + "port" => env("DB_PORT", "5432"), "database" => env("DB_DATABASE", "forge"), "username" => env("DB_USERNAME", "forge"), "password" => env("DB_PASSWORD", ""), - "unix_socket" => env("DB_SOCKET", ""), - "charset" => "utf8mb4", - "collation" => "utf8mb4_unicode_ci", + "charset" => "utf8", "prefix" => "", "prefix_indexes" => true, - "strict" => true, - "engine" => null, - "options" => extension_loaded("pdo_mysql") ? array_filter([ - PDO::MYSQL_ATTR_SSL_CA => env("MYSQL_ATTR_SSL_CA"), - ]) : [], + "search_path" => "public", + "sslmode" => "prefer", ], ], "migrations" => "migrations", + "redis" => [ + "client" => env("REDIS_CLIENT", "phpredis"), + "options" => [ + "cluster" => env("REDIS_CLUSTER", "redis"), + "prefix" => env("REDIS_PREFIX", Str::slug(env("APP_NAME", "laravel"), "_") . "_database_"), + ], + "default" => [ + "url" => env("REDIS_URL"), + "host" => env("REDIS_HOST", "127.0.0.1"), + "password" => env("REDIS_PASSWORD"), + "port" => env("REDIS_PORT", "6379"), + "database" => env("REDIS_DB", "0"), + ], + "cache" => [ + "url" => env("REDIS_URL"), + "host" => env("REDIS_HOST", "127.0.0.1"), + "password" => env("REDIS_PASSWORD"), + "port" => env("REDIS_PORT", "6379"), + "database" => env("REDIS_CACHE_DB", "1"), + ], + ], ]; diff --git a/config/filesystems.php b/config/filesystems.php index af08bf5..80a15f7 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -17,6 +17,6 @@ return [ ], ], "links" => [ - public_path("avatars") => storage_path("app/avatars"), + public_path("storage") => storage_path("app/storage"), ], ]; diff --git a/config/queue.php b/config/queue.php index 27dbd2e..626d9db 100644 --- a/config/queue.php +++ b/config/queue.php @@ -8,6 +8,14 @@ return [ "sync" => [ "driver" => "sync", ], + "redis" => [ + "driver" => "redis", + "connection" => "default", + "queue" => env("REDIS_QUEUE", "default"), + "retry_after" => 90, + "block_for" => null, + "after_commit" => false, + ], ], "failed" => [ "driver" => env("QUEUE_FAILED_DRIVER", "database-uuids"), diff --git a/config/ui-avatars.php b/config/ui-avatars.php new file mode 100644 index 0000000..68cbd82 --- /dev/null +++ b/config/ui-avatars.php @@ -0,0 +1,21 @@ + "api", + "default_region" => "eu", + "length" => 2, + "image_size" => 48, + "font_size" => 0.33, + "rounded" => true, + "smooth_rounding" => true, + "uppercase" => true, + "background_color" => "#a0a0a0", + "font_color" => "#F4F8FD", + "font_bold" => true, + "providers" => [ + "api" => Rackbeat\UIAvatars\Generators\ApiGenerator::class, + "local" => Rackbeat\UIAvatars\Generators\LocalGenerator::class, + ], +]; diff --git a/database/factories/VacationRequestActivityFactory.php b/database/factories/VacationRequestActivityFactory.php index c4b8c50..d1de4a3 100644 --- a/database/factories/VacationRequestActivityFactory.php +++ b/database/factories/VacationRequestActivityFactory.php @@ -5,7 +5,7 @@ declare(strict_types=1); namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; -use Toby\Domain\Enums\VacationRequestState; +use Toby\Domain\States\VacationRequest\VacationRequestState; use Toby\Eloquent\Models\VacationRequestActivity; class VacationRequestActivityFactory extends Factory @@ -15,8 +15,8 @@ class VacationRequestActivityFactory extends Factory public function definition(): array { return [ - "from" => $this->faker->randomElement(VacationRequestState::cases()), - "to" => $this->faker->randomElement(VacationRequestState::cases()), + "from" => $this->faker->randomElement(VacationRequestState::all()), + "to" => $this->faker->randomElement(VacationRequestState::all()), ]; } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 9cd93f7..8d58909 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -6,10 +6,8 @@ namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Carbon; -use Illuminate\Support\Collection; use Toby\Domain\PolishHolidaysRetriever; use Toby\Domain\VacationDaysCalculator; -use Toby\Eloquent\Helpers\UserAvatarGenerator; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationLimit; use Toby\Eloquent\Models\VacationRequest; @@ -17,10 +15,6 @@ use Toby\Eloquent\Models\YearPeriod; class DatabaseSeeder extends Seeder { - public function __construct( - protected UserAvatarGenerator $avatarGenerator, - ) {} - public function run(): void { User::unsetEventDispatcher(); @@ -35,8 +29,6 @@ class DatabaseSeeder extends Seeder $users = User::all(); - $this->generateAvatarsForUsers($users); - YearPeriod::factory() ->count(3) ->sequence( @@ -98,11 +90,4 @@ class DatabaseSeeder extends Seeder ->create(); } } - - protected function generateAvatarsForUsers(Collection $users): void - { - foreach ($users as $user) { - $user->saveAvatar($this->avatarGenerator->generateFor($user)); - } - } } diff --git a/database/seeders/DemoSeeder.php b/database/seeders/DemoSeeder.php index bd4a7ec..6731a3a 100644 --- a/database/seeders/DemoSeeder.php +++ b/database/seeders/DemoSeeder.php @@ -6,15 +6,19 @@ namespace Database\Seeders; use Illuminate\Database\Seeder; use Illuminate\Support\Carbon; -use Illuminate\Support\Collection; use Illuminate\Support\Str; use Toby\Domain\Enums\EmploymentForm; use Toby\Domain\Enums\Role; -use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\Enums\VacationType; use Toby\Domain\PolishHolidaysRetriever; +use Toby\Domain\States\VacationRequest\AcceptedByAdministrative; +use Toby\Domain\States\VacationRequest\AcceptedByTechnical; +use Toby\Domain\States\VacationRequest\Approved; +use Toby\Domain\States\VacationRequest\Created; +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\Helpers\UserAvatarGenerator; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationLimit; use Toby\Eloquent\Models\VacationRequest; @@ -23,10 +27,6 @@ use Toby\Eloquent\Models\YearPeriod; class DemoSeeder extends Seeder { - public function __construct( - protected UserAvatarGenerator $avatarGenerator, - ) {} - public function run(): void { User::unsetEventDispatcher(); @@ -107,8 +107,6 @@ class DemoSeeder extends Seeder $users = User::all(); - $this->generateAvatarsForUsers($users); - $year = 2021; YearPeriod::factory() @@ -148,7 +146,7 @@ class DemoSeeder extends Seeder /** @var VacationRequest $vacationRequestApproved */ $vacationRequestApproved = VacationRequest::factory([ "type" => VacationType::Vacation->value, - "state" => VacationRequestState::Created, + "state" => Created::class, "from" => Carbon::create($currentYearPeriod->year, 1, 31)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "comment" => "Komentarz do wniosku urlopowego.", @@ -175,49 +173,50 @@ class DemoSeeder extends Seeder VacationRequestActivity::factory([ "from" => null, - "to" => VacationRequestState::Created, + "to" => Created::class, ])->for($vacationRequestApproved) ->for($employee1) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::Created, - "to" => VacationRequestState::WaitingForTechnical, + "from" => Created::class, + "to" => WaitingForTechnical::class, ])->for($vacationRequestApproved) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::WaitingForTechnical, - "to" => VacationRequestState::AcceptedByTechnical, + "from" => WaitingForTechnical::class, + "to" => AcceptedByTechnical::class, ])->for($vacationRequestApproved) ->for($technicalApprover) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::AcceptedByTechnical, - "to" => VacationRequestState::WaitingForAdministrative, + "from" => AcceptedByTechnical::class, + "to" => WaitingForAdministrative::class, ])->for($vacationRequestApproved) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::WaitingForAdministrative, - "to" => VacationRequestState::AcceptedByAdministrative, + "from" => WaitingForAdministrative::class, + "to" => AcceptedByAdministrative::class, ])->for($vacationRequestApproved) ->for($administrativeApprover) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::AcceptedByAdministrative, - "to" => VacationRequestState::Approved, + "from" => AcceptedByAdministrative::class, + "to" => Approved::class, ])->for($vacationRequestApproved) ->create(); - $vacationRequestApproved->changeStateTo(VacationRequestState::Approved); + $vacationRequestApproved->state = new Approved($vacationRequestApproved); + $vacationRequestApproved->save(); /** @var VacationRequest $vacationRequestWaitsForAdminApproval */ $vacationRequestWaitsForAdminApproval = VacationRequest::factory([ "type" => VacationType::Vacation->value, - "state" => VacationRequestState::Created, + "state" => Created::class, "from" => Carbon::create($currentYearPeriod->year, 2, 14)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 14)->toDateString(), "comment" => "Komentarz do wniosku urlopowego.", @@ -244,36 +243,37 @@ class DemoSeeder extends Seeder VacationRequestActivity::factory([ "from" => null, - "to" => VacationRequestState::Created, + "to" => Created::class, ])->for($vacationRequestWaitsForAdminApproval) ->for($employee1) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::Created, - "to" => VacationRequestState::WaitingForTechnical, + "from" => Created::class, + "to" => WaitingForTechnical::class, ])->for($vacationRequestWaitsForAdminApproval) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::WaitingForTechnical, - "to" => VacationRequestState::AcceptedByTechnical, + "from" => WaitingForTechnical::class, + "to" => AcceptedByTechnical::class, ])->for($vacationRequestWaitsForAdminApproval) ->for($technicalApprover) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::AcceptedByTechnical, - "to" => VacationRequestState::WaitingForAdministrative, + "from" => AcceptedByTechnical::class, + "to" => WaitingForAdministrative::class, ])->for($vacationRequestWaitsForAdminApproval) ->create(); - $vacationRequestWaitsForAdminApproval->changeStateTo(VacationRequestState::WaitingForAdministrative); + $vacationRequestWaitsForAdminApproval->state = new WaitingForAdministrative($vacationRequestWaitsForAdminApproval); + $vacationRequestWaitsForAdminApproval->save(); /** @var VacationRequest $vacationRequestRejected */ $vacationRequestRejected = VacationRequest::factory([ "type" => VacationType::Vacation->value, - "state" => VacationRequestState::Created, + "state" => Created::class, "from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(), "comment" => "", @@ -300,31 +300,25 @@ class DemoSeeder extends Seeder VacationRequestActivity::factory([ "from" => null, - "to" => VacationRequestState::Created, + "to" => Created::class, ])->for($vacationRequestRejected) ->for($employee1) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::Created, - "to" => VacationRequestState::WaitingForTechnical, + "from" => Created::class, + "to" => WaitingForTechnical::class, ])->for($vacationRequestRejected) ->create(); VacationRequestActivity::factory([ - "from" => VacationRequestState::WaitingForTechnical, - "to" => VacationRequestState::Rejected, + "from" => WaitingForTechnical::class, + "to" => Rejected::class, ])->for($vacationRequestRejected) ->for($technicalApprover) ->create(); - $vacationRequestRejected->changeStateTo(VacationRequestState::Rejected); - } - - protected function generateAvatarsForUsers(Collection $users): void - { - foreach ($users as $user) { - $user->saveAvatar($this->avatarGenerator->generateFor($user)); - } + $vacationRequestRejected->state = new Rejected($vacationRequestRejected); + $vacationRequestRejected->save(); } } diff --git a/docker-compose.yml b/docker-compose.yml index 7fcec65..6a4231b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -35,31 +35,42 @@ services: restart: unless-stopped database: - image: mysql:8.0 + image: postgres:13 container_name: toby-db-dev environment: - - MYSQL_ROOT_PASSWORD=${DOCKER_DEV_DB_ROOT_PASSWORD} - - MYSQL_DATABASE=${DOCKER_DEV_DB_DATABASE} - - MYSQL_USER=${DOCKER_DEV_DB_USERNAME} - - MYSQL_PASSWORD=${DOCKER_DEV_DB_PASSWORD} + - PGPASSWORD=${DOCKER_DEV_DB_ROOT_PASSWORD} + - POSTGRES_DB=${DOCKER_DEV_DB_DATABASE} + - POSTGRES_USER=${DOCKER_DEV_DB_USERNAME} + - POSTGRES_PASSWORD=${DOCKER_DEV_DB_PASSWORD} ports: - - ${DOCKER_DEV_DB_EXTERNAL_PORT:-3306}:3306 + - ${DOCKER_DEV_DB_EXTERNAL_PORT:-5432}:5432 volumes: - - toby-mysql-data:/var/lib/mysql + - toby-pgsql-data:/var/lib/pgsql networks: - toby-dev restart: unless-stopped database-test: - image: mysql:8.0 + image: postgres:13 container_name: toby-db-test environment: - - MYSQL_ROOT_PASSWORD=${DOCKER_TEST_DB_ROOT_PASSWORD} - - MYSQL_DATABASE=${DOCKER_TEST_DB_DATABASE} - - MYSQL_USER=${DOCKER_TEST_DB_USERNAME} - - MYSQL_PASSWORD=${DOCKER_TEST_DB_PASSWORD} + - PGPASSWORD=${DOCKER_TEST_DB_ROOT_PASSWORD} + - POSTGRES_DB=${DOCKER_TEST_DB_DATABASE} + - POSTGRES_USER=${DOCKER_TEST_DB_USERNAME} + - POSTGRES_PASSWORD=${DOCKER_TEST_DB_PASSWORD} ports: - - ${DOCKER_TEST_DB_EXTERNAL_PORT:-3307}:3306 + - ${DOCKER_TEST_DB_EXTERNAL_PORT:-5433}:5432 + networks: + - toby-dev + restart: unless-stopped + + redis: + image: redis:6 + container_name: toby-redis + ports: + - ${FORWARD_REDIS_PORT:-6379}:6379 + volumes: + - toby-redis-data:/var/lib/redis networks: - toby-dev restart: unless-stopped @@ -91,11 +102,14 @@ services: - /dev/shm:/dev/shm networks: - toby-dev + restart: unless-stopped networks: toby-dev: driver: bridge volumes: - toby-mysql-data: - name: toby-mysql-data + toby-pgsql-data: + name: toby-pgsql-data + toby-redis-data: + name: toby-redis-data diff --git a/docker/dev/php/Dockerfile b/docker/dev/php/Dockerfile index b6cd37d..da0c855 100644 --- a/docker/dev/php/Dockerfile +++ b/docker/dev/php/Dockerfile @@ -9,12 +9,15 @@ RUN if [ ${INSTALL_XDEBUG} = true ]; then \ && docker-php-ext-enable xdebug \ ;fi -RUN apk --no-cache add \ +RUN pecl install redis \ + && apk --no-cache add \ + postgresql-dev \ zip \ libzip-dev \ - libpng-dev \ && docker-php-ext-install \ + pdo_pgsql \ zip \ - gd \ && docker-php-ext-configure \ - zip + zip \ + && docker-php-ext-enable \ + redis diff --git a/phpunit.xml b/phpunit.xml index c1b2a5c..0b25bbc 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -22,7 +22,7 @@ - + diff --git a/routes/web.php b/routes/web.php index 87f894a..c3505ad 100644 --- a/routes/web.php +++ b/routes/web.php @@ -50,9 +50,15 @@ Route::middleware("auth")->group(function (): void { ->name("vacation.requests.reject"); Route::post("/vacation-requests/{vacationRequest}/cancel", [VacationRequestController::class, "cancel"]) ->name("vacation.requests.cancel"); - Route::post("/vacation-requests/{vacationRequest}/accept-as-technical", [VacationRequestController::class, "acceptAsTechnical"]) + Route::post( + "/vacation-requests/{vacationRequest}/accept-as-technical", + [VacationRequestController::class, "acceptAsTechnical"], + ) ->name("vacation.requests.accept-as-technical"); - Route::post("/vacation-requests/{vacationRequest}/accept-as-administrative", [VacationRequestController::class, "acceptAsAdministrative"]) + Route::post( + "/vacation-requests/{vacationRequest}/accept-as-administrative", + [VacationRequestController::class, "acceptAsAdministrative"], + ) ->name("vacation.requests.accept-as-administrative"); Route::post("year-periods/{yearPeriod}/select", SelectYearPeriodController::class) diff --git a/storage/app/avatars/.gitignore b/storage/app/avatars/.gitignore deleted file mode 100644 index d6b7ef3..0000000 --- a/storage/app/avatars/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/tests/Unit/AvatarTest.php b/tests/Unit/AvatarTest.php deleted file mode 100644 index 2c13d21..0000000 --- a/tests/Unit/AvatarTest.php +++ /dev/null @@ -1,73 +0,0 @@ -createCurrentYearPeriod(); - Storage::fake(); - } - - public function testAvatarIsGeneratedWhenUserIsCreated(): void - { - $user = User::factory()->create(); - - Storage::assertExists($user->avatar); - } - - public function testAvatarIsDeletedWhenUserIsForceDeleted(): void - { - $user = User::factory()->create(); - - Storage::assertExists($user->avatar); - - $user->forceDelete(); - - Storage::assertMissing($user->avatar); - } - - public function testAvatarIsReplacedWhenUserChangedTheirName(): void - { - $user = User::factory()->create(); - $oldAvatar = $user->avatar; - - Storage::assertExists($oldAvatar); - - $user->update([ - "first_name" => "John", - "last_name" => "Doe", - ]); - - Storage::assertMissing($oldAvatar); - Storage::assertExists($user->avatar); - } - - public function testAvatarIsNotReplacedWhenUserChangedOtherData(): void - { - $user = User::factory()->create(); - $avatar = $user->avatar; - - Storage::assertExists($avatar); - - $user->update([ - "email" => "john.doe@example.com", - ]); - - Storage::assertExists($avatar); - } -}