From 7f7707d8273152ec95a8e1a9e42a0c9588492e34 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Mon, 7 May 2018 22:57:08 +0800 Subject: [PATCH 01/24] Force ipv4 resolv for calls to google maps api #113 --- src/Service/MapTools.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Service/MapTools.php b/src/Service/MapTools.php index 693b3c21..aa38cd6d 100644 --- a/src/Service/MapTools.php +++ b/src/Service/MapTools.php @@ -52,7 +52,12 @@ class MapTools // query google maps api - $res = $client->request('GET', $maps_url, ['query' => $gmaps_params]); + $res = $client->request('GET', $maps_url, [ + 'query' => $gmaps_params, + 'curl' => [ + CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4 + ], + ]); return $res->getBody(); } From 6dd052e84ee6b914351e0fa787ebe0b24e482aa4 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sat, 19 May 2018 12:52:29 +0800 Subject: [PATCH 02/24] Sort vehicle fetching by make #114 --- src/Entity/VehicleManufacturer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Entity/VehicleManufacturer.php b/src/Entity/VehicleManufacturer.php index 48de14b0..00026b05 100644 --- a/src/Entity/VehicleManufacturer.php +++ b/src/Entity/VehicleManufacturer.php @@ -30,6 +30,7 @@ class VehicleManufacturer // vehicles /** * @ORM\OneToMany(targetEntity="Vehicle", mappedBy="manufacturer") + * @ORM\OrderBy({"make" = "ASC"}) */ protected $vehicles; From 8035dc254c7266f5bd9d2006af7ef7638d0e09c4 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sat, 19 May 2018 15:11:15 +0800 Subject: [PATCH 03/24] Add LPG to fuel type #115 --- src/Ramcar/FuelType.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Ramcar/FuelType.php b/src/Ramcar/FuelType.php index c85a4d81..62f2c13a 100644 --- a/src/Ramcar/FuelType.php +++ b/src/Ramcar/FuelType.php @@ -4,11 +4,13 @@ namespace App\Ramcar; class FuelType extends NameValue { - const GAS = 'gas'; - const DIESEL = 'diesel'; + const GAS = 'gas'; + const DIESEL = 'diesel'; + const LPG = 'lpg'; const COLLECTION = [ 'gas' => 'Gas', 'diesel' => 'Diesel', + 'lpg' => 'LPG', ]; } From 365de1c66d288068609ebe4ba11e991c2a782ae8 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sun, 20 May 2018 01:54:41 +0800 Subject: [PATCH 04/24] Set customer mobile phone on update info #118 --- src/Controller/APIController.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index de3e96f7..08adc5a7 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -314,6 +314,9 @@ class APIController extends Controller ->setLastName($req->request->get('last_name')) ->setConfirmed($this->session->isConfirmed()); + // update mobile phone of customer + $cust->setPhoneMobile(substr(2, $this->session->getPhoneNumber())); + $em->flush(); return $res->getReturnResponse(); From 8b8d81991067655bfc518c471bda4944bb47fb31 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sun, 20 May 2018 13:48:06 +0800 Subject: [PATCH 05/24] Check for existing customers for the same number and merge for mobile API #116 --- src/Controller/APIController.php | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 08adc5a7..86830b7f 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -218,12 +218,29 @@ class APIController extends Controller ->setPhoneNumber($phone_number); $em->flush(); - // TODO: send sms to number + // TODO: send sms with validation code to number // response return $res->getReturnResponse(); } + // TODO: find session customer by phone number + protected function findNumberSession($number) + { + $em = $this->getDoctrine()->getManager(); + $query = $em->getRepository(MobileSession::class)->createQueryBuilder('s') + ->where('s.phone_number = :number') + ->andWhere('s.customer is not null') + ->andWhere('s.confirm_flag = 1') + ->setParameter('number', $number) + ->getQuery(); + + // we just need one + $res = $query->getOneOrNullResult(); + + return $res; + } + public function validateCode(Request $req) { // check parameters @@ -250,6 +267,16 @@ class APIController extends Controller $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); + } + $em->flush(); // response From 5498119ab3e342784610ab5d581b90cb0ff5ca30 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sun, 20 May 2018 14:22:51 +0800 Subject: [PATCH 06/24] Add setMaxResults(1) to assure single result in dupe customer query #116 --- src/Controller/APIController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index 86830b7f..e0de5ad2 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -233,6 +233,7 @@ class APIController extends Controller ->andWhere('s.customer is not null') ->andWhere('s.confirm_flag = 1') ->setParameter('number', $number) + ->setMaxResults(1) ->getQuery(); // we just need one From 429dc99b292578d6f34a9e82974b2ab4dc3c88ae Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sun, 20 May 2018 22:45:41 +0800 Subject: [PATCH 07/24] Add cancel event and have mobile sendEvent send to all sessions of a job order #122 --- src/Controller/JobOrderController.php | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index c515c345..f1be02b6 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -1364,15 +1364,20 @@ class JobOrderController extends BaseController protected function sendEvent(JobOrder $job_order, $payload) { - $session = $job_order->getCustomer()->getMobileSessions(); + $sessions = $job_order->getCustomer()->getMobileSessions(); if (count($session) == 0) return; - $phone_num = $session[0]->getPhoneNumber(); - $channel = 'motolite.control.' . $phone_num; $client = new MosquittoClient(); $client->connect('localhost', 1883); - $client->publish($channel, json_encode($payload)); + + foreach ($sessions as $sess) + { + $phone_num = $sess->getPhoneNumber(); + $channel = 'motolite.control.' . $phone_num; + $client->publish($channel, json_encode($payload)); + } + $client->disconnect(); } @@ -1783,6 +1788,13 @@ class JobOrderController extends BaseController // save $em->flush(); + // send mobile app event + $payload = [ + 'event' => 'cancelled', + 'jo_id' => $obj->getID(), + ]; + $this->sendEvent($obj, $payload); + // return successful response return $this->json([ 'success' => 'Job order has been cancelled!' From 3727ae1fedc2b529653e18522bc144a26e078a51 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sun, 20 May 2018 23:02:06 +0800 Subject: [PATCH 08/24] Fix typo bug for session #122 --- src/Controller/JobOrderController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index f1be02b6..73970431 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -1365,7 +1365,7 @@ class JobOrderController extends BaseController protected function sendEvent(JobOrder $job_order, $payload) { $sessions = $job_order->getCustomer()->getMobileSessions(); - if (count($session) == 0) + if (count($sessions) == 0) return; $client = new MosquittoClient(); From 5e0023e21511c3209e55ec9925b942366b0d9dcc Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Sun, 20 May 2018 23:18:06 +0800 Subject: [PATCH 09/24] Add cancel reason to mobile event for cancel JO #122 --- src/Controller/JobOrderController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php index 73970431..e25be13c 100644 --- a/src/Controller/JobOrderController.php +++ b/src/Controller/JobOrderController.php @@ -1791,6 +1791,7 @@ class JobOrderController extends BaseController // send mobile app event $payload = [ 'event' => 'cancelled', + 'reason' => $cancel_reason, 'jo_id' => $obj->getID(), ]; $this->sendEvent($obj, $payload); From 16478f58214af823eaaff4842405248aabbc2033 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Mon, 21 May 2018 00:08:04 +0800 Subject: [PATCH 10/24] Add page for privacy policy for mobile app #127 --- public/static/privacy.html | 117 +++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 public/static/privacy.html diff --git a/public/static/privacy.html b/public/static/privacy.html new file mode 100644 index 00000000..1db8cafa --- /dev/null +++ b/public/static/privacy.html @@ -0,0 +1,117 @@ +

Privacy Policy

+

+Oriental and Motolite Marketing Corporation (“Company,” “We,” “Us,” “Our”), is committed to protecting the privacy and security of all personal and/or sensitive information (“Personal Data”) related to its employees, customers, business partners, suppliers, contractors, and other parties that the Company will and is engaged into. For this reason, uniform practice and procedure for collecting, recording, consolidating, updating, disclosing, storing, accessing, transferring, retaining, destroying and disposing of Personal Data by the Company is hereby adopted in order to process Personal Data fairly, appropriately, and lawfully. +

+ +

+This Privacy Policy sets out how the Company uses, protects and controls any Personal Data that you will provide in our website and mobile application (the “Site”). The Company may change this policy from time to time by updating it in accordance with subsequent Laws and Implementing Rules and Regulations. The terms of this Privacy Policy apply to all users of this Site. +

+ +

Collection of Personal Data

+

+The Company collects Personal Data you voluntarily submitted in our Site and our mobile apps, as well as non-personal information provided therein. +

+ +

User Registration

+

+We collect information about you (i) when you register in order to receive a product/service; (ii) when you subscribe to marketing emails; (iii) when you apply for a job post; (iv) when you contact us for inquiries, support or feedback. Information may include Personal Data such as but not limited to your first name, last name, email address, birthdate, gender, mobile number, address and password. +

+ +

Log information

+

+When you visit our Site, we may also collect non-personal information such as but not limited to web page from which you came to our Site, your web page request, Internet Protocol (IP) address, geolocation, browser type, browser language, the date and time of your request and your registration data. Please be noted that when you purchase a product or use a web-based service in our Site, we may also log the specific path, actions, and navigation choices you make. +

+ +

Cookies

+

+We may use cookies in analyzing and evaluating performance to provide you better experience when using our Site. Cookies are small files that a Site or its service provider transfers to your computer's hard drive through your web browser (you can disable this) that allows the Site's or service provider's systems to recognize your browser and capture and remember certain information. +

+ +

Location Services

+

+Your current location is only determined if you permit our services to do so. If you allow your location to be obtained using our RESQ app, or with a browser, we will use this information to return your estimated location. We use this information solely to distinguish your current location and not to identify you. Motolite does not automatically track your location. +

+ +

Use of Personal Data

+

+

    +
  • The Company uses your Personal Data for the following purposes, without limitation:
  • +
  • to deliver or improve our products and services
  • +
  • to administer a content, promotion, survey or other Site feature
  • +
  • to send periodic emails regarding your account or other products and services
  • +
  • to process your application for any of our job posts
  • +
  • to process your application for a franchise
  • +
  • to effectively respond to your customer service requests and support needs.
  • +
+

+ +

+The Company may share the Personal Data gathered from you within the Ramcar Group of Companies and will use it consistent with the purpose of this Privacy Policy. We may also use the information in the aggregate to understand how our users as a group, use the services and resources provided on our Site. +

+ +

Further Disclosure

+

+We take reasonable precautions to be sure that nonaffiliated third parties and affiliates, to whom we disclose your Personal Data are aware of our Privacy Policy and will treat the information in a similarly responsible manner. Our contracts and written agreements with nonaffiliated third parties that receive information from us about you prohibit those parties from transferring the information other than to provide the service that you obtain from us. +

+ +

Agents and contractors

+

+Our contractors sometimes have access to your Personal Data in the course of assisting in operating our business and providing products or services to you. These contractors may include vendors and suppliers that provide us with technology, services, and/or content for the operation and maintenance of our Site. Access to your Personal Data by these contractors is limited to the information reasonably necessary for the contractor to perform its limited function. Contractors have an obligation under their contracts with us to keep your information confidential and to comply with our privacy and security policies. +

+ +

Disclosure for legal reasons

+

+We may release Personal Data to third parties: (1) to comply with valid legal requirements such as a law, regulation, search warrant, subpoena or court order; or (2) in special cases, such as a threat to security, a threat to our system or network, or cases in which we believe it is reasonably necessary to investigate or prevent harm, fraud, abuse, or illegal conduct. +

+ +

Changes in our corporate structure

+

+If all or part of the Company is sold, merged or otherwise transferred to another entity, the Personal Data you have provided to us may be transferred as part of that transaction. We will take steps to ensure that, without your consent, any Personal Data that is transferred will not be used or shared in a manner inconsistent with this Privacy Policy. +

+ +

Accuracy and Access

+

+The Company will keep your Personal Data as accurate, complete and up-to-date as is necessary for the purpose for which it is processed. In case you need to access, correct, amend, delete inaccurate Personal Data, or withdraw your consent, please immediately inform us. (see Contact Us section below) +

+ +

Security

+

+The Company employs adequate organizational, physical and technical security measures such as password protection, encryption, firewalls and other controls, to ensure and preserve the confidentiality, integrity and availability of your Personal Data. We work to protect the security of your information during transmission by using Secure Sockets Layer (SSL) software, which encrypts information you input online. Only authorized persons from the Company will have access to your Personal Data. Employees who misuse any information are subject to disciplinary action, including termination. +

+ +

Third Party Links

+

+The Company may offer links to sites that is run by third parties. If you visit other sites, you should read the site’s privacy policy, terms and conditions, and their other policies. The Company is not responsible for the policies and practices of third parties. Any information you give to those organizations is dealt with under their privacy statement, terms and conditions, and other policies. + +

Retention and Disposal

+

+The Company will retain your Personal Data only as long as necessary for the fulfillment of the stated purposes. In case that the Site is no longer functional or decommissioned, all of your Personal Data in digital or hard copies will be disposed or erased according to the Company’s guidelines, where it is irretrievable, unreadable, or unidentifiable. In case you subscribed to email/SMS marketing, you will still receive email/SMS notifications. If you want to cancel your subscription, you may click the unsubscribe link at the bottom of any email message from the Company, or follow the SMS cancellation instructions. +

+ +

Minors' Privacy

+

+The Company takes minors’ privacy seriously. If you are under 18 years of age, please do not submit any Personal Data through our Site without the express consent and participation of a parent or guardian. If you are a parent or guardian, please make every effort to guard your children's privacy. +

+ +

Applicable Law and Rights

+

+The Company upholds compliance with Republic Act No. 10173 or the Data Privacy Act of 2012 (DPA), its Implementing Rules and Regulations, and other relevant policies, including issuances of the National Privacy Commission. The Company acknowledges your right to be informed, object processing, access and rectify, suspend or withdraw Personal Data, and be indemnified in case of damages pursuant to the provisions of DPA. +

+ +

Changes to Privacy Policy

+

+The Company reserves the right to amend this Privacy Policy at any time, consistent with applicable law. In such case, an updated version will be posted in our Site. If we are going to process your Personal Data in a manner different from that stated at the time of collection, we will notify you, and you will have a choice as to whether or not we can use your Personal Data in such a way. +

+ +

Contact Us

+

+For any inquiry regarding this Privacy Policy, please contact our Data Privacy Officer, Mr. Luis Quiogue at: +

+ +

+OMMC
+Ramcar Center
+80-82 Roces Ave.
+Diliman, Quezon City PH
+(+632) 370-1100 +

From a96ac83a5f9f040fd16b12e3f5d95118c6f4ba15 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Mon, 21 May 2018 00:15:12 +0800 Subject: [PATCH 11/24] Fixed special characters for privacy policy #127 --- public/static/privacy.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/static/privacy.html b/public/static/privacy.html index 1db8cafa..bcecf84e 100644 --- a/public/static/privacy.html +++ b/public/static/privacy.html @@ -1,10 +1,10 @@

Privacy Policy

-Oriental and Motolite Marketing Corporation (“Company,” “We,” “Us,” “Our”), is committed to protecting the privacy and security of all personal and/or sensitive information (“Personal Data”) related to its employees, customers, business partners, suppliers, contractors, and other parties that the Company will and is engaged into. For this reason, uniform practice and procedure for collecting, recording, consolidating, updating, disclosing, storing, accessing, transferring, retaining, destroying and disposing of Personal Data by the Company is hereby adopted in order to process Personal Data fairly, appropriately, and lawfully. +Oriental and Motolite Marketing Corporation ("Company," "We," "Us," "Our"), is committed to protecting the privacy and security of all personal and/or sensitive information ("Personal Data") related to its employees, customers, business partners, suppliers, contractors, and other parties that the Company will and is engaged into. For this reason, uniform practice and procedure for collecting, recording, consolidating, updating, disclosing, storing, accessing, transferring, retaining, destroying and disposing of Personal Data by the Company is hereby adopted in order to process Personal Data fairly, appropriately, and lawfully.

-This Privacy Policy sets out how the Company uses, protects and controls any Personal Data that you will provide in our website and mobile application (the “Site”). The Company may change this policy from time to time by updating it in accordance with subsequent Laws and Implementing Rules and Regulations. The terms of this Privacy Policy apply to all users of this Site. +This Privacy Policy sets out how the Company uses, protects and controls any Personal Data that you will provide in our website and mobile application (the "Site"). The Company may change this policy from time to time by updating it in accordance with subsequent Laws and Implementing Rules and Regulations. The terms of this Privacy Policy apply to all users of this Site.

Collection of Personal Data

@@ -85,12 +85,12 @@ The Company may offer links to sites that is run by third parties. If you visit

Retention and Disposal

-The Company will retain your Personal Data only as long as necessary for the fulfillment of the stated purposes. In case that the Site is no longer functional or decommissioned, all of your Personal Data in digital or hard copies will be disposed or erased according to the Company’s guidelines, where it is irretrievable, unreadable, or unidentifiable. In case you subscribed to email/SMS marketing, you will still receive email/SMS notifications. If you want to cancel your subscription, you may click the unsubscribe link at the bottom of any email message from the Company, or follow the SMS cancellation instructions. +The Company will retain your Personal Data only as long as necessary for the fulfillment of the stated purposes. In case that the Site is no longer functional or decommissioned, all of your Personal Data in digital or hard copies will be disposed or erased according to the Company's guidelines, where it is irretrievable, unreadable, or unidentifiable. In case you subscribed to email/SMS marketing, you will still receive email/SMS notifications. If you want to cancel your subscription, you may click the unsubscribe link at the bottom of any email message from the Company, or follow the SMS cancellation instructions.

Minors' Privacy

-The Company takes minors’ privacy seriously. If you are under 18 years of age, please do not submit any Personal Data through our Site without the express consent and participation of a parent or guardian. If you are a parent or guardian, please make every effort to guard your children's privacy. +The Company takes minors' privacy seriously. If you are under 18 years of age, please do not submit any Personal Data through our Site without the express consent and participation of a parent or guardian. If you are a parent or guardian, please make every effort to guard your children's privacy.

Applicable Law and Rights

From 7e53a4d6de86bbdaecbac0456130a57442783dca Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Mon, 21 May 2018 01:23:59 +0800 Subject: [PATCH 12/24] Add rider rating comment feature #120 --- src/Controller/APIController.php | 5 +++++ src/Entity/RiderRating.php | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index e0de5ad2..acf3cb74 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -1225,6 +1225,11 @@ class APIController extends Controller ->setJobOrder($jo) ->setRating($rating_num); + // rider rating comment + $comment = $req->request->get('comment'); + if (!empty($comment)) + $rating->setComment($comment); + $em->persist($rating); $em->flush(); diff --git a/src/Entity/RiderRating.php b/src/Entity/RiderRating.php index e0a03ddc..f5875c27 100644 --- a/src/Entity/RiderRating.php +++ b/src/Entity/RiderRating.php @@ -52,10 +52,17 @@ class RiderRating */ protected $rating; + // customer's comment that goes along with the rating + /** + * @ORM\Column(type="text") + */ + protected $comment; + public function __construct() { $this->date_create = new DateTime(); $this->rating = 0; + $this->comment = ''; } public function getID() @@ -111,4 +118,15 @@ class RiderRating { return $this->rating; } + + public function setComment($comment) + { + $this->comment = $comment; + return $this; + } + + public function getComment() + { + return $this->comment; + } } From 9e6ff4ee15119fcc4509cd0eceaae3ff14d11c35 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Tue, 22 May 2018 20:57:50 +0800 Subject: [PATCH 13/24] Add rider username and password to forms and database #119 --- src/Controller/RiderController.php | 41 +++++++++++++++++++++++++++++- src/Entity/Rider.php | 37 +++++++++++++++++++++++++++ templates/rider/form.html.twig | 30 ++++++++++++++++++++++ 3 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/Controller/RiderController.php b/src/Controller/RiderController.php index 84e2f21d..16b9bb8c 100644 --- a/src/Controller/RiderController.php +++ b/src/Controller/RiderController.php @@ -7,6 +7,7 @@ use App\Ramcar\DayOfWeek; use App\Entity\Rider; use App\Entity\RiderSchedule; use App\Entity\Hub; +use App\Entity\User; use App\Service\FileUploader; use Doctrine\ORM\Query; @@ -14,6 +15,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; +use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; use DateTime; @@ -154,7 +156,8 @@ class RiderController extends BaseController ->setContactNumber($req->request->get('contact_no')) ->setPlateNumber($req->request->get('plate_number')) ->setImageFile($req->request->get('image_file')) - ->setActive($req->request->get('flag_active') ? true : false); + ->setActive($req->request->get('flag_active') ? true : false) + ->setUsername($req->request->get('username')); } public function addSubmit(Request $req, EncoderFactoryInterface $ef, ValidatorInterface $validator) @@ -176,6 +179,24 @@ class RiderController extends BaseController // initialize error list $error_array = []; + // get password inputs + $password = $req->request->get('password'); + $confirm_password = $req->request->get('confirm_password'); + + // custom validation for password fields + if (!$password) { + $error_array['password'] = 'This value should not be blank.'; + } else if ($password != $confirm_password) { + $error_array['confirm_password'] = 'Passwords do not match.'; + } else { + // encode password + $enc = $ef->getEncoder(new User()); + $encoded_password = $enc->encodePassword($req->request->get('password'), ''); + + // set password + $obj->setPassword($encoded_password); + } + // custom validation for associations $hub_id = $req->request->get('hub'); @@ -303,6 +324,24 @@ class RiderController extends BaseController // initialize error list $error_array = []; + // get password inputs + $password = $req->request->get('password'); + $confirm_password = $req->request->get('confirm_password'); + + // custom validation for password fields + if ($password || $confirm_password) { + if ($password != $confirm_password) { + $error_array['confirm_password'] = 'Passwords do not match.'; + } else { + // encode password + $enc = $ef->getEncoder(new User()); + $encoded_password = $enc->encodePassword($req->request->get('password'), ''); + + // set password + $obj->setPassword($encoded_password); + } + } + // custom validation for associations $hub_id = $req->request->get('hub'); diff --git a/src/Entity/Rider.php b/src/Entity/Rider.php index d637bc99..8b3dba37 100644 --- a/src/Entity/Rider.php +++ b/src/Entity/Rider.php @@ -92,6 +92,18 @@ class Rider */ protected $flag_active; + // username for rider api + /** + * @ORM\Column(type="string", length=80, unique=true, nullable=true) + */ + protected $username; + + // password for rider api + /** + * @ORM\Column(type="string", length=64) + */ + protected $password; + public function __construct() { $this->job_orders = new ArrayCollection(); @@ -99,6 +111,8 @@ class Rider $this->curr_rating = 0; $this->flag_available = true; $this->flag_active = true; + $this->username = null; + $this->password = ''; } public function getID() @@ -253,4 +267,27 @@ class Rider { return $this->flag_active; } + + public function setUsername($username) + { + $this->username = $username; + return $this; + } + + public function getUsername() + { + return $this->username; + } + + public function setPassword($pass) + { + // they have to pass the encoded password + $this->password = $pass; + return $this; + } + + public function getPassword() + { + return $this->password; + } } diff --git a/templates/rider/form.html.twig b/templates/rider/form.html.twig index c6501ca9..c08c250c 100644 --- a/templates/rider/form.html.twig +++ b/templates/rider/form.html.twig @@ -35,6 +35,36 @@
+ +
+

+ Rider App User +

+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+
+
+

Rider Details From 93b41f7a1aefd59fac8f9bb860c155dd3010958b Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Tue, 22 May 2018 20:58:27 +0800 Subject: [PATCH 14/24] Classify rider api urls as unsecured #119 --- config/packages/security.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/packages/security.yaml b/config/packages/security.yaml index b39a2272..6de188ee 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -23,6 +23,10 @@ security: pattern: ^\/api\/ security: false + rider_api: + pattern: ^\/rapi\/ + security: false + main: form_login: login_path: login From 87c6ca19268373eac58832cba01540ffc5e08393 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Tue, 22 May 2018 20:59:13 +0800 Subject: [PATCH 15/24] Add rider session entity #119 --- src/Entity/RiderSession.php | 109 ++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/Entity/RiderSession.php diff --git a/src/Entity/RiderSession.php b/src/Entity/RiderSession.php new file mode 100644 index 00000000..6d9fbf91 --- /dev/null +++ b/src/Entity/RiderSession.php @@ -0,0 +1,109 @@ +id = $this->generateKeyID(); + $this->rider = null; + $this->is_active = false; + } + + public function generateKeyID() + { + // use uniqid for now, since primary key dupes will trigger exceptions + return uniqid(); + } + + public function getID() + { + return $this->id; + } + + public function setDevicePushID($id) + { + $this->device_push_id = $id; + return $this; + } + + public function getDevicePushID() + { + return $this->device_push_id; + } + + public function setRider(Rider $rider = null) + { + $this->rider = $rider; + return $this; + } + + public function getRider() + { + return $this->rider; + } + + public function setPhoneNumber($num) + { + $this->phone_number = $num; + return $this; + } + + public function getPhoneNumber() + { + return $this->phone_number; + } + + public function setActive($flag = true) + { + $this->is_active = $flag; + return $this; + } + + public function isActive() + { + return $this->is_active; + } +} From 9d8a3fe6e4371b3e84fa3625caaa1429bcf283ae Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Tue, 22 May 2018 20:59:24 +0800 Subject: [PATCH 16/24] Add session register rider api call #119 --- config/routes/rider_api.yaml | 22 +++ src/Controller/RAPIController.php | 215 ++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 config/routes/rider_api.yaml create mode 100644 src/Controller/RAPIController.php diff --git a/config/routes/rider_api.yaml b/config/routes/rider_api.yaml new file mode 100644 index 00000000..95d5563c --- /dev/null +++ b/config/routes/rider_api.yaml @@ -0,0 +1,22 @@ +# rider app api + +rapi_register: + path: /rapi/register + controller: App\Controller\RAPIController::register + methods: [POST] + +rapi_login: + path: /rapi/login + controller: App\Controller\RAPIController::login + methods: [POST] + +rapi_get_status: + path: /rapi/status + controller: App\Controller\RAPIController::getStatus + methods: [GET] + +rapi_set_status: + path: /rapi/status + controller: App\Controller\RAPIController::setStatus + methods: [POST] + diff --git a/src/Controller/RAPIController.php b/src/Controller/RAPIController.php new file mode 100644 index 00000000..1f69a286 --- /dev/null +++ b/src/Controller/RAPIController.php @@ -0,0 +1,215 @@ +session = null; + } + + 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: type hint entity manager + protected function checkAPIKey($em, $api_key) + { + // find the api key (session id) + $session = $em->getRepository(RiderSession::class)->find($api_key); + if ($session == null) + return null; + + return $session; + } + + protected function checkParamsAndKey(Request $req, $em, $params) + { + // 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 + $sess = $this->checkAPIKey($em, $req->query->get('api_key')); + if ($sess == null) + { + $res->setError(true) + ->setErrorMessage('Invalid API Key'); + return $res; + } + + // store session + $this->session = $sess; + + return $res; + } + + public function register(Request $req) + { + $res = new APIResult(); + + // confirm parameters + $required_params = [ + 'phone_number', + 'device_push_id' + ]; + + $missing = $this->checkMissingParameters($req, $required_params); + if (count($missing) > 0) + { + $params = implode(', ', $missing); + $res->setError(true) + ->setErrorMessage('Missing parameter(s): ' . $params); + return $res->getReturnResponse(); + } + + $em = $this->getDoctrine()->getManager(); + + // retry until we get a unique id + while (true) + { + try + { + // instantiate session + $sess = new RiderSession(); + $sess->setPhoneNumber($req->request->get('phone_number')) + ->setDevicePushID($req->request->get('device_push_id')); + + // reopen in case we get an exception + if (!$em->isOpen()) + { + $em = $em->create( + $em->getConnection(), + $em->getConfiguration() + ); + } + + // save + $em->persist($sess); + $em->flush(); + } + catch (DBALException $e) + { + error_log($e->getMessage()); + // delay one second and try again + sleep(1); + continue; + } + + break; + } + + // return data + $data = [ + 'session_id' => $sess->getID() + ]; + $res->setData($data); + + + // response + return $res->getReturnResponse(); + } + + public function login(Request $req) + { + $required_params = [ + 'user', + 'pass', + ]; + $em = $this->getDoctrine()->getManager(); + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + return $res->getReturnResponse(); + } + + public function getStatus() + { + } + + public function setStatus(Request $req) + { + } +} From 5b94b1a5921d9d5b119a5c95f6927f6ce1a2d9de Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 03:03:56 +0800 Subject: [PATCH 17/24] Add login and logout features for rider api #119 --- config/routes/rider_api.yaml | 5 +++ src/Controller/RAPIController.php | 56 ++++++++++++++++++++++++++++++- src/Entity/RiderSession.php | 8 +++++ 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/config/routes/rider_api.yaml b/config/routes/rider_api.yaml index 95d5563c..3ffb4072 100644 --- a/config/routes/rider_api.yaml +++ b/config/routes/rider_api.yaml @@ -10,6 +10,11 @@ rapi_login: controller: App\Controller\RAPIController::login methods: [POST] +rapi_logout: + path: /rapi/logout + controller: App\Controller\RAPIController::logout + methods: [POST] + rapi_get_status: path: /rapi/status controller: App\Controller\RAPIController::getStatus diff --git a/src/Controller/RAPIController.php b/src/Controller/RAPIController.php index 1f69a286..961f6053 100644 --- a/src/Controller/RAPIController.php +++ b/src/Controller/RAPIController.php @@ -9,6 +9,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; use CrEOF\Spatial\PHP\Types\Geometry\Point; @@ -32,6 +33,8 @@ use App\Entity\JobOrder; use App\Entity\Promo; use App\Entity\Battery; use App\Entity\RiderRating; +use App\Entity\Rider; +use App\Entity\User; use DateTime; @@ -191,7 +194,7 @@ class RAPIController extends Controller return $res->getReturnResponse(); } - public function login(Request $req) + public function login(Request $req, EncoderFactoryInterface $ef) { $required_params = [ 'user', @@ -202,6 +205,57 @@ class RAPIController extends Controller if ($res->isError()) return $res->getReturnResponse(); + // check if session has a rider already + if ($this->session->hasRider()) + { + $res->setError(true) + ->setErrorMessage('Another rider is already logged in. Please logout first.'); + return $res->getReturnResponse(); + } + + // look for rider with username + $rider = $em->getRepository(Rider::class)->findOneBy(['username' => $req->request->get('user')]); + if ($rider == null) + { + $res->setError(true) + ->setErrorMessage('Invalid username or password.'); + return $res->getReturnResponse(); + } + + // check if rider password is correct + $encoder = $ef->getEncoder(new User()); + if (!$encoder->isPasswordValid($rider->getPassword(), $req->request->get('pass'), '')) + { + $res->setError(true) + ->setErrorMessage('Invalid username or password.'); + return $res->getReturnResponse(); + } + + // assign rider to session + $this->session->setRider($rider); + + // TODO: log rider logging in + + $em->flush(); + + return $res->getReturnResponse(); + } + + public function logout(Request $req) + { + $required_params = []; + $em = $this->getDoctrine()->getManager(); + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // remove rider from session + $this->session->setRider(null); + + // TODO: log rider logging out + + $em->flush(); + return $res->getReturnResponse(); } diff --git a/src/Entity/RiderSession.php b/src/Entity/RiderSession.php index 6d9fbf91..4c879cd7 100644 --- a/src/Entity/RiderSession.php +++ b/src/Entity/RiderSession.php @@ -106,4 +106,12 @@ class RiderSession { return $this->is_active; } + + public function hasRider() + { + if ($this->rider == null) + return false; + + return true; + } } From d5fb5222caea3163f170b4d1eaf5b4ac70b591a7 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 07:28:57 +0800 Subject: [PATCH 18/24] Add rider api get job order call #119 --- config/routes/rider_api.yaml | 26 ++++++--- src/Controller/RAPIController.php | 88 ++++++++++++++++++++++++++++++- src/Entity/Rider.php | 17 ++++++ 3 files changed, 124 insertions(+), 7 deletions(-) diff --git a/config/routes/rider_api.yaml b/config/routes/rider_api.yaml index 3ffb4072..ece4671e 100644 --- a/config/routes/rider_api.yaml +++ b/config/routes/rider_api.yaml @@ -15,13 +15,27 @@ rapi_logout: controller: App\Controller\RAPIController::logout methods: [POST] -rapi_get_status: - path: /rapi/status - controller: App\Controller\RAPIController::getStatus +rapi_jo_get: + path: /rapi/joborder + controller: App\Controller\RAPIController::getJobOrder methods: [GET] -rapi_set_status: - path: /rapi/status - controller: App\Controller\RAPIController::setStatus +rapi_jo_accept: + path: /rapi/accept + controller: App\Controller\RAPIController::acceptJobOrder methods: [POST] +rapi_jo_cancel: + path: /rapi/cancel + controller: App\Controller\RAPIController::cancelJobOrder + methods: [POST] + +rapi_arrive: + path: /rapi/arrive + controller: App\Controller\RAPIController::cancelJobOrder + methods: [POST] + +rapi_payment: + path: /rapi/payment + controller: App\Controller\RAPIController::cancelJobOrder + methods: [POST] diff --git a/src/Controller/RAPIController.php b/src/Controller/RAPIController.php index 961f6053..41b37432 100644 --- a/src/Controller/RAPIController.php +++ b/src/Controller/RAPIController.php @@ -259,8 +259,94 @@ class RAPIController extends Controller return $res->getReturnResponse(); } - public function getStatus() + public function getJobOrder(Request $req) { + // get the job order of the rider assigned to this session + $required_params = []; + $em = $this->getDoctrine()->getManager(); + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // are we logged in? + if (!$this->session->hasRider()) + { + $res->setError(true) + ->setErrorMessage('No logged in rider.'); + return $res->getReturnResponse(); + } + + $rider = $this->session->getRider(); + + // do we have a job order? + $jo = $rider->getActiveJobOrder(); + if ($jo == null) + { + $data = [ + 'job_order' => null + ]; + } + else + { + $coord = $jo->getCoordinates(); + $cust = $jo->getCustomer(); + $cv = $jo->getCustomerVehicle(); + $v = $cv->getVehicle(); + $inv = $jo->getInvoice(); + + // invoice items + $inv_items = []; + foreach ($inv->getItems() as $item) + { + $inv_items[] = [ + 'id' => $item->getID(), + 'title' => $item->getTitle(), + 'qty' => $item->getQuantity(), + 'price' => $item->getPrice(), + ]; + } + + $data = [ + 'job_order' => [ + 'id' => $jo->getID(), + 'service_type' => $jo->getServiceType(), + 'date_schedule' => $jo->getDateSchedule()->format('Ymd'), + 'longitude' => $coord->getLongitude(), + 'latitude' => $coord->getLatitude(), + 'status' => $jo->getStatus(), + 'customer' => [ + 'title' => $cust->getTitle(), + 'first_name' => $cust->getFirstName(), + 'last_name' => $cust->getLastName(), + 'phone_mobile' => $cust->getPhoneMobile(), + ], + 'vehicle' => [ + 'manufacturer' => $v->getManufacturer()->getName(), + 'make' => $v->getMake(), + 'model' => $cv->getModelYear(), + 'plate_number' => $cv->getPlateNumber(), + 'color' => $cv->getColor(), + ], + 'delivery_instructions' => $jo->getDeliveryInstructions(), + 'delivery_address' => $jo->getDeliveryAddress(), + 'landmark' => $jo->getLandmark(), + 'invoice' => [ + 'discount' => $inv->getDiscount(), + 'trade_in' => $inv->getTradeIn(), + 'total_price' => $inv->getTotalPrice(), + 'vat' => $inv->getVat(), + 'items' => $inv_items, + ], + 'mode_of_payment' => $jo->getModeOfPayment(), + + + ] + ]; + } + + $res->setData($data); + + return $res->getReturnResponse(); } public function setStatus(Request $req) diff --git a/src/Entity/Rider.php b/src/Entity/Rider.php index 8b3dba37..02bca560 100644 --- a/src/Entity/Rider.php +++ b/src/Entity/Rider.php @@ -8,6 +8,8 @@ use Symfony\Component\Validator\Constraints as Assert; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Criteria; +use App\Ramcar\JOStatus; + /** * @ORM\Entity * @ORM\Table(name="rider") @@ -290,4 +292,19 @@ class Rider { return $this->password; } + + public function getActiveJobOrder() + { + $active_status = [ + JOStatus::ASSIGNED, + JOStatus::IN_TRANSIT, + JOStatus::IN_PROGRESS, + ]; + + $criteria = Criteria::create(); + $criteria->where(Criteria::expr()->in('status', $active_status)) + ->getFirstResult(1); + + return $this->job_orders->matching($criteria)[0]; + } } From 00f602e0d7c6e9b2a5f3a37acab5e7f9039d37e7 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 09:34:59 +0800 Subject: [PATCH 19/24] Add status change calls for rider api #119 --- config/routes/rider_api.yaml | 4 +- src/Controller/RAPIController.php | 100 +++++++++++++++++++++++++++++- 2 files changed, 101 insertions(+), 3 deletions(-) diff --git a/config/routes/rider_api.yaml b/config/routes/rider_api.yaml index ece4671e..4cf98d93 100644 --- a/config/routes/rider_api.yaml +++ b/config/routes/rider_api.yaml @@ -32,10 +32,10 @@ rapi_jo_cancel: rapi_arrive: path: /rapi/arrive - controller: App\Controller\RAPIController::cancelJobOrder + controller: App\Controller\RAPIController::arrive methods: [POST] rapi_payment: path: /rapi/payment - controller: App\Controller\RAPIController::cancelJobOrder + controller: App\Controller\RAPIController::payment methods: [POST] diff --git a/src/Controller/RAPIController.php b/src/Controller/RAPIController.php index 41b37432..4dab01ff 100644 --- a/src/Controller/RAPIController.php +++ b/src/Controller/RAPIController.php @@ -349,7 +349,105 @@ class RAPIController extends Controller return $res->getReturnResponse(); } - public function setStatus(Request $req) + protected function checkJO(Request $req, $required_params) { + // set jo status to in transit + $em = $this->getDoctrine()->getManager(); + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res; + + // are we logged in? + if (!$this->session->hasRider()) + { + $res->setError(true) + ->setErrorMessage('No logged in rider.'); + return $res; + } + + $rider = $this->session->getRider(); + + // check if we have an active JO + $jo = $rider->getActiveJobOrder(); + if ($jo == null) + { + $res->setError(true) + ->setErrorMessage('No active job order.'); + return $res; + } + + // check if the jo_id sent is the same as our active jo + if ($req->request->get('jo_id') != $jo->getID()) + { + $res->setError(true) + ->setErrorMessage('Job order selected is not active job order.'); + return $res; + } + + return $res; + } + + public function acceptJobOrder(Request $req) + { + $required_params = ['jo_id']; + $res = $this->checkJO($req, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to in transit + $jo->setStatus(JOStatus::IN_TRANSIT); + + // TODO: send mqtt event + + // TODO: add event + + return $res->getReturnResponse(); + } + + public function cancelJobOrder(Request $req) + { + $required_params = ['jo_id']; + $res = $this->checkJO($req, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to cancelled + $jo->setStatus(JOStatus::CANCELLED); + + // TODO: send mqtt event + + // TODO: add event + + return $res->getReturnResponse(); + } + + public function arrive(Request $req) + { + $required_params = ['jo_id']; + $res = $this->checkJO($req, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // TODO: refactor this into a jo handler class, so we don't have to repeat for control center + + // set jo status to in progress + $jo->setStatus(JOStatus::IN_PROGRESS); + + // TODO: send mqtt event + + // TODO: add event + + return $res->getReturnResponse(); + } + + public function payment(Request $req) + { + // set invoice to paid + + // set jo status to fulfilled } } From 82fc9f3948b1599466ae051996cc3751abfd9c7e Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 19:06:47 +0800 Subject: [PATCH 20/24] Make mobile api use vehicle model formatting method #128 --- src/Controller/APIController.php | 3 ++- src/Entity/Vehicle.php | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index acf3cb74..aab55e4a 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -423,7 +423,8 @@ class APIController extends Controller { $vlist[] = [ 'id' => $v->getID(), - 'make' => $v->getMake() . ' ' . $v->getModelYearFrom() . '-' . $v->getModelYearTo(), + 'make' => trim($v->getMake() . ' ' . $v->getModelYearFormatted(false)), + // 'make' => $v->getMake() . ' ' . $v->getModelYearFrom() . '-' . $v->getModelYearTo(), ]; } diff --git a/src/Entity/Vehicle.php b/src/Entity/Vehicle.php index 05e05897..f751b473 100644 --- a/src/Entity/Vehicle.php +++ b/src/Entity/Vehicle.php @@ -114,12 +114,17 @@ class Vehicle return $this->model_year_to; } - public function getModelYearFormatted() + public function getModelYearFormatted($has_dash = true) { if ($this->model_year_from == 0) { if ($this->model_year_to == 0) - return '-'; + { + if ($has_dash) + return '-'; + + return ''; + } return $this->model_year_to; } From ed30224c09c5d62812b5008a8481f3b5613cd494 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 19:17:19 +0800 Subject: [PATCH 21/24] Capitalize plate number for customer vehicle entity #129 --- src/Entity/CustomerVehicle.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Entity/CustomerVehicle.php b/src/Entity/CustomerVehicle.php index aec185b1..01aff142 100644 --- a/src/Entity/CustomerVehicle.php +++ b/src/Entity/CustomerVehicle.php @@ -167,13 +167,16 @@ class CustomerVehicle // remove spaces $plate_number = str_replace(' ', '', $plate_number); + // upper case + $plate_number = strtoupper($plate_number); + $this->plate_number = $plate_number; return $this; } public function getPlateNumber() { - return $this->plate_number; + return strtoupper($this->plate_number); } public function setModelYear($model_year) From 7d3873022ed183aa1764274b4b650c93e4310619 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 22:04:53 +0800 Subject: [PATCH 22/24] Add mobile api resend code #130 --- config/routes/api.yaml | 10 ++++++++++ src/Controller/APIController.php | 30 ++++++++++++++++++++++++++++++ src/Entity/MobileSession.php | 18 ++++++++++++++++++ 3 files changed, 58 insertions(+) diff --git a/config/routes/api.yaml b/config/routes/api.yaml index 190f6edb..7e601657 100644 --- a/config/routes/api.yaml +++ b/config/routes/api.yaml @@ -104,3 +104,13 @@ api_device_id: path: /api/device_id controller: App\Controller\APIController:updateDeviceID methods: [POST] + +api_privacy: + path: /api/privacy + controller: App\Controller\APIController:privacySettings + methods: [POST] + +api_resend_code: + path: /api/resend_code + controller: App\Controller\APIController:resendCode + methods: [POST] diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index aab55e4a..e36bb41f 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -1398,4 +1398,34 @@ class APIController extends Controller // response return $res->getReturnResponse(); } + + public function resendCode(Request $req) + { + $required_params = []; + $em = $this->getDoctrine()->getManager(); + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // already confirmed + if ($this->session->isConfirmed()) + { + $res->setError(true) + ->setErrorMessage('User is already confirmed.'); + return $res->getReturnResponse(); + } + + // have sent code before + if ($this->session->getDateCodeSent() != null) + { + $res->setError(true) + ->setErrorMessage('Can only send confirm code every 5 mins.'); + return $res->getReturnResponse(); + } + + + // TODO: send via sms + + return $res->getReturnResponse(); + } } diff --git a/src/Entity/MobileSession.php b/src/Entity/MobileSession.php index 460ef562..c11986f4 100644 --- a/src/Entity/MobileSession.php +++ b/src/Entity/MobileSession.php @@ -79,6 +79,12 @@ class MobileSession */ protected $date_confirmed; + // date and time that the confirmation code was last sent + /** + * @ORM\Column(type="datetime", nullable=true) + */ + protected $date_code_sent; + public function __construct() { @@ -88,6 +94,7 @@ class MobileSession $this->customer = null; $this->confirm_flag = false; $this->date_confirmed = null; + $this->date_code_sent = null; } public function generateKeyID() @@ -204,4 +211,15 @@ class MobileSession { return $this->date_confirmed; } + + public function setDateCodeSent(DateTime $date) + { + $this->date_code_sent = $date; + return $this; + } + + public function getDateCodeSent() + { + return $this->date_code_sent; + } } From be5a66e68a4bc55a189474472e38312b7dbe6968 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Wed, 23 May 2018 22:40:44 +0800 Subject: [PATCH 23/24] Add mobile api privacy settings call #130 --- src/Controller/APIController.php | 29 ++++++++++++++++++++++++++ src/Entity/Customer.php | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/Controller/APIController.php b/src/Controller/APIController.php index e36bb41f..9616035e 100644 --- a/src/Controller/APIController.php +++ b/src/Controller/APIController.php @@ -1428,4 +1428,33 @@ class APIController extends Controller return $res->getReturnResponse(); } + + public function privacySettings(Request $req) + { + $required_params = [ + 'priv_third_party', + 'priv_promo', + ]; + $em = $this->getDoctrine()->getManager(); + $res = $this->checkParamsAndKey($req, $em, $required_params); + if ($res->isError()) + return $res->getReturnResponse(); + + // get customer + $cust = $this->session->getCustomer(); + if ($cust == null) + { + $res->setError(true) + ->setErrorMessage('No customer information found'); + return $res->getReturnResponse(); + } + + // set privacy settings + $cust->setPrivacyThirdParty($req->request->get('priv_third_party')) + ->setPrivacyPromo($req->request->get('priv_promo')); + + $em->flush(); + + return $res->getReturnResponse(); + } } diff --git a/src/Entity/Customer.php b/src/Entity/Customer.php index 641b188c..3390064d 100644 --- a/src/Entity/Customer.php +++ b/src/Entity/Customer.php @@ -131,6 +131,16 @@ class Customer */ protected $email; + /** + * @ORM\Column(type="boolean") + */ + protected $priv_third_party; + + /** + * @ORM\Column(type="boolean") + */ + protected $priv_promo; + public function __construct() { $this->numbers = new ArrayCollection(); @@ -152,6 +162,9 @@ class Customer $this->phone_fax = ''; $this->email = ''; + + $this->priv_third_party = 0; + $this->priv_promo = 0; } public function getID() @@ -379,4 +392,26 @@ class Customer { return $this->email; } + + public function setPrivacyThirdParty($bool = true) + { + $this->priv_third_party = $bool; + return $this; + } + + public function getPrivacyThirdParty() + { + return $this->priv_third_party; + } + + public function setPrivacyPromo($bool = true) + { + $this->priv_promo = $bool; + return $this; + } + + public function getPrivacyPromo() + { + return $this->priv_promo; + } } From c322ffe0164185122c139109a7cfcced4ac2d838 Mon Sep 17 00:00:00 2001 From: Kendrick Chan Date: Thu, 24 May 2018 16:24:11 +0800 Subject: [PATCH 24/24] Make rider session auto active #131 --- src/Entity/RiderSession.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Entity/RiderSession.php b/src/Entity/RiderSession.php index 4c879cd7..3e6fc0a7 100644 --- a/src/Entity/RiderSession.php +++ b/src/Entity/RiderSession.php @@ -49,7 +49,7 @@ class RiderSession // default date generated to now $this->id = $this->generateKeyID(); $this->rider = null; - $this->is_active = false; + $this->is_active = true; } public function generateKeyID()