From d08f6cf3e17591faa34cae0ac7a3cf63017b436c Mon Sep 17 00:00:00 2001 From: denise Date: Thu, 21 Feb 2013 17:57:56 -0500 Subject: [PATCH] CC-4961: Show linking -initial schedule service experimentation --- .../controllers/ScheduleController.php | 20 +- .../controllers/_old_ScheduleController.php | 1002 +++++++++++++ airtime_mvc/application/models/Schedule.php | 36 +- .../application/models/_old_Schedule.php | 1329 +++++++++++++++++ .../application/services/ScheduleService.php | 90 ++ 5 files changed, 2458 insertions(+), 19 deletions(-) create mode 100644 airtime_mvc/application/controllers/_old_ScheduleController.php create mode 100644 airtime_mvc/application/models/_old_Schedule.php create mode 100644 airtime_mvc/application/services/ScheduleService.php diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php index 08fde37dc..9ca879918 100644 --- a/airtime_mvc/application/controllers/ScheduleController.php +++ b/airtime_mvc/application/controllers/ScheduleController.php @@ -5,6 +5,8 @@ class ScheduleController extends Zend_Controller_Action protected $sched_sess = null; + private $service_schedule; + public function init() { $ajaxContext = $this->_helper->getHelper('AjaxContext'); @@ -38,6 +40,8 @@ class ScheduleController extends Zend_Controller_Action ->initContext(); $this->sched_sess = new Zend_Session_Namespace("schedule"); + + $this->service_schedule = new Application_Service_ScheduleService(); } public function indexAction() @@ -90,13 +94,27 @@ class ScheduleController extends Zend_Controller_Action $this->view->headLink()->appendStylesheet($baseUrl.'css/showbuilder.css?'.$CC_CONFIG['airtime_version']); //End Show builder JS/CSS requirements + $forms = $this->service_schedule->createShowForms(); + // populate forms with default values + $this->service_schedule->populateNewShowForms( + $forms["what"], $forms["when"], $forms["repeats"]); + + $this->view->what = $forms["what"]; + $this->view->when = $forms["when"]; + $this->view->repeats = $forms["repeats"]; + $this->view->live = $forms["live"]; + $this->view->rr = $forms["record"]; + $this->view->absoluteRebroadcast = $forms["abs_record"]; + $this->view->rebroadcast = $forms["rebroadcast"]; + $this->view->who = $forms["who"]; + $this->view->style = $forms["style"]; - Application_Model_Schedule::createNewFormSections($this->view); $user = Application_Model_User::getCurrentUser(); if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { $this->view->preloadShowForm = true; } + $this->view->addNewShow = true; $this->view->headScript()->appendScript( "var calendarPref = {};\n". "calendarPref.weekStart = ".Application_Model_Preference::GetWeekStartDay().";\n". diff --git a/airtime_mvc/application/controllers/_old_ScheduleController.php b/airtime_mvc/application/controllers/_old_ScheduleController.php new file mode 100644 index 000000000..08fde37dc --- /dev/null +++ b/airtime_mvc/application/controllers/_old_ScheduleController.php @@ -0,0 +1,1002 @@ +_helper->getHelper('AjaxContext'); + $ajaxContext->addActionContext('event-feed', 'json') + ->addActionContext('event-feed-preload', 'json') + ->addActionContext('make-context-menu', 'json') + ->addActionContext('add-show-dialog', 'json') + ->addActionContext('add-show', 'json') + ->addActionContext('edit-show', 'json') + ->addActionContext('move-show', 'json') + ->addActionContext('resize-show', 'json') + ->addActionContext('delete-show', 'json') + ->addActionContext('show-content-dialog', 'json') + ->addActionContext('clear-show', 'json') + ->addActionContext('get-current-playlist', 'json') + ->addActionContext('remove-group', 'json') + ->addActionContext('populate-show-form', 'json') + ->addActionContext('populate-show-instance-form', 'json') + ->addActionContext('cancel-show', 'json') + ->addActionContext('cancel-current-show', 'json') + ->addActionContext('get-form', 'json') + ->addActionContext('upload-to-sound-cloud', 'json') + ->addActionContext('content-context-menu', 'json') + ->addActionContext('set-time-scale', 'json') + ->addActionContext('set-time-interval', 'json') + ->addActionContext('edit-show-instance', 'json') + ->addActionContext('dj-edit-show', 'json') + ->addActionContext('calculate-duration', 'json') + ->addActionContext('get-current-show', 'json') + ->addActionContext('update-future-is-scheduled', 'json') + ->initContext(); + + $this->sched_sess = new Zend_Session_Namespace("schedule"); + } + + public function indexAction() + { + $CC_CONFIG = Config::getConfig(); + + $baseUrl = Application_Common_OsPath::getBaseDir(); + + $this->view->headScript()->appendFile($baseUrl.'js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + //full-calendar-functions.js requires this variable, so that datePicker widget can be offset to server time instead of client time + $this->view->headScript()->appendScript("var timezoneOffset = ".date("Z")."; //in seconds"); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/schedule/full-calendar-functions.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + $this->view->headScript()->appendFile($baseUrl.'js/fullcalendar/fullcalendar.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/timepicker/jquery.ui.timepicker.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/colorpicker/js/colorpicker.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + $this->view->headScript()->appendFile($baseUrl.'js/airtime/schedule/add-show.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/schedule/schedule.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/blockui/jquery.blockUI.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + $this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.ui.timepicker.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/fullcalendar.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/colorpicker/css/colorpicker.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/add-show.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']); + + //Start Show builder JS/CSS requirements + $this->view->headScript()->appendFile($baseUrl.'js/contextmenu/jquery.contextMenu.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/js/jquery.dataTables.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.pluginAPI.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.fnSetFilteringDelay.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.TableTools.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); + + $this->view->headScript()->appendFile($baseUrl.'js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/events/library_showbuilder.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/library.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/showbuilder/builder.js?'.$CC_CONFIG['airtime_version'],'text/javascript'); + + $this->view->headLink()->appendStylesheet($baseUrl.'css/media_library.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.contextMenu.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/datatables/css/ColVis.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/datatables/css/ColReorder.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/TableTools.css?'.$CC_CONFIG['airtime_version']); + $this->view->headLink()->appendStylesheet($baseUrl.'css/showbuilder.css?'.$CC_CONFIG['airtime_version']); + //End Show builder JS/CSS requirements + + + Application_Model_Schedule::createNewFormSections($this->view); + $user = Application_Model_User::getCurrentUser(); + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + $this->view->preloadShowForm = true; + } + + $this->view->headScript()->appendScript( + "var calendarPref = {};\n". + "calendarPref.weekStart = ".Application_Model_Preference::GetWeekStartDay().";\n". + "calendarPref.timestamp = ".time().";\n". + "calendarPref.timezoneOffset = ".date("Z").";\n". + "calendarPref.timeScale = '".Application_Model_Preference::GetCalendarTimeScale()."';\n". + "calendarPref.timeInterval = ".Application_Model_Preference::GetCalendarTimeInterval().";\n". + "calendarPref.weekStartDay = ".Application_Model_Preference::GetWeekStartDay().";\n". + "var calendarEvents = null;" + ); + } + + 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); + $editable = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)); + + $events = &Application_Model_Show::getFullCalendarEvents($start, $end, $editable); + $this->view->events = $events; + } + + public function eventFeedPreloadAction() + { + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + $editable = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)); + + $calendar_interval = Application_Model_Preference::GetCalendarTimeScale(); + Logging::info($calendar_interval); + if ($calendar_interval == "agendaDay") { + list($start, $end) = Application_Model_Show::getStartEndCurrentDayView(); + } else if ($calendar_interval == "agendaWeek") { + list($start, $end) = Application_Model_Show::getStartEndCurrentWeekView(); + } else if ($calendar_interval == "month") { + list($start, $end) = Application_Model_Show::getStartEndCurrentMonthView(); + } else { + Logging::error("Invalid Calendar Interval '$calendar_interval'"); + } + + $events = &Application_Model_Show::getFullCalendarEvents($start, $end, $editable); + $this->view->events = $events; + } + + public function getCurrentShowAction() + { + $currentShow = Application_Model_Show::getCurrentShow(); + if (!empty($currentShow)) { + $this->view->si_id = $currentShow[0]["instance_id"]; + $this->view->current_show = true; + } else { + $this->view->current_show = false; + } + } + + public function moveShowAction() + { + $deltaDay = $this->_getParam('day'); + $deltaMin = $this->_getParam('min'); + $showInstanceId = $this->_getParam('showInstanceId'); + + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + try { + $showInstance = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + $error = $showInstance->moveShow($deltaDay, $deltaMin); + } + + if (isset($error)) { + $this->view->error = $error; + } + } + + public function resizeShowAction() + { + $deltaDay = $this->_getParam('day'); + $deltaMin = $this->_getParam('min'); + $showId = $this->_getParam('showId'); + + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + try { + $show = new Application_Model_Show($showId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + $error = $show->resizeShow($deltaDay, $deltaMin); + } + + if (isset($error)) { + $this->view->error = $error; + } + } + + public function deleteShowAction() + { + $showInstanceId = $this->_getParam('id'); + + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + + try { + $showInstance = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + Logging::info($e->getMessage()); + $this->view->show_error = true; + + return false; + } + + $showInstance->delete(); + + $this->view->show_id = $showInstance->getShowId(); + } + } + + public function uploadToSoundCloudAction() + { + $show_instance = $this->_getParam('id'); + try { + $show_inst = new Application_Model_ShowInstance($show_instance); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + + $file = $show_inst->getRecordedFile(); + $id = $file->getId(); + Application_Model_Soundcloud::uploadSoundcloud($id); + // we should die with ui info + $this->_helper->json->sendJson(null); + } + + public function makeContextMenuAction() + { + $id = $this->_getParam('id'); + $menu = array(); + $epochNow = time(); + $baseUrl = Application_Common_OsPath::getBaseDir(); + + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + try { + $instance = new Application_Model_ShowInstance($id); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + + $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)); + $isDJ = $user->isHostOfShow($instance->getShowId()); + + $showStartLocalDT = Application_Common_DateHelper::ConvertToLocalDateTime($instance->getShowInstanceStart()); + $showEndLocalDT = Application_Common_DateHelper::ConvertToLocalDateTime($instance->getShowInstanceEnd()); + + if ($instance->isRecorded() && $epochNow > $showEndLocalDT->getTimestamp()) { + + $file = $instance->getRecordedFile(); + $fileId = $file->getId(); + + $menu["view_recorded"] = array("name" => _("View Recorded File Metadata"), "icon" => "overview", + "url" => $baseUrl."library/edit-file-md/id/".$fileId); + } + + if ($epochNow < $showStartLocalDT->getTimestamp()) { + if ( ($isAdminOrPM || $isDJ) + && !$instance->isRecorded() + && !$instance->isRebroadcast()) { + + $menu["schedule"] = array("name"=> _("Add / Remove Content"), "icon" => "add-remove-content", + "url" => $baseUrl."showbuilder/builder-dialog/"); + + $menu["clear"] = array("name"=> _("Remove All Content"), "icon" => "remove-all-content", + "url" => $baseUrl."schedule/clear-show"); + } + } + + if (!$instance->isRecorded()) { + + $menu["content"] = array("name"=> _("Show Content"), "icon" => "overview", "url" => $baseUrl."schedule/show-content-dialog"); + } + + if ($showEndLocalDT->getTimestamp() <= $epochNow + && $instance->isRecorded() + && Application_Model_Preference::GetUploadToSoundcloudOption()) { + + $file = $instance->getRecordedFile(); + $fileId = $file->getId(); + $scid = $instance->getSoundCloudFileId(); + + if ($scid > 0) { + $url = $file->getSoundCloudLinkToFile(); + $menu["soundcloud_view"] = array("name" => _("View on Soundcloud"), "icon" => "soundcloud", "url" => $url); + } + + $text = is_null($scid) ? _('Upload to SoundCloud') : _('Re-upload to SoundCloud'); + $menu["soundcloud_upload"] = array("name"=> $text, "icon" => "soundcloud"); + } + + if ($showStartLocalDT->getTimestamp() <= $epochNow && + $epochNow < $showEndLocalDT->getTimestamp() && $isAdminOrPM) { + + if ($instance->isRecorded()) { + $menu["cancel_recorded"] = array("name"=> _("Cancel Current Show"), "icon" => "delete"); + } else { + + if (!$instance->isRebroadcast()) { + $menu["edit"] = array("name"=> _("Edit Show"), "icon" => "edit", "_type"=>"all", "url" => $baseUrl."Schedule/populate-show-form"); + } + + $menu["cancel"] = array("name"=> _("Cancel Current Show"), "icon" => "delete"); + } + } + + if ($epochNow < $showStartLocalDT->getTimestamp()) { + + if (!$instance->isRebroadcast() && $isAdminOrPM) { + $menu["edit"] = array("name"=> _("Edit Show"), "icon" => "edit", "_type"=>"all", "url" => $baseUrl."Schedule/populate-show-form"); + } + + if ($instance->getShow()->isRepeating() && $isAdminOrPM) { + + //create delete sub menu. + $menu["del"] = array("name"=> _("Delete"), "icon" => "delete", "items" => array()); + + $menu["del"]["items"]["single"] = array("name"=> _("Delete This Instance"), "icon" => "delete", "url" => $baseUrl."schedule/delete-show"); + + $menu["del"]["items"]["following"] = array("name"=> _("Delete This Instance and All Following"), "icon" => "delete", "url" => $baseUrl."schedule/cancel-show"); + } elseif ($isAdminOrPM) { + + $menu["del"] = array("name"=> _("Delete"), "icon" => "delete", "url" => $baseUrl."schedule/delete-show"); + } + } + + $this->view->items = $menu; + } + + public function clearShowAction() + { + $showInstanceId = $this->_getParam('id'); + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + try { + $show = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + + if($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)) || $user->isHostOfShow($show->getShowId())) + $show->clearShow(); + } + + public function getCurrentPlaylistAction() + { + $range = Application_Model_Schedule::GetPlayOrderRange(); + $show = Application_Model_Show::getCurrentShow(); + + /* Convert all UTC times to localtime before sending back to user. */ + if (isset($range["previous"])) { + $range["previous"]["starts"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["previous"]["starts"]); + $range["previous"]["ends"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["previous"]["ends"]); + } + if (isset($range["current"])) { + $range["current"]["starts"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["current"]["starts"]); + $range["current"]["ends"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["current"]["ends"]); + } + if (isset($range["next"])) { + $range["next"]["starts"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["next"]["starts"]); + $range["next"]["ends"] = Application_Common_DateHelper::ConvertToLocalDateTimeString($range["next"]["ends"]); + } + + Application_Model_Show::convertToLocalTimeZone($range["currentShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); + Application_Model_Show::convertToLocalTimeZone($range["nextShow"], array("starts", "ends", "start_timestamp", "end_timestamp")); + + $source_status = array(); + $switch_status = array(); + $live_dj = Application_Model_Preference::GetSourceStatus("live_dj"); + $master_dj = Application_Model_Preference::GetSourceStatus("master_dj"); + + $scheduled_play_switch = Application_Model_Preference::GetSourceSwitchStatus("scheduled_play"); + $live_dj_switch = Application_Model_Preference::GetSourceSwitchStatus("live_dj"); + $master_dj_switch = Application_Model_Preference::GetSourceSwitchStatus("master_dj"); + + //might not be the correct place to implement this but for now let's just do it here + $source_status['live_dj_source'] = $live_dj; + $source_status['master_dj_source'] = $master_dj; + $this->view->source_status = $source_status; + + $switch_status['live_dj_source'] = $live_dj_switch; + $switch_status['master_dj_source'] = $master_dj_switch; + $switch_status['scheduled_play'] = $scheduled_play_switch; + $this->view->switch_status = $switch_status; + + $this->view->entries = $range; + $this->view->show_name = isset($show[0])?$show[0]["name"]:""; + } + + public function removeGroupAction() + { + $showInstanceId = $this->sched_sess->showInstanceId; + $group_id = $this->_getParam('groupId'); + + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + try { + $show = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)) || $user->isHostOfShow($show->getShowId())) { + $show->removeGroupFromShow($group_id); + } + + $this->view->showContent = $show->getShowContent(); + $this->view->timeFilled = $show->getTimeScheduled(); + $this->view->percentFilled = $show->getPercentScheduled(); + $this->view->chosen = $this->view->render('schedule/scheduled-content.phtml'); + unset($this->view->showContent); + } + + public function showContentDialogAction() + { + $showInstanceId = $this->_getParam('id'); + try { + $show = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + + $originalShowId = $show->isRebroadcast(); + if (!is_null($originalShowId)) { + try { + $originalShow = new Application_Model_ShowInstance($originalShowId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + $originalShowName = $originalShow->getName(); + $originalShowStart = $originalShow->getShowInstanceStart(); + + //convert from UTC to user's timezone for display. + $originalDateTime = new DateTime($originalShowStart, new DateTimeZone("UTC")); + $originalDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); + //$timestamp = Application_Common_DateHelper::ConvertToLocalDateTimeString($originalDateTime->format("Y-m-d H:i:s")); + $this->view->additionalShowInfo = + sprintf(_("Rebroadcast of show %s from %s at %s"), + $originalShowName, + $originalDateTime->format("l, F jS"), + $originalDateTime->format("G:i")); + } + $this->view->showLength = $show->getShowLength(); + $this->view->timeFilled = $show->getTimeScheduled(); + $this->view->percentFilled = $show->getPercentScheduled(); + $this->view->showContent = $show->getShowListContent(); + $this->view->dialog = $this->view->render('schedule/show-content-dialog.phtml'); + $this->view->showTitle = htmlspecialchars($show->getName()); + unset($this->view->showContent); + } + + // we removed edit show instance option in menu item + // this feature is disabled in 2.1 and should be back in 2.2 + /*public function populateShowInstanceFormAction(){ + $formWhat = new Application_Form_AddShowWhat(); + $formWho = new Application_Form_AddShowWho(); + $formWhen = new Application_Form_AddShowWhen(); + $formRepeats = new Application_Form_AddShowRepeats(); + $formStyle = new Application_Form_AddShowStyle(); + $formLive = new Application_Form_AddShowLiveStream(); + + $formWhat->removeDecorator('DtDdWrapper'); + $formWho->removeDecorator('DtDdWrapper'); + $formWhen->removeDecorator('DtDdWrapper'); + $formRepeats->removeDecorator('DtDdWrapper'); + $formStyle->removeDecorator('DtDdWrapper'); + + $this->view->what = $formWhat; + $this->view->when = $formWhen; + $this->view->repeats = $formRepeats; + $this->view->who = $formWho; + $this->view->style = $formStyle; + $this->view->live = $formLive; + $this->view->addNewShow = false; + + $showInstanceId = $this->_getParam('id'); + + $show_instance = CcShowInstancesQuery::create()->findPK($showInstanceId); + $show = new Application_Model_Show($show_instance->getDbShowId()); + + $starts_string = $show_instance->getDbStarts(); + $ends_string = $show_instance->getDbEnds(); + + $starts_datetime = new DateTime($starts_string, new DateTimeZone("UTC")); + $ends_datetime = new DateTime($ends_string, new DateTimeZone("UTC")); + + $starts_datetime->setTimezone(new DateTimeZone(date_default_timezone_get())); + $ends_datetime->setTimezone(new DateTimeZone(date_default_timezone_get())); + + $instance_duration = $starts_datetime->diff($ends_datetime); + + $formWhat->populate(array('add_show_id' => $show->getId(), + 'add_show_instance_id' => $showInstanceId, + 'add_show_name' => $show->getName(), + 'add_show_url' => $show->getUrl(), + 'add_show_genre' => $show->getGenre(), + 'add_show_description' => $show->getDescription())); + + $formWhen->populate(array('add_show_start_date' => $starts_datetime->format("Y-m-d"), + 'add_show_start_time' => $starts_datetime->format("H:i"), + 'add_show_end_date_no_repeat' => $ends_datetime->format("Y-m-d"), + 'add_show_end_time' => $ends_datetime->format("H:i"), + 'add_show_duration' => $instance_duration->format("%h"))); + + $formWhat->disable(); + $formWho->disable(); + $formWhen->disableRepeatCheckbox(); + $formRepeats->disable(); + $formStyle->disable(); + + //$formRecord->disable(); + //$formAbsoluteRebroadcast->disable(); + //$formRebroadcast->disable(); + + $this->view->action = "edit-show-instance"; + $this->view->newForm = $this->view->render('schedule/add-show-form.phtml'); + }*/ + + public function populateShowFormAction() + { + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + + $showInstanceId = $this->_getParam('id'); + + $this->view->action = "edit-show"; + try { + $showInstance = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + + $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)); + $isDJ = $user->isHostOfShow($showInstance->getShowId()); + + if (!($isAdminOrPM || $isDJ)) { + return; + } + + // in case a user was once a dj and had been assigned to a show + // but was then changed to an admin user we need to allow + // the user to edit the show as an admin (CC-4925) + if ($isDJ && !$isAdminOrPM) { + $this->view->action = "dj-edit-show"; + } + + $formWhat = new Application_Form_AddShowWhat(); + $formWho = new Application_Form_AddShowWho(); + $formWhen = new Application_Form_AddShowWhen(); + $formRepeats = new Application_Form_AddShowRepeats(); + $formStyle = new Application_Form_AddShowStyle(); + $formLive = new Application_Form_AddShowLiveStream(); + + $formWhat->removeDecorator('DtDdWrapper'); + $formWho->removeDecorator('DtDdWrapper'); + $formWhen->removeDecorator('DtDdWrapper'); + $formRepeats->removeDecorator('DtDdWrapper'); + $formStyle->removeDecorator('DtDdWrapper'); + + $this->view->what = $formWhat; + $this->view->when = $formWhen; + $this->view->repeats = $formRepeats; + $this->view->who = $formWho; + $this->view->style = $formStyle; + $this->view->live = $formLive; + $this->view->addNewShow = false; + + $show = new Application_Model_Show($showInstance->getShowId()); + + $formWhat->populate(array('add_show_id' => $show->getId(), + 'add_show_instance_id' => $showInstanceId, + 'add_show_name' => $show->getName(), + 'add_show_url' => $show->getUrl(), + 'add_show_genre' => $show->getGenre(), + 'add_show_description' => $show->getDescription())); + + $startsDateTime = new DateTime($show->getStartDate()." ".$show->getStartTime(), new DateTimeZone("UTC")); + $endsDateTime = new DateTime($show->getEndDate()." ".$show->getEndTime(), new DateTimeZone("UTC")); + + $startsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); + $endsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); + + $formWhen->populate(array('add_show_start_date' => $startsDateTime->format("Y-m-d"), + 'add_show_start_time' => $startsDateTime->format("H:i"), + 'add_show_end_date_no_repeat' => $endsDateTime->format("Y-m-d"), + 'add_show_end_time' => $endsDateTime->format("H:i"), + 'add_show_duration' => $show->getDuration(true), + 'add_show_repeats' => $show->isRepeating() ? 1 : 0)); + + if ($show->isStartDateTimeInPast()) { + // for a non-repeating show, we should never allow user to change the start time. + // for the repeating show, we should allow because the form works as repeating template form + if (!$showInstance->getShow()->isRepeating()) { + $formWhen->disableStartDateAndTime(); + } else { + $nextFutureRepeatShow = $show->getNextFutureRepeatShowTime(); + $formWhen->getElement('add_show_start_date')->setValue($nextFutureRepeatShow["starts"]->format("Y-m-d")); + $formWhen->getElement('add_show_start_time')->setValue($nextFutureRepeatShow["starts"]->format("H:i")); + $formWhen->getElement('add_show_end_date_no_repeat')->setValue($nextFutureRepeatShow["ends"]->format("Y-m-d")); + $formWhen->getElement('add_show_end_time')->setValue($nextFutureRepeatShow["ends"]->format("H:i")); + } + } + + //need to get the days of the week in the php timezone (for the front end). + $days = array(); + $showDays = CcShowDaysQuery::create()->filterByDbShowId($showInstance->getShowId())->find(); + foreach ($showDays as $showDay) { + $showStartDay = new DateTime($showDay->getDbFirstShow(), new DateTimeZone($showDay->getDbTimezone())); + $showStartDay->setTimezone(new DateTimeZone(date_default_timezone_get())); + array_push($days, $showStartDay->format('w')); + } + + $displayedEndDate = new DateTime($show->getRepeatingEndDate(), new DateTimeZone($showDays[0]->getDbTimezone())); + $displayedEndDate->sub(new DateInterval("P1D"));//end dates are stored non-inclusively. + $displayedEndDate->setTimezone(new DateTimeZone(date_default_timezone_get())); + + $formRepeats->populate(array('add_show_repeat_type' => $show->getRepeatType(), + 'add_show_day_check' => $days, + 'add_show_end_date' => $displayedEndDate->format("Y-m-d"), + 'add_show_no_end' => ($show->getRepeatingEndDate() == ''))); + + $hosts = array(); + $showHosts = CcShowHostsQuery::create()->filterByDbShow($showInstance->getShowId())->find(); + foreach ($showHosts as $showHost) { + array_push($hosts, $showHost->getDbHost()); + } + $formWho->populate(array('add_show_hosts' => $hosts)); + $formStyle->populate(array('add_show_background_color' => $show->getBackgroundColor(), + 'add_show_color' => $show->getColor())); + + $formLive->populate($show->getLiveStreamInfo()); + + $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; + foreach ($rebroadcastsRelative as $rebroadcast) { + $rebroadcastFormValues["add_show_rebroadcast_date_$i"] = $rebroadcast['day_offset']; + $rebroadcastFormValues["add_show_rebroadcast_time_$i"] = Application_Common_DateHelper::removeSecondsFromTime($rebroadcast['start_time']); + $i++; + } + $formRebroadcast->populate($rebroadcastFormValues); + + $rebroadcastsAbsolute = $show->getRebroadcastsAbsolute(); + $rebroadcastAbsoluteFormValues = array(); + $i = 1; + foreach ($rebroadcastsAbsolute as $rebroadcast) { + $rebroadcastAbsoluteFormValues["add_show_rebroadcast_date_absolute_$i"] = $rebroadcast['start_date']; + $rebroadcastAbsoluteFormValues["add_show_rebroadcast_time_absolute_$i"] = $rebroadcast['start_time']; + $i++; + } + $formAbsoluteRebroadcast->populate($rebroadcastAbsoluteFormValues); + if (!$isAdminOrPM) { + $formRecord->disable(); + $formAbsoluteRebroadcast->disable(); + $formRebroadcast->disable(); + } + + if (!$isAdminOrPM) { + $formWhat->disable(); + $formWho->disable(); + $formWhen->disable(); + $formRepeats->disable(); + $formStyle->disable(); + } + + $this->view->newForm = $this->view->render('schedule/add-show-form.phtml'); + $this->view->entries = 5; + } + + public function getFormAction() + { + $user = Application_Model_User::getCurrentUser(); + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + Application_Model_Schedule::createNewFormSections($this->view); + $this->view->form = $this->view->render('schedule/add-show-form.phtml'); + } + } + + public function djEditShowAction() + { + $js = $this->_getParam('data'); + $data = array(); + + //need to convert from serialized jQuery array. + foreach ($js as $j) { + $data[$j["name"]] = $j["value"]; + } + + //update cc_show + $show = new Application_Model_Show($data["add_show_id"]); + $show->setAirtimeAuthFlag($data["cb_airtime_auth"]); + $show->setCustomAuthFlag($data["cb_custom_auth"]); + $show->setCustomUsername($data["custom_username"]); + $show->setCustomPassword($data["custom_password"]); + + $this->view->edit = true; + } + + /*public function editShowInstanceAction(){ + $js = $this->_getParam('data'); + $data = array(); + + //need to convert from serialized jQuery array. + foreach ($js as $j) { + $data[$j["name"]] = $j["value"]; + } + + $success = Application_Model_Schedule::updateShowInstance($data, $this); + if ($success) { + $this->view->addNewShow = true; + $this->view->newForm = $this->view->render('schedule/add-show-form.phtml'); + } else { + $this->view->addNewShow = false; + $this->view->form = $this->view->render('schedule/add-show-form.phtml'); + } + }*/ + + public function editShowAction() + { + //1) Get add_show_start_date since it might not have been sent + $js = $this->_getParam('data'); + $data = array(); + + //need to convert from serialized jQuery array. + foreach ($js as $j) { + $data[$j["name"]] = $j["value"]; + } + + $data['add_show_hosts'] = $this->_getParam('hosts'); + $data['add_show_day_check'] = $this->_getParam('days'); + + if ($data['add_show_day_check'] == "") { + $data['add_show_day_check'] = null; + } + + $show = new Application_Model_Show($data['add_show_id']); + + $validateStartDate = true; + $validateStartTime = true; + if (!array_key_exists('add_show_start_date', $data)) { + //Changing the start date was disabled, since the + //array key does not exist. We need to repopulate this entry from the db. + //The start date will be returned in UTC time, so lets convert it to local time. + $dt = Application_Common_DateHelper::ConvertToLocalDateTime($show->getStartDateAndTime()); + $data['add_show_start_date'] = $dt->format("Y-m-d"); + + if (!array_key_exists('add_show_start_time', $data)) { + $data['add_show_start_time'] = $dt->format("H:i"); + $validateStartTime = false; + } + $validateStartDate = false; + } + $data['add_show_record'] = $show->isRecorded(); + + if ($show->isRepeating()) { + $nextFutureRepeatShow = $show->getNextFutureRepeatShowTime(); + $originalShowStartDateTime = $nextFutureRepeatShow["starts"]; + } else { + $originalShowStartDateTime = Application_Common_DateHelper::ConvertToLocalDateTime( + $show->getStartDateAndTime()); + } + + $success = Application_Model_Schedule::addUpdateShow($data, $this, + $validateStartDate, $originalShowStartDateTime, true, + $data['add_show_instance_id']); + + if ($success) { + $scheduler = new Application_Model_Scheduler(); + $showInstances = CcShowInstancesQuery::create()->filterByDbShowId($data['add_show_id'])->find(); + foreach ($showInstances as $si) { + $scheduler->removeGaps($si->getDbId()); + } + $this->view->addNewShow = true; + $this->view->newForm = $this->view->render('schedule/add-show-form.phtml'); + } else { + if (!$validateStartDate) { + $this->view->when->getElement('add_show_start_date')->setOptions(array('disabled' => true)); + } + if (!$validateStartTime) { + $this->view->when->getElement('add_show_start_time')->setOptions(array('disabled' => true)); + } + $this->view->rr->getElement('add_show_record')->setOptions(array('disabled' => true)); + $this->view->addNewShow = false; + $this->view->action = "edit-show"; + $this->view->form = $this->view->render('schedule/add-show-form.phtml'); + } + } + + public function addShowAction() + { + $js = $this->_getParam('data'); + $data = array(); + + //need to convert from serialized jQuery array. + foreach ($js as $j) { + $data[$j["name"]] = $j["value"]; + } + + $data['add_show_hosts'] = $this->_getParam('hosts'); + $data['add_show_day_check'] = $this->_getParam('days'); + + if ($data['add_show_day_check'] == "") { + $data['add_show_day_check'] = null; + } + + $validateStartDate = true; + $success = Application_Model_Schedule::addUpdateShow($data, $this, + $validateStartDate); + + if ($success) { + $this->view->addNewShow = true; + $this->view->newForm = $this->view->render( + 'schedule/add-show-form.phtml'); + Logging::debug("Show creation succeeded"); + } else { + $this->view->addNewShow = true; + $this->view->form = $this->view->render( + 'schedule/add-show-form.phtml'); + Logging::debug("Show creation failed"); + } + } + + public function cancelShowAction() + { + $user = Application_Model_User::getCurrentUser(); + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + $showInstanceId = $this->_getParam('id'); + + try { + $showInstance = new Application_Model_ShowInstance($showInstanceId); + } catch (Exception $e) { + $this->view->show_error = true; + + return false; + } + $show = new Application_Model_Show($showInstance->getShowId()); + + $show->cancelShow($showInstance->getShowInstanceStart()); + $this->view->show_id = $showInstance->getShowId(); + } + } + + public function cancelCurrentShowAction() + { + $user = Application_Model_User::getCurrentUser(); + + if ($user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER))) { + $id = $this->_getParam('id'); + + try { + $scheduler = new Application_Model_Scheduler(); + $scheduler->cancelShow($id); + Application_Model_StoredFile::updatePastFilesIsScheduled(); + // send kick out source stream signal to pypo + $data = array("sourcename"=>"live_dj"); + Application_Model_RabbitMq::SendMessageToPypo("disconnect_source", $data); + } catch (Exception $e) { + $this->view->error = $e->getMessage(); + Logging::info($e->getMessage()); + } + } + } + + public function contentContextMenuAction() + { + $id = $this->_getParam('id'); + + $params = '/format/json/id/#id#/'; + + $paramsPop = str_replace('#id#', $id, $params); + + // added for downlaod + $id = $this->_getParam('id'); + + $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), + 'title' => _('Download')); + + //returns format jjmenu is looking for. + $this->_helper->json->sendJson($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. + */ + 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. + */ + public function setTimeIntervalAction() + { + Application_Model_Preference::SetCalendarTimeInterval($this->_getParam('timeInterval')); + } + + public function calculateDurationAction() + { + $startParam = $this->_getParam('startTime'); + $endParam = $this->_getParam('endTime'); + + try { + $startDateTime = new DateTime($startParam); + $endDateTime = new DateTime($endParam); + + $UTCStartDateTime = $startDateTime->setTimezone(new DateTimeZone('UTC')); + $UTCEndDateTime = $endDateTime->setTimezone(new DateTimeZone('UTC')); + + $duration = $UTCEndDateTime->diff($UTCStartDateTime); + + $day = intval($duration->format('%d')); + if ($day > 0) { + $hour = intval($duration->format('%h')); + $min = intval($duration->format('%i')); + $hour += $day * 24; + $hour = min($hour, 99); + $sign = $duration->format('%r'); + $result = sprintf('%s%02dh %02dm', $sign, $hour, $min); + } else { + $result = $duration->format('%r%Hh %Im'); + } + } catch (Exception $e) { + $result = "Invalid Date"; + } + + echo Zend_Json::encode($result); + exit(); + } + + public function updateFutureIsScheduledAction() + { + $schedId = $this->_getParam('schedId'); + $redrawLibTable = Application_Model_StoredFile::setIsScheduled($schedId, false); + $this->_helper->json->sendJson(array("redrawLibTable" => $redrawLibTable)); + } +} diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index 1aac2566e..2778074d2 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -960,7 +960,7 @@ SQL; Application_Common_Database::prepareAndExecute($sql, array(':file_id'=>$fileId), 'execute'); } - public static function createNewFormSections($p_view) + /*public static function createNewFormSections($p_view) { $formWhat = new Application_Form_AddShowWhat(); $formWho = new Application_Form_AddShowWho(); @@ -1005,7 +1005,7 @@ SQL; $p_view->absoluteRebroadcast = $formAbsoluteRebroadcast; $p_view->rebroadcast = $formRebroadcast; $p_view->addNewShow = true; - } + }*/ /* This function is responsible for handling the case where an individual * show instance in a repeating show was edited (via the context menu in the Calendar). @@ -1140,13 +1140,13 @@ SQL; $data["add_show_duration"] = $hValue.":".$mValue; - $formRecord = new Application_Form_AddShowRR(); - $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); - $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); + $formRecord = new Application_Form_AddShowRR(); + $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); + $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); - $formRecord->removeDecorator('DtDdWrapper'); - $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); - $formRebroadcast->removeDecorator('DtDdWrapper'); + $formRecord->removeDecorator('DtDdWrapper'); + $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); + $formRebroadcast->removeDecorator('DtDdWrapper'); $record = $formRecord->isValid($data); @@ -1156,18 +1156,18 @@ SQL; if ($repeats) { $repeats = $formRepeats->checkReliantFields($data); } - $formAbsoluteRebroadcast->reset(); - //make it valid, results don't matter anyways. - $rebroadAb = 1; + $formAbsoluteRebroadcast->reset(); + //make it valid, results don't matter anyways. + $rebroadAb = 1; - if ($data["add_show_rebroadcast"]) { - $rebroad = $formRebroadcast->isValid($data); - if ($rebroad) { - $rebroad = $formRebroadcast->checkReliantFields($data); - } - } else { - $rebroad = 1; + if ($data["add_show_rebroadcast"]) { + $rebroad = $formRebroadcast->isValid($data); + if ($rebroad) { + $rebroad = $formRebroadcast->checkReliantFields($data); } + } else { + $rebroad = 1; + } } else { $repeats = 1; $formRebroadcast->reset(); diff --git a/airtime_mvc/application/models/_old_Schedule.php b/airtime_mvc/application/models/_old_Schedule.php new file mode 100644 index 000000000..1aac2566e --- /dev/null +++ b/airtime_mvc/application/models/_old_Schedule.php @@ -0,0 +1,1329 @@ + NOW() AT TIME ZONE 'UTC' +SQL; + $count = Application_Common_Database::prepareAndExecute( $sql, array( + ':file_id'=>$p_fileId), 'column'); + return (is_numeric($count) && ($count != '0')); + } + + public static function getAllFutureScheduledFiles() + { + $con = Propel::getConnection(); + $sql = << now() AT TIME ZONE 'UTC' +AND file_id is not null +SQL; + $files = $con->query($sql)->fetchAll(); + $real_files = array(); + foreach ($files as $f) { + $real_files[] = $f['file_id']; + } + + return $real_files; + } + + public static function getAllFutureScheduledWebstreams() + { + $con = Propel::getConnection(); + $sql = << now() AT TIME ZONE 'UTC' +AND stream_id is not null +SQL; + $streams = $con->query($sql)->fetchAll(); + $real_streams = array(); + foreach ($streams as $s) { + $real_streams[] = $s['stream_id']; + } + + return $real_streams; + } + /** + * Returns data related to the scheduled items. + * + * @param int $p_prev + * @param int $p_next + * @return date + */ + public static function GetPlayOrderRange($p_prev = 1, $p_next = 1) + { + if (!is_int($p_prev) || !is_int($p_next)) { + //must enter integers to specify ranges + Logging::info("Invalid range parameters: $p_prev or $p_next"); + + return array(); + } + + $date = new Application_Common_DateHelper; + $timeNow = $date->getTimestamp(); + $utcTimeNow = $date->getUtcTimestamp(); + + $shows = Application_Model_Show::getPrevCurrentNext($utcTimeNow); + $previousShowID = count($shows['previousShow'])>0?$shows['previousShow'][0]['instance_id']:null; + $currentShowID = count($shows['currentShow'])>0?$shows['currentShow'][0]['instance_id']:null; + $nextShowID = count($shows['nextShow'])>0?$shows['nextShow'][0]['instance_id']:null; + $results = self::GetPrevCurrentNext($previousShowID, $currentShowID, $nextShowID, $utcTimeNow); + + $range = array("env"=>APPLICATION_ENV, + "schedulerTime"=>$timeNow, + "previous"=>$results['previous'] !=null?$results['previous']:(count($shows['previousShow'])>0?$shows['previousShow'][0]:null), + "current"=>$results['current'] !=null?$results['current']:((count($shows['currentShow'])>0 && $shows['currentShow'][0]['record'] == 1)?$shows['currentShow'][0]:null), + "next"=> $results['next'] !=null?$results['next']:(count($shows['nextShow'])>0?$shows['nextShow'][0]:null), + "currentShow"=>$shows['currentShow'], + "nextShow"=>$shows['nextShow'], + "timezone"=> date("T"), + "timezoneOffset"=> date("Z") + ); + + return $range; + } + + /** + * Queries the database for the set of schedules one hour before + * and after the given time. If a show starts and ends within that + * time that is considered the current show. Then the scheduled item + * before it is the previous show, and the scheduled item after it + * is the next show. This way the dashboard getCurrentPlaylist is + * very fast. But if any one of the three show types are not found + * through this mechanism a call is made to the old way of querying + * the database to find the track info. + **/ + public static function GetPrevCurrentNext($p_previousShowID, $p_currentShowID, $p_nextShowID, $p_timeNow) + { + if ($p_previousShowID == null && $p_currentShowID == null && $p_nextShowID == null) { + return; + } + + $sql = "SELECT %%columns%% st.starts as starts, st.ends as ends, + st.media_item_played as media_item_played, si.ends as show_ends + %%tables%% WHERE "; + + $fileColumns = "ft.artist_name, ft.track_title, "; + $fileJoin = "FROM cc_schedule st JOIN cc_files ft ON st.file_id = ft.id + LEFT JOIN cc_show_instances si ON st.instance_id = si.id"; + + $streamColumns = "ws.name AS artist_name, wm.liquidsoap_data AS track_title, "; + $streamJoin = << $rows[$i]["show_ends"]) { + $rows[$i]['ends'] = $rows[$i]["show_ends"]; + } + + if ((strtotime($rows[$i]['starts']) <= $timeNowAsMillis) && (strtotime($rows[$i]['ends']) >= $timeNowAsMillis)) { + if ($i - 1 >= 0) { + $results['previous'] = array("name"=>$rows[$i-1]["artist_name"]." - ".$rows[$i-1]["track_title"], + "starts"=>$rows[$i-1]["starts"], + "ends"=>$rows[$i-1]["ends"], + "type"=>'track'); + } + $results['current'] = array("name"=>$rows[$i]["artist_name"]." - ".$rows[$i]["track_title"], + "starts"=>$rows[$i]["starts"], + "ends"=> (($rows[$i]["ends"] > $rows[$i]["show_ends"]) ? $rows[$i]["show_ends"]: $rows[$i]["ends"]), + "media_item_played"=>$rows[$i]["media_item_played"], + "record"=>0, + "type"=>'track'); + if (isset($rows[$i+1])) { + $results['next'] = array("name"=>$rows[$i+1]["artist_name"]." - ".$rows[$i+1]["track_title"], + "starts"=>$rows[$i+1]["starts"], + "ends"=>$rows[$i+1]["ends"], + "type"=>'track'); + } + break; + } + if (strtotime($rows[$i]['ends']) < $timeNowAsMillis ) { + $previousIndex = $i; + } + if (strtotime($rows[$i]['starts']) > $timeNowAsMillis) { + $results['next'] = array("name"=>$rows[$i]["artist_name"]." - ".$rows[$i]["track_title"], + "starts"=>$rows[$i]["starts"], + "ends"=>$rows[$i]["ends"], + "type"=>'track'); + break; + } + } + //If we didn't find a a current show because the time didn't fit we may still have + //found a previous show so use it. + if ($results['previous'] === null && isset($previousIndex)) { + $results['previous'] = array("name"=>$rows[$previousIndex]["artist_name"]." - ".$rows[$previousIndex]["track_title"], + "starts"=>$rows[$previousIndex]["starts"], + "ends"=>$rows[$previousIndex]["ends"]);; + } + + return $results; + } + + public static function GetLastScheduleItem($p_timeNow) + { + $sql = <<= sit.starts + AND st.starts < sit.ends +ORDER BY st.ends DESC LIMIT 1; +SQL; + $row = Application_Common_Database::prepareAndExecute($sql, array(':timeNow'=>$p_timeNow)); + + return $row; + } + + public static function GetCurrentScheduleItem($p_timeNow, $p_instanceId) + { + /* Note that usually there will be one result returned. In some + * rare cases two songs are returned. This happens when a track + * that was overbooked from a previous show appears as if it + * hasnt ended yet (track end time hasn't been reached yet). For + * this reason, we need to get the track that starts later, as + * this is the *real* track that is currently playing. So this + * is why we are ordering by track start time. */ + $sql = "SELECT *" + ." FROM cc_schedule st" + ." LEFT JOIN cc_files ft" + ." ON st.file_id = ft.id" + ." WHERE st.starts <= TIMESTAMP :timeNow1" + ." AND st.instance_id = :instanceId" + ." AND st.ends > TIMESTAMP :timeNow2" + ." ORDER BY st.starts DESC" + ." LIMIT 1"; + + $row = Application_Common_Database::prepareAndExecute($sql, array(':timeNow1'=>$p_timeNow, ':instanceId'=>$p_instanceId, ':timeNow2'=>$p_timeNow,)); + + return $row; + } + + public static function GetNextScheduleItem($p_timeNow) + { + $sql = "SELECT" + ." ft.artist_name, ft.track_title," + ." st.starts as starts, st.ends as ends" + ." FROM cc_schedule st" + ." LEFT JOIN cc_files ft" + ." ON st.file_id = ft.id" + ." LEFT JOIN cc_show_instances sit" + ." ON st.instance_id = sit.id" + ." WHERE st.starts > TIMESTAMP :timeNow" + ." AND st.starts >= sit.starts" //this and the next line are necessary since we can overbook shows. + ." AND st.starts < sit.ends" + ." ORDER BY st.starts" + ." LIMIT 1"; + + $row = Application_Common_Database::prepareAndExecute($sql, array(':timeNow'=>$p_timeNow)); + + return $row; + } + + /* + * + * @param DateTime $p_startDateTime + * + * @param DateTime $p_endDateTime + * + * @return array $scheduledItems + * + */ + public static function GetScheduleDetailItems($p_start, $p_end, $p_shows) + { + $con = Propel::getConnection(); + + $p_start_str = $p_start->format("Y-m-d H:i:s"); + $p_end_str = $p_end->format("Y-m-d H:i:s"); + + + //We need to search 24 hours before and after the show times so that that we + //capture all of the show's contents. + $p_track_start= $p_start->sub(new DateInterval("PT24H"))->format("Y-m-d H:i:s"); + $p_track_end = $p_end->add(new DateInterval("PT24H"))->format("Y-m-d H:i:s"); + + $templateSql = <<= '{$p_track_start}' + AND sched.starts < '{$p_track_end}') + OR (sched.ends > '{$p_track_start}' + AND sched.ends <= '{$p_track_end}') + OR (sched.starts <= '{$p_track_start}' + AND sched.ends >= '{$p_track_end}')) + ) +SQL; + + + $filesSql = str_replace("%%columns%%", + $filesColumns, + $templateSql); + $filesSql= str_replace("%%join%%", + $filesJoin, + $filesSql); + + $streamColumns = <<= '{$p_track_start}' + AND sched.starts < '{$p_track_end}') + OR (sched.ends > '{$p_track_start}' + AND sched.ends <= '{$p_track_end}') + OR (sched.starts <= '{$p_track_start}' + AND sched.ends >= '{$p_track_end}')) + ) + LEFT JOIN cc_subjs AS sub ON (ws.creator_id = sub.id) +SQL; + + $streamSql = str_replace("%%columns%%", + $streamColumns, + $templateSql); + $streamSql = str_replace("%%join%%", + $streamJoin, + $streamSql); + + + $showPredicate = ""; + if (count($p_shows) > 0) { + $showPredicate = " AND show_id IN (".implode(",", $p_shows).")"; + } + + $sql = <<= '{$p_start_str}' + AND si.starts < '{$p_end_str}') + OR (si.ends > '{$p_start_str}' + AND si.ends <= '{$p_end_str}') + OR (si.starts <= '{$p_start_str}' + AND si.ends >= '{$p_end_str}')) +ORDER BY si_starts, + sched_starts; +SQL; + + $rows = $con->query($sql)->fetchAll(PDO::FETCH_ASSOC); + + return $rows; + } + + public static function UpdateMediaPlayedStatus($p_id) + { + $con = Propel::getConnection(); + $sql = "UPDATE cc_schedule" + ." SET media_item_played=TRUE"; + // we need to update 'broadcasted' column as well + // check the current switch status + $live_dj = Application_Model_Preference::GetSourceSwitchStatus('live_dj') == 'on'; + $master_dj = Application_Model_Preference::GetSourceSwitchStatus('master_dj') == 'on'; + $scheduled_play = Application_Model_Preference::GetSourceSwitchStatus('scheduled_play') == 'on'; + + if (!$live_dj && !$master_dj && $scheduled_play) { + $sql .= ", broadcasted=1"; + } + + $sql .= " WHERE id=$p_id"; + + $retVal = $con->exec($sql); + + return $retVal; + } + + public static function UpdateBrodcastedStatus($dateTime, $value) + { + $now = $dateTime->format("Y-m-d H:i:s"); + + $sql = <<= :ends::TIMESTAMP +SQL; + + $retVal = Application_Common_Database::prepareAndExecute($sql, array( + ':broadcastedValue' => $value, + ':starts' => $now, + ':ends' => $now), 'execute'); + return $retVal; + } + + public static function getSchduledPlaylistCount() + { + $con = Propel::getConnection(); + $sql = "SELECT count(*) as cnt FROM cc_schedule"; + + return $con->query($sql)->fetchColumn(0); + } + + /** + * Convert a time string in the format "YYYY-MM-DD HH:mm:SS" + * to "YYYY-MM-DD-HH-mm-SS". + * + * @param string $p_time + * @return string + */ + private static function AirtimeTimeToPypoTime($p_time) + { + $p_time = substr($p_time, 0, 19); + $p_time = str_replace(" ", "-", $p_time); + $p_time = str_replace(":", "-", $p_time); + + return $p_time; + } + + /** + * Convert a time string in the format "YYYY-MM-DD-HH-mm-SS" to + * "YYYY-MM-DD HH:mm:SS". + * + * @param string $p_time + * @return string + */ + private static function PypoTimeToAirtimeTime($p_time) + { + $t = explode("-", $p_time); + + return $t[0]."-".$t[1]."-".$t[2]." ".$t[3].":".$t[4].":00"; + } + + /** + * Return true if the input string is in the format YYYY-MM-DD-HH-mm + * + * @param string $p_time + * @return boolean + */ + public static function ValidPypoTimeFormat($p_time) + { + $t = explode("-", $p_time); + if (count($t) != 5) { + return false; + } + foreach ($t as $part) { + if (!is_numeric($part)) { + return false; + } + } + + return true; + } + + /** + * Converts a time value as a string (with format HH:MM:SS.mmmmmm) to + * millisecs. + * + * @param string $p_time + * @return int + */ + public static function WallTimeToMillisecs($p_time) + { + $t = explode(":", $p_time); + $millisecs = 0; + if (strpos($t[2], ".")) { + $secParts = explode(".", $t[2]); + $millisecs = $secParts[1]; + $millisecs = str_pad(substr($millisecs, 0, 3),3, '0'); + $millisecs = intval($millisecs); + $seconds = intval($secParts[0]); + } else { + $seconds = intval($t[2]); + } + $ret = $millisecs + ($seconds * 1000) + ($t[1] * 60 * 1000) + ($t[0] * 60 * 60 * 1000); + + return $ret; + } + + /** + * Compute the difference between two times in the format . + * "HH:MM:SS.mmmmmm" Note: currently only supports calculating . + * millisec differences . + * + * @param string $p_time1 + * @param string $p_time2 + * @return double + */ + private static function TimeDiff($p_time1, $p_time2) + { + $parts1 = explode(".", $p_time1); + $parts2 = explode(".", $p_time2); + $diff = 0; + if ( (count($parts1) > 1) && (count($parts2) > 1) ) { + $millisec1 = substr($parts1[1], 0, 3); + $millisec1 = str_pad($millisec1, 3, "0"); + $millisec1 = intval($millisec1); + $millisec2 = substr($parts2[1], 0, 3); + $millisec2 = str_pad($millisec2, 3, "0"); + $millisec2 = intval($millisec2); + $diff = abs($millisec1 - $millisec2)/1000; + } + + return $diff; + } + + /** + * Returns an array of schedule items from cc_schedule table. Tries + * to return at least 3 items (if they are available). The parameters + * $p_startTime and $p_endTime specify the range. Schedule items returned + * do not have to be entirely within this range. It is enough that the end + * or beginning of the scheduled item is in the range. + * + * + * @param string $p_startTime + * In the format YYYY-MM-DD HH:MM:SS.nnnnnn + * @param string $p_endTime + * In the format YYYY-MM-DD HH:MM:SS.nnnnnn + * @return array + * Returns null if nothing found, else an array of associative + * arrays representing each row. + */ + public static function getItems($p_startTime, $p_endTime) + { + $baseQuery = << :startTime1 + AND st.starts < :endTime + AND st.playout_status > 0 + AND si.ends > :startTime2 + AND si.modified_instance = 'f' +ORDER BY st.starts +SQL; + + $sql = $baseQuery." ".$predicates; + + $rows = Application_Common_Database::prepareAndExecute($sql, array( + ':startTime1' => $p_startTime, + ':endTime' => $p_endTime, + ':startTime2' => $p_startTime)); + + if (count($rows) < 3) { + $dt = new DateTime("@".time()); + $dt->add(new DateInterval("PT24H")); + $range_end = $dt->format("Y-m-d H:i:s"); + + $predicates = << :startTime1 + AND st.starts < :rangeEnd + AND st.playout_status > 0 + AND si.ends > :startTime2 + AND si.modified_instance = 'f' +ORDER BY st.starts LIMIT 3 +SQL; + + $sql = $baseQuery." ".$predicates." "; + $rows = Application_Common_Database::prepareAndExecute($sql, + array( + ':startTime1' => $p_startTime, + ':rangeEnd' => $range_end, + ':startTime2' => $p_startTime)); + } + + return $rows; + } + + /** + * This function will ensure that an existing index in the + * associative array is never overwritten, instead appending + * _0, _1, _2, ... to the end of the key to make sure it is unique + */ + private static function appendScheduleItem(&$data, $time, $item) + { + $key = $time; + $i = 0; + + while (array_key_exists($key, $data["media"])) { + $key = "{$time}_{$i}"; + $i++; + } + + $data["media"][$key] = $item; + } + + private static function createInputHarborKickTimes(&$data, $range_start, $range_end) + { + $utcTimeZone = new DateTimeZone("UTC"); + $kick_times = Application_Model_ShowInstance::GetEndTimeOfNextShowWithLiveDJ($range_start, $range_end); + foreach ($kick_times as $kick_time_info) { + $kick_time = $kick_time_info['ends']; + $temp = explode('.', Application_Model_Preference::GetDefaultTransitionFade()); + // we round down transition time since PHP cannot handle millisecond. We need to + // handle this better in the future + $transition_time = intval($temp[0]); + $switchOffDataTime = new DateTime($kick_time, $utcTimeZone); + $switch_off_time = $switchOffDataTime->sub(new DateInterval('PT'.$transition_time.'S')); + $switch_off_time = $switch_off_time->format("Y-m-d H:i:s"); + + $kick_start = self::AirtimeTimeToPypoTime($kick_time); + $data["media"][$kick_start]['start'] = $kick_start; + $data["media"][$kick_start]['end'] = $kick_start; + $data["media"][$kick_start]['event_type'] = "kick_out"; + $data["media"][$kick_start]['type'] = "event"; + $data["media"][$kick_start]['independent_event'] = true; + + if ($kick_time !== $switch_off_time) { + $switch_start = self::AirtimeTimeToPypoTime($switch_off_time); + $data["media"][$switch_start]['start'] = $switch_start; + $data["media"][$switch_start]['end'] = $switch_start; + $data["media"][$switch_start]['event_type'] = "switch_off"; + $data["media"][$switch_start]['type'] = "event"; + $data["media"][$switch_start]['independent_event'] = true; + } + } + } + + private static function createFileScheduleEvent(&$data, $item, $media_id, $uri) + { + $start = self::AirtimeTimeToPypoTime($item["start"]); + $end = self::AirtimeTimeToPypoTime($item["end"]); + + list(,,,$start_hour,,) = explode("-", $start); + list(,,,$end_hour,,) = explode("-", $end); + + $same_hour = $start_hour == $end_hour; + $independent_event = !$same_hour; + + $replay_gain = is_null($item["replay_gain"]) ? "0": $item["replay_gain"]; + $replay_gain += Application_Model_Preference::getReplayGainModifier(); + + if ( !Application_Model_Preference::GetEnableReplayGain() ) { + $replay_gain = 0; + } + + $schedule_item = array( + 'id' => $media_id, + 'type' => 'file', + 'row_id' => $item["id"], + 'uri' => $uri, + 'fade_in' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_in"]), + 'fade_out' => Application_Model_Schedule::WallTimeToMillisecs($item["fade_out"]), + 'cue_in' => Application_Common_DateHelper::CalculateLengthInSeconds($item["cue_in"]), + 'cue_out' => Application_Common_DateHelper::CalculateLengthInSeconds($item["cue_out"]), + 'start' => $start, + 'end' => $end, + 'show_name' => $item["show_name"], + 'replay_gain' => $replay_gain, + 'independent_event' => $independent_event, + ); + + if ($schedule_item['cue_in'] > $schedule_item['cue_out']) { + $schedule_item['cue_in'] = $schedule_item['cue_out']; + } + self::appendScheduleItem($data, $start, $schedule_item); + } + + private static function createStreamScheduleEvent(&$data, $item, $media_id, $uri) + { + $start = self::AirtimeTimeToPypoTime($item["start"]); + $end = self::AirtimeTimeToPypoTime($item["end"]); + + //create an event to start stream buffering 5 seconds ahead of the streams actual time. + $buffer_start = new DateTime($item["start"], new DateTimeZone('UTC')); + $buffer_start->sub(new DateInterval("PT5S")); + + $stream_buffer_start = self::AirtimeTimeToPypoTime($buffer_start->format("Y-m-d H:i:s")); + + $schedule_item = array( + 'start' => $stream_buffer_start, + 'end' => $stream_buffer_start, + 'uri' => $uri, + 'row_id' => $item["id"], + 'type' => 'stream_buffer_start', + 'independent_event' => true + ); + + self::appendScheduleItem($data, $start, $schedule_item); + + $schedule_item = array( + 'id' => $media_id, + 'type' => 'stream_output_start', + 'row_id' => $item["id"], + 'uri' => $uri, + 'start' => $start, + 'end' => $end, + 'show_name' => $item["show_name"], + 'row_id' => $item["id"], + 'independent_event' => true + ); + self::appendScheduleItem($data, $start, $schedule_item); + + //since a stream never ends we have to insert an additional "kick stream" event. The "start" + //time of this event is the "end" time of the stream minus 1 second. + $dt = new DateTime($item["end"], new DateTimeZone('UTC')); + $dt->sub(new DateInterval("PT1S")); + + $stream_end = self::AirtimeTimeToPypoTime($dt->format("Y-m-d H:i:s")); + + $schedule_item = array( + 'start' => $stream_end, + 'end' => $stream_end, + 'uri' => $uri, + 'type' => 'stream_buffer_end', + 'row_id' => $item["id"], + 'independent_event' => true + ); + self::appendScheduleItem($data, $stream_end, $schedule_item); + + $schedule_item = array( + 'start' => $stream_end, + 'end' => $stream_end, + 'uri' => $uri, + 'type' => 'stream_output_end', + 'independent_event' => true + ); + self::appendScheduleItem($data, $stream_end, $schedule_item); + } + + private static function getRangeStartAndEnd($p_fromDateTime, $p_toDateTime) + { + $CC_CONFIG = Config::getConfig(); + + /* if $p_fromDateTime and $p_toDateTime function parameters are null, + then set range * from "now" to "now + 24 hours". */ + if (is_null($p_fromDateTime)) { + $t1 = new DateTime("@".time()); + $range_start = $t1->format("Y-m-d H:i:s"); + } else { + $range_start = Application_Model_Schedule::PypoTimeToAirtimeTime($p_fromDateTime); + } + if (is_null($p_fromDateTime)) { + $t2 = new DateTime("@".time()); + + $cache_ahead_hours = $CC_CONFIG["cache_ahead_hours"]; + + if (is_numeric($cache_ahead_hours)) { + //make sure we are not dealing with a float + $cache_ahead_hours = intval($cache_ahead_hours); + } else { + $cache_ahead_hours = 1; + } + + $t2->add(new DateInterval("PT".$cache_ahead_hours."H")); + $range_end = $t2->format("Y-m-d H:i:s"); + } else { + $range_end = Application_Model_Schedule::PypoTimeToAirtimeTime($p_toDateTime); + } + + return array($range_start, $range_end); + } + + + private static function createScheduledEvents(&$data, $range_start, $range_end) + { + $utcTimeZone = new DateTimeZone("UTC"); + $items = self::getItems($range_start, $range_end); + foreach ($items as $item) { + $showEndDateTime = new DateTime($item["show_end"], $utcTimeZone); + + $trackStartDateTime = new DateTime($item["start"], $utcTimeZone); + $trackEndDateTime = new DateTime($item["end"], $utcTimeZone); + + if ($trackStartDateTime->getTimestamp() > $showEndDateTime->getTimestamp()) { + //do not send any tracks that start past their show's end time + continue; + } + + if ($trackEndDateTime->getTimestamp() > $showEndDateTime->getTimestamp()) { + $di = $trackStartDateTime->diff($showEndDateTime); + + $item["cue_out"] = $di->format("%H:%i:%s").".000"; + $item["end"] = $showEndDateTime->format("Y-m-d H:i:s"); + } + + if (!is_null($item['file_id'])) { + //row is from "file" + $media_id = $item['file_id']; + $storedFile = Application_Model_StoredFile::Recall($media_id); + $uri = $storedFile->getFilePath(); + self::createFileScheduleEvent($data, $item, $media_id, $uri); + } elseif (!is_null($item['stream_id'])) { + //row is type "webstream" + $media_id = $item['stream_id']; + $uri = $item['url']; + self::createStreamScheduleEvent($data, $item, $media_id, $uri); + } else { + throw new Exception("Unknown schedule type: ".print_r($item, true)); + } + + } + } + + /* Check if two events are less than or equal to 1 second apart + */ + public static function areEventsLinked($event1, $event2) { + $dt1 = DateTime::createFromFormat("Y-m-d-H-i-s", $event1['start']); + $dt2 = DateTime::createFromFormat("Y-m-d-H-i-s", $event2['start']); + + $seconds = $dt2->getTimestamp() - $dt1->getTimestamp(); + return $seconds <= 1; + } + + /** + * Streams are a 4 stage process. + * 1) start buffering stream 5 seconds ahead of its start time + * 2) at the start time tell liquidsoap to switch to this source + * 3) at the end time, tell liquidsoap to stop reading this stream + * 4) at the end time, tell liquidsoap to switch away from input.http source. + * + * When we have two streams back-to-back, some of these steps are unnecessary + * for the second stream. Instead of sending commands 1,2,3,4,1,2,3,4 we should + * send 1,2,1,2,3,4 - We don't need to tell liquidsoap to stop reading (#3), because #1 + * of the next stream implies this when we pass in a new url. We also don't need #4. + * + * There's a special case here is well. When the back-to-back streams are the same, we + * can collapse the instructions 1,2,(3,4,1,2),3,4 to 1,2,3,4. We basically cut out the + * middle part. This function handles this. + */ + private static function foldData(&$data) + { + $previous_key = null; + $previous_val = null; + $previous_previous_key = null; + $previous_previous_val = null; + $previous_previous_previous_key = null; + $previous_previous_previous_val = null; + foreach ($data as $k => $v) { + + if ($v["type"] == "stream_output_start" + && !is_null($previous_previous_val) + && $previous_previous_val["type"] == "stream_output_end" + && self::areEventsLinked($previous_previous_val, $v)) { + + unset($data[$previous_previous_previous_key]); + unset($data[$previous_previous_key]); + unset($data[$previous_key]); + if ($previous_previous_val['uri'] == $v['uri']) { + unset($data[$k]); + } + } + + $previous_previous_previous_key = $previous_previous_key; + $previous_previous_previous_val = $previous_previous_val; + $previous_previous_key = $previous_key; + $previous_previous_val = $previous_val; + $previous_key = $k; + $previous_val = $v; + } + } + + public static function getSchedule($p_fromDateTime = null, $p_toDateTime = null) + { + list($range_start, $range_end) = self::getRangeStartAndEnd($p_fromDateTime, $p_toDateTime); + + $data = array(); + $data["media"] = array(); + + //Harbor kick times *MUST* be ahead of schedule events, so that pypo + //executes them first. + self::createInputHarborKickTimes($data, $range_start, $range_end); + self::createScheduledEvents($data, $range_start, $range_end); + + self::foldData($data["media"]); + return $data; + } + + public static function deleteAll() + { + $con = Propel::getConnection(); + $con->exec("TRUNCATE TABLE cc_schedule"); + } + + public static function deleteWithFileId($fileId) + { + $sql = "DELETE FROM cc_schedule WHERE file_id=:file_id"; + Application_Common_Database::prepareAndExecute($sql, array(':file_id'=>$fileId), 'execute'); + } + + public static function createNewFormSections($p_view) + { + $formWhat = new Application_Form_AddShowWhat(); + $formWho = new Application_Form_AddShowWho(); + $formWhen = new Application_Form_AddShowWhen(); + $formRepeats = new Application_Form_AddShowRepeats(); + $formStyle = new Application_Form_AddShowStyle(); + $formLive = new Application_Form_AddShowLiveStream(); + + $formWhat->removeDecorator('DtDdWrapper'); + $formWho->removeDecorator('DtDdWrapper'); + $formWhen->removeDecorator('DtDdWrapper'); + $formRepeats->removeDecorator('DtDdWrapper'); + $formStyle->removeDecorator('DtDdWrapper'); + $formLive->removeDecorator('DtDdWrapper'); + + $p_view->what = $formWhat; + $p_view->when = $formWhen; + $p_view->repeats = $formRepeats; + $p_view->who = $formWho; + $p_view->style = $formStyle; + $p_view->live = $formLive; + + $formWhat->populate(array('add_show_id' => '-1', + 'add_show_instance_id' => '-1')); + $formWhen->populate(array('add_show_start_date' => date("Y-m-d"), + 'add_show_start_time' => '00:00', + 'add_show_end_date_no_repeate' => date("Y-m-d"), + 'add_show_end_time' => '01:00', + 'add_show_duration' => '01h 00m')); + + $formRepeats->populate(array('add_show_end_date' => date("Y-m-d"))); + + $formRecord = new Application_Form_AddShowRR(); + $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); + $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); + + $formRecord->removeDecorator('DtDdWrapper'); + $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); + $formRebroadcast->removeDecorator('DtDdWrapper'); + + $p_view->rr = $formRecord; + $p_view->absoluteRebroadcast = $formAbsoluteRebroadcast; + $p_view->rebroadcast = $formRebroadcast; + $p_view->addNewShow = true; + } + + /* This function is responsible for handling the case where an individual + * show instance in a repeating show was edited (via the context menu in the Calendar). + * There is still lots of clean-up to do. For example we shouldn't be passing $controller into + * this method to manipulate the view (this should be done inside the controller function). With + * 2.1 deadline looming, this is OK for now. -Martin */ + public static function updateShowInstance($data, $controller) + { + $formWhat = new Application_Form_AddShowWhat(); + $formWhen = new Application_Form_AddShowWhen(); + $formRepeats = new Application_Form_AddShowRepeats(); + $formWho = new Application_Form_AddShowWho(); + $formStyle = new Application_Form_AddShowStyle(); + $formLive = new Application_Form_AddShowLiveStream(); + + $formWhat->removeDecorator('DtDdWrapper'); + $formWhen->removeDecorator('DtDdWrapper'); + $formRepeats->removeDecorator('DtDdWrapper'); + $formWho->removeDecorator('DtDdWrapper'); + $formStyle->removeDecorator('DtDdWrapper'); + $formLive->removeDecorator('DtDdWrapper'); + + $formRecord = new Application_Form_AddShowRR(); + $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); + $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); + + $formRecord->removeDecorator('DtDdWrapper'); + $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); + $formRebroadcast->removeDecorator('DtDdWrapper'); + $when = $formWhen->isValid($data); + + if ($when && $formWhen->checkReliantFields($data, true, null, true)) { + $start_dt = new DateTime($data['add_show_start_date']." ".$data['add_show_start_time'], + new DateTimeZone(date_default_timezone_get())); + $start_dt->setTimezone(new DateTimeZone('UTC')); + + $end_dt = new DateTime($data['add_show_end_date_no_repeat']." ".$data['add_show_end_time'], + new DateTimeZone(date_default_timezone_get())); + $end_dt->setTimezone(new DateTimeZone('UTC')); + + $ccShowInstance = CcShowInstancesQuery::create()->findPK($data["add_show_instance_id"]); + $ccShowInstance->setDbStarts($start_dt); + $ccShowInstance->setDbEnds($end_dt); + $ccShowInstance->save(); + + Application_Model_Schedule::createNewFormSections($controller->view); + + return true; + } else { + $formWhat->disable(); + $formWhen->disableRepeatCheckbox(); + $formRepeats->disable(); + $formWho->disable(); + $formStyle->disable(); + //$formLive->disable(); + + $controller->view->what = $formWhat; + $controller->view->when = $formWhen; + $controller->view->repeats = $formRepeats; + $controller->view->who = $formWho; + $controller->view->style = $formStyle; + $controller->view->live = $formLive; + $controller->view->rr = $formRecord; + $controller->view->absoluteRebroadcast = $formAbsoluteRebroadcast; + $controller->view->rebroadcast = $formRebroadcast; + + //$formRecord->disable(); + //$formAbsoluteRebroadcast->disable(); + //$formRebroadcast->disable(); + + return false; + } + } + + /* This function is responsible for handling the case where the entire show (not a single show instance) + * was edited (via the context menu in the Calendar). + * There is still lots of clean-up to do. For example we shouldn't be passing $controller into + * this method to manipulate the view (this should be done inside the controller function). With + * 2.1 deadline looming, this is OK for now. + * Another clean-up is to move all the form manipulation to the proper form class..... + * -Martin + */ + public static function addUpdateShow($data, $controller, $validateStartDate, + $originalStartDate=null, $update=false, $instanceId=null) + { + $userInfo = Zend_Auth::getInstance()->getStorage()->read(); + $user = new Application_Model_User($userInfo->id); + $isAdminOrPM = $user->isUserType(array(UTYPE_ADMIN, UTYPE_PROGRAM_MANAGER)); + + $record = false; + + $formWhat = new Application_Form_AddShowWhat(); + $formWho = new Application_Form_AddShowWho(); + $formWhen = new Application_Form_AddShowWhen(); + $formRepeats = new Application_Form_AddShowRepeats(); + $formStyle = new Application_Form_AddShowStyle(); + $formLive = new Application_Form_AddShowLiveStream(); + + $formWhat->removeDecorator('DtDdWrapper'); + $formWho->removeDecorator('DtDdWrapper'); + $formWhen->removeDecorator('DtDdWrapper'); + $formRepeats->removeDecorator('DtDdWrapper'); + $formStyle->removeDecorator('DtDdWrapper'); + $formLive->removeDecorator('DtDdWrapper'); + + $what = $formWhat->isValid($data); + $when = $formWhen->isValid($data); + $live = $formLive->isValid($data); + if ($when) { + $when = $formWhen->checkReliantFields($data, $validateStartDate, $originalStartDate, $update, $instanceId); + } + + //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 + //actually pass the format from javascript in the format hh:mm so we don't + //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)); + } + if ($mPos !== false) { + $hPos = $hPos === false ? 0 : $hPos+1; + $mValue = trim(substr($data["add_show_duration"], $hPos, -1 )); + } + + $data["add_show_duration"] = $hValue.":".$mValue; + + $formRecord = new Application_Form_AddShowRR(); + $formAbsoluteRebroadcast = new Application_Form_AddShowAbsoluteRebroadcastDates(); + $formRebroadcast = new Application_Form_AddShowRebroadcastDates(); + + $formRecord->removeDecorator('DtDdWrapper'); + $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); + $formRebroadcast->removeDecorator('DtDdWrapper'); + + + $record = $formRecord->isValid($data); + + if ($data["add_show_repeats"]) { + $repeats = $formRepeats->isValid($data); + if ($repeats) { + $repeats = $formRepeats->checkReliantFields($data); + } + $formAbsoluteRebroadcast->reset(); + //make it valid, results don't matter anyways. + $rebroadAb = 1; + + if ($data["add_show_rebroadcast"]) { + $rebroad = $formRebroadcast->isValid($data); + if ($rebroad) { + $rebroad = $formRebroadcast->checkReliantFields($data); + } + } else { + $rebroad = 1; + } + } else { + $repeats = 1; + $formRebroadcast->reset(); + //make it valid, results don't matter anyways. + $rebroad = 1; + + if ($data["add_show_rebroadcast"]) { + $rebroadAb = $formAbsoluteRebroadcast->isValid($data); + if ($rebroadAb) { + $rebroadAb = $formAbsoluteRebroadcast->checkReliantFields($data); + } + } else { + $rebroadAb = 1; + } + } + + $who = $formWho->isValid($data); + $style = $formStyle->isValid($data); + if ($what && $when && $repeats && $who && $style && $live) { + if ($record && $rebroadAb && $rebroad) { + if ($isAdminOrPM) { + Application_Model_Show::create($data); + } + + //send back a new form for the user. + Application_Model_Schedule::createNewFormSections($controller->view); + + //$controller->view->newForm = $controller->view->render('schedule/add-show-form.phtml'); + return true; + } else { + $controller->view->what = $formWhat; + $controller->view->when = $formWhen; + $controller->view->repeats = $formRepeats; + $controller->view->who = $formWho; + $controller->view->style = $formStyle; + $controller->view->rr = $formRecord; + $controller->view->absoluteRebroadcast = $formAbsoluteRebroadcast; + $controller->view->rebroadcast = $formRebroadcast; + $controller->view->live = $formLive; + //$controller->view->addNewShow = !$editShow; + + //$controller->view->form = $controller->view->render('schedule/add-show-form.phtml'); + return false; + + } + } else { + $controller->view->what = $formWhat; + $controller->view->when = $formWhen; + $controller->view->repeats = $formRepeats; + $controller->view->who = $formWho; + $controller->view->style = $formStyle; + $controller->view->live = $formLive; + + $controller->view->rr = $formRecord; + $controller->view->absoluteRebroadcast = $formAbsoluteRebroadcast; + $controller->view->rebroadcast = $formRebroadcast; + //$controller->view->addNewShow = !$editShow; + //$controller->view->form = $controller->view->render('schedule/add-show-form.phtml'); + return false; + } + } + + public static function checkOverlappingShows($show_start, $show_end, + $update=false, $instanceId=null, $showId=null) + { + $overlapping = false; + + $params = array( + ':show_end1' => $show_end->format('Y-m-d H:i:s'), + ':show_end2' => $show_end->format('Y-m-d H:i:s'), + ':show_end3' => $show_end->format('Y-m-d H:i:s') + ); + + + /* If a show is being edited, exclude it from the query + * In both cases (new and edit) we only grab shows that + * are scheduled 2 days prior + */ + if ($update) { + $sql = <<= (date(:show_end3) - INTERVAL '2 days') + AND modified_instance = FALSE +SQL; + if (is_null($showId)) { + $sql .= <<= (date(:show_end3) - INTERVAL '2 days') + AND modified_instance = FALSE +ORDER BY ends +SQL; + + $rows = Application_Common_Database::prepareAndExecute($sql, array( + ':show_end1' => $show_end->format('Y-m-d H:i:s'), + ':show_end2' => $show_end->format('Y-m-d H:i:s'), + ':show_end3' => $show_end->format('Y-m-d H:i:s')), 'all'); + } + + foreach ($rows as $row) { + $start = new DateTime($row["starts"], new DateTimeZone('UTC')); + $end = new DateTime($row["ends"], new DateTimeZone('UTC')); + + if ($show_start->getTimestamp() < $end->getTimestamp() && + $show_end->getTimestamp() > $start->getTimestamp()) { + $overlapping = true; + break; + } + } + + return $overlapping; + } + + public static function GetType($p_scheduleId){ + $scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId); + if ($scheduledItem->getDbFileId() == null) { + return 'webstream'; + } else { + return 'file'; + } + } + + public static function GetFileId($p_scheduleId) + { + $scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId); + + return $scheduledItem->getDbFileId(); + } + + public static function GetStreamId($p_scheduleId) + { + $scheduledItem = CcScheduleQuery::create()->findPK($p_scheduleId); + + return $scheduledItem->getDbStreamId(); + } +} diff --git a/airtime_mvc/application/services/ScheduleService.php b/airtime_mvc/application/services/ScheduleService.php new file mode 100644 index 000000000..983d1bd6f --- /dev/null +++ b/airtime_mvc/application/services/ScheduleService.php @@ -0,0 +1,90 @@ +removeDecorator('DtDdWrapper'); + $formWho->removeDecorator('DtDdWrapper'); + $formWhen->removeDecorator('DtDdWrapper'); + $formRepeats->removeDecorator('DtDdWrapper'); + $formStyle->removeDecorator('DtDdWrapper'); + $formLive->removeDecorator('DtDdWrapper'); + $formRecord->removeDecorator('DtDdWrapper'); + $formAbsoluteRebroadcast->removeDecorator('DtDdWrapper'); + $formRebroadcast->removeDecorator('DtDdWrapper'); + + $forms = array(); + $forms["what"] = $formWhat; + $forms["who"] = $formWho; + $forms["when"] = $formWhen; + $forms["repeats"] = $formRepeats; + $forms["style"] = $formStyle; + $forms["live"] = $formLive; + $forms["record"] = $formRecord; + $forms["abs_record"] = $formAbsoluteRebroadcast; + $forms["rebroadcast"] = $formRebroadcast; + + return $forms; + } + + /** + * + * Popluates the what, when, and repeat forms + * with default values + */ + public function populateNewShowForms($formWhat, $formWhen, $formRepeats) + { + $formWhat->populate( + array('add_show_id' => '-1', + 'add_show_instance_id' => '-1')); + + $formWhen->populate( + array('add_show_start_date' => date("Y-m-d"), + 'add_show_start_time' => '00:00', + 'add_show_end_date_no_repeate' => date("Y-m-d"), + 'add_show_end_time' => '01:00', + 'add_show_duration' => '01h 00m')); + + $formRepeats->populate(array('add_show_end_date' => date("Y-m-d"))); + } + + public function populateForm($form, $values) + { + $form->populate($values); + } + + /** + * + * Validates show forms + * + * @return array of booleans + */ + public function validateShowForms($forms) + { + + } + + /** + * + * Creates a new show if form data is valid + */ + public function createShow() + { + + } +} \ No newline at end of file