'feed', 'project'=>true), array('name'=>'project', 'project'=>true), array('name'=>'media', 'project'=>true), array('name'=>'converter', 'project'=>true) ); parent::__construct($oClassManagement, $sProcessPage, $asClasses); $this->oProject = new Project($this->oDb); $this->oMedia = new Media($this->oDb, $this->oProject); } protected function install() { //Install DB $this->oDb->install(); } 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', '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', 'geofile', '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') ), 'types' => array ( 'ref_msg_id' => "INT", 'type' => "VARCHAR(20)", 'latitude' => "DECIMAL(7,5)", 'longitude' => "DECIMAL(8,5)", 'iso_time' => "VARCHAR(24)", 'site_time' => "TIMESTAMP DEFAULT 0", //DEFAULT 0 removes auto-set to current time 'unix_time' => "INT", 'content' => "LONGTEXT", 'battery_state' => "VARCHAR(10)", 'ref_spot_id' => "VARCHAR(10)", 'name' => "VARCHAR(100)", 'codename' => "VARCHAR(100)", 'model' => "VARCHAR(20)", 'ref_feed_id' => "VARCHAR(40)", 'description' => "VARCHAR(100)", 'status' => "VARCHAR(10)", 'active_from' => "TIMESTAMP DEFAULT 0", 'active_to' => "TIMESTAMP DEFAULT 0", 'geofile' => "VARCHAR(50)", 'timezone' => "VARCHAR(100)", 'last_update' => "TIMESTAMP DEFAULT 0", 'filename' => "VARCHAR(100) NOT NULL", 'taken_on' => "TIMESTAMP DEFAULT 0", 'posted_on' => "TIMESTAMP DEFAULT 0", 'rotate' => "SMALLINT" ), '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`)" ), 'cascading_delete' => array ( Feed::SPOT_TABLE=>array(Feed::MSG_TABLE) ) ); } public function getMainPage($asGlobalVars = array(), $sMainPage = 'index', $asMainPageTags=array()) { return parent::getMainPage( array( 'vars' => array( 'chunk_size' => self::FEED_CHUNK_SIZE, 'default_project_codename' => $this->oProject->getProjectCodeName(), 'projects' => $this->oProject->getProjects() ), 'consts' => array( 'geo_server' => Settings::GEO_SERVER, 'modes' => Project::MODES, 'site_timezone' => Settings::TIMEZONE, 'site_timezone_desc' => self::getTimeZoneDesc(Settings::TIMEZONE) ) ), 'index', array( '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') ) ); } /* Managing projects */ public function setProjectId($iProjectId=0) { $this->oProject->setProjectId($iProjectId); //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()); } } public function getMarkers() { $asMessages = $this->getSpotMessages(); $bSuccess = !empty($asMessages); $sDesc = $bSuccess?'':self::NO_DATA; //Add medias if($bSuccess) { $asMedias = $this->getMedias('taken_on'); //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++; } 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; } } return self::getJsonResult($bSuccess, $sDesc, $asMessages); } private function getSpotMessages() { //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($this->oProject->getActivePeriod()); foreach($asMessages as $iIndex=>&$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'] = 'N°'.($iIndex + 1); $this->addTimeStamp($asMessage, $asMessage['unix_time']); } } usort($asMessages, function($a, $b){return $a['unix_time'] > $b['unix_time'];}); return $asMessages; } /** * Get valid medias based on $sTimeRefField (both are on site time): * - 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 * @return Array Medias info */ private function getMedias($sTimeRefField) { $asMedias = $this->oMedia->getMediasInfo(); $asValidMedias = array(); foreach($asMedias as $iIndex=>$asMedia) { $sTimeRef = $asMedia[$sTimeRefField]; if($sTimeRef >= $this->oProject->getActivePeriod('from') && $sTimeRef <= $this->oProject->getActivePeriod('to')) { $asMedia['taken_on_formatted'] = date(self::FORMAT_TIME, strtotime($asMedia['taken_on'])); $asMedia['displayed_id'] = 'N°'.($iIndex + 1); $this->addTimeStamp($asMedia, strtotime($sTimeRef)); $asValidMedias[] = $asMedia; } } usort($asValidMedias, function($a, $b){return $a['unix_time'] > $b['unix_time'];}); return $asValidMedias; } private function getPosts() { $asInfo = array( 'from' => self::POST_TABLE, 'constraint'=> array(Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId()), 'constOpe' => array(Db::getId(Project::PROJ_TABLE) => "=") ); if($this->oProject->getMode()==Project::MODE_HISTO) { $asInfo['constraint']['site_time'] = $this->oProject->getActivePeriod(); $asInfo['constOpe']['site_time'] = "BETWEEN"; } $asPosts = $this->oDb->selectRows($asInfo); foreach($asPosts as &$asPost) { $iUnixTimeStamp = strtotime($asPost['site_time']); //assumes site timezone (Settings::TIMEZONE) $asPost['formatted_name'] = Toolbox::mb_ucwords($asPost['name']); $this->addTimeStamp($asPost, $iUnixTimeStamp); } usort($asPosts, function($a, $b){return $a['unix_time'] > $b['unix_time'];}); return $asPosts; } private function addTimeStamp(&$asData, $iTime) { $asData['unix_time'] = (int) $iTime; $asData['relative_time'] = Toolbox::getDateTimeDesc($iTime, 'fr'); $asData['formatted_time'] = date(self::FORMAT_TIME, $iTime); } public function getNewsFeed($iChunk=0) { $bHistoMode = ($this->oProject->getMode() == Project::MODE_HISTO); $asFeeds = array(); $asFeedTypes = array( 'message' => array( 'table' => Feed::MSG_TABLE, 'feed' => $this->getSpotMessages(), 'priority' => 0 ), 'media' => array( 'table' => Media::MEDIA_TABLE, 'feed' => $this->getMedias('posted_on'), 'priority' => 1 ), 'post' => array( 'table' => self::POST_TABLE, 'feed' => $this->getPosts(), 'priority' => 2 ) ); foreach($asFeedTypes as $sFeedType=>$asFeedTypeInfo) { foreach($asFeedTypeInfo['feed'] as $asFeed) { $sPriority = $asFeedTypeInfo['priority']; if($bHistoMode) $sPriority = count($asFeedTypes) - 1 - $asFeedTypeInfo['priority']; $iId = ($asFeed['unix_time'] * -1).'.'.$sPriority.$asFeed[Db::getId($asFeedTypeInfo['table'])]; $asFeeds[$iId] = $asFeed; $asFeeds[$iId]['type'] = $sFeedType; } } //Sort by key if($bHistoMode) krsort($asFeeds); else ksort($asFeeds); //Split chunks $asFeeds = array_slice($asFeeds, $iChunk*self::FEED_CHUNK_SIZE, self::FEED_CHUNK_SIZE); return self::getJsonResult(true, '', $asFeeds); } public function syncMedias() { return $this->oMedia->syncFileFolder(); } public function addPost($sName, $sPost) { $asData = array( Db::getId(Project::PROJ_TABLE) => $this->oProject->getProjectId(), '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); return self::getJsonResult(($iPostId > 0), ''); } public function upload() { $this->oClassManagement->incClass('uploader', true); $oUploader = new Uploader($this->oMedia); return $oUploader->sBody; } public function getAdminSettings() { return self::getJsonResult(true, '', array('projects'=>$this->oProject->getProjects())); } public function setAdminSettings($sField, $sValue) { $bSuccess = false; $sDesc = ''; switch($sField) { case 'codename': $bSuccess = $this->oProject->setProjectCodeName($sValue); break; case 'active_from': $bSuccess = $this->oProject->setActivePeriod($sValue.' 00:00:00', 'from'); break; case 'active_to': $bSuccess = $this->oProject->setActivePeriod($sValue.' 23:59:59', 'to'); break; case 'timezone': $bSuccess = $this->oProject->setTimeZone($sValue); break; } if(!$bSuccess) $sDesc = 'Issue committing to DB'; return self::getJsonResult($bSuccess, $sDesc, array('values'=>$this->oProject->getProject())); } 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.'°'.$iMinute.'\''.$fSecond.'"'.$sDirection; } public static function getTimeZoneDesc($sTimeZone) { $sCity = substr(strrchr($sTimeZone, '/'), 1); return 'heure d'.(in_array(strtolower(substr($sCity, 0, 1)), array('a', 'e', 'i', 'o', 'u', 'h'))?'\'':'e ').$sCity; } } ?>