800 lines
27 KiB
PHP
Executable File
800 lines
27 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Franzz\Spot;
|
|
use Franzz\Objects\Db;
|
|
use Franzz\Objects\Main;
|
|
use Franzz\Objects\Translator;
|
|
use Franzz\Objects\ToolBox;
|
|
use Franzz\Objects\Mask;
|
|
use \Settings;
|
|
|
|
/* Timezones
|
|
* ---------
|
|
* Site Time: Time Zone in which the User is viewing the Site (default PHP/SQL Timezone)
|
|
* Local Time: Time Zone in which the Spot Owner is
|
|
*
|
|
* - Feeds (table `feeds`):
|
|
* - last_update: timestamp in Site Time
|
|
* - Spot Messages (table `messages`):
|
|
* - unix_time: UNIX (int) in UTC
|
|
* - site_time: timestamp in Site Time
|
|
* - iso_time: raw ISO 8601 in Local Time
|
|
* - Medias (table `medias`):
|
|
* - posted_on: timestamp in Site Time
|
|
* - taken_on: timestamp in Site Time
|
|
* - Posts (table `posts`):
|
|
* - site_time: timestamp in Site Time
|
|
*/
|
|
|
|
class Spot extends Main
|
|
{
|
|
//Database
|
|
const POST_TABLE = 'posts';
|
|
|
|
const FEED_CHUNK_SIZE = 15;
|
|
const MAIL_CHUNK_SIZE = 5;
|
|
|
|
const DEFAULT_LANG = 'en';
|
|
|
|
private Project $oProject;
|
|
private Media $oMedia;
|
|
private User $oUser;
|
|
private Map $oMap;
|
|
|
|
public function __construct($sProcessPage, $sTimezone)
|
|
{
|
|
parent::__construct($sProcessPage, true, __FILE__, $sTimezone);
|
|
|
|
$this->oUser = new User($this->oDb);
|
|
|
|
$this->oLang = new Translator('', self::DEFAULT_LANG);
|
|
|
|
$this->oProject = new Project($this->oDb);
|
|
$this->oMedia = new Media($this->oDb, $this->oProject);
|
|
|
|
$this->oMap = new Map($this->oDb);
|
|
}
|
|
|
|
protected function install()
|
|
{
|
|
//Install DB
|
|
$this->oDb->install();
|
|
|
|
//Add first user
|
|
$iUserId = $this->oDb->insertRow(User::USER_TABLE, array(
|
|
'name' => 'Admin',
|
|
'email' => 'admin@admin.com',
|
|
'language' => self::DEFAULT_LANG,
|
|
'timezone' => date_default_timezone_get(),
|
|
'active' => User::USER_ACTIVE,
|
|
'clearance' => User::CLEARANCE_ADMIN
|
|
));
|
|
$this->oUser->setUserId($iUserId);
|
|
}
|
|
|
|
public function syncPics() {
|
|
if(Settings::DEBUG) {
|
|
return (new Media($this->oDb, $this->oProject))->syncFileFolder();
|
|
}
|
|
}
|
|
|
|
protected function getSqlOptions()
|
|
{
|
|
return array
|
|
(
|
|
'tables' => array
|
|
(
|
|
Feed::MSG_TABLE => array('ref_msg_id', Db::getId(Feed::FEED_TABLE), 'type', 'latitude', 'longitude', 'iso_time', 'site_time', 'timezone', 'unix_time', 'content', 'battery_state', 'posted_on', 'weather_icon', 'weather_cond', 'weather_temp'),
|
|
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'),
|
|
self::POST_TABLE => array(Db::getId(Project::PROJ_TABLE), Db::getId(User::USER_TABLE), 'name', 'content', 'site_time', 'timezone'),
|
|
Media::MEDIA_TABLE => array(Db::getId(Project::PROJ_TABLE), 'filename', 'type', 'taken_on', 'posted_on', 'timezone', 'rotate', 'comment'),
|
|
User::USER_TABLE => array('name', 'email', 'gravatar', 'language', 'timezone', 'active', 'clearance'),
|
|
Map::MAP_TABLE => array('codename', 'pattern', 'token', 'tile_size', 'min_zoom', 'max_zoom', 'attribution'),
|
|
Map::MAPPING_TABLE => array(Db::getId(Map::MAP_TABLE) , Db::getId(Project::PROJ_TABLE))
|
|
),
|
|
'types' => array
|
|
(
|
|
'active' => "BOOLEAN DEFAULT ".User::USER_INACTIVE,
|
|
'clearance' => "TINYINT(1) DEFAULT ".User::CLEARANCE_USER,
|
|
'active_from' => "TIMESTAMP DEFAULT 0",
|
|
'active_to' => "TIMESTAMP DEFAULT 0",
|
|
'battery_state' => "VARCHAR(10)",
|
|
'codename' => "VARCHAR(100)",
|
|
'content' => "LONGTEXT",
|
|
'comment' => "LONGTEXT",
|
|
'description' => "VARCHAR(100)",
|
|
'email' => "VARCHAR(320) NOT NULL",
|
|
'filename' => "VARCHAR(100) NOT NULL",
|
|
'iso_time' => "VARCHAR(24)",
|
|
'language' => "VARCHAR(2)",
|
|
'last_update' => "TIMESTAMP DEFAULT 0",
|
|
'latitude' => "DECIMAL(7,5)",
|
|
'longitude' => "DECIMAL(8,5)",
|
|
'model' => "VARCHAR(20)",
|
|
'name' => "VARCHAR(100)",
|
|
'pattern' => "VARCHAR(200) NOT NULL",
|
|
'posted_on' => "TIMESTAMP DEFAULT 0",
|
|
'ref_feed_id' => "VARCHAR(40)",
|
|
'ref_msg_id' => "INT",
|
|
'ref_spot_id' => "VARCHAR(10)",
|
|
'rotate' => "SMALLINT",
|
|
'site_time' => "TIMESTAMP DEFAULT 0", //DEFAULT 0 removes auto-set to current time
|
|
'status' => "VARCHAR(10)",
|
|
'taken_on' => "TIMESTAMP DEFAULT 0",
|
|
'timezone' => "CHAR(64)", //see mysql.time_zone_name
|
|
'token' => "VARCHAR(4096)",
|
|
'type' => "VARCHAR(20)",
|
|
'unix_time' => "INT",
|
|
'min_zoom' => "TINYINT UNSIGNED",
|
|
'max_zoom' => "TINYINT UNSIGNED",
|
|
'attribution' => "VARCHAR(100)",
|
|
'gravatar' => "LONGTEXT",
|
|
'weather_icon' => "VARCHAR(30)",
|
|
'weather_cond' => "VARCHAR(30)",
|
|
'weather_temp' => "DECIMAL(3,1)",
|
|
'tile_size' => "SMALLINT UNSIGNED DEFAULT 256"
|
|
),
|
|
'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`)",
|
|
User::USER_TABLE => "UNIQUE KEY `uni_email` (`email`)",
|
|
Map::MAP_TABLE => "UNIQUE KEY `uni_map_name` (`codename`)"
|
|
),
|
|
'cascading_delete' => array
|
|
(
|
|
Feed::SPOT_TABLE => array(Feed::FEED_TABLE),
|
|
Feed::FEED_TABLE => array(Feed::MSG_TABLE),
|
|
Project::PROJ_TABLE => array(Feed::FEED_TABLE, Media::MEDIA_TABLE, self::POST_TABLE),
|
|
Map::MAP_TABLE => array(Map::MAPPING_TABLE)
|
|
)
|
|
);
|
|
}
|
|
|
|
public function getAppMainPage()
|
|
{
|
|
//Cache Page List
|
|
$asPages = array_diff($this->asMasks, array('email_update', 'email_conf'));
|
|
if(!$this->oUser->checkUserClearance(User::CLEARANCE_ADMIN)) {
|
|
$asPages = array_diff($asPages, array('admin', 'upload'));
|
|
}
|
|
|
|
return parent::getMainPage(
|
|
array(
|
|
'vars' => array(
|
|
'chunk_size' => self::FEED_CHUNK_SIZE,
|
|
'default_project_codename' => $this->oProject->getProjectCodeName(),
|
|
'projects' => $this->oProject->getProjects(),
|
|
'user' => $this->oUser->getUserInfo()
|
|
),
|
|
'consts' => array(
|
|
'server' => $this->asContext['serv_name'],
|
|
'modes' => Project::MODES,
|
|
'clearances' => User::CLEARANCES,
|
|
'default_timezone' => Settings::TIMEZONE
|
|
)
|
|
),
|
|
'index',
|
|
array(
|
|
'language' => $this->oLang->getLanguage(),
|
|
'host_url' => $this->asContext['serv_name'],
|
|
'filepath_css' => self::addTimestampToFilePath('style/spot.css'),
|
|
'filepath_js_d3' => self::addTimestampToFilePath('script/d3.min.js'),
|
|
'filepath_js_leaflet' => self::addTimestampToFilePath('script/leaflet.min.js'),
|
|
'filepath_js_jquery' => self::addTimestampToFilePath('script/jquery.min.js'),
|
|
'filepath_js_jquery_mods' => self::addTimestampToFilePath('script/jquery.mods.js'),
|
|
'filepath_js_spot' => self::addTimestampToFilePath('script/spot.js'),
|
|
'filepath_js_lightbox' => self::addTimestampToFilePath('script/lightbox.js')
|
|
),
|
|
$asPages
|
|
);
|
|
}
|
|
|
|
public function checkUserClearance($iClearance) {
|
|
return $this->oUser->checkUserClearance($iClearance);
|
|
}
|
|
|
|
/* Managing projects */
|
|
|
|
public function setProjectId($iProjectId=0) {
|
|
$this->oProject->setProjectId($iProjectId);
|
|
}
|
|
|
|
public function updateProject() {
|
|
$bNewMsg = false;
|
|
$bSuccess = true;
|
|
$sDesc = '';
|
|
|
|
//Update all feeds belonging to the project
|
|
$asFeeds = $this->oProject->getFeedIds();
|
|
foreach($asFeeds as $iFeedId) {
|
|
$oFeed = new Feed($this->oDb, $iFeedId);
|
|
$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
|
|
$asLastMessage = array_shift($this->getSpotMessages(array($this->oProject->getLastMessageId($this->getFeedConstraints(Feed::MSG_TABLE)))));
|
|
$oEmail->oTemplate->setTags($asLastMessage);
|
|
$oEmail->oTemplate->setTag('date_time', 'time:'.$asLastMessage['unix_time'], 'd/m/Y, H:i');
|
|
|
|
//Add latest news feed
|
|
$asNews = $this->getNextFeed(0, true);
|
|
$iPostCount = 0;
|
|
foreach($asNews as $asPost) {
|
|
if($asPost['type'] != 'message') {
|
|
$oEmail->oTemplate->newInstance('news');
|
|
$oEmail->oTemplate->setInstanceTags('news', array(
|
|
'local_server' => $this->asContext['serv_name'],
|
|
'project' => $this->oProject->getProjectCodeName(),
|
|
'type' => $asPost['type'],
|
|
'id' => $asPost['id_'.$asPost['type']])
|
|
);
|
|
$oEmail->oTemplate->addInstance($asPost['type'], $asPost);
|
|
$oEmail->oTemplate->setInstanceTag($asPost['type'], 'local_server', $this->asContext['serv_name']);
|
|
$iPostCount++;
|
|
}
|
|
if($iPostCount == self::MAIL_CHUNK_SIZE) break;
|
|
}
|
|
|
|
$bSuccess = $oEmail->send();
|
|
if(!$bSuccess) $sDesc = $oEmail->ErrorInfo;
|
|
else $sDesc = 'mail_sent';
|
|
}
|
|
else $sDesc = 'no_new_msg';
|
|
|
|
return self::getJsonResult($bSuccess, $sDesc);
|
|
}
|
|
|
|
public function genCronFile() {
|
|
//$bSuccess = (file_put_contents('spot_cron.sh', '#!/bin/bash'."\n".'cd '.dirname($_SERVER['SCRIPT_FILENAME'])."\n".'php -f index.php a=update_feed')!==false);
|
|
$sFileName = 'spot_cron.sh';
|
|
$sContent =
|
|
'#!/bin/bash'."\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, '');
|
|
}
|
|
|
|
public function getMarkers($asMessageIds=array(), $asMediaIds=array(), $bInternal=false)
|
|
{
|
|
$asMessages = $this->getSpotMessages($asMessageIds);
|
|
usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
|
|
|
//Add medias
|
|
if(!empty($asMessages)) {
|
|
$asMedias = $this->getMedias('taken_on', $asMediaIds);
|
|
usort($asMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];});
|
|
|
|
//Assign medias to closest message
|
|
$iIndex = 0;
|
|
$iMaxIndex = count($asMessages) - 1;
|
|
foreach($asMedias as $asMedia) {
|
|
while($iIndex <= $iMaxIndex && $asMedia['unix_time'] > $asMessages[$iIndex]['unix_time']) {
|
|
$iIndex++;
|
|
}
|
|
|
|
//All medias before first message or after last message are assigned to first/last message respectively
|
|
if($iIndex == 0) $iMsgIndex = $iIndex;
|
|
elseif($iIndex > $iMaxIndex) $iMsgIndex = $iMaxIndex;
|
|
else {
|
|
$iHalfWayPoint = ($asMessages[$iIndex - 1]['unix_time'] + $asMessages[$iIndex]['unix_time'])/2;
|
|
$iMsgIndex = ($asMedia['unix_time'] >= $iHalfWayPoint)?$iIndex:($iIndex - 1);
|
|
}
|
|
|
|
$asMessages[$iMsgIndex]['medias'][] = $asMedia;
|
|
}
|
|
}
|
|
|
|
//Spot Last Update
|
|
$asLastUpdate = array();
|
|
$this->addTimeStamp($asLastUpdate, $this->oProject->getLastUpdate());
|
|
|
|
$asResult = array(
|
|
'messages' => $asMessages,
|
|
'maps' => $this->oMap->getProjectMaps($this->oProject->getProjectId()),
|
|
'last_update' => $asLastUpdate
|
|
);
|
|
|
|
return $bInternal?$asResult:self::getJsonResult(true, '', $asResult);
|
|
}
|
|
|
|
public function subscribe($sEmail, $sNickName) {
|
|
$asResult = $this->oUser->addUser($sEmail, $this->oLang->getLanguage(), date_default_timezone_get(), $sNickName);
|
|
$asUserInfo = $this->oUser->getUserInfo();
|
|
|
|
//Send Confirmation Email
|
|
if($asResult['result'] && $asResult['desc']=='lang:nl_subscribed') {
|
|
$oConfEmail = new Email($this->asContext['serv_name'], 'email_conf');
|
|
$oConfEmail->setDestInfo($asUserInfo);
|
|
$oConfEmail->send();
|
|
}
|
|
|
|
return self::getJsonResult($asResult['result'], $asResult['desc'], $asUserInfo);
|
|
}
|
|
|
|
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 = explode(':', $asResult['desc'])[1];
|
|
return $this->oLang->getTranslation($sDesc);
|
|
}
|
|
|
|
private function getSpotMessages($asMsgIds=array())
|
|
{
|
|
$asConstraints = $this->getFeedConstraints(Feed::MSG_TABLE);
|
|
if(!empty($asMsgIds)) {
|
|
$asConstraints['constraint'][Db::getId(Feed::MSG_TABLE)] = $asMsgIds;
|
|
$asConstraints['constOpe'][Db::getId(Feed::MSG_TABLE)] = 'IN';
|
|
}
|
|
|
|
$asCombinedMessages = array();
|
|
|
|
//Get messages from all feeds belonging to the project
|
|
$asFeeds = $this->oProject->getFeedIds();
|
|
foreach($asFeeds as $iFeedId) {
|
|
$oFeed = new Feed($this->oDb, $iFeedId);
|
|
$asMessages = $oFeed->getMessages($asConstraints);
|
|
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'] = $asMessage[Db::getId(Feed::MSG_TABLE)];
|
|
$asMessage['static_img_url'] = $this->oMap->getMapUrl('static', array('x'=>$asMessage['longitude'], 'y'=>$asMessage['latitude']));
|
|
$asMessage['marker_img_url'] = $this->oMap->getMapUrl('static_marker', array('x'=>$asMessage['longitude'], 'y'=>$asMessage['latitude']));
|
|
|
|
$this->addTimeStamp($asMessage, $asMessage['unix_time'], $asMessage['timezone']);
|
|
$asCombinedMessages[] = $asMessage;
|
|
}
|
|
}
|
|
|
|
return $asCombinedMessages;
|
|
}
|
|
|
|
/**
|
|
* Get valid medias based on $sTimeRefField:
|
|
* - taken_on: Date/time on which the media was taken
|
|
* - posted_on: Date/time on which the media was uploaded
|
|
* @param String $sTimeRefField Field to calculate relative times: 'taken_on' or 'posted_on'
|
|
* @return Array Medias info
|
|
*/
|
|
private function getMedias($sTimeRefField, $asMediaIds=array())
|
|
{
|
|
//Constraints
|
|
$asConstraints = $this->getFeedConstraints(Media::MEDIA_TABLE, $sTimeRefField);
|
|
if(!empty($asMediaIds)) {
|
|
$asConstraints['constraint'][Db::getId(Media::MEDIA_TABLE)] = $asMediaIds;
|
|
$asConstraints['constOpe'][Db::getId(Media::MEDIA_TABLE)] = 'IN';
|
|
}
|
|
|
|
$asMedias = $this->oMedia->getMediasInfo($asConstraints);
|
|
foreach($asMedias as &$asMedia) {
|
|
$iTimeStampTakenOn = strtotime($asMedia['taken_on']);
|
|
$iTimeStampPostedOn = strtotime($asMedia['posted_on']);
|
|
$asMedia['taken_on_formatted'] = $this->getTimeFormat($iTimeStampTakenOn);
|
|
$asMedia['taken_on_formatted_local'] = $this->getTimeFormat($iTimeStampTakenOn, $asMedia['timezone']);
|
|
$asMedia['posted_on_formatted'] = $this->getTimeFormat($iTimeStampPostedOn);
|
|
$asMedia['posted_on_formatted_local'] = $this->getTimeFormat($iTimeStampPostedOn, $asMedia['timezone']);
|
|
$asMedia['displayed_id'] = $asMedia[Db::getId(Media::MEDIA_TABLE)];
|
|
|
|
$this->addTimeStamp($asMedia, strtotime($asMedia[$sTimeRefField]), $asMedia['timezone']);
|
|
}
|
|
|
|
return $asMedias;
|
|
}
|
|
|
|
private function getPosts($asPostIds=array())
|
|
{
|
|
$asInfo = array(
|
|
'select' => array(Db::getFullColumnName(self::POST_TABLE, '*'), 'gravatar'),
|
|
'from' => self::POST_TABLE,
|
|
'join' => array(User::USER_TABLE => Db::getId(User::USER_TABLE))
|
|
);
|
|
$asInfo = array_merge($asInfo, $this->getFeedConstraints(self::POST_TABLE));
|
|
|
|
if(!empty($asPostIds)) {
|
|
$asInfo['constraint'][Db::getId(self::POST_TABLE)] = $asPostIds;
|
|
$asInfo['constOpe'][Db::getId(self::POST_TABLE)] = 'IN';
|
|
}
|
|
$asPosts = $this->oDb->selectRows($asInfo);
|
|
|
|
foreach($asPosts as &$asPost) {
|
|
$iUnixTimeStamp = strtotime($asPost['site_time']); //assumes site timezone
|
|
$asPost['formatted_name'] = Toolbox::mb_ucwords($asPost['name']);
|
|
unset($asPost[Db::getId(User::USER_TABLE)]);
|
|
|
|
$this->addTimeStamp($asPost, $iUnixTimeStamp, $asPost['timezone']);
|
|
}
|
|
|
|
return $asPosts;
|
|
}
|
|
|
|
private function addTimeStamp(&$asData, $iTime, $sTimeZone='') {
|
|
$asData['unix_time'] = (int) $iTime;
|
|
$asData['relative_time'] = Toolbox::getDateTimeDesc($iTime, $this->oLang->getLanguage());
|
|
$asData['formatted_time'] = $this->getTimeFormat($iTime);
|
|
if($sTimeZone != '') $asData['formatted_time_local'] = $this->getTimeFormat($iTime, $sTimeZone);
|
|
}
|
|
|
|
private function getFeedConstraints($sType, $sTimeField='site_time', $sReturnFormat='array') {
|
|
$asConsArray = array();
|
|
$sConsSql = "";
|
|
$asActPeriod = $this->oProject->getActivePeriod();
|
|
|
|
//Filter on Project ID
|
|
$sConsSql = "WHERE ".Db::getId(Project::PROJ_TABLE)." = ".$this->oProject->getProjectId();
|
|
$asConsArray = array(
|
|
'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()),
|
|
'constOpe' => array(Db::getId(Project::PROJ_TABLE) => "=")
|
|
);
|
|
|
|
//Time Filter
|
|
switch($sType) {
|
|
case Feed::MSG_TABLE:
|
|
$asConsArray['constraint'][$sTimeField] = $asActPeriod;
|
|
$asConsArray['constOpe'][$sTimeField] = "BETWEEN";
|
|
$sConsSql .= " AND ".$sTimeField." BETWEEN '".$asActPeriod['from']."' AND '".$asActPeriod['to']."'";
|
|
break;
|
|
case Media::MEDIA_TABLE:
|
|
$asConsArray['constraint'][$sTimeField] = $asActPeriod['to'];
|
|
$asConsArray['constOpe'][$sTimeField] = "<=";
|
|
$sConsSql .= " AND ".$sTimeField." <= '".$asActPeriod['to']."'";
|
|
break;
|
|
case self::POST_TABLE:
|
|
$asConsArray['constraint'][$sTimeField] = $asActPeriod['to'];
|
|
$asConsArray['constOpe'][$sTimeField] = "<=";
|
|
$sConsSql .= " AND ".$sTimeField." <= '".$asActPeriod['to']."'";
|
|
break;
|
|
}
|
|
|
|
return ($sReturnFormat=='array')?$asConsArray:$sConsSql;
|
|
}
|
|
|
|
public function getNewFeed($iRefIdFirst) {
|
|
$asResult = array();
|
|
$sDesc = '';
|
|
|
|
if($this->oProject->getMode() != Project::MODE_HISTO) {
|
|
$asMessageIds = $asMediaIds = array();
|
|
|
|
//New Feed Items
|
|
$asResult = $this->getFeed($iRefIdFirst, ">", "DESC");
|
|
foreach($asResult['feed'] as $asItem) {
|
|
switch($asItem['type']) {
|
|
case 'message':
|
|
$asMessageIds[] = $asItem['id'];
|
|
break;
|
|
case 'media':
|
|
$asMediaIds[] = $asItem['id'];
|
|
break;
|
|
}
|
|
}
|
|
|
|
//New Markers
|
|
$asMarkers = $this->getMarkers(
|
|
empty($asMessageIds)?array(0):$asMessageIds,
|
|
empty($asMediaIds)?array(0):$asMediaIds,
|
|
true
|
|
);
|
|
|
|
$asResult = array_merge($asResult, $asMarkers);
|
|
}
|
|
else $sDesc = 'mode_histo';
|
|
|
|
return self::getJsonResult(true, $sDesc, $asResult);
|
|
}
|
|
|
|
public function getNextFeed($iRefIdLast=0, $bInternal=false) {
|
|
if($this->oProject->getMode() == Project::MODE_HISTO) {
|
|
$sDirection = ">";
|
|
$sSort = "ASC";
|
|
}
|
|
else {
|
|
$sDirection = "<";
|
|
$sSort = "DESC";
|
|
}
|
|
$asResult = $this->getFeed($iRefIdLast, $sDirection, $sSort);
|
|
return $bInternal?$asResult['feed']:self::getJsonResult(true, '', $asResult);
|
|
}
|
|
|
|
public function getFeed($iRefId=0, $sDirection, $sSort) {
|
|
$this->oDb->cleanSql($iRefId);
|
|
$this->oDb->cleanSql($sDirection);
|
|
$this->oDb->cleanSql($sSort);
|
|
|
|
$sMediaRefField = 'posted_on';
|
|
$sProjectIdField = Db::getId(Project::PROJ_TABLE);
|
|
$sMsgIdField = Db::getId(Feed::MSG_TABLE);
|
|
$sMediaIdField = Db::getId(Media::MEDIA_TABLE);
|
|
$sPostIdField = Db::getId(self::POST_TABLE);
|
|
$sFeedIdField = Db::getId(Feed::FEED_TABLE);
|
|
$sQuery = implode(" ", array(
|
|
"SELECT type, id, ref",
|
|
"FROM (",
|
|
"SELECT {$sProjectIdField}, {$sMsgIdField} AS id, 'message' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.0', {$sMsgIdField}) AS ref",
|
|
"FROM ".Feed::MSG_TABLE,
|
|
"INNER JOIN ".Feed::FEED_TABLE." USING({$sFeedIdField})",
|
|
$this->getFeedConstraints(Feed::MSG_TABLE, 'site_time', 'sql'),
|
|
"UNION",
|
|
"SELECT {$sProjectIdField}, {$sMediaIdField} AS id, 'media' AS type, CONCAT(UNIX_TIMESTAMP({$sMediaRefField}), '.1', {$sMediaIdField}) AS ref",
|
|
"FROM ".Media::MEDIA_TABLE,
|
|
$this->getFeedConstraints(Media::MEDIA_TABLE, $sMediaRefField, 'sql'),
|
|
"UNION",
|
|
"SELECT {$sProjectIdField}, {$sPostIdField} AS id, 'post' AS type, CONCAT(UNIX_TIMESTAMP(site_time), '.2', {$sPostIdField}) AS ref",
|
|
"FROM ".self::POST_TABLE,
|
|
$this->getFeedConstraints(self::POST_TABLE, 'site_time', 'sql'),
|
|
") AS items",
|
|
($iRefId > 0)?("WHERE ref ".$sDirection." ".$iRefId):"",
|
|
"ORDER BY ref ".$sSort,
|
|
"LIMIT ".self::FEED_CHUNK_SIZE
|
|
));
|
|
|
|
//Get new chunk
|
|
$asItems = $this->oDb->getArrayQuery($sQuery, true);
|
|
|
|
//Update Reference Point with latest/earliest value
|
|
$iRefIdFirst = $iRefIdLast = 0;
|
|
if(!empty($asItems)) {
|
|
$iRefIdLast = end($asItems)['ref'];
|
|
$iRefIdFirst = reset($asItems)['ref'];
|
|
}
|
|
|
|
//Sort Table IDs by type & Get attributes
|
|
$asFeedIds = array('message'=>array(), 'media'=>array(), 'message'=>array());
|
|
foreach($asItems as $asItem) {
|
|
$asFeedIds[$asItem['type']][$asItem['id']] = $asItem;
|
|
}
|
|
$asFeedAttrs = array(
|
|
'message' => empty($asFeedIds['message'])?array():$this->getSpotMessages(array_keys($asFeedIds['message'])),
|
|
'media' => empty($asFeedIds['media'])?array():$this->getMedias($sMediaRefField, array_keys($asFeedIds['media'])),
|
|
'post' => empty($asFeedIds['post'])?array():$this->getPosts(array_keys($asFeedIds['post']))
|
|
);
|
|
|
|
//Replace Array Key with Item ID
|
|
foreach($asFeedAttrs as $sType=>$asFeedAttr) {
|
|
foreach($asFeedAttr as $asFeed) {
|
|
$asFeeds[$sType][$asFeed['id_'.$sType]] = $asFeed;
|
|
}
|
|
}
|
|
|
|
//Assign
|
|
foreach($asItems as &$asItem) {
|
|
$asItem = array_merge($asFeeds[$asItem['type']][$asItem['id']], $asItem);
|
|
}
|
|
|
|
return array('ref_id_last'=>$iRefIdLast, 'ref_id_first'=>$iRefIdFirst, 'sort'=>$sSort, 'feed'=>$asItems);
|
|
}
|
|
|
|
public function syncMedias() {
|
|
return $this->oMedia->syncFileFolder();
|
|
}
|
|
|
|
public function addPost($sName, $sPost)
|
|
{
|
|
$iPostId = 0;
|
|
$sDesc = '';
|
|
|
|
if($this->oProject->getMode() != Project::MODE_HISTO) {
|
|
$asData = array(
|
|
Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(),
|
|
'name' => mb_strtolower(trim($sName)),
|
|
'content' => trim($sPost),
|
|
'site_time' => date(Db::TIMESTAMP_FORMAT), //Now in Site Time
|
|
'timezone' => date_default_timezone_get() //Site Time Zone
|
|
);
|
|
if($this->oUser->getUserId() > 0) $asData[Db::getId(User::USER_TABLE)] = $this->oUser->getUserId();
|
|
|
|
$iPostId = $this->oDb->insertRow(self::POST_TABLE, $asData);
|
|
|
|
$this->oUser->updateNickname($sName);
|
|
}
|
|
else $sDesc = 'mode_histo';
|
|
|
|
return self::getJsonResult(($iPostId > 0), $sDesc);
|
|
}
|
|
|
|
public function upload()
|
|
{
|
|
$oUploader = new Uploader($this->oMedia, $this->oLang);
|
|
|
|
return $oUploader->sBody;
|
|
}
|
|
|
|
public function addComment($iMediaId, $sComment) {
|
|
$oMedia = new Media($this->oDb, $this->oProject, $iMediaId);
|
|
$asResult = $oMedia->setComment($sComment);
|
|
return self::getJsonResult($asResult['result'], $asResult['desc'], $asResult['data']);
|
|
}
|
|
|
|
public function getAdminSettings($sType='') {
|
|
$oFeed = new Feed($this->oDb);
|
|
$asData = array(
|
|
'project' => $this->oProject->getProjects(),
|
|
'feed' => $oFeed->getFeeds(),
|
|
'spot' => $oFeed->getSpots(),
|
|
'user' => $this->oUser->getActiveUsersInfo()
|
|
);
|
|
|
|
foreach($asData['project'] as &$asProject) {
|
|
$asProject['active_from'] = substr($asProject['active_from'], 0, 10);
|
|
$asProject['active_to'] = substr($asProject['active_to'], 0, 10);
|
|
}
|
|
|
|
return self::getJsonResult(true, '', $asData);
|
|
}
|
|
|
|
public function setAdminSettings($sType, $iId, $sField, $sValue) {
|
|
$bSuccess = false;
|
|
$sDesc = '';
|
|
$asResult = array();
|
|
|
|
switch($sType) {
|
|
case 'project':
|
|
$oProject = new Project($this->oDb, $iId);
|
|
switch($sField) {
|
|
case 'name':
|
|
$bSuccess = $oProject->setProjectName($sValue);
|
|
break;
|
|
case 'codename':
|
|
$bSuccess = $oProject->setProjectCodeName($sValue);
|
|
break;
|
|
case 'active_from':
|
|
$bSuccess = $oProject->setActivePeriod($sValue.' 00:00:00', 'from');
|
|
break;
|
|
case 'active_to':
|
|
$bSuccess = $oProject->setActivePeriod($sValue.' 23:59:59', 'to');
|
|
break;
|
|
default:
|
|
$sDesc = $this->oLang->getTranslation('unknown_field', $sField);
|
|
}
|
|
$asResult = $oProject->getProject();
|
|
$asResult['active_from'] = substr($asResult['active_from'], 0, 10);
|
|
$asResult['active_to'] = substr($asResult['active_to'], 0, 10);
|
|
break;
|
|
case 'feed':
|
|
$oFeed = new Feed($this->oDb, $iId);
|
|
switch($sField) {
|
|
case 'ref_feed_id':
|
|
$bSuccess = $oFeed->setRefFeedId($sValue);
|
|
break;
|
|
case 'id_spot':
|
|
$bSuccess = $oFeed->setSpotId($sValue);
|
|
break;
|
|
case 'id_project':
|
|
$bSuccess = $oFeed->setProjectId($sValue);
|
|
break;
|
|
default:
|
|
$sDesc = $this->oLang->getTranslation('unknown_field', $sField);
|
|
}
|
|
$asResult = $oFeed->getFeed();
|
|
break;
|
|
case 'user':
|
|
switch($sField) {
|
|
case 'clearance':
|
|
$asReturnCode = $this->oUser->setUserClearance($iId, $sValue);
|
|
$bSuccess = $asReturnCode['result'];
|
|
$sDesc = $asReturnCode['desc'];
|
|
break;
|
|
default:
|
|
$sDesc = $this->oLang->getTranslation('unknown_field', $sField);
|
|
}
|
|
$asResult = $this->oUser->getActiveUserInfo($iId);
|
|
break;
|
|
}
|
|
if(!$bSuccess && $sDesc=='') $sDesc = Mask::LANG_PREFIX.'error_commit_db';
|
|
|
|
return self::getJsonResult($bSuccess, $sDesc, array($sType=>array($asResult)));
|
|
}
|
|
|
|
public function delAdminSettings($sType, $iId) {
|
|
$bSuccess = false;
|
|
$sDesc = '';
|
|
|
|
switch($sType) {
|
|
case 'project':
|
|
$oProject = new Project($this->oDb, $iId);
|
|
$asResult = $oProject->delete();
|
|
$sDesc = $asResult['project'][0]['desc'];
|
|
break;
|
|
case 'feed':
|
|
$oFeed = new Feed($this->oDb, $iId);
|
|
$asResult = array('feed'=>array($oFeed->delete()));
|
|
$sDesc = $asResult['feed'][0]['desc'];
|
|
break;
|
|
}
|
|
$bSuccess = ($sDesc=='');
|
|
|
|
return self::getJsonResult($bSuccess, $sDesc, $asResult);
|
|
}
|
|
|
|
public function createProject() {
|
|
$oProject = new Project($this->oDb);
|
|
$iNewProjectId = $oProject->createProjectId();
|
|
|
|
$oFeed = new Feed($this->oDb);
|
|
$oFeed->createFeedId($iNewProjectId);
|
|
|
|
return self::getJsonResult($iNewProjectId>0, '', array(
|
|
'project' => array($oProject->getProject()),
|
|
'feed' => array($oFeed->getFeed())
|
|
));
|
|
}
|
|
|
|
public static function decToDms($dValue, $sType) {
|
|
if($sType=='lat') $sDirection = ($dValue >= 0)?'N':'S'; //Latitude
|
|
else $sDirection = ($dValue >= 0)?'E':'W'; //Longitude
|
|
|
|
$dLeft = abs($dValue);
|
|
|
|
//Degrees
|
|
$iDegree = floor($dLeft);
|
|
$dLeft -= $iDegree;
|
|
|
|
//Minutes
|
|
$iMinute = floor($dLeft * 60);
|
|
$dLeft -= $iMinute / 60;
|
|
|
|
//Seconds
|
|
$fSecond = round($dLeft * 3600, 1);
|
|
|
|
return
|
|
$iDegree.'°'.
|
|
self::getNumberWithLeadingZeros($iMinute, 2, 0)."'".
|
|
self::getNumberWithLeadingZeros($fSecond, 2, 1).'"'.
|
|
$sDirection;
|
|
}
|
|
|
|
public static function getNumberWithLeadingZeros($fValue, $iNbLeadingZeros, $iNbDigits){
|
|
$sDecimalSeparator = ".";
|
|
if($iNbDigits > 0) $iNbLeadingZeros += mb_strlen($sDecimalSeparator) + $iNbDigits;
|
|
$sPattern = '%0'.$iNbLeadingZeros.$sDecimalSeparator.$iNbDigits.'f';
|
|
return sprintf($sPattern, $fValue);
|
|
}
|
|
|
|
public function getTimeFormat($iTime, $sTimeZone='') {
|
|
if($sTimeZone=='') $sTimeZone = date_default_timezone_get();
|
|
|
|
$oDate = new \DateTime('@'.$iTime);
|
|
$oDate->setTimezone(new \DateTimeZone($sTimeZone));
|
|
|
|
$sDate = $oDate->format('d/m/Y');
|
|
$sTime = $oDate->format('H:i');
|
|
return $this->oLang->getTranslation('date_time', array($sDate, $sTime));
|
|
}
|
|
|
|
public static function getTimeZoneFromDate($sDate) {
|
|
$sTimeZone = null;
|
|
|
|
preg_match('/(?<timezone>(\+|\-)\d{2}:?(\d{2}|))$/', $sDate, $asMatch);
|
|
if(array_key_exists('timezone', $asMatch)) {
|
|
$sTimeZone = $asMatch['timezone'];
|
|
|
|
//Complete short form: +12 => +1200
|
|
if(strlen($sTimeZone) == 3) $sTimeZone .= '00';
|
|
|
|
//Add colon: +1200 => +12:00
|
|
if(!strpos($sTimeZone, ':')) $sTimeZone = substr_replace($sTimeZone, ':', 3, 0);
|
|
}
|
|
return $sTimeZone;
|
|
}
|
|
}
|