diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index 919b365bd..4a5157f1e 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -130,9 +130,11 @@ class Bootstrap extends Zend_Application_Bootstrap_Bootstrap protected function _initTasks() { /* We need to wrap this here so that we aren't checking when we're running the unit test suite */ + $taskManager = TaskManager::getInstance(); + $taskManager->runTask(AirtimeTask::UPGRADE); // Run the upgrade on each request (if it needs to be run) if (getenv("AIRTIME_UNIT_TEST") != 1) { //This will do the upgrade too if it's needed... - TaskManager::getInstance()->runTasks(); + $taskManager->runTasks(); } } diff --git a/airtime_mvc/application/common/FileDataHelper.php b/airtime_mvc/application/common/FileDataHelper.php index 5a600e419..2c5648f9f 100644 --- a/airtime_mvc/application/common/FileDataHelper.php +++ b/airtime_mvc/application/common/FileDataHelper.php @@ -2,6 +2,27 @@ class FileDataHelper { + public static function getAudioMimeTypeArray() { + return array( + "audio/ogg" => "ogg", + "application/ogg" => "ogg", + "audio/vorbis" => "ogg", + "audio/mp3" => "mp3", + "audio/mpeg" => "mp3", + "audio/mpeg3" => "mp3", + "audio/aac" => "aac", + "audio/aacp" => "aac", + "audio/mp4" => "mp4", + "audio/x-flac" => "flac", + "audio/wav" => "wav", + "audio/x-wav" => "wav", + "audio/mp2" => "mp2", + "audio/mp1" => "mp1", + "audio/x-ms-wma" => "wma", + "audio/basic" => "au", + ); + } + /** * We want to throw out invalid data and process the upload successfully * at all costs, so check the data and sanitize it if necessary @@ -24,4 +45,24 @@ class FileDataHelper { $data["bpm"] = intval($data["bpm"]); } } + + /** + * Return a suitable extension for the given file + * + * @param string $mime + * + * @return string file extension with(!) a dot (for convenience) + * + * @throws Exception + */ + public static function getFileExtensionFromMime($mime) + { + $mime = trim(strtolower($mime)); + try { + return ('.' . static::getAudioMimeTypeArray()[$mime]); + } catch (Exception $e) { + throw new Exception("Unknown file type: $mime"); + } + } + } \ No newline at end of file diff --git a/airtime_mvc/application/common/HTTPHelper.php b/airtime_mvc/application/common/HTTPHelper.php index 04a9e9cc5..c702da480 100644 --- a/airtime_mvc/application/common/HTTPHelper.php +++ b/airtime_mvc/application/common/HTTPHelper.php @@ -45,8 +45,6 @@ class Application_Common_HTTPHelper class ZendActionHttpException extends Exception { - private $_action; - /** * @param Zend_Controller_Action $action * @param int $statusCode @@ -58,8 +56,7 @@ class ZendActionHttpException extends Exception { */ public function __construct(Zend_Controller_Action $action, $statusCode, $message, $code = 0, Exception $previous = null) { - $this->_action = $action; - Logging::info("Error in action " . $action->getRequest()->getActionName() + Logging::error("Error in action " . $action->getRequest()->getActionName() . " with status code $statusCode: $message"); $action->getResponse() ->setHttpResponseCode($statusCode) @@ -67,8 +64,4 @@ class ZendActionHttpException extends Exception { parent::__construct($message, $code, $previous); } - public function getAction() { - return $this->_action; - } - } \ No newline at end of file diff --git a/airtime_mvc/application/common/TaskManager.php b/airtime_mvc/application/common/TaskManager.php index aa250f294..c1687defa 100644 --- a/airtime_mvc/application/common/TaskManager.php +++ b/airtime_mvc/application/common/TaskManager.php @@ -2,15 +2,19 @@ /** * Class TaskManager + * + * When adding a new task, the new AirtimeTask class will need to be added to the internal task list, + * as an ENUM value to the AirtimeTask interface, and as a case in the TaskFactory. */ final class TaskManager { /** - * @var array tasks to be run + * @var array tasks to be run. Maps task names to a boolean value denoting + * whether the task has been checked/run */ protected $_taskList = [ - AirtimeTask::UPGRADE, // Always run the upgrade first - AirtimeTask::CELERY + AirtimeTask::UPGRADE => false, + AirtimeTask::CELERY => false, ]; /** @@ -19,8 +23,7 @@ final class TaskManager { protected static $_instance; /** - * @var int TASK_INTERVAL_SECONDS how often, in seconds, to run the TaskManager tasks, - * if they need to be run + * @var int TASK_INTERVAL_SECONDS how often, in seconds, to run the TaskManager tasks */ const TASK_INTERVAL_SECONDS = 30; @@ -47,6 +50,22 @@ final class TaskManager { return self::$_instance; } + /** + * Run a single task. + * + * @param string $taskName the ENUM name of the task to be run + */ + public function runTask($taskName) { + $task = TaskFactory::getTask($taskName); + if ($task && $task->shouldBeRun()) { + $task->run(); + } + $this->_taskList[$taskName] = true; // Mark that the task has been checked/run. + // This is important for prioritized tasks that + // we need to run on every request (such as the + // schema check/upgrade) + } + /** * Run all tasks that need to be run. * @@ -81,10 +100,9 @@ final class TaskManager { // better to be silent here to avoid log bloat return; } - foreach ($this->_taskList as $task) { - $task = TaskFactory::getTask($task); - if ($task && $task->shouldBeRun()) { - $task->run(); + foreach ($this->_taskList as $task => $hasTaskRun) { + if (!$hasTaskRun) { + $this->runTask($task); } } } diff --git a/airtime_mvc/application/common/WidgetHelper.php b/airtime_mvc/application/common/WidgetHelper.php index f2a9ecda8..8be23e200 100644 --- a/airtime_mvc/application/common/WidgetHelper.php +++ b/airtime_mvc/application/common/WidgetHelper.php @@ -57,83 +57,93 @@ class WidgetHelper return $result; } - // Second version of this function. - // Removing "next" days and creating two weekly arrays - public static function getWeekInfoV2($timezone) + /** + * Returns a weeks worth of shows in UTC, and an info array of the current week's days. + * Returns an array of two arrays: + * + * The first array is 7 consecutive week days, starting with the current day. + * + * The second array contains shows scheduled during the 7 week days in the first array. + * The shows returned in this array are not in any order and are in UTC. + * + * We don't do any timezone conversion in this function on purpose. All timezone conversion + * and show time ordering should be done on the frontend. + * + * @return array + */ + public static function getWeekInfoV2() { - //weekStart is in station time. - //$weekStartDateTime = Application_Common_DateHelper::getWeekStartDateTime(); $weekStartDateTime = new DateTime("now", new DateTimeZone(Application_Model_Preference::GetTimezone())); - $maxNumOFWeeks = 2; - $result = array(); - // default to the station timezone - $timezone = Application_Model_Preference::GetDefaultTimezone(); - $userDefinedTimezone = strtolower($timezone); - // if the timezone defined by the user exists, use that - if (array_key_exists($userDefinedTimezone, timezone_abbreviations_list())) { - $timezone = $userDefinedTimezone; - } $utcTimezone = new DateTimeZone("UTC"); $weekStartDateTime->setTimezone($utcTimezone); - // When querying for shows we need the start and end date range to have - // a time of "00:00". $utcDayStart is used below when querying for shows. - $utcDayStartDT = clone $weekStartDateTime; - $utcDayStartDT->setTime(0, 0, 0); - $utcDayStart = $utcDayStartDT->format(DEFAULT_TIMESTAMP_FORMAT); - $weekCounter = 0; - while ($weekCounter < $maxNumOFWeeks) { - for ($dayOfWeekCounter = 0; $dayOfWeekCounter < DAYS_PER_WEEK; $dayOfWeekCounter++) { - $dateParse = date_parse($weekStartDateTime->format(DEFAULT_TIMESTAMP_FORMAT)); + // Use this variable as the start date/time range when querying + // for shows. We set it to 1 day prior to the beginning of the + // schedule widget data to account for show date changes when + // converting their start day/time to the client's local timezone. + $showQueryDateRangeStart = clone $weekStartDateTime; + $showQueryDateRangeStart->sub(new DateInterval("P1D")); + $showQueryDateRangeStart->setTime(0, 0, 0); - $result[$weekCounter][$dayOfWeekCounter]["dayOfMonth"] = $dateParse["day"]; - $result[$weekCounter][$dayOfWeekCounter]["dayOfWeek"] = strtoupper(date("D", $weekStartDateTime->getTimestamp())); + for ($dayOfWeekCounter = 0; $dayOfWeekCounter < DAYS_PER_WEEK; $dayOfWeekCounter++) { + $dateParse = date_parse($weekStartDateTime->format("Y-m-d H:i:s")); - //have to be in station timezone when adding 1 day for daylight savings. - $weekStartDateTime->setTimezone(new DateTimeZone($timezone)); - $weekStartDateTime->add(new DateInterval('P1D')); + // Associate data to its date so that when we convert this array + // to json the order remains the same - in chronological order. + // We also format the key to be for example: "2015-6-1" to match + // javascript date formats so it's easier to sort the shows by day. + $result["weekDays"][$weekStartDateTime->format("Y-n-j")] = array(); + $result["weekDays"][$weekStartDateTime->format("Y-n-j")]["dayOfMonth"] = $dateParse["day"]; + $result["weekDays"][$weekStartDateTime->format("Y-n-j")]["dayOfWeek"] = strtoupper(_(date("D", $weekStartDateTime->getTimestamp()))); - //convert back to UTC to get the actual timestamp used for search. - $weekStartDateTime->setTimezone($utcTimezone); + // Shows scheduled for this day will get added to this array when + // we convert the show times to the client's local timezone in weekly-program.phtml + $result["weekDays"][$weekStartDateTime->format("Y-n-j")]["shows"] = array(); - // When querying for shows we need the start and end date range to have - // a time of "00:00". - $utcDayEndDT = clone $weekStartDateTime; - $utcDayEndDT->setTime(0, 0, 0); - $utcDayEnd = $utcDayEndDT->format(DEFAULT_TIMESTAMP_FORMAT); - $shows = Application_Model_Show::getNextShows($utcDayStart, "ALL", $utcDayEnd); - $utcDayStart = $utcDayEnd; + // $weekStartDateTime has to be in station timezone when adding 1 day for daylight savings. + // TODO: is this necessary since we set the time to "00:00" ? + $stationTimezone = Application_Model_Preference::GetDefaultTimezone(); + $weekStartDateTime->setTimezone(new DateTimeZone($stationTimezone)); - // convert to user-defined timezone, or default to station - Application_Common_DateHelper::convertTimestampsToTimezone( - $shows, - array("starts", "ends", "start_timestamp", "end_timestamp"), - $timezone - ); + $weekStartDateTime->add(new DateInterval('P1D')); - - foreach($shows as &$show) { - $startParseDate = date_parse($show['starts']); - $show["show_start_hour"] = str_pad($startParseDate["hour"], 2, "0", STR_PAD_LEFT).":".str_pad($startParseDate["minute"], 2, 0, STR_PAD_LEFT); - - $endParseDate = date_parse($show['ends']); - $show["show_end_hour"] = str_pad($endParseDate["hour"], 2, 0, STR_PAD_LEFT).":".str_pad($endParseDate["minute"],2, 0, STR_PAD_LEFT); - } - $result[$weekCounter][$dayOfWeekCounter]["shows"] = $shows; - - } - $weekCounter += 1; + //convert back to UTC to get the actual timestamp used for search. + $weekStartDateTime->setTimezone($utcTimezone); } + // Use this variable as the end date/time range when querying + // for shows. We set it to 1 day after the end of the schedule + // widget data to account for show date changes when converting + // their start day/time to the client's local timezone. + $showQueryDateRangeEnd = clone $weekStartDateTime; + $showQueryDateRangeEnd->setTime(23, 59, 0); + + $shows = Application_Model_Show::getNextShows( + $showQueryDateRangeStart->format("Y-m-d H:i:s"), + "ALL", + $showQueryDateRangeEnd->format("Y-m-d H:i:s")); + + // Convert each start and end time string to DateTime objects + // so we can get a real timestamp. The timestamps will be used + // to convert into javascript Date objects. + foreach($shows as &$show) { + $dtStarts = new DateTime($show["starts"], new DateTimeZone("UTC")); + $show["starts_timestamp"] = $dtStarts->getTimestamp(); + + $dtEnds = new DateTime($show["ends"], new DateTimeZone("UTC")); + $show["ends_timestamp"] = $dtEnds->getTimestamp(); + } + $result["shows"] = $shows; // XSS exploit prevention SecurityHelper::htmlescape_recursive($result); // convert image paths to point to api endpoints + //TODO: do we need this here? self::findAndConvertPaths($result); return $result; diff --git a/airtime_mvc/application/configs/constants.php b/airtime_mvc/application/configs/constants.php index 4360cd9e7..aaed5d901 100644 --- a/airtime_mvc/application/configs/constants.php +++ b/airtime_mvc/application/configs/constants.php @@ -24,7 +24,8 @@ define('LICENSE_URL' , 'http://www.gnu.org/licenses/agpl-3.0-standalone.h define('AIRTIME_COPYRIGHT_DATE' , '2010-2015'); define('AIRTIME_REST_VERSION' , '1.1'); define('AIRTIME_API_VERSION' , '1.1'); -define('AIRTIME_CODE_VERSION' , '2.5.13'); +// XXX: it's important that we upgrade this every time we add an upgrade! +define('AIRTIME_CODE_VERSION' , '2.5.14'); // Defaults define('DEFAULT_LOGO_PLACEHOLDER', 1); diff --git a/airtime_mvc/application/controllers/AudiopreviewController.php b/airtime_mvc/application/controllers/AudiopreviewController.php index c5ad22a58..bff30e929 100644 --- a/airtime_mvc/application/controllers/AudiopreviewController.php +++ b/airtime_mvc/application/controllers/AudiopreviewController.php @@ -198,23 +198,10 @@ class AudiopreviewController extends Zend_Controller_Action $elementMap['type'] = $track['type']; if ($track['type'] == 0) { - $mime = $track['mime']; - //type is file - if (strtolower($mime) === 'audio/mp3') { - $elementMap['element_mp3'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/ogg') { - $elementMap['element_oga'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/vorbis') { - $elementMap['element_oga'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/mp4') { - $elementMap['element_m4a'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/wav') { - $elementMap['element_wav'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/x-wav') { - $elementMap['element_wav'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/x-flac') { - $elementMap['element_flac'] = $track['item_id']; - } else { + $mime = trim(strtolower($track['mime'])); + try { + $elementMap['element_' . FileDataHelper::getAudioMimeTypeArray()[$mime]] = $track['item_id']; + } catch (Exception $e) { throw new Exception("Unknown file type: $mime"); } @@ -288,22 +275,10 @@ class AudiopreviewController extends Zend_Controller_Action $elementMap['type'] = $track['type']; if ($track['type'] == 0) { - $mime = $track['mime']; - if (strtolower($mime) === 'audio/mp3') { - $elementMap['element_mp3'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/ogg') { - $elementMap['element_oga'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/vorbis') { - $elementMap['element_oga'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/mp4') { - $elementMap['element_m4a'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/wav') { - $elementMap['element_wav'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/x-wav') { - $elementMap['element_wav'] = $track['item_id']; - } elseif (strtolower($mime) === 'audio/x-flac') { - $elementMap['element_flac'] = $track['item_id']; - } else { + $mime = trim(strtolower($track['mime'])); + try { + $elementMap['element_' . FileDataHelper::getAudioMimeTypeArray()[$mime]] = $track['item_id']; + } catch (Exception $e) { throw new Exception("Unknown file type: $mime"); } diff --git a/airtime_mvc/application/controllers/EmbedController.php b/airtime_mvc/application/controllers/EmbedController.php index 88c5df3e6..8ba168dc3 100644 --- a/airtime_mvc/application/controllers/EmbedController.php +++ b/airtime_mvc/application/controllers/EmbedController.php @@ -84,7 +84,6 @@ class EmbedController extends Zend_Controller_Action $request = $this->getRequest(); - $widgetStyle = $request->getParam('style'); if ($widgetStyle == "premium") { $this->view->widgetStyle = "premium"; @@ -95,10 +94,9 @@ class EmbedController extends Zend_Controller_Action } $this->view->jquery = Application_Common_HTTPHelper::getStationUrl() . "widgets/js/jquery-1.6.1.min.js?".$CC_CONFIG['airtime_version']; - $weeklyScheduleData = WidgetHelper::getWeekInfoV2($this->getRequest()->getParam("timezone")); + $weeklyScheduleData = WidgetHelper::getWeekInfoV2(); - // Return only the current week's schedule data. In the future we may use the next week's data. - $this->view->weeklyScheduleData = ($weeklyScheduleData[0]); + $this->view->schedule_data = json_encode($weeklyScheduleData); $currentDay = new DateTime("now", new DateTimeZone(Application_Model_Preference::GetTimezone())); //day of the month without leading zeros (1 to 31) diff --git a/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.14/upgrade.sql b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.14/upgrade.sql new file mode 100644 index 000000000..3a5362ca1 --- /dev/null +++ b/airtime_mvc/application/controllers/upgrade_sql/airtime_2.5.14/upgrade.sql @@ -0,0 +1,4 @@ +ALTER TABLE cc_pref ALTER COLUMN subjid SET NULL; +ALTER TABLE cc_pref ALTER COLUMN subjid SET DEFAULT NULL; +CREATE UNIQUE INDEX cc_pref_key_idx ON cc_pref (keystr) WHERE subjid IS NULL; +ANALYZE cc_pref; \ No newline at end of file diff --git a/airtime_mvc/application/forms/AddShowLiveStream.php b/airtime_mvc/application/forms/AddShowLiveStream.php index 923c6993d..57066db0b 100644 --- a/airtime_mvc/application/forms/AddShowLiveStream.php +++ b/airtime_mvc/application/forms/AddShowLiveStream.php @@ -8,14 +8,13 @@ class Application_Form_AddShowLiveStream extends Zend_Form_SubForm { $cb_airtime_auth = new Zend_Form_Element_Checkbox("cb_airtime_auth"); $cb_airtime_auth->setLabel(sprintf(_("Use %s Authentication:"), PRODUCT_NAME)) - ->setRequired(false) - ->setDecorators(array('ViewHelper')); + ->setChecked(true) + ->setRequired(false); $this->addElement($cb_airtime_auth); $cb_custom_auth = new Zend_Form_Element_Checkbox("cb_custom_auth"); $cb_custom_auth ->setLabel(_("Use Custom Authentication:")) - ->setRequired(false) - ->setDecorators(array('ViewHelper')); + ->setRequired(false); $this->addElement($cb_custom_auth); //custom username @@ -26,8 +25,7 @@ class Application_Form_AddShowLiveStream extends Zend_Form_SubForm ->setLabel(_('Custom Username')) ->setFilters(array('StringTrim')) ->setValidators(array( - new ConditionalNotEmpty(array("cb_custom_auth"=>"1")))) - ->setDecorators(array('ViewHelper')); + new ConditionalNotEmpty(array("cb_custom_auth"=>"1")))); $this->addElement($custom_username); //custom password @@ -39,18 +37,34 @@ class Application_Form_AddShowLiveStream extends Zend_Form_SubForm ->setLabel(_('Custom Password')) ->setFilters(array('StringTrim')) ->setValidators(array( - new ConditionalNotEmpty(array("cb_custom_auth"=>"1")))) - ->setDecorators(array('ViewHelper')); + new ConditionalNotEmpty(array("cb_custom_auth"=>"1")))); $this->addElement($custom_password); - $connection_url = Application_Model_Preference::GetLiveDJSourceConnectionURL(); - if (trim($connection_url) == "") { - $connection_url = "N/A"; - } + $showSourceParams = parse_url(Application_Model_Preference::GetLiveDJSourceConnectionURL()); - $this->setDecorators(array( - array('ViewScript', array('viewScript' => 'form/add-show-live-stream.phtml', "connection_url"=>$connection_url)) - )); + // Show source connection url parameters + $showSourceHost = new Zend_Form_Element_Text('show_source_host'); + $showSourceHost->setAttrib('readonly', true) + ->setLabel(_('Host:')) + ->setValue(isset($showSourceParams["host"])?$showSourceParams["host"]:""); + $this->addElement($showSourceHost); + + $showSourcePort = new Zend_Form_Element_Text('show_source_port'); + $showSourcePort->setAttrib('readonly', true) + ->setLabel(_('Port:')) + ->setValue(isset($showSourceParams["port"])?$showSourceParams["port"]:""); + $this->addElement($showSourcePort); + + $showSourceMount = new Zend_Form_Element_Text('show_source_mount'); + $showSourceMount->setAttrib('readonly', true) + ->setLabel(_('Mount:')) + ->setValue(isset($showSourceParams["path"])?$showSourceParams["path"]:""); + $this->addElement($showSourceMount); + + $this->setDecorators( + array( + array('ViewScript', array('viewScript' => 'form/add-show-live-stream.phtml')) + )); } public function isValid($data) diff --git a/airtime_mvc/application/forms/LiveStreamingPreferences.php b/airtime_mvc/application/forms/LiveStreamingPreferences.php index 0391b45dc..6701902f7 100644 --- a/airtime_mvc/application/forms/LiveStreamingPreferences.php +++ b/airtime_mvc/application/forms/LiveStreamingPreferences.php @@ -11,38 +11,38 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm $defaultFade = Application_Model_Preference::GetDefaultTransitionFade(); + $this->setDecorators(array( + array('ViewScript', array('viewScript' => 'form/preferences_livestream.phtml')), + )); + // automatic trasition on source disconnection $auto_transition = new Zend_Form_Element_Checkbox("auto_transition"); - $auto_transition->setLabel(_("Auto Switch Off")) - ->setValue(Application_Model_Preference::GetAutoTransition()) - ->setDecorators(array('ViewHelper')); + $auto_transition->setLabel(_("Auto Switch Off:")) + ->setValue(Application_Model_Preference::GetAutoTransition()); $this->addElement($auto_transition); // automatic switch on upon source connection $auto_switch = new Zend_Form_Element_Checkbox("auto_switch"); - $auto_switch->setLabel(_("Auto Switch On")) - ->setValue(Application_Model_Preference::GetAutoSwitch()) - ->setDecorators(array('ViewHelper')); + $auto_switch->setLabel(_("Auto Switch On:")) + ->setValue(Application_Model_Preference::GetAutoSwitch()); $this->addElement($auto_switch); // Default transition fade $transition_fade = new Zend_Form_Element_Text("transition_fade"); - $transition_fade->setLabel(_("Switch Transition Fade (s)")) + $transition_fade->setLabel(_("Switch Transition Fade (s):")) ->setFilters(array('StringTrim')) ->addValidator('regex', false, array('/^\d*(\.\d+)?$/', 'messages' => _('Please enter a time in seconds (eg. 0.5)'))) - ->setValue($defaultFade) - ->setDecorators(array('ViewHelper')); + ->setValue($defaultFade); $this->addElement($transition_fade); //Master username $master_username = new Zend_Form_Element_Text('master_username'); $master_username->setAttrib('autocomplete', 'off') ->setAllowEmpty(true) - ->setLabel(_('Master Username')) + ->setLabel(_('Username:')) ->setFilters(array('StringTrim')) - ->setValue(Application_Model_Preference::GetLiveStreamMasterUsername()) - ->setDecorators(array('ViewHelper')); + ->setValue(Application_Model_Preference::GetLiveStreamMasterUsername()); $this->addElement($master_username); //Master password @@ -56,26 +56,51 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm ->setAttrib('renderPassword','true') ->setAllowEmpty(true) ->setValue(Application_Model_Preference::GetLiveStreamMasterPassword()) - ->setLabel(_('Master Password')) - ->setFilters(array('StringTrim')) - ->setDecorators(array('ViewHelper')); + ->setLabel(_('Password:')) + ->setFilters(array('StringTrim')); $this->addElement($master_password); - //Master source connection url - $master_dj_connection_url = new Zend_Form_Element_Text('master_dj_connection_url'); - $master_dj_connection_url->setAttrib('readonly', true) - ->setLabel(_('Master Source Connection URL')) - ->setValue(Application_Model_Preference::GetMasterDJSourceConnectionURL()) - ->setDecorators(array('ViewHelper')); - $this->addElement($master_dj_connection_url); + $masterSourceParams = parse_url(Application_Model_Preference::GetMasterDJSourceConnectionURL()); - //Show source connection url - $live_dj_connection_url = new Zend_Form_Element_Text('live_dj_connection_url'); - $live_dj_connection_url->setAttrib('readonly', true) - ->setLabel(_('Show Source Connection URL')) - ->setValue(Application_Model_Preference::GetLiveDJSourceConnectionURL()) - ->setDecorators(array('ViewHelper')); - $this->addElement($live_dj_connection_url); + // Master source connection url parameters + $masterSourceHost = new Zend_Form_Element_Text('master_source_host'); + $masterSourceHost->setAttrib('readonly', true) + ->setLabel(_('Host:')) + ->setValue(isset($masterSourceParams["host"])?$masterSourceParams["host"]:""); + $this->addElement($masterSourceHost); + + $masterSourcePort = new Zend_Form_Element_Text('master_source_port'); + $masterSourcePort->setAttrib('readonly', true) + ->setLabel(_('Port:')) + ->setValue(isset($masterSourceParams["port"])?$masterSourceParams["port"]:""); + $this->addElement($masterSourcePort); + + $masterSourceMount = new Zend_Form_Element_Text('master_source_mount'); + $masterSourceMount->setAttrib('readonly', true) + ->setLabel(_('Mount:')) + ->setValue(isset($masterSourceParams["path"])?$masterSourceParams["path"]:""); + $this->addElement($masterSourceMount); + + $showSourceParams = parse_url(Application_Model_Preference::GetLiveDJSourceConnectionURL()); + + // Show source connection url parameters + $showSourceHost = new Zend_Form_Element_Text('show_source_host'); + $showSourceHost->setAttrib('readonly', true) + ->setLabel(_('Host:')) + ->setValue(isset($showSourceParams["host"])?$showSourceParams["host"]:""); + $this->addElement($showSourceHost); + + $showSourcePort = new Zend_Form_Element_Text('show_source_port'); + $showSourcePort->setAttrib('readonly', true) + ->setLabel(_('Port:')) + ->setValue(isset($showSourceParams["port"])?$showSourceParams["port"]:""); + $this->addElement($showSourcePort); + + $showSourceMount = new Zend_Form_Element_Text('show_source_mount'); + $showSourceMount->setAttrib('readonly', true) + ->setLabel(_('Mount:')) + ->setValue(isset($showSourceParams["path"])?$showSourceParams["path"]:""); + $this->addElement($showSourceMount); // demo only code if (!$isStreamConfigable) { @@ -93,19 +118,30 @@ class Application_Form_LiveStreamingPreferences extends Zend_Form_SubForm $CC_CONFIG = Config::getConfig(); $isDemo = isset($CC_CONFIG['demo']) && $CC_CONFIG['demo'] == 1; - $master_dj_connection_url = Application_Model_Preference::GetMasterDJSourceConnectionURL(); - $live_dj_connection_url = Application_Model_Preference::GetLiveDJSourceConnectionURL(); + $masterSourceParams = parse_url(Application_Model_Preference::GetMasterDJSourceConnectionURL()); + $showSourceParams = parse_url(Application_Model_Preference::GetLiveDJSourceConnectionURL()); - $this->setDecorators(array( - array('ViewScript', array('viewScript' => 'form/preferences_livestream.phtml', 'master_dj_connection_url'=>$master_dj_connection_url, 'live_dj_connection_url'=>$live_dj_connection_url, 'isDemo' => $isDemo)) - )); + $this->setDecorators( + array ( + array ('ViewScript', + array ( + 'viewScript' => 'form/preferences_livestream.phtml', + 'master_source_host' => isset($masterSourceParams["host"])?$masterSourceParams["host"]:"", + 'master_source_port' => isset($masterSourceParams["port"])?$masterSourceParams["port"]:"", + 'master_source_mount' => isset($masterSourceParams["path"])?$masterSourceParams["path"]:"", + 'show_source_host' => isset($showSourceParams["host"])?$showSourceParams["host"]:"", + 'show_source_port' => isset($showSourceParams["port"])?$showSourceParams["port"]:"", + 'show_source_mount' => isset($showSourceParams["path"])?$showSourceParams["path"]:"", + 'isDemo' => $isDemo, + ) + ) + ) + ); } public function isValid($data) { - $isValid = parent::isValid($data); - - return $isValid; + return parent::isValid($data); } } diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index 736dbef98..5c1e7c889 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -163,9 +163,9 @@ class Application_Model_Preference $sql .= " AND subjid = :id"; $paramMap[':id'] = $userId; } - + $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, Application_Common_Database::COLUMN); - + //return an empty string if the result doesn't exist. if ($result == 0) { $res = ""; diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 58fe8a703..e975ccd8c 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -17,6 +17,7 @@ class Application_Model_StoredFile { /** * @holds propel database object + * @var CcFiles */ private $_file; @@ -467,48 +468,6 @@ SQL; $this->_file->save(); } - - public function getRealFileExtension() { - $path = $this->_file->getDbFilepath(); - $path_elements = explode('.', $path); - if (count($path_elements) < 2) { - return ""; - } else { - return $path_elements[count($path_elements) - 1]; - } - } - - /** - * Return suitable extension. - * - * @return string - * file extension without a dot - */ - public function getFileExtension() - { - $possible_ext = $this->getRealFileExtension(); - if ($possible_ext !== "") { - return $possible_ext; - } - - // We fallback to guessing the extension from the mimetype if we - // cannot extract it from the file name - - $mime = $this->_file->getDbMime(); - - if ($mime == "audio/ogg" || $mime == "application/ogg" || $mime == "audio/vorbis") { - return "ogg"; - } elseif ($mime == "audio/mp3" || $mime == "audio/mpeg") { - return "mp3"; - } elseif ($mime == "audio/x-flac") { - return "flac"; - } elseif ($mime == "audio/mp4") { - return "mp4"; - } else { - throw new Exception("Unknown $mime"); - } - } - /** * Get the absolute filepath * @@ -568,7 +527,7 @@ SQL; */ public function getRelativeFileUrl($baseUrl) { - return $baseUrl."api/get-media/file/".$this->getId().".".$this->getFileExtension(); + return $baseUrl."api/get-media/file/".$this->getId(); } public function getResourceId() diff --git a/airtime_mvc/application/models/airtime/CcFiles.php b/airtime_mvc/application/models/airtime/CcFiles.php index 16fb99c67..c574c9d7c 100644 --- a/airtime_mvc/application/models/airtime/CcFiles.php +++ b/airtime_mvc/application/models/airtime/CcFiles.php @@ -205,11 +205,6 @@ class CcFiles extends BaseCcFiles { $cloudFile->save(); Application_Model_Preference::updateDiskUsage($fileSizeBytes); - - $now = new DateTime("now", new DateTimeZone("UTC")); - $file->setDbMtime($now); - $file->save(); - } else if ($file) { // Since we check for this value when deleting files, set it first @@ -238,14 +233,13 @@ class CcFiles extends BaseCcFiles { $file->setDbFilepath($filePathRelativeToStor); } } - - $now = new DateTime("now", new DateTimeZone("UTC")); - $file->setDbMtime($now); - $file->save(); - } else { throw new FileNotFoundException(); } + + $now = new DateTime("now", new DateTimeZone("UTC")); + $file->setDbMtime($now); + $file->save(); } catch (FileNotFoundException $e) { @@ -356,17 +350,27 @@ class CcFiles extends BaseCcFiles { /** * * Strips out the private fields we do not want to send back in API responses - * @param $file string a CcFiles object + * + * @param CcFiles $file a CcFiles object + * + * @return array */ //TODO: rename this function? - public static function sanitizeResponse($file) - { + public static function sanitizeResponse($file) { $response = $file->toArray(BasePeer::TYPE_FIELDNAME); - + foreach (self::$privateFields as $key) { unset($response[$key]); } - + + $mime = $file->getDbMime(); + if (!empty($mime)) { + // Get an extension based on the file's mime type and change the path to use this extension + $path = pathinfo($file->getDbFilepath()); + $ext = FileDataHelper::getFileExtensionFromMime($mime); + $response["filepath"] = ($path["dirname"] . '/' . $path["filename"] . $ext); + } + return $response; } diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php index aa012eca6..bcd9c5093 100644 --- a/airtime_mvc/application/upgrade/Upgrades.php +++ b/airtime_mvc/application/upgrade/Upgrades.php @@ -455,3 +455,21 @@ class AirtimeUpgrader2513 extends AirtimeUpgrader return '2.5.13'; } } + +/** + * Class AirtimeUpgrader2514 + * + * SAAS-923 - Add a partial constraint to cc_pref so that keystrings must be unique + */ +class AirtimeUpgrader2514 extends AirtimeUpgrader +{ + protected function getSupportedSchemaVersions() { + return array ( + '2.5.13' + ); + } + + public function getNewVersion() { + return '2.5.14'; + } +} diff --git a/airtime_mvc/application/views/scripts/embed/weekly-program.phtml b/airtime_mvc/application/views/scripts/embed/weekly-program.phtml index 3420b7587..a7bb24e69 100644 --- a/airtime_mvc/application/views/scripts/embed/weekly-program.phtml +++ b/airtime_mvc/application/views/scripts/embed/weekly-program.phtml @@ -2,13 +2,20 @@ + - - +
- weeklyScheduleData as $day => $data) { - $activeClass = $this->currentDayOfMonth == $data["dayOfMonth"] ? "active" : ""; - - echo "
"; - if (count($data["shows"]) == 0) { - echo "
Looks like there are no shows scheduled on this day.
"; - } else { - foreach ($data["shows"] as $show => $showData) { - echo "
"; - echo "
" . $showData["show_start_hour"] . ' - ' . $showData["show_end_hour"] . "
"; - echo "
" . $showData["name"] . "
"; - echo "
"; - } - } - echo "
"; - }?> +
+
Looks like there are no shows scheduled on this day.
+
+
{{show.show_start_hour}} - {{show.show_end_hour}}
+
{{show.name}}
+
+