From 8dfae71477dc7bb19ee4c2effdb1f90d16232040 Mon Sep 17 00:00:00 2001 From: "sosuke.iwabuchi" Date: Mon, 12 Jun 2023 19:51:37 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=AD=E3=82=B0=E3=82=A4=E3=83=B3=E3=83=A6?= =?UTF-8?q?=E3=83=BC=E3=82=B6=E3=83=BC=E4=B8=80=E8=A6=A7=E6=A9=9F=E8=83=BD?= =?UTF-8?q?=E7=AD=89=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Web/LoginUser/CreateController.php | 74 +++++++++ .../Controllers/Web/LoginUser/CreateParam.php | 26 ++++ .../Web/LoginUser/LoginUsersController.php | 63 ++++++++ .../Web/LoginUser/LoginUsersParam.php | 28 ++++ app/Http/Controllers/Web/WebController.php | 4 + app/Logic/User/LoginUserManager.php | 146 ++++++++++++++++++ app/Models/User.php | 18 ++- app/Repositories/LoginUserRepository.php | 81 ++++++++++ app/Repositories/LoginUserRepositoryData.php | 10 ++ .../2023_04_15_150500_create_users_table.php | 15 +- database/seeders/TestUserSeeder.php | 8 + routes/api.php | 4 + 12 files changed, 471 insertions(+), 6 deletions(-) create mode 100644 app/Http/Controllers/Web/LoginUser/CreateController.php create mode 100644 app/Http/Controllers/Web/LoginUser/CreateParam.php create mode 100644 app/Http/Controllers/Web/LoginUser/LoginUsersController.php create mode 100644 app/Http/Controllers/Web/LoginUser/LoginUsersParam.php create mode 100644 app/Logic/User/LoginUserManager.php create mode 100644 app/Repositories/LoginUserRepository.php create mode 100644 app/Repositories/LoginUserRepositoryData.php diff --git a/app/Http/Controllers/Web/LoginUser/CreateController.php b/app/Http/Controllers/Web/LoginUser/CreateController.php new file mode 100644 index 0000000..d2d6a6b --- /dev/null +++ b/app/Http/Controllers/Web/LoginUser/CreateController.php @@ -0,0 +1,74 @@ +roleAllow(UserRole::CONTRACT_ADMIN); + } + + protected function getParam(): IParam + { + return $this->param; + } + + protected function run(Request $request): JsonResponse + { + $param = $this->param; + + + try { + $this->transaction->beginTransaction(); + + + $currentContract = $this->loginUser()->getCurrentContract(); + if (!$currentContract) { + throw new AppCommonException("認証不正"); + } + + $messages = $this->manager->initForCreate($currentContract) + ->fill($param->toArray()) + ->create(); + + if (count($messages) !== 0) { + $this->transaction->rollBack(); + return $this->validateErrorResponse($messages); + } + + $this->transaction->commit(); + } catch (Exception $e) { + $this->transaction->rollBack(); + throw $e; + } + + return $this->successResponse(); + } +} diff --git a/app/Http/Controllers/Web/LoginUser/CreateParam.php b/app/Http/Controllers/Web/LoginUser/CreateParam.php new file mode 100644 index 0000000..baa55fb --- /dev/null +++ b/app/Http/Controllers/Web/LoginUser/CreateParam.php @@ -0,0 +1,26 @@ + $this->str(['email:dns']), + User::COL_NAME_NAME => $this->str(), + User::COL_NAME_PASSWORD => $this->str([new LoginPassword()]), + ]; + } +} diff --git a/app/Http/Controllers/Web/LoginUser/LoginUsersController.php b/app/Http/Controllers/Web/LoginUser/LoginUsersController.php new file mode 100644 index 0000000..283aea2 --- /dev/null +++ b/app/Http/Controllers/Web/LoginUser/LoginUsersController.php @@ -0,0 +1,63 @@ +roleAllow(UserRole::CONTRACT_ADMIN); + } + + protected function getParam(): IParam + { + return $this->param; + } + + protected function run(Request $request): JsonResponse + { + $param = $this->param; + + $currentContractId = $this->loginUser()->getCurrentContractId(); + if (!$currentContractId) { + throw new AppCommonException("認証不正"); + } + + $condition = [ + ...$param->toArray(), + LoginUserRepository::CONDITION_CONTRACT_ID => $currentContractId, + ]; + + $list = $this->repository->get($condition); + + + return $this->successResponse([ + 'records' => $list + ]); + } +} diff --git a/app/Http/Controllers/Web/LoginUser/LoginUsersParam.php b/app/Http/Controllers/Web/LoginUser/LoginUsersParam.php new file mode 100644 index 0000000..c3f0b6a --- /dev/null +++ b/app/Http/Controllers/Web/LoginUser/LoginUsersParam.php @@ -0,0 +1,28 @@ + $this->str(true), + Repository::CONDITION_NAME => $this->str(true), + Repository::CONDITION_EMAIL => $this->str(true), + ], + $this->sortableRules(), + ); + } +} diff --git a/app/Http/Controllers/Web/WebController.php b/app/Http/Controllers/Web/WebController.php index e3eee6d..bdf4785 100644 --- a/app/Http/Controllers/Web/WebController.php +++ b/app/Http/Controllers/Web/WebController.php @@ -7,6 +7,7 @@ use App\Codes\UserRole; use App\Exceptions\AppCommonException; use App\Exceptions\ExclusiveException; use App\Exceptions\GeneralErrorMessageException; +use App\Util\DBUtil; use Exception; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Bus\DispatchesJobs; @@ -74,6 +75,8 @@ abstract class WebController extends BaseController */ private $data = null; + protected DBUtil $transaction; + /** * 返却する結果コード * @@ -83,6 +86,7 @@ abstract class WebController extends BaseController public function __construct() { + $this->transaction = DBUtil::instance(); } diff --git a/app/Logic/User/LoginUserManager.php b/app/Logic/User/LoginUserManager.php new file mode 100644 index 0000000..4aa75c3 --- /dev/null +++ b/app/Logic/User/LoginUserManager.php @@ -0,0 +1,146 @@ +setContract($contractId); + $this->setUser(null); + $this->initialized = true; + return $this; + } + + public function initForModify(string|Contract $contractId, string|User $userId) + { + $this->setContract($contractId); + $this->setUser($userId); + $this->initialized = true; + return $this; + } + + public function getTimestamp(): Carbon + { + if (!$this->initialized) { + throw new LogicException("初期化不正"); + } + return $this->user->updated_at < $this->contract->updated_at ? $this->contract->updated_at : $this->user->updated_at; + } + + public function fill(array $attr) + { + if (!$this->initialized) { + throw new LogicException("初期化不正"); + } + $this->user->fill($attr); + return $this; + } + + public function create(): array + { + $messages = $this->checkParam(); + + if (count($messages) !== 0) { + return $messages; + } + + $this->user->save(); + return []; + } + public function update(): array + { + $messages = $this->checkParam(); + + if (count($messages) !== 0) { + return $messages; + } + + $this->user->save(); + return []; + } + + private function setContract(string|Contract $contractId) + { + if ($contractId instanceof Contract) { + $this->contract = $contractId; + $this->initialized = true; + return; + } + + $this->contract = Contract::findOrFail($contractId); + $this->initialized = true; + return; + } + + private function setUser(string|User|null $userId) + { + if ($userId instanceof User) { + $this->user = $userId; + return; + } else if (is_string($userId)) { + $this->user = User::findOrFail($userId); + return; + } + + $this->user = new User(); + $this->user->setContract($this->contract); + $this->user->role = UserRole::NORMAL_ADMIN; + } + + private function checkParam() + { + $validator = Validator::make($this->user->toArray(), []); + + if ($validator->failed()) { + throw new LogicException("バリデートエラー"); + } + + $messages = []; + + $this->checkEmailUnique($messages); + $this->passwordEncrypto($messages); + + return $messages; + } + + private function passwordEncrypto(array &$messages) + { + if ($this->user->isDirty(User::COL_NAME_PASSWORD)) { + $this->user->password = Hash::make($this->user->password); + } + } + + private function checkEmailUnique(array &$messages) + { + if ($this->user->isDirty(User::COL_NAME_EMAIL)) { + + $exists = User::whereEmail($this->user->email) + ->where(User::COL_NAME_ID, '<>', $this->user->id) + ->exists(); + + if ($exists) { + $messages[User::COL_NAME_EMAIL] = trans('validation.unique'); + } + } + } +} diff --git a/app/Models/User.php b/app/Models/User.php index 5035fa7..838d8ef 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -24,6 +24,13 @@ class User extends Authenticatable implements IModelFeature const COL_NAME_ROLE = 'role'; const COL_NAME_EMAIL = 'email'; const COL_NAME_NAME = 'name'; + const COL_NAME_PASSWORD = 'password'; + + const COL_NAME_CREATED_BY = ColumnName::CREATED_BY; + const COL_NAME_UPDATED_BY = ColumnName::UPDATED_BY; + const COL_NAME_CREATED_AT = ColumnName::CREATED_AT; + const COL_NAME_UPDATED_AT = ColumnName::UPDATED_AT; + const COL_NAME_DELETED_AT = ColumnName::DELETED_AT; /** * The attributes that should be hidden for serialization. @@ -31,7 +38,16 @@ class User extends Authenticatable implements IModelFeature * @var array */ protected $hidden = [ - 'password', + self::COL_NAME_PASSWORD, + ]; + + protected $guarded = [ + self::COL_NAME_ID, + self::COL_NAME_CREATED_BY, + self::COL_NAME_UPDATED_BY, + self::COL_NAME_CREATED_AT, + self::COL_NAME_UPDATED_AT, + self::COL_NAME_DELETED_AT, ]; protected $casts = [ diff --git a/app/Repositories/LoginUserRepository.php b/app/Repositories/LoginUserRepository.php new file mode 100644 index 0000000..16cb0d1 --- /dev/null +++ b/app/Repositories/LoginUserRepository.php @@ -0,0 +1,81 @@ + + */ + public function get(array $condition): Collection + { + $table = User::getBuilder(static::TABLE_USER); + + + // -----検索条件 + // ID + $this->where($table, $condition, static::CONDITION_ID, $this->makeColumnName([static::TABLE_USER, User::COL_NAME_ID])); + + // 名前 + $name = data_get($condition, static::CONDITION_NAME); + if ($name) { + $table->where($this->makeColumnName([static::TABLE_USER, User::COL_NAME_NAME]), 'like', "%{$name}%"); + } + + // EMAIL + $email = data_get($condition, static::CONDITION_EMAIL); + if ($email) { + $table->where($this->makeColumnName([static::TABLE_USER, User::COL_NAME_EMAIL]), 'like', "%{$email}%"); + } + // 契約ID + $this->where($table, $condition, static::CONDITION_CONTRACT_ID, $this->makeColumnName([static::TABLE_USER, User::COL_NAME_CONTRACT_ID])); + + $table->select($this->columns()); + + $main = DB::table($table, "main"); + + // ソート + $this->sort($main, $condition); + $main->orderBy(static::CONDITION_ID); + + // リミット + $this->limit($main, $condition); + + + return LoginUserRepositoryData::makeList($main->get()); + } + + private function columns() + { + $user = static::TABLE_USER; + $columns = [ + $this->makeColumnNameForSelect([$user, User::COL_NAME_ID]), + $this->makeColumnNameForSelect([$user, User::COL_NAME_NAME]), + $this->makeColumnNameForSelect([$user, User::COL_NAME_ROLE]), + $this->makeColumnNameForSelect([$user, User::COL_NAME_EMAIL]), + $this->makeColumnNameForSelect([$user, User::COL_NAME_UPDATED_AT]), + ]; + + + return $columns; + } +} diff --git a/app/Repositories/LoginUserRepositoryData.php b/app/Repositories/LoginUserRepositoryData.php new file mode 100644 index 0000000..eb4cf56 --- /dev/null +++ b/app/Repositories/LoginUserRepositoryData.php @@ -0,0 +1,10 @@ +schema()); - MigrationHelper::createTable('user_histories', $this->schema()); + MigrationHelper::createTable('users', $this->schema(false)); + MigrationHelper::createTable('user_histories', $this->schema(true)); } /** @@ -27,10 +27,10 @@ return new class extends Migration Schema::dropIfExists('user_histories'); } - private function schema() + private function schema(bool $forHistory) { - return function (Blueprint $table, MigrationHelper $helper) { + return function (Blueprint $table, MigrationHelper $helper) use ($forHistory) { $helper->baseColumn() ->contractId(); @@ -41,7 +41,12 @@ return new class extends Migration $helper->index(1, [ColumnName::CONTRACT_ID]); - $helper->index(2, ['email']); + + if ($forHistory) { + $helper->index(2, ['email']); + } else { + $helper->unique(1, ['email']); + } }; } }; diff --git a/database/seeders/TestUserSeeder.php b/database/seeders/TestUserSeeder.php index b218c8c..66685bb 100644 --- a/database/seeders/TestUserSeeder.php +++ b/database/seeders/TestUserSeeder.php @@ -52,5 +52,13 @@ class TestUserSeeder extends Seeder User::COL_NAME_NAME => $email . "太郎", ]); } + $email = 'hello-admin@aa.com'; + if (!User::whereEmail($email)->exists()) { + User::factory()->for($contract)->create([ + User::COL_NAME_EMAIL => $email, + User::COL_NAME_ROLE => UserRole::CONTRACT_ADMIN, + User::COL_NAME_NAME => $email . "太郎", + ]); + } } } diff --git a/routes/api.php b/routes/api.php index 45ab848..322ac2f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -30,6 +30,10 @@ RouteHelper::get('/receipt/download', App\Http\Controllers\Web\ReceiptIssuingOrd RouteHelper::get('/contracts', App\Http\Controllers\Web\Contract\ContractsController::class); +RouteHelper::get('/users', App\Http\Controllers\Web\LoginUser\LoginUsersController::class); +RouteHelper::post('/user/create', App\Http\Controllers\Web\LoginUser\CreateController::class); + + // Custom for HelloTechno RouteHelper::get('/custom/hello-techno/customers', App\Http\Controllers\Web\Custom\HelloTechno\CustomersController::class); RouteHelper::get('/custom/hello-techno/parkings', App\Http\Controllers\Web\Custom\HelloTechno\ParkingsController::class);