From 9ad1f0d9b27bfc907c8aa5b41edfdc9eb2dee2e0 Mon Sep 17 00:00:00 2001 From: Ramon Gutierrez Date: Fri, 11 Aug 2023 07:26:49 +0800 Subject: [PATCH] Add account deletion api endpoints #746 --- config/packages/security.yaml | 4 +- config/routes/apiv2.yaml | 18 +- .../CustomerAppAPI/AccountController.php | 169 ++++++++++++++ .../CustomerAppAPI/AuthController.php | 4 +- src/Entity/CustomerDeleteRequest.php | 209 ++++++++++++++++++ src/Entity/CustomerSession.php | 2 +- 6 files changed, 401 insertions(+), 5 deletions(-) create mode 100644 src/Controller/CustomerAppAPI/AccountController.php create mode 100644 src/Entity/CustomerDeleteRequest.php diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 776c5e9a..acb25b0a 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -54,7 +54,7 @@ security: security: false cust_api_v2: - pattern: ^\/apiv2\/(?!register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/|version_check|version_check\/) + pattern: ^\/apiv2\/(?!register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/|version_check|version_check\/|account|account\/|account_code_validate|account_code_validate\/|account_resend_code|account_resend_code\/) provider: api_v2_provider access_denied_handler: Catalyst\ApiBundle\Service\AccessDeniedHandler stateless: true @@ -63,7 +63,7 @@ security: - Catalyst\ApiBundle\Security\Authenticator cust_api_v2_guest: - pattern: ^\/apiv2\/(register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/|version_check|version_check\/) + pattern: ^\/apiv2\/(register|register\/|number_confirm|number_confirm\/|code_validate|code_validate\/|resend_code|resend_code\/|version_check|version_check\/|account|account\/|account_code_validate|account_code_validate\/|account_resend_code|account_resend_code\/) security: false warranty_api: diff --git a/config/routes/apiv2.yaml b/config/routes/apiv2.yaml index d9abd0a2..6472fc82 100644 --- a/config/routes/apiv2.yaml +++ b/config/routes/apiv2.yaml @@ -244,4 +244,20 @@ apiv2_partner_review_tags: apiv2_rider_review_tags: path: /apiv2/review_tags/rider - controller: App\Controller\CustomerAppAPI\ReviewTagController::getRiderReviewTags \ No newline at end of file + controller: App\Controller\CustomerAppAPI\ReviewTagController::getRiderReviewTags + +# account deletion +apiv2_account_delete: + path: /apiv2/account + controller: App\Controller\CustomerAppAPI\AccountController::deleteAccount + methods: [DELETE] + +apiv2_account_delete_resend_code: + path: /apiv2/account_resend_code + controller: App\Controller\CustomerAppAPI\AccountController:resendCode + methods: [POST] + +apiv2_account_delete_code_validate: + path: /apiv2/account_code_validate + controller: App\Controller\CustomerAppAPI\AccountController::validateDeleteCode + methods: [POST] \ No newline at end of file diff --git a/src/Controller/CustomerAppAPI/AccountController.php b/src/Controller/CustomerAppAPI/AccountController.php new file mode 100644 index 00000000..135514d3 --- /dev/null +++ b/src/Controller/CustomerAppAPI/AccountController.php @@ -0,0 +1,169 @@ +hasMissingParams($req, [ + 'phone_number', + ]); + + if ($missing) { + return new ApiResponse(false, $missing); + } + + // user input + $phone_number = $req->request->get('phone_number'); + $reason = $req->request->get('reason'); + + // get otp_mode from .env + $otp_mode = $_ENV['OTP_MODE']; + + // use the test code if we're using a test number or are on test mode + $code = $this->getConfirmCode($phone_number); + + // build model + $obj = new CustomerDeleteRequest(); + $obj->setPhoneNumber($phone_number); + $obj->setReason($reason); + $obj->setConfirmCode($code); + + // send sms to number if not in test mode + if ($otp_mode != 'test') { + $this->sendConfirmationCode($rt, $phone_number, $code, $translator); + } + + // save the model + $obj->setDateCodeSent(new DateTime()); + $this->em->persist($obj); + $this->em->flush(); + + // response + return new ApiResponse(true, '', [ + 'request_id' => $obj->getID(), + ]); + } + + public function validateDeleteCode(Request $req) + { + // validate params + $missing = $this->hasMissingParams($req, [ + 'request_id', + 'code', + ]); + + if ($missing) { + return new ApiResponse(false, $missing); + } + + // user input + $code = $req->request->get('code'); + $request_id = $req->request->get('request_id'); + + // get the request + $obj = $this->em->getRepository(CustomerDeleteRequest::class)->findOneBy([ + 'id' => $request_id, + 'confirm_code' => $code, + 'flag_confirmed' => false, + 'flag_completed' => false, + ]); + if (empty($obj)) { + return new ApiResponse(false, 'Invalid request details provided.'); + } + + // confirm the request + $obj->setConfirmed(true); + $obj->setDateConfirmed(new DateTime()); + $this->em->flush(); + + // response + return new ApiResponse(); + } + + public function resendCode(Request $req, RisingTideGateway $rt, TranslatorInterface $translator) + { + // validate params + $missing = $this->hasMissingParams($req, [ + 'request_id', + ]); + + if ($missing) { + return new ApiResponse(false, $missing); + } + + // user input + $request_id = $req->request->get('request_id'); + $now = time(); + + // get the request + $obj = $this->em->getRepository(CustomerDeleteRequest::class)->findOneBy([ + 'id' => $request_id, + 'flag_confirmed' => false, + 'flag_completed' => false, + ]); + if (empty($obj)) { + return new ApiResponse(false, 'Invalid request details provided.'); + } + + // prevent resend spamming + if ($now - $obj->getDateCodeSent()->getTimestamp() < 300) { + return new ApiResponse(false, 'Can only send confirm code every 5 mins.'); + } + + // use the test code if we're using a test number or are on test mode + $phone_number = $obj->getPhoneNumber(); + $code = $this->getConfirmCode($phone_number); + + // send sms to number if not in test mode + if ($otp_mode != 'test') { + $this->sendConfirmationCode($rt, $phone_number, $code, $translator); + } + + // update last sent timestamp + $obj->setDateCodeSent(new DateTime()); + $this->em->flush(); + + // response + return new ApiResponse(); + } + + protected function getConfirmCode($phone_number) + { + // get otp_mode from .env + $otp_mode = $_ENV['OTP_MODE']; + + // check for hardcoded phone number for app store testing + $test_numbers = explode(",", $_ENV['TEST_PHONE_NUMBERS']); + + if (in_array($phone_number, $test_numbers) || $otp_mode == 'test') { + $code = "123456"; + } else { + // generate code + $code = $this->generateConfirmCode(); + } + + return $code; + } + + protected function generateConfirmCode() + { + return sprintf("%06d", mt_rand(100000, 999999)); + } + + protected function sendConfirmationCode(RisingTideGateway $rt, $phone_number, $code, TranslatorInterface $translator) + { + // send sms to number + $message = $translator->trans('message.confirmation_code') . ' ' . $code; + $rt->sendSMS($phone_number, $translator->trans('message.battery_brand_allcaps'), $message); + } +} diff --git a/src/Controller/CustomerAppAPI/AuthController.php b/src/Controller/CustomerAppAPI/AuthController.php index 92613f13..1aa5bcb9 100644 --- a/src/Controller/CustomerAppAPI/AuthController.php +++ b/src/Controller/CustomerAppAPI/AuthController.php @@ -85,7 +85,9 @@ class AuthController extends ApiController $otp_mode = $_ENV['OTP_MODE']; // check for hardcoded phone number for app store testing - if ($phone_number == '9991112233' || $phone_number == '9221111111') { + $test_numbers = explode(",", $_ENV['TEST_PHONE_NUMBERS']); + + if (in_array($phone_number, $test_numbers)) { $code = '123456'; $this->session->setConfirmCode($code) ->setPhoneNumber($phone_number); diff --git a/src/Entity/CustomerDeleteRequest.php b/src/Entity/CustomerDeleteRequest.php new file mode 100644 index 00000000..17bca994 --- /dev/null +++ b/src/Entity/CustomerDeleteRequest.php @@ -0,0 +1,209 @@ +id = $this->generateKeyID(); + $this->flag_confirmed = false; + $this->flag_completed = false; + $this->date_created = new DateTime(); + $this->date_code_sent = null; + $this->date_confirmed = null; + $this->date_completed = null; + $this->reason = null; + $this->customer = null; + } + + public function generateKeyID() + { + // use uniqid with unix timestamp prefix for now + return uniqid(time()); + } + + public function getID() + { + return $this->id; + } + + public function setPhoneNumber($num) + { + $this->phone_number = $num; + return $this; + } + + public function getPhoneNumber() + { + return $this->phone_number; + } + + public function setReason($reason) + { + $this->reason = $reason; + return $this; + } + + public function getReason() + { + return $this->reason; + } + + public function setConfirmCode($code) + { + $this->confirm_code = $code; + return $this; + } + + public function getConfirmCode() + { + return $this->confirm_code; + } + + public function setConfirmed($flag = true) + { + $this->flag_confirmed = $flag; + return $this; + } + + public function isConfirmed() + { + return $this->flag_confirmed; + } + + public function setCompleted($flag = true) + { + $this->flag_completed = $flag; + return $this; + } + + public function isCompleted() + { + return $this->flag_completed; + } + + public function getDateCreated() + { + return $this->date_created; + } + + public function setDateCodeSent(DateTime $date) + { + $this->date_code_sent = $date; + return $this; + } + + public function getDateCodeSent() + { + return $this->date_code_sent; + } + + public function setDateConfirmed(DateTime $date) + { + $this->date_confirmed = $date; + return $this; + } + + public function getDateConfirmed() + { + return $this->date_confirmed; + } + + public function setDateCompleted(DateTime $date) + { + $this->date_completed = $date; + return $this; + } + + public function getDateCompleted() + { + return $this->date_completed; + } + + public function setCustomer(Customer $cust = null) + { + $this->customer = $cust; + return $this; + } + + public function getCustomer() + { + return $this->customer; + } +} diff --git a/src/Entity/CustomerSession.php b/src/Entity/CustomerSession.php index 77f453aa..a8e2d6c6 100644 --- a/src/Entity/CustomerSession.php +++ b/src/Entity/CustomerSession.php @@ -20,7 +20,7 @@ class CustomerSession */ protected $id; - // link to customer er + // link to customer /** * @ORM\ManyToOne(targetEntity="Customer") * @ORM\JoinColumn(name="customer_id", referencedColumnName="id", nullable=true)