diff --git a/airtime_mvc/application/controllers/ErrorController.php b/airtime_mvc/application/controllers/ErrorController.php index 774db9926..a840da163 100644 --- a/airtime_mvc/application/controllers/ErrorController.php +++ b/airtime_mvc/application/controllers/ErrorController.php @@ -7,6 +7,15 @@ class ErrorController extends Zend_Controller_Action { //We cannot show that. $this->view->layout()->disableLayout(); $this->setupCSS(); + + // TODO: set Help button URL based on whether or not user is logged in + try { + $service_user = new Application_Service_UserService(); + $service_user->getCurrentUser(); + $this->view->helpUrl = Application_Common_OsPath::getBaseDir() . 'dashboard/help'; + } catch (Exception $e) { + $this->view->helpUrl = HELP_URL; + } } public function errorAction() { diff --git a/airtime_mvc/application/controllers/plugins/Acl_plugin.php b/airtime_mvc/application/controllers/plugins/Acl_plugin.php index 01b977079..9f9293434 100644 --- a/airtime_mvc/application/controllers/plugins/Acl_plugin.php +++ b/airtime_mvc/application/controllers/plugins/Acl_plugin.php @@ -211,8 +211,10 @@ class Zend_Controller_Plugin_Acl extends Zend_Controller_Plugin_Abstract $resourceName .= $controller; /** Check if the controller/action can be accessed by the current user */ - if (!$this->getAcl()->has($resourceName) - || !$this->getAcl()->isAllowed($this->_roleName, + if (!$this->getAcl()->has($resourceName)) { + $this->setErrorPage('error404'); + $this->denyAccess(); + } else if (!$this->getAcl()->isAllowed($this->_roleName, $resourceName, $request->getActionName())) { /** Redirect to access denied page */ diff --git a/airtime_mvc/application/forms/PodcastPreferences.php b/airtime_mvc/application/forms/PodcastPreferences.php index adf86c84e..9c007439e 100644 --- a/airtime_mvc/application/forms/PodcastPreferences.php +++ b/airtime_mvc/application/forms/PodcastPreferences.php @@ -17,16 +17,6 @@ class Application_Form_PodcastPreferences extends Zend_Form_SubForm { )); $stationPodcastPrivacy->setValue($isPrivate); $this->addElement($stationPodcastPrivacy); - - $stationPodcast = PodcastQuery::create()->findOneByDbId(Application_Model_Preference::getStationPodcastId()); - $url = $stationPodcast->getDbUrl(); - $feedUrl = new Zend_Form_Element_Text("stationPodcastFeedUrl"); - $feedUrl->setAttrib('class', 'input_text') - ->setAttrib('disabled', 'disabled') - ->setRequired(false) - ->setLabel(_("Feed URL")) - ->setValue($url); - $this->addElement($feedUrl); } } \ No newline at end of file diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index 82731f524..5757171b0 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -1572,6 +1572,9 @@ class Application_Model_Preference self::setValue("station_podcast_download_counter", empty($c) ? 0 : --$c); } + /** + * @return int either 0 (public) or 1 (private) + */ public static function getStationPodcastPrivacy() { if (!Billing::isStationPodcastAllowed()) { // return private setting diff --git a/airtime_mvc/application/models/Scheduler.php b/airtime_mvc/application/models/Scheduler.php index de3b73ca1..f3f0c508c 100644 --- a/airtime_mvc/application/models/Scheduler.php +++ b/airtime_mvc/application/models/Scheduler.php @@ -482,10 +482,15 @@ class Application_Model_Scheduler ->orderByDbStarts() ->find($this->con); + $now = new DateTime("now", new DateTimeZone("UTC")); $itemStartDT = $instance->getDbStarts(null); foreach ($schedule as $item) { $itemEndDT = $this->findEndTime($itemStartDT, $item->getDbClipLength()); - Logging::info($itemEndDT); + // If the track has already ended, don't change it. + if ($itemEndDT < $now) { + $itemStartDT = $itemEndDT; + continue; + } $item->setDbStarts($itemStartDT) ->setDbEnds($itemEndDT) ->save($this->con); @@ -515,10 +520,15 @@ class Application_Model_Scheduler ->orderByDbStarts() ->find($this->con); + $now = new DateTime("now", new DateTimeZone("UTC")); $itemStartDT = $instance->getDbStarts(null); foreach ($schedule as $item) { - $itemEndDT = $this->findEndTime($itemStartDT, $item->getDbClipLength()); + // If the track has already ended, don't change it. + if ($itemEndDT < $now) { + $itemStartDT = $itemEndDT; + continue; + } $item->setDbStarts($itemStartDT) ->setDbEnds($itemEndDT); @@ -1191,7 +1201,7 @@ class Application_Model_Scheduler foreach ($removedItems as $removedItem) { $instance = $removedItem->getCcShowInstances($this->con); - $effectedInstanceIds[] = $instance->getDbId(); + $effectedInstanceIds[$instance->getDbId()] = $instance->getDbId(); //check if instance is linked and if so get the schedule items //for all linked instances so we can delete them too diff --git a/airtime_mvc/application/services/MediaService.php b/airtime_mvc/application/services/MediaService.php index e1712c92d..d5d43c9c7 100644 --- a/airtime_mvc/application/services/MediaService.php +++ b/airtime_mvc/application/services/MediaService.php @@ -133,17 +133,23 @@ class Application_Service_MediaService ->filterByDbImportStatus(CcFiles::IMPORT_STATUS_PENDING) ->filterByDbUtime($oneHourAgo, Criteria::LESS_EQUAL) ->find(); - return !empty(self::$_pendingFiles); + $pendingEpisodes = Application_Service_PodcastEpisodeService::getStuckPendingImports(); + return !empty(self::$_pendingFiles) && !empty($pendingEpisodes); } /** * Clean up stuck imports by changing their import status to Failed */ public static function clearStuckPendingImports() { - foreach(self::$_pendingFiles as $file) { + $pendingEpisodes = Application_Service_PodcastEpisodeService::getStuckPendingImports(); + foreach (self::$_pendingFiles as $file) { /** @var $file CcFiles */ $file->setDbImportStatus(CcFiles::IMPORT_STATUS_FAILED)->save(); } + foreach ($pendingEpisodes as $episode) { + /** @var $episode PodcastEpisodes */ + $episode->delete(); + } } } diff --git a/airtime_mvc/application/services/PodcastEpisodeService.php b/airtime_mvc/application/services/PodcastEpisodeService.php index 56298e467..313518744 100644 --- a/airtime_mvc/application/services/PodcastEpisodeService.php +++ b/airtime_mvc/application/services/PodcastEpisodeService.php @@ -12,6 +12,8 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir const DOWNLOAD = 'download'; + const PENDING_EPISODE_TIMEOUT_SECONDS = 3600; + /** * @var string service name to store in ThirdPartyTrackReferences database */ @@ -143,7 +145,11 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir 'callback_url' => Application_Common_HTTPHelper::getStationUrl() . '/rest/media', 'api_key' => $apiKey = $CC_CONFIG["apiKey"][0], ); - $this->_executeTask(static::$_CELERY_TASKS[self::DOWNLOAD], $data); + $task = $this->_executeTask(static::$_CELERY_TASKS[self::DOWNLOAD], $data); + // Get the created ThirdPartyTaskReference and set the episode ID so + // we can remove the placeholder if the import ends up stuck in a pending state + $ref = ThirdPartyTrackReferencesQuery::create()->findPk($task->getDbTrackReference()); + $ref->setDbForeignId($id)->save(); } /** @@ -161,6 +167,7 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir */ public function updateTrackReference($task, $episodeId, $episode, $status) { $ref = parent::updateTrackReference($task, $episodeId, $episode, $status); + $ref->setDbForeignId($episode->episodeid)->save(); $dbEpisode = PodcastEpisodesQuery::create()->findOneByDbId($episode->episodeid); try { @@ -231,6 +238,32 @@ class Application_Service_PodcastEpisodeService extends Application_Service_Thir return (int) $stationPodcast->hasEpisodeForFile($fileId); } + /** + * Find any episode placeholders that have been stuck pending (empty file ID) for over an hour + * + * @return array the episode imports stuck in pending + */ + public static function getStuckPendingImports() { + $oneHourAgo = gmdate(DEFAULT_TIMESTAMP_FORMAT, (microtime(true) - self::PENDING_EPISODE_TIMEOUT_SECONDS)); + $episodes = PodcastEpisodesQuery::create() + ->filterByDbFileId() + ->find(); + $stuckImports = array(); + foreach ($episodes as $episode) { + $ref = ThirdPartyTrackReferencesQuery::create() + ->findOneByDbForeignId(strval($episode->getDbId())); + if (!empty($ref)) { + $task = CeleryTasksQuery::create() + ->filterByDbDispatchTime($oneHourAgo, Criteria::LESS_EQUAL) + ->findOneByDbTrackReference($ref->getDbId()); + if (!empty($task)) { + array_push($stuckImports, $episode); + } + } + } + return $stuckImports; + } + /** * @param $episodeId * @return array diff --git a/airtime_mvc/application/services/ThirdPartyCeleryService.php b/airtime_mvc/application/services/ThirdPartyCeleryService.php index f1f3f709a..e84645086 100644 --- a/airtime_mvc/application/services/ThirdPartyCeleryService.php +++ b/airtime_mvc/application/services/ThirdPartyCeleryService.php @@ -20,15 +20,20 @@ abstract class Application_Service_ThirdPartyCeleryService extends Application_S * @param string $taskName the name of the celery task to execute * @param array $data the data array to send as task parameters * @param int $fileId the unique identifier for the file involved in the task + * + * @return CeleryTasks the created task + * + * @throws Exception */ protected function _executeTask($taskName, $data, $fileId = null) { try { $brokerTaskId = CeleryManager::sendCeleryMessage($taskName, static::$_CELERY_EXCHANGE_NAME, $data); - $this->_createTaskReference($fileId, $brokerTaskId, $taskName); + return $this->_createTaskReference($fileId, $brokerTaskId, $taskName); } catch (Exception $e) { - Logging::info("Invalid request: " . $e->getMessage()); + Logging::error("Invalid request: " . $e->getMessage()); + throw $e; } } @@ -41,6 +46,8 @@ abstract class Application_Service_ThirdPartyCeleryService extends Application_S * receive completed task messages * @param $taskName string broker task name * + * @return CeleryTasks the created task + * * @throws Exception * @throws PropelException */ @@ -54,6 +61,7 @@ abstract class Application_Service_ThirdPartyCeleryService extends Application_S $task->setDbStatus(CELERY_PENDING_STATUS); $task->setDbTrackReference($trackReferenceId); $task->save(); + return $task; } /** diff --git a/airtime_mvc/application/services/ThirdPartyService.php b/airtime_mvc/application/services/ThirdPartyService.php index 1fca386f5..61a979ea6 100644 --- a/airtime_mvc/application/services/ThirdPartyService.php +++ b/airtime_mvc/application/services/ThirdPartyService.php @@ -30,12 +30,10 @@ abstract class Application_Service_ThirdPartyService { public function createTrackReference($fileId) { // First, check if the track already has an entry in the database // If the file ID given is null, create a new reference - $ref = is_null($fileId) ? null : ThirdPartyTrackReferencesQuery::create() - ->filterByDbService(static::$_SERVICE_NAME) - ->findOneByDbFileId($fileId); - if (is_null($ref)) { - $ref = new ThirdPartyTrackReferences(); - } + $ref = is_null($fileId) ? new ThirdPartyTrackReferences() + : ThirdPartyTrackReferencesQuery::create() + ->filterByDbService(static::$_SERVICE_NAME) + ->findOneByDbFileId($fileId); $ref->setDbService(static::$_SERVICE_NAME); $ref->setDbFileId($fileId); $ref->save(); diff --git a/airtime_mvc/application/views/scripts/billing/upgrade.phtml b/airtime_mvc/application/views/scripts/billing/upgrade.phtml index 83077cb9e..b3b6b09f0 100644 --- a/airtime_mvc/application/views/scripts/billing/upgrade.phtml +++ b/airtime_mvc/application/views/scripts/billing/upgrade.phtml @@ -193,13 +193,13 @@ $(document).ready(function() {