diff --git a/airtime_mvc/application/modules/rest/Bootstrap.php b/airtime_mvc/application/modules/rest/Bootstrap.php index 08e249970..808912c9a 100644 --- a/airtime_mvc/application/modules/rest/Bootstrap.php +++ b/airtime_mvc/application/modules/rest/Bootstrap.php @@ -84,5 +84,18 @@ class Rest_Bootstrap extends Zend_Application_Module_Bootstrap ) ); $router->addRoute('publish', $publishRoute); + + $publishSourcesRoute = new Zend_Controller_Router_Route( + 'rest/media/:id/publish-sources', + array( + 'controller' => 'media', + 'action' => 'publish-sources', + 'module' => 'rest' + ), + array( + 'id' => '\d+' + ) + ); + $router->addRoute('publish-sources', $publishSourcesRoute); } } diff --git a/airtime_mvc/application/modules/rest/controllers/MediaController.php b/airtime_mvc/application/modules/rest/controllers/MediaController.php index b0357af5e..2e6e49110 100644 --- a/airtime_mvc/application/modules/rest/controllers/MediaController.php +++ b/airtime_mvc/application/modules/rest/controllers/MediaController.php @@ -200,7 +200,7 @@ class Rest_MediaController extends Zend_Rest_Controller try { // Is there a better way to do this? $data = json_decode($this->getRequest()->getRawBody(), true)["sources"]; - Application_Service_MediaService::publish($id, $data); + Application_Service_PublishService::publish($id, $data); $this->getResponse() ->setHttpResponseCode(200); } catch (Exception $e) { @@ -209,6 +209,15 @@ class Rest_MediaController extends Zend_Rest_Controller } } + public function publishSourcesAction() { + $id = $this->_getParam('id', false); + $sources = Application_Service_PublishService::getSourceLists($id); + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody(json_encode($sources)); + + } + private function getId() { if (!$id = $this->_getParam('id', false)) { diff --git a/airtime_mvc/application/services/MediaService.php b/airtime_mvc/application/services/MediaService.php index 40464f1a9..1bd3e6772 100644 --- a/airtime_mvc/application/services/MediaService.php +++ b/airtime_mvc/application/services/MediaService.php @@ -111,19 +111,5 @@ class Application_Service_MediaService } } - /** - * Publish or remove the file with the given file ID from the services - * specified in the request data (ie. SoundCloud, the station podcast) - * - * @param int $fileId ID of the file to be published - * @param array $data request data containing what services to publish to - */ - public static function publish($fileId, $data) { - foreach ($data as $k => $v) { - $service = PublishServiceFactory::getService($k); - $service->$v($fileId); - } - } - } diff --git a/airtime_mvc/application/services/PublishService.php b/airtime_mvc/application/services/PublishService.php new file mode 100644 index 000000000..5f21b4ddd --- /dev/null +++ b/airtime_mvc/application/services/PublishService.php @@ -0,0 +1,105 @@ + SOUNDCLOUD, + "station_podcast" => "My Station Podcast" + ); + + /** + * @var array map of arbitrary source names to functions that return + * their publication state (true = published) + */ + private static $SOURCE_FUNCTIONS = array( + "soundcloud" => "getSoundCloudPublishStatus", + "station_podcast" => "getStationPodcastPublishStatus" + ); + + /** + * Publish or remove the file with the given file ID from the services + * specified in the request data (ie. SoundCloud, the station podcast) + * + * @param int $fileId ID of the file to be published + * @param array $data request data containing what services to publish to + */ + public static function publish($fileId, $data) { + foreach ($data as $k => $v) { + $service = PublishServiceFactory::getService($k); + if ($v) $service->publish($fileId); + } + } + + /** + * For the file with the given ID, check external sources and generate + * an array of source states and labels. + * + * Sources to which the file has been published should be passed back in a + * "published" array, while sources to which the file has not been published + * should be passed back in a "toPublish" array. + * + * @param int $fileId the ID of the file to check + * + * @return array array containing published and toPublish arrays. Has the form + * [ + * "toPublish" => [ + * "source" => "label", + * ... + * ] + * "published" => [ + * "source" => "label", + * ... + * ] + * ] + */ + public static function getSourceLists($fileId) { + $publishSources = $publishedSources = array(); + foreach (self::$SOURCES as $source => $label) { + $fn = self::$SOURCE_FUNCTIONS[$source]; + // Should be in a ternary but PHP doesn't play nice + if (self::$fn($fileId)) { + $publishedSources[$source] = _($label); + } else { + $publishSources[$source] = _($label); + } + } + + return array( + "toPublish" => $publishSources, + "published" => $publishedSources + ); + } + + /** @noinspection PhpUnusedPrivateMethodInspection + * Reflective accessor for SoundCloud publication status for the + * file with the given ID + * + * @param int $fileId the ID of the file to check + * + * @return bool true if the file has been published to SoundCloud, + * otherwise false + */ + private static function getSoundCloudPublishStatus($fileId) { + $soundcloudService = new Application_Service_SoundcloudService(); + return ($soundcloudService->getServiceId($fileId) != 0); + } + + /** @noinspection PhpUnusedPrivateMethodInspection + * Reflective accessor for Station podcast publication status for the + * file with the given ID + * + * @param int $fileId the ID of the file to check + * + * @return bool true if the file has been published to the Station podcast, + * otherwise false + */ + private static function getStationPodcastPublishStatus($fileId) { + $stationPodcast = StationPodcastQuery::create() + ->findOneByDbPodcastId(Application_Model_Preference::getStationPodcastId()); + return $stationPodcast->hasEpisodeForFile($fileId); + } + +} diff --git a/airtime_mvc/application/views/scripts/library/publish-dialog.phtml b/airtime_mvc/application/views/scripts/library/publish-dialog.phtml index ad9d10131..15911a68a 100644 --- a/airtime_mvc/application/views/scripts/library/publish-dialog.phtml +++ b/airtime_mvc/application/views/scripts/library/publish-dialog.phtml @@ -16,12 +16,27 @@
- -
- - +
+ +
+
+
+ " + . "Published tracks can be removed or updated below.") ?> +
+
+
+ +
+ + {{label}} + +
+
+ " + . "Check the boxes above and hit 'Publish' to publish this track to the marked sources.") ?> +
- diff --git a/airtime_mvc/public/css/styles.css b/airtime_mvc/public/css/styles.css index eeecf8e9e..fbba3eb85 100644 --- a/airtime_mvc/public/css/styles.css +++ b/airtime_mvc/public/css/styles.css @@ -3991,3 +3991,15 @@ li .ui-state-hover { /* jQuery dialog */ .no-close .ui-dialog-titlebar-close {display: none } + +/* Publishing Dialog */ +.published-sources { + color: #efefef; + font-size: 14px; + line-height: 26px; +} + +.published-sources > .checked-icon { + height: 26px; + padding-right: 8px; +} \ No newline at end of file diff --git a/airtime_mvc/public/js/airtime/library/podcast.js b/airtime_mvc/public/js/airtime/library/podcast.js index 7364abbb2..cab96932e 100644 --- a/airtime_mvc/public/js/airtime/library/podcast.js +++ b/airtime_mvc/public/js/airtime/library/podcast.js @@ -21,7 +21,7 @@ var AIRTIME = (function (AIRTIME) { tab.setName($scope.podcast.title); $scope.csrf = jQuery("#csrf").val(); tab.contents.find("table").attr("id", "podcast_episodes_" + podcast.id); - var episodeTable = AIRTIME.podcast.initPodcastEpisodeDatatable(podcast.episodes, tab); + var episodeTable = AIRTIME.podcast.initPodcastEpisodeDatatable(podcast, tab); // Override the switchTo function to reload the table when the tab is focused. // Should help to reduce the number of cases where the frontend doesn't match the state @@ -162,7 +162,7 @@ var AIRTIME = (function (AIRTIME) { } }; - mod.initPodcastEpisodeDatatable = function(episodes, tab) { + mod.initPodcastEpisodeDatatable = function(podcast, tab) { var aoColumns = [ /* GUID */ { "sTitle" : "" , "mDataProp" : "guid" , "sClass" : "podcast_episodes_guid" , "bVisible" : false }, /* Title */ { "sTitle" : $.i18n._("Title") , "mDataProp" : "title" , "sClass" : "podcast_episodes_title" , "sWidth" : "170px" }, @@ -194,7 +194,7 @@ var AIRTIME = (function (AIRTIME) { // as json. Doing this caches all the episode data on the front-end, // which means we also don't need to go back to the server for pagination 'sAjaxSource' : null, - 'aaData' : episodes, + 'aaData' : podcast.episodes, "oColVis": { "sAlign": "right", "aiExclude": [0, 1], diff --git a/airtime_mvc/public/js/airtime/library/publish.js b/airtime_mvc/public/js/airtime/library/publish.js index 4b50abc57..021e5d7bc 100644 --- a/airtime_mvc/public/js/airtime/library/publish.js +++ b/airtime_mvc/public/js/airtime/library/publish.js @@ -15,34 +15,51 @@ var AIRTIME = (function (AIRTIME) { //AngularJS app var publishApp = angular.module(PUBLISH_APP_NAME, []) - .controller('RestController', function($scope, $http, mediaId, tab) { + .controller('RestController', function ($scope, $http, mediaId, tab) { $scope.publishSources = {}; - $http.get(endpoint + mediaId, { csrf_token: jQuery("#csrf").val() }) - .success(function(json) { - console.log(json); - $scope.media = json; - tab.setName($scope.media.track_title); - }); + function init () { + $http.get(endpoint + mediaId, { csrf_token: jQuery("#csrf").val() }) + .success(function (json) { + console.log(json); + $scope.media = json; + tab.setName($scope.media.track_title); + }); - // TODO: implement GET request to endpoint that returns source information - // ie. SoundCloud connection + publish status + // Get an object containing all sources, their translated labels, + // and their publication state for the file with the given ID + $http.get(endpoint + mediaId + '/publish-sources', { csrf_token: jQuery("#csrf").val() }) + .success(function (json) { + $scope.sources = json; + // Store the data (whether each source should be published to when publish is clicked) + // in a separate array so we don't overwrite the labels + $scope.publishData = {}; + jQuery.each($scope.sources.toPublish, function (k, v) { + $scope.publishData[k] = false; + }); + }); + } - $scope.publish = function() { - var sources = {}; - $.each($scope.publishSources, function(k, v) { - if (v) sources[k] = 'publish'; // Tentative TODO: decide on a robust implementation - }); - $http.put(endpoint + $scope.media.id + '/publish', { csrf_token: jQuery("#csrf").val(), sources: sources }) - .success(function() { - // TODO + $scope.publish = function () { + $http.put(endpoint + mediaId + '/publish', + { + csrf_token: jQuery("#csrf").val(), + sources: $scope.publishData + }).success(function () { + init(); }); }; - $scope.discard = function() { + $scope.remove = function (source) { + // TODO + }; + + $scope.discard = function () { tab.close(); $scope.media = {}; }; + + init(); });