Add update emails

This commit is contained in:
2020-04-13 18:06:48 +02:00
parent a5fa444997
commit 47b693988a
11 changed files with 205 additions and 153 deletions

View File

@@ -10,54 +10,28 @@ require_once 'inc/PHPMailer/SMTP.php';
class Email extends PhpObject {
private $sServName;
private $sTemplate;
private $sTemplateName;
/**
*
* @var Translator[]
* Email Template
* @var Mask
*/
private $asTranslators;
/**
*
* @var Mask[]
*/
private $asTemplates;
public $oTemplate;
private $asDests;
public function __construct($sServName, $sTemplate='') {
public function __construct($sServName, $sTemplateName='') {
$this->sServName = $sServName;
$this->setTemplate($sTemplate);
$this->setTemplate($sTemplateName);
$this->asDests = array();
}
public function setTemplate($sTemplate) {
$this->sTemplate = $sTemplate;
$this->asTranslators = array();
$this->asTemplates = array();
}
private function getTemplate($sLanguage) {
if(!array_key_exists($sLanguage, $this->asTemplates)) {
$this->asTranslators[$sLanguage] = new Translator($sLanguage);
$this->buildTemplate($sLanguage);
}
return array('subject'=>$this->asTranslators[$sLanguage]->getTranslation('conf_subject'), 'email'=>$this->asTemplates[$sLanguage]);
}
private function buildTemplate($sLanguage) {
$oTemplate = new Mask($this->sTemplate, $this->asTranslators[$sLanguage]);
switch($this->sTemplate) {
case 'confirmation':
break;
case 'update':
break;
}
$this->asTemplates[$sLanguage] = $oTemplate;
public function setTemplate($sTemplateName) {
$this->sTemplateName = $sTemplateName;
$this->oTemplate = new Mask($this->sTemplateName);
$this->oTemplate->setTag('local_server', $this->sServName);
$this->oTemplate->setTag('live_server', Settings::LIVE_SERVER);
$this->oTemplate->setTag('geo_server', Settings::GEO_SERVER);
}
/**
@@ -69,91 +43,47 @@ class Email extends PhpObject {
$this->asDests = $asDests;
}
/*public function send() {
$sEOL = "\r\n";
public function send() {
foreach($this->asDests as $asDest) {
$oPHPMailer = new PHPMailer(true);
//Server settings
if(Settings::DEBUG) $oPHPMailer->SMTPDebug = SMTP::DEBUG_SERVER;//Enable verbose debug output
$oPHPMailer->isSMTP(); //Send using SMTP
$oPHPMailer->CharSet = Settings::TEXT_ENC; //Mail Character Set
$oPHPMailer->Encoding = 'base64'; //Base 64 Character Encoding
$oPHPMailer->Host = Settings::MAIL_SERVER; //Set the SMTP server to send through
$oPHPMailer->SMTPAuth = true; //Enable SMTP authentication
$oPHPMailer->Username = Settings::MAIL_USER; //SMTP username
$oPHPMailer->Password = Settings::MAIL_PASS; //SMTP password
$oPHPMailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
$oPHPMailer->Port = 587; //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
$oPHPMailer->setFrom(Settings::MAIL_FROM, 'Spotty');
$oPHPMailer->addReplyTo(Settings::MAIL_FROM, 'Spotty');
//Message
$asTemplate = $this->getTemplate($asDest['language']);
$oEmail = $asTemplate['email'];
$this->oTemplate->setLanguage($asDest['language'], Spot::DEFAULT_LANG);
//Unsubscribe Link
$sUnsubLink = $this->sServName.'?a=unsubscribe_email&id='.$asDest['id_user'];
$oEmail->setTag('unsubscribe_link', $sUnsubLink);
$this->oTemplate->setTag('unsubscribe_link', htmlspecialchars($sUnsubLink));
$oPHPMailer->addCustomHeader('List-Unsubscribe','<mailto:'.Settings::MAIL_FROM.'?subject=unsubscribe>, <'.$sUnsubLink.'>');
$oPHPMailer->addCustomHeader('List-Unsubscribe-Post','List-Unsubscribe=One-Click');
//Email Content
$sHtmlMessage = $oEmail->getMask();
$sHtmlMessage = $this->oTemplate->getMask();
$sPlainMessage = strip_tags(str_replace('<br />', "\n", $sHtmlMessage));
//Email
$iBoundary = uniqid("HTMLEMAIL");
$sHeaders =
'From: Spotty <spot@lutran.fr>'.$sEOL.
'Reply-To: Spotty <spot@lutran.fr>'.$sEOL.
'List-Unsubscribe: <mailto:unsubscribe@'.parse_url($this->sServName)['host'].'?subject=unsubscribe>, <'.$sUnsubLink.'>'.$sEOL.
'List-Unsubscribe-Post: List-Unsubscribe=One-Click'.$sEOL.
'MIME-Version: 1.0'.$sEOL.
'Content-Type: multipart/alternative; boundary="'.$iBoundary.'"'.$sEOL;
//Recipients
$oPHPMailer->addAddress($asDest['email'], $asDest['name']);
$sBody =
'--'.$iBoundary.$sEOL. //Plain Message
'Content-Type: text/plain; charset=UTF-8'.$sEOL.
'Content-Transfer-Encoding: base64'.$sEOL.
chunk_split(base64_encode($sPlainMessage)).$sEOL.
'--'.$iBoundary.$sEOL. //HTML Message
'Content-Type: text/html; charset=UTF-8'.$sEOL.
'Content-Transfer-Encoding: base64'.$sEOL.
chunk_split(base64_encode($sHtmlMessage)).$sEOL.
'--'.$iBoundary.'--';
//Send
if(!mail($asDest['email'], $asTemplate['subject'], $sBody, $sHeaders)) $this->addError('Could not send '.$this->sTemplate.' email to '.$asDest['email']);
}
}*/
public function send() {
//Instantiation and passing `true` enables exceptions
$oPHPMailer = new PHPMailer(true);
//Content
$oPHPMailer->isHTML(true);
$oPHPMailer->Subject = $this->oTemplate->getTranslator()->getTranslation($this->sTemplateName.'_subject');
$oPHPMailer->Body = $sHtmlMessage;
$oPHPMailer->AltBody = $sPlainMessage;
//Server settings
if(Settings::DEBUG) $oPHPMailer->SMTPDebug = SMTP::DEBUG_SERVER;//Enable verbose debug output
$oPHPMailer->isSMTP(); //Send using SMTP
$oPHPMailer->CharSet = Settings::TEXT_ENC; //Mail Character Set
$oPHPMailer->Encoding = 'base64'; //Base 64 Character Encoding
$oPHPMailer->Host = Settings::MAIL_SERVER; //Set the SMTP server to send through
$oPHPMailer->SMTPAuth = true; //Enable SMTP authentication
$oPHPMailer->Username = Settings::MAIL_USER; //SMTP username
$oPHPMailer->Password = Settings::MAIL_PASS; //SMTP password
$oPHPMailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; //Enable TLS encryption; `PHPMailer::ENCRYPTION_SMTPS` encouraged
$oPHPMailer->Port = 587; //TCP port to connect to, use 465 for `PHPMailer::ENCRYPTION_SMTPS` above
$oPHPMailer->setFrom(Settings::MAIL_FROM, 'Spotty');
$oPHPMailer->addReplyTo(Settings::MAIL_FROM, 'Spotty');
foreach($this->asDests as $asDest) {
try {
//Message
$asTemplate = $this->getTemplate($asDest['language']);
$oEmail = $asTemplate['email'];
//Unsubscribe Link
$sUnsubLink = $this->sServName.'?a=unsubscribe_email&id='.$asDest['id_user'];
$oEmail->setTag('unsubscribe_link', $sUnsubLink);
$oPHPMailer->addCustomHeader('List-Unsubscribe','<mailto:'.Settings::MAIL_FROM.'?subject=unsubscribe>, <'.$sUnsubLink.'>');
$oPHPMailer->addCustomHeader('List-Unsubscribe-Post','List-Unsubscribe=One-Click');
//Email Content
$sHtmlMessage = $oEmail->getMask();
$sPlainMessage = strip_tags(str_replace('<br />', "\n", $sHtmlMessage));
//Recipients
$oPHPMailer->addAddress($asDest['email'], $asDest['name']);
//Content
$oPHPMailer->isHTML(true);
$oPHPMailer->Subject = $asTemplate['subject'];
$oPHPMailer->Body = $sHtmlMessage;
$oPHPMailer->AltBody = $sPlainMessage;
$oPHPMailer->send();
}
catch (Exception $e) {
@@ -161,5 +91,4 @@ class Email extends PhpObject {
}
}
}
}

View File

@@ -10,6 +10,7 @@ class Feed extends PhpObject {
const FEED_HOOK = 'https://api.findmespot.com/spot-main-web/consumer/rest-api/2.0/public/feed/';
const FEED_TYPE_XML = '/message.xml';
const FEED_TYPE_JSON = '/message.json';
const FEED_MAX_REFRESH = 5 * 60; //Seconds
//DB Tables
const SPOT_TABLE = 'spots';
@@ -101,32 +102,40 @@ class Feed extends PhpObject {
}
public function checkUpdateFeed($sProjectMode) {
//Feed updated once every hour in Blog Mode (no need for timezone when substracting 2 dates)
$bNewMsg = false;
//Spam Check: no more than 1 API request per 5 minutes
if($sProjectMode == Project::MODE_BLOG) {
$oLastUpdate = new DateTime('@'.$this->iLastUpdate);
$oNow = new DateTime('now');
if(intval($oNow->diff($oLastUpdate)->format('%H')) > 0) $this->updateFeed();
$iSecDiff = $oNow->getTimestamp() - $oLastUpdate->getTimestamp();
if($iSecDiff > self::FEED_MAX_REFRESH) $bNewMsg = $this->updateFeed();
}
return $bNewMsg;
}
private function updateFeed() {
$bNewMsg = false;
$asData = $this->retrieveFeed();
$sLastUpdate = date(Db::TIMESTAMP_FORMAT);
if(!isset($asData['response']['errors']) || empty($asData['response']['errors'])) {
$asMsgs = $asData['response']['feedMessageResponse']['messages'];
if(array_key_exists('message', $asMsgs)) $asMsgs = $asMsgs['message'];
$asFeed = $asData['response']['feedMessageResponse']['feed'];
if(!empty($asMsgs))
{
//Fix unstable Spot API Structure
if(array_key_exists('message', $asMsgs)) $asMsgs = $asMsgs['message']; //Sometimes adds an extra "message" level
if(!array_key_exists(0, $asMsgs)) $asMsgs = array($asMsgs); //Jumps a level when there is only 1 message
//Update Spot, Feed & Messages
if(!empty($asMsgs) && array_key_exists('messengerId', $asMsgs[0])) {
//Update Spot Info from the first message
$asFirstMsg = array_values($asMsgs)[0];
$asSpotInfo = array(
'ref_spot_id' => $asFirstMsg['messengerId'],
'name' => $asFirstMsg['messengerName'],
'model' => $asFirstMsg['modelId']
'ref_spot_id' => $asMsgs[0]['messengerId'],
'name' => $asMsgs[0]['messengerName'],
'model' => $asMsgs[0]['modelId']
);
$iSpotId = $this->oDb->insertUpdateRow(self::SPOT_TABLE, $asSpotInfo, array('ref_spot_id'));
@@ -142,8 +151,7 @@ class Feed extends PhpObject {
$iFeedId = $this->oDb->insertUpdateRow(self::FEED_TABLE, $asFeedInfo, array('ref_feed_id'));
//Update Messages
foreach($asMsgs as $asMsg)
{
foreach($asMsgs as $asMsg) {
$asMsg = array(
'ref_msg_id' => $asMsg['id'],
Db::getId(self::FEED_TABLE) => $iFeedId,
@@ -151,16 +159,24 @@ class Feed extends PhpObject {
'latitude' => $asMsg['latitude'],
'longitude' => $asMsg['longitude'],
'iso_time' => $asMsg['dateTime'], //ISO 8601 time (backup)
'site_time' => date(Db::TIMESTAMP_FORMAT, $asMsg['unixTime']), //Conversion to Site Time (see Settings::TIMEZONE)
'site_time' => date(Db::TIMESTAMP_FORMAT, $asMsg['unixTime']), //Conversion to Site Time (default timezone, see Settings::TIMEZONE)
'unix_time' => $asMsg['unixTime'], //UNIX Time (backup)
'content' => $asMsg['messageContent'],
'battery_state' => $asMsg['batteryState']
);
$this->oDb->insertUpdateRow(self::MSG_TABLE, $asMsg, array('ref_msg_id'));
$iMsgId = $this->oDb->selectId(self::MSG_TABLE, array('ref_msg_id'=>$asMsg['ref_msg_id']));
if(!$iMsgId) {
$this->oDb->insertRow(self::MSG_TABLE, $asMsg);
$bNewMsg = true;
}
else $this->oDb->updateRow(self::MSG_TABLE, $iMsgId, $asMsg);
}
}
}
else $this->oDb->updateRow(self::FEED_TABLE, $this->getFeedId(), array('last_update'=>$sLastUpdate));
return $bNewMsg;
}
private function retrieveFeed() {

View File

@@ -163,12 +163,45 @@ class Spot extends Main
public function setProjectId($iProjectId=0) {
$this->oProject->setProjectId($iProjectId);
}
public function updateProject() {
$bNewMsg = false;
//Update all feeds belonging to the project
$asFeeds = $this->oProject->getFeedIds();
foreach($asFeeds as $iFeedId) {
$oFeed = new Feed($this->oDb, $iFeedId);
$oFeed->checkUpdateFeed($this->oProject->getMode());
$bNewMsg = $bNewMsg || $oFeed->checkUpdateFeed($this->oProject->getMode());
}
//Send Update Email
if($bNewMsg) {
$oEmail = new Email($this->asContext['serv_name'], 'email_update');
$oEmail->setDestInfo($this->oUser->getActiveUsersInfo());
//Add Position
$asMessages = $this->getSpotMessages();
$asLastMessage = end($asMessages);
$asLastMessage['token'] = Settings::GEO_SERVER_TOKEN;
$oEmail->oTemplate->setTags($asLastMessage);
$oEmail->oTemplate->setTag('date_time', 'lang:date_time', array(date('d/m/Y', $asLastMessage['unix_time']), date('H:i', $asLastMessage['unix_time'])));
//Add latest news feed
$asNews = $this->getNewsFeed(0, true);
$iPostCount = 0;
foreach($asNews as $asPost) {
if($asPost['type'] != 'message') {
$oEmail->oTemplate->newInstance('news');
$oEmail->oTemplate->setInstanceTag('news', 'local_server', $this->asContext['serv_name']);
$oEmail->oTemplate->addInstance($asPost['type'], $asPost);
$oEmail->oTemplate->setInstanceTag($asPost['type'], 'local_server', $this->asContext['serv_name']);
$iPostCount++;
}
if($iPostCount==5) break;
}
$oEmail->send();
}
}
@@ -177,7 +210,7 @@ class Spot extends Main
$sFileName = 'spot_cron.sh';
$sContent =
'#!/bin/bash'."\n".
'wget -qO- '.$this->asContext['serv_name'].'index.php?a=dummy > /dev/null'."\n".
'wget -qO- '.$this->asContext['serv_name'].'index.php?a=update_project > /dev/null'."\n".
'#Crontab job: 0 * * * * . '.dirname($_SERVER['SCRIPT_FILENAME']).'/'.$sFileName.' > /dev/null'."\n";
$bSuccess = (file_put_contents($sFileName, $sContent)!==false);
return self::getJsonResult($bSuccess, '');
@@ -220,7 +253,7 @@ class Spot extends Main
//Send Confirmation Email
if($asResult['result'] && $asResult['desc']=='lang:nl_subscribed') {
$oConfEmail = new Email($this->asContext['serv_name'], 'email_confirmation');
$oConfEmail = new Email($this->asContext['serv_name'], 'email_conf');
$oConfEmail->setDestInfo($asUserInfo);
$oConfEmail->send();
}
@@ -331,7 +364,7 @@ class Spot extends Main
$asData['formatted_time'] = $this->getTimeFormat($iTime);
}
public function getNewsFeed($iChunk=0)
public function getNewsFeed($iChunk=0, $bInternal=false)
{
$bHistoMode = ($this->oProject->getMode() == Project::MODE_HISTO);
$asFeeds = array();
@@ -368,9 +401,9 @@ class Spot extends Main
else ksort($asFeeds);
//Split chunks
$asFeeds = array_slice($asFeeds, $iChunk*self::FEED_CHUNK_SIZE, self::FEED_CHUNK_SIZE);
$asFeeds = array_slice($asFeeds, $iChunk * self::FEED_CHUNK_SIZE, self::FEED_CHUNK_SIZE);
return self::getJsonResult(true, '', $asFeeds);
return $bInternal?$asFeeds:self::getJsonResult(true, '', $asFeeds);
}
public function syncMedias() {

View File

@@ -22,7 +22,7 @@ class User extends PhpObject {
parent::__construct(__CLASS__, Settings::DEBUG);
$this->oDb = &$oDb;
$this->iUserId = 0;
$this->asUserInfo = array('name'=>'', 'email'=>'', 'language'=>'', 'active'=>'0');
$this->asUserInfo = array(Db::getId(self::USER_TABLE)=>0, 'name'=>'', 'email'=>'', 'language'=>'', 'active'=>'0');
$this->checkUserCookie();
}
@@ -96,22 +96,31 @@ class User extends PhpObject {
return $this->iUserId;
}
public function getUserInfo() {
$asUserInfo = $this->asUserInfo;
$asUserInfo[Db::getId(self::USER_TABLE)] = $this->iUserId;
return $asUserInfo;
}
public function setUserId($iUserId) {
$this->iUserId = 0;
$asUser = $this->oDb->selectRow(self::USER_TABLE, array(Db::getId(self::USER_TABLE)=>$iUserId, 'active'=>'1'), array_keys($this->asUserInfo));
$asUser = $this->getActiveUsersInfo($iUserId);
if(!empty($asUser)) {
$this->iUserId = $iUserId;
$this->asUserInfo = $asUser;
$this->asUserInfo = array_shift($asUser);
}
}
public function getUserInfo() {
return $this->asUserInfo;
}
public function getActiveUsersInfo($iUserId=-1) {
$asInfo = array(
'select' => array_keys($this->asUserInfo),
'from' => self::USER_TABLE,
'constraint'=> array('active'=>'1')
);
if($iUserId != -1) $asInfo['constraint'][Db::getId(self::USER_TABLE)] = $iUserId;
return $this->oDb->selectRows($asInfo);
}
private function updateCookie() {
setcookie(self::COOKIE_ID_USER, $this->iUserId, time() + 60 * 60 * 24 * 365);
}