New settings panel & &subscription
This commit is contained in:
106
inc/email.php
Normal file
106
inc/email.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
class Email extends PhpObject {
|
||||
|
||||
private $sServName;
|
||||
private $sTemplate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Translator[]
|
||||
*/
|
||||
private $asTranslators;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var Mask[]
|
||||
*/
|
||||
private $asTemplates;
|
||||
|
||||
private $asDests;
|
||||
|
||||
public function __construct($sServName, $sTemplate='') {
|
||||
$this->sServName = $sServName;
|
||||
$this->setTemplate($sTemplate);
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Target User Info
|
||||
* @param array $asDests Contains: id_user, name, email, language, active
|
||||
*/
|
||||
public function setDestInfo($asDests) {
|
||||
if(array_key_exists('email', $asDests)) $asDests = array($asDests);
|
||||
$this->asDests = $asDests;
|
||||
}
|
||||
|
||||
public function send() {
|
||||
$sEOL = "\r\n";
|
||||
foreach($this->asDests as $asDest) {
|
||||
//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);
|
||||
|
||||
//Email Content
|
||||
$sHtmlMessage = $oEmail->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;
|
||||
|
||||
$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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ class Feed extends PhpObject {
|
||||
}
|
||||
|
||||
public function checkUpdateFeed($sProjectMode) {
|
||||
//Feed updated once a day in Blog Mode
|
||||
//Feed updated once every hour in Blog Mode
|
||||
if($sProjectMode == Project::MODE_BLOG && date('Y-m-d-H', $this->iLastUpdate) != date('Y-m-d-H')) $this->updateFeed();
|
||||
}
|
||||
|
||||
|
||||
98
inc/spot.php
98
inc/spot.php
@@ -21,6 +21,8 @@ class Spot extends Main
|
||||
|
||||
const FEED_CHUNK_SIZE = 15;
|
||||
|
||||
const DEFAULT_LANG = 'en';
|
||||
|
||||
/**
|
||||
* Active Project
|
||||
* @var Project
|
||||
@@ -33,18 +35,27 @@ class Spot extends Main
|
||||
*/
|
||||
private $oMedia;
|
||||
|
||||
/**
|
||||
* User
|
||||
* @var User
|
||||
*/
|
||||
private $oUser;
|
||||
|
||||
public function __construct($oClassManagement, $sProcessPage, $sTimezone)
|
||||
{
|
||||
$asClasses = array(
|
||||
array('name'=>'feed', 'project'=>true),
|
||||
array('name'=>'project', 'project'=>true),
|
||||
array('name'=>'media', 'project'=>true),
|
||||
array('name'=>'converter', 'project'=>true)
|
||||
array('name'=>'converter', 'project'=>true),
|
||||
array('name'=>'user', 'project'=>true)
|
||||
);
|
||||
parent::__construct($oClassManagement, $sProcessPage, $asClasses, true, __FILE__, $sTimezone);
|
||||
|
||||
$this->oUser = new User($this->oDb);
|
||||
|
||||
$this->oClassManagement->incClass('translator');
|
||||
$this->oLang = new Translator('', 'en');
|
||||
$this->oLang = new Translator($this->oUser->getLang(), self::DEFAULT_LANG);
|
||||
|
||||
$this->oProject = new Project($this->oDb);
|
||||
$this->oMedia = new Media($this->oDb, $this->oProject);
|
||||
@@ -60,16 +71,17 @@ class Spot extends Main
|
||||
{
|
||||
return array
|
||||
(
|
||||
'tables' => array
|
||||
'tables' => array
|
||||
(
|
||||
Feed::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'unix_time', 'content', 'battery_state'),
|
||||
Feed::FEED_TABLE => array('ref_feed_id', Db::getId(Feed::SPOT_TABLE), Db::getId(Project::PROJ_TABLE), 'name', 'description', 'status', 'last_update'),
|
||||
Feed::SPOT_TABLE => array('ref_spot_id', 'name', 'model'),
|
||||
Project::PROJ_TABLE => array('name', 'codename', 'active_from', 'active_to', 'timezone'),
|
||||
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), 'name', 'content', 'site_time'),
|
||||
Media::MEDIA_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'type', 'taken_on', 'posted_on', 'rotate', 'comment')
|
||||
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), Db::getId(User::USER_TABLE), 'name', 'content', 'site_time'),
|
||||
Media::MEDIA_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'type', 'taken_on', 'posted_on', 'rotate', 'comment'),
|
||||
User::USER_TABLE => array('name', 'email', 'language', 'active')
|
||||
),
|
||||
'types' => array
|
||||
'types' => array
|
||||
(
|
||||
'ref_msg_id' => "INT",
|
||||
'type' => "VARCHAR(20)",
|
||||
@@ -95,19 +107,23 @@ class Spot extends Main
|
||||
'taken_on' => "TIMESTAMP DEFAULT 0",
|
||||
'posted_on' => "TIMESTAMP DEFAULT 0",
|
||||
'rotate' => "SMALLINT",
|
||||
'comment' => "LONGTEXT"
|
||||
'comment' => "LONGTEXT",
|
||||
'email' => "VARCHAR(320)",
|
||||
'language' => "VARCHAR(2)",
|
||||
'active' => "BOOLEAN"
|
||||
),
|
||||
'constraints' => array
|
||||
'constraints' => array
|
||||
(
|
||||
Feed::MSG_TABLE => array("UNIQUE KEY `uni_ref_msg_id` (`ref_msg_id`)", "INDEX(`ref_msg_id`)"),
|
||||
Feed::FEED_TABLE => array("UNIQUE KEY `uni_ref_feed_id` (`ref_feed_id`)", "INDEX(`ref_feed_id`)"),
|
||||
Feed::SPOT_TABLE => array("UNIQUE KEY `uni_ref_spot_id` (`ref_spot_id`)", "INDEX(`ref_spot_id`)"),
|
||||
Project::PROJ_TABLE => "UNIQUE KEY `uni_proj_name` (`codename`)",
|
||||
Media::MEDIA_TABLE => "UNIQUE KEY `uni_file_name` (`filename`)"
|
||||
Media::MEDIA_TABLE => "UNIQUE KEY `uni_file_name` (`filename`)",
|
||||
User::USER_TABLE => "UNIQUE KEY `uni_email` (`email`)"
|
||||
),
|
||||
'cascading_delete' => array
|
||||
'cascading_delete' => array
|
||||
(
|
||||
Feed::SPOT_TABLE=>array(Feed::MSG_TABLE)
|
||||
Feed::SPOT_TABLE => array(Feed::MSG_TABLE)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -119,7 +135,8 @@ class Spot extends Main
|
||||
'vars' => array(
|
||||
'chunk_size' => self::FEED_CHUNK_SIZE,
|
||||
'default_project_codename' => $this->oProject->getProjectCodeName(),
|
||||
'projects' => $this->oProject->getProjects()
|
||||
'projects' => $this->oProject->getProjects(),
|
||||
'user' => $this->oUser->getUserInfo()
|
||||
),
|
||||
'consts' => array(
|
||||
'geo_server' => Settings::GEO_SERVER,
|
||||
@@ -155,7 +172,7 @@ class Spot extends Main
|
||||
public function getMarkers()
|
||||
{
|
||||
$asMessages = $this->getSpotMessages();
|
||||
$bSuccess = !empty($asMessages);
|
||||
$bSuccess = !empty($this->getMedias('posted_on') + $asMessages + $this->getPosts());
|
||||
$sDesc = $bSuccess?'':self::NO_DATA;
|
||||
|
||||
//Add medias
|
||||
@@ -183,6 +200,35 @@ class Spot extends Main
|
||||
return self::getJsonResult($bSuccess, $sDesc, $asMessages);
|
||||
}
|
||||
|
||||
public function subscribe($sEmail) {
|
||||
$asResult = $this->oUser->addUser($sEmail, $this->oLang->getLanguage());
|
||||
|
||||
//Send Confirmation Email
|
||||
if($asResult['result']) {
|
||||
$this->oClassManagement->incClass('email', true);
|
||||
$oConfEmail = new Email($this->asContext['serv_name'],'email_confirmation');
|
||||
$oConfEmail->setDestInfo($this->oUser->getUserInfo());
|
||||
$oConfEmail->send();
|
||||
}
|
||||
|
||||
return self::getJsonResult($asResult['result'], $asResult['desc'], $asResult['data']);
|
||||
}
|
||||
|
||||
public function unsubscribe() {
|
||||
$asResult = $this->oUser->removeUser();
|
||||
return self::getJsonResult($asResult['result'], $asResult['desc'], $asResult['data']);
|
||||
}
|
||||
|
||||
public function unsubscribeFromEmail($iUserId) {
|
||||
$this->oUser->setUserId($iUserId);
|
||||
$this->oLang->setLanguage($this->oUser->getLang(), self::DEFAULT_LANG);
|
||||
$asResult = $this->oUser->removeUser();
|
||||
|
||||
$sDesc = $asResult['desc'];
|
||||
if($sDesc=='') $sDesc = $this->oLang->getTranslation('nl_unsubscribed');
|
||||
return $sDesc;
|
||||
}
|
||||
|
||||
private function getSpotMessages()
|
||||
{
|
||||
$asMessages = array();
|
||||
@@ -192,20 +238,22 @@ class Spot extends Main
|
||||
foreach($asFeeds as $iFeedId) {
|
||||
$oFeed = new Feed($this->oDb, $iFeedId);
|
||||
$asMessages = $oFeed->getMessages($this->oProject->getActivePeriod());
|
||||
foreach($asMessages as $iIndex=>&$asMessage)
|
||||
foreach($asMessages as &$asMessage)
|
||||
{
|
||||
$asMessage['latitude'] = floatval($asMessage['latitude']);
|
||||
$asMessage['longitude'] = floatval($asMessage['longitude']);
|
||||
$asMessage['lat_dms'] = self::decToDms($asMessage['latitude'], 'lat');
|
||||
$asMessage['lon_dms'] = self::decToDms($asMessage['longitude'], 'lon');
|
||||
$asMessage['displayed_id'] = $iIndex + 1;
|
||||
|
||||
$this->addTimeStamp($asMessage, $asMessage['unix_time']);
|
||||
}
|
||||
}
|
||||
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
|
||||
return $asMessages;
|
||||
$asSortedMessages = array_values($asMessages);
|
||||
foreach($asSortedMessages as $iIndex=>&$asSortedMessage) $asSortedMessage['displayed_id'] = $iIndex + 1;
|
||||
|
||||
return $asSortedMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,20 +267,23 @@ class Spot extends Main
|
||||
{
|
||||
$asMedias = $this->oMedia->getMediasInfo();
|
||||
$asValidMedias = array();
|
||||
foreach($asMedias as $iIndex=>$asMedia) {
|
||||
foreach($asMedias as $asMedia) {
|
||||
$sTimeRef = $asMedia[$sTimeRefField];
|
||||
if($sTimeRef >= $this->oProject->getActivePeriod('from') && $sTimeRef <= $this->oProject->getActivePeriod('to')) {
|
||||
$asMedia['taken_on_formatted'] = $this->getTimeFormat(strtotime($asMedia['taken_on']));
|
||||
$asMedia['posted_on_formatted'] = $this->getTimeFormat(strtotime($asMedia['posted_on']));
|
||||
$asMedia['displayed_id'] = $iIndex + 1;
|
||||
|
||||
$this->addTimeStamp($asMedia, strtotime($sTimeRef));
|
||||
$asValidMedias[] = $asMedia;
|
||||
}
|
||||
}
|
||||
|
||||
usort($asValidMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
||||
|
||||
return $asValidMedias;
|
||||
$asSortedMedias = array_values($asValidMedias);
|
||||
foreach($asSortedMedias as $iIndex=>&$asSortedMedia) $asSortedMedia['displayed_id'] = $iIndex + 1;
|
||||
|
||||
return $asSortedMedias;
|
||||
}
|
||||
|
||||
private function getPosts()
|
||||
@@ -251,6 +302,7 @@ class Spot extends Main
|
||||
foreach($asPosts as &$asPost) {
|
||||
$iUnixTimeStamp = strtotime($asPost['site_time']); //assumes site timezone (Settings::TIMEZONE)
|
||||
$asPost['formatted_name'] = Toolbox::mb_ucwords($asPost['name']);
|
||||
unset($asPost[Db::getId(User::USER_TABLE)]);
|
||||
|
||||
$this->addTimeStamp($asPost, $iUnixTimeStamp);
|
||||
}
|
||||
@@ -314,12 +366,16 @@ class Spot extends Main
|
||||
public function addPost($sName, $sPost)
|
||||
{
|
||||
$asData = array(
|
||||
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
||||
Db::getId(User::USER_TABLE) => $this->oUser->getUserId(),
|
||||
'name' => mb_strtolower(trim($sName)),
|
||||
'content' => trim($sPost),
|
||||
'site_time' => date(Db::TIMESTAMP_FORMAT) //site time (Settings::TIMEZONE)
|
||||
);
|
||||
$iPostId = $this->oDb->insertRow(self::POST_TABLE, $asData);
|
||||
|
||||
$this->oUser->updateNickname($sName);
|
||||
|
||||
return self::getJsonResult(($iPostId > 0), '');
|
||||
}
|
||||
|
||||
@@ -342,7 +398,7 @@ class Spot extends Main
|
||||
return self::getJsonResult(true, '', array(
|
||||
'project' => $this->oProject->getProjects(),
|
||||
'feed' => $oFeed->getFeeds(),
|
||||
'spot' => $oFeed->getSpots()
|
||||
'spot' => $oFeed->getSpots()
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
108
inc/user.php
Normal file
108
inc/user.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
class User extends PhpObject {
|
||||
|
||||
//DB Tables
|
||||
const USER_TABLE = 'users';
|
||||
|
||||
//Cookie
|
||||
const COOKIE_ID_USER = 'subscriber';
|
||||
|
||||
/**
|
||||
* Database Handle
|
||||
* @var Db
|
||||
*/
|
||||
private $oDb;
|
||||
|
||||
//User Info
|
||||
private $iUserId;
|
||||
private $asUserInfo;
|
||||
|
||||
public function __construct(Db &$oDb) {
|
||||
parent::__construct(__CLASS__, Settings::DEBUG);
|
||||
$this->oDb = &$oDb;
|
||||
$this->iUserId = 0;
|
||||
$this->asUserInfo = array('name'=>'', 'email'=>'', 'language'=>'', 'active'=>0);
|
||||
$this->checkUserCookie();
|
||||
}
|
||||
|
||||
public function getLang() {
|
||||
return $this->asUserInfo['language'];
|
||||
}
|
||||
|
||||
public function addUser($sEmail, $sLang) {
|
||||
$bSuccess = false;
|
||||
$sDesc = '';
|
||||
$sEmail = trim($sEmail);
|
||||
|
||||
//Check Email availability
|
||||
$iUserId = $this->oDb->selectValue(self::USER_TABLE, Db::getId(self::USER_TABLE), array('email'=>$sEmail, 'active'=>true));
|
||||
|
||||
if($iUserId > 0) $sDesc = 'lang:nl_email_exists';
|
||||
else {
|
||||
//Add/Reactivate user
|
||||
$iUserId = $this->oDb->insertUpdateRow(self::USER_TABLE, array('email'=>$sEmail, 'language'=>$sLang, 'active'=>true), array('email'));
|
||||
if($iUserId==0) $sDesc = 'lang:error_commit_db';
|
||||
else $bSuccess = true;
|
||||
}
|
||||
|
||||
//Set Cookie (valid 1 year)
|
||||
if($iUserId > 0) {
|
||||
$this->setUserId($iUserId);
|
||||
$this->updateCookie();
|
||||
}
|
||||
|
||||
return Spot::getResult($bSuccess, $sDesc, $this->getUserInfo());
|
||||
}
|
||||
|
||||
public function removeUser() {
|
||||
$bSuccess = false;
|
||||
$sDesc = '';
|
||||
|
||||
if($this->iUserId > 0) {
|
||||
$iUserId = $this->oDb->updateRow(self::USER_TABLE, $this->iUserId, array('active'=>false));
|
||||
if($iUserId==0) $sDesc = 'lang:error_commit_db';
|
||||
else $bSuccess = true;
|
||||
}
|
||||
else $sDesc = 'lang:nl_unknown_email';
|
||||
|
||||
return Spot::getResult($bSuccess, $sDesc);
|
||||
}
|
||||
|
||||
public function updateNickname($sNickname) {
|
||||
if($this->iUserId > 0 && $sNickname!='') $this->oDb->updateRow(self::USER_TABLE, $this->iUserId, array('name'=>$sNickname));
|
||||
}
|
||||
|
||||
private function checkUserCookie() {
|
||||
if(isset($_COOKIE[self::COOKIE_ID_USER])){
|
||||
$this->setUserId($_COOKIE[self::COOKIE_ID_USER]);
|
||||
|
||||
//Extend cookie life
|
||||
if($this->iUserId > 0) $this->updateCookie();
|
||||
}
|
||||
}
|
||||
|
||||
public function getUserId() {
|
||||
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'=>true), array_keys($this->asUserInfo));
|
||||
if(!empty($asUser)) {
|
||||
$this->iUserId = $iUserId;
|
||||
$this->asUserInfo = $asUser;
|
||||
}
|
||||
}
|
||||
|
||||
private function updateCookie() {
|
||||
setcookie(self::COOKIE_ID_USER, $this->iUserId, time() + 60 * 60 * 24 * 365);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user