From 69c221f78cc053849a954ebb2c8b3f87f7757877 Mon Sep 17 00:00:00 2001 From: Korina Cordero Date: Wed, 23 Jun 2021 09:30:28 +0000 Subject: [PATCH] Add controller for customer-related requests for mobile API. #591 --- src/Controller/ResqAPI/CustomerController.php | 419 ++++++++++++++++++ 1 file changed, 419 insertions(+) create mode 100644 src/Controller/ResqAPI/CustomerController.php diff --git a/src/Controller/ResqAPI/CustomerController.php b/src/Controller/ResqAPI/CustomerController.php new file mode 100644 index 00000000..dc1c260a --- /dev/null +++ b/src/Controller/ResqAPI/CustomerController.php @@ -0,0 +1,419 @@ +acl_gen = $acl_gen; + } + + public function register(Request $req, EntityManagerInterface $em) + { + // no need for access for register + + $res = new APIResult(); + // confirm parameters + $required_params = [ + 'phone_model', + 'os_type', + 'os_version', + 'phone_id' + ]; + + // TODO: APIController has a function called checkRequiredParameters that does the same thing + // as checkMissingParameters. Maybe we can use that? + $missing = $this->checkMissingParameters($req, $required_params); + if (count($missing) > 0) + { + $params = implode(', ', $missing); + $res->setError(true) + ->setErrorMessage('Missing parameter(s): ' . $params); + return $res->getReturnResponse(); + } + + // retry until we get a unique id + while (true) + { + try + { + // create mobile user + $mobile_user = new MobileUser(); + $mobile_user->setPhoneModel($req->request->get('phone_model')) + ->setOSType($req->request->get('os_type')) + ->setOSVersion($req->request->get('os_version')) + ->setPhoneID($req->request->get('phone_id')); + + // reopen in case we get an exception + if (!$em->isOpen()) + { + $em = $em->create( + $em->getConnection(), + $em->getConfiguration() + ); + } + + // save + $em->persist($mobile_user); + $em->flush(); + } + catch (DBALException $e) + { + error_log($e->getMessage()); + // delay one second and try again + sleep(1); + continue; + } + + break; + } + + // return data + // need to make sure the names returned to app are the same + // so we still use session_id name + // TODO: depending on what data type we return, this might need changes + $data = [ + 'session_id' => $mobile_user->getID() + ]; + + // response + return $res->getReturnResponse(); + } + + public function confirmNumber(RisingTideGateway $rt, Request $req, EntityManagerInterface $em) + { + // check parameters + $required_params = [ + 'phone_number', + ]; + + // check required parameters and api key + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // phone number + $phone_number = $req->request->get('phone_number'); + + // get otp_mode from .env + $dotenv = new Dotenv(); + $dotenv->loadEnv(__DIR__.'/../../.env'); + + $otp_mode = $_ENV['OTP_MODE']; + + // check for hardcoded phone number for app store testing + if ($phone_number == '639991112233') + { + $code = '123456'; + // TODO: mobile session no longer exists, use mobile_user + $this->session->setConfirmCode($code) + ->setPhoneNumber($phone_number); + $em->flush(); + + return $res->getReturnResponse(); + } + + // check if otp_mode is test + if ($otp_mode == 'test') + { + $code = '123456'; + // TODO: mobile session no longer exists, use mobile_user + $this->session->setConfirmCode($code) + ->setPhoneNumber($phone_number); + $em->flush(); + + return $res->getReturnResponse(); + } + + // TODO: spam protection + + // TODO: validate phone number + + // generate code and save + $code = $this->generateConfirmCode(); + // TODO: mobile session no longer exists, use mobile_user + $this->session->setConfirmCode($code) + ->setPhoneNumber($phone_number); + $em->flush(); + + if ($otp_mode != 'test') + { + // send sms to number + $this->sendConfirmationCode($rt, $phone_number, $code); + } + + // response + return $res->getReturnResponse(); + } + + // TODO: needs to be modified for mobile user + public function validateCode(Request $req, EntityManagerInterface $em) + { + // check parameters + $required_params = [ + 'code', + ]; + + // check required parameters and api key + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // code is wrong + $code = $req->request->get('code'); + if ($this->session->getConfirmCode() != $code) + { + $res->setError(true) + ->setErrorMessage('Wrong confirm code'); + return $res->getReturnResponse(); + } + + // set confirm date + $date = new DateTime(); + $this->session->setDateConfirmed($date) + ->setConfirmed(); + + + // TODO: check if we have the number registered before and merge + $dupe_sess = $this->findNumberSession($this->session->getPhoneNumber()); + if ($dupe_sess != null) + { + $dupe_cust = $dupe_sess->getCustomer(); + $this->session->setCustomer($dupe_cust); + } + + // TODO: check if mobile matches mobile of customer + $customer = $this->findCustomerByNumber($this->session->getPhoneNumber()); + if ($customer != null) + { + // TODO: if there is a dupe_sess, do we need to check if + // dupe_cust is the same as the customer we found? + $this->session->setCustomer($customer); + } + + $em->flush(); + + // response + return $res->getReturnResponse(); + } + + // TODO: needs to be modified for mobile user + public function getInfo(Request $req, EntityManagerInterface $em) + { + // check required parameters and api key + $required_params = []; + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // if no customer found + $cust = $this->session->getCustomer(); + if ($cust == null) + { + $data = [ + 'first_name' => '', + 'last_name' => '', + 'priv_third_party' => (bool) false, + 'priv_promo' => (bool) false, + ]; + $res->setData($data); + + return $res->getReturnResponse(); + } + + // send back customer details + $data = [ + 'first_name' => $cust->getFirstName(), + 'last_name' => $cust->getLastName(), + 'priv_third_party' => (bool) $cust->getPrivacyThirdParty(), + 'priv_promo' => (bool) $cust->getPrivacyPromo(), + ]; + $res->setData($data); + + return $res->getReturnResponse(); + } + + // TODO: needs to be modified for mobile user + public function updateInfo(Request $req, EntityManagerInterface $em) + { + // check required parameters and api key + $required_params = [ + 'first_name', + 'last_name', + ]; + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + $cust = $this->updateCustomerInfo($req, $em); + + // get privacy policy for mobile + $dotenv = new Dotenv(); + $dotenv->loadEnv(__DIR__.'/../../.env'); + + $policy_mobile_id = $_ENV['POLICY_MOBILE']; + + $mobile_policy = $em->getRepository(PrivacyPolicy::class)->find($policy_mobile_id); + + // set policy id + if ($mobile_policy != null) + { + $cust->setPrivacyPolicyMobile($mobile_policy); + } + + $em->flush(); + + return $res->getReturnResponse(); + } + + // TODO: needs to be modified for mobile user + public function getStatus(Request $req, EntityManagerInterface $em) + { + // check required parameters and api key + $required_params = []; + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // set data + $data = []; + if ($this->session->isConfirmed()) + $data['status'] = 'confirmed'; + else + $data['status'] = 'unconfirmed'; + $res->setData($data); + + return $res->getReturnResponse(); + } + + + + // TODO: this might not be needed if we use APIController's checkRequiredParameters + protected function checkMissingParameters(Request $req, $params = []) + { + $missing = []; + + // check if parameters are there + foreach ($params as $param) + { + if ($req->getMethod() == 'GET') + { + $check = $req->query->get($param); + if (empty($check)) + $missing[] = $param; + } + else if ($req->getMethod() == 'POST') + { + $check = $req->request->get($param); + if (empty($check)) + $missing[] = $param; + } + else + return $params; + } + + return $missing; + } + + // TODO: since we broke the functions into separate files, we need + // to figure out how to make this accessible to all ResqAPI controllers + protected function checkParamsAndKey(Request $req, $em, $params) + { + // TODO: depends on what we decide to return + // returns APIResult object + $res = new APIResult(); + + // check for api_key in query string + $api_key = $req->query->get('api_key'); + if (empty($api_key)) + { + $res->setError(true) + ->setErrorMessage('Missing API key'); + return $res; + } + + // check missing parameters + $missing = $this->checkMissingParameters($req, $params); + if (count($missing) > 0) + { + $miss_string = implode(', ', $missing); + $res->setError(true) + ->setErrorMessage('Missing parameter(s): ' . $miss_string); + return $res; + } + + // check api key + $mobile_user = $this->checkAPIKey($em, $req->query->get('api_key')); + if ($mobile_user == null) + { + $res->setError(true) + ->setErrorMessage('Invalid API Key'); + return $res; + } + + // store session + $this->session = $sess; + + return $res; + } + + // TODO: type hint entity manager + // TODO: since we broke the functions into separate files, we need + // to figure out how to make this accessible to all ResqAPI controllers + protected function checkAPIKey($em, $api_key) + { + // find the api key (session id) + // TODO: user validation needs to be changed + $m_user = $em->getRepository(MobileUser::class)->find($api_key); + if ($m_user == null) + return null; + + return $m_user; + } + + // TODO: needs to be modified for mobile user + protected function updateCustomerInfo($req, $em) + { + // create new customer if it's not there + $cust = $this->session->getCustomer(); + if ($cust == null) + { + $cust = new Customer(); + $em->persist($cust); + + $this->session->setCustomer($cust); + } + + $cust->setFirstName($req->request->get('first_name')) + ->setLastName($req->request->get('last_name')) + ->setEmail($req->request->get('email', '')) + ->setConfirmed($this->session->isConfirmed()); + + // update mobile phone of customer + $cust->setPhoneMobile(substr($this->session->getPhoneNumber(), 2)); + + return $cust; + } + + +}