292 lines
9.2 KiB
PHP
292 lines
9.2 KiB
PHP
<?php
|
|
|
|
namespace App\Controller\CustomerAppAPI;
|
|
|
|
use Doctrine\DBAL\DBALException;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Contracts\Translation\TranslatorInterface;
|
|
use Catalyst\ApiBundle\Component\Response as ApiResponse;
|
|
|
|
use App\Entity\Customer;
|
|
use App\Entity\CustomerUser;
|
|
use App\Entity\CustomerSession;
|
|
use App\Service\RisingTideGateway;
|
|
|
|
use DateTime;
|
|
|
|
class AuthController extends ApiController
|
|
{
|
|
public function register(Request $req)
|
|
{
|
|
// validate params
|
|
$missing = $this->hasMissingParams($req, [
|
|
'phone_model',
|
|
'os_type',
|
|
'os_version',
|
|
'phone_id',
|
|
]);
|
|
|
|
if ($missing) {
|
|
return new ApiResponse(false, $missing);
|
|
}
|
|
|
|
// retry until we get a unique id
|
|
while (true) {
|
|
try {
|
|
// instantiate session
|
|
$sess = new CustomerSession();
|
|
$sess->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 (!$this->em->isOpen()) {
|
|
$this->em = $this->em->create(
|
|
$this->em->getConnection(),
|
|
$this->em->getConfiguration()
|
|
);
|
|
}
|
|
|
|
// save
|
|
$this->em->persist($sess);
|
|
$this->em->flush();
|
|
} catch (DBALException $e) {
|
|
error_log($e->getMessage());
|
|
// delay one second and try again
|
|
sleep(1);
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// return data
|
|
return new ApiResponse(true, '', [
|
|
'session_key' => $sess->getID(),
|
|
]);
|
|
}
|
|
|
|
public function confirmNumber(RisingTideGateway $rt, Request $req, TranslatorInterface $translator)
|
|
{
|
|
// validate request
|
|
$validity = $this->validateRequest($req, [
|
|
'phone_number'
|
|
]);
|
|
|
|
if (!$validity['is_valid']) {
|
|
return new ApiResponse(false, $validity['error']);
|
|
}
|
|
|
|
// phone number
|
|
$phone_number = $req->request->get('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)) {
|
|
$code = '123456';
|
|
$this->session->setConfirmCode($code)
|
|
->setPhoneNumber($phone_number);
|
|
$this->em->flush();
|
|
|
|
return new ApiResponse();
|
|
}
|
|
|
|
// check if otp_mode is test
|
|
if ($otp_mode == 'test') {
|
|
$code = '123456';
|
|
$this->session->setConfirmCode($code)
|
|
->setPhoneNumber($phone_number);
|
|
$this->em->flush();
|
|
|
|
return new ApiResponse();
|
|
}
|
|
|
|
// TODO: spam protection
|
|
|
|
// TODO: validate phone number
|
|
|
|
// generate code and save
|
|
$code = $this->generateConfirmCode();
|
|
$this->session->setConfirmCode($code)
|
|
->setPhoneNumber($phone_number);
|
|
$this->em->flush();
|
|
|
|
if ($otp_mode != 'test') {
|
|
// send sms to number
|
|
$this->sendConfirmationCode($rt, $phone_number, $code, $translator);
|
|
}
|
|
|
|
// response
|
|
return new ApiResponse();
|
|
}
|
|
|
|
public function validateCode(Request $req)
|
|
{
|
|
// validate request
|
|
$validity = $this->validateRequest($req, [
|
|
'code',
|
|
]);
|
|
|
|
if (!$validity['is_valid']) {
|
|
return new ApiResponse(false, $validity['error']);
|
|
}
|
|
|
|
// already confirmed
|
|
if ($this->session->isConfirmed()) {
|
|
return new ApiResponse(false, 'User is already confirmed.');
|
|
}
|
|
|
|
// code is wrong
|
|
$code = $req->request->get('code');
|
|
if ($this->session->getConfirmCode() != $code) {
|
|
return new ApiResponse(false, 'Wrong confirm code.');
|
|
}
|
|
|
|
// set confirm date
|
|
$date = new DateTime();
|
|
$this->session->setDateConfirmed($date)
|
|
->setConfirmed();
|
|
|
|
// figure out if we have customer and customer user already
|
|
$customer_user = false;
|
|
|
|
// TODO: check if we have the number registered before and merge
|
|
$dupe_sess = $this->findNumberSession($this->session->getPhoneNumber());
|
|
if ($dupe_sess != null) {
|
|
error_log("Found existing customer session for " . $this->session->getPhoneNumber());
|
|
$dupe_cust = $dupe_sess->getCustomer();
|
|
$this->session->setCustomer($dupe_cust);
|
|
|
|
// set customer user if it exists
|
|
$customer_user = $dupe_sess->getCustomerUser() ?? $dupe_cust->getCustomerUser();
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
|
|
if (!$customer_user) {
|
|
error_log("We don't have a customer user for session " . $this->session->getID());
|
|
|
|
$customer_user = $this->findCustomerUserByNumber($this->session->getPhoneNumber());
|
|
|
|
if ($customer_user === null) {
|
|
error_log("Creating a new customer user for " . $this->session->getPhoneNumber());
|
|
$customer_user = new CustomerUser();
|
|
$customer_user->setCustomer($this->session->getCustomer())
|
|
->setPhoneNumber($this->session->getPhoneNumber());
|
|
|
|
// save
|
|
$this->em->persist($customer_user);
|
|
$this->em->flush();
|
|
} else {
|
|
error_log("Found existing customer user for " . $this->session->getPhoneNumber());
|
|
}
|
|
}
|
|
|
|
error_log("Customer user ID is " . $customer_user->getID());
|
|
|
|
// set session customer user
|
|
$this->session->setCustomerUser($customer_user);
|
|
$this->em->flush();
|
|
|
|
// response
|
|
return new ApiResponse(true, '', [
|
|
'api_key' => $customer_user->getApiKey(),
|
|
'secret_key'=> $customer_user->getSecretKey(),
|
|
]);
|
|
}
|
|
|
|
public function resendCode(Request $req, RisingTideGateway $rt, TranslatorInterface $translator)
|
|
{
|
|
// validate request
|
|
$validity = $this->validateRequest($req);
|
|
|
|
if (!$validity['is_valid']) {
|
|
return new ApiResponse(false, $validity['error']);
|
|
}
|
|
|
|
// already confirmed
|
|
if ($this->session->isConfirmed()) {
|
|
return new ApiResponse(false, 'User is already confirmed.');
|
|
}
|
|
|
|
// have sent code before
|
|
if ($this->session->getDateCodeSent() != null) {
|
|
return new ApiResponse(false, 'Can only send confirm code every 5 mins.');
|
|
}
|
|
|
|
// TODO: send via sms
|
|
$phone_number = $this->session->getPhoneNumber();
|
|
$code = $this->session->getConfirmCode();
|
|
$this->sendConfirmationCode($rt, $phone_number, $code, $translator);
|
|
|
|
// response
|
|
return new ApiResponse();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// TODO: find session customer by phone number
|
|
protected function findNumberSession($number)
|
|
{
|
|
$query = $this->em->getRepository(CustomerSession::class)->createQueryBuilder('s')
|
|
->where('s.phone_number = :number')
|
|
->andWhere('s.customer is not null')
|
|
->andWhere('s.customer_user is not null')
|
|
->andWhere('s.confirm_flag = 1')
|
|
->setParameter('number', $number)
|
|
->setMaxResults(1)
|
|
->getQuery();
|
|
|
|
// we just need one
|
|
$res = $query->getOneOrNullResult();
|
|
|
|
return $res;
|
|
}
|
|
|
|
protected function findCustomerByNumber($number)
|
|
{
|
|
$customers = $this->em->getRepository(Customer::class)->findBy(['phone_mobile' => $number]);
|
|
|
|
// find the customer with the most number of cars
|
|
$car_count = 0;
|
|
$cust = null;
|
|
|
|
foreach ($customers as $customer) {
|
|
$vehicles = $customer->getVehicles();
|
|
if (count($vehicles) > $car_count) {
|
|
$car_count = count($vehicles);
|
|
|
|
// "save" customer object
|
|
$cust = $customer;
|
|
}
|
|
}
|
|
|
|
return $cust;
|
|
}
|
|
|
|
protected function findCustomerUserByNumber($number)
|
|
{
|
|
return $this->em->getRepository(CustomerUser::class)->findOneBy(['phone_number' => $number]);
|
|
}
|
|
}
|