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::MAPPING_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->isEditable()) { $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->isEditable()) { $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('/(?(\+|\-)\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; } }