diff --git a/airtime_mvc/application/Bootstrap.php b/airtime_mvc/application/Bootstrap.php index 510e591f5..2a82ca501 100644 --- a/airtime_mvc/application/Bootstrap.php +++ b/airtime_mvc/application/Bootstrap.php @@ -14,8 +14,7 @@ if (!isset($configRun) || !$configRun) { require_once 'autoload.php'; require_once CONFIG_PATH . "constants.php"; -require_once 'Preference.php'; -require_once 'Locale.php'; +/* Common */ require_once "DateHelper.php"; require_once "LocaleHelper.php"; require_once "FileDataHelper.php"; @@ -27,15 +26,20 @@ require_once "ProvisioningHelper.php"; require_once "SecurityHelper.php"; require_once "GoogleAnalytics.php"; require_once "Timezone.php"; -require_once "Auth.php"; -require_once "interface/OAuth2.php"; -require_once "interface/OAuth2Controller.php"; +require_once "CeleryManager.php"; require_once "TaskManager.php"; require_once "UsabilityHints.php"; -require_once "MediaType.php"; require_once __DIR__.'/models/formatters/LengthFormatter.php'; -require_once __DIR__.'/services/CeleryManager.php'; -require_once __DIR__.'/services/SoundcloudService.php'; +/* Models */ +require_once "Auth.php"; +require_once 'Preference.php'; +require_once 'Locale.php'; +/* Enums */ +require_once "MediaType.php"; +/* Interfaces */ +require_once "OAuth2.php"; +require_once "OAuth2Controller.php"; + require_once __DIR__.'/forms/helpers/ValidationTypes.php'; require_once __DIR__.'/forms/helpers/CustomDecorators.php'; require_once __DIR__.'/controllers/plugins/RabbitMqPlugin.php'; diff --git a/airtime_mvc/application/services/CeleryManager.php b/airtime_mvc/application/common/CeleryManager.php similarity index 100% rename from airtime_mvc/application/services/CeleryManager.php rename to airtime_mvc/application/common/CeleryManager.php diff --git a/airtime_mvc/application/configs/ACL.php b/airtime_mvc/application/configs/ACL.php index 6a2215468..91fee1194 100644 --- a/airtime_mvc/application/configs/ACL.php +++ b/airtime_mvc/application/configs/ACL.php @@ -41,6 +41,7 @@ $ccAcl->add(new Zend_Acl_Resource('library')) ->add(new Zend_Acl_Resource('thank-you')) ->add(new Zend_Acl_Resource('provisioning')) ->add(new Zend_Acl_Resource('player')) + ->add(new Zend_Acl_Resource('render')) ->add(new Zend_Acl_Resource('soundcloud')) ->add(new Zend_Acl_Resource('embeddablewidgets')) ->add(new Zend_Acl_Resource('setup')); @@ -52,6 +53,7 @@ $ccAcl->allow('G', 'index') ->allow('G', 'error') ->allow('G', 'user', 'edit-user') ->allow('G', 'showbuilder') + ->allow('G', 'render') ->allow('G', 'api') ->allow('G', 'schedule') ->allow('G', 'dashboard') @@ -63,13 +65,16 @@ $ccAcl->allow('G', 'index') ->allow('G', 'downgrade') ->allow('G', 'rest:show-image', 'get') ->allow('G', 'rest:media', 'get') - ->allow('G', 'rest:podcast', 'index') +// ->allow('G', 'rest:podcast', 'index') + ->allow('G', 'rest:podcast', 'get') ->allow('G', 'rest:podcast-episodes', 'get') ->allow('G', 'setup') ->allow('G', 'embeddablewidgets') ->allow('H', 'soundcloud') ->allow('H', 'rest:show-image') ->allow('H', 'rest:media') + ->allow('H', 'rest:podcast') + ->allow('H', 'rest:podcast-episodes') ->allow('H', 'preference', 'is-import-in-progress') ->allow('H', 'usersettings') ->allow('H', 'plupload') diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php index 1c85621e7..ad3d5cffd 100644 --- a/airtime_mvc/application/controllers/LibraryController.php +++ b/airtime_mvc/application/controllers/LibraryController.php @@ -133,7 +133,7 @@ class LibraryController extends Zend_Controller_Action // SOUNDCLOUD MENU OPTION $ownerId = empty($obj) ? $file->getFileOwnerId() : $obj->getCreatorId(); if ($isAdminOrPM || $ownerId == $user->getId()) { - $soundcloudService = new SoundcloudService(); + $soundcloudService = new Application_Service_SoundcloudService(); if ($type === "audioclip" && $soundcloudService->hasAccessToken()) { //create a menu separator diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php index 6df8efb80..6a1f8efc3 100644 --- a/airtime_mvc/application/controllers/ShowbuilderController.php +++ b/airtime_mvc/application/controllers/ShowbuilderController.php @@ -65,12 +65,13 @@ class ShowbuilderController extends Zend_Controller_Action // MEDIA BUILDER $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/spl.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); + $this->view->headScript()->appendFile($baseUrl.'js/airtime/library/podcast.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headScript()->appendFile($baseUrl.'js/airtime/playlist/smart_blockbuilder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript'); $this->view->headLink()->appendStylesheet($baseUrl.'css/playlist_builder.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'css/jquery.ui.timepicker.css?'.$CC_CONFIG['airtime_version']); $this->view->headLink()->appendStylesheet($baseUrl.'css/showbuilder.css?'.$CC_CONFIG['airtime_version']); - $this->view->headLink()->appendStylesheet($baseUrl.'css/dashboard.css?'.$CC_CONFIG['airtime_version']); // TODO + $this->view->headLink()->appendStylesheet($baseUrl.'css/dashboard.css?'.$CC_CONFIG['airtime_version']); $csrf_namespace = new Zend_Session_Namespace('csrf_namespace'); $csrf_element = new Zend_Form_Element_Hidden('csrf'); diff --git a/airtime_mvc/application/controllers/SoundcloudController.php b/airtime_mvc/application/controllers/SoundcloudController.php index 5f9d89585..e3c31d72c 100644 --- a/airtime_mvc/application/controllers/SoundcloudController.php +++ b/airtime_mvc/application/controllers/SoundcloudController.php @@ -6,7 +6,7 @@ require_once "ise/php-soundcloud/src/Soundcloud/Service.php"; class SoundcloudController extends ThirdPartyController implements OAuth2Controller { /** - * @var SoundcloudService + * @var Application_Service_SoundcloudService */ protected $_service; @@ -20,7 +20,7 @@ class SoundcloudController extends ThirdPartyController implements OAuth2Control */ public function init() { parent::init(); - $this->_service = new SoundcloudService(); + $this->_service = new Application_Service_SoundcloudService(); } /** diff --git a/airtime_mvc/application/controllers/ThirdPartyController.php b/airtime_mvc/application/controllers/ThirdPartyController.php index 7189b8c35..384235038 100644 --- a/airtime_mvc/application/controllers/ThirdPartyController.php +++ b/airtime_mvc/application/controllers/ThirdPartyController.php @@ -11,7 +11,7 @@ abstract class ThirdPartyController extends Zend_Controller_Action { protected $_baseUrl; /** - * @var ThirdPartyService third party service object + * @var Application_Service_ThirdPartyService third party service object */ protected $_service; diff --git a/airtime_mvc/application/services/CeleryServiceFactory.php b/airtime_mvc/application/services/CeleryServiceFactory.php index defb6ce81..6293a15ab 100644 --- a/airtime_mvc/application/services/CeleryServiceFactory.php +++ b/airtime_mvc/application/services/CeleryServiceFactory.php @@ -7,12 +7,12 @@ class CeleryServiceFactory { * * @param $serviceName string the name of the service to create * - * @return ThirdPartyCeleryService|null + * @return Application_Service_ThirdPartyCeleryService|null */ public static function getService($serviceName) { switch($serviceName) { case SOUNDCLOUD_SERVICE_NAME: - return new SoundcloudService(); + return new Application_Service_SoundcloudService(); } return null; } diff --git a/airtime_mvc/application/services/SoundcloudService.php b/airtime_mvc/application/services/SoundcloudService.php index 53daf9fc7..aba8d2b98 100644 --- a/airtime_mvc/application/services/SoundcloudService.php +++ b/airtime_mvc/application/services/SoundcloudService.php @@ -2,7 +2,7 @@ require_once "ThirdPartyCeleryService.php"; -class SoundcloudService extends ThirdPartyCeleryService implements OAuth2 { +class Application_Service_SoundcloudService extends Application_Service_ThirdPartyCeleryService implements OAuth2 { /** * @var string service access token for accessing remote API diff --git a/airtime_mvc/application/services/ThirdPartyCeleryService.php b/airtime_mvc/application/services/ThirdPartyCeleryService.php index 24e9a5800..8ecf512ff 100644 --- a/airtime_mvc/application/services/ThirdPartyCeleryService.php +++ b/airtime_mvc/application/services/ThirdPartyCeleryService.php @@ -2,7 +2,7 @@ require_once "ThirdPartyService.php"; -abstract class ThirdPartyCeleryService extends ThirdPartyService { +abstract class Application_Service_ThirdPartyCeleryService extends Application_Service_ThirdPartyService { /** * @var string broker exchange name for third-party tasks diff --git a/airtime_mvc/application/services/ThirdPartyService.php b/airtime_mvc/application/services/ThirdPartyService.php index 523e0e5cc..466838db5 100644 --- a/airtime_mvc/application/services/ThirdPartyService.php +++ b/airtime_mvc/application/services/ThirdPartyService.php @@ -8,7 +8,7 @@ class ServiceNotFoundException extends Exception {} /** * Class ThirdPartyService generic superclass for third-party services */ -abstract class ThirdPartyService { +abstract class Application_Service_ThirdPartyService { /** * @var string service access token for accessing third-party API diff --git a/airtime_mvc/application/views/scripts/form/preferences_soundcloud.phtml b/airtime_mvc/application/views/scripts/form/preferences_soundcloud.phtml index 2697a6508..7cafb2ced 100644 --- a/airtime_mvc/application/views/scripts/form/preferences_soundcloud.phtml +++ b/airtime_mvc/application/views/scripts/form/preferences_soundcloud.phtml @@ -1,7 +1,7 @@
hasAccessToken()) { echo $this->element->getElement('SoundCloudDisconnect')->render(); } else { diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index c5e998144..65442583d 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -1249,20 +1249,28 @@ var AIRTIME = (function(AIRTIME) { ]; var ajaxSourceURL = baseUrl+"rest/podcast"; - var podcastTolbarButtons = AIRTIME.widgets.Table.getStandardToolbarButtons(); - podcastTolbarButtons[AIRTIME.widgets.Table.TOOLBAR_BUTTON_ROLES.NEW].eventHandlers.click = function(e) { alert('New!'); }; - podcastTolbarButtons[AIRTIME.widgets.Table.TOOLBAR_BUTTON_ROLES.EDIT].eventHandlers.click = function(e) { alert('Edit!'); }; - podcastTolbarButtons[AIRTIME.widgets.Table.TOOLBAR_BUTTON_ROLES.DELETE].eventHandlers.click = function(e) { alert('Delete!'); }; + var podcastToolbarButtons = AIRTIME.widgets.Table.getStandardToolbarButtons(); + podcastToolbarButtons[AIRTIME.widgets.Table.TOOLBAR_BUTTON_ROLES.NEW].eventHandlers.click = function(e) { + AIRTIME.podcast.createUrlDialog(); + }; + podcastToolbarButtons[AIRTIME.widgets.Table.TOOLBAR_BUTTON_ROLES.EDIT].eventHandlers.click = function(e) { + AIRTIME.podcast.editSelectedPodcasts(); + }; + podcastToolbarButtons[AIRTIME.widgets.Table.TOOLBAR_BUTTON_ROLES.DELETE].eventHandlers.click = function(e) { + AIRTIME.podcast.deleteSelectedPodcasts(); + }; //Set up the div with id "podcast_table" as a datatable. - mod.podcastDataTable = new AIRTIME.widgets.Table( + mod.podcastTableWidget = new AIRTIME.widgets.Table( $('#podcast_table'), //DOM node to create the table inside. true, //Enable item selection - podcastTolbarButtons, //Toolbar buttons + podcastToolbarButtons, //Toolbar buttons { //Datatables overrides. 'aoColumns' : aoColumns, 'sAjaxSource' : ajaxSourceURL }); + + mod.podcastDataTable = mod.podcastTableWidget.getDatatable(); } diff --git a/airtime_mvc/public/js/airtime/library/podcast.js b/airtime_mvc/public/js/airtime/library/podcast.js new file mode 100644 index 000000000..e80b927ca --- /dev/null +++ b/airtime_mvc/public/js/airtime/library/podcast.js @@ -0,0 +1,114 @@ +var endpoint = 'rest/podcast/'; + +var podcastApp = angular.module('podcast', []) + .controller('RestController', function($scope, $http, podcast) { + $scope.podcast = podcast; + console.log(podcast); + AIRTIME.tabs.setActiveTabName($scope.podcast.title); + + $scope.put = function() { + $http.put(endpoint + $scope.podcast.id, { csrf_token: $("#csrf").val(), podcast: $scope.podcast }) + .success(function() { + AIRTIME.tabs.setActiveTabName($scope.podcast.title); + // TODO + }); + }; + + $scope.discard = function() { + AIRTIME.tabs.closeTab(); + $scope.podcast = {}; + }; + }); + +var AIRTIME = (function (AIRTIME) { + var mod; + + if (AIRTIME.podcast === undefined) { + AIRTIME.podcast = {}; + } + + mod = AIRTIME.podcast; + + function _bulkAction(method, callback) { + var selected = $("#podcast_table").find(".selected"), + ids = []; + var selectedData = AIRTIME.library.podcastTableWidget.getSelectedRows(); + selectedData.forEach(function(el) { + ids.push(el.id); + }); + + // Bulk methods should use post because we're sending data in the request body + $.post(endpoint + "bulk", { csrf_token: $("#csrf").val(), method: method, ids: ids }, callback); + } + + function _bootstrapAngularApp(podcast) { + podcastApp.value('podcast', JSON.parse(podcast)); + angular.bootstrap(document.getElementById("podcast-wrapper"), ["podcast"]); + } + + mod.createUrlDialog = function() { + $.get('/render/podcast-url-dialog', function(json) { + $(document.body).append(json.html); + $("#podcast_url_dialog").dialog({ + title: $.i18n._("Add New Podcast"), + resizable: false, + modal: true, + width: 'auto', + height: 'auto' + }); + }); + }; + + mod.addPodcast = function() { + $.post(endpoint, $("#podcast_url_dialog").find("form").serialize(), function(json) { + AIRTIME.tabs.openTab(json, AIRTIME.podcast.init); + _bootstrapAngularApp(json.podcast); + $("#podcast_url_dialog").dialog("close"); + }); + }; + + mod.editSelectedPodcasts = function() { + _bulkAction("GET", function(json) { + json.forEach(function(el) { + AIRTIME.tabs.openTab(el, AIRTIME.podcast.init); + _bootstrapAngularApp(el.podcast); + }); + }); + }; + + mod.deleteSelectedPodcasts = function() { + if (confirm($.i18n._("Are you sure you want to delete the selected podcasts from your library?"))) { + _bulkAction("DELETE", function () { + AIRTIME.library.podcastDataTable.fnDraw(); + }); + } + }; + + /* + * Callback when creating podcast tabs to initialize bindings + */ + mod.init = function(newTab) { + // FIXME: get rid of this duplication by abstracting out functionality in tabs + newTab.tab.on("click", function() { + if (!$(this).hasClass('active')) { + AIRTIME.tabs.switchTab(newTab.pane, newTab.tab); + } + }); + + $(".lib_pl_close").unbind().click(function(e) { + e.preventDefault(); + e.stopPropagation(); + $(this).unbind("click"); // Prevent repeated clicks in quick succession from closing multiple tabs + + var tabId = $(this).closest("li").attr("data-tab-id"); + + // We need to update the text on the add button + AIRTIME.library.checkAddButton(); + // We also need to run the draw callback to update how dragged items are drawn + AIRTIME.library.fnDrawCallback(); + AIRTIME.tabs.closeTab(tabId); + }); + }; + + return AIRTIME; +}(AIRTIME || {})); diff --git a/airtime_mvc/public/js/airtime/widgets/table.js b/airtime_mvc/public/js/airtime/widgets/table.js index 667b7f7db..f2ffb4f54 100644 --- a/airtime_mvc/public/js/airtime/widgets/table.js +++ b/airtime_mvc/public/js/airtime/widgets/table.js @@ -85,7 +85,8 @@ var AIRTIME = (function(AIRTIME) { self._setupEventHandlers(bItemSelection); - return self._datatable; + //return self._datatable; + return self; }; //TODO: Wrap everything into the prototype @@ -102,7 +103,7 @@ var AIRTIME = (function(AIRTIME) { */ if (bItemSelection) { $(self._datatable, 'tbody tr').on('click contextmenu', 'tr', function (e) { - var aData = $(this).data(); //Neat trick - thanks DataTables! + var aData = self._datatable.fnGetData($(this).index()); // $(this).data(); //Neat trick - thanks DataTables! var iDisplayIndex = $(this).index(); //The index of the row in the current page in the table. var nRow = this; @@ -127,7 +128,7 @@ var AIRTIME = (function(AIRTIME) { $this = $(this); var iVisualRowIdx = $this.parent().parent().index(); - var aData = $this.parent().parent().data(); + var aData = self._datatable.fnGetData(iVisualRowIdx); var selectionMode = self.SELECTION_MODE.MULTI_CTRL; //Behaviour for checkboxes. if (e.shiftKey) { selectionMode = self.SELECTION_MODE.MULTI_SHIFT; @@ -408,6 +409,12 @@ var AIRTIME = (function(AIRTIME) { }; + //Accessors / Mutators + + Table.prototype.getDatatable = function() { + return this._datatable; + }; + //Static initializers / Class variables