diff --git a/app/Email/Guests/PasswordSettingStart.php b/app/Email/Guests/PasswordSettingStart.php new file mode 100644 index 0000000..086df31 --- /dev/null +++ b/app/Email/Guests/PasswordSettingStart.php @@ -0,0 +1,35 @@ + $this->getVerifyUrl(), + ]; + } + + private function getVerifyUrl(): string + { + return $this->getAppUrl(['setting', 'password', 'verify', $this->token->token]); + } +} diff --git a/app/Http/Controllers/Web/Auth/LoginController.php b/app/Http/Controllers/Web/Auth/LoginController.php index 938e072..aec001b 100644 --- a/app/Http/Controllers/Web/Auth/LoginController.php +++ b/app/Http/Controllers/Web/Auth/LoginController.php @@ -43,9 +43,6 @@ class LoginController extends WebController return $this->failedResponse(); } - /** - * @var Customer - */ $customer = $customer->first(); $kintoneId = $customer->getRecordId(); @@ -66,7 +63,6 @@ class LoginController extends WebController $user->save(); } - if (Auth::attempt([ 'email' => $param->email, 'password' => $param->password, @@ -76,22 +72,7 @@ class LoginController extends WebController return $this->failedResponse(); } } else { - // 初回ログインのケース - $password = "testtest"; - $user = new User(); - $user->email = $param->email; - $user->kintone_id = $customer->getRecordId(); - $user->password = $password; - $user->kintone_customer_code = $customer->getNumber(Customer::FIELD_CUSTOMER_CODE); - $user->save(); - if (Auth::attempt([ - 'email' => $param->email, - 'password' => $password, - ])) { - return $this->successResponse($customer->toArray()); - } else { - return $this->failedResponse(); - } + return $this->failedResponse(); } } } diff --git a/app/Http/Controllers/Web/Auth/PasswordSettingStartController.php b/app/Http/Controllers/Web/Auth/PasswordSettingStartController.php new file mode 100644 index 0000000..d0cb290 --- /dev/null +++ b/app/Http/Controllers/Web/Auth/PasswordSettingStartController.php @@ -0,0 +1,77 @@ +param; + + $access = Customer::getAccess(); + $query = Customer::getQuery()->where(Customer::FIELD_EMAIL, $param->email); + + $customer = $access->some($query); + + if ($customer->count() !== 1) { + + // 無効なユーザだが、セキュリティ対策として成功と見せかける + return $this->successResponse(); + } + + $customer = $customer->first(); + + $kintoneId = $customer->getRecordId(); + + $user = User::whereKintoneId($kintoneId) + ->first(); + + if ($user instanceof User) { + //データ同期 + if ($user->email !== $param->email) { + $user->email = $param->email; + $user->save(); + } + if ($user->kintone_customer_code !== $customer->getNumber(Customer::FIELD_CUSTOMER_CODE)) { + $user->kintone_customer_code = $customer->getNumber(Customer::FIELD_CUSTOMER_CODE); + $user->save(); + } + } else { + // 新規の場合はユーザーを追加する + $user = new User(); + $user->email = $param->email; + $user->kintone_id = $customer->getRecordId(); + $user->kintone_customer_code = $customer->getNumber(Customer::FIELD_CUSTOMER_CODE); + $user->save(); + } + + // トークン生成 + $this->manager->generate($user); + + return $this->successResponse(); + } +} diff --git a/app/Http/Controllers/Web/Auth/PasswordSettingStartParam.php b/app/Http/Controllers/Web/Auth/PasswordSettingStartParam.php new file mode 100644 index 0000000..ec80827 --- /dev/null +++ b/app/Http/Controllers/Web/Auth/PasswordSettingStartParam.php @@ -0,0 +1,19 @@ + $this->str([...Rule::email()]), + ]; + } +} diff --git a/app/Http/Controllers/Web/Auth/PasswordSettingVerifyController.php b/app/Http/Controllers/Web/Auth/PasswordSettingVerifyController.php new file mode 100644 index 0000000..d526a14 --- /dev/null +++ b/app/Http/Controllers/Web/Auth/PasswordSettingVerifyController.php @@ -0,0 +1,45 @@ +param; + + $user = $this->manager->verify($param->token); + if ($user === null) { + return $this->failedResponse(); + } + + $user->password = $param->password; + $user->save(); + + return $this->successResponse(); + } +} diff --git a/app/Http/Controllers/Web/Auth/PasswordSettingVerifyParam.php b/app/Http/Controllers/Web/Auth/PasswordSettingVerifyParam.php new file mode 100644 index 0000000..087f952 --- /dev/null +++ b/app/Http/Controllers/Web/Auth/PasswordSettingVerifyParam.php @@ -0,0 +1,21 @@ + $this->str(), + 'password' => $this->str([new LoginPassword()]), + ]; + } +} diff --git a/app/Listeners/Model/UpdatingListener.php b/app/Listeners/Model/UpdatingListener.php index da8ee48..fca496e 100644 --- a/app/Listeners/Model/UpdatingListener.php +++ b/app/Listeners/Model/UpdatingListener.php @@ -25,7 +25,9 @@ class UpdatingListener extends ModelListener // ログインパスワードのハッシュ化 if ($event->model instanceof User) { if ($event->model->isDirty(User::COL_NAME_PASSWORD)) { - $event->model->password = Hash::make($event->model->password); + if ($event->model->password !== null) { + $event->model->password = Hash::make($event->model->password); + } } } diff --git a/app/Logic/PasswordSettingManager.php b/app/Logic/PasswordSettingManager.php new file mode 100644 index 0000000..1520b8b --- /dev/null +++ b/app/Logic/PasswordSettingManager.php @@ -0,0 +1,50 @@ +user_id = $user->id; + $model->token = Str::uuid(); + $model->expires_at = DateUtil::now()->addHours(24); + $model->save(); + + // メール送信 + $email = (new PasswordSettingStart($model)) + ->setEmail($user->email); + $emailManager = new EmailManager($email); + $emailManager->confirm(); + } + + public function verify(string $token): User|null + { + $model = PasswordSettingToken::whereToken($token) + ->expiresIn() + ->first(); + + if ($model === null) { + return null; + } + + $user = User::whereId($model->user_id)->firstOrFail(); + + $model->delete(); + + return $user; + } +} diff --git a/app/Models/PasswordSettingToken.php b/app/Models/PasswordSettingToken.php new file mode 100644 index 0000000..19bb402 --- /dev/null +++ b/app/Models/PasswordSettingToken.php @@ -0,0 +1,35 @@ + 'datetime', + ]; + + public function getHistory(): ?HistoryModel + { + return null; + } + + public function getModelName(): string + { + return "ログインパスワード設定トークン"; + } + + public function scopeExpiresIn(Builder $query) + { + return $query->where(self::COL_NAME_EXPIRES_AT, '>', DateUtil::now()); + } +} diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2014_10_12_000000_create_users_table.php index cfc308d..ebbf6b8 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2014_10_12_000000_create_users_table.php @@ -16,9 +16,9 @@ return new class extends Migration $helper = new MigrationHelper($table); $helper->baseColumn(); $table->string('email')->unique()->comment('Email'); - $table->string('password')->comment('ログインパスワード'); - $table->string('kintone_id')->comment('KintoneID'); - $table->string('kintone_customer_code')->comment('顧客コード'); + $table->string('password')->nullable()->comment('ログインパスワード'); + $table->string('kintone_id')->nullable()->comment('KintoneID'); + $table->string('kintone_customer_code')->nullable()->comment('顧客コード'); $helper->index(1, ['email']); $helper->index(2, ['kintone_id']); @@ -29,9 +29,9 @@ return new class extends Migration $helper->baseColumn(); $table->string('email')->comment('Email'); - $table->string('password')->comment('ログインパスワード'); - $table->string('kintone_id')->comment('KintoneID'); - $table->string('kintone_customer_code')->comment('顧客コード'); + $table->string('password')->nullable()->comment('ログインパスワード'); + $table->string('kintone_id')->nullable()->comment('KintoneID'); + $table->string('kintone_customer_code')->nullable()->comment('顧客コード'); $helper->index(1, ['email']); $helper->index(2, ['kintone_id']); diff --git a/database/migrations/2023_09_22_154100_create_password_setting_tokens_table.php b/database/migrations/2023_09_22_154100_create_password_setting_tokens_table.php new file mode 100644 index 0000000..ff2b196 --- /dev/null +++ b/database/migrations/2023_09_22_154100_create_password_setting_tokens_table.php @@ -0,0 +1,37 @@ +baseColumn(); + + $table->uuid(ColumnName::USER_ID)->unique()->comment('ユーザーID'); + $table->uuid('token')->unique()->comment('トークン'); + $table->string('expires_at')->comment('有効期限'); + + $helper->index(1, [ColumnName::USER_ID]); + $helper->index(3, ['token']); + $helper->index(4, ['expires_at']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('email_change_tokens'); + } +}; diff --git a/resources/views/emails/guests/password_setting_start.blade.php b/resources/views/emails/guests/password_setting_start.blade.php new file mode 100644 index 0000000..54ef19d --- /dev/null +++ b/resources/views/emails/guests/password_setting_start.blade.php @@ -0,0 +1,6 @@ +@extends('emails.layouts.guest') + +@section('contents') +こちらのURLにアクセスし、ログインパスワードの変更手続きを進めてください。 +{{ $url }} +@endsection \ No newline at end of file diff --git a/routes/api.php b/routes/api.php index 8fdb9df..57e579f 100644 --- a/routes/api.php +++ b/routes/api.php @@ -34,3 +34,6 @@ RouteHelper::post('/ask', App\Http\Controllers\Web\FAQ\AskController::class); RouteHelper::post('/email/change/start', App\Http\Controllers\Web\Customer\ChangeEmailStartController::class); RouteHelper::post('/email/change/verify', App\Http\Controllers\Web\Customer\ChangeEmailVerifyController::class); + +RouteHelper::post('/password/setting/start', App\Http\Controllers\Web\Auth\PasswordSettingStartController::class); +RouteHelper::post('/password/setting/verify', App\Http\Controllers\Web\Auth\PasswordSettingVerifyController::class);