From 6b2aff910b7d5758a2ed77eaf1e595956961a8ca Mon Sep 17 00:00:00 2001 From: Leonid Nikitin Date: Sun, 2 Jul 2023 16:17:18 +0600 Subject: [PATCH] Added console command to add user with admin role. --- app/Console/Commands/CreateUserAdmin.php | 94 +++++++++++++++++++ app/Dto/User/ManyRoleDto.php | 32 +++++++ .../Dto/User/ManyRoleDtoException.php | 8 ++ app/Models/Role.php | 59 ++++++++++++ app/Models/User.php | 18 ++++ app/Repositories/RoleRepository.php | 13 +++ app/Services/User/UserCommandHandler.php | 57 +++++++++++ .../2023_06_28_155124_create_roles.php | 60 ++++++++++++ 8 files changed, 341 insertions(+) create mode 100644 app/Console/Commands/CreateUserAdmin.php create mode 100644 app/Dto/User/ManyRoleDto.php create mode 100644 app/Exceptions/Dto/User/ManyRoleDtoException.php create mode 100644 app/Models/Role.php create mode 100644 app/Repositories/RoleRepository.php create mode 100644 app/Services/User/UserCommandHandler.php create mode 100644 database/migrations/2023_06_28_155124_create_roles.php diff --git a/app/Console/Commands/CreateUserAdmin.php b/app/Console/Commands/CreateUserAdmin.php new file mode 100644 index 0000000..518ddbe --- /dev/null +++ b/app/Console/Commands/CreateUserAdmin.php @@ -0,0 +1,94 @@ +getData(); + + if ($validator->fails()) { + $this->errorMessageAndStop($validator->errors()->all()); + } + $data = $validator->valid(); + + try { + $role = $roleRepository->getRoleBySlug(SystemRole::Admin->value); + if (is_null($role)) { + $this->errorMessageAndStop('Administrator role not found.'); + } + $user = DB::transaction(function () use($data, $userCommandHandler, $role) { + $data['name'] = 'Administrator'; + $user = $userCommandHandler->handleStore($data, $data['password']); + $userCommandHandler->handleConfirmationByEmail($user); + $roles = new ManyRoleDto([$role->id]); + $userCommandHandler->handleSyncRoles($user, $roles); + + return $user; + }); + } catch (\Throwable $e) { + $this->errorMessageAndStop($e->getMessage()); + } + + $this->info('The command was successful!'); + } + + private function getData(): Validator + { + return ValidatorFacade::make([ + 'email' => $this->argument('email'), + 'password' => $this->argument('password'), + ], [ + 'email' => ['required', 'email', 'unique:users,email'], + 'password' => ['required', Password::default()], + ]); + } + + private function stop(): never + { + exit; + } + + private function errorMessageAndStop(string | array $error): never + { + $this->info('User not created. See error messages below:'); + + if (is_array($error)) { + foreach ($error as $err) { + $this->error($err); + } + } else { + $this->error($error); + } + + $this->stop(); + } +} diff --git a/app/Dto/User/ManyRoleDto.php b/app/Dto/User/ManyRoleDto.php new file mode 100644 index 0000000..00e4a8a --- /dev/null +++ b/app/Dto/User/ManyRoleDto.php @@ -0,0 +1,32 @@ +add((int) $role); + } + } + + public function add(int $id): void + { + if ($id < 1) { + throw new ManyRoleDtoException('Only Integer > 0.'); + } + $this->roles[] = $id; + } + + public function toArray(): array + { + return $this->roles; + } +} diff --git a/app/Exceptions/Dto/User/ManyRoleDtoException.php b/app/Exceptions/Dto/User/ManyRoleDtoException.php new file mode 100644 index 0000000..5c985ed --- /dev/null +++ b/app/Exceptions/Dto/User/ManyRoleDtoException.php @@ -0,0 +1,8 @@ +orderBy('id', 'desc'); + } + + public function scopeAlphavit(Builder $query): Builder + { + return $query->orderBy('name', 'asc'); + } + + public function permissions(): hasMany + { + return $this->hasMany(RolePermission::class, 'role_id', 'id'); + } + + + /** + * Проверяем можем мы удалять эту группу или нет. + * Есть системные группы, которые нельзя удалять. + */ + public function isRemove(): bool + { + $dontRemove = SystemRoleEnum::toArray(); + return (array_search($this->slug, $dontRemove) === false); + } + + /** + * Проверка эта группа самая главная или нет. + */ + public function isAdmin(): bool + { + return ($this->slug === SystemRoleEnum::Admin->value); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index af1babe..1145d40 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -4,6 +4,7 @@ namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; @@ -13,6 +14,15 @@ final class User extends Authenticatable { use HasApiTokens, HasFactory, Notifiable, SoftDeletes; + /** + * The model's default values for attributes. + * + * @var array + */ + protected $attributes = [ + 'is_active' => true, + ]; + /** * The attributes that are mass assignable. * @@ -46,4 +56,12 @@ final class User extends Authenticatable 'email_verified_at' => 'datetime', 'is_active' => 'boolean' ]; + + /** + * Return the user's roles + */ + public function roles(): belongsToMany + { + return $this->belongsToMany(Role::class); + } } diff --git a/app/Repositories/RoleRepository.php b/app/Repositories/RoleRepository.php new file mode 100644 index 0000000..cba64f6 --- /dev/null +++ b/app/Repositories/RoleRepository.php @@ -0,0 +1,13 @@ +where('slug', $slug)->first(); + } +} diff --git a/app/Services/User/UserCommandHandler.php b/app/Services/User/UserCommandHandler.php new file mode 100644 index 0000000..6176855 --- /dev/null +++ b/app/Services/User/UserCommandHandler.php @@ -0,0 +1,57 @@ +hashPassword($password); + $user = User::create($data); + + return $user; + } + + public function handleUpdate(User $user, array $data): User + { + if (isset($data['email'])) { + $data['email'] = Str::lower($data['email']); + } + + if (isset($data['password'])) { + unset($data['password']); + } + + $user->update($data); + $user->touch(); + + return $user; + } + + public function handleConfirmationByEmail(User $user): void + { + $user->update(['email_verified_at' => new Carbon('NOW')]); + } + + public function handleUpdatePassword(User $user, int|string $password): void + { + $user->update(['password' => $this->hashPassword($password)]); + } + + public function handleSyncRoles(User $user, ManyRoleDto $roles): void + { + $user->roles()->sync($roles->toArray()); + } + + private function hashPassword(int|string $password): string + { + return Hash::make($password); + } +} diff --git a/database/migrations/2023_06_28_155124_create_roles.php b/database/migrations/2023_06_28_155124_create_roles.php new file mode 100644 index 0000000..ed1d755 --- /dev/null +++ b/database/migrations/2023_06_28_155124_create_roles.php @@ -0,0 +1,60 @@ +id(); + $table->string('name'); + $table->string('slug')->unique(); + $table->timestamps(); + $table->softDeletes(); + }); + + DB::table('roles')->insert([ + 'name' => 'Administrator', + 'slug' => 'admin', + 'created_at' => Carbon::now(), + 'updated_at' => Carbon::now() + ]); + + Schema::create('role_user', function (Blueprint $table) { + $table->unsignedBigInteger('user_id')->index(); + $table->unsignedBigInteger('role_id'); + $table->foreign('user_id')->references('id')->on('users'); + $table->foreign('role_id')->references('id')->on('roles'); + $table->primary(['user_id', 'role_id']); + }); + + Schema::create('role_permission', function (Blueprint $table) { + $table->id(); + $table->unsignedBigInteger('role_id')->index(); + $table->string('permission'); + $table->foreign('role_id')->references('id')->on('roles'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('role_permission'); + Schema::dropIfExists('role_user'); + Schema::dropIfExists('roles'); + } +};