Added Other AP

This commit is contained in:
dev-chiefworks
2022-04-26 11:30:34 -04:00
parent 5e006a6a21
commit 47f4fad75c
251 changed files with 29298 additions and 4 deletions
+28
View File
@@ -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"
+152
View File
@@ -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;
}
}
+84
View File
@@ -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() {}
}
+45
View File
@@ -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);
}
}
+59
View File
@@ -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;
}
}
+13
View File
@@ -0,0 +1,13 @@
{
"name": "vendor/email",
"authors": [
{
"name": "Jack",
"email": "jack@goldenowl.asia"
}
],
"require": {
"guzzlehttp/guzzle": "~6.0",
"sendgrid/sendgrid": "~7"
}
}
+122
View File
@@ -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' "
*
* )
* )
*/
+54
View File
@@ -0,0 +1,54 @@
<?php
$profile = getenv("SAVVY_PROFILE");
if ($profile) {
require("../../core/backend.${profile}.php");
} else {
require('../../core/backend.php');
}
require_once('../common/Db.php');
require('./Email.php');
global $savvyext;
$batch_limit = 100;
$sleep_interval = 60;
$max_retries = 3;
$db = new Db();
$client = new GearmanClient();
$client->addServers($savvyext->cfgReadChar('gearman.servers'));
do {
echo "[".date("Y-m-d H:i:s")."] Scheduler is starting\n";
$i_need_some_sleep = true;
$q = "UPDATE emails SET status=0, updated_at=NOW() WHERE status = 2 AND updated_at + interval '5 minutes' < now()";
pg_query($db->getConnect(), $q);
$emails = Email::findEmails($db->getConnect(), ['status' => 2], $batch_limit+1);
if (is_array($emails) && count($emails) < $batch_limit) {
$emails = Email::findEmails($db->getConnect(), ['status' => 0,'retries' => $max_retries], $batch_limit+1 - count($emails));
if (is_array($emails) && count($emails)>0) {
echo "[".date("Y-m-d H:i:s")."] Scheduling ".count($emails)." email(s)\n";
$i = 1; // Base 1 for > condition
foreach ($emails as $email) {
if ($i>$batch_limit) {
$i_need_some_sleep = true;
break;
}
$q = "UPDATE emails SET status=2, updated_at=NOW() WHERE id=".$email['id'];
pg_query($db->getConnect(), $q);
$client->doBackground('sendemail', json_encode($email));
$i++;
}
$i_need_some_sleep = false;
}
}
if ($i_need_some_sleep) {
sleep($sleep_interval); // Sleep for 1 minute between cycles
}
} while(true);
+92
View File
@@ -0,0 +1,92 @@
<?php
$profile = getenv("SAVVY_PROFILE");
if ($profile) {
require("../../core/backend.${profile}.php");
} else {
require('../../core/backend.php');
}
require './vendor/autoload.php';
require('./Email.php');
require('./Sendgrid.php');
require_once('../common/Db.php');
global $savvyext;
$db = new Db();
$apiKey = $savvyext->cfgReadChar('mailsend.api_key');
$sg = new \SendGrid($apiKey);
$worker= new GearmanWorker();
$worker->addServers($savvyext->cfgReadChar('gearman.servers'));
$worker->addFunction('sendemail', 'sendEmailJob');
while (1)
{
$worker->work();
if ($worker->returnCode() != GEARMAN_SUCCESS) break;
}
function sendEmailJob($job) {
global $db, $sg;
echo "[".date("Y-m-d H:i:s")."] Send Email job starting\n";
$workload = $job->workload();
$email = json_decode($workload, true);
$id = $email['id'];
echo "[".date("Y-m-d H:i:s")."] Processing email ID #${id}\n";
// $q = "UPDATE emails SET status=2, updated_at=NOW() WHERE id=${id}";
// pg_query($db->getConnect(), $q);
if (is_array($email) && array_key_exists('to_emails',$email)
&& is_array($email['to_emails']) && count($email['to_emails'])>0) {
$receivers = array_map(function($to) {
return ['email' => $to];
}, $email['to_emails']);
// Prepare sendgrid receivers
$sendgridReceivers = prepareReceivers($receivers, []);
$subject = $email['subject'] ?? '';
$template = $email['html_body'] ?? '';
// Prepare email will be sent through sendgrid
$parsedEmail = SendGridService::prepareEmail($sendgridReceivers, $subject, $template, []);
// Send email
try {
$response = $sg->send($parsedEmail);
//Email::updateEmail($db->getConnect(), $id, NULL, NULL, NULL, '1');
if ($response->statusCode()==202) {
$q = "UPDATE emails SET status=1,updated_at=NOW(),message=NULL WHERE id=".$id;
$r = pg_query($db->getConnect(), $q);
} else {
throw new Exception("Invalid return status code: ".$response->statusCode());
}
echo "[".date("Y-m-d H:i:s")."] Email sent successfully.\n";
} catch(Exception $e) {
// TODO: Handle send email error.
// Maybe we can log the error here
$msg = pg_escape_string(substr($e->getMessage(),0,200));
$q = "UPDATE emails SET status=0, retries=retries+1, updated_at=NOW(),message='${msg}' WHERE id= ${id}";
$r = pg_query($db->getConnect(), $q);
echo "[".date("Y-m-d H:i:s")."] Email not sent: ${msg}\n";
}
}
echo "[".date("Y-m-d H:i:s")."] Send Email job complete\n";
}
function prepareReceivers($receivers = [], $subs = []) {
$results = [];
foreach ( $receivers as $key => $receiver ) {
$substitutions = array_merge($subs, $receiver['substitutions'] ?? []);
$results[] = SendGridService::prepareSengridToObject($receiver, $substitutions ?? []) ?? NULL;
}
return $results;
}