public function moveShow($deltaDay, $deltaMin) { if ($this->getShow()->isRepeating()) { return "Can't drag and drop repeating shows"; } $today_timestamp = time(); $startsDateTime = new DateTime($this->getShowInstanceStart(), new DateTimeZone("UTC")); $endsDateTime = new DateTime($this->getShowInstanceEnd(), new DateTimeZone("UTC")); if ($today_timestamp > $startsDateTime->getTimestamp()) { return "Can't move a past show"; } //the user is moving the show on the calendar from the perspective of local time. //incase a show is moved across a time change border offsets should be added to the localtime //stamp and then converted back to UTC to avoid show time changes! $startsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); $endsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); $newStartsDateTime = self::addDeltas($startsDateTime, $deltaDay, $deltaMin); $newEndsDateTime = self::addDeltas($endsDateTime, $deltaDay, $deltaMin); //convert our new starts/ends to UTC. $newStartsDateTime->setTimezone(new DateTimeZone("UTC")); $newEndsDateTime->setTimezone(new DateTimeZone("UTC")); if ($today_timestamp > $newStartsDateTime->getTimestamp()) { return "Can't move show into past"; } //check if show is overlapping $overlapping = Application_Model_Schedule::checkOverlappingShows($newStartsDateTime, $newEndsDateTime, true, $this->getShowInstanceId()); if ($overlapping) { return "Cannot schedule overlapping shows"; } if ($this->isRecorded()) { //rebroadcasts should start at max 1 hour after a recorded show has ended. $minRebroadcastStart = self::addDeltas($newEndsDateTime, 0, 60); //check if we are moving a recorded show less than 1 hour before any of its own rebroadcasts. $rebroadcasts = CcShowInstancesQuery::create()->filterByDbOriginalShow($this->_instanceId)->filterByDbStarts($minRebroadcastStart->format('Y-m-d H:i:s'), Criteria::LESS_THAN)->find(); if (count($rebroadcasts) > 0) { return "Can't move a recorded show less than 1 hour before its rebroadcasts."; } } if ($this->isRebroadcast()) { try { $recordedShow = new Application_Model_ShowInstance($this->_showInstance->getDbOriginalShow()); } catch (Exception $e) { $this->_showInstance->delete(); return "Show was deleted because recorded show does not exist!"; } $recordEndDateTime = new DateTime($recordedShow->getShowInstanceEnd(), new DateTimeZone("UTC")); $newRecordEndDateTime = self::addDeltas($recordEndDateTime, 0, 60); if ($newStartsDateTime->getTimestamp() < $newRecordEndDateTime->getTimestamp()) { return "Must wait 1 hour to rebroadcast."; } } $this->setShowStart($newStartsDateTime); $this->setShowEnd($newEndsDateTime); $this->correctScheduleStartTimes(); $show = new Application_Model_Show($this->getShowId()); if (!$show->isRepeating() && is_null($this->isRebroadcast())) { $show->setShowFirstShow($newStartsDateTime); $show->setShowLastShow($newEndsDateTime); } Application_Model_RabbitMq::PushSchedule(); }
private function validateShowMove($deltaDay, $deltaMin) { if (!$this->currentUser->isAdminOrPM()) { throw new Exception(_("Permission denied")); } if ($this->ccShow->isRepeating()) { throw new Exception(_("Can't drag and drop repeating shows")); } $today_timestamp = time(); $startsDateTime = $this->ccShowInstance->getDbStarts(null); $endsDateTime = $this->ccShowInstance->getDbEnds(null); if ($today_timestamp > $startsDateTime->getTimestamp()) { throw new Exception(_("Can't move a past show")); } //the user is moving the show on the calendar from the perspective of local time. //incase a show is moved across a time change border offsets should be added to the localtime //stamp and then converted back to UTC to avoid show time changes! $showTimezone = $this->ccShow->getFirstCcShowDay()->getDbTimezone(); $startsDateTime->setTimezone(new DateTimeZone($showTimezone)); $endsDateTime->setTimezone(new DateTimeZone($showTimezone)); $duration = $startsDateTime->diff($endsDateTime); $newStartsDateTime = self::addDeltas($startsDateTime, $deltaDay, $deltaMin); /* WARNING: Do not separately add a time delta to the start and end times because that does not preserve the duration across a DST time change. For example, 5am - 3 hours = 3am when DST occurs at 2am. BUT, 6am - 3 hours = 3am also! So when a DST change occurs, adding the deltas like this separately does not conserve the duration of a show. Since that's what we want (otherwise we'll get a zero length show), we calculate the show duration FIRST, then we just add that on to the start time to calculate the end time. This is a safer approach. The key lesson here is that in general: duration != end - start ... so be careful! */ //$newEndsDateTime = self::addDeltas($endsDateTime, $deltaDay, $deltaMin); <--- Wrong, don't do it. $newEndsDateTime = clone $newStartsDateTime; $newEndsDateTime = $newEndsDateTime->add($duration); //convert our new starts/ends to UTC. $newStartsDateTime->setTimezone(new DateTimeZone("UTC")); $newEndsDateTime->setTimezone(new DateTimeZone("UTC")); if ($today_timestamp > $newStartsDateTime->getTimestamp()) { throw new Exception(_("Can't move show into past")); } //check if show is overlapping $overlapping = Application_Model_Schedule::checkOverlappingShows($newStartsDateTime, $newEndsDateTime, true, $this->ccShowInstance->getDbId()); if ($overlapping) { throw new Exception(_("Cannot schedule overlapping shows")); } if ($this->ccShow->isRecorded()) { //rebroadcasts should start at max 1 hour after a recorded show has ended. $minRebroadcastStart = self::addDeltas($newEndsDateTime, 0, 60); //check if we are moving a recorded show less than 1 hour before any of its own rebroadcasts. $rebroadcasts = CcShowInstancesQuery::create()->filterByDbOriginalShow($this->ccShow->getDbId())->filterByDbStarts($minRebroadcastStart->format('Y-m-d H:i:s'), Criteria::LESS_THAN)->find(); if (count($rebroadcasts) > 0) { throw new Exception(_("Can't move a recorded show less than 1 hour before its rebroadcasts.")); } } if ($this->ccShow->isRebroadcast()) { $recordedShow = CcShowInstancesQuery::create()->filterByCcShow($this->ccShowInstance->getDbOriginalShow())->findOne(); if (is_null($recordedShow)) { $this->ccShowInstance->delete(); throw new Exception(_("Show was deleted because recorded show does not exist!")); } $recordEndDateTime = new DateTime($recordedShow->getDbEnds(), new DateTimeZone("UTC")); $newRecordEndDateTime = self::addDeltas($recordEndDateTime, 0, 60); if ($newStartsDateTime->getTimestamp() < $newRecordEndDateTime->getTimestamp()) { throw new Exception(_("Must wait 1 hour to rebroadcast.")); } } return array($newStartsDateTime, $newEndsDateTime); }
public function resizeShow($deltaDay, $deltaMin, $instanceId) { $con = Propel::getConnection(); if ($deltaDay > 0) { return _("Shows can have a max length of 24 hours."); } $utcTimezone = new DateTimeZone("UTC"); $nowDateTime = new DateTime("now", $utcTimezone); //keep track of cc_show_day entries we need to update $showDayIds = array(); /* * If the resized show is an edited instance of a repeating show we * need to treat it as a separate show and not resize the other instances * * Also, if the resized show has edited instances, we need to exclude * those from the resize */ $ccShow = CcShowQuery::create()->findPk($this->_showId); if ($ccShow->isRepeating()) { //convert instance to local timezone $ccShowInstance = CcShowInstancesQuery::create()->findPk($instanceId); $startsDT = $ccShowInstance->getDbStarts(null); $timezone = $ccShow->getFirstCcShowDay()->getDbTimezone(); $startsDT->setTimezone(new DateTimeZone($timezone)); /* Get cc_show_day for the current instance. If we don't find one * we know it is a repeat interval of one of cc_show_days first * show and we can assume we aren't resizing a modified instance */ $ccShowDay = CcShowDaysQuery::create()->filterByDbFirstShow($startsDT->format("Y-m-d"))->filterByDbStartTime($startsDT->format("H:i:s"))->filterByDbShowId($this->_showId)->findOne(); /* Check if this cc_show_day rule is non-repeating. If it is, then * we know this instance was edited out of the repeating sequence */ if (!$ccShowDay || $ccShowDay->getDbRepeatType() != -1) { $ccShowDays = $ccShow->getRepeatingCcShowDays(); foreach ($ccShowDays as $day) { array_push($showDayIds, $day->getDbId()); } $excludeIds = $ccShow->getEditedRepeatingInstanceIds(); //exlcude edited instances from resize $showInstances = CcShowInstancesQuery::create()->filterByDbShowId($this->_showId)->filterByDbModifiedInstance(false)->filterByDbId($excludeIds, criteria::NOT_IN)->find(); } elseif ($ccShowDay->getDbRepeatType() == -1) { array_push($showDayIds, $ccShowDay->getDbId()); //treat edited instance as separate show for resize $showInstances = CcShowInstancesQuery::create()->filterByDbId($instanceId)->find(); } } else { $ccShowDays = $ccShow->getCcShowDayss(); foreach ($ccShowDays as $day) { array_push($showDayIds, $day->getDbId()); } $showInstances = CcShowInstancesQuery::create()->filterByDbShowId($this->_showId)->find($con); } /* Check two things: 1. If the show being resized and any of its repeats end in the past 2. If the show being resized and any of its repeats overlap with other scheduled shows */ //keep track of instance ids for update show instances start/end times $instanceIds = array(); $displayTimezone = new DateTimeZone(Application_Model_Preference::GetUserTimezone()); //check if new show time overlaps with any other shows foreach ($showInstances as $si) { array_push($instanceIds, $si->getDbId()); $startsDateTime = $si->getDbStarts(null); $endsDateTime = $si->getDbEnds(null); /* The user is moving the show on the calendar from the perspective of local time. * incase a show is moved across a time change border offsets should be added to the local * timestamp and then converted back to UTC to avoid show time changes */ $startsDateTime->setTimezone($displayTimezone); $endsDateTime->setTimezone($displayTimezone); //$newStartsDateTime = Application_Model_ShowInstance::addDeltas($startsDateTime, $deltaDay, $deltaMin); $newEndsDateTime = Application_Model_ShowInstance::addDeltas($endsDateTime, $deltaDay, $deltaMin); if ($newEndsDateTime->getTimestamp() < $nowDateTime->getTimestamp()) { return _("End date/time cannot be in the past"); } //convert our new starts/ends to UTC. //$newStartsDateTime->setTimezone($utc); $newEndsDateTime->setTimezone($utcTimezone); $overlapping = Application_Model_Schedule::checkOverlappingShows($startsDateTime, $newEndsDateTime, true, $si->getDbId()); if ($overlapping) { return _("Cannot schedule overlapping shows.\nNote: Resizing a repeating show " . "affects all of its repeats."); } } $hours = $deltaMin / 60; $hours = $hours > 0 ? floor($hours) : ceil($hours); $mins = abs($deltaMin % 60); $sql_gen = "UPDATE cc_show_instances " . "SET ends = (ends + :deltaDay1::INTERVAL + :interval1::INTERVAL) " . "WHERE (id IN (" . implode($instanceIds, ",") . ") " . "AND ends > :current_timestamp1) " . "AND ((ends + :deltaDay2::INTERVAL + :interval2::INTERVAL - starts) <= interval '24:00')"; Application_Common_Database::prepareAndExecute($sql_gen, array(':deltaDay1' => "{$deltaDay} days", ':interval1' => "{$hours}:{$mins}", ':current_timestamp1' => $nowDateTime->format("Y-m-d H:i:s"), ':deltaDay2' => "{$deltaDay} days", ':interval2' => "{$hours}:{$mins}"), "execute"); $sql_gen = "UPDATE cc_show_days " . "SET duration = (CAST(duration AS interval) + :deltaDay3::INTERVAL + :interval3::INTERVAL) " . "WHERE id IN (" . implode($showDayIds, ",") . ") " . "AND ((CAST(duration AS interval) + :deltaDay4::INTERVAL + :interval4::INTERVAL) <= interval '24:00')"; Application_Common_Database::prepareAndExecute($sql_gen, array(':deltaDay3' => "{$deltaDay} days", ':interval3' => "{$hours}:{$mins}", ':deltaDay4' => "{$deltaDay} days", ':interval4' => "{$hours}:{$mins}"), "execute"); $con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME); $con->beginTransaction(); try { //update the status flag in cc_schedule. /* Since we didn't use a propel object when updating * cc_show_instances table we need to clear the instances * so the correct information is retrieved from the db */ CcShowInstancesPeer::clearInstancePool(); $instances = CcShowInstancesQuery::create()->filterByDbEnds($nowDateTime->format("Y-m-d H:i:s"), Criteria::GREATER_THAN)->filterByDbId($instanceIds, Criteria::IN)->find($con); foreach ($instances as $instance) { $instance->updateScheduleStatus($con); } $con->commit(); } catch (Exception $e) { $con->rollback(); Logging::info("Couldn't update schedule status."); Logging::info($e->getMessage()); } Application_Model_RabbitMq::PushSchedule(); }
public function checkRebroadcastDates($repeatShowStart, $formData, $hours, $minutes, $showEdit = false) { $overlapping = false; for ($i = 1; $i <= 10; $i++) { if (empty($formData["add_show_rebroadcast_date_" . $i])) { break; } $rebroadcastShowStart = clone $repeatShowStart; /* formData is in local time so we need to set the * show start back to local time */ $rebroadcastShowStart->setTimezone(new DateTimeZone($formData["add_show_timezone"])); $rebroadcastWhenDays = explode(" ", $formData["add_show_rebroadcast_date_" . $i]); $rebroadcastWhenTime = explode(":", $formData["add_show_rebroadcast_time_" . $i]); $rebroadcastShowStart->add(new DateInterval("P" . $rebroadcastWhenDays[0] . "D")); $rebroadcastShowStart->setTime($rebroadcastWhenTime[0], $rebroadcastWhenTime[1]); $rebroadcastShowStart->setTimezone(new DateTimeZone('UTC')); $rebroadcastShowEnd = clone $rebroadcastShowStart; $rebroadcastShowEnd->add(new DateInterval("PT" . $hours . "H" . $minutes . "M")); if ($showEdit) { $overlapping = Application_Model_Schedule::checkOverlappingShows($rebroadcastShowStart, $rebroadcastShowEnd, true, null, $formData['add_show_id']); } else { $overlapping = Application_Model_Schedule::checkOverlappingShows($rebroadcastShowStart, $rebroadcastShowEnd); } if ($overlapping) { break; } } return $overlapping; }
public function resizeShow($deltaDay, $deltaMin) { $con = Propel::getConnection(); if ($deltaDay > 0) { return "Shows can have a max length of 24 hours."; } $utc = new DateTimeZone("UTC"); $nowDateTime = new DateTime("now", $utc); $showInstances = CcShowInstancesQuery::create()->filterByDbShowId($this->_showId)->find($con); /* Check two things: 1. If the show being resized and any of its repeats end in the past 2. If the show being resized and any of its repeats overlap with other scheduled shows */ foreach ($showInstances as $si) { $startsDateTime = new DateTime($si->getDbStarts(), new DateTimeZone("UTC")); $endsDateTime = new DateTime($si->getDbEnds(), new DateTimeZone("UTC")); /* The user is moving the show on the calendar from the perspective of local time. * incase a show is moved across a time change border offsets should be added to the local * timestamp and then converted back to UTC to avoid show time changes */ $startsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); $endsDateTime->setTimezone(new DateTimeZone(date_default_timezone_get())); $newStartsDateTime = Application_Model_ShowInstance::addDeltas($startsDateTime, $deltaDay, $deltaMin); $newEndsDateTime = Application_Model_ShowInstance::addDeltas($endsDateTime, $deltaDay, $deltaMin); if ($newEndsDateTime->getTimestamp() < $nowDateTime->getTimestamp()) { return "End date/time cannot be in the past"; } //convert our new starts/ends to UTC. $newStartsDateTime->setTimezone($utc); $newEndsDateTime->setTimezone($utc); $overlapping = Application_Model_Schedule::checkOverlappingShows($newStartsDateTime, $newEndsDateTime, true, $si->getDbId()); if ($overlapping) { return "Cannot schedule overlapping shows.\nNote: Resizing a repeating show " . "affects all of its repeats."; } } $hours = $deltaMin / 60; $hours = $hours > 0 ? floor($hours) : ceil($hours); $mins = abs($deltaMin % 60); //current timesamp in UTC. $current_timestamp = gmdate("Y-m-d H:i:s"); $sql_gen = <<<SQL UPDATE cc_show_instances SET ends = (ends + :deltaDay1::INTERVAL + :interval1::INTERVAL) WHERE (show_id = :show_id1 AND ends > :current_timestamp1) AND ((ends + :deltaDay2::INTERVAL + :interval2::INTERVAL - starts) <= interval '24:00') SQL; Application_Common_Database::prepareAndExecute($sql_gen, array(':deltaDay1' => "{$deltaDay} days", ':interval1' => "{$hours}:{$mins}", ':show_id1' => $this->_showId, ':current_timestamp1' => $current_timestamp, ':deltaDay2' => "{$deltaDay} days", ':interval2' => "{$hours}:{$mins}"), "execute"); $sql_gen = <<<SQL UPDATE cc_show_days SET duration = (CAST(duration AS interval) + :deltaDay3::INTERVAL + :interval3::INTERVAL) WHERE show_id = :show_id2 AND ((CAST(duration AS interval) + :deltaDay4::INTERVAL + :interval4::INTERVAL) <= interval '24:00') SQL; Application_Common_Database::prepareAndExecute($sql_gen, array(':deltaDay3' => "{$deltaDay} days", ':interval3' => "{$hours}:{$mins}", ':show_id2' => $this->_showId, ':deltaDay4' => "{$deltaDay} days", ':interval4' => "{$hours}:{$mins}"), "execute"); $con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME); $con->beginTransaction(); try { //update the status flag in cc_schedule. $instances = CcShowInstancesQuery::create()->filterByDbEnds($current_timestamp, Criteria::GREATER_THAN)->filterByDbShowId($this->_showId)->find($con); foreach ($instances as $instance) { $instance->updateScheduleStatus($con); } $con->commit(); } catch (Exception $e) { $con->rollback(); Logging::info("Couldn't update schedule status."); Logging::info($e->getMessage()); } Application_Model_RabbitMq::PushSchedule(); }