From 61d8fa7baa39341bee1336ff08180a62e9c57497 Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Tue, 15 Nov 2011 15:20:33 +0100 Subject: [PATCH 1/9] CC-3034 Record/Rebroadcast Shows have time problems fixing some UTC to non UTC comparisons, adding offsets properly to create a rebroadcast show's start/end time. --- airtime_mvc/application/models/Show.php | 247 +++++++++++++----------- 1 file changed, 138 insertions(+), 109 deletions(-) diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 1990663df..81f872516 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -119,17 +119,17 @@ class Application_Model_Show { WHERE starts >= '{$day_timestamp}' AND show_id = {$this->_showId}"; $CC_DBC->query($sql); - + // check if we can safely delete the show $showInstancesRow = CcShowInstancesQuery::create() ->filterByDbShowId($this->_showId) ->findOne(); - + if(is_null($showInstancesRow)){ $sql = "DELETE FROM cc_show WHERE id = {$this->_showId}"; $CC_DBC->query($sql); } - + Application_Model_RabbitMq::PushSchedule(); } @@ -137,10 +137,10 @@ class Application_Model_Show { * This function is called when a repeating show is edited and the * days that is repeats on have changed. More specifically, a day * that the show originally repeated on has been "unchecked". - * + * * Removes Show Instances that occur on days of the week specified * by input array. For example, if array contains one value of "0", - * (0 = Sunday, 1=Monday) then all show instances that occur on + * (0 = Sunday, 1=Monday) then all show instances that occur on * Sunday are removed. * * @param array p_uncheckedDays @@ -385,8 +385,8 @@ class Application_Model_Show { /** * Deletes all show instances of current show before a - * certain date. - * + * certain date. + * * This function is used in the case where a repeating show is being * edited and the start date of the first show has been changed more * into the future. In this case, delete any show instances that @@ -454,11 +454,11 @@ class Application_Model_Show { return $startTime; } } - + /** * Get the end date of the current show. * Note that this is not the end date of repeated show - * + * * @return string * The end date in the format YYYY-MM-DD */ @@ -466,12 +466,12 @@ class Application_Model_Show { $startDate = $this->getStartDate(); $startTime = $this->getStartTime(); $duration = $this->getDuration(); - + $startDateTime = new DateTime($startDate.' '.$startTime); $duration = explode(":", $duration); - + $endDate = $startDateTime->add(new DateInterval('PT'.$duration[0].'H'.$duration[1].'M')); - + return $endDate->format('Y-m-d'); } @@ -485,12 +485,12 @@ class Application_Model_Show { $startDate = $this->getStartDate(); $startTime = $this->getStartTime(); $duration = $this->getDuration(); - + $startDateTime = new DateTime($startDate.' '.$startTime); $duration = explode(":", $duration); - + $endDate = $startDateTime->add(new DateInterval('PT'.$duration[0].'H'.$duration[1].'M')); - + return $endDate->format('H:i:s'); } @@ -511,7 +511,7 @@ class Application_Model_Show { * Get the ID's of future instance of the current show. * * @return array - * A simple array containing all ID's of show instance + * A simple array containing all ID's of show instance * scheduled in the future. */ public function getAllFutureInstanceIds(){ @@ -535,11 +535,11 @@ class Application_Model_Show { } /* Called when a show's duration is changed (edited). - * + * * @param array $p_data - * array containing the POST data about the show from the + * array containing the POST data about the show from the * browser. - * + * */ private function updateDurationTime($p_data){ //need to update cc_show_instances, cc_show_days @@ -640,7 +640,7 @@ class Application_Model_Show { public function getInstanceOnDate($p_dateTime){ global $CC_DBC; $timestamp = $p_dateTime->format("Y-m-d H:i:s"); - + $showId = $this->getId(); $sql = "SELECT id FROM cc_show_instances" ." WHERE date(starts) = date(TIMESTAMP '$timestamp') " @@ -836,7 +836,7 @@ class Application_Model_Show { $daysAdd = 6 - $startDow + 1 + $day; else $daysAdd = $day - $startDow; - + $startDateTimeClone->add(new DateInterval("P".$daysAdd."D")); } if (is_null($endDate) || $startDateTimeClone->getTimestamp() <= $endDateTime->getTimestamp()) { @@ -905,12 +905,12 @@ class Application_Model_Show { $showHost->save(); } } - + Application_Model_Show::populateShowUntil($showId); Application_Model_RabbitMq::PushSchedule(); return $showId; } - + /** * Generate repeating show instances for a single show up to the given date. * If no date is given, use the one in the user's preferences, which is stored @@ -934,7 +934,7 @@ class Application_Model_Show { $p_dateTime = $date; } } - + $sql = "SELECT * FROM cc_show_days WHERE show_id = $p_showId"; $res = $CC_DBC->GetAll($sql); @@ -942,7 +942,7 @@ class Application_Model_Show { Application_Model_Show::populateShow($showRow, $p_dateTime); } } - + /** * We are going to use cc_show_days as a template, to generate Show Instances. This function * is basically a dispatcher that looks at the show template, and sends it to the correct function @@ -953,8 +953,8 @@ class Application_Model_Show { * A row from cc_show_days table * @param DateTime $p_dateTime * DateTime object in UTC time. - */ - private static function populateShow($p_showRow, $p_dateTime) { + */ + private static function populateShow($p_showRow, $p_dateTime) { if($p_showRow["repeat_type"] == -1) { Application_Model_Show::populateNonRepeatingShow($p_showRow, $p_dateTime); } @@ -969,7 +969,7 @@ class Application_Model_Show { } Application_Model_RabbitMq::PushSchedule(); } - + /** * Creates a single show instance. If the show is recorded, it may have multiple * rebroadcast dates, and so this function will create those as well. @@ -978,11 +978,11 @@ class Application_Model_Show { * A row from cc_show_days table * @param DateTime $p_dateTime * DateTime object in UTC time. - */ + */ private static function populateNonRepeatingShow($p_showRow, $p_dateTime) { global $CC_DBC; - + $show_id = $p_showRow["show_id"]; $first_show = $p_showRow["first_show"]; //non-UTC $start_time = $p_showRow["start_time"]; //non-UTC @@ -990,7 +990,7 @@ class Application_Model_Show { $day = $p_showRow["day"]; $record = $p_showRow["record"]; $timezone = $p_showRow["timezone"]; - + $start = $first_show." ".$start_time; $utcStartDateTime = Application_Model_DateHelper::ConvertToUtcDateTime($start, $timezone); @@ -1012,7 +1012,7 @@ class Application_Model_Show { $newInstance = true; } - if ($newInstance || $ccShowInstance->getDbStarts() > $currentUtcTimestamp){ + if ($newInstance || $ccShowInstance->getDbStarts() > $currentUtcTimestamp){ $ccShowInstance->setDbShowId($show_id); $ccShowInstance->setDbStarts($utcStartDateTime); $ccShowInstance->setDbEnds($utcEndDateTime); @@ -1029,27 +1029,29 @@ class Application_Model_Show { $sql = "SELECT * FROM cc_show_rebroadcast WHERE show_id={$show_id}"; $rebroadcasts = $CC_DBC->GetAll($sql); - - self::createRebroadcastInstances($rebroadcasts, $currentUtcTimestamp, $show_id, $show_instance_id, $utcStartDateTime, $duration); + + Logging::log('$start time of non repeating record '.$start); + + self::createRebroadcastInstances($rebroadcasts, $currentUtcTimestamp, $show_id, $show_instance_id, $start, $duration, $timezone); } } - + /** - * Creates a 1 or more than 1 show instances (user has stated this show repeats). If the show - * is recorded, it may have multiple rebroadcast dates, and so this function will create + * Creates a 1 or more than 1 show instances (user has stated this show repeats). If the show + * is recorded, it may have multiple rebroadcast dates, and so this function will create * those as well. * * @param array $p_showRow * A row from cc_show_days table * @param DateTime $p_dateTime - * DateTime object in UTC time. + * DateTime object in UTC time. "shows_populated_until" date YY-mm-dd in cc_pref * @param string $p_interval - * Period of time between repeating shows - */ + * Period of time between repeating shows (in php DateInterval notation 'P7D') + */ private static function populateRepeatingShow($p_showRow, $p_dateTime, $p_interval) { global $CC_DBC; - + $show_id = $p_showRow["show_id"]; $next_pop_date = $p_showRow["next_pop_date"]; $first_show = $p_showRow["first_show"]; //non-UTC @@ -1060,26 +1062,27 @@ class Application_Model_Show { $record = $p_showRow["record"]; $timezone = $p_showRow["timezone"]; + $date = new Application_Model_DateHelper(); + $currentUtcTimestamp = $date->getUtcTimestamp(); if(isset($next_pop_date)) { $start = $next_pop_date." ".$start_time; } else { $start = $first_show." ".$start_time; } - + $utcStartDateTime = Application_Model_DateHelper::ConvertToUtcDateTime($start, $timezone); - + //convert $last_show into a UTC DateTime object, or null if there is no last show. + $utcLastShowDateTime = $last_show ? Application_Model_DateHelper::ConvertToUtcDateTime($last_show, $timezone) : null; + $sql = "SELECT * FROM cc_show_rebroadcast WHERE show_id={$show_id}"; $rebroadcasts = $CC_DBC->GetAll($sql); + $show = new Application_Model_Show($show_id); - $date = new Application_Model_DateHelper(); - $currentUtcTimestamp = $date->getUtcTimestamp(); - - while($utcStartDateTime->getTimestamp() - <= $p_dateTime->getTimestamp() && - ($utcStartDateTime->getTimestamp() < strtotime($last_show) || is_null($last_show))) { - + while($utcStartDateTime->getTimestamp() <= $p_dateTime->getTimestamp() + && (is_null($utcLastShowDateTime) || $utcStartDateTime->getTimestamp() < $utcLastShowDateTime->getTimestamp())){ + $utcStart = $utcStartDateTime->format("Y-m-d H:i:s"); $sql = "SELECT timestamp '{$utcStart}' + interval '{$duration}'"; $utcEndDateTime = new DateTime($CC_DBC->GetOne($sql), new DateTimeZone("UTC")); @@ -1113,37 +1116,63 @@ class Application_Model_Show { $showInstance->correctScheduleStartTimes(); } - self::createRebroadcastInstances($rebroadcasts, $currentUtcTimestamp, $show_id, $show_instance_id, $utcStartDateTime, $duration); + self::createRebroadcastInstances($rebroadcasts, $currentUtcTimestamp, $show_id, $show_instance_id, $start, $duration, $timezone); $dt = new DateTime($start, new DateTimeZone($timezone)); $dt->add(new DateInterval($p_interval)); $start = $dt->format("Y-m-d H:i:s"); - + $dt->setTimezone(new DateTimeZone('UTC')); $utcStartDateTime = $dt; - + } - + Application_Model_Show::setNextPop($start, $show_id, $day); } - - private static function createRebroadcastInstances($p_rebroadcasts, $p_currentUtcTimestamp, $p_showId, $p_showInstanceId, $p_utcStartDateTime, $p_duration){ - global $CC_DBC; - - foreach($p_rebroadcasts as $rebroadcast) { - $timeinfo = $p_utcStartDateTime->format("Y-m-d H:i:s"); - $sql = "SELECT timestamp '{$timeinfo}' + interval '{$rebroadcast["day_offset"]}' + interval '{$rebroadcast["start_time"]}'"; + /* Create rebroadcast instances for a created show marked for recording + * + * @param $p_rebroadcasts rows gotten from the db table cc_show_rebroadcasts, tells airtime when to schedule the rebroadcasts. + * @param $p_currentUtcTimestamp a timestring in format "Y-m-d H:i:s", current UTC time. + * @param $p_showId int of the show it belongs to (from cc_show) + * @param $p_showInstanceId the instance id of the created recorded show instance + * (from cc_show_instances), used to associate rebroadcasts to this show. + * @param $p_startTime a timestring in format "Y-m-d H:i:s" in the timezone, not UTC of the rebroadcasts' parent recorded show. + * @param $p_duration duration of the show in format 1:0 + * @param $p_timezone string of user's timezone "Europe/Prague" + * + */ + private static function createRebroadcastInstances($p_rebroadcasts, $p_currentUtcTimestamp, $p_showId, $p_showInstanceId, $p_startTime, $p_duration, $p_timezone=null){ + global $CC_DBC; + + Logging::log('Count of rebroadcasts '. count($p_rebroadcasts)); + + foreach($p_rebroadcasts as $rebroadcast) { + + //use only the date part of the show start time stamp for the offsets to work properly. + $sql = "SELECT date '{$p_startTime}' + interval '{$rebroadcast["day_offset"]}' + interval '{$rebroadcast["start_time"]}'"; $rebroadcast_start_time = $CC_DBC->GetOne($sql); + Logging::log('rebroadcast start '.$rebroadcast_start_time); $sql = "SELECT timestamp '{$rebroadcast_start_time}' + interval '{$p_duration}'"; $rebroadcast_end_time = $CC_DBC->GetOne($sql); - - if ($rebroadcast_start_time > $p_currentUtcTimestamp){ + Logging::log('rebroadcast end '.$rebroadcast_end_time); + + //convert to UTC, after we have used the defined offsets to calculate rebroadcasts. + $utc_rebroadcast_start_time = Application_Model_DateHelper::ConvertToUtcDateTime($rebroadcast_start_time, $p_timezone); + $utc_rebroadcast_end_time = Application_Model_DateHelper::ConvertToUtcDateTime($rebroadcast_end_time, $p_timezone); + + Logging::log('UTC rebroadcast start '.$utc_rebroadcast_start_time->format("Y-m-d H:i:s")); + Logging::log('UTC rebroadcast end '.$utc_rebroadcast_end_time->format("Y-m-d H:i:s")); + Logging::log('Current UTC timestamp '.$p_currentUtcTimestamp); + + if ($utc_rebroadcast_start_time->format("Y-m-d H:i:s") > $p_currentUtcTimestamp){ + Logging::log('Creating rebroadcast show starting at UTC '.$utc_rebroadcast_start_time->format("Y-m-d H:i:s")); + $newRebroadcastInstance = new CcShowInstances(); $newRebroadcastInstance->setDbShowId($p_showId); - $newRebroadcastInstance->setDbStarts($rebroadcast_start_time); - $newRebroadcastInstance->setDbEnds($rebroadcast_end_time); + $newRebroadcastInstance->setDbStarts($utc_rebroadcast_start_time->format("Y-m-d H:i:s")); + $newRebroadcastInstance->setDbEnds($utc_rebroadcast_end_time->format("Y-m-d H:i:s")); $newRebroadcastInstance->setDbRecord(0); $newRebroadcastInstance->setDbRebroadcast(1); $newRebroadcastInstance->setDbOriginalShow($p_showInstanceId); @@ -1233,7 +1262,7 @@ class Application_Model_Show { public static function populateAllShowsInRange($p_startTimestamp, $p_endTimestamp) { global $CC_DBC; - + $endTimeString = $p_endTimestamp->format("Y-m-d H:i:s"); if (!is_null($p_startTimestamp)) { $startTimeString = $p_startTimestamp->format("Y-m-d H:i:s"); @@ -1272,7 +1301,7 @@ class Application_Model_Show { $days = $interval->format('%a'); $shows = Application_Model_Show::getShows($start, $end); - + $today_timestamp = date("Y-m-d H:i:s"); foreach ($shows as $show) { @@ -1284,7 +1313,7 @@ class Application_Model_Show { $show_instance = new Application_Model_ShowInstance($show["instance_id"]); $options["percent"] = $show_instance->getPercentScheduled(); } - + if ($editable && (strtotime($today_timestamp) < strtotime($show["starts"]))) { $options["editable"] = true; $events[] = Application_Model_Show::makeFullCalendarEvent($show, $options); @@ -1304,10 +1333,10 @@ class Application_Model_Show { if($show["rebroadcast"]) { $event["disableResizing"] = true; } - + $startDateTime = new DateTime($show["starts"], new DateTimeZone("UTC")); $startDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); - + $endDateTime = new DateTime($show["ends"], new DateTimeZone("UTC")); $endDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); @@ -1321,7 +1350,7 @@ class Application_Model_Show { $event["record"] = intval($show["record"]); $event["deleted_instance"] = $show["deleted_instance"]; $event["rebroadcast"] = intval($show["rebroadcast"]); - + // get soundcloud_id if(!is_null($show["file_id"])){ $file = Application_Model_StoredFile::Recall($show["file_id"]); @@ -1345,28 +1374,28 @@ class Application_Model_Show { return $event; } - + public function setShowFirstShow($s_date){ $showDay = CcShowDaysQuery::create() ->filterByDbShowId($this->_showId) ->findOne(); - + $showDay->setDbFirstShow($s_date) ->save(); } - + public function setShowLastShow($e_date){ $showDay = CcShowDaysQuery::create() ->filterByDbShowId($this->_showId) ->findOne(); - + $showDay->setDbLastShow($e_date) ->save(); } /** * Given local current time $timeNow, returns the show being played right now. - * + * * @param type $timeNow local current time * @return type show being played right now */ @@ -1374,10 +1403,10 @@ class Application_Model_Show { { global $CC_CONFIG, $CC_DBC; - // Need this in the query below, so that we are NOT comparing UTC + // Need this in the query below, so that we are NOT comparing UTC // timestamps si.starts/si.ends with local timestamps $timeNow $timezoneInterval = Application_Model_Show::GetTimezoneIntervalString(true); - + $sql = "SELECT si.starts as start_timestamp, si.ends as end_timestamp, s.name, s.id, si.id as instance_id, si.record, s.url" ." FROM $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s" ." WHERE si.show_id = s.id" @@ -1387,15 +1416,15 @@ class Application_Model_Show { // Convert back to local timezone $rows = $CC_DBC->GetAll($sql); Application_Model_Show::ConvertToLocalTimeZone($rows, array("starts", "ends", "start_timestamp", "end_timestamp")); - + return $rows; } /** - * Given local current time $timeNow, returns the next $limit number of - * shows within 2 days if $timeEnd is not given; Otherwise, returns the + * Given local current time $timeNow, returns the next $limit number of + * shows within 2 days if $timeEnd is not given; Otherwise, returns the * next $limit number of shows from $timeNow to $timeEnd, both in local time. - * + * * @param type $timeNow local current time * @param type $limit number of shows to return * @param type $timeEnd optional: interval end time @@ -1404,11 +1433,11 @@ class Application_Model_Show { public static function GetNextShows($timeNow, $limit, $timeEnd = "") { global $CC_CONFIG, $CC_DBC; - - // Need this in the query below, so that we are NOT comparing UTC + + // Need this in the query below, so that we are NOT comparing UTC // timestamps si.starts with local timestamps $timeNow $timezoneInterval = Application_Model_Show::GetTimezoneIntervalString(true); - + // defaults to retrieving shows from next 2 days if no end time has // been specified if($timeEnd == "") { @@ -1416,7 +1445,7 @@ class Application_Model_Show { } else { $timeEnd = "'$timeEnd' + $timezoneInterval"; } - + $sql = "SELECT *, si.starts as start_timestamp, si.ends as end_timestamp FROM " ." $CC_CONFIG[showInstances] si, $CC_CONFIG[showTable] s" ." WHERE si.show_id = s.id" @@ -1428,14 +1457,14 @@ class Application_Model_Show { // Convert timestamps to local timezone $rows = $CC_DBC->GetAll($sql); Application_Model_Show::ConvertToLocalTimeZone($rows, array("starts", "ends", "start_timestamp", "end_timestamp")); - + return $rows; } - + /** - * Given a day of the week variable $day, based in local time, returns the + * Given a day of the week variable $day, based in local time, returns the * shows being played on this day of the week we're in right now. - * + * * @param type $day day of the week * @return type shows being played on this day */ @@ -1445,14 +1474,14 @@ class Application_Model_Show { //SELECT EXTRACT(DOW FROM TIMESTAMP '2001-02-16 20:38:40'); //Result: 5 - + global $CC_CONFIG, $CC_DBC; - + // Need this in the query below, so that we are NOT extracting DOW and WEEK - // information from UTC timestamps si.starts, and comparing with a local + // information from UTC timestamps si.starts, and comparing with a local // timezone based variable $day and localtimestamp $timezoneInterval = Application_Model_Show::GetTimezoneIntervalString(); - + $sql = "SELECT" ." si.starts as show_starts," ." si.ends as show_ends," @@ -1464,69 +1493,69 @@ class Application_Model_Show { ." WHERE EXTRACT(DOW FROM si.starts + $timezoneInterval) = $day" ." AND EXTRACT(WEEK FROM si.starts + $timezoneInterval) = EXTRACT(WEEK FROM localtimestamp)" ." ORDER BY si.starts"; - + // Convert result timestamps to local timezone $rows = $CC_DBC->GetAll($sql); Application_Model_Show::ConvertToLocalTimeZone($rows, array("show_starts", "show_ends")); return $rows; } - + /** - * Convert the columns given in the array $columnsToConvert in the + * Convert the columns given in the array $columnsToConvert in the * database result $rows to local timezone. - * + * * @param type $rows arrays of arrays containing database query result * @param type $columnsToConvert array of column names to convert */ public static function ConvertToLocalTimeZone(&$rows, $columnsToConvert) { $timezone = date_default_timezone_get(); - + foreach($rows as &$row) { foreach($columnsToConvert as $column) { $row[$column] = Application_Model_DateHelper::ConvertToLocalDateTimeString($row[$column]); } } } - + /** * Returns the timezone difference as an INTERVAL string that can be used * by SQL queries. - * + * * E.g., if local timezone is -4:30, this function returns: * INTERVAL '-4 hours -30 minutes' - * + * * Note that if $fromLocalToUtc is true, then it returns: * INTERVAL '4 hours 30 minutes' - * - * @param type $fromLocalToUtc true if we're converting from local to UTC + * + * @param type $fromLocalToUtc true if we're converting from local to UTC */ public static function GetTimeZoneIntervalString($fromLocalToUtc = false) { $date = new Application_Model_DateHelper; $timezoneHour = $date->getLocalOffsetHour(); $timezoneMin = $date->getLocalOffsetMinute(); - + // negate the hour and min if converting from local to UTC if($fromLocalToUtc) { $timezoneHour = -$timezoneHour; $timezoneMin = -$timezoneMin; } - + return "INTERVAL '$timezoneHour hours $timezoneMin minutes'"; } - + public static function GetMaxLengths() { global $CC_CONFIG, $CC_DBC; $sql = "SELECT column_name, character_maximum_length FROM information_schema.columns" ." WHERE table_name = 'cc_show' AND character_maximum_length > 0"; $result = $CC_DBC->GetAll($sql); - + // store result into assoc array $assocArray = array(); foreach($result as $row) { $assocArray[$row['column_name']] = $row['character_maximum_length']; } - + return $assocArray; } } From 6f91a9b1070e1ee532a4f52e38f6edfb1ca6dd5b Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Tue, 15 Nov 2011 15:56:52 +0100 Subject: [PATCH 2/9] CC-3046 : Show contents for Rebroadcast in wrong timezone --- .../controllers/ScheduleController.php | 102 +++++++++--------- 1 file changed, 52 insertions(+), 50 deletions(-) diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index d244097ca..59077cc42 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -56,7 +56,7 @@ class ScheduleController extends Zend_Controller_Action $this->view->headLink()->appendStylesheet($baseUrl.'/css/colorpicker/css/colorpicker.css'); $this->view->headLink()->appendStylesheet($baseUrl.'/css/add-show.css'); $this->view->headLink()->appendStylesheet($baseUrl.'/css/contextmenu.css'); - + Application_Model_Schedule::createNewFormSections($this->view); $userInfo = Zend_Auth::getInstance()->getStorage()->read(); @@ -141,7 +141,7 @@ class ScheduleController extends Zend_Controller_Action $this->view->show_error = true; return false; } - + $show->deleteShow(); } } @@ -177,15 +177,15 @@ class ScheduleController extends Zend_Controller_Action $this->view->show_error = true; return false; } - + $params = '/format/json/id/#id#'; - + $showStartDateHelper = Application_Model_DateHelper::ConvertToLocalDateTime($show->getShowInstanceStart()); $showEndDateHelper = Application_Model_DateHelper::ConvertToLocalDateTime($show->getShowInstanceEnd()); - + $menu = array(); - + if ($epochNow < $showStartDateHelper->getTimestamp()) { if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER, UTYPE_HOST),$show->getShowId()) && !$show->isRecorded() && !$show->isRebroadcast()) { @@ -239,7 +239,7 @@ class ScheduleController extends Zend_Controller_Action 'callback' => 'window["scheduleRefetchEvents"]'), 'title' => 'Delete This Instance and All Following'); } } - + //returns format jjmenu is looking for. die(json_encode($menu)); } @@ -305,12 +305,12 @@ class ScheduleController extends Zend_Controller_Action $this->view->show_error = true; return false; } - + $playlists = $show->searchPlaylistsForShow($post); foreach( $playlists['aaData'] as &$data){ // calling two functions to format time to 1 decimal place $sec = Application_Model_Playlist::playlistTimeToSeconds($data[4]); - $data[4] = Application_Model_Playlist::secondsToPlaylistTime($sec); + $data[4] = Application_Model_Playlist::secondsToPlaylistTime($sec); } //for datatables @@ -354,13 +354,13 @@ class ScheduleController extends Zend_Controller_Action $this->view->show_error = true; return false; } - + $start_timestamp = $show->getShowInstanceStart(); $end_timestamp = $show->getShowInstanceEnd(); //check to make sure show doesn't overlap. - if(Application_Model_Show::getShows(new DateTime($start_timestamp, new DateTimeZone("UTC")), - new DateTime($end_timestamp, new DateTimeZone("UTC")), + if(Application_Model_Show::getShows(new DateTime($start_timestamp, new DateTimeZone("UTC")), + new DateTime($end_timestamp, new DateTimeZone("UTC")), array($showInstanceId))) { $this->view->error = "cannot schedule an overlapping show."; return; @@ -368,7 +368,7 @@ class ScheduleController extends Zend_Controller_Action $dateInfo_s = getDate(strtotime(Application_Model_DateHelper::ConvertToLocalDateTimeString($start_timestamp))); $dateInfo_e = getDate(strtotime(Application_Model_DateHelper::ConvertToLocalDateTimeString($end_timestamp))); - + $this->view->showContent = $show->getShowContent(); $this->view->timeFilled = $show->getTimeScheduled(); $this->view->showName = $show->getName(); @@ -410,7 +410,9 @@ class ScheduleController extends Zend_Controller_Action $originalShowName = $originalShow->getName(); $originalShowStart = $originalShow->getShowInstanceStart(); - $timestamp = strtotime($originalShowStart); + //convert from UTC to user's timezone for display. + $originalDateTime = new DateTime($originalShowStart, new DateTimeZone("UTC")); + $timestamp = strtotime(Application_Model_DateHelper::ConvertToLocalDateTimeString($originalDateTime->format("Y-m-d H:i:s"))); $this->view->additionalShowInfo = "Rebroadcast of show \"$originalShowName\" from " .date("l, F jS", $timestamp)." at ".date("G:i", $timestamp); @@ -427,7 +429,7 @@ class ScheduleController extends Zend_Controller_Action if(!$user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { return; } - + $isSaas = Application_Model_Preference::GetPlanLevel() == 'disabled'?false:true; $showInstanceId = $this->_getParam('id'); @@ -464,10 +466,10 @@ class ScheduleController extends Zend_Controller_Action 'add_show_url' => $show->getUrl(), 'add_show_genre' => $show->getGenre(), 'add_show_description' => $show->getDescription())); - + $startsDateTime = new DateTime($show->getStartDate()." ".$show->getStartTime(), new DateTimeZone(date_default_timezone_get())); $endsDateTime = new DateTime($show->getEndDate()." ".$show->getEndTime(), new DateTimeZone(date_default_timezone_get())); - + //$startsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); //$endsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); @@ -505,27 +507,27 @@ class ScheduleController extends Zend_Controller_Action $formWho->populate(array('add_show_hosts' => $hosts)); $formStyle->populate(array('add_show_background_color' => $show->getBackgroundColor(), 'add_show_color' => $show->getColor())); - + if(!$isSaas){ $formRecord = new Application_Form_AddShowRR(); $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); - + $formRecord->removeDecorator('DtDdWrapper'); $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); $formRebroadcast->removeDecorator('DtDdWrapper'); - + $this->view->rr = $formRecord; $this->view->absoluteRebroadcast = $formAbsoluteRebroadcast; $this->view->rebroadcast = $formRebroadcast; - + $formRecord->populate(array('add_show_record' => $show->isRecorded(), 'add_show_rebroadcast' => $show->isRebroadcast())); - + $formRecord->getElement('add_show_record')->setOptions(array('disabled' => true)); - - - + + + $rebroadcastsRelative = $show->getRebroadcastsRelative(); $rebroadcastFormValues = array(); $i = 1; @@ -535,7 +537,7 @@ class ScheduleController extends Zend_Controller_Action $i++; } $formRebroadcast->populate($rebroadcastFormValues); - + $rebroadcastsAbsolute = $show->getRebroadcastsAbsolute(); $rebroadcastAbsoluteFormValues = array(); $i = 1; @@ -551,7 +553,7 @@ class ScheduleController extends Zend_Controller_Action $this->view->entries = 5; } - public function getFormAction(){ + public function getFormAction(){ Application_Model_Schedule::createNewFormSections($this->view); $this->view->form = $this->view->render('schedule/add-show-form.phtml'); } @@ -565,7 +567,7 @@ class ScheduleController extends Zend_Controller_Action foreach($js as $j){ $data[$j["name"]] = $j["value"]; } - + $show = new Application_Model_Show($data['add_show_id']); $startDateModified = true; @@ -582,10 +584,10 @@ class ScheduleController extends Zend_Controller_Action if($data['add_show_day_check'] == "") { $data['add_show_day_check'] = null; } - + $isSaas = Application_Model_Preference::GetPlanLevel() == 'disabled'?false:true; $record = false; - + $formWhat = new Application_Form_AddShowWhat(); $formWho = new Application_Form_AddShowWho(); $formWhen = new Application_Form_AddShowWhen(); @@ -604,8 +606,8 @@ class ScheduleController extends Zend_Controller_Action $when = $formWhen->checkReliantFields($data, $startDateModified); } - - //The way the following code works is that is parses the hour and + + //The way the following code works is that is parses the hour and //minute from a string with the format "1h 20m" or "2h" or "36m". //So we are detecting whether an hour or minute value exists via strpos //and then parse appropriately. A better way to do this in the future is @@ -613,10 +615,10 @@ class ScheduleController extends Zend_Controller_Action //have to do this extra String parsing. $hPos = strpos($data["add_show_duration"], 'h'); $mPos = strpos($data["add_show_duration"], 'm'); - + $hValue = 0; $mValue = 0; - + if($hPos !== false){ $hValue = trim(substr($data["add_show_duration"], 0, $hPos)); } @@ -624,18 +626,18 @@ class ScheduleController extends Zend_Controller_Action $hPos = $hPos === FALSE ? 0 : $hPos+1; $mValue = trim(substr($data["add_show_duration"], $hPos, -1 )); } - + $data["add_show_duration"] = $hValue.":".$mValue; - + if(!$isSaas){ $formRecord = new Application_Form_AddShowRR(); $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); - + $formRecord->removeDecorator('DtDdWrapper'); $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); $formRebroadcast->removeDecorator('DtDdWrapper'); - + //If show is a new show (not updated), then get //isRecorded from POST data. Otherwise get it from //the database since the user is not allowed to @@ -648,7 +650,7 @@ class ScheduleController extends Zend_Controller_Action $record = $formRecord->isValid($data); } } - + if($data["add_show_repeats"]) { $repeats = $formRepeats->isValid($data); if($repeats) { @@ -658,7 +660,7 @@ class ScheduleController extends Zend_Controller_Action $formAbsoluteRebroadcast->reset(); //make it valid, results don't matter anyways. $rebroadAb = 1; - + if ($data["add_show_rebroadcast"]) { $rebroad = $formRebroadcast->isValid($data); if($rebroad) { @@ -676,7 +678,7 @@ class ScheduleController extends Zend_Controller_Action $formRebroadcast->reset(); //make it valid, results don't matter anyways. $rebroad = 1; - + if ($data["add_show_rebroadcast"]) { $rebroadAb = $formAbsoluteRebroadcast->isValid($data); if($rebroadAb) { @@ -699,10 +701,10 @@ class ScheduleController extends Zend_Controller_Action if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { Application_Model_Show::create($data); } - + //send back a new form for the user. Application_Model_Schedule::createNewFormSections($this->view); - + $this->view->newForm = $this->view->render('schedule/add-show-form.phtml'); } }else{ @@ -711,14 +713,14 @@ class ScheduleController extends Zend_Controller_Action if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { Application_Model_Show::create($data); } - + //send back a new form for the user. Application_Model_Schedule::createNewFormSections($this->view); - + $this->view->newForm = $this->view->render('schedule/add-show-form.phtml'); } } - else { + else { $this->view->what = $formWhat; $this->view->when = $formWhen; $this->view->repeats = $formRepeats; @@ -730,7 +732,7 @@ class ScheduleController extends Zend_Controller_Action $this->view->rebroadcast = $formRebroadcast; } $this->view->addNewShow = true; - + //the form still needs to be "update" since //the validity test failed. if ($data['add_show_id'] != -1){ @@ -798,7 +800,7 @@ class ScheduleController extends Zend_Controller_Action $file_id = $this->_getParam('id', null); $file = Application_Model_StoredFile::Recall($file_id); - + $baseUrl = $this->getRequest()->getBaseUrl(); $url = $file->getRelativeFileUrl($baseUrl).'/download/true'; $menu[] = array('action' => array('type' => 'gourl', 'url' => $url), @@ -807,7 +809,7 @@ class ScheduleController extends Zend_Controller_Action //returns format jjmenu is looking for. die(json_encode($menu)); } - + /** * Sets the user specific preference for which time scale to use in Calendar. * This is only being used by schedule.js at the moment. @@ -815,7 +817,7 @@ class ScheduleController extends Zend_Controller_Action public function setTimeScaleAction() { Application_Model_Preference::SetCalendarTimeScale($this->_getParam('timeScale')); } - + /** * Sets the user specific preference for which time interval to use in Calendar. * This is only being used by schedule.js at the moment. From 63d0163f15eaa5edaebf357e00752e240700636d Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Tue, 15 Nov 2011 16:32:07 +0100 Subject: [PATCH 3/9] CC-3047 : getting full calendar events setting editable flag incorrectly --- airtime_mvc/application/models/DateHelper.php | 59 ++++++++++--------- airtime_mvc/application/models/Show.php | 3 +- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/airtime_mvc/application/models/DateHelper.php b/airtime_mvc/application/models/DateHelper.php index 1ab295d7b..2ca559d39 100644 --- a/airtime_mvc/application/models/DateHelper.php +++ b/airtime_mvc/application/models/DateHelper.php @@ -17,7 +17,7 @@ class Application_Model_DateHelper { return date("Y-m-d H:i:s", $this->_dateTime); } - + /** * Get time of object construction in the format * YYYY-MM-DD HH:mm:ss @@ -59,10 +59,10 @@ class Application_Model_DateHelper /** * Calculate and return the timestamp for end of day today * in local time. - * + * * For example, if local time is 2PM on 2011-11-01, * then the function would return 2011-11-02 00:00:00 - * + * * @return End of day timestamp in local timezone */ function getDayEndTimestamp() { @@ -70,7 +70,7 @@ class Application_Model_DateHelper $dateTime->add(new DateInterval('P1D')); return $dateTime->format('Y-m-d H:i:s'); } - + /** * Find the epoch timestamp difference from "now" to the beginning of today. */ @@ -98,7 +98,7 @@ class Application_Model_DateHelper * Returns the offset in seconds, between local and UTC timezones. * E.g., if local timezone is -4, this function * returns -14400. - * + * * @return type offset in int, between local and UTC timezones */ function getLocalTimeZoneOffset() { @@ -106,31 +106,31 @@ class Application_Model_DateHelper $timezone = new DateTimeZone(date_default_timezone_get()); return $timezone->getOffset($dateTime); } - + /** * Returns the offset hour in int, between local and UTC timezones. * E.g., if local timezone is -4:30, this function * returns -4. - * + * * @return type offset hour in int, between local and UTC timezones */ function getLocalOffsetHour() { $offset = $this->getLocalTimeZoneOffset(); return (int)($offset / 3600); } - + /** * Returns the offset minute in int, between local and UTC timezones. * E.g., if local timezone is -4:30, this function * returns -30. - * + * * @return type offset minute in int, between local and UTC timezones */ function getLocalOffsetMinute() { $offset = $this->getLocalTimeZoneOffset(); return (int)(($offset % 3600) / 60); } - + public static function TimeDiff($time1, $time2) { return strtotime($time2) - strtotime($time1); @@ -193,11 +193,11 @@ class Application_Model_DateHelper $explode = explode(" ", $p_dateTime); return $explode[1]; } - - /* Given a track length in the format HH:MM:SS.mm, we want to + + /* Given a track length in the format HH:MM:SS.mm, we want to * convert this to seconds. This is useful for Liquidsoap which - * likes input parameters give in seconds. - * For example, 00:06:31.444, should be converted to 391.444 seconds + * likes input parameters give in seconds. + * For example, 00:06:31.444, should be converted to 391.444 seconds * @param int $p_time * The time interval in format HH:MM:SS.mm we wish to * convert to seconds. @@ -205,46 +205,51 @@ class Application_Model_DateHelper * The input parameter converted to seconds. */ public static function calculateLengthInSeconds($p_time){ - + if (2 !== substr_count($p_time, ":")){ return FALSE; } - + if (1 === substr_count($p_time, ".")){ list($hhmmss, $ms) = explode(".", $p_time); } else { $hhmmss = $p_time; $ms = 0; } - + list($hours, $minutes, $seconds) = explode(":", $hhmmss); - + $totalSeconds = $hours*3600 + $minutes*60 + $seconds + $ms/1000; - + return $totalSeconds; } - - public static function ConvertToUtcDateTime($p_dateString, $timezone){ - $dateTime = new DateTime($p_dateString, new DateTimeZone($timezone)); + + public static function ConvertToUtcDateTime($p_dateString, $timezone=null){ + if (isset($timezone)) { + $dateTime = new DateTime($p_dateString, new DateTimeZone($timezone)); + } + else { + $dateTime = new DateTime($p_dateString, new DateTimeZone(date_default_timezone_get())); + } $dateTime->setTimezone(new DateTimeZone("UTC")); - - return $dateTime; + + return $dateTime; } - + public static function ConvertToSpecificTimezoneDateTime($p_dateString, $timezone){ $dateTime = new DateTime($p_dateString, new DateTimeZone("UTC")); $dateTime->setTimezone(new DateTimeZone($timezone)); return $dateTime; } - + public static function ConvertToLocalDateTime($p_dateString){ $dateTime = new DateTime($p_dateString, new DateTimeZone("UTC")); $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); return $dateTime; } - + public static function ConvertToLocalDateTimeString($p_dateString, $format="Y-m-d H:i:s"){ $dateTime = new DateTime($p_dateString, new DateTimeZone("UTC")); $dateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index 81f872516..e0b5175db 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -1302,7 +1302,8 @@ class Application_Model_Show { $shows = Application_Model_Show::getShows($start, $end); - $today_timestamp = date("Y-m-d H:i:s"); + $today_timestamp = Application_Model_DateHelper::ConvertToUtcDateTime(date("Y-m-d H:i:s"))->format("Y-m-d H:i:s"); + foreach ($shows as $show) { if ($show["deleted_instance"] != "t"){ From 4bdf866acaa40aa461bf987a973c5614c4cd8eab Mon Sep 17 00:00:00 2001 From: Naomi Aro Date: Tue, 15 Nov 2011 18:22:21 +0100 Subject: [PATCH 4/9] CC-3035 : Should be able to resize a show, have it affect all future instances of the show resizing is only working for single instance currently like the past. --- .../controllers/ScheduleController.php | 7 +++- airtime_mvc/application/models/Show.php | 1 + .../application/models/ShowInstance.php | 37 ++++++++++--------- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index 59077cc42..10f5c860a 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -68,7 +68,9 @@ class ScheduleController extends Zend_Controller_Action public function eventFeedAction() { $start = new DateTime($this->_getParam('start', null)); + $start->setTimezone(new DateTimeZone("UTC")); $end = new DateTime($this->_getParam('end', null)); + $end->setTimezone(new DateTimeZone("UTC")); $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new Application_Model_User($userInfo->id); @@ -113,7 +115,7 @@ class ScheduleController extends Zend_Controller_Action $userInfo = Zend_Auth::getInstance()->getStorage()->read(); $user = new Application_Model_User($userInfo->id); - if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { try{ $show = new Application_Model_ShowInstance($showInstanceId); }catch(Exception $e){ @@ -123,8 +125,9 @@ class ScheduleController extends Zend_Controller_Action $error = $show->resizeShow($deltaDay, $deltaMin); } - if(isset($error)) + if (isset($error)) { $this->view->error = $error; + } } public function deleteShowAction() diff --git a/airtime_mvc/application/models/Show.php b/airtime_mvc/application/models/Show.php index e0b5175db..09c6b80b6 100644 --- a/airtime_mvc/application/models/Show.php +++ b/airtime_mvc/application/models/Show.php @@ -1196,6 +1196,7 @@ class Application_Model_Show { { global $CC_DBC; + //UTC DateTime object $showsPopUntil = Application_Model_Preference::GetShowsPopulatedUntil(); //if application is requesting shows past our previous populated until date, generate shows up until this point. diff --git a/airtime_mvc/application/models/ShowInstance.php b/airtime_mvc/application/models/ShowInstance.php index 937db958f..865b5b71b 100644 --- a/airtime_mvc/application/models/ShowInstance.php +++ b/airtime_mvc/application/models/ShowInstance.php @@ -24,7 +24,7 @@ class Application_Model_ShowInstance { { return $this->_instanceId; } - + public function getShow(){ return new Application_Model_Show($this->getShowId()); } @@ -136,7 +136,7 @@ class Application_Model_ShowInstance { $con = Propel::getConnection(CcShowInstancesPeer::DATABASE_NAME); $this->_showInstance->updateDbTimeFilled($con); } - + public function isDeleted() { $this->_showInstance->getDbDeletedInstance(); @@ -174,7 +174,7 @@ class Application_Model_ShowInstance { public function moveShow($deltaDay, $deltaMin) { global $CC_DBC; - + if ($this->getShow()->isRepeating()){ return "Can't drag and drop repeating shows"; } @@ -190,7 +190,7 @@ class Application_Model_ShowInstance { $today_timestamp = time(); $starts = $this->getShowInstanceStart(); $ends = $this->getShowInstanceEnd(); - + $startsDateTime = new DateTime($starts, new DateTimeZone("UTC")); if($today_timestamp > $startsDateTime->getTimestamp()) { @@ -205,13 +205,13 @@ class Application_Model_ShowInstance { $new_ends = $CC_DBC->GetOne($sql); $newEndsDateTime = new DateTime($new_ends, new DateTimeZone("UTC")); - + if($today_timestamp > $newStartsDateTime->getTimestamp()) { return "Can't move show into past"; } $overlap = Application_Model_Show::getShows($newStartsDateTime, $newEndsDateTime, array($this->_instanceId)); - + if(count($overlap) > 0) { return "Should not overlap shows"; } @@ -229,13 +229,13 @@ class Application_Model_ShowInstance { $this->setShowStart($new_starts); $this->setShowEnd($new_ends); $this->correctScheduleStartTimes(); - + $show = new Application_Model_Show($this->getShowId()); if(!$show->isRepeating()){ $show->setShowFirstShow($new_starts); $show->setShowLastShow($new_ends); } - + Application_Model_RabbitMq::PushSchedule(); } @@ -251,7 +251,7 @@ class Application_Model_ShowInstance { $mins = abs($deltaMin%60); - $today_timestamp = date("Y-m-d H:i:s"); + $today_timestamp = Application_Model_DateHelper::ConvertToUtcDateTime(date("Y-m-d H:i:s"))->format("Y-m-d H:i:s"); $starts = $this->getShowInstanceStart(); $ends = $this->getShowInstanceEnd(); @@ -264,8 +264,11 @@ class Application_Model_ShowInstance { //only need to check overlap if show increased in size. if(strtotime($new_ends) > strtotime($ends)) { - //TODO --martin - $overlap = Application_Model_Show::getShows($ends, $new_ends); + + $utcStartDateTime = new DateTime($ends, new DateTimeZone("UTC")); + $utcEndDateTime = new DateTime($new_ends, new DateTimeZone("UTC")); + + $overlap = Application_Model_Show::getShows($utcStartDateTime, $utcEndDateTime); if(count($overlap) > 0) { return "Should not overlap shows"; @@ -385,7 +388,7 @@ class Application_Model_ShowInstance { public function deleteShow() { global $CC_DBC; - + // see if it was recording show $recording = CcShowInstancesQuery::create() ->findPK($this->_instanceId) @@ -394,18 +397,18 @@ class Application_Model_ShowInstance { $showId = CcShowInstancesQuery::create() ->findPK($this->_instanceId) ->getDbShowId(); - + CcShowInstancesQuery::create() ->findPK($this->_instanceId) ->setDbDeletedInstance(true) ->save(); - + // check if we can safely delete the show $showInstancesRow = CcShowInstancesQuery::create() ->filterByDbShowId($showId) ->filterByDbDeletedInstance(false) ->findOne(); - + /* If we didn't find any instances of the show that haven't * been deleted, then just erase everything related to that show. * We can just delete, the show and the foreign key-constraint should @@ -415,7 +418,7 @@ class Application_Model_ShowInstance { ->filterByDbId($showId) ->delete(); } - + Application_Model_RabbitMq::PushSchedule(); if($recording){ Application_Model_RabbitMq::SendMessageToShowRecorder("cancel_recording"); @@ -671,7 +674,7 @@ class Application_Model_ShowInstance { return new Application_Model_ShowInstance($id); } } - + // returns number of show instances that ends later than $day public static function GetShowInstanceCount($day){ global $CC_CONFIG, $CC_DBC; From f6f58c93992561e9c807c72845fb8a1e60aed03b Mon Sep 17 00:00:00 2001 From: Yuchen Wang Date: Tue, 15 Nov 2011 12:37:54 -0500 Subject: [PATCH 5/9] CC-3044: Error in system status seen in apache log - Added check for length > 0 before trying to get property - Got rid of repeating code --- .../application/models/Systemstatus.php | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/airtime_mvc/application/models/Systemstatus.php b/airtime_mvc/application/models/Systemstatus.php index ca522c991..bf8c7264d 100644 --- a/airtime_mvc/application/models/Systemstatus.php +++ b/airtime_mvc/application/models/Systemstatus.php @@ -96,24 +96,25 @@ class Application_Model_Systemstatus } public static function GetPlatformInfo(){ - $data = array("release"=>"UNKNOWN", - "machine"=>"UNKNOWN", - "memory"=>"UNKNOWN", - "swap"=>"UNKNOWN"); - + $keys = array("release", "machine", "memory", "swap"); + foreach($keys as $key) { + $data[$key] = "UNKNOWN"; + } + $docRoot = self::GetMonitStatus("localhost"); if (!is_null($docRoot)){ foreach ($docRoot->getElementsByTagName("platform") AS $item) { - $data["release"] = $item->getElementsByTagName("release")->item(0)->nodeValue; - $data["machine"] = $item->getElementsByTagName("machine")->item(0)->nodeValue; - $data["memory"] = $item->getElementsByTagName("memory")->item(0)->nodeValue; - $data["swap"] = $item->getElementsByTagName("swap")->item(0)->nodeValue; + foreach($keys as $key) { + $keyElement = $item->getElementsByTagName($key); + if($keyElement->length > 0) { + $data[$key] = $keyElement->item(0)->nodeValue; + } + } } } return $data; - } public static function GetPypoStatus(){ From 383fa35fc50d2cf34c385b48138516ae35e3c378 Mon Sep 17 00:00:00 2001 From: Yuchen Wang Date: Tue, 15 Nov 2011 14:24:14 -0500 Subject: [PATCH 6/9] CC-2950: Tell users if they are running an out-of-date version or not - Hide tooltip and close button on mouseout when current version is up to date - Return version diff instead of tooltip msg in VersionNotify.php, make js side responsible for picking the msg --- .../views/helpers/VersionNotify.php | 14 ++--- .../js/airtime/dashboard/versiontooltip.js | 62 ++++++++++++++++--- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/airtime_mvc/application/views/helpers/VersionNotify.php b/airtime_mvc/application/views/helpers/VersionNotify.php index be87718a7..e4ece3df3 100644 --- a/airtime_mvc/application/views/helpers/VersionNotify.php +++ b/airtime_mvc/application/views/helpers/VersionNotify.php @@ -26,35 +26,31 @@ class Airtime_View_Helper_VersionNotify extends Zend_View_Helper_Abstract{ return ""; } - // Calculate version diff + // Calculate major version diff; + // Example: if current = 1.9.5 and latest = 3.0.0, major diff = 11 // Note: algorithm assumes the number after 1st dot never goes above 9 $diff = (intval($latestMatch[1]) * 10 + intval($latestMatch[2])) - (intval($curMatch[1]) * 10 + intval($curMatch[2])); - // Pick icon and tooltip msg + // Pick icon $bg = "/css/images/"; - $msg = ""; - $link = "" . $latest . ""; if(($diff == 0 && $current == $latest) || $diff < 0) { // current version is up to date $bg .= "icon_uptodate.png"; - $msg = "You are running the latest version"; } else if($diff <= 2) { // 2 or less major versions back $bg .= "icon_update.png"; - $msg = "New version available: " . $link; } else if($diff == 3) { // 3 major versions back $bg .= "icon_update2.png"; - $msg = "This version will soon be obsolete.
Please upgrade to " . $link; } else { // more than 3 major versions back $bg .= "icon_outdated.png"; - $msg = "This version is no longer supported.
Please upgrade to " . $link; } - $result = "" + $result = "" . "" + . "" . "
"; return $result; } diff --git a/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js b/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js index 0f014a5db..ab96e6759 100644 --- a/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js +++ b/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js @@ -1,19 +1,63 @@ /** - * Get the tooltip message to be displayed, - * which is stored inside a pair of hidden div tags + * Get the tooltip message to be displayed */ function getContent() { - return $("#version_message").html(); + var diff = getVersionDiff(); + var link = getLatestLink(); + + var msg = ""; + if(isUpToDate()) { + msg = "You are running the latest version"; + } else if(diff <= 2) { + msg = "New version available: " + link; + } else if(diff == 3) { + msg = "This version will soon be obsolete.
Please upgrade to " + link; + } else { + msg = "This version is no longer supported.
Please upgrade to " + link; + } + + return msg; } /** - * Get the current version, - * which is stored inside a pair of hidden div tags + * Get major version difference b/w current and latest version, in int + */ +function getVersionDiff() { + return parseInt($("#version_diff").html()); +} + +/** + * Get the current version */ function getCurrentVersion() { return $("#version_current").html(); } +/** + * Get the latest version + */ +function getLatestVersion() { + return $("#version_latest").html(); +} + +/** + * Returns true if current version is up to date + */ +function isUpToDate() { + var diff = getVersionDiff(); + var current = getCurrentVersion(); + var latest = getLatestVersion(); + var temp = (diff == 0 && current == latest) || diff < 0; + return (diff == 0 && current == latest) || diff < 0; +} + +/** + * Returns the download link to latest release in HTML + */ +function getLatestLink() { + return "" + getLatestVersion() + ""; +} + /** * Sets up the tooltip for version notification */ @@ -26,10 +70,12 @@ function setupVersionQtip(){ text: getContent(), title: { text: getCurrentVersion(), - button: true + button: isUpToDate() ? false : true } }, - hide: false, /* Don't hide on mouseout */ + hide: { + event: isUpToDate() ? 'mouseleave' : 'unfocus' + }, position: { my: "top right", at: "bottom left" @@ -46,7 +92,7 @@ function setupVersionQtip(){ } $(document).ready(function() { - if($('#version_message').length > 0) { + if($('#version_icon').length > 0) { setupVersionQtip(); } }); \ No newline at end of file From 4c26cb868baca05930168b6c8eba0f483116e610 Mon Sep 17 00:00:00 2001 From: lukabazuka Date: Tue, 15 Nov 2011 20:29:37 +0100 Subject: [PATCH 7/9] CC-2959 Signed-off-by: lukabazuka --- .../public/css/images/stream_status.png | Bin 1091 -> 5106 bytes airtime_mvc/public/css/styles.css | 23 ++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/airtime_mvc/public/css/images/stream_status.png b/airtime_mvc/public/css/images/stream_status.png index 99c2ca38ca4a3b32e5dfada0438e6abc03be065c..8ee45a015bea1e876e4510e22ab48d856e788a2a 100644 GIT binary patch literal 5106 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 diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index 927cea5f4..bc081003a 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -60,16 +60,15 @@ select { /* Version Notification Starts*/ #version_icon { position:absolute; - right:85px; + right:98px; top:104px; height:35px; width:35px; z-index:1000; display:block; - cursor:pointer; - - background-repeat:no-repeat; - background-position:center; + cursor:pointer; + background-repeat:no-repeat; + background-position:center; } #ui-tooltip-version a { @@ -2397,4 +2396,18 @@ tfoot tr th { } .status-error h3 { color:#DA0101; +} +.status-info { + background:#fff7e0 url(images/stream_status.png) no-repeat 5px -278px; + border-color:#f68826; +} +.status-info h3 { + color:#f1830c; +} +.status-disabled { + background:#c8ccc8 url(images/stream_status.png) no-repeat 5px -429px; + border-color:#7f827f; +} +.status-disabled h3 { + color:#646664; } \ No newline at end of file From ace68bd3630b5680b8ca3bf5d04b033273304a90 Mon Sep 17 00:00:00 2001 From: lukabazuka Date: Tue, 15 Nov 2011 21:00:14 +0100 Subject: [PATCH 8/9] CC-3029 Signed-off-by: lukabazuka --- .../public/css/images/icon_outdated.png | Bin 3861 -> 1207 bytes airtime_mvc/public/css/images/icon_update.png | Bin 3686 -> 1217 bytes .../public/css/images/icon_update2.png | Bin 3787 -> 1219 bytes .../public/css/images/icon_uptodate.png | Bin 3747 -> 1369 bytes airtime_mvc/public/css/styles.css | 15 +++++++++++++++ 5 files changed, 15 insertions(+) diff --git a/airtime_mvc/public/css/images/icon_outdated.png b/airtime_mvc/public/css/images/icon_outdated.png index 57202058fdf8b21f0db7e9176cd3f144b501788c..f977408a7d0f5f162f21ea4b8f78541ba2c76488 100644 GIT binary patch literal 1207 zcmeAS@N?(olHy`uVBq!ia0vp^5v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gtf;oFf&jvGt@IQ zHZeCh*HJJsFf`CNFw!?P(ls=P;d@5RS3__OUW-U21O3UuP&)YnPsUdZbkXI3gFPS%EV&3ivb~DL-eMQ6Jq*6 z$LNES22xUi2?5g|hzU>lKn^_Xq~-zhOA#<*ymEh61k6+~JzX3_DsH_AJI&i{z*FjU z#C-#kI+MHGYc|;h)+L*!vF>R8!QoN3YJuD;Hm&E!CM!vEyl1sP+NinI!E5CKUWwD2 zd{jL*rS(ja6u)P}%dtnmso{C$5~j~KuUD{6m=krtVaEA`iO#pTMav!ExYebd^{zcDqkY-^WRmqXdyz8~lGXFT5}-kSJgN$8i_`ZX?x4PHzwJg3OP zRK>rpl=rB`p~K%FPFwbc$s_Mk+~l9nd2d&&i&HeX^(;@FZ&uH9#%oiBUR*Wt{r|ps t@9!f!8P0!}iDBH?`tjh^_@mwpj10%D829t4@^*lV5>Hn@mvv4FO#qTEmxKTS literal 3861 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 Eg32W~ZU6uP diff --git a/airtime_mvc/public/css/images/icon_update2.png b/airtime_mvc/public/css/images/icon_update2.png index 38fa5330f27acf86bfca3232a070d96219d73eb3..8557d85e607f2069cba49de45293f8ab81b40a24 100644 GIT binary patch literal 1219 zcmeAS@N?(olHy`uVBq!ia0vp^5v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gtf;oFf&jvGt@IQ zHZeCh*HJJsFf`CNFw!?P(ls=P;d@5RS3__OUW-U21O3UuP&)YnPsUdZbkXI3gFPS%EV&3ivb~DL-eMQ6Jq*6 z$LNES22xUi2?5g|hzU>lKn^_Xq~-zhOA#<*Fs^@R49rwtJzX3_DsH`*<}Gwcfv2r; zQ+9sfj)wFPW_erY9lgEdBiNOx$f(k>@zWBI#$0W~h{3rTg>PN#T zvIj(^RDG{+ZkF~B7tWX6;l%BE`MAlKwb2guzaMmGEzx+r|KkJx4@??d3mM8EFW@VX z=TKZEclpGkZMpXRf>#eeVOY2|Z6(XLrypd4{)Wb|N-#VUnC-#wz0U_!ta!TmxvX4Tx0C?K1*LgJ5>l*;@XAEN>lY|i&A(N%-wA!-E8d(c7wqlGmvR`G-PS$KK zM3F3UX|WVimZ&755=mTSm-+pneYyAdJNNhe^?aZ6zUO@3_j8`}o(F&hY{+D1DgbaH zdAb{_E8|Sf%yG0&ff3k&9b`eyhTuU~(%094-^To7KmY(d60;$bo#zs(dc^Jbv|;X7 zTVji+7~$`O+1=F48~}j>05*s9Tp9q_Y}a!Q0AM@eN%jOlSONeW!O?~YfFJ{asQV#9 z6#zsQ0H7V#^AZ3++pgzz0D$%;ICuge+5u3kB%%`ufOZG~wV!C`K>$GG0KkVpcJ~B8 zrvZSXi;F7}0R0pI@TO+wxb@#W!UZ7f1;8NxwdQsR;F>D{cI<0S$Ps{37NC^oYi(8^ z5CDK+zv*EwB?$lk2qq-}ngI%B77sw12=FnULRrbDP(Bs_Ao~Gs`w+a`y+7R%f=UYD zpT5`6`6-YH04e}5L8ww;sX~$5)G{=9no5*5YLwQWZU?VwTEjj_1?*SefygfN)?xs zqg8wlII5beX{zti5Y^<-!f4;rSw1+W`&zGGzuTbIu)*k0<4q=Ihl@=wn&q44SY%qJ zTcsUIJ(_BrYLjaFfS6&IWuN1a?|9Ma^0Ct670xv-w@EFo9poo&gYIJ<)1E8dG$$}V z+`jme(tb+*x&fAf$AWx=BSO;tC=9)Es`Ye#*!%Ft2%SiQD7k3u80#~hu~Bik@l^@! ziLa8DQ&>}l&#I(Zrh8??Wfo;MWe=WP&SlS&%GWD!J|B7E(#7UWuZobDw-zgv*jx#@ znqS&jHd2ndzP&=bl2nygU3p`rmQu%GuW{4mR?_X7JA;j=Cb4GYy8-tuv^;E`zt7vQ z`4HQY-PzJL`-rCp-E+P-_i_7^rM_*?jQT^KmktaJG7aq+c6yoqs`d5MNcbDG(WtSy zx0CN^-kqBWeP1>CcIxzBdegh7duAqPBR?FPQEUwF%I1~oRio9Z zk1=cbwPuPfh4RT?2`Nv_LY?$q_$&X$-|-v&1E2g;g zuDxEDev83v!&;+?LsyLpP0k$&%>5k$P6UPpr37CLsr=(^ z=+jfxrxnA{;d~L&k(yCf(e5!3XR>3j$F;=|CoCpmlJUvoDc-4WXQR_Dq~Ffy&s@l6 zJ-0JQJJ&HUEWeRX58@x3t zwN8J=)>YK^-%`6H++fh?+mzSbc6X*_bE|3_>3-USx`$Jp*e=y>w@2AMt-bS4_@CZHc_yysG=Ee4o%{LTgPF8_F607=P-2G%}G|h`NGCi)IAn zM=MI_MsLl4Vkl)aXQE-c&TNm~g6?Dq!zf~wH&n5DY?RtK$5yrJB)bv^14kEUI+nmC z!A048pF4xcdCPuYR^HdR8ov0g4*UuNSb-VA2iuB-!tliHD#H9C)FN+0Tf~ZY#O?GF zHA-D)*|iA81sq zRXeFRuYO+RoMyUKvUa@AnS+tK;d){Ej{2hpp@yMGrw*Mq4mXKDe8x1vEX6#-!q4KP zWwBNHk(#4-tXplmZTkr$#3{Qg_EHWQM;<5PV{*q;osC>a+pQ9S43Ro<*4T9@)*T49I?`I z2JxhXn8eFTEy<&)sI!7;s_Awa;hBY5t=Z!_Ou0Mr4D-DU($Cjl7`}um6e-d#)-K7q z(s=c48RnXNx%Kskin7YS>ccgnwI+WC*Ilmfy`^(Uw86CTR8v{=S_@;Ve4G9Kr1pk~ zTRL%FdfkDKuJ*imZ1hyI&+S=3fA0Y5h5X?0VaJzUuW3ehy>S`M8+$y?@J?aE>wWR$ z@L$?9y0fQ0)XjZZ5LqNFWi9utGJjNClV9tl%mA#vcK`q=S%9Q%048PtCL#cFQ2=-V zU@rvFX9hU53#h~kfQlOri0e{c-VX#Ife|pk4uT*D2f+;NAOv#Y4vfGef)OEuutCHl z?jW8a=BPxdh*UXL|C+{mNI0^~TgG<6X5Md}AMJTzpQCe&t>Cn^usK`TZZLpw=l zNOyzo9X*adihiDf$k5BE&REB|z$D33%)E^`AI*o(V-a8}Vwu3~#N61RvY~_3igj{h zFxw`!Vzz}%Dw_t_eK|NdsyIzKSFw3q8eG|2)0?xnHMtjg3b$DBvhX(J0{Gg+Z z)!ojc$aBhD_C%0R>&Z=i1po2?^FU;fad1%xCDi0pX&8ODT|`3^Uvx;!t6258k_6U7 zzogeG`l)qiJ<>$dGc%d8g0es49LqN^=)GWYv7=D8=wY!zNzYaD(xGckxXZhxPxxE)TGor(28xVZMS$p>C)<+eysXrx?lG>Wr+9^I}$OrI$kp=J6$uU zyx6&FN1=T3M*-vi&A$V+_SOHBzSw8~AN1{6ihkDrVsHPA{`dCBzSaN#*sJ`5{lAz0 z**((jSMq5h>6sZupXGCh|JlCoVEyoC`+I(^*mjEtl#YV#>7LBTs(m^Ax-YH`5npwF z)}LCK^ncuD&eflsn{ffZHvX0H?|j!g z`)A+3>+FA}OZB_HPR{u3yRLig>bJg^Vt)`8`@xvw+aAB?*NSbcy&tu1-KDjz{baf? zr(gFu<;Arj;!EtS&etU)5u-|DtK&5j-jlLZ3)3~T{&UI;bc>zK8EX<03c&h|1ONaG zngmypva>7U_~#je0W^UCu0R51a0XW(!0}%%{NKaV&c_n~K*g2p>+a;>=!sJzlb!8w znk2#wQJkc>xcuMmU!UOs08ki!ECm37x&)@5*8K-8=JKxedEoT`000JJOGiWi00000 z0Qp0^e*gdg32;bRa{vGf6951U69E94oEQKA00(qQO+^RW3l0PbIkWewvH$=Bl}SWF zR5;6xl)-BwRUF5^znM%Yo0+i9vW0G`QmxBcFDixVvZq`EJrq1hP){!C!GkRJ+@sLz zV*h|rZ{o?xIUgBP~fcp_5E9^L}3snbg=V;tw9o{N8)t-}m$0 z{6_E}L2?+t^CUeHF#rORe^{0k;QvIk+3X8tNR~(*lKhM03CUxURg!;_yq~PY>gwv{ zV(oSt01(IVTdI1bsx@QGv8tX7jwJWg7*md-=uH49m&@lmGAP>VbY^VZ{u)4h$viLQ z2*9-4?dfbbd-N~Cv$Hcej`N~rSwDyf08mx0t13w%>UO2wYRMJPQ?jS)d0su)AE@e7 zsZ?qei$z!f;QKyAqf{y(>-+5_U+=qA)eOmxip3%TzzV|< z0HCVxs47$y#+V+Gh-_|d`akXN%HG}{9;~fpBths$Lh*M0-Abp^2!h~sk{(GR36c;I zsa7i2mX?-45}xPbyN3_aIy=i*1ER^ESF6>k0O%o$$ZM(^_Z^Z%I|#DHV$o`cAr}@F zFgG`c%F&U$fA_BKx^8CBp{m07{g(hBl~ge#2dkpdXtFH@tFsbxlaM9tDC&Tme^Ol`TAqWCAn@zOB5Fg*WC;R*R{=h|xs(z6e>v31B zRk*JEf{6SGKmkC=>(0>7KP^J`h6v&~27#00+)TY*AD^6@jGt+}N~LlqlgWHV(j;@V zEQ=TLB)JFzh>S6JMn*<{f2Nmh+qR4`Lt9&0?@dfhd}`Zvw%hI6#u!^fC?XI6Ez35J z<1mV%lXAKIL7`Ci9)RhCoS&gFMnoi)&*#6*=kp(KZ*T7zV_cAqF=i-^;~`_ziK58) zW^?n)+qd6%w@@gQ0XTz{gUA*D*G;=QoA!-Xr}doYd9TdQ&b~Z4I+}^1D6Z9N^|iIN zT>y_EQUzH9&;$_m9m<8@qT~C1I*#M3aUADJT%(CS?YU4J2nA@wz$t*I00ID=1R0kJ z3IOpuFBJrVn?dGE3oR$X(!@yzK$tw6{#VhDzX2nGJwbQ0VIu$l002ovPDHLkV1m-I BZ%qII diff --git a/airtime_mvc/public/css/images/icon_uptodate.png b/airtime_mvc/public/css/images/icon_uptodate.png index 8ed6bb01dcd8e58f19d877278839ac9423c44600..ee278e90dde030c77fbdfc0e07d385f17c17fc19 100644 GIT binary patch literal 1369 zcmeAS@N?(olHy`uVBq!ia0vp^5v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`Gtf;oFf&jvGt@IQ zHZeCh*HJJsFf`CNFw!?P(ls=rM=H8gZJbTVP;d@5RS3__OUW-U21O3UuP&)YnPsUdZbkXI3gFPS%EV^70U=*Q^rny#V){VG z=!235Qc{5l0n;Cd2~YSy4m|6m<^l6d5inx}1$UlcU|{U_ba4!+xOHaQO}|49B5nRJ zRaiAylSLjCDPMW&+T;D`wAK#W&eKb|eR~#cxiM?Y<2eUcZsl3(ByD>#W!tyk*8gYD z3|TnEY4z1b6Z|z;9`0J#yhvl_q>qPlZ!cr9ZV?CwH4SFG|Gn}otH8Xi4IE0-np3ZR zu;DlHmEO#;SU_~f(jDu#pYE-WJO2Dx9AjN&>VHA6+h(tA4?L(bjX8OTiNoCD&cj*} z#Z|25uDV$<&Rl)cbTOUs@!{56qqc(!`RZ^r$m2lhowewN_F zziqi7#Cq98alM1tI)_ZN**pJ+)^HgxJQD0^aWc~ literal 3747 zcmV;U4qWkxP)4Tx0C?K1*LgJ5>l*;@XAEN>lY|i&A(N%-wA!-E8d(c7wqlGmvR`G-PS$KK zM3F3UX|WVimZ&755=mTSm-+pneYyAdJNNhe^?aZ6zUO@3_j8`}o(F&hY{+D1DgbaH zdAb{_E8|Sf%yG0&ff3k&9b`eyhTuU~(%094-^To7KmY(d60;$bo#zs(dc^Jbv|;X7 zTVji+7~$`O+1=F48~}j>05*s9Tp9q_Y}a!Q0AM@eN%jOlSONeW!O?~YfFJ{asQV#9 z6#zsQ0H7V#^AZ3++pgzz0D$%;ICuge+5u3kB%%`ufOZG~wV!C`K>$GG0KkVpcJ~B8 zrvZSXi;F7}0R0pI@TO+wxb@#W!UZ7f1;8NxwdQsR;F>D{cI<0S$Ps{37NC^oYi(8^ z5CDK+zv*EwB?$lk2qq-}ngI%B77sw12=FnULRrbDP(Bs_Ao~Gs`w+a`y+7R%f=UYD zpT5`6`6-YH04e}5L8ww;sX~$5)G{=9no5*5YLwQWZU?VwTEjj_1?*SefygfN)?xs zqg8wlII5beX{zti5Y^<-!f4;rSw1+W`&zGGzuTbIu)*k0<4q=Ihl@=wn&q44SY%qJ zTcsUIJ(_BrYLjaFfS6&IWuN1a?|9Ma^0Ct670xv-w@EFo9poo&gYIJ<)1E8dG$$}V z+`jme(tb+*x&fAf$AWx=BSO;tC=9)Es`Ye#*!%Ft2%SiQD7k3u80#~hu~Bik@l^@! ziLa8DQ&>}l&#I(Zrh8??Wfo;MWe=WP&SlS&%GWD!J|B7E(#7UWuZobDw-zgv*jx#@ znqS&jHd2ndzP&=bl2nygU3p`rmQu%GuW{4mR?_X7JA;j=Cb4GYy8-tuv^;E`zt7vQ z`4HQY-PzJL`-rCp-E+P-_i_7^rM_*?jQT^KmktaJG7aq+c6yoqs`d5MNcbDG(WtSy zx0CN^-kqBWeP1>CcIxzBdegh7duAqPBR?FPQEUwF%I1~oRio9Z zk1=cbwPuPfh4RT?2`Nv_LY?$q_$&X$-|-v&1E2g;g zuDxEDev83v!&;+?LsyLpP0k$&%>5k$P6UPpr37CLsr=(^ z=+jfxrxnA{;d~L&k(yCf(e5!3XR>3j$F;=|CoCpmlJUvoDc-4WXQR_Dq~Ffy&s@l6 zJ-0JQJJ&HUEWeRX58@x3t zwN8J=)>YK^-%`6H++fh?+mzSbc6X*_bE|3_>3-USx`$Jp*e=y>w@2AMt-bS4_@CZHc_yysG=Ee4o%{LTgPF8_F607=P-2G%}G|h`NGCi)IAn zM=MI_MsLl4Vkl)aXQE-c&TNm~g6?Dq!zf~wH&n5DY?RtK$5yrJB)bv^14kEUI+nmC z!A048pF4xcdCPuYR^HdR8ov0g4*UuNSb-VA2iuB-!tliHD#H9C)FN+0Tf~ZY#O?GF zHA-D)*|iA81sq zRXeFRuYO+RoMyUKvUa@AnS+tK;d){Ej{2hpp@yMGrw*Mq4mXKDe8x1vEX6#-!q4KP zWwBNHk(#4-tXplmZTkr$#3{Qg_EHWQM;<5PV{*q;osC>a+pQ9S43Ro<*4T9@)*T49I?`I z2JxhXn8eFTEy<&)sI!7;s_Awa;hBY5t=Z!_Ou0Mr4D-DU($Cjl7`}um6e-d#)-K7q z(s=c48RnXNx%Kskin7YS>ccgnwI+WC*Ilmfy`^(Uw86CTR8v{=S_@;Ve4G9Kr1pk~ zTRL%FdfkDKuJ*imZ1hyI&+S=3fA0Y5h5X?0VaJzUuW3ehy>S`M8+$y?@J?aE>wWR$ z@L$?9y0fQ0)XjZZ5LqNFWi9utGJjNClV9tl%mA#vcK`q=S%9Q%048PtCL#cFQ2=-V zU@rvFX9hU53#h~kfQlOri0e{c-VX#Ife|pk4uT*D2f+;NAOv#Y4vfGef)OEuutCHl z?jW8a=BPxdh*UXL|C+{mNI0^~TgG<6X5Md}AMJTzpQCe&t>Cn^usK`TZZLpw=l zNOyzo9X*adihiDf$k5BE&REB|z$D33%)E^`AI*o(V-a8}Vwu3~#N61RvY~_3igj{h zFxw`!Vzz}%Dw_t_eK|NdsyIzKSFw3q8eG|2)0?xnHMtjg3b$DBvhX(J0{Gg+Z z)!ojc$aBhD_C%0R>&Z=i1po2?^FU;fad1%xCDi0pX&8ODT|`3^Uvx;!t6258k_6U7 zzogeG`l)qiJ<>$dGc%d8g0es49LqN^=)GWYv7=D8=wY!zNzYaD(xGckxXZhxPxxE)TGor(28xVZMS$p>C)<+eysXrx?lG>Wr+9^I}$OrI$kp=J6$uU zyx6&FN1=T3M*-vi&A$V+_SOHBzSw8~AN1{6ihkDrVsHPA{`dCBzSaN#*sJ`5{lAz0 z**((jSMq5h>6sZupXGCh|JlCoVEyoC`+I(^*mjEtl#YV#>7LBTs(m^Ax-YH`5npwF z)}LCK^ncuD&eflsn{ffZHvX0H?|j!g z`)A+3>+FA}OZB_HPR{u3yRLig>bJg^Vt)`8`@xvw+aAB?*NSbcy&tu1-KDjz{baf? zr(gFu<;Arj;!EtS&etU)5u-|DtK&5j-jlLZ3)3~T{&UI;bc>zK8EX<03c&h|1ONaG zngmypva>7U_~#je0W^UCu0R51a0XW(!0}%%{NKaV&c_n~K*g2p>+a;>=!sJzlb!8w znk2#wQJkc>xcuMmU!UOs08ki!ECm37x&)@5*8K-8=JKxedEoT`000JJOGiWi{{a60 z|De66lK=n!32;bRa{vGf6951U69E94oEQKA00(qQO+^RW3k?q$Cj`Ot&Hw-dZAnBy zR5;6xR8L5xbr^o$-_Or)oNt_TQ5(@MTZ7etRDw$OG?xKy9XeE(_E47)_7K~lc5ikM za(B;ygo(A0CBa6A1oKc3!kjD(YMfAJbZ4Czzdyg<)4}f>CUuuyc;VxHe>^|qkQg!^FsMTr-P@3e|B>y7$56J_P`y|UG|0elq{0_^@%NK(+ zn@s>f6h*IFYxk_R6=Tf4wf3Mr_roSXmvthH}iYw@^LN^yREzH4o5 zEj>9kMWs~IBgr>ffT>gp^?H4Zq(@RnB1xrGGAnLvZFPLUxR@EcdKH&?dL#_P*GLQAMV|~n{754a%FUsAKkij=y{&K01VsP+uQ%~VXamxk?c%- zW{i=0ckXoWl}auFymS5f!?E%4AW?G0m%nGT+3CZ>!_yhYTmG``hD9lb*&8=%xxqny zVsf(i(!|6?U<4r6+Ajd0x3~9{VYys}>$=a0$S(kF{15;{DMe$9h)6p~``k>mS{)u8 z9gWVNUa3^NmQJTvNha4qr4-wk1AxR#2_Q7aTD<`Zcza}IWKL_{ z9Rz_k#%K|th(H8XN*l*<7>40Nu~>Y!P$>KqpDSBF1b|ppM?RnbF`v)Bx4F6bn=!@( z=@?@=qbTY$#yVjbIzK#k@Xhq}t8Wzwg(3jwoOjxO6t0_cdo}f7!*5*nJnw~>nVGR% zE|(6&Fsf84)s>Z%Ujh69kut~%fEs`>VR&|HP9~E{MN#xr6h*xxF407uJ!N4va3a9N z2si|A1fUMUk0s+GKmj10=XKQUbvKQ4R|5?vmStlmK7f<>+r;%&{0r7sJhMR+8QuT@ N002ovPDHLkV1nTLSU~^) diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index bc081003a..b1b4e37f9 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -70,6 +70,18 @@ select { background-repeat:no-repeat; background-position:center; } +#version_icon.outdated { + background-image:url(images/icon_outdated.png); +} +#version_icon.update2 { + background-image:url(images/icon_update2.png); +} +#version_icon.update { + background-image:url(images/icon_update.png); +} +#version_icon.uptodate { + background-image:url(images/icon_uptodate.png); +} #ui-tooltip-version a { color:#ff5d1a; @@ -2365,6 +2377,9 @@ tfoot tr th { margin:2px 1px 10px 0px; width: auto; } +dd .stream-status { + margin-bottom:1px; +} .stream-status h3 { font-size: 12px; font-weight: bold; From af1b376cdfe07a8bb395239a121eb388606ee493 Mon Sep 17 00:00:00 2001 From: Yuchen Wang Date: Tue, 15 Nov 2011 16:08:05 -0500 Subject: [PATCH 9/9] CC-3029: Graphic design for the version notification feature - use classes in VersionNotify.php for displaying icons instead of inline styling - change underscore to hyphen so that naming convention is consistent with the rest in style.css --- .../views/helpers/VersionNotify.php | 17 +++++++------- airtime_mvc/public/css/styles.css | 22 +++++++++---------- .../js/airtime/dashboard/versiontooltip.js | 10 ++++----- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/airtime_mvc/application/views/helpers/VersionNotify.php b/airtime_mvc/application/views/helpers/VersionNotify.php index e4ece3df3..655843f0e 100644 --- a/airtime_mvc/application/views/helpers/VersionNotify.php +++ b/airtime_mvc/application/views/helpers/VersionNotify.php @@ -33,25 +33,24 @@ class Airtime_View_Helper_VersionNotify extends Zend_View_Helper_Abstract{ - (intval($curMatch[1]) * 10 + intval($curMatch[2])); // Pick icon - $bg = "/css/images/"; if(($diff == 0 && $current == $latest) || $diff < 0) { // current version is up to date - $bg .= "icon_uptodate.png"; + $class = "uptodate"; } else if($diff <= 2) { // 2 or less major versions back - $bg .= "icon_update.png"; + $class = "update"; } else if($diff == 3) { // 3 major versions back - $bg .= "icon_update2.png"; + $class = "update2"; } else { // more than 3 major versions back - $bg .= "icon_outdated.png"; + $class = "outdated"; } - $result = "" - . "" - . "" - . "
"; + $result = "" + . "" + . "" + . "
"; return $result; } } diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index b1b4e37f9..04fc58027 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -58,9 +58,9 @@ select { } /* Version Notification Starts*/ -#version_icon { +#version-icon { position:absolute; - right:98px; + right:96px; top:104px; height:35px; width:35px; @@ -68,19 +68,19 @@ select { display:block; cursor:pointer; background-repeat:no-repeat; - background-position:center; + background-position:center; } -#version_icon.outdated { - background-image:url(images/icon_outdated.png); +#version-icon.outdated { + background-image:url(/css/images/icon_outdated.png); } -#version_icon.update2 { - background-image:url(images/icon_update2.png); +#version-icon.update2 { + background-image:url(/css/images/icon_update2.png); } -#version_icon.update { - background-image:url(images/icon_update.png); +#version-icon.update { + background-image:url(/css/images/icon_update.png); } -#version_icon.uptodate { - background-image:url(images/icon_uptodate.png); +#version-icon.uptodate { + background-image:url(/css/images/icon_uptodate.png); } #ui-tooltip-version a { diff --git a/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js b/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js index ab96e6759..e428cc7f3 100644 --- a/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js +++ b/airtime_mvc/public/js/airtime/dashboard/versiontooltip.js @@ -23,21 +23,21 @@ function getContent() { * Get major version difference b/w current and latest version, in int */ function getVersionDiff() { - return parseInt($("#version_diff").html()); + return parseInt($("#version-diff").html()); } /** * Get the current version */ function getCurrentVersion() { - return $("#version_current").html(); + return $("#version-current").html(); } /** * Get the latest version */ function getLatestVersion() { - return $("#version_latest").html(); + return $("#version-latest").html(); } /** @@ -62,7 +62,7 @@ function getLatestLink() { * Sets up the tooltip for version notification */ function setupVersionQtip(){ - var qtipElem = $('#version_icon'); + var qtipElem = $('#version-icon'); if (qtipElem.length > 0){ qtipElem.qtip({ id: 'version', @@ -92,7 +92,7 @@ function setupVersionQtip(){ } $(document).ready(function() { - if($('#version_icon').length > 0) { + if($('#version-icon').length > 0) { setupVersionQtip(); } }); \ No newline at end of file