Added Other AP
@@ -13,11 +13,11 @@ class Home extends BaseController
|
|||||||
$results = $query->getResult();
|
$results = $query->getResult();
|
||||||
|
|
||||||
foreach ($results as $row) {
|
foreach ($results as $row) {
|
||||||
echo $row->id;
|
// echo $row->id;
|
||||||
echo $row->bank_name;
|
// echo $row->bank_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
echo 'Total Results: ' . count($results);
|
//echo 'Total Results: ' . count($results);
|
||||||
return view('welcome_message',$data);
|
return view('welcome_message',$data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -466,7 +466,8 @@ $vl='';
|
|||||||
$pieces = explode("/", $uri);
|
$pieces = explode("/", $uri);
|
||||||
$endpoint = $pieces[6];
|
$endpoint = $pieces[6];
|
||||||
$this->logArray($pieces);
|
$this->logArray($pieces);
|
||||||
|
echo 'Ameye';
|
||||||
|
var_dump($pieces);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.8 MiB |
@@ -0,0 +1 @@
|
|||||||
|
7468EFC34890E27C9CC2D4518EF3340FF6F8BA1E9478D5CDD5DD8E475FF5D38F comodoca.com 5cb548574b285
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/advice/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,347 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Destinations {
|
||||||
|
|
||||||
|
const TIME_DELTA = 180; // min (3 hrs)
|
||||||
|
const TIME_LIMIT = 1262322000; // 2010-01-01
|
||||||
|
const DEFAULT_COUNTRY = 'SG';
|
||||||
|
const DEFAULT_OPTIONS = 5;
|
||||||
|
const CITY_CURVATURE = 1.25;
|
||||||
|
const CITY_SPEED = 0.667; // km/min (0.0667 = 40 km/h)
|
||||||
|
const MIN_ACTIVITY_DISTANCE = 0.05; // 50m
|
||||||
|
const MAX_ACTIVITY_DISTANCE = 50.0; // 50km
|
||||||
|
|
||||||
|
const ACTIVITY_RADIUS = 100000; // 100km
|
||||||
|
|
||||||
|
public static function byActivity($db, $gpsdb, $member_id, $lat, $lng, $radius, $time, $time_delta=Destinations::TIME_DELTA, $country=Destinations::DEFAULT_COUNTRY) {
|
||||||
|
syslog(LOG_WARNING,"Activity::getActivity(\$db, \$gpsdb, $member_id, $lat, $lng, $radius, $time, $time_delta, $country)");
|
||||||
|
$all_time_days = Destinations::getAllTimeDays();
|
||||||
|
$res = [];
|
||||||
|
|
||||||
|
list($res1, $err1) = Destinations::activityByRangeAndTimeAndRadius(
|
||||||
|
$gpsdb, $db, $member_id, $all_time_days, $lat, $lng, $radius, 'start', $time, $time_delta);
|
||||||
|
if ($res1 && count($res1)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res1));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,$err1);
|
||||||
|
|
||||||
|
list($res2, $err2) = Destinations::activityByRangeAndTimeAndRadius(
|
||||||
|
$gpsdb, $db, $member_id, $all_time_days, $lat, $lng, $radius, 'end', $time, $time_delta);
|
||||||
|
if ($res2 && count($res2)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res2));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,$err2);
|
||||||
|
|
||||||
|
list($res3, $err3) = Destinations::activityByRangeAndRadius(
|
||||||
|
$gpsdb, $db, $member_id, $all_time_days, $lat, $lng, $radius, 'start');
|
||||||
|
if ($res3 && count($res3)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res3));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,$err3);
|
||||||
|
|
||||||
|
list($res4, $err4) = Destinations::activityByRangeAndRadius(
|
||||||
|
$gpsdb, $db, $member_id, $all_time_days, $lat, $lng, $radius, 'end');
|
||||||
|
if ($res4 && count($res4)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res4));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,$err4);
|
||||||
|
|
||||||
|
if ($country=='SG') {
|
||||||
|
// For US it may produce the results too far apart
|
||||||
|
list($res1, $err1) = Destinations::activityByRangeAndTime($db, $member_id, 7, $time, $time_delta, $country);
|
||||||
|
if ($res1 && count($res1)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res1));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list($res2, $err2) = Destinations::activityByRangeAndTime($db, $member_id, 30, $time, $time_delta, $country);
|
||||||
|
if ($res2 && count($res2)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res2));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list($res3, $err3) = Destinations::activityByRangeAndTime($db, $member_id, $all_time_days, $time, $time_delta, $country);
|
||||||
|
if ($res3 && count($res3)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res3));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list($res4, $err4) = Destinations::activityByRange($db, $member_id, 7, $country);
|
||||||
|
if ($res4 && count($res4)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res4));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list($res5, $err5) = Destinations::activityByRange($db, $member_id, 30, $country);
|
||||||
|
if ($res5 && count($res5)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res5));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list($res6, $err6) = Destinations::activityByRange($db, $member_id, $all_time_days, $country);
|
||||||
|
if ($res6 && count($res6)>0) {
|
||||||
|
$res = Destinations::uniqueTrips(array_merge($res,$res6));
|
||||||
|
if (count($res)>=Destinations::DEFAULT_OPTIONS) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//*/
|
||||||
|
if ($res && count($res)>0) {
|
||||||
|
return [$res, NULL];
|
||||||
|
}
|
||||||
|
return [NULL, "We could not find any recent activity in this area"];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAddressActivity($db, $address, $member_id, $time, $time_delta=Destinations::TIME_DELTA) {
|
||||||
|
// TODO: radius search
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
id | bigint | not null default nextval('address_id_seq'::regclass)
|
||||||
|
address | character varying(200) |
|
||||||
|
latitude | numeric |
|
||||||
|
longitude | numeric |
|
||||||
|
timezone | integer |
|
||||||
|
geocoding_date | date |
|
||||||
|
postal | character varying(40) |
|
||||||
|
country | character varying(2) | default 'SG'::character varying
|
||||||
|
geometry | geography(Point,4326) |
|
||||||
|
description | character varying(100) |
|
||||||
|
city_id | integer |
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static function activityByRange($db, $member_id, $days, $country=Destinations::DEFAULT_COUNTRY) {
|
||||||
|
$db_time = strtotime($time);
|
||||||
|
$db_days = date("w",$db_time) + (int)$days;
|
||||||
|
$db_country = pg_escape_string($country);
|
||||||
|
$q = "SELECT b.*, 60*date_part('hour', b.travel_date)+date_part('minute',b.travel_date) AS dm ";
|
||||||
|
/////// Start Locations ///////
|
||||||
|
$q.= ", c.address AS location_start_address, c.latitude AS location_start_lat, c.longitude AS location_start_lng";
|
||||||
|
$q.= ", c.timezone AS location_start_timezone, c.postal AS location_start_postal, c.country AS location_start_country";
|
||||||
|
$q.= ", c.description AS location_start_description, c.city_id AS location_start_city_id, c.geometry AS location_start_geometry ";
|
||||||
|
$q.= ", d.address AS location_end_address, d.latitude AS location_end_lat, d.longitude AS location_end_lng";
|
||||||
|
$q.= ", d.timezone AS location_end_timezone, d.postal AS location_end_postal, d.country AS location_end_country";
|
||||||
|
$q.= ", d.description AS location_end_description, d.city_id AS location_end_city_id, d.geometry AS location_end_geometry ";
|
||||||
|
/////// End Locations ///////
|
||||||
|
$q.= " FROM trackedemail_item a, parsedemail_item b ";
|
||||||
|
$q.= " LEFT JOIN address c ON (c.id=b.location_start_id) ";
|
||||||
|
$q.= " LEFT JOIN address d ON (d.id=b.location_end_id) ";
|
||||||
|
$q.= " WHERE a.id=b.trackedemail_item_id AND a.member_id=".((int)$member_id);
|
||||||
|
$q.= " AND b.dup_id IS NULL AND b.travel_date_end > (now() - interval '${db_days} days') ";
|
||||||
|
$q.= " AND (c.country='${db_country}' OR d.country='${db_country}') ";
|
||||||
|
$q.= " ORDER BY b.travel_date DESC LIMIT ".Destinations::DEFAULT_OPTIONS;
|
||||||
|
syslog(LOG_WARNING,$q);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
$result = [];
|
||||||
|
while ($f=pg_fetch_assoc($r)) {
|
||||||
|
$f["location_start_address"] = html_entity_decode ($f["location_start_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$f["location_end_address"] = html_entity_decode ($f["location_end_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$result[] = $f;
|
||||||
|
}
|
||||||
|
return [$result, NULL];
|
||||||
|
}
|
||||||
|
return [NULL,pg_last_error()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function activityByRangeAndRadius($gpsdb, $db, $member_id, $days, $lat, $lng, $radius, $what) {
|
||||||
|
syslog(LOG_WARNING,"Activity::activityByRangeAndRadius(\$gpsdb, \$db, $member_id, $days, $lat, $lng, $radius, $what)");
|
||||||
|
$limit_lat = (float)$lat;
|
||||||
|
$limit_lng = (float)$lng;
|
||||||
|
$limit_rad = $radius;
|
||||||
|
$db_days = (int)$days;
|
||||||
|
$q = "SELECT b.*, 60*date_part('hour', b.travel_date)+date_part('minute',b.travel_date) AS dm ";
|
||||||
|
/////// Start Locations ///////
|
||||||
|
$q.= ", c.address AS location_start_address, c.latitude AS location_start_lat, c.longitude AS location_start_lng";
|
||||||
|
$q.= ", c.timezone AS location_start_timezone, c.postal AS location_start_postal, c.country AS location_start_country";
|
||||||
|
$q.= ", c.description AS location_start_description, c.city_id AS location_start_city_id, c.geometry AS location_start_geometry ";
|
||||||
|
$q.= ", d.address AS location_end_address, d.latitude AS location_end_lat, d.longitude AS location_end_lng";
|
||||||
|
$q.= ", d.timezone AS location_end_timezone, d.postal AS location_end_postal, d.country AS location_end_country";
|
||||||
|
$q.= ", d.description AS location_end_description, d.city_id AS location_end_city_id, d.geometry AS location_end_geometry ";
|
||||||
|
/////// End Locations ///////
|
||||||
|
$q.= " FROM trackedemail_item a, parsedemail_item b ";
|
||||||
|
$q.= " LEFT JOIN address c ON (c.id=b.location_start_id) ";
|
||||||
|
$q.= " LEFT JOIN address d ON (d.id=b.location_end_id) ";
|
||||||
|
$q.= " WHERE a.id=b.trackedemail_item_id AND a.member_id=".((int)$member_id);
|
||||||
|
$q.= " AND b.dup_id IS NULL AND b.travel_date_end > (now() - interval '${db_days} days') ";
|
||||||
|
//$q.= " AND (b.location_start_id IN (%d,%d) OR b.location_end_id IN (%d,%d)) ";
|
||||||
|
$q.= " AND (";
|
||||||
|
$q.= "ST_DWithin(c.geometry,ST_SetSRID(ST_MakePoint(${limit_lng},${limit_lat}),4326)::geography,${limit_rad})";
|
||||||
|
$q.= " OR ";
|
||||||
|
$q.= "ST_DWithin(d.geometry,ST_SetSRID(ST_MakePoint(${limit_lng},${limit_lat}),4326)::geography,${limit_rad})";
|
||||||
|
$q.= ") ORDER BY b.travel_date DESC LIMIT ".Destinations::DEFAULT_OPTIONS;
|
||||||
|
syslog(LOG_WARNING,$q);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
$cache_from = [];
|
||||||
|
$cache_to = [];
|
||||||
|
$result = [];
|
||||||
|
while ($f = pg_fetch_assoc($r)) {
|
||||||
|
if (array_key_exists($f["location_start_geometry"],$cache_from) && $f["location_end_geometry"]==$cache_from[$f["location_start_geometry"]]) {
|
||||||
|
continue; // We have similar trip in result set - let's skip it
|
||||||
|
}
|
||||||
|
if (array_key_exists($f["location_end_geometry"],$cache_to) && $f["location_start_geometry"]==$cache_to[$f["location_end_geometry"]]) {
|
||||||
|
continue; // We have similar trip in result set - let's skip it
|
||||||
|
}
|
||||||
|
$f["location_start_address"] = html_entity_decode ($f["location_start_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$f["location_end_address"] = html_entity_decode ($f["location_end_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$result[] = $f;
|
||||||
|
$cache_from[$f["location_start_geometry"]] = $f["location_end_geometry"];
|
||||||
|
$cache_to[$f["location_end_geometry"]] = $f["location_start_geometry"];
|
||||||
|
}
|
||||||
|
unset($cache_from); // clear
|
||||||
|
unset($cache_to); // clear
|
||||||
|
return [$result, NULL];
|
||||||
|
}
|
||||||
|
return [NULL,pg_last_error()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function activityByRangeAndTimeAndRadius($gpsdb, $db, $member_id, $days, $lat, $lng, $radius, $what, $time, $time_delta=Destinations::TIME_DELTA) {
|
||||||
|
syslog(LOG_WARNING,"Activity::activityByRangeAndTimeAndRadius(\$gpsdb, \$db, $member_id, $days, $lat, $lng, $radius, $what, $time, $time_delta)");
|
||||||
|
$limit_lat = (float)$lat;
|
||||||
|
$limit_lng = (float)$lng;
|
||||||
|
$limit_rad = $radius;
|
||||||
|
$db_time = strtotime($time);
|
||||||
|
$db_days = date("w",$db_time) + (int)$days;
|
||||||
|
$db_time_delta = (int)$time_delta;
|
||||||
|
syslog(LOG_WARNING,"${db_time}=".date("Y-m-d H:i",$db_time));
|
||||||
|
// Ranges
|
||||||
|
$dh = 60*date("G",$db_time)+date("i",$db_time);
|
||||||
|
$d1 = $dh - $db_time_delta;
|
||||||
|
$d2 = $dh + $db_time_delta;
|
||||||
|
syslog(LOG_WARNING,"${d1} <= x <= ${d2}");
|
||||||
|
$q = "SELECT e.* FROM (SELECT b.*, 60*date_part('hour', b.travel_date)+date_part('minute',b.travel_date) AS dm ";
|
||||||
|
/////// Start Locations ///////
|
||||||
|
$q.= ", c.address AS location_start_address, c.latitude AS location_start_lat, c.longitude AS location_start_lng";
|
||||||
|
$q.= ", c.timezone AS location_start_timezone, c.postal AS location_start_postal, c.country AS location_start_country";
|
||||||
|
$q.= ", c.description AS location_start_description, c.city_id AS location_start_city_id, c.geometry AS location_start_geometry ";
|
||||||
|
$q.= ", d.address AS location_end_address, d.latitude AS location_end_lat, d.longitude AS location_end_lng";
|
||||||
|
$q.= ", d.timezone AS location_end_timezone, d.postal AS location_end_postal, d.country AS location_end_country";
|
||||||
|
$q.= ", d.description AS location_end_description, d.city_id AS location_end_city_id, d.geometry AS location_end_geometry ";
|
||||||
|
/////// End Locations ///////
|
||||||
|
$q.= " FROM trackedemail_item a, parsedemail_item b ";
|
||||||
|
$q.= " LEFT JOIN address c ON (c.id=b.location_start_id) ";
|
||||||
|
$q.= " LEFT JOIN address d ON (d.id=b.location_end_id) ";
|
||||||
|
$q.= " WHERE a.id=b.trackedemail_item_id AND a.member_id=".((int)$member_id);
|
||||||
|
$q.= " AND b.dup_id IS NULL AND b.travel_date_end > (now() - interval '${db_days} days') ";
|
||||||
|
$q.= " AND (";
|
||||||
|
$q.= "ST_DWithin(c.geometry,ST_SetSRID(ST_MakePoint(${limit_lng},${limit_lat}),4326)::geography,${limit_rad})";
|
||||||
|
$q.= " OR ";
|
||||||
|
$q.= "ST_DWithin(d.geometry,ST_SetSRID(ST_MakePoint(${limit_lng},${limit_lat}),4326)::geography,${limit_rad})";
|
||||||
|
$q.= ")) AS e ";
|
||||||
|
$q.= " WHERE e.dm>=${d1} AND e.dm<=${d2} ";
|
||||||
|
$q.= " ORDER BY e.travel_date DESC LIMIT ".Destinations::DEFAULT_OPTIONS;
|
||||||
|
syslog(LOG_WARNING,$q);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
syslog(LOG_WARNING,"parsedemail_item(s) to process: ".pg_num_rows($r));
|
||||||
|
$cache_from = [];
|
||||||
|
$cache_to = [];
|
||||||
|
$result = [];
|
||||||
|
while ($f=pg_fetch_assoc($r)) {
|
||||||
|
if (array_key_exists($f["location_start_geometry"],$cache_from) && $f["location_end_geometry"]==$cache_from[$f["location_start_geometry"]]) {
|
||||||
|
continue; // We have similar trip in result set - let's skip it
|
||||||
|
}
|
||||||
|
if (array_key_exists($f["location_end_geometry"],$cache_to) && $f["location_start_geometry"]==$cache_to[$f["location_end_geometry"]]) {
|
||||||
|
continue; // We have similar trip in result set - let's skip it
|
||||||
|
}
|
||||||
|
$f["location_start_address"] = html_entity_decode ($f["location_start_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$f["location_end_address"] = html_entity_decode ($f["location_end_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$result[] = $f;
|
||||||
|
}
|
||||||
|
unset($cache_from); // clear
|
||||||
|
unset($cache_to); // clear
|
||||||
|
return [$result, NULL];
|
||||||
|
}
|
||||||
|
return [NULL,pg_last_error()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function activityByRangeAndTime($db, $member_id, $days, $time, $time_delta=Destinations::TIME_DELTA, $country=Destinations::DEFAULT_COUNTRY) {
|
||||||
|
syslog(LOG_WARNING,"Activity::activityByRangeAndTime(\$db, $member_id, $days, $time, $time_delta");
|
||||||
|
$db_time = strtotime($time);
|
||||||
|
$db_days = date("w",$db_time) + (int)$days;
|
||||||
|
$db_time_delta = (int)$time_delta;
|
||||||
|
$db_country = pg_escape_string($country);
|
||||||
|
syslog(LOG_WARNING,"${db_time}=".date("Y-m-d H:i",$db_time));
|
||||||
|
// Ranges
|
||||||
|
$dh = 60*date("G",$db_time)+date("i",$db_time);
|
||||||
|
$d1 = $dh - $db_time_delta;
|
||||||
|
$d2 = $dh + $db_time_delta;
|
||||||
|
syslog(LOG_WARNING,"${d1} <= x <= ${d2}");
|
||||||
|
$q = "SELECT e.* FROM (SELECT b.*, 60*date_part('hour', b.travel_date)+date_part('minute',b.travel_date) AS dm ";
|
||||||
|
/////// Start Locations ///////
|
||||||
|
$q.= ", c.address AS location_start_address, c.latitude AS location_start_lat, c.longitude AS location_start_lng";
|
||||||
|
$q.= ", c.timezone AS location_start_timezone, c.postal AS location_start_postal, c.country AS location_start_country";
|
||||||
|
$q.= ", c.description AS location_start_description, c.city_id AS location_start_city_id, c.geometry AS location_start_geometry ";
|
||||||
|
$q.= ", d.address AS location_end_address, d.latitude AS location_end_lat, d.longitude AS location_end_lng";
|
||||||
|
$q.= ", d.timezone AS location_end_timezone, d.postal AS location_end_postal, d.country AS location_end_country";
|
||||||
|
$q.= ", d.description AS location_end_description, d.city_id AS location_end_city_id, d.geometry AS location_end_geometry ";
|
||||||
|
/////// End Locations ///////
|
||||||
|
$q.= " FROM trackedemail_item a, parsedemail_item b ";
|
||||||
|
$q.= " LEFT JOIN address c ON (c.id=b.location_start_id) ";
|
||||||
|
$q.= " LEFT JOIN address d ON (d.id=b.location_end_id) ";
|
||||||
|
$q.= " WHERE a.id=b.trackedemail_item_id AND a.member_id=".((int)$member_id);
|
||||||
|
$q.= " AND (c.country='${db_country}' OR d.country='${db_country}') ";
|
||||||
|
$q.= " AND b.dup_id IS NULL AND b.travel_date_end > (now() - interval '${db_days} days')) AS e ";
|
||||||
|
$q.= " WHERE e.dm>=${d1} AND e.dm<=${d2} ";
|
||||||
|
$q.= " ORDER BY e.travel_date DESC LIMIT ".Destinations::DEFAULT_OPTIONS;
|
||||||
|
syslog(LOG_WARNING,$q);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
$result = [];
|
||||||
|
while ($f=pg_fetch_assoc($r)) {
|
||||||
|
$f["location_start_address"] = html_entity_decode ($f["location_start_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$f["location_end_address"] = html_entity_decode ($f["location_end_address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$result[] = $f;
|
||||||
|
}
|
||||||
|
return [$result, NULL];
|
||||||
|
}
|
||||||
|
return [NULL,pg_last_error()];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getAllTimeDays() {
|
||||||
|
$datediff = time() - Destinations::TIME_LIMIT;
|
||||||
|
return round($datediff / (60 * 60 * 24));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function uniqueTrips($res) {
|
||||||
|
$cache = [];
|
||||||
|
$result = [];
|
||||||
|
foreach ($res as $trip) {
|
||||||
|
$key1ids = $trip["location_start_id"]."_".$trip["location_end_id"];
|
||||||
|
$key1gps = $trip["location_start_lat"]."_".$trip["location_start_lng"]."_".$trip["location_end_lat"]."_".$trip["location_end_lng"];
|
||||||
|
$key2ids = $trip["location_end_id"]."_".$trip["location_start_id"];
|
||||||
|
$key2gps = $trip["location_end_lat"]."_".$trip["location_end_lng"]."_".$trip["location_start_lat"]."_".$trip["location_start_lng"];
|
||||||
|
if (array_key_exists($key1ids, $cache) || array_key_exists($key2ids, $cache)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (array_key_exists($key1gps, $cache) || array_key_exists($key2gps, $cache)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$cache[$key1ids] = $key2ids;
|
||||||
|
$cache[$key1gps] = $key2gps;
|
||||||
|
$result[] = $trip;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DestinationsApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'destinations';
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error' => 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get single record (by id)
|
||||||
|
* http://DOMAIN/destinations/1
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error'=> 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING,'DestinationsApi::createAction()');
|
||||||
|
$message = 'We could not find any recent activity in this area';
|
||||||
|
$code = 404;
|
||||||
|
$time = $this->requestParams['time'] ?? '';
|
||||||
|
$location = $this->requestParams['location'] ?? [];
|
||||||
|
$country = $this->requestParams['country'] ?? '';
|
||||||
|
$member_id = $this->requestParams['member_id'] ?? 0;
|
||||||
|
try {
|
||||||
|
$db = new Db();
|
||||||
|
|
||||||
|
$country = Geocode::getCountryByGPS($db->getConnect(), $location, $country, Destinations::DEFAULT_COUNTRY);
|
||||||
|
syslog(LOG_WARNING,'country='.$country);
|
||||||
|
|
||||||
|
$country = Geocode::mockGPSCountry($db->getConnect(), $member_id, $country, 'default');
|
||||||
|
|
||||||
|
$gps_country_code = $country; // Guessed
|
||||||
|
|
||||||
|
if ($country!='US' && $country!='SG') {
|
||||||
|
throw new RuntimeException('Trips has not yet launched in your country. You can still track your travel activity and access exclusive deals. Start exploring!',500);
|
||||||
|
}
|
||||||
|
if ($member_id<1) {
|
||||||
|
throw new RuntimeException('Invalid member ID',500);
|
||||||
|
}
|
||||||
|
if ($time=='' || strtotime($time)<Destinations::TIME_LIMIT) {
|
||||||
|
throw new RuntimeException('Invalid time',500);
|
||||||
|
}
|
||||||
|
$address = NULL;
|
||||||
|
$street_address = "";
|
||||||
|
syslog(LOG_WARNING, "location => " . json_encode($location));
|
||||||
|
|
||||||
|
if (is_array($location) && isset($location["lat"]) && isset($location["lng"])) {
|
||||||
|
// DEBUG
|
||||||
|
list($location["lat"],$location["lng"]) = Geocode::mockGPSLocation(
|
||||||
|
$db->getConnect(), $member_id, $location["lat"], $location["lng"], 'default');
|
||||||
|
|
||||||
|
syslog(LOG_WARNING,"lat=".$location["lat"].",lng=".$location["lng"]);
|
||||||
|
list($street_address,$err) = GeocodeApi::reverseGeocode($db, $location["lat"], $location["lng"]);
|
||||||
|
if ($street_address=="") {
|
||||||
|
list($address,$err) = GeofenceApi::getAnchor($db, $location["lat"], $location["lng"]);
|
||||||
|
if (is_array($address) && array_key_exists("address",$address) && $address["address"]!="") {
|
||||||
|
$street_address = $address["address"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($street_address=="") {
|
||||||
|
syslog(LOG_WARNING,'Reverse geocoder failed for ('.$location["lat"].', '.$location["lng"].')');
|
||||||
|
throw new RuntimeException($err?"Geocoder failed: $err":'Cannot geocode your GPS location',500);
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,"street_address=".json_encode($street_address));
|
||||||
|
if (!is_array($address) || !array_key_exists("address",$address) || $address["address"]=="") {
|
||||||
|
list($address,$err) = Geocode::checkLatLngByAddress($db->getConnect(), $street_address, $country);
|
||||||
|
}
|
||||||
|
if (!is_array($address) || !isset($address["address"])) {
|
||||||
|
syslog(LOG_WARNING,'Geocoder failed for "'.$street_address.'"');
|
||||||
|
throw new RuntimeException($err?"Geocoder failed: $err":'Cannot get address for your GPS location '.$street_address,500);
|
||||||
|
}
|
||||||
|
// Adjust GPS coordinates if any
|
||||||
|
if (array_key_exists("latitude", $address) && $address["latitude"]!=null &&
|
||||||
|
array_key_exists("longitude",$address) && $address["longitude"]!=null &&
|
||||||
|
$address["latitude"]!=0 && $address["longitude"]!=0) {
|
||||||
|
$location["lat"] = $address["latitude"];
|
||||||
|
$location["lng"] = $address["longitude"];
|
||||||
|
$address["lat"] = $address["latitude"];
|
||||||
|
$address["lng"] = $address["longitude"];
|
||||||
|
} else if (array_key_exists("lat",$address) && $address["lat"]!=null &&
|
||||||
|
array_key_exists("lng",$address) && $address["lng"]!=null &&
|
||||||
|
$address["lat"]!=0 && $address["lng"]!=0) {
|
||||||
|
$location["lat"] = $address["lat"];
|
||||||
|
$location["lng"] = $address["lng"];
|
||||||
|
$address["latitude"] = $address["lat"];
|
||||||
|
$address["longitude"] = $address["lng"];
|
||||||
|
}
|
||||||
|
list($location,$address) = DestinationsApi::adjustAddressLocationGPS($location,$address);
|
||||||
|
if (is_array($address) && array_key_exists("country",$address)) {
|
||||||
|
$gps_country_code = $address["country"]; // Geocoded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 0. Check if we are in the service area
|
||||||
|
/* GeocodeApi::checkWithinTheServiceArea($country,[
|
||||||
|
[
|
||||||
|
"type"=>1,
|
||||||
|
"geocode" => [
|
||||||
|
"lat" => $location["lat"],
|
||||||
|
"lng" => $location["lng"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]); //*/
|
||||||
|
syslog(LOG_WARNING, "location => " . json_encode($location));
|
||||||
|
|
||||||
|
// Step 1. Get activities
|
||||||
|
list($res,$err) = Destinations::byActivity(
|
||||||
|
$db->getConnect(), $db->getConnectGPS(), $member_id,
|
||||||
|
$location["lat"], $location["lng"], Destinations::ACTIVITY_RADIUS,
|
||||||
|
$time, Destinations::TIME_DELTA, $country);
|
||||||
|
if (!$res || count($res)<1) {
|
||||||
|
if ($err!="") {
|
||||||
|
throw new RuntimeException($err, 500);
|
||||||
|
}
|
||||||
|
throw new RuntimeException($message, 404);
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,'Recent activity has '.count($res).' trips!');
|
||||||
|
//DestinationsApi::debugTrips($res,'0');
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"trips" => $res,
|
||||||
|
"address" => $address,
|
||||||
|
"country" => $country,
|
||||||
|
"gps_country_code" => $gps_country_code,
|
||||||
|
"street_address" => html_entity_decode($street_address)
|
||||||
|
), 200);
|
||||||
|
} catch (RuntimeException $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
$code = $e->getCode();
|
||||||
|
syslog(LOG_WARNING,$message);
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), $code);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function adjustAddressLocationGPS($location,$address) {
|
||||||
|
syslog(LOG_WARNING,'DestinationsApi::adjustAddressLocationGPS($location,$address)');
|
||||||
|
if (array_key_exists("latitude", $address) && $address["latitude"]!=null &&
|
||||||
|
array_key_exists("longitude",$address) && $address["longitude"]!=null &&
|
||||||
|
$address["latitude"]!=0 && $address["longitude"]!=0) {
|
||||||
|
$location["lat"] = $address["latitude"];
|
||||||
|
$location["lng"] = $address["longitude"];
|
||||||
|
$address["lat"] = $address["latitude"];
|
||||||
|
$address["lng"] = $address["longitude"];
|
||||||
|
} else if (array_key_exists("lat",$address) && $address["lat"]!=null &&
|
||||||
|
array_key_exists("lng",$address) && $address["lng"]!=null &&
|
||||||
|
$address["lat"]!=0 && $address["lng"]!=0) {
|
||||||
|
$location["lat"] = $address["lat"];
|
||||||
|
$location["lng"] = $address["lng"];
|
||||||
|
$address["latitude"] = $address["lat"];
|
||||||
|
$address["longitude"] = $address["lng"];
|
||||||
|
}
|
||||||
|
//syslog(LOG_WARNING,json_encode($address));
|
||||||
|
//syslog(LOG_WARNING,"location => " . json_encode($location));
|
||||||
|
return [$location,$address];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function debugTrips($trips,$what='0') {
|
||||||
|
return; /*
|
||||||
|
foreach ($trips as $trip) {
|
||||||
|
$leg_fare = $trip['multimodal']['options']['leg_fare'];
|
||||||
|
syslog(LOG_WARNING,'>>>>>>> '.$what.' >>>>>>> '.json_encode($leg_fare));
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error"
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
require_once('../../core/backend.php');
|
||||||
|
require_once('../constants.php');
|
||||||
|
|
||||||
|
require_once('../common/vendor/autoload.php');
|
||||||
|
require_once('../common/Api.php');
|
||||||
|
require_once('../common/Db.php');
|
||||||
|
require_once('../common/GoogleKMS.php');
|
||||||
|
require_once('../common/Logger.php');
|
||||||
|
require_once('../common/Utilities.php');
|
||||||
|
|
||||||
|
require_once('Destinations.php');
|
||||||
|
require_once('DestinationsApi.php');
|
||||||
|
|
||||||
|
require_once('../trips/Address.php');
|
||||||
|
require_once('../trips/Geocode.php');
|
||||||
|
require_once('../trips/GeocodeApi.php');
|
||||||
|
require_once('../trips/Geofence.php');
|
||||||
|
require_once('../trips/GeofenceApi.php');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"],-strlen($httpAuthToken))!=$httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"],-strlen($httpAuthToken))!=$httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'],'/api/')===false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'],'/'));
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
if ($requestUri[0]=='destinations') {
|
||||||
|
$api = new DestinationsApi($requestUri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(Array('error' => 'Invalid API request'));
|
||||||
|
}
|
||||||
|
echo $api->run();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
echo json_encode(Array('error' => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 665 B |
|
After Width: | Height: | Size: 628 B |
@@ -0,0 +1,60 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="swagger-ui.css" >
|
||||||
|
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
html
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after
|
||||||
|
{
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
margin:0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script src="swagger-ui-bundle.js"> </script>
|
||||||
|
<script src="swagger-ui-standalone-preset.js"> </script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "../swagger.php",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
})
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
require('../../../adminsavvy/vendor/autoload.php');
|
||||||
|
$openapi = \OpenApi\scan('.');
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo $openapi->toJson();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/banklogin/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Banklogin {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class BankloginApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'banklogin';
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Data not found"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get single record (by id)
|
||||||
|
* http://DOMAIN/geocode/1
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error'=> 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
global $savvyext;
|
||||||
|
$path = $this->requestParams['path'];
|
||||||
|
$method = $this->requestParams['method'];
|
||||||
|
$authToken = $this->requestParams['auth_token'] ?? "";
|
||||||
|
$data = $this->requestParams['data'] ?? array();
|
||||||
|
|
||||||
|
$url = $savvyext->cfgReadChar('microservices.account') . "/api/v1/" . rtrim($path, '/') . '/';
|
||||||
|
|
||||||
|
$opts = array(
|
||||||
|
'http' => array(
|
||||||
|
'method' => $method,
|
||||||
|
'protocol_version' => 1.1,
|
||||||
|
'header' =>
|
||||||
|
"Accept: application/json\r\n"
|
||||||
|
),
|
||||||
|
"ssl" => array(
|
||||||
|
"verify_peer"=>false,
|
||||||
|
"verify_peer_name"=>false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if(!empty($authToken)){
|
||||||
|
$opts['http']['header'] .= "Authorization: Token ${authToken}\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($method == 'GET') {
|
||||||
|
if(is_array($data)) {
|
||||||
|
$data = "?" . http_build_query($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
$url .= $data;
|
||||||
|
$opts['http']['header'] .= "Content-Type: application/x-www-form-urlencoded\r\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$opts['http']['content'] = json_encode($data);
|
||||||
|
$opts['http']['header'] .= "Content-Type: application/json\r\nConnection: close\r\n";
|
||||||
|
$opts['http']['header'] .= "Content-length: " . strlen($opts['http']['content']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$context = stream_context_create($opts);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$body = file_get_contents($url, false, $context);
|
||||||
|
$result = json_decode($body,true);
|
||||||
|
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'data'=>$result,
|
||||||
|
'options'=>""), 200);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log(json_encode($e));
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error"
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once('../../core/backend.php');
|
||||||
|
require_once('../constants.php');
|
||||||
|
|
||||||
|
require_once('../common/Api.php');
|
||||||
|
require_once('../common/Db.php');
|
||||||
|
|
||||||
|
require_once('Banklogin.php');
|
||||||
|
require_once('BankloginApi.php');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$bankloginAuthToken = $savvyext->cfgReadChar('system.bank_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"],-strlen($httpAuthToken))!=$httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"],-strlen($httpAuthToken))!=$httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'],'/api/')===false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'],'/'));
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
if ($requestUri[0]=='banklogin') {
|
||||||
|
$api = new BankloginApi($requestUri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(Array('error' => 'Invalid API request'));
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $api->run();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
echo json_encode(Array('error' => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 665 B |
|
After Width: | Height: | Size: 628 B |
@@ -0,0 +1,60 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="swagger-ui.css" >
|
||||||
|
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
html
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after
|
||||||
|
{
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
margin:0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script src="swagger-ui-bundle.js"> </script>
|
||||||
|
<script src="swagger-ui-standalone-preset.js"> </script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "../swagger.php",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
})
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
require('../../../adminsavvy/vendor/autoload.php');
|
||||||
|
$openapi = \OpenApi\scan('.');
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo $openapi->toJson();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/blog/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Blog {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class BlogApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'blog';
|
||||||
|
|
||||||
|
public function __construct($requestUri, $encryption=true) {
|
||||||
|
$this->cacheWhitelist = [
|
||||||
|
"viewAction" => ['ttl' => 900], // 900 sec. = 15 min.
|
||||||
|
"indexAction" => ['ttl' => 900]
|
||||||
|
];
|
||||||
|
parent::__construct($requestUri, $encryption);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
global $savvyext;
|
||||||
|
$message = "Data not found";
|
||||||
|
$limit = trim($this->requestParams["limit"] ?? "");
|
||||||
|
$page = trim($this->requestParams["page"] ?? "");
|
||||||
|
$params =[
|
||||||
|
'limit' => $limit,
|
||||||
|
'page' => $page
|
||||||
|
];
|
||||||
|
|
||||||
|
$url = $savvyext->cfgReadChar('system.blog_api_url') . "/latest-articles?".http_build_query($params);
|
||||||
|
|
||||||
|
try {
|
||||||
|
$body = file_get_contents($url, false);
|
||||||
|
$result = json_decode($body, true);
|
||||||
|
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'data' => $result,
|
||||||
|
'error' => ""),
|
||||||
|
200);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log(json_encode($e));
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message,
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get single record (by id)
|
||||||
|
* http://DOMAIN/blog/679
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
global $savvyext;
|
||||||
|
$message = "Data not found";
|
||||||
|
$id = array_shift($this->requestUri);
|
||||||
|
if(!empty($id)){
|
||||||
|
$url = $savvyext->cfgReadChar('system.blog_api_url') . "/articles/" . intval($id);
|
||||||
|
try {
|
||||||
|
$body = file_get_contents($url, false);
|
||||||
|
$result = json_decode($body, true);
|
||||||
|
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'data' => $result,
|
||||||
|
'error' => ""), 200);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
error_log(json_encode($e));
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message,
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Data not found",
|
||||||
|
), 400);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error",
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error",
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once('../../core/backend.php');
|
||||||
|
require_once('../constants.php');
|
||||||
|
|
||||||
|
require_once('../common/Api.php');
|
||||||
|
require_once('../common/Db.php');
|
||||||
|
|
||||||
|
require_once('Blog.php');
|
||||||
|
require_once('BlogApi.php');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$bankloginAuthToken = $savvyext->cfgReadChar('system.bank_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"],-strlen($httpAuthToken))!=$httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"],-strlen($httpAuthToken))!=$httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'],'/api/')===false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'],'/'));
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
if ($requestUri[0]=='blog') {
|
||||||
|
$api = new BlogApi($requestUri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(Array('error' => 'Invalid API request'));
|
||||||
|
}
|
||||||
|
|
||||||
|
echo $api->run();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
echo json_encode(Array('error' => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/booking/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Booking {
|
||||||
|
|
||||||
|
const STATUS_ERROR = -1;
|
||||||
|
const STATUS_INIT = 1;
|
||||||
|
const STATUS_BOOKED = 2;
|
||||||
|
const STATUS_CANCELED = 3;
|
||||||
|
const STATUS_VENDOR_CANCELED = 4;
|
||||||
|
const STATUS_VEHICLE_ARRIVED = 5;
|
||||||
|
const STATUS_COMPLETED = 6;
|
||||||
|
const STATUS_IN_PROGRESS = 7;
|
||||||
|
const STATUS_DISPATCHED = 8;
|
||||||
|
const STATUS_LOCATION_UPDATE = 9;
|
||||||
|
|
||||||
|
/*
|
||||||
|
CREATE TABLE booking (
|
||||||
|
id serial not null constraint booking_pkey primary key,
|
||||||
|
quote_id bigint not null,
|
||||||
|
provider_booking_ref varchar(200) not null,
|
||||||
|
details json,
|
||||||
|
created timestamp default now(),
|
||||||
|
updated timestamp,
|
||||||
|
completed timestamp,
|
||||||
|
status smallint default 0,
|
||||||
|
message text,
|
||||||
|
cost numeric default 0
|
||||||
|
);
|
||||||
|
|
||||||
|
alter table booking
|
||||||
|
add constraint booking_quotes_id_fk
|
||||||
|
foreign key (quote_id) references quotes;
|
||||||
|
|
||||||
|
|
||||||
|
CREATE TABLE booking_details (
|
||||||
|
id serial not null constraint booking_details_pkey primary key,
|
||||||
|
booking_id bigint not null,
|
||||||
|
action varchar(64),
|
||||||
|
details json,
|
||||||
|
created timestamp default now(),
|
||||||
|
message text,
|
||||||
|
request json
|
||||||
|
);
|
||||||
|
|
||||||
|
alter table booking_details
|
||||||
|
add constraint booking_details_booking_id_fk
|
||||||
|
foreign key (booking_id) references booking;*/
|
||||||
|
|
||||||
|
public static function getById($db, $id) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getById(\$db, $id)" );
|
||||||
|
Logger::debug( "Booking::getById(\$db, $id)" );
|
||||||
|
$result = [];
|
||||||
|
// $q = "SELECT * FROM booking WHERE id=${id}";
|
||||||
|
$q = "SELECT b.*,
|
||||||
|
a_s.address as location_start, a_s.latitude as location_start_lat, a_s.longitude as location_start_lng,
|
||||||
|
a_e.address as location_end, a_e.latitude as location_end_lat, a_e.longitude as location_end_lng,
|
||||||
|
a_s.country as location_country
|
||||||
|
FROM booking b
|
||||||
|
LEFT JOIN quotes q on b.quote_id = q.id
|
||||||
|
LEFT JOIN address a_s on q.location_start_id = a_s.id
|
||||||
|
LEFT JOIN address a_e on q.location_end_id = a_e.id
|
||||||
|
WHERE b.id=${id}";
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
//syslog(LOG_WARNING,$q);
|
||||||
|
if ( $r && pg_num_rows( $r ) && $f = pg_fetch_assoc( $r ) ) {
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getAll($db, $params = []) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getAll(\$db, $params)" );
|
||||||
|
Logger::debug( "Booking::getAll(\$db, $params)" );
|
||||||
|
$result = [];
|
||||||
|
// $q = "SELECT * FROM booking ";
|
||||||
|
$q = "SELECT b.*,
|
||||||
|
a.address as location_end, a.latitude as location_end_lat, a.longitude as location_end_lng,
|
||||||
|
a.country as location_country
|
||||||
|
FROM booking b
|
||||||
|
LEFT JOIN quotes q on b.quote_id = q.id
|
||||||
|
LEFT JOIN address a on q.location_end_id = a.id ";
|
||||||
|
if (count($params)) {
|
||||||
|
if (array_key_exists('active', $params) && (bool)$params['active'] == true) {
|
||||||
|
$q .= " WHERE b.status = ". Booking::STATUS_BOOKED. " OR b.status = ". Booking::STATUS_IN_PROGRESS. " OR b.status = ". Booking::STATUS_DISPATCHED ;
|
||||||
|
} else if (array_key_exists('status', $params) && isset($params['status'])) {
|
||||||
|
//$statuses = explode(',', $params['status']);
|
||||||
|
$q .= " WHERE b.status IN(". $params['status'] .")";
|
||||||
|
}
|
||||||
|
if (array_key_exists('limit', $params) && array_key_exists('offset', $params)) {
|
||||||
|
$limit = $params['limit'];
|
||||||
|
$offset = $params['offset'];
|
||||||
|
$q .= " ORDER BY created DESC LIMIT ${limit} OFFSET ${offset} ";
|
||||||
|
} else {
|
||||||
|
$q .= " ORDER BY created DESC LIMIT 10 OFFSET 0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
$result = [];
|
||||||
|
if ( $r && pg_num_rows( $r ) ) {
|
||||||
|
while ($row = pg_fetch_assoc($r)) {
|
||||||
|
array_push($result, $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getByBookingRef($db, $bookingRef) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getByBookingRef(\$db, $bookingRef)" );
|
||||||
|
Logger::debug( "Booking::getById(\$db, $bookingRef)" );
|
||||||
|
$result = [];
|
||||||
|
$q = "SELECT * FROM booking WHERE provider_booking_ref='${bookingRef}'";
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
//syslog(LOG_WARNING,$q);
|
||||||
|
if ( $r && pg_num_rows( $r ) && $f = pg_fetch_assoc( $r ) ) {
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function getByMemberId($db, $id, $params = []) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getByMemberId(\$db, $id)" );
|
||||||
|
Logger::debug( "Booking::getByMemberId(\$db, $id)" );
|
||||||
|
$result = [];
|
||||||
|
// $q = "SELECT * FROM booking WHERE member_id=${id} ";
|
||||||
|
$q = "SELECT b.*,
|
||||||
|
a.address as location_end, a.latitude as location_end_lat, a.longitude as location_end_lng,
|
||||||
|
a.country as location_country
|
||||||
|
FROM booking b
|
||||||
|
LEFT JOIN quotes q on b.quote_id = q.id
|
||||||
|
LEFT JOIN address a on q.location_end_id = a.id
|
||||||
|
WHERE b.member_id=${id}";
|
||||||
|
|
||||||
|
if (count($params)) {
|
||||||
|
if (array_key_exists('active', $params) && (bool)$params['active'] == true) {
|
||||||
|
$q .= " AND b.status = ". Booking::STATUS_BOOKED. " OR b.status = ". Booking::STATUS_IN_PROGRESS. " OR b.status = ". Booking::STATUS_DISPATCHED ;
|
||||||
|
} else if (array_key_exists('status', $params) && isset($params['status'])) {
|
||||||
|
//$statuses = explode(',', $params['status']);
|
||||||
|
$q .= " AND b.status IN(". $params['status'] .")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('limit', $params) && array_key_exists('offset', $params)) {
|
||||||
|
$limit = $params['limit'];
|
||||||
|
$offset = $params['offset'];
|
||||||
|
$q .= " ORDER BY created DESC LIMIT ${limit} OFFSET ${offset} ";
|
||||||
|
} else {
|
||||||
|
$q .= " ORDER BY created DESC LIMIT 10 OFFSET 0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
$result = [];
|
||||||
|
if ( $r && pg_num_rows( $r ) ) {
|
||||||
|
while ($row = pg_fetch_assoc($r)) {
|
||||||
|
array_push($result, $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLastNotCompletedBookingForMember($db, $member_id) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getLastNotCompletedBookingForMember(\$db, $member_id)" );
|
||||||
|
Logger::debug( "Booking::getLastNotCompletedBookingForMember(\$db, $member_id)" );
|
||||||
|
$result = [];
|
||||||
|
$q = "SELECT * FROM booking WHERE member_id=${member_id} AND completed IS NULL AND status = ". Booking::STATUS_BOOKED ." AND cost > 0";
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
//syslog(LOG_WARNING,$q);
|
||||||
|
if ( $r && pg_num_rows( $r ) && $f = pg_fetch_assoc( $r ) ) {
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function create($db, $data) {
|
||||||
|
syslog(LOG_WARNING,'Booking::create($db, $data)');
|
||||||
|
|
||||||
|
$quote_id = $data["quote_id"];
|
||||||
|
$provider_booking_ref = $data["provider_booking_ref"];
|
||||||
|
$details = $data["details"];
|
||||||
|
$status = (int)$data["status"];
|
||||||
|
$memberId = (int)$data["member_id"];
|
||||||
|
$cost = (int)$data["cost"];
|
||||||
|
$q = "INSERT INTO booking(quote_id, provider_booking_ref, details, status, member_id, cost) VALUES (${quote_id}, '${provider_booking_ref}', '${details}', ${status}, ${memberId}, ${cost}) RETURNING id";
|
||||||
|
$log = [
|
||||||
|
'message' => 'Insert Booking',
|
||||||
|
'data' =>$data,
|
||||||
|
'query' =>$q
|
||||||
|
];
|
||||||
|
Logger::debug($log);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
return [self::getById($db, $f["id"]),NULL];
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,pg_last_error($db));
|
||||||
|
return [NULL,pg_last_error($db)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function update($db, $data) {
|
||||||
|
syslog(LOG_WARNING,'Booking::update(): '.json_encode($data));
|
||||||
|
$q = self::buildUpdateSQL($data);
|
||||||
|
syslog(LOG_WARNING,$q);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
$log = [
|
||||||
|
'affected_row' => pg_affected_rows($r),
|
||||||
|
'message' => 'Update Booking',
|
||||||
|
'data' =>$data,
|
||||||
|
'query' =>$q
|
||||||
|
];
|
||||||
|
Logger::debug($log);
|
||||||
|
if ($r && pg_affected_rows($r)) {
|
||||||
|
return array(self::getById($db, $data["id"]),NULL);
|
||||||
|
}
|
||||||
|
return array(NULL, pg_last_error($db));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function buildUpdateSQL($data) {
|
||||||
|
$q = "UPDATE booking SET";
|
||||||
|
foreach ($data as $key => $value) {
|
||||||
|
if ($key != 'id') {
|
||||||
|
if (is_int($value) || "now()" == $value) {
|
||||||
|
$q .= " ${key}=${value},";
|
||||||
|
} else {
|
||||||
|
$q .= " ${key}='".pg_escape_string($value)."',";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$q = substr($q, 0, -1);
|
||||||
|
$q .= " WHERE id=".$data["id"];
|
||||||
|
return $q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createDetails($db, $data) {
|
||||||
|
syslog(LOG_WARNING,'Booking::createDetails($db, $data)');
|
||||||
|
|
||||||
|
$booking_id = $data['booking_id'];
|
||||||
|
$action = $data['action'];
|
||||||
|
$details = $data['details'];
|
||||||
|
$message = $data['message'];
|
||||||
|
$request = $data['request'];
|
||||||
|
|
||||||
|
$q = "INSERT INTO booking_details(booking_id, action, details, message, request) VALUES (${booking_id}, '${action}', '${details}', '${message}', '${request}') RETURNING id";
|
||||||
|
$log = [
|
||||||
|
'message' => 'Insert Booking Details',
|
||||||
|
'data' =>$data,
|
||||||
|
'query' =>$q
|
||||||
|
];
|
||||||
|
Logger::debug($log);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
return [self::getDetailsById($db, $f["id"]),NULL];
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,pg_last_error($db));
|
||||||
|
return [NULL,pg_last_error($db)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDetailsById($db, $id) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getDetailsById(\$db, $id)" );
|
||||||
|
Logger::debug( "Booking::getDetailsById(\$db, $id)" );
|
||||||
|
$result = [];
|
||||||
|
$q = "SELECT id, booking_id, action, details, message FROM booking_details WHERE id=${id}";
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
if ( $r && pg_num_rows( $r ) && $f = pg_fetch_assoc( $r ) ) {
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDetailsByBookingId($db, $booking_id) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getDetailsByBookingId(\$db, $booking_id)" );
|
||||||
|
Logger::debug( "Booking::getDetailsByBookingId(\$db, $booking_id)" );
|
||||||
|
$result = [];
|
||||||
|
$q = "SELECT id, booking_id, action, details, message FROM booking_details WHERE booking_id=${booking_id} ORDER BY id";
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
$result = [];
|
||||||
|
if ( $r && pg_num_rows( $r ) ) {
|
||||||
|
while ($row = pg_fetch_assoc($r)) {
|
||||||
|
array_push($result, $row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getMemberBySessionId($db, $sessionId) {
|
||||||
|
syslog( LOG_WARNING, "Booking::getMemberBySessionId(\$db, $sessionId)" );
|
||||||
|
Logger::debug( "Booking::getMemberBySessionId(\$db, $sessionId)" );
|
||||||
|
$result = [];
|
||||||
|
$q = "SELECT * FROM public.members_session WHERE session = ${sessionId} LIMIT 1 OFFSET 0";
|
||||||
|
$r = pg_query( $db, $q );
|
||||||
|
if ( $r && pg_num_rows( $r ) && $f = pg_fetch_assoc( $r )) {
|
||||||
|
return [$f, NULL];
|
||||||
|
}
|
||||||
|
syslog(LOG_WARNING,pg_last_error($db));
|
||||||
|
return [NULL,pg_last_error($db)];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Options {
|
||||||
|
|
||||||
|
public static function getTransportOptions($db, $origin, $destination) {
|
||||||
|
return Options::getServicesByLatitudeLongitude($db, $origin["lat"],$origin["lng"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getServicesByLatitudeLongitude($db, $lat, $lng) {
|
||||||
|
// $lat,$lng => geofence_area_country
|
||||||
|
$geofence_area_country = [];
|
||||||
|
$q = "SELECT * FROM (SELECT *,ST_DistanceSphere(location::geometry,ST_SetSRID(ST_MakePoint(";
|
||||||
|
$q.= $lng.",".$lat."),4326)::geometry) AS distance FROM geofence_area_country ";
|
||||||
|
$q.= " WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(";
|
||||||
|
$q.= $lng.",".$lat."),4326)::geography,radius)) AS a ORDER BY a.distance ASC LIMIT 1";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$geofence_area_country = $f;
|
||||||
|
} else {
|
||||||
|
// Fatal
|
||||||
|
$err = pg_last_error($db);
|
||||||
|
$err = $err ? $err : $q;
|
||||||
|
error_log('Options::getTransportOptions => '.$err);
|
||||||
|
throw new Exception("Failed to match input origin to a country");
|
||||||
|
}
|
||||||
|
// geofence_area_country => country_servies
|
||||||
|
$country_services = [];
|
||||||
|
if (array_key_exists("id",$geofence_area_country) && $geofence_area_country["id"]>0) {
|
||||||
|
$q = "SELECT * FROM country_services WHERE country_id=".$geofence_area_country["id"]." AND status=1";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
while ($f=pg_fetch_assoc($r)) {
|
||||||
|
$country_services[] = $f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Non-fatal, try to get city services next
|
||||||
|
$err = pg_last_error($db);
|
||||||
|
$err = $err ? $err : $q;
|
||||||
|
error_log('Options::getTransportOptions => '.$err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// $lat,$lng => geofence_area_city
|
||||||
|
$geofence_area_city = [];
|
||||||
|
$q = "SELECT * FROM (SELECT *,ST_DistanceSphere(location::geometry,ST_SetSRID(ST_MakePoint(";
|
||||||
|
$q.= $lng.",".$lat."),4326)::geometry) AS distance FROM geofence_area_city ";
|
||||||
|
$q.= " WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(";
|
||||||
|
$q.= $lng.",".$lat."),4326)::geography,radius)) AS a ORDER BY a.distance ASC LIMIT 1";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$geofence_area_city = $f;
|
||||||
|
} else {
|
||||||
|
// Non-fatal, at least we know the country
|
||||||
|
$err = pg_last_error($db);
|
||||||
|
$err = $err ? $err : $q;
|
||||||
|
error_log('Options::getTransportOptions => '.$err);
|
||||||
|
}
|
||||||
|
// geofence_area_city => city_services
|
||||||
|
$city_services = [];
|
||||||
|
if (array_key_exists("id",$geofence_area_city) && $geofence_area_city["id"]>0) {
|
||||||
|
$q = "SELECT * FROM city_services WHERE city_id=".$geofence_area_city["id"]." AND status=1";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
while ($f=pg_fetch_assoc($r)) {
|
||||||
|
$city_services[] = $f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Non-fatal, if we have country services (let upstream decide what to do)
|
||||||
|
$err = pg_last_error($db);
|
||||||
|
$err = $err ? $err : $q;
|
||||||
|
error_log('Options::getTransportOptions => '.$err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_array($country_services) && count($country_services)>0 && (!is_array($city_services) || count($city_services)<1)) {
|
||||||
|
$services = $country_services;
|
||||||
|
} else if (is_array($city_services) && count($city_services)>0 && (!is_array($country_services) || count($country_services)<1)) {
|
||||||
|
$services = $city_services;
|
||||||
|
} else {
|
||||||
|
$services = $city_services;
|
||||||
|
foreach ($country_services as $country_service) {
|
||||||
|
$exists = false;
|
||||||
|
foreach($services as $service) {
|
||||||
|
if ($service["transport_provider_id"]>0
|
||||||
|
&& $service["transport_provider_id"]==$country_service["transport_provider_id"]) {
|
||||||
|
// The service is available on city level - skip
|
||||||
|
$exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$exists) {
|
||||||
|
// Add country service
|
||||||
|
$services[] = $country_service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
$services,
|
||||||
|
[
|
||||||
|
'geofence_area_country' => $geofence_area_country,
|
||||||
|
'country_services' => $country_services,
|
||||||
|
'geofence_area_city' => $geofence_area_city,
|
||||||
|
'city_services' => $city_services
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processGooglePlace($db, $data) {
|
||||||
|
// data.address
|
||||||
|
// data.place
|
||||||
|
// data.lat
|
||||||
|
// data.lng
|
||||||
|
// data.utc_offset_minutes
|
||||||
|
// data.postal
|
||||||
|
// data.vicinity
|
||||||
|
// data.city
|
||||||
|
// data.country
|
||||||
|
$db_address = pg_escape_string(html_entity_decode($data["address"],ENT_QUOTES|ENT_HTML5,"UTF-8"));
|
||||||
|
$db_lat = floatval($data["lat"]);
|
||||||
|
$db_lng = floatval($data["lng"]);
|
||||||
|
$db_city = pg_escape_string($data["city"]);
|
||||||
|
$db_postal = pg_escape_string($data["postal"]);
|
||||||
|
$db_country = pg_escape_string($data["country"]);
|
||||||
|
|
||||||
|
// Step 1: Check address
|
||||||
|
$q = "SELECT a.*,b.timezone AS \"timeZoneId\" FROM address a LEFT JOIN address_timezone b ON (b.id=a.timezone) ";
|
||||||
|
$q .= " WHERE LOWER(a.address)=LOWER('${db_address}')";
|
||||||
|
$q .= "AND latitude<>0 AND longitude<>0 AND geocoding_date IS NOT NULL AND postal IS NOT NULL ";
|
||||||
|
$q .= "ORDER BY geocoding_date DESC LIMIT 1";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
|
||||||
|
$f["address"] = html_entity_decode ($f["address"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
foreach ($f as $key=>$val) {
|
||||||
|
$data[$key] = $val;
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
// Step 2: Get timezone
|
||||||
|
date_default_timezone_set('UTC');
|
||||||
|
$seconds = $data["utc_offset_minutes"] * 60;
|
||||||
|
$timezone = timezone_name_from_abbr('', $seconds, 1);
|
||||||
|
$q = "SELECT * FROM address_timezone WHERE LOWER(timezone)=LOWER('${timezone}')";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$data["timezone"] = $f["id"];
|
||||||
|
$data["timeZoneId"] = $f["timezone"];
|
||||||
|
} else {
|
||||||
|
$q = "INSERT INTO address_timezone (timezone) VALUES('".pg_escape_string($timezone)."') RETURNING *";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$data["timezone"] = $f["id"];
|
||||||
|
$data["timeZoneId"] = $f["timezone"];
|
||||||
|
} else { // Most likely this is very wrong...
|
||||||
|
$data["timezone"] = 1; // Singapore
|
||||||
|
$data["timeZoneId"] = 'Asia/Singapore';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step 3: Get city
|
||||||
|
$q = "SELECT id FROM geofence_area_city WHERE LOWER(city) ILIKE '" . strtolower($db_city) . "' AND country='${db_country}' LIMIT 1";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
|
||||||
|
$data["city_id"] = $f[0];
|
||||||
|
} else {
|
||||||
|
$q = "INSERT INTO geofence_area_city (city,country,latitude,longitude,location) VALUES (";
|
||||||
|
$q.= "'${db_city}','${db_country}',${db_lat},${db_lng},ST_SetSRID(ST_MakePoint(${db_lng},${db_lat}), 4326)) RETURNING id";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f = pg_fetch_row($r)) {
|
||||||
|
$data["city_id"] = $f[0];
|
||||||
|
} else {
|
||||||
|
// Most likely this is very wrong...
|
||||||
|
$data["city_id"] = 1; // Singapore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step 4: Get closest postal if missing...
|
||||||
|
$db_tz = $data["timezone"];
|
||||||
|
if (empty($db_postal)) {
|
||||||
|
$distance = 50000; // 50 km
|
||||||
|
$q = "SELECT postal,
|
||||||
|
ST_DistanceSphere(geometry::geometry, ST_SetSRID(ST_MakePoint(${db_lng},${db_lat}),4326)) AS distance
|
||||||
|
FROM geoname_postal_code
|
||||||
|
WHERE ST_DistanceSphere(geometry::geometry, ST_SetSRID(ST_MakePoint(${db_lng},${db_lat}),4326)) BETWEEN 0 AND ${distance} AND country='${db_country}'
|
||||||
|
ORDER BY distance
|
||||||
|
LIMIT 1;";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
|
||||||
|
$db_postal = $f["postal"];
|
||||||
|
$data["postal"] = $f["postal"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Step 5: Save address
|
||||||
|
$q = "INSERT INTO address (address,latitude,longitude,timezone,geocoding_date,postal,country,geometry, city_id) VALUES (";
|
||||||
|
$q.= "'${db_address}',${db_lat},${db_lng}," . ($db_tz == null ? "NULL" : $db_tz);
|
||||||
|
$q.= ",now(),'${db_postal}','${db_country}',ST_SetSRID(ST_MakePoint(${db_lng},${db_lat}), 4326),'".$data["city_id"]."')";
|
||||||
|
$q.= " RETURNING id, address, latitude as lat, longitude as lng, postal, country";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f = pg_fetch_assoc($r)) {
|
||||||
|
$data["id"] = $f["id"];
|
||||||
|
$data["address"] = $f["address"];
|
||||||
|
$data["lat"] = $f["lat"];
|
||||||
|
$data["lng"] = $f["lng"];
|
||||||
|
$data["geometry"] = $f["geometry"];
|
||||||
|
$data["postal"] = $f["postal"];
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkValidLocations($db, $origin, $destination) {
|
||||||
|
// Check for Google places result
|
||||||
|
if (is_array($origin) && array_key_exists('place',$origin) && is_array($origin['place'])) {
|
||||||
|
$origin = Options::processGooglePlace($db, $origin);
|
||||||
|
}
|
||||||
|
// Basic input sanity check: origin
|
||||||
|
if (!is_array($origin) || !array_key_exists('address',$origin)
|
||||||
|
|| !array_key_exists('lat',$origin) || !array_key_exists('lng',$origin)
|
||||||
|
|| !array_key_exists('id',$origin) || $origin['id']<1) {
|
||||||
|
throw new Exception('Invalid input origin');
|
||||||
|
}
|
||||||
|
// Check for Google places result
|
||||||
|
if (is_array($destination) && array_key_exists('place',$destination) && is_array($destination['place'])) {
|
||||||
|
$destination = Options::processGooglePlace($db, $destination);
|
||||||
|
}
|
||||||
|
// Basic input sanity check: destination
|
||||||
|
if (!is_array($destination) || !array_key_exists('address',$destination)
|
||||||
|
|| !array_key_exists('lat',$destination) || !array_key_exists('lng',$destination)
|
||||||
|
|| !array_key_exists('id',$destination) || $destination['id']<1) {
|
||||||
|
throw new Exception('Invalid input destination');
|
||||||
|
}
|
||||||
|
// Basic input sanity check: GPS coordinates
|
||||||
|
if ($origin['lat']==null || $origin['lng']==null || $destination['lat']==null || $destination['lng']==null
|
||||||
|
|| ($origin['lat']==0 && $origin['lng']==0) || ($destination['lat']==0 && $destination['lng']==0)) {
|
||||||
|
throw new Exception('Invalid origin and/or destination coordinates');
|
||||||
|
}
|
||||||
|
return [$origin, $destination];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkValidOption($db, $option) {
|
||||||
|
// Basic input sanity check: option
|
||||||
|
if (!is_array($option) || !array_key_exists('name',$option)
|
||||||
|
|| !array_key_exists('transport_provider_id',$option) || $option['transport_provider_id']<1
|
||||||
|
|| !array_key_exists('id',$option) || $option['id']<1) {
|
||||||
|
throw new Exception('Invalid transport option');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkValidTrip($db, $trip) {
|
||||||
|
// TODO!
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createTrip($db, $country, $duration, $distance, $location_start_id, $location_end_id) {
|
||||||
|
error_log("Options::createTrip(\$db, $country, $duration, $distance, $location_start_id, $location_end_id)");
|
||||||
|
$data = [
|
||||||
|
'travel_date' => Options::getDate($country),
|
||||||
|
'duration' => ((int)($duration/60)),
|
||||||
|
'cost_raw' => NULL,
|
||||||
|
'trackedemail_item_id' => NULL,
|
||||||
|
'cost' => NULL,
|
||||||
|
'distance' => sprintf("%0.02f",$distance/1000.0),
|
||||||
|
'transport_provider_id' => NULL,
|
||||||
|
'scheduled' => NULL,
|
||||||
|
'travel_date_end' => Options::getDate($country),
|
||||||
|
'dup_id' => NULL,
|
||||||
|
'location_start_id' => $location_start_id,
|
||||||
|
'location_end_id' => $location_end_id,
|
||||||
|
'private' => 't', /* this is a private entry without the source e-mail */
|
||||||
|
'booking' => 't' /* this is a booking entry */
|
||||||
|
];
|
||||||
|
list($id, $err) = Options::saveTrip($db->getConnect(), $data);
|
||||||
|
if ($id && $id>0) {
|
||||||
|
$trip = Options::getTripById($db->getConnect(), $id);
|
||||||
|
return $trip;
|
||||||
|
}
|
||||||
|
return NULL; // WTF?
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTripById($db, $id) {
|
||||||
|
$result = array();
|
||||||
|
$q = "SELECT a.*,
|
||||||
|
b.address AS location_start, b.latitude AS location_start_lat, b.longitude AS location_start_lng,
|
||||||
|
c.address AS location_end, c.latitude AS location_end_lat, c.longitude AS location_end_lng,
|
||||||
|
a.id AS parsedemail_item_id
|
||||||
|
FROM parsedemail_item a
|
||||||
|
LEFT JOIN address b ON (b.id=a.location_start_id)
|
||||||
|
LEFT JOIN address c ON (c.id=a.location_end_id)
|
||||||
|
WHERE a.id=${id}";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$f["location_start"] = html_entity_decode ($f["location_start"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$f["location_end"] = html_entity_decode ($f["location_end"],ENT_QUOTES|ENT_HTML5,"UTF-8");
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveTrip($db, $data) {
|
||||||
|
$fields = array(
|
||||||
|
'travel_date' => false,
|
||||||
|
'duration' => false,
|
||||||
|
'cost_raw' => false,
|
||||||
|
'trackedemail_item_id' => false,
|
||||||
|
'cost' => false,
|
||||||
|
'updated' => false,
|
||||||
|
'distance' => false,
|
||||||
|
'transport_provider_id' => false,
|
||||||
|
'scheduled' => false,
|
||||||
|
'travel_date_end' => false,
|
||||||
|
'dup_id' => false,
|
||||||
|
'location_start_id' => true,
|
||||||
|
'location_end_id' => true,
|
||||||
|
'private' => false,
|
||||||
|
'booking' => false
|
||||||
|
);
|
||||||
|
$field_key_list = [];
|
||||||
|
$field_val_list = [];
|
||||||
|
foreach ($fields as $key=>$required) {
|
||||||
|
if ($required && !isset($data[$key])) {
|
||||||
|
return [NULL, "Missing required field '${key}'"];
|
||||||
|
}
|
||||||
|
if (!isset($data[$key])) continue;
|
||||||
|
$field_key_list[] = "${key}";
|
||||||
|
$field_val_list[] = (($data[$key]==NULL || $data[$key]=="")?"NULL":"'".pg_escape_string($data[$key])."'");
|
||||||
|
}
|
||||||
|
$q = "INSERT INTO parsedemail_item (".implode(",",$field_key_list).")
|
||||||
|
VALUES(".implode(",",$field_val_list).") RETURNING id";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
$f = pg_fetch_row($r);
|
||||||
|
return [$f[0], NULL];
|
||||||
|
}
|
||||||
|
return [NULL, pg_last_error($db)];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function validateTrip($db, $trip) {
|
||||||
|
if (!is_array($trip) || !array_key_exists("id",$trip) || $trip["id"]<1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!array_key_exists("options",$trip) || !is_array($trip["options"]) || !array_key_exists("legs",$trip["options"])
|
||||||
|
|| !is_array($trip["options"]["legs"]) || count($trip["options"]["legs"])<1
|
||||||
|
|| !array_key_exists("id",$trip["options"]["legs"][0]) || $trip["options"]["legs"][0]["id"]<1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveTripAdvice($db, $trip) {
|
||||||
|
error_log('Options::saveTripAdvice($db, $trip)');
|
||||||
|
if (!is_array($trip) || !array_key_exists("id",$trip) || $trip["id"]<1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
$q = "INSERT INTO parsedemail_item_advice_google (parsedemail_item_id,routes,source) VALUES (".$trip["id"].",1,'".$trip["source"]."') RETURNING id";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
|
||||||
|
return $f[0];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveTripAdviceLeg($db, $trip, $leg) {
|
||||||
|
error_log('Options::saveTripAdviceLeg($db, $trip, $leg)');
|
||||||
|
$fare_raw = "NULL";
|
||||||
|
if (array_key_exists("fare_raw",$leg) && $leg["fare_raw"]>0) {
|
||||||
|
$fare_raw = (int)$leg["fare_raw"];
|
||||||
|
}
|
||||||
|
$q = "INSERT INTO google_directions_legs (parsedemail_item_advice_google_id,arrival_time,arrival_time_zone,";
|
||||||
|
$q.= "departure_time,departure_time_zone,distance,duration,steps,fare_raw,polyline) VALUES(";
|
||||||
|
$q.= $leg["parsedemail_item_advice_google_id"].",'".pg_escape_string($leg["arrival_time"])."',".((int)$leg["arrival_time_zone"]);
|
||||||
|
$q.= ",'".pg_escape_string($leg["departure_time"])."',".((int)$leg["departure_time_zone"]).",";
|
||||||
|
$q.= ((int)$leg["distance"]).",".((int)$leg["duration"]).",1,${fare_raw},'".pg_escape_string($leg["polyline"])."') RETURNING id";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
error_log($q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
|
||||||
|
return $f[0];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveTripAdviceLegStep($db, $trip, $leg, $step) {
|
||||||
|
error_log('Options::saveTripAdviceLegStep($db, $trip, $leg, $step)');
|
||||||
|
$q = "INSERT INTO google_directions_leg_steps (google_directions_leg_id,distance,duration,travel_mode,";
|
||||||
|
$q.= "location_start_lat,location_start_lng,location_end_lat,location_end_lng,html_instructions,polyline) VALUES (";
|
||||||
|
$q.= $leg["id"].",".((int)$step["distance"]).",".((int)$step["duration"]).",";
|
||||||
|
$q.= "'".pg_escape_string($step["travel_mode"])."',".$step["location_start_lat"].",".$step["location_start_lng"].",";
|
||||||
|
$q.= $step["location_end_lat"].",".$step["location_end_lng"].",'".pg_escape_string($step["html_instructions"])."',";
|
||||||
|
$q.= "'".pg_escape_string($step["polyline"])."') RETURNING id";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
error_log($q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
|
||||||
|
return $f[0];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function saveTripAdviceLegStepQuote($db, $trip, $leg, $step) {
|
||||||
|
$fare_raw = NULL;
|
||||||
|
if (array_key_exists("fare_raw",$step) && $step["fare_raw"]>0) {
|
||||||
|
$fare_raw = (int)$step["fare_raw"];
|
||||||
|
}
|
||||||
|
if ($fare_raw>0) {
|
||||||
|
$q = "INSERT INTO leg_step_quote (google_directions_leg_step_id,name,service,board,alight,";
|
||||||
|
$q.= "distance,fare,fare_raw,distance_raw) VALUES (".$step["id"].",";
|
||||||
|
$q.= "'".pg_escape_string($trip["source"])."','".pg_escape_string($trip["source"])."',";
|
||||||
|
$q.= "'".pg_escape_string($trip["location_start"])."','".pg_escape_string($trip["location_end"])."',";
|
||||||
|
$q.= "'".sprintf("%0.02f",$step["distance"]/1000.0)."','".sprintf("%0.02f",$fare_raw/100.0)."',";
|
||||||
|
$q.= ((int)$fare_raw).",".((int)$step["distance"]).") RETURNING id";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
|
||||||
|
return $f[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDate($country) {
|
||||||
|
$tz = 'Asia/Singapore';
|
||||||
|
if ($country=='US') {
|
||||||
|
$tz = 'America/Los_Angeles';
|
||||||
|
}
|
||||||
|
$timestamp = time();
|
||||||
|
$dt = new DateTime("now", new DateTimeZone($tz)); //first argument "must" be a string
|
||||||
|
$dt->setTimestamp($timestamp); //adjust the object to correct timestamp
|
||||||
|
return $dt->format('Y-m-d, H:i:s');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getTimezoneById($db, $id, $def='Asia/Singapore') {
|
||||||
|
$q = "SELECT timezone FROM address_timezone WHERE id=".((int)$id);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
return $f['timezone'];
|
||||||
|
}
|
||||||
|
return $def; //$id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class OptionsApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'options';
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$message = "Unexpected options error";
|
||||||
|
|
||||||
|
$latitude = $this->requestParams["latitude"] ?? 0;
|
||||||
|
$longitude = $this->requestParams["longitude"] ?? 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if ($latitude==null || $longitude==null || ($latitude==0 || $longitude==0)) {
|
||||||
|
throw new Exception('Invalid location: '.$latitude.",".$longitude);
|
||||||
|
}
|
||||||
|
$db = new Db();
|
||||||
|
|
||||||
|
list ($res, $details) = Options::getServicesByLatitudeLongitude($db->getConnect(), $latitude, $longitude);
|
||||||
|
if (is_array($res)) {
|
||||||
|
return $this->response([
|
||||||
|
'services' => $res,
|
||||||
|
'details' => $details
|
||||||
|
], 200);
|
||||||
|
} else {
|
||||||
|
throw new Exception("Failed to get transport options for origin");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get single record (by id)
|
||||||
|
* http://DOMAIN/remove/1
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
//id must be the first parameter after /remove/x
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error'=> 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$message = "Unexpected options error";
|
||||||
|
|
||||||
|
$origin = $this->requestParams["origin"] ?? [];
|
||||||
|
$destination = $this->requestParams["destination"] ?? [];
|
||||||
|
$create = $this->requestParams["create"] ?? false;
|
||||||
|
$country = $this->requestParams["country"] ?? NULL;
|
||||||
|
$duration = $this->requestParams["duration"] ?? 0;
|
||||||
|
$distance = $this->requestParams["distance"] ?? 0;
|
||||||
|
$member_id = $this->requestParams["member_id"] ?? 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = new Db();
|
||||||
|
|
||||||
|
list ($origin, $destination) = Options::checkValidLocations($db->getConnect(), $origin, $destination);
|
||||||
|
|
||||||
|
list ($res, $details) = Options::getTransportOptions($db->getConnect(), $origin, $destination);
|
||||||
|
if (is_array($res)) {
|
||||||
|
$trip = NULL;
|
||||||
|
if ($create) {
|
||||||
|
$country = $origin["country"];
|
||||||
|
$trip = Options::createTrip($db, $country, $duration, $distance, $origin["id"], $destination["id"]);
|
||||||
|
}
|
||||||
|
return $this->response([
|
||||||
|
'services' => $res,
|
||||||
|
'details' => $details,
|
||||||
|
'trip' => $trip
|
||||||
|
], 200);
|
||||||
|
} else {
|
||||||
|
throw new Exception("Failed to get transport options for origin");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error"
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,643 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Quote {
|
||||||
|
|
||||||
|
const QUOTE_CHECK_RETRIES = 10;
|
||||||
|
const QUOTE_CHECK_TIMEOUT = 3;
|
||||||
|
|
||||||
|
public static function getTransportQuote($db, $origin, $destination, $option, $trip, $route) {
|
||||||
|
$quote = [];
|
||||||
|
switch ($option["transport_provider_id"]) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 8:
|
||||||
|
list($option, $trip, $quote) = Quote::rideshareQuote($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 11: // BART
|
||||||
|
list($option, $trip, $quote) = Quote::bartQuote($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 12: // Muni
|
||||||
|
list($option, $trip, $quote) = Quote::muniQuote($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 13: // LTA
|
||||||
|
list($option, $trip, $quote) = Quote::ltaQuote($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 14: // MARTA
|
||||||
|
list($option, $trip, $quote) = Quote::martaQuote($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return [$option, $trip, $quote];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function rideshareQuote($db, $origin, $destination, $option, $trip) {
|
||||||
|
$res = [];
|
||||||
|
|
||||||
|
$input = [
|
||||||
|
"origin" => $origin,
|
||||||
|
"destination" => $destination,
|
||||||
|
"member_id" => $option["member_id"],
|
||||||
|
"country" => $origin["country"],
|
||||||
|
"transport_provider_id" => $option["transport_provider_id"],
|
||||||
|
"group_quote_id" => 0,
|
||||||
|
"trackedemail_item_id" => 0,
|
||||||
|
"prefill" => 'f'
|
||||||
|
];
|
||||||
|
|
||||||
|
list($res,$body) = Quote::postServiceCall("/trips/api/quote", json_encode($input));
|
||||||
|
$log = [
|
||||||
|
'message' => 'BookingQuote::rideshareQuote',
|
||||||
|
'function' =>'Quote::postServiceCall()',
|
||||||
|
'data' =>$input,
|
||||||
|
'response' => $res
|
||||||
|
];
|
||||||
|
Logger::debug($log);
|
||||||
|
if (!is_array($res) || !array_key_exists("id",$res) || $res["id"]<1) {
|
||||||
|
if (!is_array($res)) {
|
||||||
|
error_log($res);
|
||||||
|
}
|
||||||
|
error_log($body);
|
||||||
|
throw new Exception("Failed to schedule quote");
|
||||||
|
}
|
||||||
|
if (array_key_exists("complete",$res) && $res["complete"]!=NULL && $res["complete"]!="") {
|
||||||
|
if (array_key_exists("cost",$res) && $res["cost"]>0) {
|
||||||
|
$trip = Quote::patchRideshareTrip($trip, $res["cost"]);
|
||||||
|
return [$option, $trip, $res];
|
||||||
|
} else {
|
||||||
|
throw new Exception("Failed to get the quote");
|
||||||
|
// $res["message"] ?
|
||||||
|
// return [$option, $trip, $res]; // Do we want to recover?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Will try for 30 seconds?
|
||||||
|
$endpoint = "/trips/api/quote/".$res["id"];
|
||||||
|
$i = 0;
|
||||||
|
while ($i<Quote::QUOTE_CHECK_RETRIES) {
|
||||||
|
sleep(Quote::QUOTE_CHECK_TIMEOUT);
|
||||||
|
list($res,$body) = Quote::getServiceCall($endpoint);
|
||||||
|
$log = [
|
||||||
|
'message' => 'BookingQuote::rideshareQuote',
|
||||||
|
'function' =>'Quote::getServiceCall()',
|
||||||
|
'data' =>$endpoint,
|
||||||
|
'response' => $res
|
||||||
|
];
|
||||||
|
Logger::debug($log);
|
||||||
|
if (!is_array($res) || !array_key_exists("id",$res) || $res["id"]<1) {
|
||||||
|
continue; // Try again...
|
||||||
|
}
|
||||||
|
if (array_key_exists("complete",$res) && $res["complete"]!=NULL && $res["complete"]!="") {
|
||||||
|
break; // No mater the result, maybe client will want to recover
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
if (!is_array($res) || !array_key_exists("cost",$res) || !isset($res["cost"]) || $res["cost"] == 0) {
|
||||||
|
$avgPriceInfo = Quote::averagePrice($db, $origin, $destination, $option["transport_provider_id"]);
|
||||||
|
if (isset($avgPriceInfo) && array_key_exists('cost', $avgPriceInfo)) {
|
||||||
|
$res["cost"] = $avgPriceInfo['cost'];
|
||||||
|
$res["is_average_cost"] = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
$trip = Quote::patchRideshareTrip($trip, $res["cost"]);
|
||||||
|
Quote::updateRideshareCosts($db, $trip);
|
||||||
|
return [$option, $trip, $res]; // last check quote result
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function patchRideshareTrip($trip, $cost) {
|
||||||
|
// Do we save the quote?
|
||||||
|
$fare_raw = ((int)(100.0*$cost));
|
||||||
|
if (array_key_exists("options",$trip)) {
|
||||||
|
$gid = $trip["options"]["gid"];
|
||||||
|
$trip["options"]["legs"][0]["fare_raw"] = $fare_raw;
|
||||||
|
$trip["options"]["leg_fare"][$gid] = $fare_raw;
|
||||||
|
$trip["options"]["leg_steps"][$gid][0]["fare_raw"] = $fare_raw;
|
||||||
|
} else {
|
||||||
|
$trip["options"] = [
|
||||||
|
"gid" => "1",
|
||||||
|
"routes" => 1,
|
||||||
|
"legs" => [
|
||||||
|
[
|
||||||
|
"id" => 1,
|
||||||
|
"fare_raw" => $fare_raw
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"leg_steps" => [
|
||||||
|
1 => [
|
||||||
|
"fare_raw" => $fare_raw
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"leg_fare" => [
|
||||||
|
1 => $fare_raw
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $trip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateRideshareCosts($db, $trip) {
|
||||||
|
if (array_key_exists("options",$trip)) {
|
||||||
|
$gid = $trip["options"]["legs"][0]["id"];
|
||||||
|
if ($gid>1 && $trip["options"]["legs"][0]["fare_raw"]>0) {
|
||||||
|
$q = "UPDATE google_directions_legs SET fare_raw=".((int)$trip["options"]["legs"][0]["fare_raw"]);
|
||||||
|
$q.= " WHERE id=".((int)$gid);
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
Options::saveTripAdviceLegStepQuote(
|
||||||
|
$db, $trip, $trip["options"]["legs"][0], $trip["options"]["leg_steps"][$gid][0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"id": "224583",
|
||||||
|
"transport_provider_id": "4",
|
||||||
|
"automation_id": "206441",
|
||||||
|
"cost_raw": null,
|
||||||
|
"cost": null,
|
||||||
|
"created": "2020-01-09 13:09:01.072305",
|
||||||
|
"completed": null,
|
||||||
|
"member_id": "13",
|
||||||
|
"location_start_id": "4426",
|
||||||
|
"location_end_id": "4386",
|
||||||
|
"quote_group_id": "0",
|
||||||
|
"prefill": "f",
|
||||||
|
"location_start": "97 Meyer Rd, 93, Singapore 437918",
|
||||||
|
"location_start_lat": "1.2970849",
|
||||||
|
"location_start_lng": "103.8925712",
|
||||||
|
"location_start_tz": "1",
|
||||||
|
"location_geocoding_date": "2019-10-11",
|
||||||
|
"location_end": "1 Fusionopolis Way, #01-07 & #02-14, Connexis, Singapore 138632",
|
||||||
|
"location_end_lat": "1.2987049",
|
||||||
|
"location_end_lng": "103.7875699",
|
||||||
|
"deeplink": "ComfortDelGroTaxi:\/\/\/?action=setBooking&endingLat=1.298705&endingLong=103.787570&startingLat=1.297085&startingLong=103.892571"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"id": 224583,
|
||||||
|
"location_start": "97 Meyer Rd, 93, Singapore 437918",
|
||||||
|
"location_end": "1 Fusionopolis Way, #01-07 & #02-14, Connexis, Singapore 138632",
|
||||||
|
"cost_raw": "14.6",
|
||||||
|
"trackedemail_item_id": 0,
|
||||||
|
"cost": "14.60",
|
||||||
|
"transport_provider_id": 4,
|
||||||
|
"location_start_lat": "1.2970576",
|
||||||
|
"location_start_lng": "103.8925856",
|
||||||
|
"location_end_lat": "1.2987049",
|
||||||
|
"location_end_lng": "103.7875699",
|
||||||
|
"request_date": "2020-01-09T13:09:00.955Z",
|
||||||
|
"started": "2020-01-09T13:09:04.203Z",
|
||||||
|
"complete": "2020-01-09T13:09:04.743Z",
|
||||||
|
"status": 0,
|
||||||
|
"message": "android_automation_job_detail",
|
||||||
|
"attempts": 0,
|
||||||
|
"automation_id": 206441,
|
||||||
|
"completed": "2020-01-09T13:09:04.743Z",
|
||||||
|
"created": "2020-01-09 13:09:01.072305",
|
||||||
|
"location_start_id": "4426",
|
||||||
|
"location_end_id": "4386",
|
||||||
|
"member_id": "13",
|
||||||
|
"deeplink": "ComfortDelGroTaxi:\/\/\/?action=setBooking&endingLat=1.298705&endingLong=103.787570&startingLat=1.297085&startingLong=103.892571"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static function bartQuote($db, $origin, $destination, $option, $trip) {
|
||||||
|
$quote = [];
|
||||||
|
|
||||||
|
$quote["cost_raw"] = NULL;
|
||||||
|
$quote["transport_provider_id"] = $option["transport_provider_id"];
|
||||||
|
$quote["deeplink"] = NULL;
|
||||||
|
//$quote["leg_fare"] = $trip["options"]["leg_fare"];
|
||||||
|
|
||||||
|
$leg = [
|
||||||
|
"fare_raw" => 1
|
||||||
|
];
|
||||||
|
// Select leg
|
||||||
|
//error_log(">>>>>>>>> ".json_encode($trip));
|
||||||
|
foreach ($trip["options"]["legs"] as $leg) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$quote["cost"] = sprintf("%0.02f",$leg["fare_raw"]/100.0);
|
||||||
|
|
||||||
|
return [$option, $trip, $quote];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function muniQuote($db, $origin, $destination, $option, $trip) {
|
||||||
|
$quote = [];
|
||||||
|
|
||||||
|
$quote["cost_raw"] = NULL;
|
||||||
|
$quote["transport_provider_id"] = $option["transport_provider_id"];
|
||||||
|
$quote["deeplink"] = NULL;
|
||||||
|
//$quote["leg_fare"] = $trip["options"]["leg_fare"];
|
||||||
|
|
||||||
|
$leg = [
|
||||||
|
"fare_raw" => 1
|
||||||
|
];
|
||||||
|
// Select leg
|
||||||
|
//error_log(">>>>>>>>> ".json_encode($trip));
|
||||||
|
foreach ($trip["options"]["legs"] as $leg) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$quote["cost"] = sprintf("%0.02f",$leg["fare_raw"]/100.0);
|
||||||
|
|
||||||
|
return [$option, $trip, $quote];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function ltaQuote($db, $origin, $destination, $option, $trip) {
|
||||||
|
$quote = [];
|
||||||
|
|
||||||
|
$cost = 0;
|
||||||
|
|
||||||
|
$quote["cost_raw"] = NULL;
|
||||||
|
$quote["transport_provider_id"] = $option["transport_provider_id"];
|
||||||
|
$quote["deeplink"] = NULL;
|
||||||
|
|
||||||
|
$legs = $trip["options"]["legs"];
|
||||||
|
$leg_steps = $trip["options"]["leg_steps"];
|
||||||
|
$leg_fare = $trip["options"]["leg_fare"];
|
||||||
|
|
||||||
|
foreach ($legs as $i=>$leg) {
|
||||||
|
$leg_id = $leg["id"];
|
||||||
|
if (array_key_exists($leg_id,$leg_fare) && $leg_fare[$leg_id]>0) {
|
||||||
|
if ($cost==0) $cost = $leg["fare_raw"];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (array_key_exists("fare_raw",$leg) && $leg["fare_raw"]>0) {
|
||||||
|
if ($cost==0) $cost = $leg["fare_raw"];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
list ($leg, $leg_steps) = Quote::legStepsQuote($db, $origin, $destination, $option, $trip, $leg, $leg_steps);
|
||||||
|
$leg_fare[$leg_id] = $leg["fare_raw"];
|
||||||
|
if ($cost==0 && $leg["fare_raw"]>0) $cost = $leg["fare_raw"];
|
||||||
|
$legs[$i] = $leg;
|
||||||
|
}
|
||||||
|
$trip["options"]["legs"] = $legs;
|
||||||
|
$trip["options"]["leg_steps"] = $leg_steps;
|
||||||
|
$trip["options"]["leg_fare"] = $leg_fare;
|
||||||
|
|
||||||
|
$quote["cost"] = $cost;
|
||||||
|
//$quote["leg_fare"] = $leg_fare;
|
||||||
|
|
||||||
|
// Update model to save the quote
|
||||||
|
Quote::updateQuotes($db, $trip);
|
||||||
|
|
||||||
|
return [$option, $trip, $quote];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function martaQuote($db, $origin, $destination, $option, $trip) {
|
||||||
|
$quote = [];
|
||||||
|
|
||||||
|
$quote["cost_raw"] = NULL;
|
||||||
|
$quote["transport_provider_id"] = $option["transport_provider_id"];
|
||||||
|
$quote["deeplink"] = NULL;
|
||||||
|
//$quote["leg_fare"] = $trip["options"]["leg_fare"];
|
||||||
|
|
||||||
|
$leg = [
|
||||||
|
"fare_raw" => 1
|
||||||
|
];
|
||||||
|
// Select leg
|
||||||
|
//error_log(">>>>>>>>> ".json_encode($trip));
|
||||||
|
foreach ($trip["options"]["legs"] as $leg) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$quote["cost"] = sprintf("%0.02f",$leg["fare_raw"]/100.0);
|
||||||
|
|
||||||
|
return [$option, $trip, $quote];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateQuotes($db, $trip) {
|
||||||
|
$legs = $trip["options"]["legs"];
|
||||||
|
$leg_steps = $trip["options"]["leg_steps"];
|
||||||
|
$leg_fare = $trip["options"]["leg_fare"];
|
||||||
|
foreach ($legs as $leg) {
|
||||||
|
$leg_id = $leg["id"];
|
||||||
|
$steps = $leg_steps[$leg_id];
|
||||||
|
foreach ($steps as $step) {
|
||||||
|
if (array_key_exists("fare_raw",$step) && $step["fare_raw"]>0) {
|
||||||
|
$q = "SELECT id FROM leg_step_quote WHERE google_directions_leg_step_id=".$step["id"];
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_row($r)) {
|
||||||
|
$q = "UPDATE leg_step_quote SET fare_raw=".((int)$step["fare_raw"])." WHERE id=".$f[0];
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
} else {
|
||||||
|
$q = "INSERT INTO leg_step_quote (google_directions_leg_step_id,name,service,board,alight,distance,fare,fare_raw,distance_raw) VALUES(";
|
||||||
|
$q.= $step["id"].",'".pg_escape_string($step["short_line"])."','".pg_escape_string($step["line"])."',";
|
||||||
|
$q.= "'".pg_escape_string($step["departure_stop"])."','".pg_escape_string($step["arrival_stop"])."',";
|
||||||
|
$q.= "'".sprintf("%0.02f",$step["distance"]/100.0)."','".sprintf("%0.02f",$step["fare_raw"]/100.0)."',";
|
||||||
|
$q.= ((int)$step["fare_raw"]).",".((int)$step["distance"]).")";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists("fare_raw",$leg) && $leg["fare_raw"]>0) {
|
||||||
|
$q = "UPDATE google_directions_legs SET fare_raw=".((int)$leg["fare_raw"])." WHERE id=${leg_id}";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (array_key_exists($leg_id,$leg_fare) && $leg_fare[$leg_id]>0) {
|
||||||
|
$q = "UPDATE google_directions_legs SET fare_raw=".((int)$leg["fare_raw"])." WHERE id=${leg_id}";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function legStepsQuote($db, $origin, $destination, $option, $trip, $leg, $leg_steps) {
|
||||||
|
$leg_id = $leg["id"];
|
||||||
|
$steps = $leg_steps[$leg_id];
|
||||||
|
|
||||||
|
$fare_raw = 0;
|
||||||
|
foreach ($steps as $i=>$step) {
|
||||||
|
if (array_key_exists("fare_raw",$step) && $step["fare_raw"]>0) {
|
||||||
|
$fare_raw += $step["fare_raw"];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$step = Quote::stepQuote($db, $origin, $destination, $option, $trip, $step);
|
||||||
|
if (array_key_exists("fare_raw",$step) && $step["fare_raw"]>0) {
|
||||||
|
$fare_raw += $step["fare_raw"];
|
||||||
|
}
|
||||||
|
$steps[$i] = $step;
|
||||||
|
}
|
||||||
|
$leg["fare_raw"] = $fare_raw;
|
||||||
|
$leg_steps[$leg_id] = $steps;
|
||||||
|
return [$leg, $leg_steps];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stepQuote($db, $origin, $destination, $option, $trip, $step) {
|
||||||
|
switch ($step["travel_mode"]) {
|
||||||
|
case "": break;
|
||||||
|
case "BIKE":
|
||||||
|
$bike_time = $step['duration'];
|
||||||
|
$country = $origin['country'];
|
||||||
|
list($price,$err) = SGBikeApi::quote($db, $bike_time, $country,$step);
|
||||||
|
if (!empty($price) && $price>0) {
|
||||||
|
$step["fare_raw"] = $price;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "WALKING": break;
|
||||||
|
case "NUS_TRANSIT":
|
||||||
|
// NUS Internal Shuttle Buses are free of charge
|
||||||
|
// http://www.nus.edu.sg/celc/symposium/Symposium%20Documents/Symposium%202016%20Visitors'%20Guide.pdf
|
||||||
|
break;
|
||||||
|
case "PARK": break;
|
||||||
|
case "SCOOTER":
|
||||||
|
// No scooter quotes right now
|
||||||
|
// list($res,$err) = ScooterApi::quote($db, $scooter_time, $country);
|
||||||
|
break;
|
||||||
|
case "TAXI":
|
||||||
|
// We do not know how to quote "TAXI" in another countries
|
||||||
|
if ($origin["country"]=="SG") {
|
||||||
|
// Reverse geocode the "TAXI" step
|
||||||
|
$input = [
|
||||||
|
"latitude" => $step["location_start_lat"],
|
||||||
|
"longitude" => $step["location_start_lng"],
|
||||||
|
"country" => $origin["country"]
|
||||||
|
];
|
||||||
|
list($originTaxi, $body) = Quote::putServiceCall("/trips/api/geocode",$input);
|
||||||
|
$input = [
|
||||||
|
"latitude" => $step["location_end_lat"],
|
||||||
|
"longitude" => $step["location_end_lng"],
|
||||||
|
"country" => $destination["country"]
|
||||||
|
];
|
||||||
|
list($destinationTaxi, $body) = Quote::putServiceCall("/trips/api/geocode",$input);
|
||||||
|
if (!is_array($originTaxi) || !array_key_exists("address",$originTaxi)
|
||||||
|
|| !is_array($destinationTaxi) || !array_key_exists("address",$destinationTaxi)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$option["transport_provider_id"] = 4; // ComfortDelGro
|
||||||
|
list($optionTaxi, $tripTaxi, $quoteTaxi) =
|
||||||
|
Quote::rideshareQuote($db, $originTaxi, $destinationTaxi, $option, $trip);
|
||||||
|
if (is_array($quoteTaxi) && array_key_exists("cost",$quoteTaxi) && $quoteTaxi["cost"]>0) {
|
||||||
|
$step["fare_raw"] = (int)(100.0*$quoteTaxi["cost"]); // fare_raw is in cents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "TRANSIT":
|
||||||
|
// We do not know how to quote "TRANSIT" in another countries from here (must be specific)
|
||||||
|
if ($origin["country"]=="SG") {
|
||||||
|
$step_id = $step["id"];
|
||||||
|
$result = Quote::mytansportsgServiceStepQuote($step_id);
|
||||||
|
error_log('***********************************************************************');
|
||||||
|
error_log(json_encode($result));
|
||||||
|
error_log('***********************************************************************');
|
||||||
|
// {"code":0,"data":{"307575":{"total":92}}}
|
||||||
|
if (is_array($result) && array_key_exists("code",$result) && $result["code"]===0 && array_key_exists("data",$result)) {
|
||||||
|
$data = $result["data"];
|
||||||
|
if (is_array($data) && array_key_exists($step_id,$data) && is_array($data[$step_id]) && array_key_exists('total',$data[$step_id]) && $data[$step_id]['total']>0) {
|
||||||
|
// Conversion ???
|
||||||
|
$step["fare_raw"] = (int)$data[$step_id]['total']; // fare_raw is in cents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return $step;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
BIKE | 4743
|
||||||
|
NUS_TRANSIT | 367
|
||||||
|
PARK | 1796
|
||||||
|
SCOOTER | 1023
|
||||||
|
TAXI | 2060
|
||||||
|
TRANSIT | 88781
|
||||||
|
WALKING | 154766
|
||||||
|
| 3
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static function postServiceCall($endpoint, $payload) {
|
||||||
|
global $savvyext;
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
|
||||||
|
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
|
||||||
|
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
|
||||||
|
$api_url = $savvyext->cfgReadChar('system.api_url');
|
||||||
|
|
||||||
|
$encrypted_payload = bin2hex(
|
||||||
|
openssl_encrypt(
|
||||||
|
$payload, $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV
|
||||||
|
));
|
||||||
|
|
||||||
|
$postdata = "{\"encrypted_payload\": \"${encrypted_payload}\"}";
|
||||||
|
|
||||||
|
$url = $api_url . $endpoint;
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, false);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Authorization: Server-Token ' . $httpAuthToken)
|
||||||
|
);
|
||||||
|
|
||||||
|
$body = curl_exec($ch);
|
||||||
|
$result = json_decode($body, true);
|
||||||
|
|
||||||
|
$payload = openssl_decrypt(
|
||||||
|
hex2bin(
|
||||||
|
$result['payload']
|
||||||
|
), $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV
|
||||||
|
);
|
||||||
|
$payload = json_decode($payload, true);
|
||||||
|
return [$payload, $body];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function putServiceCall($endpoint, $payload) {
|
||||||
|
global $savvyext;
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
|
||||||
|
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
|
||||||
|
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
|
||||||
|
$api_url = $savvyext->cfgReadChar('system.api_url');
|
||||||
|
|
||||||
|
/* $encrypted_payload = bin2hex(
|
||||||
|
openssl_encrypt(
|
||||||
|
$payload, $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV
|
||||||
|
));
|
||||||
|
$postdata = "{\"encrypted_payload\": \"${encrypted_payload}\"}"; */
|
||||||
|
$postdata = http_build_query($payload);
|
||||||
|
|
||||||
|
$url = $api_url . $endpoint;
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, false);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||||
|
'Content-Type: application/x-www-form-urlencoded',
|
||||||
|
'Authorization: Server-Token ' . $httpAuthToken)
|
||||||
|
);
|
||||||
|
|
||||||
|
$body = curl_exec($ch);
|
||||||
|
$result = json_decode($body, true);
|
||||||
|
|
||||||
|
$payload = openssl_decrypt(
|
||||||
|
hex2bin(
|
||||||
|
$result['payload']
|
||||||
|
), $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV
|
||||||
|
);
|
||||||
|
$payload = json_decode($payload, true);
|
||||||
|
return [$payload, $body];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getServiceCall($endpoint, $shouldDecrypt = true) {
|
||||||
|
global $savvyext;
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
|
||||||
|
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
|
||||||
|
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
|
||||||
|
$api_url = $savvyext->cfgReadChar('system.api_url');
|
||||||
|
|
||||||
|
$url = $api_url . $endpoint;
|
||||||
|
|
||||||
|
$ch = curl_init($url);
|
||||||
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||||
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_VERBOSE, false);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
|
||||||
|
'Content-Type: application/json',
|
||||||
|
'Authorization: Server-Token ' . $httpAuthToken)
|
||||||
|
);
|
||||||
|
|
||||||
|
$body = curl_exec($ch);
|
||||||
|
if ($shouldDecrypt) {
|
||||||
|
$result = json_decode($body,true);
|
||||||
|
$payload = openssl_decrypt(
|
||||||
|
hex2bin(
|
||||||
|
$result['payload']
|
||||||
|
),
|
||||||
|
$encryptionAlg,
|
||||||
|
$encryptionKey,
|
||||||
|
OPENSSL_RAW_DATA,
|
||||||
|
$encryptionIV
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$payload = $body;
|
||||||
|
}
|
||||||
|
$payload = json_decode($payload, true);
|
||||||
|
return [$payload, $body];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function mytansportsgServiceStepQuote($id) {
|
||||||
|
global $savvyext;
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
|
||||||
|
$url = $oauth2_url."mytransportsg/?step_id=" . $id;
|
||||||
|
$opts = array(
|
||||||
|
'http' => array(
|
||||||
|
'method' => "GET",
|
||||||
|
'timeout' => 60, /* 1 minute */
|
||||||
|
'header' =>
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n" .
|
||||||
|
"Accept: application/json\r\n" .
|
||||||
|
"Authorization: Server-Token ${httpAuthToken}\r\n",
|
||||||
|
),
|
||||||
|
"ssl" => array(
|
||||||
|
"verify_peer"=>false,
|
||||||
|
"verify_peer_name"=>false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$context = stream_context_create($opts);
|
||||||
|
$body = file_get_contents($url, false, $context);
|
||||||
|
$advice = json_decode($body,true);
|
||||||
|
return $advice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function averagePrice($db, $origin, $destination, $providerId) {
|
||||||
|
|
||||||
|
if (!array_key_exists('id', $origin) || !isset($origin['id'])
|
||||||
|
|| !array_key_exists('country', $origin) || !isset($origin['country'])
|
||||||
|
|| !array_key_exists('timeZoneId', $origin) || !isset($origin['timeZoneId'])
|
||||||
|
|| !array_key_exists('id', $destination) || !isset($destination['id']) ) {
|
||||||
|
throw new Exception('Quote::averagePrices. Invalid input origin or destination');
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = ['cost'=>0];
|
||||||
|
$timeZoneId = $origin['timeZoneId'];
|
||||||
|
$country = $origin['country'];
|
||||||
|
$originId = $origin['id'];
|
||||||
|
$destinationId = $destination['id'];
|
||||||
|
|
||||||
|
$endpoint = "/geofencearea/api/addresstoarea/?country=${country}&address_id=";
|
||||||
|
list($res,$body) = Quote::getServiceCall($endpoint.$originId, false);
|
||||||
|
if(count($res) == 0 || array_key_exists('error', $res) && isset($res['error'])) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
$originAreaId = $res['areas'][0]['id'];
|
||||||
|
list($res,$body) = Quote::getServiceCall($endpoint.$destinationId, false);
|
||||||
|
if(count($res) == 0 || array_key_exists('error', $res) && isset($res['error'])) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
$destinationAreaId = $res['areas'][0]['id'];
|
||||||
|
|
||||||
|
$dt = new DateTime('now', new DateTimeZone($timeZoneId));
|
||||||
|
$currentHour = $dt->format('G');
|
||||||
|
|
||||||
|
$q = "SELECT average_cost, hour, last_quotes_id, last_updated FROM geofence_area_average_quotes
|
||||||
|
WHERE transport_provider_id=${providerId}
|
||||||
|
AND area_start_id=${originAreaId}
|
||||||
|
AND area_end_id=${destinationAreaId}
|
||||||
|
AND hour=${currentHour}
|
||||||
|
";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$result['cost'] = $f['average_cost'];
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class QuoteApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'quote';
|
||||||
|
|
||||||
|
protected $hasPrice = true;
|
||||||
|
|
||||||
|
public function __construct($requestUri, $encryption=true) {
|
||||||
|
$this->cacheWhitelist = [
|
||||||
|
"createAction" => ['ttl' => 300] // 300 sec. = 5 min.
|
||||||
|
];
|
||||||
|
parent::__construct($requestUri, $encryption);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error' => 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get single record (by id)
|
||||||
|
* http://DOMAIN/remove/1
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
//id must be the first parameter after /remove/x
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error'=> 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$message = "Unexpected options error";
|
||||||
|
|
||||||
|
$origin = $this->requestParams["origin"] ?? [];
|
||||||
|
$destination = $this->requestParams["destination"] ?? [];
|
||||||
|
$option = $this->requestParams["option"] ?? [];
|
||||||
|
$trip = $this->requestParams["trip"] ?? [];
|
||||||
|
$route = $this->requestParams["route"] ?? [];
|
||||||
|
$member_id = $this->requestParams["member_id"] ?? 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = new Db();
|
||||||
|
|
||||||
|
list ($origin, $destination) = Options::checkValidLocations($db->getConnect(), $origin, $destination);
|
||||||
|
Options::checkValidOption($db->getConnect(), $option);
|
||||||
|
Options::checkValidTrip($db->getConnect(), $trip);
|
||||||
|
Route::checkValidRoute($db->getConnect(), $route);
|
||||||
|
|
||||||
|
$option["member_id"] = $member_id;
|
||||||
|
$trip["member_id"] = $member_id;
|
||||||
|
list ($option, $trip, $quote) = Quote::getTransportQuote($db->getConnect(), $origin, $destination, $option, $trip, $route);
|
||||||
|
if (is_array($quote)) {
|
||||||
|
$this->hasPrice = array_key_exists('cost', $quote) && isset($quote['cost']) && intval($quote['cost']) > 0;
|
||||||
|
return $this->response([
|
||||||
|
'option' => $option,
|
||||||
|
'trip' => $trip,
|
||||||
|
'quote' => $quote,
|
||||||
|
'route' => $route
|
||||||
|
], 200);
|
||||||
|
} else {
|
||||||
|
throw new Exception("Failed to get transport quote for origin");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error"
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function storeInCache() {
|
||||||
|
return http_response_code() === 200 && $this->hasPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCacheKey() {
|
||||||
|
$origin = json_encode($this->requestParams["origin"]);
|
||||||
|
$destination = json_encode($this->requestParams["destination"]);
|
||||||
|
$option = $this->requestParams["option"];
|
||||||
|
$transport_provider_id = $option["transport_provider_id"];
|
||||||
|
return hash('md5', $this->method.'|'.$this->apiName.'|'.$this->action.'|'.$origin.'|'.$destination.'|'.$transport_provider_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,633 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Route {
|
||||||
|
|
||||||
|
/*
|
||||||
|
savvy=> select id,name from transport_providers;
|
||||||
|
id | name
|
||||||
|
----+---------------
|
||||||
|
1 | Uber
|
||||||
|
2 | Lyft
|
||||||
|
3 | Grab
|
||||||
|
4 | ComfortDelGro
|
||||||
|
5 | GOJEK
|
||||||
|
6 | Turo
|
||||||
|
7 | Getaround
|
||||||
|
10 | GrabWheels
|
||||||
|
11 | BART
|
||||||
|
12 | Muni
|
||||||
|
13 | LTA
|
||||||
|
(11 rows)
|
||||||
|
*/
|
||||||
|
public static function getTransportRoute($db, $origin, $destination, $option, $trip) {
|
||||||
|
$route = [];
|
||||||
|
switch ($option["transport_provider_id"]) {
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 4:
|
||||||
|
case 5:
|
||||||
|
case 8:
|
||||||
|
list($option, $trip, $route) = Route::drivingDirections($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 11: // BART
|
||||||
|
list($option, $trip, $route) = Route::bartDirections($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 12: // Muni
|
||||||
|
list($option, $trip, $route) = Route::muniDirections($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 13: // LTA
|
||||||
|
list($option, $trip, $route) = Route::ltaDirections($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
case 14: // MARTA
|
||||||
|
list($option, $trip, $route) = Route::martaDirections($db, $origin, $destination, $option, $trip);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error_log(json_encode($trip));
|
||||||
|
return [$option, $trip, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function drivingDirections($db, $origin, $destination, $option, $trip) {
|
||||||
|
list($option, $trip, $route) = Route::processRideshareOption($db, $option, $origin, $destination, $trip);
|
||||||
|
$option["travel_time"] = (int)$trip["duration"];
|
||||||
|
$option["travel_distance"] = (int)$trip["distance"];
|
||||||
|
$trip["source"] = strtolower($option["name"]);
|
||||||
|
return [$option, $trip, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function drivingDirectionsOriginal($db, $origin, $destination, $option, $trip) {
|
||||||
|
$options = [];
|
||||||
|
$trip = [];
|
||||||
|
$option["travel_time"] = 0;
|
||||||
|
$option["travel_distance"] = 0;
|
||||||
|
$fromLat = $origin['lat'];
|
||||||
|
$fromLng = $origin['lng'];
|
||||||
|
$toLat = $destination['lat'];
|
||||||
|
$toLng = $destination['lng'];
|
||||||
|
// This is paranoid redudant check, but since the function is "public"...
|
||||||
|
if ($fromLat==null || $fromLng==null || $toLat==null || $toLng==null
|
||||||
|
|| ($fromLat==0 && $fromLng==0) || ($toLat==0 && $toLng==0)) {
|
||||||
|
throw new Exception('Invalid origin and/or destination coordinates');
|
||||||
|
}
|
||||||
|
list($res, $err) = Route::serviceRoute($db, $fromLat, $fromLng, $toLat, $toLng);
|
||||||
|
if ($err!=NULL || !is_array($res) || !isset($res["routes"]) || count($res["routes"])<1) {
|
||||||
|
$options['error'] = $err!=NULL ? $err : 'No available routes';
|
||||||
|
return [$option, $trip, $options];
|
||||||
|
}
|
||||||
|
$options["route_overlay"] = [];
|
||||||
|
$travel_time = PHP_INT_MAX;
|
||||||
|
$travel_distance = PHP_INT_MAX;
|
||||||
|
foreach ($res["routes"] as $route) {
|
||||||
|
$r = Route::processRoute($route);
|
||||||
|
if ($travel_time>$r['duration']) {
|
||||||
|
$travel_time = $r['duration'];
|
||||||
|
$travel_distance = $r['distance'];
|
||||||
|
}
|
||||||
|
$options["route_overlay"][] = $r;
|
||||||
|
}
|
||||||
|
$options["travel_time"] = $travel_time==PHP_INT_MAX ? NULL : $travel_time;
|
||||||
|
$options["travel_distance"] = $travel_distance==PHP_INT_MAX ? NULL : $travel_distance;
|
||||||
|
|
||||||
|
$option["travel_time"] = (int)$options["travel_time"];
|
||||||
|
$option["travel_distance"] = (int)$options["travel_distance"];
|
||||||
|
|
||||||
|
//https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
||||||
|
//overview_polyline
|
||||||
|
//bounds contains the viewport bounding box of the overview_polyline.
|
||||||
|
return [$option, $trip, $options];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function bartDirections($db, $origin, $destination, $option, $trip) {
|
||||||
|
$route = [];
|
||||||
|
|
||||||
|
$option["travel_time"] = 0;
|
||||||
|
$option["travel_distance"] = 0;
|
||||||
|
|
||||||
|
$route["travel_time"] = 0;
|
||||||
|
$route["travel_distance"] = 0;
|
||||||
|
$route["route_overlay"] = [];
|
||||||
|
|
||||||
|
$country = $origin["country"];
|
||||||
|
$member_id = $option["member_id"];
|
||||||
|
|
||||||
|
// New directions
|
||||||
|
$tripService = Route::tripService($trip["id"], $country, 'BART');
|
||||||
|
|
||||||
|
//error_log(json_encode($tripService));
|
||||||
|
if (is_array($tripService) && isset($tripService["travel_date"])) {
|
||||||
|
$tripService["member_id"] = $member_id; // Pass along
|
||||||
|
$tripService["country"] = $country;
|
||||||
|
$tripService = MultiModalFilter::byDuration($tripService);
|
||||||
|
//$tripService = MultiModalFilter::byCost($tripService);
|
||||||
|
$trip = $tripService;
|
||||||
|
|
||||||
|
$option["travel_time"] = (int)$trip["options"]["legs"][0]["duration"];
|
||||||
|
$option["travel_distance"] = (int)$trip["options"]["legs"][0]["distance"];
|
||||||
|
|
||||||
|
$route = Route::routeFromTrip($db, $origin, $destination, $option, $trip);
|
||||||
|
}
|
||||||
|
return [$option, $trip, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function muniDirections($db, $origin, $destination, $option, $trip) {
|
||||||
|
$route = [];
|
||||||
|
|
||||||
|
$option["travel_time"] = 0;
|
||||||
|
$option["travel_distance"] = 0;
|
||||||
|
$country = $origin["country"];
|
||||||
|
$member_id = $option["member_id"];
|
||||||
|
|
||||||
|
// New directions
|
||||||
|
$tripService = Route::tripService($trip["id"], $country, 'MUNI');
|
||||||
|
|
||||||
|
//error_log(json_encode($tripService));
|
||||||
|
if (is_array($tripService) && isset($tripService["travel_date"])) {
|
||||||
|
$tripService["member_id"] = $member_id; // Pass along
|
||||||
|
$tripService["country"] = $country;
|
||||||
|
|
||||||
|
$tripService = MultiModalFilter::byDuration($tripService);
|
||||||
|
//$tripService = MultiModalFilter::byCost($tripService);
|
||||||
|
$trip = $tripService;
|
||||||
|
|
||||||
|
$option["travel_time"] = (int)$trip["options"]["legs"][0]["duration"];
|
||||||
|
$option["travel_distance"] = (int)$trip["options"]["legs"][0]["distance"];
|
||||||
|
|
||||||
|
$route = Route::routeFromTrip($db, $origin, $destination, $option, $trip);
|
||||||
|
}
|
||||||
|
return [$option, $trip, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function ltaDirections($db, $origin, $destination, $option, $trip) {
|
||||||
|
$route = [];
|
||||||
|
|
||||||
|
$option["travel_time"] = 0;
|
||||||
|
$option["travel_distance"] = 0;
|
||||||
|
$country = $origin["country"];
|
||||||
|
$member_id = $option["member_id"];
|
||||||
|
|
||||||
|
// New directions
|
||||||
|
$tripService = Route::tripService($trip["id"], $country, 'LTA');
|
||||||
|
|
||||||
|
//error_log(json_encode($tripService));
|
||||||
|
if (is_array($tripService) && isset($tripService["travel_date"])) {
|
||||||
|
$tripService["member_id"] = $member_id; // Pass along
|
||||||
|
$tripService["country"] = $country;
|
||||||
|
|
||||||
|
$tripService = MultiModalFilter::byDuration($tripService);
|
||||||
|
//$tripService = MultiModalFilter::byCost($tripService);
|
||||||
|
$trip = $tripService;
|
||||||
|
|
||||||
|
$option["travel_time"] = (int)$trip["options"]["legs"][0]["duration"];
|
||||||
|
$option["travel_distance"] = (int)$trip["options"]["legs"][0]["distance"];
|
||||||
|
|
||||||
|
$route = Route::routeFromTrip($db, $origin, $destination, $option, $trip);
|
||||||
|
}
|
||||||
|
return [$option, $trip, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function martaDirections($db, $origin, $destination, $option, $trip) {
|
||||||
|
$route = [];
|
||||||
|
|
||||||
|
$option["travel_time"] = 0;
|
||||||
|
$option["travel_distance"] = 0;
|
||||||
|
$country = $origin["country"];
|
||||||
|
$member_id = $option["member_id"];
|
||||||
|
|
||||||
|
// New directions
|
||||||
|
$tripService = Route::tripService($trip["id"], $country, 'MARTA');
|
||||||
|
|
||||||
|
//error_log(json_encode($tripService));
|
||||||
|
if (is_array($tripService) && isset($tripService["travel_date"])) {
|
||||||
|
$tripService["member_id"] = $member_id; // Pass along
|
||||||
|
$tripService["country"] = $country;
|
||||||
|
|
||||||
|
$tripService = MultiModalFilter::byDuration($tripService);
|
||||||
|
$trip = $tripService;
|
||||||
|
|
||||||
|
$option["travel_time"] = (int)$trip["options"]["legs"][0]["duration"];
|
||||||
|
$option["travel_distance"] = (int)$trip["options"]["legs"][0]["distance"];
|
||||||
|
|
||||||
|
$route = Route::routeFromTrip($db, $origin, $destination, $option, $trip);
|
||||||
|
}
|
||||||
|
return [$option, $trip, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function routeFromTrip($db, $origin, $destination, $option, $trip) {
|
||||||
|
|
||||||
|
$leg = [
|
||||||
|
"distance" => 0,
|
||||||
|
"duration" => 0,
|
||||||
|
"polyline" => NULL
|
||||||
|
];
|
||||||
|
// Select leg
|
||||||
|
foreach ($trip["options"]["legs"] as $leg) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$route["travel_time"] = (int)$leg["duration"];
|
||||||
|
$route["travel_distance"] = (int)$leg["distance"];
|
||||||
|
|
||||||
|
// TODO: BART fix polyline!
|
||||||
|
|
||||||
|
$route["route_overlay"][] = [
|
||||||
|
"polyline" => [],
|
||||||
|
"distance" => $leg["distance"],
|
||||||
|
"duration" => $leg["duration"],
|
||||||
|
"summary" => "Generated option",
|
||||||
|
"overview_polyline" => [
|
||||||
|
"points" => Route::processPolyline($leg["polyline"])
|
||||||
|
],
|
||||||
|
"bounds" => [
|
||||||
|
"northeast" => [
|
||||||
|
"lat" => $origin["lat"],
|
||||||
|
"lng" => $origin["lng"]
|
||||||
|
],
|
||||||
|
"southwest" => [
|
||||||
|
"lat" => $destination["lat"],
|
||||||
|
"lng" => $destination["lng"]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
return $route;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function checkValidRoute($db, $route) {
|
||||||
|
// Basic input sanity check: route
|
||||||
|
if (!is_array($route) || !array_key_exists('travel_time',$route) || !is_numeric($route['travel_time'])
|
||||||
|
|| !array_key_exists('travel_distance',$route) || !is_numeric($route['travel_distance'])
|
||||||
|
|| !array_key_exists('route_overlay',$route) || !is_array($route['route_overlay'])) {
|
||||||
|
throw new Exception('Invalid transport route');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function serviceRoute($db, $fromLat, $fromLng, $toLat, $toLng, $mode='driving',$waypoints=[]) {
|
||||||
|
global $savvyext;
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
|
||||||
|
error_log("Route::serviceRoute(\$db, $fromLat, $fromLng, $toLat, $toLng, $mode, \$waypoints=[])");
|
||||||
|
// Call geocoding service
|
||||||
|
$data = http_build_query(
|
||||||
|
array(
|
||||||
|
'gps' => implode(",",array($fromLat, $fromLng, $toLat, $toLng)),
|
||||||
|
'mode' => $mode,
|
||||||
|
'waypoints' => implode(",",$waypoints)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$url = $oauth2_url."route?" . $data;
|
||||||
|
$opts = array(
|
||||||
|
'http' => array(
|
||||||
|
'method' => "GET",
|
||||||
|
'timeout' => 60, /* 1 minute */
|
||||||
|
'header' =>
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n" .
|
||||||
|
"Accept: application/json\r\n" .
|
||||||
|
"Authorization: Server-Token ${httpAuthToken}\r\n",
|
||||||
|
),
|
||||||
|
"ssl" => array(
|
||||||
|
"verify_peer"=>false,
|
||||||
|
"verify_peer_name"=>false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$context = stream_context_create($opts);
|
||||||
|
$body = file_get_contents($url, false, $context);
|
||||||
|
$geocoded = json_decode($body,true);
|
||||||
|
if (is_array($geocoded) && is_array($geocoded["data"]) && !isset($geocoded["error"])) {
|
||||||
|
return array($geocoded["data"], NULL);
|
||||||
|
} else if (is_array($geocoded) && isset($geocoded["error"])) {
|
||||||
|
$body = $geocoded["error"];
|
||||||
|
}
|
||||||
|
return array(NULL, "Routing service call error: ".$body);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processRoute($route) {
|
||||||
|
require_once('../common/Polyline.php');
|
||||||
|
$result = [
|
||||||
|
'polyline' => array(),
|
||||||
|
'distance' => NULL,
|
||||||
|
'duration' => NULL,
|
||||||
|
'summary' => $route["summary"],
|
||||||
|
'overview_polyline' => $route["overview_polyline"],
|
||||||
|
'bounds' => $route["bounds"]
|
||||||
|
];
|
||||||
|
$distance = 0;
|
||||||
|
$duration = 0;
|
||||||
|
foreach ($route["legs"] as $leg) {
|
||||||
|
$distance += $leg["distance"]["value"];
|
||||||
|
$duration += $leg["duration"]["value"];
|
||||||
|
foreach ($leg["steps"] as $step) {
|
||||||
|
$points = Polyline::decode($step["polyline"]["points"]);
|
||||||
|
$result['polyline'] = array_merge($result['polyline'],Polyline::pair($points));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result['distance'] = $distance;
|
||||||
|
$result['duration'] = $duration;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processRideshareOption($db, $option, $origin, $destination, $trip) {
|
||||||
|
error_log("Options::processRideshareOption(\$db, \$option, \$origin, \$destination, \$trip)");
|
||||||
|
$route = [];
|
||||||
|
$route["travel_time"] = 0;
|
||||||
|
$route["travel_distance"] = 0;
|
||||||
|
$route["route_overlay"] = [];
|
||||||
|
$member_id = $option["member_id"];
|
||||||
|
$country = $origin["country"];
|
||||||
|
$rideshare = $option["name"];
|
||||||
|
$transport_provider_id = $option["transport_provider_id"];
|
||||||
|
if (array_key_exists("timeZoneId",$origin) && $origin["timeZoneId"]!="") {
|
||||||
|
$tz = $origin["timeZoneId"];
|
||||||
|
} else if (array_key_exists("timeZoneId",$destination) && $destination["timeZoneId"]!="") {
|
||||||
|
$tz = $destination["timeZoneId"];
|
||||||
|
} else {
|
||||||
|
$tz = Options::getTimezoneById($db, $origin["timezone"], "Asia/Singapore");
|
||||||
|
}
|
||||||
|
//"trips"=>$trips;
|
||||||
|
if (!is_array($trip) && count($trip)<1) {
|
||||||
|
syslog(LOG_WARNING,"Invalid trip");
|
||||||
|
return [$option, $trip, $route]; // No idea how to handle it
|
||||||
|
}
|
||||||
|
/*if (!array_key_exists('trip',$trip) || !is_array($trip['trip']) || count($trip['trip'])<10) {
|
||||||
|
syslog(LOG_WARNING,"Invalid trip[0]!");
|
||||||
|
return $trips; // No idea how to handle it
|
||||||
|
} //*/
|
||||||
|
$oldTrip = $trip; //['trip'];
|
||||||
|
|
||||||
|
$origin['latitude'] = $origin['lat'];
|
||||||
|
$origin['longitude'] = $origin['lng'];
|
||||||
|
$destination['latitude'] = $destination['lat'];
|
||||||
|
$destination['longitude'] = $destination['lng'];
|
||||||
|
list($res, $err) = Route::serviceRoute($db,
|
||||||
|
$origin['lat'], $origin['lng'],
|
||||||
|
$destination['lat'], $destination['lng'], 'driving'
|
||||||
|
);
|
||||||
|
if ($err!=NULL || !is_array($res) || !isset($res["routes"]) || count($res["routes"])<1) {
|
||||||
|
error_log('No available routes!');
|
||||||
|
error_log($err);
|
||||||
|
return [$option, $trip, $route]; // We cannot route driving!
|
||||||
|
}
|
||||||
|
$route_overlay = [];
|
||||||
|
$travel_time = PHP_INT_MAX;
|
||||||
|
$travel_distance = PHP_INT_MAX;
|
||||||
|
foreach ($res["routes"] as $item) {
|
||||||
|
$r = Route::processRoute($item);
|
||||||
|
if ($travel_time>$r['duration']) {
|
||||||
|
$travel_time = $r['duration'];
|
||||||
|
$travel_distance = $r['distance'];
|
||||||
|
}
|
||||||
|
$route_overlay[] = $r;
|
||||||
|
}
|
||||||
|
$oldTrip["duration"] = $travel_time==PHP_INT_MAX ? NULL : $travel_time;
|
||||||
|
$oldTrip["distance"] = $travel_distance==PHP_INT_MAX ? NULL : $travel_distance;
|
||||||
|
|
||||||
|
$route["travel_time"] = (int)$oldTrip["duration"];
|
||||||
|
$route["travel_distance"] = (int)$oldTrip["distance"];
|
||||||
|
$route["route_overlay"] = $route_overlay;
|
||||||
|
/*
|
||||||
|
$result = [
|
||||||
|
'polyline' => array(),
|
||||||
|
'distance' => NULL,
|
||||||
|
'duration' => NULL,
|
||||||
|
'summary' => $route["summary"],
|
||||||
|
'overview_polyline' => $route["overview_polyline"],
|
||||||
|
'bounds' => $route["bounds"]
|
||||||
|
];
|
||||||
|
*/
|
||||||
|
//syslog(LOG_WARNING,json_encode($res));
|
||||||
|
$route_0 = $res["routes"][0];
|
||||||
|
$route_leg = $route_0["legs"][0];
|
||||||
|
$route_leg_steps = $route_leg["steps"];
|
||||||
|
$overview_polyline = Route::processPolyline($route_0["overview_polyline"]["points"]);
|
||||||
|
|
||||||
|
$leg_steps = [];
|
||||||
|
$distance = 0;
|
||||||
|
$duration = 0;
|
||||||
|
$location_start_lat = 0;
|
||||||
|
$location_start_lng = 0;
|
||||||
|
$location_end_lat = 0;
|
||||||
|
$location_end_lng = 0;
|
||||||
|
$polyline = [];
|
||||||
|
$i = 0; $j=1; $n = count($route_leg_steps);
|
||||||
|
for (; $i<$n; $i++) {
|
||||||
|
$step = $route_leg_steps[$i];
|
||||||
|
if ($step["travel_mode"] == "DRIVING") {
|
||||||
|
$location_start_lat = $step["start_location"]["lat"];
|
||||||
|
$location_start_lng = $step["start_location"]["lng"];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$leg_steps[] = [
|
||||||
|
'distance' => $step["distance"]["value"],
|
||||||
|
'duration' => $step["duration"]["value"],
|
||||||
|
'html_instructions' => $step["html_instructions"],
|
||||||
|
'location_end_lat' => $step["end_location"]["lat"],
|
||||||
|
'location_end_lng' => $step["end_location"]["lng"],
|
||||||
|
'location_start_lat' => $step["start_location"]["lat"],
|
||||||
|
'location_start_lng' => $step["start_location"]["lng"],
|
||||||
|
'polyline' => $step["polyline"]["points"], /*"yz|Fm_nxRi@e@_@P",*/
|
||||||
|
'sid' => $j++,
|
||||||
|
'travel_mode' => $step["travel_mode"]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
for (;$i<$n; $i++) {
|
||||||
|
$step = $route_leg_steps[$i];
|
||||||
|
if ($step["travel_mode"] != "DRIVING") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$distance += $step["distance"]["value"];
|
||||||
|
$duration += $step["duration"]["value"];
|
||||||
|
$location_end_lat = $step["end_location"]["lat"];
|
||||||
|
$location_end_lng = $step["end_location"]["lng"];
|
||||||
|
$polyline[] = $step["polyline"]["points"];
|
||||||
|
}
|
||||||
|
$leg_steps[] = [
|
||||||
|
'distance' => $distance,
|
||||||
|
'duration' => $duration,
|
||||||
|
'fare_quote' => null,
|
||||||
|
'fare_raw' => null,
|
||||||
|
'html_instructions' => "Take ".$rideshare." to ".$destination["address"],
|
||||||
|
'location_end_lat' => $location_end_lat,
|
||||||
|
'location_end_lng' => $location_end_lng,
|
||||||
|
'location_start_lat' => $location_start_lat,
|
||||||
|
'location_start_lng' => $location_start_lng,
|
||||||
|
'polyline' => Route::processPolyline($polyline),
|
||||||
|
'quote_group_id' => null,
|
||||||
|
'sid' => $j++,
|
||||||
|
'travel_mode' => strtoupper($rideshare)
|
||||||
|
];
|
||||||
|
for (;$i<$n; $i++) {
|
||||||
|
$step = $route_leg_steps[$i];
|
||||||
|
$leg_steps[] = [
|
||||||
|
'distance' => $step["distance"]["value"],
|
||||||
|
'duration' => $step["duration"]["value"],
|
||||||
|
'html_instructions' => $step["html_instructions"],
|
||||||
|
'location_end_lat' => $step["end_location"]["lat"],
|
||||||
|
'location_end_lng' => $step["end_location"]["lng"],
|
||||||
|
'location_start_lat' => $step["start_location"]["lat"],
|
||||||
|
'location_start_lng' => $step["start_location"]["lng"],
|
||||||
|
'polyline' => $step["polyline"]["points"], /*"yz|Fm_nxRi@e@_@P",*/
|
||||||
|
'sid' => $j++,
|
||||||
|
'travel_mode' => $step["travel_mode"]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$cost = null;
|
||||||
|
|
||||||
|
$rideshare = [
|
||||||
|
'cost' => $cost,
|
||||||
|
'cost_raw' => $cost,
|
||||||
|
'count' => 1,
|
||||||
|
'country' => $country,
|
||||||
|
'distance' => $oldTrip['distance'],
|
||||||
|
'dup_id' => null,
|
||||||
|
'duration' => $oldTrip['duration'],
|
||||||
|
'id' => $oldTrip['id'],
|
||||||
|
'location_end' => $destination['address'],
|
||||||
|
'location_end_id' => $oldTrip['location_end_id'],
|
||||||
|
'location_end_lat' => $destination['latitude'],
|
||||||
|
'location_end_lng' => $destination['longitude'],
|
||||||
|
'location_end_tz' => $destination['timezone'],
|
||||||
|
'location_start' => $origin['address'],
|
||||||
|
'location_start_id' => $oldTrip['location_start_id'],
|
||||||
|
'location_start_lat' => $origin['latitude'],
|
||||||
|
'location_start_lng' => $origin['longitude'],
|
||||||
|
'location_start_tz' => $origin['timezone'],
|
||||||
|
'member_id' => $member_id,
|
||||||
|
'options' => [],
|
||||||
|
'parsedemail_item_id' => null, /* $trip['id'] ??? */
|
||||||
|
'private' => 't',
|
||||||
|
'scheduled' => null,
|
||||||
|
'trackedemail_item_id' => null,
|
||||||
|
'transport_provider_id' => $transport_provider_id,
|
||||||
|
'travel_date' => $oldTrip['travel_date'],
|
||||||
|
'travel_date_end' => $oldTrip['travel_date_end'],
|
||||||
|
'updated' => $oldTrip['updated']
|
||||||
|
];
|
||||||
|
// Create trip advice
|
||||||
|
$rideshare["source"] = strtolower($option["name"]);
|
||||||
|
$parsedemail_item_advice_google_id = Options::saveTripAdvice($db, $rideshare);
|
||||||
|
error_log(json_encode($parsedemail_item_advice_google_id));
|
||||||
|
|
||||||
|
$leg_fare = $cost;
|
||||||
|
// Get departure and arrival times...
|
||||||
|
$date = new DateTime("now", new DateTimeZone($tz));
|
||||||
|
$date->add(new DateInterval('PT15M'));
|
||||||
|
$departure_time = $date->getTimestamp();
|
||||||
|
$duration = Route::getDuration(array_key_exists('duration',$oldTrip)?$oldTrip['duration']:900);
|
||||||
|
$date->add(new DateInterval('PT'.$duration.'M'));
|
||||||
|
$arrival_time = $date->getTimestamp();
|
||||||
|
|
||||||
|
$leg = [
|
||||||
|
'id' => NULL,
|
||||||
|
'parsedemail_item_advice_google_id' => $parsedemail_item_advice_google_id,
|
||||||
|
'arrival_time' => $arrival_time,
|
||||||
|
'arrival_time_zone' => $destination['timezone'],
|
||||||
|
'arrival_timezone' => $tz,
|
||||||
|
'departure_time' => $departure_time,
|
||||||
|
'departure_time_zone' => $origin['timezone'],
|
||||||
|
'departure_timezone' => $tz,
|
||||||
|
'distance' => $oldTrip['distance'],
|
||||||
|
'duration' => $oldTrip['duration'],
|
||||||
|
'fare_raw' => $cost,
|
||||||
|
'polyline' => $overview_polyline,
|
||||||
|
'quote' => $cost,
|
||||||
|
'steps' => count($leg_steps),
|
||||||
|
];
|
||||||
|
// Create leg
|
||||||
|
$google_directions_leg_id = Options::saveTripAdviceLeg($db, $rideshare, $leg);
|
||||||
|
$leg['id'] = $google_directions_leg_id;
|
||||||
|
foreach ($leg_steps as $i=>$step) {
|
||||||
|
$step['google_directions_leg_id'] = $google_directions_leg_id;
|
||||||
|
$google_directions_leg_step_id = Options::saveTripAdviceLegStep($db, $rideshare, $leg, $step);
|
||||||
|
$step['id'] = $google_directions_leg_step_id;
|
||||||
|
$leg_steps[$i] = $step;
|
||||||
|
}
|
||||||
|
$options = [
|
||||||
|
'gid' => $google_directions_leg_id, /* ??? */
|
||||||
|
'leg_fare' => [$google_directions_leg_id => $leg_fare],
|
||||||
|
'leg_steps' => [$google_directions_leg_id => $leg_steps],
|
||||||
|
'legs' => [$leg],
|
||||||
|
'routes' => 1
|
||||||
|
];
|
||||||
|
$rideshare['options'] = $options;
|
||||||
|
return [$option, $rideshare, $route];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function getDuration($duration=900) {
|
||||||
|
if ($duration==NULL) {
|
||||||
|
return 15;
|
||||||
|
}
|
||||||
|
if ($duration>60) {
|
||||||
|
return (int)($duration/60);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processPolyline($data) {
|
||||||
|
if (!is_array($data)) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
require_once('../common/Polyline.php');
|
||||||
|
$points = [];
|
||||||
|
foreach ($data as $item) {
|
||||||
|
$points = array_merge($points, Polyline::decode($item));
|
||||||
|
//$points = array_merge(Polyline::decode($item),$points);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Polyline::encode($points);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function tripService($id, $country, $mode) {
|
||||||
|
global $savvyext;
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
$oauth2_url = $savvyext->cfgReadChar('system.oauth2_url');
|
||||||
|
error_log("Route::tripService($id)");
|
||||||
|
if ($country!='SG' && $country!='US') {
|
||||||
|
throw new Exception('Unsupported country: '.$country);
|
||||||
|
}
|
||||||
|
// curl -d 'id=44254' -d 'mode=BART' -d 'country=US' -H 'Authorization: Server-Token 99dfe35fcb7de1ee' -X POST {$oauth2_url}modetrips
|
||||||
|
$postdata = http_build_query(
|
||||||
|
array(
|
||||||
|
'id'=> $id,
|
||||||
|
'mode' => $mode,
|
||||||
|
'country' => $country
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$url = $oauth2_url."modetrips";
|
||||||
|
$opts = array(
|
||||||
|
'http' => array(
|
||||||
|
'method' => "POST",
|
||||||
|
'timeout' => 60, /* 1 minute */
|
||||||
|
'header' =>
|
||||||
|
"Content-Type: application/x-www-form-urlencoded\r\n" .
|
||||||
|
"Accept: application/json\r\n" .
|
||||||
|
"Authorization: Server-Token ${httpAuthToken}\r\n",
|
||||||
|
'content' => $postdata
|
||||||
|
),
|
||||||
|
"ssl" => array(
|
||||||
|
"verify_peer"=>false,
|
||||||
|
"verify_peer_name"=>false,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$context = stream_context_create($opts);
|
||||||
|
error_log("started trips service call");
|
||||||
|
$t = time();
|
||||||
|
$body = file_get_contents($url, false, $context);
|
||||||
|
error_log("complete trips service call: ".(time()-$t)." seconds");
|
||||||
|
$trip = json_decode($body,true);
|
||||||
|
return $trip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
["id"]=>
|
||||||
|
string(1) "5"
|
||||||
|
["city_id"]=>
|
||||||
|
string(1) "2"
|
||||||
|
["name"]=>
|
||||||
|
string(4) "Uber"
|
||||||
|
["transport_provider_id"]=>
|
||||||
|
string(1) "1"
|
||||||
|
["custom"]=>
|
||||||
|
NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class RouteApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'route';
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error' => 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get single record (by id)
|
||||||
|
* http://DOMAIN/remove/1
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
//id must be the first parameter after /remove/x
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error'=> 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$message = "Unexpected options error";
|
||||||
|
|
||||||
|
$origin = $this->requestParams["origin"] ?? [];
|
||||||
|
$destination = $this->requestParams["destination"] ?? [];
|
||||||
|
$option = $this->requestParams["option"] ?? [];
|
||||||
|
$trip = $this->requestParams["trip"] ?? [];
|
||||||
|
$member_id = $this->requestParams["member_id"] ?? 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$db = new Db();
|
||||||
|
|
||||||
|
list ($origin, $destination) = Options::checkValidLocations($db->getConnect(), $origin, $destination);
|
||||||
|
Options::checkValidOption($db->getConnect(), $option);
|
||||||
|
Options::checkValidTrip($db->getConnect(), $trip);
|
||||||
|
|
||||||
|
$option["member_id"] = $member_id;
|
||||||
|
$trip["member_id"] = $member_id;
|
||||||
|
list ($res, $trip, $route) = Route::getTransportRoute($db->getConnect(), $origin, $destination, $option, $trip);
|
||||||
|
if (is_array($res)) {
|
||||||
|
return $this->response([
|
||||||
|
'option' => $res,
|
||||||
|
'trip' => $trip,
|
||||||
|
'route' => $route
|
||||||
|
], 200);
|
||||||
|
} else {
|
||||||
|
throw new Exception("Failed to get transport route for origin");
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error"
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,431 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Psr7;
|
||||||
|
use GuzzleHttp\Exception\ClientException;
|
||||||
|
use GuzzleHttp\Exception\RequestException;
|
||||||
|
|
||||||
|
class Autocab {
|
||||||
|
|
||||||
|
const TIMEOUT = 60;
|
||||||
|
const DEBUG = false;
|
||||||
|
const SSL_VERIFY = false;
|
||||||
|
|
||||||
|
const REASON_NOT_REQUIRED = "NotRequired";
|
||||||
|
const REASON_PRICE_CHANGED = "PriceChanged";
|
||||||
|
|
||||||
|
private $httpClient;
|
||||||
|
private $agentId;
|
||||||
|
private $agentPassword;
|
||||||
|
private $currency;
|
||||||
|
private $vendorId;
|
||||||
|
private $templatesDir;
|
||||||
|
private $config = [];
|
||||||
|
private $templates = [];
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($config) {
|
||||||
|
if (empty($config)) {
|
||||||
|
throw new Exception("Configuration is not provided");
|
||||||
|
}
|
||||||
|
$this->setConfig($config);
|
||||||
|
if (!isset($config["baseUrl"]) || empty($config["baseUrl"])) {
|
||||||
|
throw new Exception("The API URL is not specified");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->httpClient = new Client(['base_uri' => $config["baseUrl"]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setConfig($config) {
|
||||||
|
global $savvyext;
|
||||||
|
$this->config = $config;
|
||||||
|
$this->agentId = $config["agentId"] ;
|
||||||
|
$this->agentPassword = $config["agentPassword"];
|
||||||
|
$this->currency = $config["currency"];
|
||||||
|
$this->templatesDir = $config["templatesDir"];
|
||||||
|
$this->loadTemplates($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadTemplates($config) {
|
||||||
|
if ( !array_key_exists('templatesDir', $config) || empty($config["templatesDir"])) {
|
||||||
|
throw new Exception("The templates dir is not specified");
|
||||||
|
}
|
||||||
|
$files = scandir($this->templatesDir);
|
||||||
|
if ($files) {
|
||||||
|
foreach ($files as $templateFile) {
|
||||||
|
$template = file_get_contents($this->templatesDir."/".$templateFile);
|
||||||
|
if ($template) {
|
||||||
|
$this->templates[$templateFile] = $template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($this->templates) == 0) {
|
||||||
|
throw new Exception("Any one template is not initialized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTemplate($name, $oldRootTag=NULL, $newRootTag=NULL) {
|
||||||
|
if (!isset($this->templates[$name])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$template = $this->templates[$name];
|
||||||
|
if (isset($oldRootTag) && isset($newRootTag)) {
|
||||||
|
$template = str_replace($oldRootTag, $newRootTag, $template);
|
||||||
|
}
|
||||||
|
$xmlElement = new SimpleXMLElement($template);
|
||||||
|
$xmlElement->Agent->attributes()->Id = $this->config["agentId"];
|
||||||
|
$xmlElement->Agent->Password = $this->config["agentPassword"];
|
||||||
|
return $xmlElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHeaders($extraHeaders = []) {
|
||||||
|
$headers = [
|
||||||
|
'content-type' => 'text/xml',
|
||||||
|
];
|
||||||
|
return array_merge($headers,$extraHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAvailability($source, $destination) {
|
||||||
|
if (!isset($this->templates['autocab_agent_bid_request.xml'])) {
|
||||||
|
throw new Exception("Bid request template is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = '/api/agent';
|
||||||
|
$xmlElement = $this->getTemplate('autocab_agent_bid_request.xml');
|
||||||
|
|
||||||
|
$xmlElement->Agent->Time = gmdate("Y-m-d\TH:i:s.v\Z");
|
||||||
|
$xmlElement->BidParameters->Journey->From->Data = $source["address"];
|
||||||
|
$xmlElement->BidParameters->Journey->From->Coordinate->Latitude = $source["latitude"];
|
||||||
|
$xmlElement->BidParameters->Journey->From->Coordinate->Longitude = $source["longitude"];
|
||||||
|
$xmlElement->BidParameters->Journey->To->Data = $destination["address"];
|
||||||
|
$xmlElement->BidParameters->Journey->To->Coordinate->Latitude = $destination["latitude"];
|
||||||
|
$xmlElement->BidParameters->Journey->To->Coordinate->Longitude = $destination["longitude"];
|
||||||
|
|
||||||
|
$xml = $xmlElement->asXML();
|
||||||
|
|
||||||
|
$result = $this->genericPost($uri, $xml);
|
||||||
|
|
||||||
|
if ($result["error"]) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result["code"] != 200) {
|
||||||
|
var_dump($result["data"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlResponse = new SimpleXMLElement($result["data"]);
|
||||||
|
$error = self::processError($xmlResponse);
|
||||||
|
if($error) {
|
||||||
|
return ["error"=>1, "data" => $error, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
$costs = [];
|
||||||
|
foreach ($xmlResponse->Offers->Offer as $offer) {
|
||||||
|
$item = self::processBidOffer($offer);
|
||||||
|
array_push($costs, $item);
|
||||||
|
}
|
||||||
|
return array("error"=>0, "data"=>$costs, "raw_data"=>$xmlResponse, "request"=>$xmlElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBookingAvailability($source, $destination, $vendor) {
|
||||||
|
|
||||||
|
if (!isset($this->templates['autocab_agent_booking_availability_request.xml'])) {
|
||||||
|
throw new Exception("Booking Availability request template is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = '/api/agent';
|
||||||
|
$xmlElement = $this->getTemplate('autocab_agent_booking_availability_request.xml');
|
||||||
|
$xmlElement->Vendor->attributes()->Id = $vendor;
|
||||||
|
$xmlElement->Agent->Time = gmdate("Y-m-d\TH:i:s.v\Z");
|
||||||
|
$xmlElement->BookingParameters->Journey->From->Data = $source["address"] ?? "No Address";
|
||||||
|
$xmlElement->BookingParameters->Journey->From->Coordinate->Latitude = $source["latitude"];
|
||||||
|
$xmlElement->BookingParameters->Journey->From->Coordinate->Longitude = $source["longitude"];
|
||||||
|
$xmlElement->BookingParameters->Journey->To->Data = $destination["address"] ?? "No Address";
|
||||||
|
$xmlElement->BookingParameters->Journey->To->Coordinate->Latitude = $destination["latitude"];
|
||||||
|
$xmlElement->BookingParameters->Journey->To->Coordinate->Longitude = $destination["longitude"];
|
||||||
|
|
||||||
|
$xml = $xmlElement->asXML();
|
||||||
|
|
||||||
|
$result = $this->genericPost($uri, $xml);
|
||||||
|
|
||||||
|
if ($result["error"]) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result["code"] != 200) {
|
||||||
|
var_dump($result["data"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlResponse = new SimpleXMLElement($result["data"]);
|
||||||
|
$error = self::processError($xmlResponse);
|
||||||
|
if($error) {
|
||||||
|
return ["error"=>1, "data" => $error, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
$cost = null;
|
||||||
|
|
||||||
|
if(isset($xmlResponse->Pricing)) {
|
||||||
|
$cost = [
|
||||||
|
'currency' => (string)$xmlResponse->Pricing->Currency,
|
||||||
|
'availability_ref' => (string)$xmlResponse->AvailabilityReference,
|
||||||
|
'display_name' => (string)$xmlResponse->VendorDetails->Name,
|
||||||
|
'high_estimate' => (int)$xmlResponse->Pricing->Price,
|
||||||
|
'low_estimate' => (int)$xmlResponse->Pricing->Price,
|
||||||
|
'distance_estimate' => (int) $xmlResponse->EstimatedJourney->Distance,
|
||||||
|
'duration_estimate' => (int) $xmlResponse->EstimatedJourney->Duration * 60,
|
||||||
|
'vendor_id' => (string) $xmlResponse->Vendor->attributes()->Id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ["error"=>0, "data"=>$cost, "raw_data"=>$xmlResponse, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancelAvailability($availabilityRef, $vendor, $reason = self::REASON_NOT_REQUIRED) {
|
||||||
|
|
||||||
|
if (!isset($this->templates['autocab_agent_booking_not_authorized_request.xml'])) {
|
||||||
|
throw new Exception("BookingNotAuthorizedRequest template is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($availabilityRef)) {
|
||||||
|
throw new Exception("Invalid availability reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = '/api/agent';
|
||||||
|
$xmlElement = $this->getTemplate('autocab_agent_booking_not_authorized_request.xml');
|
||||||
|
$xmlElement->Vendor->attributes()->Id = $vendor;
|
||||||
|
$xmlElement->Agent->Time = gmdate("Y-m-d\TH:i:s.v\Z");
|
||||||
|
$xmlElement->AvailabilityReference = $availabilityRef;
|
||||||
|
$xmlElement->Reason = $reason;
|
||||||
|
|
||||||
|
$xml = $xmlElement->asXML();
|
||||||
|
|
||||||
|
$result = $this->genericPost($uri, $xml);
|
||||||
|
|
||||||
|
if ($result["error"]) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result["code"] != 200) {
|
||||||
|
var_dump($result["data"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlResponse = new SimpleXMLElement($result["data"]);
|
||||||
|
$error = self::processError($xmlResponse);
|
||||||
|
if($error) {
|
||||||
|
return ["error"=>1, "data" => $error, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
return ["error"=>0, "data"=>[], "raw_data"=>$xmlResponse, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function booking($availabilityRef, $passengers=[], $vendor) {
|
||||||
|
|
||||||
|
if (!isset($this->templates['autocab_agent_booking_athorization_request.xml'])) {
|
||||||
|
throw new Exception("BookingAuthorization template is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($availabilityRef)) {
|
||||||
|
throw new Exception("Invalid availability reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_array($passengers) || count($passengers) < 1
|
||||||
|
|| !array_key_exists("name", $passengers[0]) || empty($passengers[0]["name"])
|
||||||
|
) {
|
||||||
|
throw new Exception("Invalid passengers information");
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = '/api/agent';
|
||||||
|
$xmlElement = $this->getTemplate('autocab_agent_booking_athorization_request.xml');
|
||||||
|
$xmlElement->Vendor->attributes()->Id = $vendor;
|
||||||
|
$xmlElement->Agent->Time = gmdate("Y-m-d\TH:i:s.v\Z");
|
||||||
|
$xmlElement->AvailabilityReference = $availabilityRef;
|
||||||
|
foreach ($passengers as $key => $passenger) {
|
||||||
|
$xmlPassenger = $xmlElement->Passengers->addChild("PassengerDetails");
|
||||||
|
$isLead = ($key === array_keys($passengers)[0]) ? "true" : "false";
|
||||||
|
$xmlPassenger->addAttribute("IsLead", "$isLead");
|
||||||
|
$xmlPassenger->addChild("Name", $passenger["name"]);
|
||||||
|
if (array_key_exists("phone", $passenger) && isset($passenger["phone"])) {
|
||||||
|
$xmlPassenger->addChild( "TelephoneNumber", $passenger["phone"] );
|
||||||
|
}
|
||||||
|
if (array_key_exists("email", $passenger) && isset($passenger["email"])) {
|
||||||
|
$xmlPassenger->addChild("EmailAddress", $passenger["email"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$xml = $xmlElement->asXML();
|
||||||
|
|
||||||
|
$result = $this->genericPost($uri, $xml);
|
||||||
|
|
||||||
|
if ($result["error"]) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result["code"] != 200) {
|
||||||
|
var_dump($result["data"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlResponse = new SimpleXMLElement($result["data"]);
|
||||||
|
$error = self::processError($xmlResponse);
|
||||||
|
if($error) {
|
||||||
|
return ["error"=>1, "data" => $error];
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp = [];
|
||||||
|
if(isset($xmlResponse->AuthorizationReference)) {
|
||||||
|
$resp = [
|
||||||
|
'authorization_ref' => (string)$xmlResponse->AuthorizationReference,
|
||||||
|
'booking_ref' => (string)$xmlResponse->BookingReference,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ["error"=>0, "data"=>$resp, "raw_data"=>$xmlResponse, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bookingStatus($authorizationRef, $vendor) {
|
||||||
|
|
||||||
|
if (!isset($this->templates['autocab_agent_booking_status_request.xml'])) {
|
||||||
|
throw new Exception("BookingStatusRequest template is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($authorizationRef)) {
|
||||||
|
throw new Exception("Invalid authorization reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = '/api/agent';
|
||||||
|
$xmlElement = $this->getTemplate('autocab_agent_booking_status_request.xml');
|
||||||
|
$xmlElement->Vendor->attributes()->Id = $vendor;
|
||||||
|
$xmlElement->Agent->Time = gmdate("Y-m-d\TH:i:s.v\Z");
|
||||||
|
$xmlElement->AuthorizationReference = $authorizationRef;
|
||||||
|
|
||||||
|
$xml = $xmlElement->asXML();
|
||||||
|
|
||||||
|
$result = $this->genericPost($uri, $xml);
|
||||||
|
|
||||||
|
if ($result["error"]) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result["code"] != 200) {
|
||||||
|
var_dump($result["data"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlResponse = new SimpleXMLElement($result["data"]);
|
||||||
|
$error = self::processError($xmlResponse);
|
||||||
|
if($error) {
|
||||||
|
return ["error"=>1, "data" => $error, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp = [
|
||||||
|
'booking_ref' => (string)$xmlResponse->BookingReference,
|
||||||
|
'status' => (string)$xmlResponse->Status,
|
||||||
|
'cancellation_reason' => (string)$xmlResponse->CancellationReason
|
||||||
|
];
|
||||||
|
return ["error"=>0, "data"=>$resp, "raw_data"=>$xmlResponse, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function bookingCancellation($authorizationRef, $vendor) {
|
||||||
|
|
||||||
|
if (!isset($this->templates['autocab_agent_booking_cancellation_request.xml'])) {
|
||||||
|
throw new Exception("BookingCancellationRequest template is not initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($authorizationRef)) {
|
||||||
|
throw new Exception("Invalid authorization reference");
|
||||||
|
}
|
||||||
|
|
||||||
|
$uri = '/api/agent';
|
||||||
|
$xmlElement = $this->getTemplate('autocab_agent_booking_cancellation_request.xml');
|
||||||
|
$xmlElement->Vendor->attributes()->Id = $vendor;
|
||||||
|
$xmlElement->Agent->Time = gmdate("Y-m-d\TH:i:s.v\Z");
|
||||||
|
$xmlElement->AuthorizationReference = $authorizationRef;
|
||||||
|
|
||||||
|
$xml = $xmlElement->asXML();
|
||||||
|
|
||||||
|
$result = $this->genericPost($uri, $xml);
|
||||||
|
|
||||||
|
if ($result["error"]) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result["code"] != 200) {
|
||||||
|
var_dump($result["data"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$xmlResponse = new SimpleXMLElement($result["data"]);
|
||||||
|
$error = self::processError($xmlResponse);
|
||||||
|
if($error) {
|
||||||
|
return ["error"=>1, "data" => $error, "code" => 500, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
$resp = [];
|
||||||
|
return ["error"=>0, "data"=>$resp, "code" => 200, "raw_data"=>$xmlResponse, "request"=>$xmlElement];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function genericPost($uri, $xml, $extraHeaders=[]) {
|
||||||
|
$code = 0;
|
||||||
|
$data = [];
|
||||||
|
$error = 0;
|
||||||
|
try {
|
||||||
|
$json = json_encode($data);
|
||||||
|
$length = strlen($json);
|
||||||
|
$response = $this->httpClient->request('POST', $uri, [
|
||||||
|
'decode_content' => true,
|
||||||
|
'connect_timeout' => SELF::TIMEOUT,
|
||||||
|
'debug' => SELF::DEBUG,
|
||||||
|
'verify' => SELF::SSL_VERIFY,
|
||||||
|
'headers' => $this->getHeaders(),
|
||||||
|
'body' => $xml
|
||||||
|
]);
|
||||||
|
$code = $response->getStatusCode();
|
||||||
|
$data = $response->getBody();
|
||||||
|
} catch (RequestException $e) {
|
||||||
|
if (SELF::DEBUG) {
|
||||||
|
echo Psr7\str($e->getRequest());
|
||||||
|
if ($e->hasResponse()) {
|
||||||
|
echo Psr7\str($e->getResponse());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($e->hasResponse()) {
|
||||||
|
$code = (int) $e->getResponse()->getStatusCode();
|
||||||
|
}
|
||||||
|
$data = ["error" => "exception", "error_description" => $e->getMessage()];
|
||||||
|
$error = 1;
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
if (SELF::DEBUG) {
|
||||||
|
echo Psr7\str($e->getRequest());
|
||||||
|
echo Psr7\str($e->getResponse());
|
||||||
|
}
|
||||||
|
$code = (int)$e->getResponse()->getStatusCode();
|
||||||
|
$data = ["error" => "exception", "error_description" => $e->getMessage()];
|
||||||
|
$error = 1;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
if (SELF::DEBUG) {
|
||||||
|
echo Psr7\str($e->getRequest());
|
||||||
|
echo Psr7\str($e->getResponse());
|
||||||
|
}
|
||||||
|
$code = (int)$e->getResponse()->getStatusCode();
|
||||||
|
$data = ["error" => "exception", "error_description" => $e->getMessage()];
|
||||||
|
$error = 1;
|
||||||
|
}
|
||||||
|
return ["error" => $error, "data" => $data, "code" => $code];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processError($xmlResponse) {
|
||||||
|
if ((string)$xmlResponse->Result->Success == "true") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return ["error"=>"API error", "error_description" => (string) $xmlResponse->Result->FailureReason, "error_code" => (string) $xmlResponse->Result->FailureCode];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processBidOffer($offer) {
|
||||||
|
$item = [
|
||||||
|
'currency' => (string)$offer->Pricing->Currency,
|
||||||
|
'transport_product' => (string)$offer['Reference'],
|
||||||
|
'display_name' => (string)$offer->VendorDetails->Name,
|
||||||
|
'high_estimate' => (int)$offer->Pricing->Price,
|
||||||
|
'low_estimate' => (int)$offer->Pricing->Price,
|
||||||
|
'distance_estimate' => (int) $offer->EstimatedJourney->Distance,
|
||||||
|
'duration_estimate' => (int) $offer->EstimatedJourney->Duration * 60,
|
||||||
|
];
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<AgentBidRequest>
|
||||||
|
<Agent Id="{{agent_id}}">
|
||||||
|
<Password>{{agent_password}}</Password>
|
||||||
|
<Reference>AgentRef</Reference>
|
||||||
|
<Time>{{agent_time}}</Time>
|
||||||
|
</Agent>
|
||||||
|
<BidParameters>
|
||||||
|
<Pricing>
|
||||||
|
<Currency>USD</Currency>
|
||||||
|
<PaymentType>Cash</PaymentType>
|
||||||
|
</Pricing>
|
||||||
|
<Journey>
|
||||||
|
<From>
|
||||||
|
<Type>Address</Type>
|
||||||
|
<Data>1563 Van Dyke Ave, San Francisco, CA 94124, USA</Data>
|
||||||
|
<Coordinate>
|
||||||
|
<Latitude>37.7286068</Latitude>
|
||||||
|
<Longitude>-122.3919092</Longitude>
|
||||||
|
</Coordinate>
|
||||||
|
</From>
|
||||||
|
<To>
|
||||||
|
<Type>Address</Type>
|
||||||
|
<Data>536 Edinburgh St, San Francisco, CA 94112, USA</Data>
|
||||||
|
<Coordinate>
|
||||||
|
<Latitude>37.7206606</Latitude>
|
||||||
|
<Longitude>-122.4326099</Longitude>
|
||||||
|
</Coordinate>
|
||||||
|
</To>
|
||||||
|
</Journey>
|
||||||
|
<Ride Type="Passenger">
|
||||||
|
</Ride>
|
||||||
|
</BidParameters>
|
||||||
|
</AgentBidRequest>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<AgentBookingAuthorizationRequest>
|
||||||
|
<Agent Id="{{agent_id}}">
|
||||||
|
<Password>{{agent_password}}</Password>
|
||||||
|
<Reference>AgentRef</Reference>
|
||||||
|
<Time>{{agent_time}}</Time>
|
||||||
|
</Agent>
|
||||||
|
<Vendor Id="{{vendor_id}}" />
|
||||||
|
<AvailabilityReference>{{availability_reference}}</AvailabilityReference>
|
||||||
|
<Passengers>
|
||||||
|
</Passengers>
|
||||||
|
<Notifications>
|
||||||
|
<VendorEvents>BookingDispatched NoFare BookingCompleted BookingCancelled</VendorEvents>
|
||||||
|
<AlertMethod>None</AlertMethod>
|
||||||
|
<AgentEvents>BookingDispatched NoFare BookingCompleted BookingCancelled LocationUpdate VehicleArrived PassengerOnBoard</AgentEvents>
|
||||||
|
</Notifications>
|
||||||
|
</AgentBookingAuthorizationRequest>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<AgentBookingAvailabilityRequest>
|
||||||
|
<Agent Id="{{agent_id}}">
|
||||||
|
<Password>{{agent_password}}</Password>
|
||||||
|
<Reference>AgentRef</Reference>
|
||||||
|
<Time>{{agent_time}}</Time>
|
||||||
|
</Agent>
|
||||||
|
<Vendor Id="{{vendor_id}}" />
|
||||||
|
<BookingParameters>
|
||||||
|
<Pricing>
|
||||||
|
<Currency>USD</Currency>
|
||||||
|
<PaymentType>Cash</PaymentType>
|
||||||
|
</Pricing>
|
||||||
|
<Journey>
|
||||||
|
<From>
|
||||||
|
<Type>Address</Type>
|
||||||
|
<Data>1563 Van Dyke Ave, San Francisco, CA 94124, USA</Data>
|
||||||
|
<Coordinate>
|
||||||
|
<Latitude>37.7286068</Latitude>
|
||||||
|
<Longitude>-122.3919092</Longitude>
|
||||||
|
</Coordinate>
|
||||||
|
</From>
|
||||||
|
<To>
|
||||||
|
<Type>Address</Type>
|
||||||
|
<Data>536 Edinburgh St, San Francisco, CA 94112, USA</Data>
|
||||||
|
<Coordinate>
|
||||||
|
<Latitude>37.7206606</Latitude>
|
||||||
|
<Longitude>-122.4326099</Longitude>
|
||||||
|
</Coordinate>
|
||||||
|
</To>
|
||||||
|
</Journey>
|
||||||
|
<Ride Type="Passenger">
|
||||||
|
</Ride>
|
||||||
|
</BookingParameters>
|
||||||
|
</AgentBookingAvailabilityRequest>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<AgentBookingCancellationRequest>
|
||||||
|
<Agent Id="{{agent_id}}">
|
||||||
|
<Password>{{agent_password}}</Password>
|
||||||
|
<Reference>AgentRef</Reference>
|
||||||
|
<Time>{{agent_time}}</Time>
|
||||||
|
</Agent>
|
||||||
|
<Vendor Id="{{vendor_id}}" />
|
||||||
|
<AuthorizationReference>{{authorization_reference}}</AuthorizationReference>
|
||||||
|
</AgentBookingCancellationRequest>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<AgentBookingCancelledEventResponse>
|
||||||
|
<Vendor Id="{{vendor_id}}">
|
||||||
|
<Reference>{{vendor_ref}}</Reference>
|
||||||
|
<Time>{{vendor_time}}</Time>
|
||||||
|
</Vendor>
|
||||||
|
<Agent Id="{{agent_id}}"/>
|
||||||
|
<Result>
|
||||||
|
<Success>true</Success>
|
||||||
|
<FailureCode/>
|
||||||
|
<FailureReason/>
|
||||||
|
</Result>
|
||||||
|
<AcknowledgementReference>{{acknowledgement_ref}}</AcknowledgementReference>
|
||||||
|
</AgentBookingCancelledEventResponse>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<AgentBookingNotAuthorizedRequest>
|
||||||
|
<Agent Id="{{agent_id}}">
|
||||||
|
<Password>{{agent_password}}</Password>
|
||||||
|
<Reference>AgentRef</Reference>
|
||||||
|
<Time>{{agent_time}}</Time>
|
||||||
|
</Agent>
|
||||||
|
<Vendor Id="{{vendor_id}}" />
|
||||||
|
<AvailabilityReference>{{availability_reference}}</AvailabilityReference>
|
||||||
|
<Reason>NotRequired</Reason>
|
||||||
|
</AgentBookingNotAuthorizedRequest>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<AgentBookingStatusRequest>
|
||||||
|
<Agent Id="{{agent_id}}">
|
||||||
|
<Password>{{agent_password}}</Password>
|
||||||
|
<Reference>AgentRef</Reference>
|
||||||
|
<Time>{{agent_time}}</Time>
|
||||||
|
</Agent>
|
||||||
|
<Vendor Id="{{vendor_id}}" />
|
||||||
|
<AuthorizationReference>{{authorization_reference}}</AuthorizationReference>
|
||||||
|
</AgentBookingStatusRequest>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<AgentVehicleArrivedEventResponse>
|
||||||
|
<Vendor Id="{{vendor_id}}">
|
||||||
|
<Reference>{{vendor_ref}}</Reference>
|
||||||
|
<Time>{{vendor_time}}</Time>
|
||||||
|
</Vendor>
|
||||||
|
<Agent Id="{{agent_id}}"/>
|
||||||
|
<Result>
|
||||||
|
<Success>true</Success>
|
||||||
|
<FailureCode/>
|
||||||
|
<FailureReason/>
|
||||||
|
</Result>
|
||||||
|
<AcknowledgementReference>{{acknowledgement_ref}}</AcknowledgementReference>
|
||||||
|
</AgentVehicleArrivedEventResponse>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<AgentEventResponse>
|
||||||
|
<Vendor Id="{{vendor_id}}">
|
||||||
|
<Reference>{{vendor_ref}}</Reference>
|
||||||
|
<Time>{{vendor_time}}</Time>
|
||||||
|
</Vendor>
|
||||||
|
<Agent Id="{{agent_id}}"/>
|
||||||
|
<Result>
|
||||||
|
<Success>true</Success>
|
||||||
|
<FailureCode/>
|
||||||
|
<FailureReason/>
|
||||||
|
</Result>
|
||||||
|
<AcknowledgementReference>{{acknowledgement_ref}}</AcknowledgementReference>
|
||||||
|
</AgentEventResponse>
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$profile = getenv("SAVVY_PROFILE");
|
||||||
|
if ($profile) {
|
||||||
|
require_once("../../core/backend.${profile}.php");
|
||||||
|
} else {
|
||||||
|
require_once( '../../core/backend.php' );
|
||||||
|
}
|
||||||
|
|
||||||
|
include_once '../config.php';
|
||||||
|
require_once('../constants.php');
|
||||||
|
|
||||||
|
require_once('../common/vendor/autoload.php');
|
||||||
|
require_once('../common/Api.php');
|
||||||
|
require_once('../common/Db.php');
|
||||||
|
require_once('../common/GoogleKMS.php');
|
||||||
|
require_once('../common/Logger.php');
|
||||||
|
|
||||||
|
require_once('../trips/MultiModalFilter.php');
|
||||||
|
|
||||||
|
require_once('Options.php');
|
||||||
|
require_once('OptionsApi.php');
|
||||||
|
require_once('Quote.php');
|
||||||
|
require_once('QuoteApi.php');
|
||||||
|
require_once('Route.php');
|
||||||
|
require_once('RouteApi.php');
|
||||||
|
require_once('AutocabApi.php');
|
||||||
|
require_once('autocab/Autocab.php');
|
||||||
|
require_once('Booking.php');
|
||||||
|
require_once('../trips/SGBikeApi.php');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"],-strlen($httpAuthToken))!=$httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"],-strlen($httpAuthToken))!=$httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'],'/api/')===false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'],'/'));
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
if ($requestUri[0]=='options') {
|
||||||
|
$api = new OptionsApi($requestUri);
|
||||||
|
}
|
||||||
|
else if ($requestUri[0]=='route') {
|
||||||
|
$api = new RouteApi($requestUri);
|
||||||
|
}
|
||||||
|
else if ($requestUri[0]=='quote') {
|
||||||
|
$api = new QuoteApi($requestUri);
|
||||||
|
}
|
||||||
|
else if ($requestUri[0]=='autocab') {
|
||||||
|
$api = new AutocabApi($requestUri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(Array('error' => 'Invalid API request'));
|
||||||
|
}
|
||||||
|
echo $api->run();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
echo json_encode(Array('error' => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 665 B |
|
After Width: | Height: | Size: 628 B |
@@ -0,0 +1,60 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="swagger-ui.css" >
|
||||||
|
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
html
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after
|
||||||
|
{
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
margin:0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script src="swagger-ui-bundle.js"> </script>
|
||||||
|
<script src="swagger-ui-standalone-preset.js"> </script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "../swagger.php",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
})
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
require('../../../adminsavvy/vendor/autoload.php');
|
||||||
|
$openapi = \OpenApi\scan('.');
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo $openapi->toJson();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/callback/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class AccountApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'account';
|
||||||
|
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error' => 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method GET
|
||||||
|
* Get member record (by id)
|
||||||
|
* http://DOMAIN/trips/1
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/SAVVY/callback/api/account/:id",
|
||||||
|
* summary="Get member account data by its unique ID",
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="id",
|
||||||
|
* in="path",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(ref="#/components/schemas/member_id")
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="200",
|
||||||
|
* description="Members data",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* type="object",
|
||||||
|
* @OA\Schema(ref="#/components/schemas/member_data")
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function viewAction()
|
||||||
|
{
|
||||||
|
//id must be the first parameter after /account/x
|
||||||
|
$id = array_shift($this->requestUri);
|
||||||
|
|
||||||
|
if($id && (int)$id>0){
|
||||||
|
$db = new Db();
|
||||||
|
$member = Callback::getMemberById($db->getConnect(), (int)$id);
|
||||||
|
if(is_array($member) && count($member)>0){
|
||||||
|
return $this->response($member, 200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
'error'=> 'Data not found'
|
||||||
|
), 404);
|
||||||
|
}
|
||||||
|
// * description = "curl -d '{\"member_id\":22,\"last_acct\":\"2019-05-06\",\"count_acct\":1}' -X POST https://svrsavvy.sworks.float.sg/SAVVY/callback/api/account",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/SAVVY/callback/api/account",
|
||||||
|
* summary="Save account data within members record",
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="",
|
||||||
|
* description = "Account callback data",
|
||||||
|
* in="body",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(ref="#/components/schemas/account_request")
|
||||||
|
* ),
|
||||||
|
* @OA\Response(
|
||||||
|
* response="200",
|
||||||
|
* description="Members data",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* type="object",
|
||||||
|
* @OA\Schema(ref="#/components/schemas/member_data")
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$message = "Failed to save data";
|
||||||
|
$member_id = $this->requestParams["member_id"] ?? 0;
|
||||||
|
$last_acct = $this->requestParams["last_acct"] ?? "";
|
||||||
|
$count_acct = $this->requestParams["count_acct"] ?? 0;
|
||||||
|
|
||||||
|
if ($member_id>0 && $last_acct!="" && strtotime($last_acct)>0 && $count_acct>0) {
|
||||||
|
$db = new Db();
|
||||||
|
$member = Callback::getMemberById($db->getConnect(), (int)$member_id);
|
||||||
|
if (isset($member["id"]) && $member["id"]>0) {
|
||||||
|
$result = Callback::updateMember(
|
||||||
|
$db->getConnect(),
|
||||||
|
(int)$member_id,
|
||||||
|
$last_acct,
|
||||||
|
$count_acct);
|
||||||
|
if (is_array($result) && count($result)>0) {
|
||||||
|
return $this->response($result, 200);
|
||||||
|
} else {
|
||||||
|
$message = "Failed to update member";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = "Invalid member id";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$message = "Invalid input $member_id>0 && $last_acct!= $count_acct";
|
||||||
|
}
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Update error"
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteAction()
|
||||||
|
{
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"error" => "Delete error"
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Callback {
|
||||||
|
|
||||||
|
public function getMemberById($db, $id) {
|
||||||
|
$result = array();
|
||||||
|
$db_id = (int)$id;
|
||||||
|
$q = "SELECT * FROM members WHERE id=${db_id}";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMemberByEmail($db, $email) {
|
||||||
|
$result = array();
|
||||||
|
$db_email = pg_escape_string(strtolower($email));
|
||||||
|
$q = "SELECT * FROM members WHERE lower(email)='${db_email}' OR lower(username)='${db_email}'";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$result = $f;
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateMember($db, $member_id, $last_acct, $count_acct) {
|
||||||
|
$result = array();
|
||||||
|
$id = (int)$member_id;
|
||||||
|
$db_last_acct = date("Y-m-d H:i:s",strtotime($last_acct));
|
||||||
|
$db_count_acct = (int)$count_acct;
|
||||||
|
$q = "UPDATE members SET last_acct='${db_last_acct}',count_acct=${db_count_acct} WHERE id=${id}";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_affected_rows($r)) {
|
||||||
|
return Callback::getMemberById($db, $id);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
require_once('../../core/backend.php');
|
||||||
|
require_once('../constants.php');
|
||||||
|
|
||||||
|
require_once('../common/Api.php');
|
||||||
|
require_once('../common/Db.php');
|
||||||
|
|
||||||
|
require_once('Callback.php');
|
||||||
|
require_once('AccountAPI.php');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"],-strlen($httpAuthToken))!=$httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"],-strlen($httpAuthToken))!=$httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'],'/api/')===false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'],'/'));
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
if ($requestUri[0]=='account') {
|
||||||
|
$api = new AccountApi($requestUri);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo json_encode(Array('error' => 'Invalid API request'));
|
||||||
|
}
|
||||||
|
echo $api->run();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
echo json_encode(Array('error' => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Info(
|
||||||
|
* title="Call Backend Endpoint API",
|
||||||
|
* version="0.1",
|
||||||
|
* @OA\Contact(
|
||||||
|
* email="support@float.sg"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="member_id",
|
||||||
|
* type="integer",
|
||||||
|
* format="int64",
|
||||||
|
* description="The unique identifier of a member in our system"
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="account_request",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(
|
||||||
|
* property="member_id",
|
||||||
|
* description="The unique identifier of a member in our system",
|
||||||
|
* type="int",
|
||||||
|
* format="int64",
|
||||||
|
* example=22
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="last_acct",
|
||||||
|
* description="Last date of the account connection",
|
||||||
|
* type="string",
|
||||||
|
* format="date-time",
|
||||||
|
* example="2019-05-06"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="count_acct",
|
||||||
|
* description="Count of the account items",
|
||||||
|
* type="int",
|
||||||
|
* format="int64",
|
||||||
|
* example=1
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="member_data",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(
|
||||||
|
* property="id",
|
||||||
|
* description="The unique identifier of a member in our system",
|
||||||
|
* type="int",
|
||||||
|
* format="int64",
|
||||||
|
* example=22
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="last_acct",
|
||||||
|
* description="Last date of the account connection",
|
||||||
|
* type="string",
|
||||||
|
* format="date-time",
|
||||||
|
* example="2019-05-06"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="count_acct",
|
||||||
|
* description="Count of the account items",
|
||||||
|
* type="int",
|
||||||
|
* format="int64",
|
||||||
|
* example=1
|
||||||
|
* ),
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
After Width: | Height: | Size: 665 B |
|
After Width: | Height: | Size: 628 B |
@@ -0,0 +1,60 @@
|
|||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="swagger-ui.css" >
|
||||||
|
<link rel="icon" type="image/png" href="favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style>
|
||||||
|
html
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after
|
||||||
|
{
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
margin:0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script src="swagger-ui-bundle.js"> </script>
|
||||||
|
<script src="swagger-ui-standalone-preset.js"> </script>
|
||||||
|
<script>
|
||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "../swagger.php",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
})
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?php
|
||||||
|
require('../../../adminsavvy/vendor/autoload.php');
|
||||||
|
$openapi = \OpenApi\scan('.');
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
echo $openapi->toJson();
|
||||||
|
?>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/carpool/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Carpool {
|
||||||
|
|
||||||
|
|
||||||
|
public function getCarpoolStatus($db, $gpsdb, $data) {
|
||||||
|
|
||||||
|
$member_id = (int) $data['member_id'];
|
||||||
|
if ($member_id < 1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// get user email
|
||||||
|
$q = "select username from members WHERE id=${member_id};";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
while ($f = pg_fetch_assoc($r)) {
|
||||||
|
// get user email
|
||||||
|
$user_email = "";
|
||||||
|
// if not found return error, weird
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the sent invites
|
||||||
|
$q = "select c.id, c.member_id, c.card_id, c.pool, c.status, c.added, c.updated, cf.firstname, cf.lastname, cf.email, cf.status, cf.accept_status, cf.pool_status
|
||||||
|
from members_carpool c
|
||||||
|
join members_carpool_friends cf on c.id = cf.carpool_id
|
||||||
|
WHERE member_id = ${member_id};";
|
||||||
|
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
while ($f = pg_fetch_assoc($r)) {
|
||||||
|
// get user sent invites
|
||||||
|
$sent_invites = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the received invites
|
||||||
|
$q = "select id, carpool_id,email, status, accept_status, pool_status, added, updated from members_carpool_friends where email = '${user_email}';";
|
||||||
|
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
while ($f = pg_fetch_assoc($r)) {
|
||||||
|
// get user received invites
|
||||||
|
$received_invites = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'sent_invites' => $sent_invites,
|
||||||
|
'received_invites' => $received_invites,
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
CARPOOL AND POINT
|
||||||
|
*/
|
||||||
|
include '../../core/backend.php';
|
||||||
|
include_once '../config.php';
|
||||||
|
include_once '../constants.php';
|
||||||
|
include '../formarter.php';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$endpoints = array(
|
||||||
|
'carpooltrack' => array('POST'),
|
||||||
|
'another' => array('POST')
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//*
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
//*/
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["authorization"]) || substr($headers["authorization"], -strlen($httpAuthToken)) != $httpAuthToken) &&
|
||||||
|
(!isset($headers["Authorization"]) || substr($headers["Authorization"], -strlen($httpAuthToken)) != $httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$endpoint = strtolower(str_replace('/SAVVY/carpool/', '', strtok($_SERVER['REQUEST_URI'], '?')));
|
||||||
|
|
||||||
|
$id = 0; // update, get & delete actions require ID
|
||||||
|
if (substr($endpoint, 0, 19) == 'gettransportrequest' || substr($endpoint, 0, 13) == 'updateprofile') {
|
||||||
|
$endpoint = strtok($endpoint, '/');
|
||||||
|
$id = strtok('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($endpoints[$endpoint])) {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
header('Status: 400 Bad Request');
|
||||||
|
echo "{\"status\":\"Invalid endpoint url\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$methods = $endpoints[$endpoint];
|
||||||
|
|
||||||
|
if (array_search($_SERVER['REQUEST_METHOD'], $methods) === false) {
|
||||||
|
header('HTTP/1.1 405 Method Not Allowed');
|
||||||
|
header('Status: 405 Method Not Allowed');
|
||||||
|
echo "{\"status\":\"Invalid request method\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
include '../rest_api.php';
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||||
|
if ($endpoint == "uploadfile") {
|
||||||
|
upload_file_call();
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$raw_json = file_get_contents("php://input");
|
||||||
|
$raw_array = json_decode($raw_json, true);
|
||||||
|
$in = flatten($raw_array);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] == "PUT") {
|
||||||
|
parse_str(file_get_contents('php://input'), $in);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt the input
|
||||||
|
if (isset($in['encrypted_payload'])) {
|
||||||
|
$payload = openssl_decrypt(hex2bin($in['encrypted_payload']), $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV);
|
||||||
|
unset($in['encrypted_payload']);
|
||||||
|
$in = array_merge($in, json_decode($payload, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get who is connecting IP
|
||||||
|
$in["loc"] = getRemoteIpAddress(); // Do not use $_SERVER["REMOTE_ADDR"]; it is INVALID!!!
|
||||||
|
$in["pid"] = 100;
|
||||||
|
// override session parameter(s) with the header value
|
||||||
|
$in["session"] = $headers["x-session-id"];
|
||||||
|
$in["sessionid"] = $headers["x-session-id"];
|
||||||
|
|
||||||
|
$out = array();
|
||||||
|
|
||||||
|
$extension_call = true; // by defualt unless specified at the gate
|
||||||
|
switch ($endpoint) {
|
||||||
|
|
||||||
|
case 'carpooltrack': $in["action"] = SAVVY_CARPOOL_TRACK;
|
||||||
|
$out["status"] = "Got here anyway";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$in["pid"] = 100;
|
||||||
|
|
||||||
|
//file_put_contents("in_debug.log", $in); // DEBUG
|
||||||
|
//external_internal_call($in, $out);
|
||||||
|
|
||||||
|
function Fextension_call($in, &$out) {
|
||||||
|
global $savvyext;
|
||||||
|
foreach ($in as $key=>$val) {
|
||||||
|
if ($val!="" && is_string($val)) {
|
||||||
|
$in[$key] = pg_escape_string($val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$out = $savvyext->savvyext_api($in);
|
||||||
|
return $out["retval"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($extension_call == true) {
|
||||||
|
Fextension_call($in, $out);
|
||||||
|
}
|
||||||
|
|
||||||
|
header("HTTP/1.1 200 OK");
|
||||||
|
header("Status: 200 OK");
|
||||||
|
//$out = array_merge($in, $out); // DEBUG
|
||||||
|
$payload = json_encode(processOutJson($in, $out));
|
||||||
|
echo $payload."\n";
|
||||||
|
//$encrypted_payload = bin2hex(openssl_encrypt($payload, $encryptionAlg, $encryptionKey, OPENSSL_RAW_DATA, $encryptionIV));
|
||||||
|
//echo "{\"payload\": \"${encrypted_payload}\"}";
|
||||||
|
exit();
|
||||||
|
|
||||||
|
function flatten($data, $parentkey = "") {
|
||||||
|
$result = array();
|
||||||
|
foreach ($data as $key => $val) {
|
||||||
|
if (is_array($val)) {
|
||||||
|
$result = array_merge($result, flatten($val, $parentkey . $key . "_"));
|
||||||
|
} else {
|
||||||
|
$result[$parentkey . $key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function getRemoteIpAddress() {
|
||||||
|
$ip = NULL;
|
||||||
|
if (!empty($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)) {
|
||||||
|
$ip = trim($_SERVER['HTTP_CLIENT_IP']);
|
||||||
|
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)) {
|
||||||
|
$ip = trim($_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||||
|
} else {
|
||||||
|
// Will not make much sense since we are behind the WAF reverse proxy
|
||||||
|
$ip = trim($_SERVER['REMOTE_ADDR']);
|
||||||
|
}
|
||||||
|
putenv("REMOTE_ADDR=${ip}");
|
||||||
|
$_ENV["REMOTE_ADDR"] = $ip;
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/cityservices/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class CityServiceApi extends Api {
|
||||||
|
|
||||||
|
public $apiName = 'cityservices';
|
||||||
|
|
||||||
|
public function __construct($requestUri, $encryption=true) {
|
||||||
|
$encryption = false; // We do not need encryption for this class
|
||||||
|
parent::__construct($requestUri, $encryption);
|
||||||
|
//$this->encryption = $encryption;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Get(
|
||||||
|
* path="/SAVVY/touristattraction/api/touristattraction?city={city}&country={country}",
|
||||||
|
* security={{"token": {}}},
|
||||||
|
* summary="Get geofenceareacity by city and country code",
|
||||||
|
* @OA\Response(
|
||||||
|
* response="200",
|
||||||
|
* description="Found geofence area city",
|
||||||
|
* @OA\JsonContent(
|
||||||
|
* type="object"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function indexAction() {
|
||||||
|
$message = 'No locations found';
|
||||||
|
|
||||||
|
$city = $this->requestParams['city'] ?? '';
|
||||||
|
$results = [];
|
||||||
|
$res_status = 404;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (empty($city)) {
|
||||||
|
throw new Exception("Invalid city");
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = new Db();
|
||||||
|
list($results, $err) = CityServiceModel::get( $db->getConnect(), $city );
|
||||||
|
if (!empty($err)) {
|
||||||
|
$result = [
|
||||||
|
"services" => NULL,
|
||||||
|
"error" => $err
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
$result = [
|
||||||
|
"services" => $results,
|
||||||
|
];
|
||||||
|
$res_status = 200;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message = $e->getMessage();
|
||||||
|
$result = [
|
||||||
|
"services" => NULL,
|
||||||
|
"error" => $message
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response($result, $res_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viewAction() {}
|
||||||
|
|
||||||
|
public function createAction() {}
|
||||||
|
|
||||||
|
public function updateAction() {}
|
||||||
|
|
||||||
|
public function deleteAction() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class CityServiceModel {
|
||||||
|
|
||||||
|
public static function get($db, $city) {
|
||||||
|
$city = (int)$city;
|
||||||
|
|
||||||
|
// Step 1: Load address
|
||||||
|
$q = "SELECT *FROM city_services WHERE city_id = ${city}";
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
if ($r && pg_num_rows($r)) {
|
||||||
|
$results = pg_fetch_all($r);
|
||||||
|
} else {
|
||||||
|
return [NULL, "Services not found"];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$results, NULL];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once '../../core/backend.php';
|
||||||
|
|
||||||
|
require_once '../common/Api.php';
|
||||||
|
require_once '../common/Db.php';
|
||||||
|
|
||||||
|
require_once 'CityServiceModel.php';
|
||||||
|
require_once 'CityServiceApi.php';
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"], -strlen($httpAuthToken)) != $httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"], -strlen($httpAuthToken)) != $httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'], '/api/') === false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($requestUri[0] == 'cityservices') {
|
||||||
|
$api = new CityServiceApi($requestUri, false);
|
||||||
|
}
|
||||||
|
echo $api->run();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo json_encode(array('error' => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Info(
|
||||||
|
* title="Geofence Area City Endpoint API",
|
||||||
|
* version="1.0",
|
||||||
|
* @OA\Contact(
|
||||||
|
* email="support@float.sg"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @OA\SecurityScheme(
|
||||||
|
* securityScheme="token",
|
||||||
|
* type="apiKey",
|
||||||
|
* name="Authorization",
|
||||||
|
* in="header"
|
||||||
|
* )
|
||||||
|
*/
|
||||||
@@ -0,0 +1,415 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once('../common/vendor/autoload.php');
|
||||||
|
|
||||||
|
use Phpfastcache\CacheManager;
|
||||||
|
use Phpfastcache\Drivers\Redis\Config;
|
||||||
|
|
||||||
|
abstract class Api
|
||||||
|
{
|
||||||
|
public $apiName = ''; //trips
|
||||||
|
|
||||||
|
protected $method = ''; //GET|POST|PUT|DELETE
|
||||||
|
|
||||||
|
public $requestUri = [];
|
||||||
|
public $requestParams = [];
|
||||||
|
public $requestHeaders = [];
|
||||||
|
public $requestWhitelist = [];
|
||||||
|
public $clientIP = null;
|
||||||
|
|
||||||
|
protected $action = '';
|
||||||
|
//Method name to execute
|
||||||
|
protected $encryption = true;
|
||||||
|
|
||||||
|
public $cacheWhitelist = [];
|
||||||
|
public $cache;
|
||||||
|
public $cacheEnabled = false;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct($requestUri, $encryption=true) {
|
||||||
|
global $savvyext;
|
||||||
|
header("Access-Control-Allow-Orgin: *");
|
||||||
|
header("Access-Control-Allow-Methods: *");
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
|
||||||
|
//GET parameter array separated by slash
|
||||||
|
//$this->requestUri = explode('/', trim($_SERVER['REQUEST_URI'],'/'));
|
||||||
|
$this->requestUri = $requestUri;
|
||||||
|
|
||||||
|
if (is_array($requestUri) && count($requestUri)>1) {
|
||||||
|
if (($pos=strpos($requestUri[1],'?'))!==false) {
|
||||||
|
$requestUri[1] = substr($requestUri[1],1+$pos);
|
||||||
|
}
|
||||||
|
parse_str($requestUri[1],$this->requestParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->encryption = $encryption;
|
||||||
|
|
||||||
|
//Define the request method
|
||||||
|
$this->method = $_SERVER['REQUEST_METHOD'];
|
||||||
|
if ($this->method == 'POST' && array_key_exists('HTTP_X_HTTP_METHOD', $_SERVER)) {
|
||||||
|
if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'DELETE') {
|
||||||
|
$this->method = 'DELETE';
|
||||||
|
}
|
||||||
|
else if ($_SERVER['HTTP_X_HTTP_METHOD'] == 'PUT') {
|
||||||
|
$this->method = 'PUT';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Exception("Unexpected Header");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->cacheEnabled = ($savvyext->cfgReadLong('cache.enabled') != NULL && $savvyext->cfgReadLong('cache.enabled') == 1);
|
||||||
|
if ($this->cacheEnabled ) {
|
||||||
|
$hostsString = $savvyext->cfgReadChar( 'cache.servers' );
|
||||||
|
$serverConf = [];
|
||||||
|
if ( ! empty( $hostsString ) ) {
|
||||||
|
$hostsInfo = explode( ",", $hostsString );
|
||||||
|
foreach ( $hostsInfo as $hostInfo ) {
|
||||||
|
$hostInfoItems = explode( ":", $hostInfo );
|
||||||
|
if ( count( $hostInfoItems ) > 0 ) {
|
||||||
|
$serverConf = [
|
||||||
|
'host' => $hostInfoItems[0],
|
||||||
|
'port' => $hostInfoItems[1] ? intval( $hostInfoItems[1] ) : 6379,
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( count( $serverConf ) != 0 ) {
|
||||||
|
$conf = new Config($serverConf);
|
||||||
|
$this->cache = CacheManager::getInstance( 'redis', $conf );
|
||||||
|
} else {
|
||||||
|
$this->cacheEnabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->method=="POST") {
|
||||||
|
$raw_json = file_get_contents("php://input");
|
||||||
|
$this->requestParams = json_decode($raw_json, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->method == "PUT") {
|
||||||
|
// Do we do key=val&key=val ?
|
||||||
|
$raw_json = file_get_contents("php://input");
|
||||||
|
if (strpos($raw_json, 'encrypted_payload') !== false) {
|
||||||
|
$this->requestParams = json_decode($raw_json, true);
|
||||||
|
} else {
|
||||||
|
parse_str($raw_json, $this->requestParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We can inspect the headers later on
|
||||||
|
$this->loadRequestHeaders();
|
||||||
|
|
||||||
|
// Decrypt the input
|
||||||
|
if (isset($this->requestParams['encrypted_payload'])) {
|
||||||
|
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
|
||||||
|
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
|
||||||
|
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
|
||||||
|
$payload = openssl_decrypt(
|
||||||
|
hex2bin(
|
||||||
|
$this->requestParams['encrypted_payload']
|
||||||
|
),
|
||||||
|
$encryptionAlg,
|
||||||
|
$encryptionKey,
|
||||||
|
OPENSSL_RAW_DATA,
|
||||||
|
$encryptionIV
|
||||||
|
);
|
||||||
|
unset($this->requestParams['encrypted_payload']);
|
||||||
|
if (is_array($this->requestParams) && count($this->requestParams)>0) {
|
||||||
|
$this->requestParams = array_merge($this->requestParams, json_decode($payload, true));
|
||||||
|
} else {
|
||||||
|
$data = json_decode($payload, true);
|
||||||
|
$this->requestParams = is_array($data) ? $data : [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No action taken YET!
|
||||||
|
// TODO: delegate the decision into controller, the default (unset) behaviour is to block
|
||||||
|
protected function checkRequestHeaders($db, $action) {
|
||||||
|
error_log('Checking '.$this->apiName.'::'.$action.'...');
|
||||||
|
if (array_key_exists($action,$this->requestWhitelist)) {
|
||||||
|
error_log('whitelisted!');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$sessionID = null;
|
||||||
|
$deviceToken = null;
|
||||||
|
if (array_key_exists("x-session-id",$this->requestHeaders)) {
|
||||||
|
$sessionID = $this->requestHeaders["x-session-id"];
|
||||||
|
}
|
||||||
|
if (array_key_exists("x-devicetoken",$this->requestHeaders)) {
|
||||||
|
$deviceToken = $this->requestHeaders["x-devicetoken"];
|
||||||
|
}
|
||||||
|
error_log('X-Session-ID: '.$sessionID);
|
||||||
|
error_log('X-DeviceToken: '.$deviceToken);
|
||||||
|
// Step 1a: Get member_id by X-DeviceToken
|
||||||
|
$header_member_id = 0;
|
||||||
|
$conn = $db->getConnect();
|
||||||
|
$q = "SELECT * FROM members_devices WHERE access_token='".pg_escape_string($deviceToken)."'";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$header_member_id = $f['member_id'];
|
||||||
|
$q = "UPDATE members_devices SET updated=now(), status=1 WHERE id=".((int)$f['id'])." RETURNING *";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
error_log('Status updated at: '.$f['updated']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($header_member_id<1) {
|
||||||
|
//return false; //throw new RuntimeException('Invalid header member ID', 500);
|
||||||
|
}
|
||||||
|
// Step 1b: Get member_id by X-Session-ID
|
||||||
|
$session_member_id = 0;
|
||||||
|
$q = "SELECT * FROM members_session WHERE session='".pg_escape_string($sessionID)."'";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$session_member_id = $f['member_id'];
|
||||||
|
if ($header_member_id<1) {
|
||||||
|
$q = "UPDATE members_devices SET updated=now(), status=1 WHERE id=".((int)$f['id'])." RETURNING *";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
error_log('Status updated at: '.$f['updated']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($session_member_id<1) {
|
||||||
|
//return false; //throw new RuntimeException('Invalid session member ID', 500);
|
||||||
|
}
|
||||||
|
// Step 2: Get member_id from $this->requestParams
|
||||||
|
$request_member_id = 0;
|
||||||
|
if (array_key_exists('member_id',$this->requestParams)) {
|
||||||
|
$request_member_id = (int)$this->requestParams['member_id'];
|
||||||
|
}
|
||||||
|
error_log('member_id[request] = '.$request_member_id);
|
||||||
|
error_log('member_id[token] = '.$header_member_id);
|
||||||
|
error_log('member_id[session] = '.$session_member_id);
|
||||||
|
if ($request_member_id != $session_member_id && $session_member_id>0) {
|
||||||
|
//$request_member_id = $session_member_id;
|
||||||
|
$this->requestParams['member_id'] = $session_member_id;
|
||||||
|
}
|
||||||
|
// Step 3a: Match Step 1 and 2 result
|
||||||
|
if ($request_member_id>0) {
|
||||||
|
// Step 3b: Fallback to X-Session-ID?
|
||||||
|
if ($request_member_id!=$header_member_id || $request_member_id!=$session_member_id) {
|
||||||
|
//return false; //throw new RuntimeException('Invalid request member ID', 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function loadRequestHeaders() {
|
||||||
|
$this->requestHeaders = [];
|
||||||
|
foreach (getallheaders() as $key=>$val) {
|
||||||
|
// https://cloud.google.com/load-balancing/docs/https/
|
||||||
|
// After September 30, HTTP(S) Load Balancers will convert HTTP/1.1 header names to lowercase
|
||||||
|
// in the request and response directions; header values will not be affected.
|
||||||
|
//error_log('DEBUG: "'.$key.'" => "'.$val.'"');
|
||||||
|
$this->requestHeaders[strtolower($key)] = $val;
|
||||||
|
}
|
||||||
|
return count($this->requestHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function checkThrottling($db) {
|
||||||
|
if (!empty($_SERVER['HTTP_CLIENT_IP']) && filter_var($_SERVER['HTTP_CLIENT_IP'], FILTER_VALIDATE_IP)) {
|
||||||
|
$ip = pg_escape_string($_SERVER['HTTP_CLIENT_IP']);
|
||||||
|
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']) && filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP)) {
|
||||||
|
$ip = pg_escape_string($_SERVER['HTTP_X_FORWARDED_FOR']);
|
||||||
|
} else {
|
||||||
|
// Will not make much sense since we are behind the reverse proxy
|
||||||
|
$ip = pg_escape_string($_SERVER['REMOTE_ADDR']);
|
||||||
|
}
|
||||||
|
$this->clientIP = $ip;
|
||||||
|
$lastRec = NULL;
|
||||||
|
$rec = NULL;
|
||||||
|
$conn = $db->getConnect();
|
||||||
|
$q = "SELECT *,(EXTRACT(EPOCH FROM time_last) * 1000)::bigint AS last_ms FROM throttling_ip WHERE ip='${ip}'";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$lastRec = $f;
|
||||||
|
$q = "UPDATE throttling_ip SET total=total+1,time_last=NOW() WHERE ip='${ip}' RETURNING *,(EXTRACT(EPOCH FROM time_last) * 1000)::bigint AS last_ms";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$rec = $f;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$q = "INSERT INTO throttling_ip (ip) VALUES ('${ip}') RETURNING *,(EXTRACT(EPOCH FROM time_last) * 1000)::bigint AS last_ms";
|
||||||
|
$r = pg_query($conn, $q);
|
||||||
|
if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
|
||||||
|
$rec = $f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$lastRec && $rec && is_array($rec) && count($rec)>0) {
|
||||||
|
error_log('New IP spotted!');
|
||||||
|
return true; // New record - never seen this IP before...
|
||||||
|
}
|
||||||
|
if (!$lastRec && (!$rec || !is_array($rec) || !count($rec)<1)) {
|
||||||
|
// Failed to insert new record
|
||||||
|
error_log('Error: not throttling!');
|
||||||
|
return true; // TODO: should we fail?
|
||||||
|
}
|
||||||
|
// Compare $lastRec to $rec
|
||||||
|
if (($rec["last_ms"]-$lastRec["last_ms"]) > 10) {
|
||||||
|
error_log('Not throttle!');
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
error_log('Throttle: ' . $rec["last_ms"] . " - " . $lastRec["last_ms"] . " = ".($rec["last_ms"]-$lastRec["last_ms"]));
|
||||||
|
return true; // Throttle if less than a second within
|
||||||
|
}
|
||||||
|
return true; // OK
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function isActionCached($action) {
|
||||||
|
error_log('Check is it '.$this->apiName.'::'.$action.' could be cached...');
|
||||||
|
if (array_key_exists($action,$this->cacheWhitelist) || in_array($action,$this->cacheWhitelist)) {
|
||||||
|
$ttl = $this->cacheWhitelist[$action]['ttl'] ?? 60;
|
||||||
|
if ($ttl == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
error_log('whitelisted!');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run() {
|
||||||
|
|
||||||
|
//The first 2 elemets of URI array must by "api" and table name
|
||||||
|
if(array_shift($this->requestUri) !== $this->apiName){
|
||||||
|
throw new RuntimeException('API Not Found', 404);
|
||||||
|
}
|
||||||
|
//Select the action to execute
|
||||||
|
$this->action = $this->getAction();
|
||||||
|
|
||||||
|
$db = new Db();
|
||||||
|
// Inspect throttling
|
||||||
|
if (!$this->checkThrottling($db)) {
|
||||||
|
unset($db);
|
||||||
|
throw new RuntimeException('Too Many Requests', 429);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inspect header
|
||||||
|
if (!$this->checkRequestHeaders($db, $this->action)) {
|
||||||
|
unset($db);
|
||||||
|
throw new RuntimeException('Request check failed', 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($db);
|
||||||
|
|
||||||
|
//If the method (action) defined in the child API class
|
||||||
|
if (method_exists($this, $this->action)) {
|
||||||
|
|
||||||
|
$result = null;
|
||||||
|
|
||||||
|
if( $this->cacheEnabled && $this->isActionCached($this->action)) {
|
||||||
|
$key = $this->getCacheKey();
|
||||||
|
$ttl = $this->cacheWhitelist[$this->action]['ttl'] ?? 300;
|
||||||
|
$cachedString = $this->cache->getItem($key);
|
||||||
|
$result = $cachedString->get();
|
||||||
|
if (!is_null($result)) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
$result = $this->{
|
||||||
|
$this->action
|
||||||
|
}
|
||||||
|
();
|
||||||
|
if($this->storeInCache()) {
|
||||||
|
$cachedString->set($result)->expiresAfter($ttl);
|
||||||
|
$this->cache->save($cachedString);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
} else {
|
||||||
|
return $this->{
|
||||||
|
$this->action
|
||||||
|
}
|
||||||
|
();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new RuntimeException('Invalid Method', 405);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function response($data, $status = 500) {
|
||||||
|
global $savvyext;
|
||||||
|
header("HTTP/1.1 " . $status . " " . $this->requestStatus($status));
|
||||||
|
if ($this->encryption) {
|
||||||
|
// encrypt data
|
||||||
|
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
|
||||||
|
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
|
||||||
|
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
|
||||||
|
$payload = json_encode($data);
|
||||||
|
$encrypted_payload = bin2hex(
|
||||||
|
openssl_encrypt(
|
||||||
|
$payload,
|
||||||
|
$encryptionAlg,
|
||||||
|
$encryptionKey,
|
||||||
|
OPENSSL_RAW_DATA,
|
||||||
|
$encryptionIV
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$data = array(); // Comment out to see the data
|
||||||
|
$data["payload"] = $encrypted_payload;
|
||||||
|
}
|
||||||
|
return json_encode($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function requestStatus($code) {
|
||||||
|
$status = array(
|
||||||
|
200 => 'OK',
|
||||||
|
404 => 'Not Found',
|
||||||
|
405 => 'Method Not Allowed',
|
||||||
|
500 => 'Internal Server Error',
|
||||||
|
);
|
||||||
|
return ($status[$code])?$status[$code]:$status[500];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getAction()
|
||||||
|
{
|
||||||
|
$method = $this->method;
|
||||||
|
switch ($method) {
|
||||||
|
case 'GET':
|
||||||
|
$pos = strpos($this->requestUri[0],'?');
|
||||||
|
if ($pos!==false && $pos==0) {
|
||||||
|
// We want to get "all"
|
||||||
|
$this->requestUri[0] = "all".$this->requestUri[0];
|
||||||
|
}
|
||||||
|
$tok = strtok($this->requestUri[0],'?');
|
||||||
|
if($tok===false || $tok=='all'){
|
||||||
|
return 'indexAction';
|
||||||
|
} else {
|
||||||
|
return 'viewAction';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'POST':
|
||||||
|
return 'createAction';
|
||||||
|
break;
|
||||||
|
case 'PUT':
|
||||||
|
return 'updateAction';
|
||||||
|
break;
|
||||||
|
case 'DELETE':
|
||||||
|
return 'deleteAction';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected function indexAction();
|
||||||
|
abstract protected function viewAction();
|
||||||
|
abstract protected function createAction();
|
||||||
|
abstract protected function updateAction();
|
||||||
|
abstract protected function deleteAction();
|
||||||
|
|
||||||
|
protected function getCacheKey() {
|
||||||
|
return hash('md5', $this->method.'|'.$this->apiName.'|'.$this->action.'|'.json_encode($this->requestParams));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function storeInCache() {
|
||||||
|
return http_response_code() === 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Db {
|
||||||
|
|
||||||
|
private $conn;
|
||||||
|
private $conn_gps;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnect() {
|
||||||
|
global $savvyext;
|
||||||
|
if ($this->conn==NULL || !pg_version($this->conn)) {
|
||||||
|
$db_host = $savvyext->cfgReadChar('database.host');
|
||||||
|
$db_name = $savvyext->cfgReadChar('database.name');
|
||||||
|
$db_user = $savvyext->cfgReadChar('database.user');
|
||||||
|
$db_pass = $savvyext->cfgReadChar('database.pass');
|
||||||
|
$db_port = $savvyext->cfgReadLong('database.port');
|
||||||
|
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
|
||||||
|
$this->conn = pg_connect($connstr);
|
||||||
|
}
|
||||||
|
return $this->conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getConnectGPS() {
|
||||||
|
global $savvyext;
|
||||||
|
if ($this->conn_gps==NULL || !pg_version($this->conn_gps)) {
|
||||||
|
$db_host = $savvyext->cfgReadChar('gpsdatabase.host');
|
||||||
|
$db_name = $savvyext->cfgReadChar('gpsdatabase.name');
|
||||||
|
$db_user = $savvyext->cfgReadChar('gpsdatabase.user');
|
||||||
|
$db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
|
||||||
|
$db_port = $savvyext->cfgReadLong('gpsdatabase.port');
|
||||||
|
$connstr = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
|
||||||
|
$this->conn_gps = pg_connect($connstr);
|
||||||
|
}
|
||||||
|
return $this->conn_gps;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
if(!empty($this->conn)){
|
||||||
|
pg_close($this->conn);
|
||||||
|
}
|
||||||
|
if(!empty($this->conn_gps)){
|
||||||
|
pg_close($this->conn_gps);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// vi:ts=2
|
||||||
|
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Gis {
|
||||||
|
|
||||||
|
final public static function haversineDistanceBetweenTwoGpsCoordinates($lat1, $lon1, $lat2, $lon2, $unit="M") {
|
||||||
|
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$theta = $lon1 - $lon2;
|
||||||
|
$dist = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
|
||||||
|
$dist = acos($dist);
|
||||||
|
$dist = rad2deg($dist);
|
||||||
|
$miles = $dist * 60 * 1.1515;
|
||||||
|
$unit = strtoupper($unit);
|
||||||
|
|
||||||
|
if ($unit == "K") {
|
||||||
|
return ($miles * 1.609344);
|
||||||
|
} else if ($unit == "N") {
|
||||||
|
return ($miles * 0.8684);
|
||||||
|
} else {
|
||||||
|
return $miles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function cosinesDistanceBetweenTwoGpsCoordinates($lat1, $lon1, $lat2, $lon2, $unit="M") {
|
||||||
|
if (($lat1 == $lat2) && ($lon1 == $lon2)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$dist = acos(sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon2 - $lon1))) * 6371;
|
||||||
|
$unit = strtoupper($unit);
|
||||||
|
if ($unit == "K") {
|
||||||
|
return $dist;
|
||||||
|
} else {
|
||||||
|
return $dist/1.609344;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getCityServicesAvailableForCoordinates($db_conn ,$lat, $lng, $providers=[]) {
|
||||||
|
return self::getServicesAvailableForCoordinates($db_conn, self::GET_CITY_PROVIDERS_IN_RADIUS, $lat, $lng, $providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
final public static function getCountryServicesAvailableForCoordinates($db_conn ,$lat, $lng, $providers=[]) {
|
||||||
|
return self::getServicesAvailableForCoordinates($db_conn, self::GET_COUNTRY_PROVIDERS_IN_RADIUS, $lat, $lng, $providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected static function getServicesAvailableForCoordinates($db_conn, $q, $lat, $lng, $providers=[]) {
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
$params = [ $lng, $lat];
|
||||||
|
|
||||||
|
if (count($providers)) {
|
||||||
|
$params[]="{".implode(",", $providers). "}";
|
||||||
|
$q = $q."AND transport_provider_id = ANY($3)";
|
||||||
|
}
|
||||||
|
$req_result = pg_query_params($db_conn, $q, $params);
|
||||||
|
if (!$req_result) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
while ($row = pg_fetch_assoc($req_result)) {
|
||||||
|
array_push($result, $row);
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GET_CITY_PROVIDERS_IN_RADIUS = "
|
||||||
|
SELECT cs.* FROM geofence_area_city gac
|
||||||
|
LEFT JOIN city_services cs ON gac.id = cs.city_id
|
||||||
|
WHERE
|
||||||
|
ST_DistanceSphere(location::geometry, ST_SetSRID(ST_MakePoint($1,$2),4326)) <= radius
|
||||||
|
";
|
||||||
|
|
||||||
|
const GET_COUNTRY_PROVIDERS_IN_RADIUS = "
|
||||||
|
SELECT cs.* FROM geofence_area_country gac
|
||||||
|
LEFT JOIN country_services cs ON gac.id = cs.country_id
|
||||||
|
WHERE
|
||||||
|
ST_DistanceSphere(location::geometry, ST_SetSRID(ST_MakePoint($1,$2),4326)) <= radius
|
||||||
|
";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
# Imports the Google Cloud client libraries
|
||||||
|
use Google\ApiCore\ApiException;
|
||||||
|
use Google\Cloud\Kms\V1\CryptoKey;
|
||||||
|
use Google\Cloud\Kms\V1\CryptoKey\CryptoKeyPurpose;
|
||||||
|
use Google\Cloud\Kms\V1\KeyManagementServiceClient;
|
||||||
|
use Google\Cloud\Kms\V1\KeyRing;
|
||||||
|
|
||||||
|
class GoogleKMS {
|
||||||
|
|
||||||
|
private $client;
|
||||||
|
private $projectId;
|
||||||
|
private $authFile;
|
||||||
|
|
||||||
|
private $keyRing = NULL;
|
||||||
|
private $keyRingId = NULL;
|
||||||
|
private $keyRingName = NULL;
|
||||||
|
private $keyName = NULL;
|
||||||
|
private $cryptoKey = NULL;
|
||||||
|
private $location = 'global';
|
||||||
|
|
||||||
|
public function __construct($projectId, $authFile, $keyRingId=NULL, $keyId=NULL) {
|
||||||
|
// Your Google Cloud Platform project ID
|
||||||
|
$this->projectId = $projectId; // 'float-app-224118';
|
||||||
|
// The file path to credentials JSON
|
||||||
|
//error_log($authFile);
|
||||||
|
putenv("GOOGLE_APPLICATION_CREDENTIALS=${authFile}");
|
||||||
|
apache_setenv("GOOGLE_APPLICATION_CREDENTIALS",$authFile,true);
|
||||||
|
$this->authFile = $authFile; // './float-app-224118-52ef1783d2c5.json';
|
||||||
|
// Instantiates a client
|
||||||
|
$this->client = new KeyManagementServiceClient([
|
||||||
|
'projectId' => $projectId,
|
||||||
|
'keyFile' => json_decode(file_get_contents($authFile), true)
|
||||||
|
]);
|
||||||
|
if ($keyRingId!=NULL) {
|
||||||
|
$this->createKeyring($keyRingId);
|
||||||
|
if ($keyId!=NULL) {
|
||||||
|
$this->createCryptokey($keyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createKeyring($keyRingId) {
|
||||||
|
try {
|
||||||
|
$locationName = $this->client::locationName(
|
||||||
|
$this->projectId,
|
||||||
|
$this->location
|
||||||
|
);
|
||||||
|
$keyRingName = $this->client::keyRingName(
|
||||||
|
$this->projectId,
|
||||||
|
$this->location,
|
||||||
|
$keyRingId
|
||||||
|
);
|
||||||
|
$this->keyRing = $this->client->getKeyRing($keyRingName);
|
||||||
|
$this->keyRingId = $keyRingId;
|
||||||
|
$this->keyRingName = $keyRingName;
|
||||||
|
} catch (ApiException $e) {
|
||||||
|
if ($e->getStatus() === 'NOT_FOUND') {
|
||||||
|
$this->keyRing = new KeyRing();
|
||||||
|
$this->keyRing->setName($keyRingName);
|
||||||
|
$this->client->createKeyRing(
|
||||||
|
$locationName,
|
||||||
|
$keyRingId,
|
||||||
|
$this->keyRing);
|
||||||
|
$this->keyRingId = $keyRingId;
|
||||||
|
$this->keyRingName = $keyRingName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->keyRing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createCryptokey($keyId) {
|
||||||
|
try {
|
||||||
|
$keyName = $this->client::cryptoKeyName(
|
||||||
|
$this->projectId,
|
||||||
|
$this->location,
|
||||||
|
$this->keyRingId,
|
||||||
|
$keyId);
|
||||||
|
$this->cryptoKey = $this->client->getCryptoKey($keyName);
|
||||||
|
$this->keyName = $keyName;
|
||||||
|
} catch (ApiException $e) {
|
||||||
|
if ($e->getStatus() === 'NOT_FOUND') {
|
||||||
|
$this->cryptoKey = new CryptoKey();
|
||||||
|
$this->cryptoKey->setPurpose(CryptoKeyPurpose::ENCRYPT_DECRYPT);
|
||||||
|
$this->cryptoKey = $this->client->createCryptoKey(
|
||||||
|
$this->keyRingName,
|
||||||
|
$keyId,
|
||||||
|
$this->cryptoKey);
|
||||||
|
$this->keyName = $keyName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $this->cryptoKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function encrypt($secret) {
|
||||||
|
$response = $this->client->encrypt($this->keyName, $secret);
|
||||||
|
$cipherText = $response->getCiphertext();
|
||||||
|
return $cipherText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decrypt($cipherText) {
|
||||||
|
$response = $this->client->decrypt($this->keyName, $cipherText);
|
||||||
|
$plainText = $response->getPlaintext();
|
||||||
|
return $plainText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,388 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class GooglePlacesClient
|
||||||
|
{
|
||||||
|
public function get($url)
|
||||||
|
{
|
||||||
|
$curl = curl_init();
|
||||||
|
$options = array(
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_HEADER => false,
|
||||||
|
CURLOPT_SSL_VERIFYPEER => true,
|
||||||
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
|
);
|
||||||
|
curl_setopt_array($curl, $options);
|
||||||
|
$response = curl_exec($curl);
|
||||||
|
if ($error = curl_error($curl))
|
||||||
|
{
|
||||||
|
throw new \Exception('CURL Error: ' . $error);
|
||||||
|
}
|
||||||
|
curl_close($curl);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GooglePlaces
|
||||||
|
{
|
||||||
|
public $client = '';
|
||||||
|
public $sleep = 3;
|
||||||
|
private $key = '';
|
||||||
|
private $base_url = 'https://maps.googleapis.com/maps/api/place';
|
||||||
|
private $method = null;
|
||||||
|
private $response = null;
|
||||||
|
|
||||||
|
public $keyword = null;
|
||||||
|
public $language = 'en';
|
||||||
|
public $location = null;
|
||||||
|
public $output = 'json';
|
||||||
|
public $name = null;
|
||||||
|
public $pagetoken = null;
|
||||||
|
public $radius = null;
|
||||||
|
public $rankby = 'prominence';
|
||||||
|
public $sensor = false;
|
||||||
|
public $types = null;
|
||||||
|
public $placeid = null;
|
||||||
|
public $reference = null;
|
||||||
|
public $opennow = null;
|
||||||
|
public $input = null;
|
||||||
|
|
||||||
|
public $subradius = null;
|
||||||
|
public $getmax = true;
|
||||||
|
private $grid = null;
|
||||||
|
|
||||||
|
private $exceptions = array(
|
||||||
|
'base_url', 'client', 'exceptions', 'getmax', 'grid', 'method',
|
||||||
|
'output', 'pagetoken', 'response', 'sleep', 'subradius',
|
||||||
|
);
|
||||||
|
|
||||||
|
public function __construct($key, $client = false)
|
||||||
|
{
|
||||||
|
$this->key = $key;
|
||||||
|
$this->client = $client ? $client : new GooglePlacesClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
function __set($variable, $value)
|
||||||
|
{
|
||||||
|
// Compensates for mixed variable naming
|
||||||
|
$variable = str_replace('_', '', strtolower($variable));
|
||||||
|
$this->$variable = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($method, $arguments)
|
||||||
|
{
|
||||||
|
$this->output = strtolower($this->output);
|
||||||
|
|
||||||
|
if (!in_array($this->output, array('json', 'xml')))
|
||||||
|
{
|
||||||
|
throw new \Exception('Invalid output, please specify either "json" or "xml".');
|
||||||
|
}
|
||||||
|
|
||||||
|
$method = $this->method = strtolower($method);
|
||||||
|
$url = implode('/', array($this->base_url, $method, $this->output));
|
||||||
|
$parameters = array();
|
||||||
|
$parameters = $this->parameterBuilder($parameters);
|
||||||
|
$parameters = $this->methodChecker($parameters, $method);
|
||||||
|
|
||||||
|
if (!empty($this->subradius))
|
||||||
|
{
|
||||||
|
return $this->subdivide($url, $parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->pagetoken !== null)
|
||||||
|
{
|
||||||
|
$parameters['pagetoken'] = $this->pagetoken;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->queryGoogle($url, $parameters);
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loops through all of our variables to make a parameter list
|
||||||
|
*/
|
||||||
|
private function parameterBuilder($parameters)
|
||||||
|
{
|
||||||
|
foreach (get_object_vars($this) as $variable => $value)
|
||||||
|
{
|
||||||
|
// Except these variables
|
||||||
|
if (!in_array($variable, $this->exceptions))
|
||||||
|
{
|
||||||
|
// Assuming it's not null
|
||||||
|
if ($value !== null)
|
||||||
|
{
|
||||||
|
// Converts boolean to string
|
||||||
|
if (is_bool($value))
|
||||||
|
{
|
||||||
|
$value = $value ? 'true' : 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($variable)
|
||||||
|
{
|
||||||
|
// Allows LatLng to be passed as an array
|
||||||
|
case 'location':
|
||||||
|
if (is_array($value))
|
||||||
|
{
|
||||||
|
// Just in case it's an associative array
|
||||||
|
$value = array_values($value);
|
||||||
|
$value = $value[0] . ',' . $value[1];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Checks that it's a value rank by value
|
||||||
|
case 'rankby':
|
||||||
|
$value = strtolower($value);
|
||||||
|
|
||||||
|
if (!in_array($value, array('prominence', 'distance')))
|
||||||
|
{
|
||||||
|
throw new \Exception('Invalid rank by value, please specify either "prominence" or "distance".');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Allows types to be passed as an array
|
||||||
|
case 'types':
|
||||||
|
if (is_array($value))
|
||||||
|
{
|
||||||
|
$value = implode('|', $value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters[$variable] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* takes the parameters and method to throw exceptions or modify parameters as needed
|
||||||
|
* @todo Method to sanity check passed types
|
||||||
|
*/
|
||||||
|
private function methodChecker($parameters, $method)
|
||||||
|
{
|
||||||
|
if (!isset($parameters['pagetoken']))
|
||||||
|
{
|
||||||
|
switch ($method)
|
||||||
|
{
|
||||||
|
case 'nearbysearch':
|
||||||
|
if (!isset($parameters['location']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify a location before calling nearbysearch().');
|
||||||
|
}
|
||||||
|
elseif (isset($parameters['rankby']))
|
||||||
|
{
|
||||||
|
switch ($parameters['rankby'])
|
||||||
|
{
|
||||||
|
case 'distance':
|
||||||
|
if (!isset($parameters['keyword'])
|
||||||
|
&& !isset($parameters['name'])
|
||||||
|
&& !isset($parameters['types']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You much specify at least one of the following: "keyword", "name", "types".');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($parameters['radius']))
|
||||||
|
{
|
||||||
|
unset($this->radius, $parameters['radius']);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'prominence':
|
||||||
|
if (!isset($parameters['radius']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify a radius.');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'radarsearch':
|
||||||
|
if (!isset($parameters['location']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify a location before calling radarsearch().');
|
||||||
|
}
|
||||||
|
elseif (!isset($parameters['radius']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify a radius.');
|
||||||
|
}
|
||||||
|
elseif (empty($parameters['keyword'])
|
||||||
|
&& empty($parameters['name'])
|
||||||
|
&& empty($parameters['types']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You much specify at least one of the following: "keyword", "name", "types".');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($parameters['rankby']))
|
||||||
|
{
|
||||||
|
unset($this->rankby, $parameters['rankby']);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'details':
|
||||||
|
if (!(isset($parameters['reference'])
|
||||||
|
^ isset($parameters['placeid'])))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify either a "placeid" or a "reference" (but not both) before calling details().');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($parameters['rankby']))
|
||||||
|
{
|
||||||
|
unset($this->rankby, $parameters['rankby']);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'autocomplete':
|
||||||
|
/*if (!isset($parameters['location']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify a location before calling autocomplete().');
|
||||||
|
}
|
||||||
|
elseif (!isset($parameters['radius']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You must specify a radius.');
|
||||||
|
}
|
||||||
|
else*/if (empty($parameters['input']))
|
||||||
|
{
|
||||||
|
throw new \Exception('You much specify the user entered input string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits request via curl, sets the response, then returns the response
|
||||||
|
*/
|
||||||
|
private function queryGoogle($url, $parameters)
|
||||||
|
{
|
||||||
|
if ($this->pagetoken !== null)
|
||||||
|
{
|
||||||
|
$parameters['pagetoken'] = $this->pagetoken;
|
||||||
|
sleep($this->sleep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Couldn't seem to get http_build_query() to work right so...
|
||||||
|
$querystring = '';
|
||||||
|
|
||||||
|
foreach ($parameters as $variable => $value)
|
||||||
|
{
|
||||||
|
if ($querystring != '')
|
||||||
|
{
|
||||||
|
$querystring .= '&';
|
||||||
|
}
|
||||||
|
|
||||||
|
$querystring .= $variable . '=' . urlencode($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->client->get($url . '?' . $querystring);
|
||||||
|
|
||||||
|
if ($this->output == 'json')
|
||||||
|
{
|
||||||
|
$response = json_decode($response, true);
|
||||||
|
|
||||||
|
if ($response === null)
|
||||||
|
{
|
||||||
|
throw new \Exception('The returned JSON was malformed or nonexistent.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new \Exception('XML is terrible, don\'t use it, ever.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->response = $response;
|
||||||
|
|
||||||
|
return $this->response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the longitude equal to a given distance (meters) at a given latitude
|
||||||
|
*/
|
||||||
|
public function meters2lng($meters, $latitude)
|
||||||
|
{
|
||||||
|
return $meters / (cos(deg2rad($latitude)) * 40075160 / 360);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the latitude equal to a given distance (meters)
|
||||||
|
*/
|
||||||
|
public function meters2lat($meters)
|
||||||
|
{
|
||||||
|
return $meters / (40075160 / 360);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the aggregated responses for a subdivided search
|
||||||
|
*/
|
||||||
|
private function subdivide($url, $parameters)
|
||||||
|
{
|
||||||
|
if ($this->subradius < 200)
|
||||||
|
{
|
||||||
|
throw new \Exception('Subradius should be at least 200 meters.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$quotient = $parameters['radius'] / $this->subradius;
|
||||||
|
|
||||||
|
if ($parameters['radius'] % $this->subradius || $quotient % 2)
|
||||||
|
{
|
||||||
|
throw new \Exception('Subradius should divide evenly into radius.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$center = explode(',', $parameters['location']);
|
||||||
|
$centerlat = $center[0];
|
||||||
|
$centerlng = $center[1];
|
||||||
|
$count = $quotient;
|
||||||
|
$lati = $this->meters2lat($this->subradius * 2);
|
||||||
|
|
||||||
|
$this->grid['results'] = array();
|
||||||
|
|
||||||
|
for ($i = $count / 2 * -1; $i <= $count / 2; $i++)
|
||||||
|
{
|
||||||
|
$lat = $centerlat + $i * $lati;
|
||||||
|
$lngi = $this->meters2lng($this->subradius * 2, $lat);
|
||||||
|
|
||||||
|
for ($j = $count / 2 * -1; $j <= $count / 2; $j++)
|
||||||
|
{
|
||||||
|
$lng = $centerlng + $j * $lngi;
|
||||||
|
$loc = $lat . ',' . $lng;
|
||||||
|
|
||||||
|
$parameters['location'] = $loc;
|
||||||
|
$parameters['radius'] = $this->subradius;
|
||||||
|
|
||||||
|
$pagetoken = true;
|
||||||
|
|
||||||
|
while ($pagetoken)
|
||||||
|
{
|
||||||
|
$this->queryGoogle($url, $parameters);
|
||||||
|
|
||||||
|
$this->grid[$i][$j] = $this->response;
|
||||||
|
|
||||||
|
$this->grid['results'] = array_merge(
|
||||||
|
$this->grid['results'],
|
||||||
|
$this->response['results']
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($this->response['next_page_token']))
|
||||||
|
{
|
||||||
|
$this->pagetoken = $this->response['next_page_token'];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->pagetoken = null;
|
||||||
|
$pagetoken = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->grid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
class Logger
|
||||||
|
{
|
||||||
|
protected static $instance;
|
||||||
|
private static $logger;
|
||||||
|
|
||||||
|
const ERROR = 0;
|
||||||
|
const WARNING = 1;
|
||||||
|
const INFO = 2;
|
||||||
|
const DEBUG = 3;
|
||||||
|
const DEBUG1 = 4;
|
||||||
|
const DEBUG2 = 5;
|
||||||
|
const DEBUG3 = 6;
|
||||||
|
const DEBUG4 = 7;
|
||||||
|
const SQL = 8;
|
||||||
|
const FLOG_MAX = 9;
|
||||||
|
|
||||||
|
const LEVELS = [
|
||||||
|
'ERROR', 'WARNING', 'INFO', 'DEBUG', 'DEBUG1', 'DEBUG2', 'DEBUG3', 'DEBUG4', 'SQL', 'FLOG_MAX'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getLogger()
|
||||||
|
{
|
||||||
|
if (!self::$instance) {
|
||||||
|
self::initLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::$instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function initLogger()
|
||||||
|
{
|
||||||
|
global $savvyext;
|
||||||
|
$fluent_host = $savvyext->cfgReadChar('phplogger.host');
|
||||||
|
$fluent_port = $savvyext->cfgReadLong('phplogger.port');
|
||||||
|
$log_enabled = $savvyext->cfgReadLong('phplogger.enabled');
|
||||||
|
|
||||||
|
if ($log_enabled == 1) {
|
||||||
|
self::$logger = new Fluent\Logger\FluentLogger($fluent_host, $fluent_port);
|
||||||
|
}
|
||||||
|
self::$instance = self::$logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function __callStatic($name, $arguments){
|
||||||
|
if(is_array($arguments) && count($arguments)>0 && in_array(strtoupper($name), Logger::LEVELS)) {
|
||||||
|
$data = $arguments[0];
|
||||||
|
$tag = NULL;
|
||||||
|
if (count($arguments)>1) {
|
||||||
|
$tag = $arguments[1];
|
||||||
|
}
|
||||||
|
if (count($arguments)>2) {
|
||||||
|
$name = $arguments[1];
|
||||||
|
$tag = $arguments[2];
|
||||||
|
}
|
||||||
|
$level = Logger::levelByName($name);
|
||||||
|
return Logger::log($level, $data, $name, $tag);
|
||||||
|
}
|
||||||
|
error_log("Logger::__callStatic($name, \$arguments) => Invalid method name!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function levelByName($name) {
|
||||||
|
$val = strtoupper($name);
|
||||||
|
if(in_array($val, Logger::LEVELS)) {
|
||||||
|
return array_search($val, Logger::LEVELS, false);
|
||||||
|
} else {
|
||||||
|
return Logger::FLOG_MAX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function nameByLevel($level) {
|
||||||
|
$level = (int)$level;
|
||||||
|
return Logger::ERROR < $level || $level > Logger::FLOG_MAX ? Logger::LEVELS[Logger::FLOG_MAX] : Logger::LEVELS[$level];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function log($level, $data = [], $name = NULL, $tag = NULL)
|
||||||
|
{
|
||||||
|
global $savvyext;
|
||||||
|
$clevel = $savvyext->cfgReadLong('phplogger.level');
|
||||||
|
$ilevel = (int)$level;
|
||||||
|
if ($ilevel > $clevel) {
|
||||||
|
error_log("Logger::log() invalid log level! '$level' => '$ilevel' > '$clevel'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$tag = $tag ?? $savvyext->cfgReadChar('phplogger.tag');
|
||||||
|
$name = $name ?? $savvyext->cfgReadChar('phplogger.name');
|
||||||
|
$data = [
|
||||||
|
"log" => $name,
|
||||||
|
"level" => Logger::nameByLevel($level),
|
||||||
|
"pid" => getmypid(),
|
||||||
|
"zz" => is_array($data) || is_object($data) ? json_encode($data) : $data,
|
||||||
|
];
|
||||||
|
if (self::getLogger()) {
|
||||||
|
self::getLogger()->post($tag, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polyline
|
||||||
|
*
|
||||||
|
* PHP Version 5.3
|
||||||
|
*
|
||||||
|
* A simple class to handle polyline-encoding for Google Maps
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Mapping
|
||||||
|
* @package Polyline
|
||||||
|
* @author E. McConville <emcconville@emcconville.com>
|
||||||
|
* @copyright 2009-2015 E. McConville
|
||||||
|
* @license http://www.gnu.org/licenses/lgpl.html LGPL v3
|
||||||
|
* @version GIT: $Id$
|
||||||
|
* @link https://github.com/emcconville/google-map-polyline-encoding-tool
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polyline encoding & decoding class
|
||||||
|
*
|
||||||
|
* Convert list of points to encoded string following Google's Polyline
|
||||||
|
* Algorithm.
|
||||||
|
*
|
||||||
|
* @category Mapping
|
||||||
|
* @package Polyline
|
||||||
|
* @author E. McConville <emcconville@emcconville.com>
|
||||||
|
* @license http://www.gnu.org/licenses/lgpl.html LGPL v3
|
||||||
|
* @link https://github.com/emcconville/google-map-polyline-encoding-tool
|
||||||
|
*/
|
||||||
|
class Polyline
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Default precision level of 1e-5.
|
||||||
|
*
|
||||||
|
* Overwrite this property in extended class to adjust precision of numbers.
|
||||||
|
* !!!CAUTION!!!
|
||||||
|
* 1) Adjusting this value will not guarantee that third party
|
||||||
|
* libraries will understand the change.
|
||||||
|
* 2) Float point arithmetic IS NOT real number arithmetic. PHP's internal
|
||||||
|
* float precision may contribute to undesired rounding.
|
||||||
|
*
|
||||||
|
* @var int $precision
|
||||||
|
*/
|
||||||
|
protected static $precision = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply Google Polyline algorithm to list of points.
|
||||||
|
*
|
||||||
|
* @param array $points List of points to encode. Can be a list of tuples,
|
||||||
|
* or a flat, one-dimensional array.
|
||||||
|
*
|
||||||
|
* @return string encoded string
|
||||||
|
*/
|
||||||
|
final public static function encode( $points )
|
||||||
|
{
|
||||||
|
$points = self::flatten($points);
|
||||||
|
$encodedString = '';
|
||||||
|
$index = 0;
|
||||||
|
$previous = array(0,0);
|
||||||
|
foreach ( $points as $number ) {
|
||||||
|
$number = (float)($number);
|
||||||
|
$number = (int)round($number * pow(10, static::$precision));
|
||||||
|
$diff = $number - $previous[$index % 2];
|
||||||
|
$previous[$index % 2] = $number;
|
||||||
|
$number = $diff;
|
||||||
|
$index++;
|
||||||
|
$number = ($number < 0) ? ~($number << 1) : ($number << 1);
|
||||||
|
$chunk = '';
|
||||||
|
while ( $number >= 0x20 ) {
|
||||||
|
$chunk .= chr((0x20 | ($number & 0x1f)) + 63);
|
||||||
|
$number >>= 5;
|
||||||
|
}
|
||||||
|
$chunk .= chr($number + 63);
|
||||||
|
$encodedString .= $chunk;
|
||||||
|
}
|
||||||
|
return $encodedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse Google Polyline algorithm on encoded string.
|
||||||
|
*
|
||||||
|
* @param string $string Encoded string to extract points from.
|
||||||
|
*
|
||||||
|
* @return array points
|
||||||
|
*/
|
||||||
|
final public static function decode( $string )
|
||||||
|
{
|
||||||
|
$points = array();
|
||||||
|
$index = $i = 0;
|
||||||
|
$previous = array(0,0);
|
||||||
|
while ($i < strlen($string)) {
|
||||||
|
$shift = $result = 0x00;
|
||||||
|
do {
|
||||||
|
$bit = ord(substr($string, $i++)) - 63;
|
||||||
|
$result |= ($bit & 0x1f) << $shift;
|
||||||
|
$shift += 5;
|
||||||
|
} while ($bit >= 0x20);
|
||||||
|
|
||||||
|
$diff = ($result & 1) ? ~($result >> 1) : ($result >> 1);
|
||||||
|
$number = $previous[$index % 2] + $diff;
|
||||||
|
$previous[$index % 2] = $number;
|
||||||
|
$index++;
|
||||||
|
$points[] = $number * 1 / pow(10, static::$precision);
|
||||||
|
}
|
||||||
|
return $points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reduce multi-dimensional to single list
|
||||||
|
*
|
||||||
|
* @param array $array Subject array to flatten.
|
||||||
|
*
|
||||||
|
* @return array flattened
|
||||||
|
*/
|
||||||
|
final public static function flatten( $array )
|
||||||
|
{
|
||||||
|
$flatten = array();
|
||||||
|
array_walk_recursive(
|
||||||
|
$array, // @codeCoverageIgnore
|
||||||
|
function ($current) use (&$flatten) {
|
||||||
|
$flatten[] = $current;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return $flatten;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concat list into pairs of points
|
||||||
|
*
|
||||||
|
* @param array $list One-dimensional array to segment into list of tuples.
|
||||||
|
*
|
||||||
|
* @return array pairs
|
||||||
|
*/
|
||||||
|
final public static function pair( $list )
|
||||||
|
{
|
||||||
|
return is_array($list) ? array_chunk($list, 2) : array();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
//namespace Utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class RandomStringGenerator
|
||||||
|
* @package Utils
|
||||||
|
*
|
||||||
|
* Solution taken from here:
|
||||||
|
* http://stackoverflow.com/a/13733588/1056679
|
||||||
|
*/
|
||||||
|
class RandomStringGenerator
|
||||||
|
{
|
||||||
|
/** @var string */
|
||||||
|
protected $alphabet;
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
protected $alphabetLength;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $alphabet
|
||||||
|
*/
|
||||||
|
public function __construct($alphabet = '')
|
||||||
|
{
|
||||||
|
if ('' !== $alphabet) {
|
||||||
|
$this->setAlphabet($alphabet);
|
||||||
|
} else {
|
||||||
|
$this->setAlphabet(
|
||||||
|
implode(range('a', 'z'))
|
||||||
|
. implode(range('A', 'Z'))
|
||||||
|
. implode(range(0, 9))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $alphabet
|
||||||
|
*/
|
||||||
|
public function setAlphabet($alphabet)
|
||||||
|
{
|
||||||
|
$this->alphabet = $alphabet;
|
||||||
|
$this->alphabetLength = strlen($alphabet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $length
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function generate($length)
|
||||||
|
{
|
||||||
|
$token = '';
|
||||||
|
|
||||||
|
for ($i = 0; $i < $length; $i++) {
|
||||||
|
$randomKey = $this->getRandomInteger(0, $this->alphabetLength);
|
||||||
|
$token .= $this->alphabet[$randomKey];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $min
|
||||||
|
* @param int $max
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
protected function getRandomInteger($min, $max)
|
||||||
|
{
|
||||||
|
$range = ($max - $min);
|
||||||
|
|
||||||
|
if ($range < 0) {
|
||||||
|
// Not so random...
|
||||||
|
return $min;
|
||||||
|
}
|
||||||
|
|
||||||
|
$log = log($range, 2);
|
||||||
|
|
||||||
|
// Length in bytes.
|
||||||
|
$bytes = (int) ($log / 8) + 1;
|
||||||
|
|
||||||
|
// Length in bits.
|
||||||
|
$bits = (int) $log + 1;
|
||||||
|
|
||||||
|
// Set all lower bits to 1.
|
||||||
|
$filter = (int) (1 << $bits) - 1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
|
||||||
|
|
||||||
|
// Discard irrelevant bits.
|
||||||
|
$rnd = $rnd & $filter;
|
||||||
|
|
||||||
|
} while ($rnd >= $range);
|
||||||
|
|
||||||
|
return ($min + $rnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
class Utilities
|
||||||
|
{
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function convertUtcToLocal($datetime, $timezone, $format = 'Y-m-d H:i:s')
|
||||||
|
{
|
||||||
|
if (!empty($datetime) && !empty($timezone)) {
|
||||||
|
$datetime = date($format, strtotime($datetime));
|
||||||
|
$utc_date = DateTime::createFromFormat(
|
||||||
|
$format,
|
||||||
|
$datetime,
|
||||||
|
new DateTimeZone('UTC')
|
||||||
|
);
|
||||||
|
if ($utc_date) {
|
||||||
|
$utc_date->setTimeZone(new DateTimeZone($timezone));
|
||||||
|
return $utc_date->format($format);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $datetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getClientIpAddress()
|
||||||
|
{
|
||||||
|
$ip="";
|
||||||
|
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
|
||||||
|
//ip from share internet
|
||||||
|
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||||
|
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||||
|
//ip pass from proxy
|
||||||
|
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||||
|
} else {
|
||||||
|
$ip = $_SERVER['REMOTE_ADDR'];
|
||||||
|
}
|
||||||
|
return $ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function startBenchmark(&$benchmark=[]){
|
||||||
|
$benchmark['start'] = microtime(true) * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function finishBenchmark(&$benchmark){
|
||||||
|
$benchmark['finish'] = microtime(true) * 1000;
|
||||||
|
$benchmark['duration'] = $benchmark['finish'] - $benchmark['start'];
|
||||||
|
error_log('benchmark'.json_encode($benchmark));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,403 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Class to validate the email address
|
||||||
|
*
|
||||||
|
* @author CodexWorld.com <contact@codexworld.com>
|
||||||
|
* @copyright Copyright (c) 2018, CodexWorld.com
|
||||||
|
* @url https://www.codexworld.com
|
||||||
|
*/
|
||||||
|
class VerifyEmail {
|
||||||
|
|
||||||
|
protected $stream = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMTP port number
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $port = 25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email address for request
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $from = 'root@localhost';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The connection timeout, in seconds.
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $max_connection_timeout = 30;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timeout value on stream, in seconds.
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $stream_timeout = 5;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait timeout on stream, in seconds.
|
||||||
|
* * 0 - not wait
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
protected $stream_timeout_wait = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to throw exceptions for errors.
|
||||||
|
* @type boolean
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected $exceptions = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of errors encountered.
|
||||||
|
* @type integer
|
||||||
|
* @access protected
|
||||||
|
*/
|
||||||
|
protected $error_count = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class debug output mode.
|
||||||
|
* @type boolean
|
||||||
|
*/
|
||||||
|
public $Debug = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How to handle debug output.
|
||||||
|
* Options:
|
||||||
|
* * `echo` Output plain-text as-is, appropriate for CLI
|
||||||
|
* * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
|
||||||
|
* * `log` Output to error log as configured in php.ini
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $Debugoutput = 'echo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SMTP RFC standard line ending.
|
||||||
|
*/
|
||||||
|
const CRLF = "\r\n";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the most recent error message.
|
||||||
|
* @type string
|
||||||
|
*/
|
||||||
|
public $ErrorInfo = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param boolean $exceptions Should we throw external exceptions?
|
||||||
|
*/
|
||||||
|
public function __construct($exceptions = false) {
|
||||||
|
$this->exceptions = (boolean) $exceptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set email address for SMTP request
|
||||||
|
* @param string $email Email address
|
||||||
|
*/
|
||||||
|
public function setEmailFrom($email) {
|
||||||
|
if (!self::validate($email)) {
|
||||||
|
$this->set_error('Invalid address : ' . $email);
|
||||||
|
$this->edebug($this->ErrorInfo);
|
||||||
|
if ($this->exceptions) {
|
||||||
|
throw new verifyEmailException($this->ErrorInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->from = $email;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set connection timeout, in seconds.
|
||||||
|
* @param int $seconds
|
||||||
|
*/
|
||||||
|
public function setConnectionTimeout($seconds) {
|
||||||
|
if ($seconds > 0) {
|
||||||
|
$this->max_connection_timeout = (int) $seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the timeout value on stream, expressed in the seconds
|
||||||
|
* @param int $seconds
|
||||||
|
*/
|
||||||
|
public function setStreamTimeout($seconds) {
|
||||||
|
if ($seconds > 0) {
|
||||||
|
$this->stream_timeout = (int) $seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setStreamTimeoutWait($seconds) {
|
||||||
|
if ($seconds >= 0) {
|
||||||
|
$this->stream_timeout_wait = (int) $seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate email address.
|
||||||
|
* @param string $email
|
||||||
|
* @return boolean True if valid.
|
||||||
|
*/
|
||||||
|
public static function validate($email) {
|
||||||
|
return (boolean) filter_var($email, FILTER_VALIDATE_EMAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get array of MX records for host. Sort by weight information.
|
||||||
|
* @param string $hostname The Internet host name.
|
||||||
|
* @return array Array of the MX records found.
|
||||||
|
*/
|
||||||
|
public function getMXrecords($hostname) {
|
||||||
|
$mxhosts = array();
|
||||||
|
$mxweights = array();
|
||||||
|
if (getmxrr($hostname, $mxhosts, $mxweights) === FALSE) {
|
||||||
|
$this->set_error('MX records not found or an error occurred');
|
||||||
|
$this->edebug($this->ErrorInfo);
|
||||||
|
} else {
|
||||||
|
array_multisort($mxweights, $mxhosts);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Add A-record as last chance (e.g. if no MX record is there).
|
||||||
|
* Thanks Nicht Lieb.
|
||||||
|
* @link http://www.faqs.org/rfcs/rfc2821.html RFC 2821 - Simple Mail Transfer Protocol
|
||||||
|
*/
|
||||||
|
if (empty($mxhosts)) {
|
||||||
|
$mxhosts[] = $hostname;
|
||||||
|
}
|
||||||
|
return $mxhosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses input string to array(0=>user, 1=>domain)
|
||||||
|
* @param string $email
|
||||||
|
* @param boolean $only_domain
|
||||||
|
* @return string|array
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
public static function parse_email($email, $only_domain = TRUE) {
|
||||||
|
sscanf($email, "%[^@]@%s", $user, $domain);
|
||||||
|
return ($only_domain) ? $domain : array($user, $domain);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an error message to the error container.
|
||||||
|
* @access protected
|
||||||
|
* @param string $msg
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function set_error($msg) {
|
||||||
|
$this->error_count++;
|
||||||
|
$this->ErrorInfo = $msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an error occurred.
|
||||||
|
* @access public
|
||||||
|
* @return boolean True if an error did occur.
|
||||||
|
*/
|
||||||
|
public function isError() {
|
||||||
|
return ($this->error_count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output debugging info
|
||||||
|
* Only generates output if debug output is enabled
|
||||||
|
* @see verifyEmail::$Debugoutput
|
||||||
|
* @see verifyEmail::$Debug
|
||||||
|
* @param string $str
|
||||||
|
*/
|
||||||
|
protected function edebug($str) {
|
||||||
|
if (!$this->Debug) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch ($this->Debugoutput) {
|
||||||
|
case 'log':
|
||||||
|
//Don't output, just log
|
||||||
|
error_log($str);
|
||||||
|
break;
|
||||||
|
case 'html':
|
||||||
|
//Cleans up output a bit for a better looking, HTML-safe output
|
||||||
|
echo htmlentities(
|
||||||
|
preg_replace('/[\r\n]+/', '', $str), ENT_QUOTES, 'UTF-8'
|
||||||
|
)
|
||||||
|
. "<br>\n";
|
||||||
|
break;
|
||||||
|
case 'echo':
|
||||||
|
default:
|
||||||
|
//Normalize line breaks
|
||||||
|
$str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
|
||||||
|
echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
|
||||||
|
"\n", "\n \t ", trim($str)
|
||||||
|
) . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate email
|
||||||
|
* @param string $email Email address
|
||||||
|
* @return boolean True if the valid email also exist
|
||||||
|
*/
|
||||||
|
public function check($email) {
|
||||||
|
$result = FALSE;
|
||||||
|
|
||||||
|
if (!self::validate($email)) {
|
||||||
|
$this->set_error("{$email} incorrect e-mail");
|
||||||
|
$this->edebug($this->ErrorInfo);
|
||||||
|
if ($this->exceptions) {
|
||||||
|
throw new verifyEmailException($this->ErrorInfo);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
$this->error_count = 0; // Reset errors
|
||||||
|
$this->stream = FALSE;
|
||||||
|
|
||||||
|
$mxs = $this->getMXrecords(self::parse_email($email));
|
||||||
|
$timeout = ceil($this->max_connection_timeout / count($mxs));
|
||||||
|
foreach ($mxs as $host) {
|
||||||
|
/**
|
||||||
|
* suppress error output from stream socket client...
|
||||||
|
* Thanks Michael.
|
||||||
|
*/
|
||||||
|
$this->stream = @stream_socket_client("tcp://" . $host . ":" . $this->port, $errno, $errstr, $timeout);
|
||||||
|
if ($this->stream === FALSE) {
|
||||||
|
if ($errno == 0) {
|
||||||
|
$this->set_error("Problem initializing the socket");
|
||||||
|
$this->edebug($this->ErrorInfo);
|
||||||
|
if ($this->exceptions) {
|
||||||
|
throw new verifyEmailException($this->ErrorInfo);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
$this->edebug($host . ":" . $errstr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
stream_set_timeout($this->stream, $this->stream_timeout);
|
||||||
|
stream_set_blocking($this->stream, 1);
|
||||||
|
|
||||||
|
if ($this->_streamCode($this->_streamResponse()) == '220') {
|
||||||
|
$this->edebug("Connection success {$host}");
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
fclose($this->stream);
|
||||||
|
$this->stream = FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->stream === FALSE) {
|
||||||
|
$this->set_error("All connection fails");
|
||||||
|
$this->edebug($this->ErrorInfo);
|
||||||
|
if ($this->exceptions) {
|
||||||
|
throw new verifyEmailException($this->ErrorInfo);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->_streamQuery("HELO " . self::parse_email($this->from));
|
||||||
|
$this->_streamResponse();
|
||||||
|
$this->_streamQuery("MAIL FROM: <{$this->from}>");
|
||||||
|
$this->_streamResponse();
|
||||||
|
$this->_streamQuery("RCPT TO: <{$email}>");
|
||||||
|
$code = $this->_streamCode($this->_streamResponse());
|
||||||
|
$this->_streamResponse();
|
||||||
|
$this->_streamQuery("RSET");
|
||||||
|
$this->_streamResponse();
|
||||||
|
$code2 = $this->_streamCode($this->_streamResponse());
|
||||||
|
$this->_streamQuery("QUIT");
|
||||||
|
fclose($this->stream);
|
||||||
|
|
||||||
|
$code = !empty($code2)?$code2:$code;
|
||||||
|
switch ($code) {
|
||||||
|
case '250':
|
||||||
|
/**
|
||||||
|
* http://www.ietf.org/rfc/rfc0821.txt
|
||||||
|
* 250 Requested mail action okay, completed
|
||||||
|
* email address was accepted
|
||||||
|
*/
|
||||||
|
case '450':
|
||||||
|
case '451':
|
||||||
|
case '452':
|
||||||
|
/**
|
||||||
|
* http://www.ietf.org/rfc/rfc0821.txt
|
||||||
|
* 450 Requested action not taken: the remote mail server
|
||||||
|
* does not want to accept mail from your server for
|
||||||
|
* some reason (IP address, blacklisting, etc..)
|
||||||
|
* Thanks Nicht Lieb.
|
||||||
|
* 451 Requested action aborted: local error in processing
|
||||||
|
* 452 Requested action not taken: insufficient system storage
|
||||||
|
* email address was greylisted (or some temporary error occured on the MTA)
|
||||||
|
* i believe that e-mail exists
|
||||||
|
*/
|
||||||
|
return TRUE;
|
||||||
|
case '550':
|
||||||
|
return FALSE;
|
||||||
|
default :
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* writes the contents of string to the file stream pointed to by handle
|
||||||
|
* If an error occurs, returns FALSE.
|
||||||
|
* @access protected
|
||||||
|
* @param string $string The string that is to be written
|
||||||
|
* @return string Returns a result code, as an integer.
|
||||||
|
*/
|
||||||
|
protected function _streamQuery($query) {
|
||||||
|
$this->edebug($query);
|
||||||
|
return stream_socket_sendto($this->stream, $query . self::CRLF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads all the line long the answer and analyze it.
|
||||||
|
* If an error occurs, returns FALSE
|
||||||
|
* @access protected
|
||||||
|
* @return string Response
|
||||||
|
*/
|
||||||
|
protected function _streamResponse($timed = 0) {
|
||||||
|
$reply = stream_get_line($this->stream, 1);
|
||||||
|
$status = stream_get_meta_data($this->stream);
|
||||||
|
|
||||||
|
if (!empty($status['timed_out'])) {
|
||||||
|
$this->edebug("Timed out while waiting for data! (timeout {$this->stream_timeout} seconds)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($reply === FALSE && $status['timed_out'] && $timed < $this->stream_timeout_wait) {
|
||||||
|
return $this->_streamResponse($timed + $this->stream_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if ($reply !== FALSE && $status['unread_bytes'] > 0) {
|
||||||
|
$reply .= stream_get_line($this->stream, $status['unread_bytes'], self::CRLF);
|
||||||
|
}
|
||||||
|
$this->edebug($reply);
|
||||||
|
return $reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Response code from Response
|
||||||
|
* @param string $str
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function _streamCode($str) {
|
||||||
|
preg_match('/^(?<code>[0-9]{3})(\s|-)(.*)$/ims', $str, $matches);
|
||||||
|
$code = isset($matches['code']) ? $matches['code'] : false;
|
||||||
|
return $code;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* verifyEmail exception handler
|
||||||
|
*/
|
||||||
|
class verifyEmailException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prettify error message output
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function errorMessage() {
|
||||||
|
$errorMsg = $this->getMessage();
|
||||||
|
return $errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"require": {
|
||||||
|
"fluent/logger": "^1.0",
|
||||||
|
"guzzlehttp/guzzle": "^6.3",
|
||||||
|
"google/apiclient": "^2.4",
|
||||||
|
"google/cloud-kms": "^1.9",
|
||||||
|
"ramsey/uuid": "^3.8",
|
||||||
|
"phpfastcache/phpfastcache": "^7.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$base_url = 'https://' . str_replace("extlayer", "svrlayer", $_SERVER["SERVER_NAME"]);
|
||||||
|
$local_url = 'https://' . $_SERVER["SERVER_NAME"];
|
||||||
|
$target_url = $base_url . "/internal.php";
|
||||||
|
|
||||||
|
$tracklocation_dir = $savvyext->cfgReadChar('system.tracklocation_dir');
|
||||||
|
$gearmanServers = $savvyext->cfgReadChar('gearman.servers');
|
||||||
|
|
||||||
|
$encryptionAlg = $savvyext->cfgReadChar('encryption.algorithm');
|
||||||
|
$encryptionKey = $savvyext->cfgReadChar('encryption.key');
|
||||||
|
$encryptionIV = $savvyext->cfgReadChar('encryption.iv');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
|
||||||
|
global $pgconn, $pgconn_gps;
|
||||||
|
//PostgreSQL
|
||||||
|
$gps_db_host = $savvyext->cfgReadChar('gpsdatabase.host');
|
||||||
|
$gps_db_port = $savvyext->cfgReadLong('gpsdatabase.port');
|
||||||
|
$gps_db_name = $savvyext->cfgReadChar('gpsdatabase.name');
|
||||||
|
$gps_db_user = $savvyext->cfgReadChar('gpsdatabase.user');
|
||||||
|
$gps_db_pass = $savvyext->cfgReadChar('gpsdatabase.pass');
|
||||||
|
$conn_string_gps = "host=${gps_db_host} port=${gps_db_port} dbname=${gps_db_name} user=${gps_db_user} password=${gps_db_pass}";
|
||||||
|
$pgconn_gps = pg_connect($conn_string_gps);
|
||||||
|
|
||||||
|
$db_host = $savvyext->cfgReadChar('database.host');
|
||||||
|
$db_port = $savvyext->cfgReadLong('database.port');
|
||||||
|
$db_name = $savvyext->cfgReadChar('database.name');
|
||||||
|
$db_user = $savvyext->cfgReadChar('database.user');
|
||||||
|
$db_pass = $savvyext->cfgReadChar('database.pass');
|
||||||
|
$conn_string = "host=${db_host} port=${db_port} dbname=${db_name} user=${db_user} password=${db_pass}";
|
||||||
|
$pgconn = pg_connect($conn_string);
|
||||||
|
|
||||||
|
if ($pgconn) {
|
||||||
|
// echo "Okay";
|
||||||
|
} else {
|
||||||
|
//echo pg_last_error($pgconn);
|
||||||
|
}
|
||||||
|
|
||||||
|
$autocabApiConfig = [
|
||||||
|
'baseUrl' => $savvyext->cfgReadChar('autocab.baseUrl'),
|
||||||
|
'agentId' => $savvyext->cfgReadChar('autocab.agentId'),
|
||||||
|
'agentPassword' => $savvyext->cfgReadChar('autocab.agentPassword'),
|
||||||
|
'currency' => $savvyext->cfgReadChar('autocab.currency'),
|
||||||
|
'vendorId' => $savvyext->cfgReadChar('autocab.vendorId'),
|
||||||
|
'templatesDir' => $savvyext->cfgReadChar('autocab.templatesDir')
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$target_url = $base_url . "/internal.php";
|
||||||
|
|
||||||
|
if (defined('SITE_NAME')) {
|
||||||
|
// Inclided more than once?
|
||||||
|
} else {
|
||||||
|
define('SITE_NAME', 'Savvy');
|
||||||
|
define('SITE_EMAIL', 'info@savvy.com');
|
||||||
|
define('SITE_PHONE', '+1 911 9110');
|
||||||
|
define('SITE_FAX', '+1 9FX 9110');
|
||||||
|
|
||||||
|
define('PHP_API_OK', 0);
|
||||||
|
define('MAX_ADMIN_SESSION', 1200);
|
||||||
|
|
||||||
|
define('MOBIDELIV_UPLOADS', 4505);
|
||||||
|
define('MOBIDELIV_DOWNLOAD', 4506);
|
||||||
|
|
||||||
|
define('SAVVY_USER_CREATEACCOUNT', 22010);
|
||||||
|
define('SAVVY_USER_PSERSONALITY', 22011);
|
||||||
|
|
||||||
|
define('SAVVY_USER_RESETPASS', 22013);
|
||||||
|
define('SAVVY_USER_LOGINACCOUNT', 22015);
|
||||||
|
define('SAVVY_USER_TRACKLOCATION', 22020);
|
||||||
|
define('SAVVY_USER_SAVECARDPAYMT', 22025);
|
||||||
|
define('SAVVY_USER_GETCARDPMYLIST', 22030);
|
||||||
|
define('SAVVY_USER_MANAGEPAYLIST', 22035);
|
||||||
|
define('SAVVY_USER_LOADUSERPROFILE', 22040);
|
||||||
|
define('SAVVY_USER_ENABLEFEATURE', 22042);
|
||||||
|
|
||||||
|
define('SAVVY_USER_UPDATEUSERPROFILE', 22045);
|
||||||
|
define('SAVVY_USER_TRANSPORTLIST', 22047);
|
||||||
|
define('SAVVY_USER_TRANSPORTPROFILE', 22048);
|
||||||
|
define('SAVVY_USER_SAVEBUDGET', 22049);
|
||||||
|
|
||||||
|
define('SAVVY_USERSUSC_LOAD', 22051);
|
||||||
|
define('SAVVY_USERSUSC_STATUS', 22052);
|
||||||
|
define('SAVVY_USERSAPP_GETLIST', 22053);
|
||||||
|
|
||||||
|
define('SAVVY_USER_GETSAVEDTRIPS', 22070);
|
||||||
|
define('SAVVY_USER_SAVEUPDTTRIP', 22071);
|
||||||
|
|
||||||
|
define('SAVVY_USER_REFRESHSESSION', 22997);
|
||||||
|
|
||||||
|
define('SAVVY_USER_VERIFYSESSION', 22999);
|
||||||
|
|
||||||
|
define('SAVVY_USERSAPP_SLIDECARD', 44054);
|
||||||
|
define('SAVVY_USERSAPP_DEALSUB', 44056);
|
||||||
|
|
||||||
|
define('SAVVY_USERSAPP_CARPOOL', 44057);
|
||||||
|
|
||||||
|
define('SAVVY_USERSAPP_SURVEY', 44060);
|
||||||
|
define('SAVVY_USERSAPP_POINTSDEATAIL', 44061);
|
||||||
|
define('SAVVY_USERSAPP_LOADREDEEM', 44062);
|
||||||
|
define('SAVVY_USERSAPP_REDEEMPPOINTS', 44064);
|
||||||
|
|
||||||
|
define('SAVVY_USERSAPP_TRACKCARDCLICK', 44067);
|
||||||
|
|
||||||
|
define('SAVVY_USERCARD_DASHCARD', 40100);
|
||||||
|
define('SAVVY_USERSAVE_DASHCARD', 40110);
|
||||||
|
define('SAVVY_USERLOAD_SAVEDCARDS', 40115);
|
||||||
|
define('SAVVY_USERPROP_SETTINGSARRAY', 40007);
|
||||||
|
|
||||||
|
define('SAVVY_CARPOOL_SUBSCRIBE', 60010);
|
||||||
|
define('SAVVY_CARPOOL_STATUS', 60015);
|
||||||
|
define('SAVVY_CARPOOL_TRACK', 60020);
|
||||||
|
|
||||||
|
//cards
|
||||||
|
define('PHP_LOGIN_OK', 0);
|
||||||
|
define('PHP_API_BAD_PARAM', -1);
|
||||||
|
define('CARD_LOCATION_DEFAULT', 0);
|
||||||
|
define('CARD_ADD_DENIED', 0);
|
||||||
|
define('CARD_LOCATION_MAINFEED', 100);
|
||||||
|
define('CARD_ADD_ALLOWED', 100);
|
||||||
|
define('CARD_LOCATION_ACTIVITIES', 200);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<IfModule mod_rewrite.c>
|
||||||
|
|
||||||
|
RewriteEngine On
|
||||||
|
RewriteBase /SAVVY/email/
|
||||||
|
#RewriteBase /
|
||||||
|
|
||||||
|
#Checks to
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-f
|
||||||
|
RewriteCond %{REQUEST_FILENAME} !-d
|
||||||
|
RewriteRule ^(.*)$ index.php?/$1 [L]
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
<IfModule !mod_rewrite.c>
|
||||||
|
# If we don't have mod_rewrite installed, all 404's
|
||||||
|
# can be sent to index.php, and everything works as normal.
|
||||||
|
# Submitted by: ElliotHaughin
|
||||||
|
|
||||||
|
ErrorDocument 404 /index.php
|
||||||
|
|
||||||
|
</IfModule>
|
||||||
|
|
||||||
|
#Header add Access-Control-Allow-Origin "*"
|
||||||
|
#Header add Access-Control-Expose-Headers "Access-Control-Allow-Origin"
|
||||||
|
#Header add Access-Control-Allow-Headers "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With"
|
||||||
|
#Header add Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
|
||||||
|
#Header add Content-type "application/json"
|
||||||
|
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Email {
|
||||||
|
|
||||||
|
static function createEmail($db, $to, $subject, $htmlBody) {
|
||||||
|
$result = array();
|
||||||
|
|
||||||
|
$status = '0';
|
||||||
|
|
||||||
|
$values = array(
|
||||||
|
"to_emails" => NULL,
|
||||||
|
"subject" => NULL,
|
||||||
|
"html_body" => NULL,
|
||||||
|
"status"=>"0",
|
||||||
|
"created_at"=>(new DateTime())->format('c'),
|
||||||
|
"updated_at"=>(new DateTime())->format('c')
|
||||||
|
);
|
||||||
|
|
||||||
|
if(isset($to)) {
|
||||||
|
$values["to_emails"] = Email::prepareEmailsQueryString($to);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($subject)) {
|
||||||
|
$values["subject"] = pg_escape_string($subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isset($htmlBody)) {
|
||||||
|
$values["html_body"] = pg_escape_string($htmlBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
$values = array_filter($values, 'strlen');
|
||||||
|
|
||||||
|
$q = "INSERT INTO emails";
|
||||||
|
|
||||||
|
// implode keys of $values...
|
||||||
|
$q .= " (".implode(", ", array_keys($values)).")";
|
||||||
|
|
||||||
|
// implode values of $values...
|
||||||
|
$q .= " VALUES ('".implode("', '", $values)."') ";
|
||||||
|
|
||||||
|
$rs = pg_query($db, $q);
|
||||||
|
|
||||||
|
if (!$rs) {
|
||||||
|
return array("success" => false, "message" => "Something went wrong!");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
return array("success" => (boolean)pg_affected_rows($rs), "message" => "Successfully create new email.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static function getEmailById($db, $id) {
|
||||||
|
$result = [];
|
||||||
|
$q = "SELECT * from emails where id = '" . pg_escape_string($id) . "'";
|
||||||
|
|
||||||
|
$rs = pg_query($db, $q);
|
||||||
|
|
||||||
|
while ($row = pg_fetch_assoc($rs)) {
|
||||||
|
array_push($result, Email::parseData($row));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array("success" => true, "data" => $result[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function findEmails($db, $filter, $limit=0)
|
||||||
|
{
|
||||||
|
$results = array();
|
||||||
|
$condition = [];
|
||||||
|
$q = "SELECT * FROM emails";
|
||||||
|
|
||||||
|
if (count($filter)) {
|
||||||
|
$q .= " where ";
|
||||||
|
if (isset($filter['status'])) {
|
||||||
|
$condition[] = "status = '" . pg_escape_string($filter['status']) . "'";
|
||||||
|
}
|
||||||
|
if (isset($filter['retries'])) {
|
||||||
|
$condition[] = "retries < ".((int)$filter['retries']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$q .= implode(" AND ", $condition);
|
||||||
|
|
||||||
|
if ($limit>0) {
|
||||||
|
$q.= " LIMIT ".$limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rs = pg_query($db, $q);
|
||||||
|
|
||||||
|
while ($row = pg_fetch_assoc($rs)) {
|
||||||
|
array_push($results, Email::parseData($row));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results ?? NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function updateEmail($db, $id, $to, $subject, $htmlBody, $status) {
|
||||||
|
if (!isset($id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$q = "update emails set ";
|
||||||
|
$values = [
|
||||||
|
"updated_at = '" . (new DateTime())->format('c') ."'"
|
||||||
|
];
|
||||||
|
|
||||||
|
if (isset($to)) {
|
||||||
|
// $q .= "to_email = " . Email::prepareEmailsQueryString($to);
|
||||||
|
$values[] = "to_emails = '" . Email::prepareEmailsQueryString($to) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($subject)) {
|
||||||
|
$values[] = "subject = '" . pg_escape_string($subject) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($htmlBody)) {
|
||||||
|
$values[] = "html_body = '" . pg_escape_string($htmlBody) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($status)) {
|
||||||
|
$values[] = "status = '" . pg_escape_string($status) . "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
$q .= implode(", ", $values);
|
||||||
|
$q .= " where id = " . pg_escape_string((string)$id);
|
||||||
|
|
||||||
|
$r = pg_query($db, $q);
|
||||||
|
|
||||||
|
if (!$r) {
|
||||||
|
return array("success" => false, "message" => "Something went wrong!");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array("success" => true, "message" => "Successfully update email.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function parseData($obj) {
|
||||||
|
$emails = $obj['to_emails'];
|
||||||
|
$emails = str_replace('{', '', $emails);
|
||||||
|
$emails = str_replace('}', '', $emails);
|
||||||
|
|
||||||
|
$emails = explode(',', $emails);
|
||||||
|
|
||||||
|
$obj['to_emails'] = $emails;
|
||||||
|
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function prepareEmailsQueryString($to) {
|
||||||
|
$result = "{";
|
||||||
|
$result .= join(',', $to);
|
||||||
|
$result .= "}";
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require './vendor/autoload.php';
|
||||||
|
require '../../core/backend.php';
|
||||||
|
|
||||||
|
class EmailApi extends Api
|
||||||
|
{
|
||||||
|
public $apiName = 'email';
|
||||||
|
public $sg;
|
||||||
|
|
||||||
|
public function __construct($requestUri, $encryption=true) {
|
||||||
|
parent::__construct($requestUri, $encryption);
|
||||||
|
|
||||||
|
global $savvyext;
|
||||||
|
|
||||||
|
$apiKey = $savvyext->cfgReadChar('mailsend.api_key');
|
||||||
|
$sg = new \SendGrid($apiKey);
|
||||||
|
|
||||||
|
$this->sg = $sg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function indexAction() {
|
||||||
|
$results = $this->findNewEmails();
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"success" => true,
|
||||||
|
"data" => $results
|
||||||
|
), 200 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Post(
|
||||||
|
* path="/v1/email/api/email/new",
|
||||||
|
* summary="Send email to users",
|
||||||
|
* @OA\Parameter(
|
||||||
|
* name="name",
|
||||||
|
* description = "Name of email template",
|
||||||
|
* in="body",
|
||||||
|
* required=true,
|
||||||
|
* @OA\Schema(ref="#/components/schemas/create_params")
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$db = new Db();
|
||||||
|
$message = "Failed to send email";
|
||||||
|
|
||||||
|
$subject = $this->requestParams['subject'] ?? NULL;
|
||||||
|
$receivers = $this->requestParams["to"] ?? NULL;
|
||||||
|
$htmlBody = $this->requestParams['html_body'] ?? NULL;
|
||||||
|
|
||||||
|
if (!isset($subject) || !isset($receivers) || !isset($htmlBody)) {
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"success" => false,
|
||||||
|
"message" => 'Missing params'
|
||||||
|
), 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = Email::createEmail(
|
||||||
|
$db->getConnect(),
|
||||||
|
$receivers,
|
||||||
|
$subject,
|
||||||
|
$htmlBody
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isset($result)) {
|
||||||
|
return $this->response(
|
||||||
|
array(
|
||||||
|
"success" => false,
|
||||||
|
"message" => $message
|
||||||
|
), 500);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->response($result, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function viewAction() {}
|
||||||
|
|
||||||
|
public function updateAction() {}
|
||||||
|
|
||||||
|
public function deleteAction() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require './vendor/autoload.php';
|
||||||
|
|
||||||
|
use GuzzleHttp\Client;
|
||||||
|
use GuzzleHttp\Exception\ClientException;
|
||||||
|
use GuzzleHttp\Exception\ServerException;
|
||||||
|
|
||||||
|
class MailchimpAPI
|
||||||
|
{
|
||||||
|
private static function handleResponse($response)
|
||||||
|
{
|
||||||
|
$res = json_decode($response->getBody());
|
||||||
|
|
||||||
|
if (!isset($res)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge((array) $res);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($url, $params)
|
||||||
|
{
|
||||||
|
require_once('../../core/backend.php');
|
||||||
|
global $savvyext;
|
||||||
|
$token = $savvyext->cfgReadChar('mailchimp.api_key');
|
||||||
|
$baseUri = $savvyext->cfgReadChar('mailchimp.domain');
|
||||||
|
|
||||||
|
$client = new Client(['base_uri' => $baseUri]);
|
||||||
|
$header = ['Authorization' => "apikey $token"];
|
||||||
|
|
||||||
|
try {
|
||||||
|
$response = $client->request('GET', $url, [
|
||||||
|
'headers' => $header,
|
||||||
|
'query' => $params,
|
||||||
|
]);
|
||||||
|
} catch (ServerException $e) {
|
||||||
|
$response = $e->getResponse();
|
||||||
|
} catch (ClientException $e) {
|
||||||
|
$response = $e->getResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::handleResponse($response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require './vendor/autoload.php';
|
||||||
|
|
||||||
|
use \SendGrid\Mail\To;
|
||||||
|
use \SendGrid\Mail\Mail;
|
||||||
|
use \SendGrid\Mail\From;
|
||||||
|
use \SendGrid\Mail\HtmlContent;
|
||||||
|
use \SendGrid\Mail\Personalization;
|
||||||
|
|
||||||
|
class SendGridService {
|
||||||
|
public static function sendEmail($email) {
|
||||||
|
global $savvyext;
|
||||||
|
|
||||||
|
$apiKey = $savvyext->cfgReadChar('mailsend.api_key');
|
||||||
|
$sg = new \SendGrid($apiKey);
|
||||||
|
|
||||||
|
$response = $sg->send($email);
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function prepareSengridToObject($receiver = [], $substitutions = NULL) {
|
||||||
|
return new \SendGrid\Mail\To(
|
||||||
|
$receiver['email'],
|
||||||
|
$receiver['firstname'] ?? '',
|
||||||
|
$substitutions ?? NULL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function prepareEmail($receivers, $subject, $template, $globalSubstitutions) {
|
||||||
|
global $savvyext;
|
||||||
|
|
||||||
|
$fromEmail = $savvyext->cfgReadChar('mailsend.from');
|
||||||
|
$fromName = $savvyext->cfgReadChar('mailsend.name');
|
||||||
|
|
||||||
|
$email = new Mail(
|
||||||
|
new From($fromEmail, $fromName),
|
||||||
|
NULL,
|
||||||
|
$subject, // or array of subjects, these take precendence
|
||||||
|
$plainTextContent ?? NULL,
|
||||||
|
new HtmlContent($template),
|
||||||
|
$globalSubstitutions ?? NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach($receivers as $receiver) {
|
||||||
|
$personalization = SendGridService::createPersonalize($receiver);
|
||||||
|
$email->addPersonalization($personalization);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createPersonalize($to) {
|
||||||
|
$personalize = new Personalization();
|
||||||
|
$personalize->addTo($to);
|
||||||
|
|
||||||
|
return $personalize;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"name": "vendor/email",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Jack",
|
||||||
|
"email": "jack@goldenowl.asia"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"guzzlehttp/guzzle": "~6.0",
|
||||||
|
"sendgrid/sendgrid": "~7"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
require_once('../../core/backend.php');
|
||||||
|
|
||||||
|
require_once('../common/Api.php');
|
||||||
|
require_once('../common/Db.php');
|
||||||
|
|
||||||
|
require_once('Email.php');
|
||||||
|
require_once('EmailApi.php');
|
||||||
|
|
||||||
|
$httpAuthToken = $savvyext->cfgReadChar('system.oauth2_token');
|
||||||
|
|
||||||
|
header("Access-Control-Allow-Origin: *");
|
||||||
|
header("Access-Control-Expose-Headers: Access-Control-Allow-Origin");
|
||||||
|
header("Access-Control-Allow-Headers: Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, client_id");
|
||||||
|
header("Access-Control-Allow-Methods: POST, GET, PUT, DELETE, OPTIONS");
|
||||||
|
header('Content-type: application/json');
|
||||||
|
|
||||||
|
if ("OPTIONS" === $_SERVER['REQUEST_METHOD']) {
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$headers = getallheaders();
|
||||||
|
if ((!isset($headers["Authorization"]) || substr($headers["Authorization"],-strlen($httpAuthToken))!=$httpAuthToken) &&
|
||||||
|
(!isset($headers["authorization"]) || substr($headers["authorization"],-strlen($httpAuthToken))!=$httpAuthToken)) {
|
||||||
|
header('HTTP/1.1 401 Unauthorized');
|
||||||
|
header('Status: 401 Unauthorized');
|
||||||
|
echo "{\"status\":\"Missing authorization\"}";
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (strpos($_SERVER['REQUEST_URI'], '/api/')===false) {
|
||||||
|
throw new Exception("Invalid API request");
|
||||||
|
}
|
||||||
|
$requestUri = explode('/', trim($_SERVER['REQUEST_URI'], '/'));
|
||||||
|
|
||||||
|
while (array_shift($requestUri) !== 'api') {
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($requestUri[0] == 'email') {
|
||||||
|
$api = new EmailApi($requestUri, false);
|
||||||
|
} else {
|
||||||
|
echo json_encode(Array("message" => 'Invalid API request'));
|
||||||
|
}
|
||||||
|
echo $api->run();
|
||||||
|
}
|
||||||
|
catch (Exception $e) {
|
||||||
|
echo json_encode(Array("message" => $e->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Info(
|
||||||
|
* title="Email Endpoint API",
|
||||||
|
* version="1.0",
|
||||||
|
* @OA\Contact(
|
||||||
|
* email="support@float.sg"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="receivers",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(
|
||||||
|
* property="email",
|
||||||
|
* description="Email of receiver",
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* example="jack@goldenowl.asia"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="name",
|
||||||
|
* description="Name of receiver",
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* example="Jack Nguyen",
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="substitutions",
|
||||||
|
* description="Receiver's personal information for email"
|
||||||
|
* type="object"
|
||||||
|
* example="{ "{{key}}": "value" }"
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @OA\Schema(
|
||||||
|
* schema="create_params",
|
||||||
|
* type="object",
|
||||||
|
* @OA\Property(
|
||||||
|
* property="name",
|
||||||
|
* description="Name of email template",
|
||||||
|
* type="string",
|
||||||
|
* format="string",
|
||||||
|
* example="welcome"
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="data",
|
||||||
|
* description="Global dynamic data for the template",
|
||||||
|
* type="object",
|
||||||
|
* properties:
|
||||||
|
* key:
|
||||||
|
* type: string,
|
||||||
|
* format: "{{key_name}}"
|
||||||
|
* value:
|
||||||
|
* type: string
|
||||||
|
* example= {
|
||||||
|
* "{{contactus}}": "https://float.sg"
|
||||||
|
* }
|
||||||
|
* ),
|
||||||
|
* @OA\Property(
|
||||||
|
* property="receivers",
|
||||||
|
* description="List email's receivers",
|
||||||
|
* type="array",
|
||||||
|
* items="$ref: '#/components/schemas/receivers' "
|
||||||
|
*
|
||||||
|
* )
|
||||||
|
* )
|
||||||
|
*/
|
||||||