diff --git a/.env.example b/.env.example index 696b7171..a75778c8 100644 --- a/.env.example +++ b/.env.example @@ -51,3 +51,5 @@ MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" UNITY_APP_URL="https://unity.izyim.com" +EXCHANGE_URL=https://dev.exchange.cief-malaysia.com/ +MIX_EXCHANGE_URL="${EXCHANGE_URL}" diff --git a/app/Classes/Modules/Accounts/ControllersLogic/CrossAuthenticateUserLogic.php b/app/Classes/Modules/Accounts/ControllersLogic/CrossAuthenticateUserLogic.php new file mode 100644 index 00000000..33bce845 --- /dev/null +++ b/app/Classes/Modules/Accounts/ControllersLogic/CrossAuthenticateUserLogic.php @@ -0,0 +1,44 @@ + 'Cross Authentication', + 'message' => 'You have successfully logged in to your account' + ]; + } + + /** @var CrossAuthenticationProcessor */ + private $crossAuthenticationProcessor; + + + /** + * CrossAuthenticateUserLogic constructor. + * @param CrossAuthenticationProcessor $authenticationProcessor + */ + public function __construct(CrossAuthenticationProcessor $crossAuthenticationProcessor) + { + $this->crossAuthenticationProcessor = $crossAuthenticationProcessor; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\AccessUnauthorisedException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function logic(Request $request): JsonResponse { + return $this->response($this->crossAuthenticationProcessor->execute($request)); + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/DataTransferObjects/CrossAuthenticationCredentialsObject.php b/app/Classes/Modules/Accounts/DataTransferObjects/CrossAuthenticationCredentialsObject.php new file mode 100644 index 00000000..67abf905 --- /dev/null +++ b/app/Classes/Modules/Accounts/DataTransferObjects/CrossAuthenticationCredentialsObject.php @@ -0,0 +1,43 @@ +access_token = $access_token; + $this->platform = $platform; + } + + /** + * @return string + */ + public function getAccessToken(): string + { + return $this->access_token; + } + + /** + * @return string + */ + public function getPlatform(): int + { + return $this->platform; + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/DataTransferObjects/UserSocialAccountObject.php b/app/Classes/Modules/Accounts/DataTransferObjects/UserSocialAccountObject.php new file mode 100644 index 00000000..7740a04e --- /dev/null +++ b/app/Classes/Modules/Accounts/DataTransferObjects/UserSocialAccountObject.php @@ -0,0 +1,54 @@ +app_id = $app_id; + $this->user = $user; + $this->platform = $platform; + } + + /** + * @return string + */ + public function getAppId(): String + { + return $this->app_id; + } + + /** + * @return User + */ + public function getUser(): User + { + return $this->user; + } + + /** + * @return int + */ + public function getPlatform(): int + { + return $this->platform; + } +} diff --git a/app/Classes/Modules/Accounts/Processors/CrossAuthenticationProcessor.php b/app/Classes/Modules/Accounts/Processors/CrossAuthenticationProcessor.php new file mode 100644 index 00000000..5658f932 --- /dev/null +++ b/app/Classes/Modules/Accounts/Processors/CrossAuthenticationProcessor.php @@ -0,0 +1,211 @@ +canCrossAuthenticateUser = $canCrossAuthenticateUser; + $this->crossAuthenticatesUser = $crossAuthenticatesUser; + $this->generatesAuthenticationToken = $generatesAuthenticationToken; + $this->fetchesUser = $fetchesUser; + $this->authenticationRedirect = $authenticationRedirect; + $this->createUserProcessor = $createUserProcessor; + $this->createCompanyProcessor = $createCompanyProcessor; + $this->createContactProcessor = $createContactProcessor; + $this->createCompanyModuleProcessor = $createCompanyModuleProcessor; + $this->createsCompanyConnection = $createsCompanyConnection; + $this->createsCompanyConnection = $createsCompanyConnection; + $this->approvesCompanyConnection = $approvesCompanyConnection; + $this->assignEmployeeProcessor = $assignEmployeeProcessor; + $this->uploadIdentityDocumentProcessor = $uploadIdentityDocumentProcessor; + $this->createsUserSocialAccount = $createsUserSocialAccount; + } + + + /** + * @param Request $request + * @return array + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\AccessUnauthorisedException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function execute(Request $request): array { + + $object = new CrossAuthenticationCredentialsObject($request->input('access_token'), $request->input('platform')); + + $this->canCrossAuthenticateUser->passes($object); + + $cross = $this->crossAuthenticatesUser->execute($object); + + $user_social_account = UserSocialAccount::where('app_id', $cross->token->user->id)->first(); + if (!$user_social_account) { + + $request->request->add([ + 'name' => $cross->token->user->name, + 'email' => $cross->token->user->email, + 'password' => 'pass123', + 'password_confirmation' => 'pass123', + ]); + + $user = $this->createUserProcessor->execute( + $request, + RoleTypes::USER, + env('APP_ENV') != 'production' ? ApprovalStatus::APPROVED : ApprovalStatus::PENDING_VERIFICATION + ); + + $company = $this->createCompanyProcessor->execute( + $cross->payload->data->name, + CompanyType::COMPANY_BUSINESS, + ApprovalStatus::PENDING_SUBMISSION + ); + + $contactObject = new ContactObject( + $cross->payload->data->contact->reference, + $cross->payload->data->contact->phone, + $cross->payload->data->contact->email, + $cross->payload->data->contact->wechat_id + ); + $contact = $this->createContactProcessor->execute($contactObject, $company); + + $companyModule = $this->createCompanyModuleProcessor->execute($company, BusinessType::IMPORTER); + + $connectionObject = new CompanyConnectionObject( + $companyModule, 'CIEF', + mt_rand(1000, 9999).(new GeneratesInitials())->name($company->name)->length(3)->generate() + ); + $connection = $this->createsCompanyConnection->execute($connectionObject); + + $this->approvesCompanyConnection->execute($connection); + + $object = new EmploymentObject($companyModule, $user); + $this->assignEmployeeProcessor->execute($object); + + $request->request->add([ + 'files' => [$cross->document->src], + 'identification_no' => $cross->payload->data->identification->reference, + ]); + + $this->uploadIdentityDocumentProcessor->execute($request, $company); + + $object = new UserSocialAccountObject( + $cross->token->user->id, + $user, + $request->input('platform') + ); + $this->createsUserSocialAccount->execute($object); + } + else { + $user = $user_social_account->user()->first(); + } + + return ['access_token' => $this->generatesAuthenticationToken->execute($user), 'redirect_url' => $this->authenticationRedirect->url($user)]; + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/Services/CreatesUserSocialAccount.php b/app/Classes/Modules/Accounts/Services/CreatesUserSocialAccount.php new file mode 100644 index 00000000..a6fd8fcd --- /dev/null +++ b/app/Classes/Modules/Accounts/Services/CreatesUserSocialAccount.php @@ -0,0 +1,24 @@ +user_id = $object->getUser()->id; + $model->app_id = $object->getAppId(); + $model->platform = $object->getPlatform(); + return $this->handler($model); + + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/Services/CrossAuthenticatesUser.php b/app/Classes/Modules/Accounts/Services/CrossAuthenticatesUser.php new file mode 100644 index 00000000..54835b17 --- /dev/null +++ b/app/Classes/Modules/Accounts/Services/CrossAuthenticatesUser.php @@ -0,0 +1,40 @@ +getPlatform() == PlatformType::EXCHANGE) { + + $token = $object->getAccessToken(); + + $tokenParts = explode(".", $token); + $tokenPayload = base64_decode($tokenParts[1]); + $jwtPayload = json_decode($tokenPayload); + + $response = Http::withToken($object->getAccessToken())->get(env('EXCHANGE_URL') . 'api/v1/company/' . $jwtPayload->user->company_id . '/show')->object(); + + $response_document = Http::withToken($object->getAccessToken())->get(env('EXCHANGE_URL') . 'api/v1/storage/' . $response->payload->data->identification->files[0]->file->file_info[0]->original->file . '/fetch')->object(); + $response->token = $jwtPayload; + $response->document = $response_document->payload; + } + + return $response; + + } + +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/Services/FetchesUserSocialAccount.php b/app/Classes/Modules/Accounts/Services/FetchesUserSocialAccount.php new file mode 100644 index 00000000..c2e1c676 --- /dev/null +++ b/app/Classes/Modules/Accounts/Services/FetchesUserSocialAccount.php @@ -0,0 +1,33 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/Standards/Rules/CanCrossAuthenticateUser.php b/app/Classes/Modules/Accounts/Standards/Rules/CanCrossAuthenticateUser.php new file mode 100644 index 00000000..115a7ea6 --- /dev/null +++ b/app/Classes/Modules/Accounts/Standards/Rules/CanCrossAuthenticateUser.php @@ -0,0 +1,54 @@ +userCrossAuthenticationValidation = $userCrossAuthenticationValidation; + } + + /** + * @return bool + */ + protected function authorized(): bool + { + return true; + + } + + + /** + * @param AuthenticationCredentialsObject $object + * @return bool + * @throws RequestValidationException + */ + protected function validators($object): bool + { + return $this->userCrossAuthenticationValidation->validate($object); + } + + /** + * @param AuthenticationCredentialsObject $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounts/Standards/Validators/UserCrossAuthenticationValidation.php b/app/Classes/Modules/Accounts/Standards/Validators/UserCrossAuthenticationValidation.php new file mode 100644 index 00000000..ec170dc7 --- /dev/null +++ b/app/Classes/Modules/Accounts/Standards/Validators/UserCrossAuthenticationValidation.php @@ -0,0 +1,43 @@ + $object->getAccesstoken(), + 'platform' => $object->getPlatform() + ]; + } + + /** + * @return array + */ + protected function rules(): array { + return [ + 'access_token' => 'required', + 'platform' => 'required' + ]; + } + + /** + * @return array + */ + protected function messages(): array { + return []; + } + + + + +} \ No newline at end of file diff --git a/app/Classes/ValueObjects/Constants/PlatformType.php b/app/Classes/ValueObjects/Constants/PlatformType.php new file mode 100644 index 00000000..d9ddd0e3 --- /dev/null +++ b/app/Classes/ValueObjects/Constants/PlatformType.php @@ -0,0 +1,9 @@ +execute($request); + } + +} diff --git a/app/Models/UserSocialAccount.php b/app/Models/UserSocialAccount.php new file mode 100644 index 00000000..71aa73d8 --- /dev/null +++ b/app/Models/UserSocialAccount.php @@ -0,0 +1,32 @@ +belongsTo(User::class, 'user_id', 'id'); + } +} diff --git a/database/migrations/2021_09_01_212235_create_user_social_accounts_table.php b/database/migrations/2021_09_01_212235_create_user_social_accounts_table.php new file mode 100644 index 00000000..612f47c6 --- /dev/null +++ b/database/migrations/2021_09_01_212235_create_user_social_accounts_table.php @@ -0,0 +1,35 @@ +id(); + $table->foreignId('user_id'); + $table->string('app_id')->nullable(); + $table->integer('platform')->default(0); + $table->softDeletes(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_social_accounts'); + } +} diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index bba317e6..983c7aad 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -23,7 +23,7 @@ class DatabaseSeeder extends Seeder $this->call(CountriesTableSeeder::class); $this->call(CurrenciesTableSeeder::class); - $this->call(CompaniesTableSeeder::class); - $this->call(OrdersTableSeeder::class); + // $this->call(CompaniesTableSeeder::class); + // $this->call(OrdersTableSeeder::class); } } \ No newline at end of file diff --git a/resources/assets/vue/components/accounts/forms/CrossPlatformLoginFormComponent.vue b/resources/assets/vue/components/accounts/forms/CrossPlatformLoginFormComponent.vue new file mode 100644 index 00000000..0634ddbe --- /dev/null +++ b/resources/assets/vue/components/accounts/forms/CrossPlatformLoginFormComponent.vue @@ -0,0 +1,66 @@ + + \ No newline at end of file diff --git a/resources/views/pages/accounts/login.blade.php b/resources/views/pages/accounts/login.blade.php index 78d275b7..bc31ecc4 100644 --- a/resources/views/pages/accounts/login.blade.php +++ b/resources/views/pages/accounts/login.blade.php @@ -26,6 +26,7 @@
+
diff --git a/routes/account.php b/routes/account.php index ff6a9960..b62064aa 100644 --- a/routes/account.php +++ b/routes/account.php @@ -7,9 +7,14 @@ Route::group(['prefix' => 'account', 'namespace' => 'Accounts', 'as' => 'account Route::post('/registration', 'CreateCustomerController@create')->name('registration.register'); Route::post('/invite/registration', 'CreateInvitedCustomerController@create')->name('registration.invite.register'); + + Route::group(['prefix' => 'authentication', 'as' => 'authentication.'], function () { Route::group(['prefix' => 'login', 'as' => 'authenticate.'], function () { Route::post('/attempt', 'UserAuthenticationController@authenticate')->name('attempt'); + + Route::post('/cross-attempt', 'UserCrossAuthenticationController@authenticate')->name('cross.attempt'); + Route::post('/check_email', 'CheckEmailController@check')->name('email.check'); });