diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php index ee36cb629..48bbed8d9 100644 --- a/airtime_mvc/application/controllers/ShowbuilderController.php +++ b/airtime_mvc/application/controllers/ShowbuilderController.php @@ -83,20 +83,19 @@ class ShowbuilderController extends Zend_Controller_Action public function scheduleAddAction() { $request = $this->getRequest(); - $mediaItems = $request->getParam("mediaIds", null); $scheduledIds = $request->getParam("schedIds", null); - $json = array(); - try { $scheduler = new Application_Model_Scheduler(); $scheduler->scheduleAfter($scheduledIds, $mediaItems); - - $json["message"]="success... maybe"; + } + catch (OutDatedScheduleException $e) { + $this->view->error = $e->getMessage(); + Logging::log($e->getMessage()); } catch (Exception $e) { - $json["message"]=$e->getMessage(); + $this->view->error = $e->getMessage(); Logging::log($e->getMessage()); } @@ -106,42 +105,38 @@ class ShowbuilderController extends Zend_Controller_Action public function scheduleRemoveAction() { $request = $this->getRequest(); - $items = $request->getParam("items", null); - $json = array(); - try { $scheduler = new Application_Model_Scheduler(); $scheduler->removeItems($items); - - $json["message"]="success... maybe"; } - catch (Exception $e) { - $json["message"]=$e->getMessage(); + catch (OutDatedScheduleException $e) { + $this->view->error = $e->getMessage(); + Logging::log($e->getMessage()); + } + catch (Exception $e) { + $this->view->error = $e->getMessage(); Logging::log($e->getMessage()); } - - $this->view->data = $json; } public function scheduleMoveAction() { $request = $this->getRequest(); - $selectedItem = $request->getParam("selectedItem"); $afterItem = $request->getParam("afterItem"); - $json = array(); - try { $scheduler = new Application_Model_Scheduler(); $scheduler->moveItem($selectedItem, $afterItem); - - $json["message"]="success... maybe"; + } + catch (OutDatedScheduleException $e) { + $this->view->error = $e->getMessage(); + Logging::log($e->getMessage()); } catch (Exception $e) { - $json["message"]=$e->getMessage(); + $this->view->error = $e->getMessage(); Logging::log($e->getMessage()); } diff --git a/airtime_mvc/application/models/Schedule.php b/airtime_mvc/application/models/Schedule.php index be8aedc75..1c2100d35 100644 --- a/airtime_mvc/application/models/Schedule.php +++ b/airtime_mvc/application/models/Schedule.php @@ -313,7 +313,7 @@ class Application_Model_Schedule { showt.background_color AS show_background_colour, showt.id AS show_id, si.starts AS si_starts, si.ends AS si_ends, si.time_filled AS si_time_filled, - si.record AS si_record, si.rebroadcast AS si_rebroadcast, si.id AS si_id, + si.record AS si_record, si.rebroadcast AS si_rebroadcast, si.id AS si_id, si.last_scheduled AS si_last_scheduled, sched.starts AS sched_starts, sched.ends AS sched_ends, sched.id AS sched_id, diff --git a/airtime_mvc/application/models/Scheduler.php b/airtime_mvc/application/models/Scheduler.php index bd06b1ff1..851064145 100644 --- a/airtime_mvc/application/models/Scheduler.php +++ b/airtime_mvc/application/models/Scheduler.php @@ -297,10 +297,23 @@ class Application_Model_Scheduler { $scheduledIds = array(); foreach ($scheduledItems as $item) { - $scheduledIds[] = $item["id"]; + $scheduledIds[$item["id"]] = $item["timestamp"]; + } + + $removedItems = CcScheduleQuery::create()->findPks(array_keys($scheduledIds)); + + //check to make sure all items selected are up to date + foreach ($removedItems as $removedItem) { + $ts = $scheduledIds[$removedItem->getDbId()]; + $instance = $removedItem->getCcShowInstances($this->con); + $currTs = intval($instance->getDbLastScheduled("U")) ? : 0; + + if ($ts !== $currTs) { + $show = $instance->getCcShow($this->con); + throw new OutDatedScheduleException("The show {$show->getDbName()} is outdated!"); + } } - $removedItems = CcScheduleQuery::create()->findPks($scheduledIds); $removedItems->delete($this->con); if ($adjustSched === true) { @@ -338,6 +351,9 @@ class Application_Model_Scheduler { Logging::log("removing gaps from show instance #".$showInstance); $instance = CcShowInstancesQuery::create()->findPK($showInstance, $this->con); + $instance->setDbLastScheduled(new DateTime("now", new DateTimeZone("UTC"))); + $instance->save($this->con); + $itemStartDT = $instance->getDbStarts(null); $schedule = CcScheduleQuery::create() @@ -360,4 +376,6 @@ class Application_Model_Scheduler { $itemStartDT = $itemEndDT; } } -} \ No newline at end of file +} + +class OutDatedScheduleException extends Exception {} \ No newline at end of file diff --git a/airtime_mvc/application/models/ShowBuilder.php b/airtime_mvc/application/models/ShowBuilder.php index 9feb17647..01dc84636 100644 --- a/airtime_mvc/application/models/ShowBuilder.php +++ b/airtime_mvc/application/models/ShowBuilder.php @@ -22,7 +22,8 @@ class Application_Model_ShowBuilder { "runtime" => "", "title" => "", "creator" => "", - "album" => "" + "album" => "", + "timestamp" => null ); /* @@ -100,9 +101,22 @@ class Application_Model_ShowBuilder { return $row; } + private function getRowTimestamp($p_item, &$row) { + + if (is_null($p_item["si_last_scheduled"])) { + $ts = 0; + } + else { + $dt = new DateTime($p_item["si_last_scheduled"], new DateTimeZone("UTC")); + $ts = intval($dt->format("U")); + } + $row["timestamp"] = $ts; + } + private function makeHeaderRow($p_item) { $row = $this->defaultRowArray; + $this->getRowTimestamp($p_item, &$row); $showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC")); $showStartDT->setTimezone(new DateTimeZone($this->timezone)); @@ -126,6 +140,7 @@ class Application_Model_ShowBuilder { $epoch_now = time(); $showStartDT = new DateTime($p_item["si_starts"], new DateTimeZone("UTC")); + $this->getRowTimestamp($p_item, &$row); //can only schedule the show if it hasn't started and you are allowed. if ($epoch_now < $showStartDT->format('U') && $this->user->canSchedule($p_item["show_id"]) == true) { diff --git a/airtime_mvc/application/models/airtime/CcShowInstances.php b/airtime_mvc/application/models/airtime/CcShowInstances.php index 26d568f09..d1c97f437 100644 --- a/airtime_mvc/application/models/airtime/CcShowInstances.php +++ b/airtime_mvc/application/models/airtime/CcShowInstances.php @@ -76,4 +76,35 @@ class CcShowInstances extends BaseCcShowInstances { return $dt->format($format); } } + + /** + * Get the [optionally formatted] temporal [last_scheduled] column value. + * + * + * @param string $format The date/time format string (either date()-style or strftime()-style). + * If format is NULL, then the raw DateTime object will be returned. + * @return mixed Formatted date/time value as string or DateTime object (if format is NULL), NULL if column is NULL + * @throws PropelException - if unable to parse/validate the date/time value. + */ + public function getDbLastScheduled($format = 'Y-m-d H:i:s') + { + if ($this->last_scheduled === null) { + return null; + } + + try { + $dt = new DateTime($this->last_scheduled, new DateTimeZone("UTC")); + } catch (Exception $x) { + throw new PropelException("Internally stored date/time/timestamp value could not be converted to DateTime: " . var_export($this->last_scheduled, true), $x); + } + + if ($format === null) { + // Because propel.useDateTimeClass is TRUE, we return a DateTime object. + return $dt; + } elseif (strpos($format, '%') !== false) { + return strftime($format, $dt->format('U')); + } else { + return $dt->format($format); + } + } } // CcShowInstances diff --git a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js index a2cb407e1..f5f3f0b8e 100644 --- a/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js +++ b/airtime_mvc/public/js/airtime/library/events/library_showbuilder.js @@ -31,18 +31,13 @@ var AIRTIME = (function(AIRTIME){ fnResetCol, fnAddSelectedItems, - fnTest = function() { - alert("hi"); - }; - fnResetCol = function () { ColReorder.fnReset( oLibTable ); return false; }; fnAddSelectedItems = function() { - var oSchedTable = $("#show_builder_table").dataTable(), - oLibTT = TableTools.fnGetInstance('library_display'), + var oLibTT = TableTools.fnGetInstance('library_display'), oSchedTT = TableTools.fnGetInstance('show_builder_table'), aData = oLibTT.fnGetSelectedData(), item, @@ -68,12 +63,10 @@ var AIRTIME = (function(AIRTIME){ } } - $.post("/showbuilder/schedule-add", - {"format": "json", "mediaIds": aMediaIds, "schedIds": aSchedIds}, - function(json){ - oLibTT.fnSelectNone(); - oSchedTable.fnDraw(); - }); + AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds, function(){ + oLibTT.fnSelectNone(); + }); + }; //[0] = button text //[1] = id diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder.js b/airtime_mvc/public/js/airtime/showbuilder/builder.js index af718f056..3e98d1af8 100644 --- a/airtime_mvc/public/js/airtime/showbuilder/builder.js +++ b/airtime_mvc/public/js/airtime/showbuilder/builder.js @@ -1,3 +1,61 @@ +var AIRTIME = (function(AIRTIME){ + var mod, + oSchedTable; + + if (AIRTIME.showbuilder === undefined) { + AIRTIME.showbuilder = {}; + } + mod = AIRTIME.showbuilder; + + function checkError(json) { + if (json.error !== undefined) { + alert(json.error); + } + } + + mod.fnAdd = function(aMediaIds, aSchedIds, callback) { + + $.post("/showbuilder/schedule-add", + {"format": "json", "mediaIds": aMediaIds, "schedIds": aSchedIds}, + function(json){ + checkError(json); + oSchedTable.fnDraw(); + + if ($.isFunction(callback)) { + callback(); + } + }); + }; + + mod.fnMove = function(aSelect, aAfter) { + + $.post("/showbuilder/schedule-move", + {"format": "json", "selectedItem": aSelect, "afterItem": aAfter}, + function(json){ + checkError(json); + oSchedTable.fnDraw(); + }); + }; + + mod.fnRemove = function(aItems) { + + $.post( "/showbuilder/schedule-remove", + {"items": aItems, "format": "json"}, + function(json) { + checkError(json); + oSchedTable.fnDraw(); + }); + }; + + mod.init = function(oTable) { + oSchedTable = oTable; + }; + + return AIRTIME; + +}(AIRTIME || {})); + + $(document).ready(function() { var tableDiv = $('#show_builder_table'), oTable, @@ -201,15 +259,11 @@ $(document).ready(function() { for (item in aData) { temp = aData[item]; if (temp !== null && temp.hasOwnProperty('id')) { - aItems.push({"id": temp.id, "instance": temp.instance}); + aItems.push({"id": temp.id, "instance": temp.instance, "timestamp": temp.timestamp}); } } - $.post( "/showbuilder/schedule-remove", - {"items": aItems, "format": "json"}, - function(data) { - oTable.fnDraw(); - }); + AIRTIME.showbuilder.fnRemove(aItems); }; oTable = tableDiv.dataTable( { @@ -258,7 +312,7 @@ $(document).ready(function() { //don't select separating rows, or shows without privileges. if ($(node).hasClass("sb-header") || $(node).hasClass("sb-footer") - || $(node).hasClass("sb-not-allowed")){ + || $(node).hasClass("sb-not-allowed")) { return false; } return true; @@ -352,28 +406,20 @@ $(document).ready(function() { var aMediaIds = [], aSchedIds = []; - aSchedIds.push({"id": oPrevData.id, "instance": oPrevData.instance}); + aSchedIds.push({"id": oPrevData.id, "instance": oPrevData.instance, "timestamp": oPrevData.timestamp}); aMediaIds.push({"id": oItemData.id, "type": oItemData.ftype}); - $.post("/showbuilder/schedule-add", - {"format": "json", "mediaIds": aMediaIds, "schedIds": aSchedIds}, - function(json){ - oTable.fnDraw(); - }); + AIRTIME.showbuilder.fnAdd(aMediaIds, aSchedIds); }; fnMove = function() { var aSelect = [], aAfter = []; - aSelect.push({"id": oItemData.id, "instance": oItemData.instance}); - aAfter.push({"id": oPrevData.id, "instance": oPrevData.instance}); + aSelect.push({"id": oItemData.id, "instance": oItemData.instance, "timestamp": oItemData.timestamp}); + aAfter.push({"id": oPrevData.id, "instance": oPrevData.instance, "timestamp": oPrevData.timestamp}); - $.post("/showbuilder/schedule-move", - {"format": "json", "selectedItem": aSelect, "afterItem": aAfter}, - function(json){ - oTable.fnDraw(); - }); + AIRTIME.showbuilder.fnMove(aSelect, aAfter); }; fnReceive = function(event, ui) { @@ -414,4 +460,7 @@ $(document).ready(function() { .append('
') .click(fnRemoveSelectedItems); + //set things like a reference to the table. + AIRTIME.showbuilder.init(oTable); + });