From 1d1a6f63a67fd7366e8ec7e874cb0f76927d0e63 Mon Sep 17 00:00:00 2001 From: Franzz Date: Mon, 13 Apr 2020 18:06:48 +0200 Subject: [PATCH] Add update emails --- inc/email.php | 155 +++++------------- inc/feed.php | 46 ++++-- inc/spot.php | 45 ++++- inc/user.php | 27 ++- index.php | 3 + languages/en.lang | 12 +- languages/fr.lang | 12 +- ...mail_confirmation.html => email_conf.html} | 6 +- masks/email_update.html | 47 ++++++ readme.md | 3 +- settings-sample.php | 2 + 11 files changed, 205 insertions(+), 153 deletions(-) rename masks/{email_confirmation.html => email_conf.html} (77%) create mode 100644 masks/email_update.html diff --git a/inc/email.php b/inc/email.php index 51135af..14eb3c2 100644 --- a/inc/email.php +++ b/inc/email.php @@ -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',', <'.$sUnsubLink.'>'); + $oPHPMailer->addCustomHeader('List-Unsubscribe-Post','List-Unsubscribe=One-Click'); + //Email Content - $sHtmlMessage = $oEmail->getMask(); + $sHtmlMessage = $this->oTemplate->getMask(); $sPlainMessage = strip_tags(str_replace('
', "\n", $sHtmlMessage)); - //Email - $iBoundary = uniqid("HTMLEMAIL"); - $sHeaders = - 'From: Spotty '.$sEOL. - 'Reply-To: Spotty '.$sEOL. - 'List-Unsubscribe: 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',', <'.$sUnsubLink.'>'); - $oPHPMailer->addCustomHeader('List-Unsubscribe-Post','List-Unsubscribe=One-Click'); - - //Email Content - $sHtmlMessage = $oEmail->getMask(); - $sPlainMessage = strip_tags(str_replace('
', "\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 { } } } - } \ No newline at end of file diff --git a/inc/feed.php b/inc/feed.php index 567256f..2aeb1a9 100644 --- a/inc/feed.php +++ b/inc/feed.php @@ -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() { diff --git a/inc/spot.php b/inc/spot.php index 05155a7..dba3e9f 100755 --- a/inc/spot.php +++ b/inc/spot.php @@ -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() { diff --git a/inc/user.php b/inc/user.php index 74ccedf..91c34e5 100644 --- a/inc/user.php +++ b/inc/user.php @@ -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); } diff --git a/index.php b/index.php index 497b7de..bbe8055 100755 --- a/index.php +++ b/index.php @@ -39,6 +39,9 @@ if($sAction!='') case 'feed': $sResult = $oSpot->getNewsFeed($iChunk); break; + case 'update_project': + $sResult = $oSpot->updateProject(); + break; case 'upload': $sResult = $oSpot->upload(); break; diff --git a/languages/en.lang b/languages/en.lang index dff86c9..01b61c6 100644 --- a/languages/en.lang +++ b/languages/en.lang @@ -78,7 +78,10 @@ nl_unsubscribe = Unsubscribe nl_unsubscribed = Done. No more junk mail from us nl_unknown_email = Unknown email address -conf_subject = Successful Registration +email_unsubscribe = PS: Changed your mind? +email_unsub_btn = Unsubscribe + +email_conf_subject = Successful Registration conf_preheader = Thanks for keeping in touch! conf_thanks_sub = You're all set! conf_body_para_1 = Thank you for checking in on my wanderings :). I'll make sure to keep you posted on my progress along the trail. @@ -86,5 +89,8 @@ conf_body_para_2 = I usually check-in once a day, plus sometimes on special even conf_body_para_3 = If I've posted some pictures recently, you should also get them in this email. conf_body_conclusion= Happy Trails! conf_signature = --François -conf_unsubscribe = PS: Changed your mind? -conf_unsubscribe_btn= Unsubscribe \ No newline at end of file + +email_update_subject= Spotted! +update_preheader = New position received +update_title = Message +update_latest_news = Latest news: \ No newline at end of file diff --git a/languages/fr.lang b/languages/fr.lang index 09af20f..9728007 100644 --- a/languages/fr.lang +++ b/languages/fr.lang @@ -78,7 +78,10 @@ nl_unsubscribe = Se désinscrire nl_unsubscribed = C'est fait. Fini le spam! nl_unknown_email = Adresse email inconnue -conf_subject = Confirmation +email_unsubscribe = PS: Trop d'emails ? +email_unsub_btn = Se désinscrire + +email_conf_subject = Confirmation conf_preheader = Merci de rester en contact ! conf_thanks_sub = C'est tout bon ! conf_body_para_1 = C'est gentil de venir voir où j'en suis. Promis, je vous tiendrais au courant de mon avancée. @@ -86,5 +89,8 @@ conf_body_para_2 = En général, j'envoie un message une fois par jour. Lorsque conf_body_para_3 = If I've posted some pictures recently, you should also get them in this email. conf_body_conclusion= A bientôt sur les chemins ! conf_signature = --François -conf_unsubscribe = PS: Trop d'emails ? -conf_unsubscribe_btn= Se désinscrire \ No newline at end of file + +email_update_subject= Nouvelle position reçue +update_preheader = Nouvelle position ! +update_title = Message +update_latest_news = Dernières nouvelles : \ No newline at end of file diff --git a/masks/email_confirmation.html b/masks/email_conf.html similarity index 77% rename from masks/email_confirmation.html rename to masks/email_conf.html index 0f064d1..b6edcd3 100644 --- a/masks/email_confirmation.html +++ b/masks/email_conf.html @@ -2,13 +2,13 @@ - [#]lang:conf_subject[#] + [#]lang:email_conf_subject[#] [#]lang:conf_preheader[#] - + @@ -25,7 +25,7 @@
logologo

[#]lang:conf_thanks_sub[#]

-

[#]lang:conf_unsubscribe[#] [#]lang:conf_unsubscribe_btn[#]

+

[#]lang:email_unsubscribe[#] [#]lang:email_unsub_btn[#]

diff --git a/masks/email_update.html b/masks/email_update.html new file mode 100644 index 0000000..763320a --- /dev/null +++ b/masks/email_update.html @@ -0,0 +1,47 @@ + + + + + [#]lang:email_update_subject[#] + + + [#]lang:update_preheader[#] + + + + + + + + + + + + + + +
logo

[#]lang:update_title[#] [#]type[#] #[#]displayed_id[#]

+
+ position +
[#]lat_dms[#] [#]lon_dms[#] +
[#]date_time[#] +
+
+

[#]lang:update_latest_news[#]

+ + + + + + +
+ +
[#]comment[#] + [#]content[#]
--[#]formatted_name[#] +
+
+
+

[#]lang:email_unsubscribe[#] [#]lang:email_unsub_btn[#]

+
+ + \ No newline at end of file diff --git a/readme.md b/readme.md index f79cea7..bc0516b 100644 --- a/readme.md +++ b/readme.md @@ -14,4 +14,5 @@ * Fix video fullscreen button on ios * Fix lightbox portrait mode: push text under * Subscribe to message feed -* Add mail frequency slider \ No newline at end of file +* Add mail frequency slider +* Add Timezone to user table \ No newline at end of file diff --git a/settings-sample.php b/settings-sample.php index 51a8755..1b39662 100755 --- a/settings-sample.php +++ b/settings-sample.php @@ -3,6 +3,8 @@ class Settings { const GEO_SERVER = 'http(s)://geo.server.tld'; + const GEO_SERVER_TOKEN = ''; + const LIVE_SERVER = 'http(s)://live.server.tld'; const DB_SERVER = 'localhost'; const DB_LOGIN = ''; const DB_PASS = '';