diff --git a/composer.json b/composer.json index d70a547..5c6f5f0 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "moon/pbs-media-manager-craft-gacraft", - "description": "Media Manager 3 for PBS API", - "version": "3.3.1", + "description": "Media Manager 4 for PBS API", + "version": "4.0.0-beta.1", "type": "craft-plugin", "keywords": ["craftcms", "pbs", "media-manager"], "license": "MIT", @@ -9,18 +9,22 @@ { "name": "Paper Tiger", "homepage": "https://papertiger.com" + }, + { + "name": "Good Work", + "homepage": "https://simplygoodwork.com" } ], "support": { - "email": "info@papertiger.com", - "issues": "https://projects.pbs.org/bitbucket/projects/MOON/repos/pbs-media-manager-craft-plugin/issues", - "source": "https://projects.pbs.org/bitbucket/projects/MOON/repos/pbs-media-manager-craft-plugin/browse", - "docs": "https://projects.pbs.org/bitbucket/projects/MOON/repos/pbs-media-manager-craft-plugin/browse/README.md" + "email": "dev@simplygoodwork.com", + "issues": "https://github.com/pbs/pbs-media-manager-craft-kenburns/issues", + "source": "https://github.com/pbs/pbs-media-manager-craft-kenburns/blob/main/README.md", + "docs": "https://github.com/pbs/pbs-media-manager-craft-kenburns/blob/main/README.md" }, "require": { - "craftcms/cms": ">=3.1.0", - "craftcms/redactor": ">=2.3.0", - "peppeocchi/php-cron-scheduler": "4.*" + "craftcms/cms": "^4.0.0", + "craftcms/redactor": "^3.0.0", + "craftcms/ckeditor": "^3.0.0" }, "autoload": { "psr-4": { @@ -30,7 +34,7 @@ "extra": { "handle": "mediamanager", "name": "Media Manager", - "documentationUrl": "https://projects.pbs.org/bitbucket/projects/MOON/repos/pbs-media-manager-craft-plugin/browse/README.md", + "documentationUrl": "https://github.com/pbs/pbs-media-manager-craft-plugin/blob/main/README.md", "class": "papertiger\\mediamanager\\MediaManager" }, "config": { @@ -38,5 +42,10 @@ "craftcms/plugin-installer": true, "yiisoft/yii2-composer": true } + }, + "minimum-stability": "dev", + "prefer-stable": true, + "require-dev": { + "craftcms/rector": "dev-main" } } diff --git a/src/MediaManager.php b/src/MediaManager.php index f02a319..c4ed8e0 100644 --- a/src/MediaManager.php +++ b/src/MediaManager.php @@ -11,37 +11,36 @@ namespace papertiger\mediamanager; use Craft; -use craft\queue\Queue; -use craft\web\Application; use Exception; -use papertiger\mediamanager\jobs\ShowSync; -use papertiger\mediamanager\variables\MediaManagerVariable; use yii\base\Event; +use Psr\Log\LogLevel; use craft\base\Plugin; use craft\web\UrlManager; +use craft\web\Application; use craft\services\Plugins; -use craft\events\PluginEvent; -use craft\events\ModelEvent; use craft\helpers\UrlHelper; -use craft\services\Utilities; +use craft\log\MonologTarget; +use craft\models\FieldGroup; +use craft\events\PluginEvent; +use Monolog\Formatter\LineFormatter; use craft\events\RegisterUrlRulesEvent; -use craft\events\RegisterComponentTypesEvent; -use craft\web\twig\variables\CraftVariable; -use papertiger\mediamanager\models\SettingsModel; +use papertiger\mediamanager\jobs\ShowSync; +use craft\web\twig\variables\CraftVariable; use papertiger\mediamanager\helpers\SetupHelper; +use papertiger\mediamanager\models\SettingsModel; +use papertiger\mediamanager\base\ConstantAbstract; use papertiger\mediamanager\helpers\SettingsHelper; -use papertiger\mediamanager\helpers\DependencyHelper; use papertiger\mediamanager\behaviors\MediaBehavior; +use papertiger\mediamanager\helpers\DependencyHelper; use papertiger\mediamanager\services\Api as ApiService; use papertiger\mediamanager\services\Show as ShowService; use papertiger\mediamanager\services\ScheduledSyncService; +use papertiger\mediamanager\variables\MediaManagerVariable; use papertiger\mediamanager\services\OldSettings as OldSettingsService; -use papertiger\mediamanager\helpers\aftersavesettings\FieldLayoutHelper; +use papertiger\mediamanager\helpers\aftersavesettings\OldSettingsHelper; use papertiger\mediamanager\helpers\aftersavesettings\ApiColumnFieldsHelper; -use papertiger\mediamanager\helpers\aftersavesettings\ShowFieldLayoutHelper; use papertiger\mediamanager\helpers\aftersavesettings\ShowApiColumnFieldsHelper; -use papertiger\mediamanager\helpers\aftersavesettings\OldSettingsHelper; /** * Class MediaManager @@ -61,10 +60,10 @@ class MediaManager extends Plugin // Public Properties // ========================================================================= - public $hasCpSettings = true; - public $hasCpSection = true; - - public $schemaVersion = '1.0.1'; + public bool $hasCpSettings = true; + public bool $hasCpSection = true; + + public string $schemaVersion = '1.0.1'; // Public Methods // ========================================================================= @@ -83,42 +82,84 @@ public function init() $this->registerBehaviors(); $this->registerPluginServices(); - $fileTarget = new \craft\log\FileTarget([ - 'logFile' => '@storage/logs/media-manager.log', + Craft::getLogger()->dispatcher->targets[] = new MonologTarget([ + 'name' => 'media-manager', 'categories' => ['papertiger\mediamanager\*'], - 'enableRotation' => true, + 'level' => LogLevel::INFO, + 'logContext' => false, + 'allowLineBreaks' => false, + 'formatter' => new LineFormatter( + format: "%datetime% [%level_name%] from %extra.yii_category%: %message%\n", + dateFormat: 'Y-m-d H:i:s', + ), ]); - Craft::getLogger()->dispatcher->targets[] = $fileTarget; // ? ERROR LOG FILE - $errorTarget = new \craft\log\FileTarget([ - 'logFile' => '@storage/logs/media-manager-errors.log', + Craft::getLogger()->dispatcher->targets[] = new MonologTarget([ + 'name' => 'media-manager-errors', 'categories' => ['papertiger\mediamanager\*'], - 'levels' => ['error'], - 'enableRotation' => true, + 'level' => LogLevel::ERROR, + 'logContext' => true, + 'allowLineBreaks' => true, + 'formatter' => new LineFormatter( + format: "%datetime% [%level_name%] from %extra.yii_category%: %message%\n", + dateFormat: 'Y-m-d H:i:s', + ), ]); - Craft::getLogger()->dispatcher->targets[] = $errorTarget; } - public function beforeInstall(): bool + public function beforeInstall(): void { - if( version_compare( Craft::$app->getInfo()->version, '3.0', '<' ) ) { - throw new Exception( 'Media Manager 3 requires Craft CMS 3.0+ in order to run.' ); + if( version_compare( Craft::$app->getInfo()->version, '4.0', '<' ) ) { + throw new Exception( 'Media Manager 4 requires Craft CMS 4.0+ in order to run.' ); } + } + public function afterInstall(): void + { + // create Media Manager field group + $fieldgroup = \craft\records\FieldGroup::find()->where(['name' => ConstantAbstract::DEFAULT_FIELD_GROUP])->one(); - return true; + if(!$fieldgroup) { + $fieldgroup = new FieldGroup(); + $fieldgroup->name = ConstantAbstract::DEFAULT_FIELD_GROUP; + Craft::$app->getFields()->saveGroup($fieldgroup); + } + + foreach(ConstantAbstract::API_COLUMN_FIELDS as $field) { + $fieldExists = Craft::$app->getFields()->getFieldByHandle($field[3]); + + if(!$fieldExists) { + $newField = Craft::$app->getFields()->createField([ + 'type' => $field[4], + 'name' => $field[2], + 'handle' => $field[3], + 'groupId' => $fieldgroup->id + ]); + } + } + + foreach(ConstantAbstract::SHOW_API_COLUMN_FIELDS as $field) { + $fieldExists = Craft::$app->getFields()->getFieldByHandle($field[3]); + + if(!$fieldExists) { + $newField = Craft::$app->getFields()->createField([ + 'type' => $field[4], + 'name' => $field[2], + 'handle' => $field[3], + 'groupId' => $fieldgroup->id + ]); + } + } } - public function afterSaveSettings() + public function afterSaveSettings(): void { ApiColumnFieldsHelper::process(); - FieldLayoutHelper::process(); ShowApiColumnFieldsHelper::process(); - ShowFieldLayoutHelper::process(); OldSettingsHelper::process(); } - public function getSettingsResponse() + public function getSettingsResponse(): mixed { // This way we can have more flexibility on displaying settings template return Craft::$app->controller->renderTemplate( 'mediamanager/settings', SettingsHelper::templateVariables() ); @@ -139,7 +180,7 @@ public function getCpNavItem(): array 'label' => self::t( 'Synchronize' ), 'url' => 'mediamanager/synchronize' ]; - + $navigation[ 'subnav' ][ 'scheduler' ] = [ 'label' => self::t( 'Scheduler' ), 'url' => 'mediamanager/scheduler' @@ -157,11 +198,11 @@ public function getCpNavItem(): array 'label' => self::t( 'Clean Garbage Entries' ), 'url' => 'mediamanager/clean' ]; - - $navigation['subnav']['stale-media'] = [ - 'label' => self::t('Manage Stale Media'), - 'url' => 'mediamanager/stale-media' - ]; + + $navigation['subnav']['stale-media'] = [ + 'label' => self::t('Manage Stale Media'), + 'url' => 'mediamanager/stale-media' + ]; $navigation[ 'subnav' ][ 'settings' ] = [ 'label' => self::t( 'Settings' ), @@ -188,7 +229,7 @@ function(RegisterUrlRulesEvent $event) { $event->rules[ 'mediamanager/shows' ] = 'mediamanager/show'; $event->rules[ 'mediamanager/shows/' ] = 'mediamanager/show'; - + $event->rules[ 'mediamanager/synchronize' ] = 'mediamanager/synchronize'; $event->rules[ 'mediamanager/synchronize/' ] = 'mediamanager/synchronize'; $event->rules[ 'mediamanager/synchronize/all' ] = 'mediamanager/synchronize/all'; @@ -198,9 +239,9 @@ function(RegisterUrlRulesEvent $event) { $event->rules[ 'mediamanager/synchronize/synchronize-single' ] = 'mediamanager/synchronize/synchronize-single'; $event->rules[ 'mediamanager/synchronize/synchronize-all' ] = 'mediamanager/synchronize/synchronize-all'; $event->rules[ 'mediamanager/synchronize/synchronize-show-entries' ] = 'mediamanager/synchronize/synchronize-show-entries'; - $event->rules[ 'mediamanager/scheduler'] = 'mediamanager/scheduled-sync/index'; - $event->rules['mediamanager/scheduler/'] = 'mediamanager/scheduled-sync/edit'; - $event->rules['mediamanager/scheduler/new'] = 'mediamanager/scheduled-sync/edit'; + $event->rules[ 'mediamanager/scheduler'] = 'mediamanager/scheduled-sync/index'; + $event->rules['mediamanager/scheduler/'] = 'mediamanager/scheduled-sync/edit'; + $event->rules['mediamanager/scheduler/new'] = 'mediamanager/scheduled-sync/edit'; $event->rules[ 'mediamanager/clean' ] = 'mediamanager/synchronize/clean'; } @@ -231,8 +272,8 @@ function( PluginEvent $event ) { } } ); - - + + // Before plugin uninstalled Event::on( @@ -253,30 +294,29 @@ private function registerBehaviors() CraftVariable::class, CraftVariable::EVENT_INIT, function( Event $e ) { - $variable = $e->sender; $variable->attachBehaviors([ MediaBehavior::class, ]); - $variable->set('mediamanager', MediaManagerVariable::class); + $variable->set('mediamanager', MediaManagerVariable::class); } ); - + Event::on( Application::class, Application::EVENT_INIT, function (Event $event) { - $scheduledSyncService = MediaManager::$plugin->scheduledSync; + $scheduledSyncService = MediaManager::$plugin->scheduledSync; $pushableSyncs = $scheduledSyncService->getPushableSyncs(); - + foreach ($pushableSyncs as $pushableSync) { Craft::$app->getQueue()->push(new ShowSync([ 'showId' => $pushableSync->showId, - 'regenerateThumbnails' => $pushableSync->regenerateThumbnail, + 'regenerateThumbnails' => $pushableSync->regenerateThumbnail, 'scheduledSync' => $pushableSync->id ])); - - $pushableSync->processed = 1; + + $pushableSync->processed = 1; $scheduledSyncService->saveScheduledSync($pushableSync); } } @@ -290,7 +330,7 @@ private function registerPluginServices() 'show' => ShowService::class, 'api' => ApiService::class, 'oldsettings' => OldSettingsService::class, - 'scheduledSync' => ScheduledSyncService::class, + 'scheduledSync' => ScheduledSyncService::class, ]); } diff --git a/src/assetbundles/showcpsection/dist/js/Show.js b/src/assetbundles/showcpsection/dist/js/Show.js index 37fa226..4e952f2 100644 --- a/src/assetbundles/showcpsection/dist/js/Show.js +++ b/src/assetbundles/showcpsection/dist/js/Show.js @@ -6,234 +6,219 @@ * @copyright Copyright (c) 2020 Paper Tiger * @link https://www.papertiger.com/ */ -(function($) { - /** global: Craft */ - /** global: Garnish */ - Craft.ShowAdmin = Garnish.Base.extend( - { - $shows: null, - $selectedShow: null, - - init: function() { - var self = this; - this.$shows = $('#shows'); - this.$selectedShow = this.$shows.find('a.sel:first'); - - this.addListener($('#newshowbtn'), 'activate', 'addNewShow'); - this.addListener($('#showupdatebtn'), 'activate', 'updateShow'); - this.addListener($('#addshowsite'), 'activate', 'addShowSite'); - - // Add Remove Button to Select - $( '#siteId-field .select' ).after( ' 
' ); - $( 'body' ).on( 'click', '.deletesite', function() { - self.deleteShowSite( $( this ).parents( '#siteId-field' ) ); - }) - - // Show Settings Buttons - var $showSettingsBtn = $('#showsettingsbtn'); - - if ($showSettingsBtn.length) { - var menuBtn = $showSettingsBtn.data('menubtn'); - - menuBtn.settings.onOptionSelect = $.proxy(function(elem) { - var $elem = $(elem); - - if ($elem.hasClass('disabled')) { - return; - } +(function ($) { + /** global: Craft */ + /** global: Garnish */ + Craft.ShowAdmin = Garnish.Base.extend( + { + $shows: null, + $selectedShow: null, + + init: function () { + var self = this; + this.$shows = $('#shows'); + this.$selectedShow = this.$shows.find('a.sel:first'); + + this.addListener($('#newshowbtn'), 'activate', 'addNewShow'); + this.addListener($('#showupdatebtn'), 'activate', 'updateShow'); + this.addListener($('#addshowsite'), 'activate', 'addShowSite'); + + // Add Remove Button to Select + $('#siteId-field .select').after(' 
'); + $('body').on('click', '.deletesite', function () { + self.deleteShowSite($(this).parents('#siteId-field')); + }) + + // Show Settings Buttons + var $showSettingsBtn = $('#showsettingsbtn'); + + if ($showSettingsBtn.length) { + var menuBtn = $showSettingsBtn.data('menubtn'); + + menuBtn.settings.onOptionSelect = $.proxy(function (elem) { + var $elem = $(elem); + + if ($elem.hasClass('disabled')) { + return; + } - switch ($elem.data('action')) { - case 'rename': { - this.renameSelectedShow(); - break; - } - case 'delete': { - this.deleteSelectedShow(); - break; - } - } - }, this); - } - - - }, - - addShowSite: function() { - - var siteField = $( '#siteId-field' ) - var clone = siteField.clone() - var modifiedClone = $( clone ).find( '.heading' ).remove().end() - - $( '#addshowsite' ).before( $( modifiedClone ).find( 'select' ).val( 1 ).end() ) - - }, - - deleteShowSite: function( target ) { - - if( $( 'select[name="siteId[]"]' ).length > 1 ) { - - target.remove(); - return - } - - Craft.cp.displayError(Craft.t('mediamanager', 'You need at least one associated site.') ); - - }, - - updateShow: function() { - - var apiKey = $( '#apiKey' ).val() - var showId = $( '#showId' ).val() - var showName = $( '#showName' ).val() - var siteId = [] - - $( 'select[name="siteId[]"]' ).each( function() { - - var thisSiteId = $( this ).val() - - if( siteId.indexOf( thisSiteId ) === -1 ) { - siteId.push( thisSiteId ); - } - }) - - if( apiKey && showId && siteId ) { - - var data = { - id: showId, - name: showName, - apiKey: apiKey, - siteId: siteId - }; - - $( '#showupdatebtn' ).addClass( 'disabled' ); - - Craft.postActionRequest('mediamanager/show/save', data, $.proxy(function(response, textStatus) { - - $( '#showupdatebtn' ).removeClass( 'disabled' ); - - if (textStatus === 'success') { - if (response.success) { - $( '#apiKey' ).val(response.show.apiKey); - Craft.cp.displayNotice(Craft.t('mediamanager', 'Show updated')); - } - else if (response.errors) { - var errors = this.flattenErrors(response.errors); - Craft.cp.displayError(Craft.t('mediamanager', 'Could not update the show:') + "\n\n" + errors.join("\n") ); - } - else { - Craft.cp.displayError(); - } - } - - }, this)); - - } else { - - if( !showId ) { - Craft.cp.displayError(Craft.t('mediamanager', 'Something wrong, please reload the page')); - return - } - - Craft.cp.displayError(Craft.t('mediamanager', 'API Key is required')); - } - - }, - - addNewShow: function() { - var name = this.promptForShowName(''); - - if (name) { - var data = { - name: name - }; - - Craft.postActionRequest('mediamanager/show/save', data, $.proxy(function(response, textStatus) { - if (textStatus === 'success') { - if (response.success) { - location.href = Craft.getUrl('mediamanager/shows/' + response.show.id ); - } - else if (response.errors) { - var errors = this.flattenErrors(response.errors); - alert(Craft.t('mediamanager', 'Could not create the show:') + "\n\n" + errors.join("\n")); - } - else { - Craft.cp.displayError(); - } - } - - }, this)); - } - }, - - renameSelectedShow: function() { - var oldName = this.$selectedShow.text(), - newName = this.promptForShowName(oldName); - - if (newName && newName !== oldName) { - var data = { - id: this.$selectedShow.data('id'), - name: newName - }; - - Craft.postActionRequest('mediamanager/show/save', data, $.proxy(function(response, textStatus) { - if (textStatus === 'success') { - if (response.success) { - this.$selectedShow.text(response.show.name); - Craft.cp.displayNotice(Craft.t('mediamanager', 'Show renamed')); - } - else if (response.errors) { - var errors = this.flattenErrors(response.errors); - alert(Craft.t('mediamanager', 'Could not rename the show:') + "\n\n" + errors.join("\n")); - } - else { - Craft.cp.displayError(); - } - } - - }, this)); - } - }, - - deleteSelectedShow: function() { - if (confirm(Craft.t('mediamanager', 'Are you sure you want to delete this show? This will remove relationship too.'))) { - var data = { - id: this.$selectedShow.data('id') - }; - - Craft.postActionRequest('mediamanager/show/delete', data, $.proxy(function(response, textStatus) { - if (textStatus === 'success') { - if (response.success) { - location.href = Craft.getUrl('mediamanager/shows'); - } - else if (response.errors) { - var errors = this.flattenErrors(response.errors); - alert(Craft.t('mediamanager', 'Could not delete the show:') + "\n\n" + errors.join("\n")); - } - else { - Craft.cp.displayError(); - } - } - }, this)); - } - }, - - promptForShowName: function(oldName) { - return prompt(Craft.t('mediamanager', 'What do you want to name the Show?'), oldName); - }, - - flattenErrors: function(responseErrors) { - var errors = []; - - for (var attribute in responseErrors) { - if (!responseErrors.hasOwnProperty(attribute)) { - continue; - } - - errors = errors.concat(responseErrors[attribute]); - } - - return errors; + switch ($elem.data('action')) { + case 'rename': { + this.renameSelectedShow(); + break; + } + case 'delete': { + this.deleteSelectedShow(); + break; + } } - } - ); -})(jQuery); \ No newline at end of file + }, this); + } + + + }, + + addShowSite: function () { + var siteField = $('#siteId-field') + var clone = siteField.clone() + var modifiedClone = $(clone).find('.heading').remove().end() + + $('#addshowsite').before($(modifiedClone).find('select').val(1).end()) + }, + + deleteShowSite: function (target) { + if ($('select[name="siteId[]"]').length > 1) { + target.remove(); + return + } + + Craft.cp.displayError(Craft.t('mediamanager', 'You need at least one associated site.')); + }, + + updateShow: function () { + var apiKey = $('#apiKey').val() + var showId = $('#showId').val() + var showName = $('#showName').val() + var siteId = [] + + $('select[name="siteId[]"]').each(function () { + var thisSiteId = $(this).val() + + if (siteId.indexOf(thisSiteId) === -1) { + siteId.push(thisSiteId); + } + }) + + if (apiKey && showId && siteId) { + var data = { + id: showId, + name: showName, + apiKey: apiKey, + siteId: siteId + }; + + $('#showupdatebtn').addClass('disabled'); + + Craft.sendActionRequest('POST', 'mediamanager/show/save', {data}) + .then((response) => { + + $('#showupdatebtn').removeClass('disabled'); + if (response.data.success) { + $('#apiKey').val(response.data.show.apiKey); + Craft.cp.displayNotice(Craft.t('mediamanager', 'Show updated')); + } + else if (response.data.errors) { + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not update the show:') + "\n\n" + errors.join("\n")); + } + + }) + + .catch(({ response }) => { + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not update the show:') + "\n\n" + errors.join("\n")); + }) + } else { + + if (!showId) { + Craft.cp.displayError(Craft.t('mediamanager', 'Something wrong, please reload the page')); + return + } + + Craft.cp.displayError(Craft.t('mediamanager', 'API Key is required')); + } + }, + + addNewShow: function () { + var name = this.promptForShowName(''); + + if (name) { + var data = { + name: name + }; + + Craft.sendActionRequest('POST', 'mediamanager/show/save', { data }) + .then((response) => { + if (response.data.success) { + location.href = Craft.getUrl('mediamanager/shows/' + response.data.show.id); + } + else if (response.data.errors) { + var errors = this.flattenErrors(response.data.errors); + alert(Craft.t('mediamanager', 'Could not create the show:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + Craft.cp.displayError(); + }) + } + }, + + renameSelectedShow: function () { + var oldName = this.$selectedShow.text(), + newName = this.promptForShowName(oldName); + + if (newName && newName !== oldName) { + var data = { + id: this.$selectedShow.data('id'), + name: newName + }; + + Craft.sendActionRequest('POST', 'mediamanager/show/save', { data }) + .then((response) => { + if (response.data.success) { + this.$selectedShow.text(response.data.show.name); + Craft.cp.displayNotice(Craft.t('mediamanager', 'Show renamed')); + } + else if (response.data.errors) { + var errors = this.flattenErrors(response.data.errors); + alert(Craft.t('mediamanager', 'Could not rename the show:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + Craft.cp.displayError(); + }) + } + }, + + deleteSelectedShow: function () { + if (confirm(Craft.t('mediamanager', 'Are you sure you want to delete this show? This will remove relationship too.'))) { + var data = { + id: this.$selectedShow.data('id') + }; + + Craft.sendActionRequest('POST', 'mediamanager/show/delete', { data }) + .then((response) => { + if (response.data.success) { + location.href = Craft.getUrl('mediamanager/shows'); + } + else if (response.data.errors) { + var errors = this.flattenErrors(response.data.errors); + alert(Craft.t('mediamanager', 'Could not delete the show:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + Craft.cp.displayError(); + }) + } + }, + + promptForShowName: function (oldName) { + return prompt(Craft.t('mediamanager', 'What do you want to name the Show?'), oldName); + }, + + flattenErrors: function (responseErrors) { + var errors = []; + + for (var attribute in responseErrors) { + if (!responseErrors.hasOwnProperty(attribute)) { + continue; + } + + errors = errors.concat(responseErrors[attribute]); + } + + return errors; + } + } + ); +})(jQuery); diff --git a/src/assetbundles/synchronizecpsection/dist/js/Synchronize.js b/src/assetbundles/synchronizecpsection/dist/js/Synchronize.js index b5b965d..9ee4a46 100644 --- a/src/assetbundles/synchronizecpsection/dist/js/Synchronize.js +++ b/src/assetbundles/synchronizecpsection/dist/js/Synchronize.js @@ -6,285 +6,248 @@ * @copyright Copyright (c) 2020 Paper Tiger * @link https://www.papertiger.com/ */ -(function($) { - /** global: Craft */ - /** global: Garnish */ - Craft.SynchronizeAdmin = Garnish.Base.extend( - { - init: function() { - var self = this; - - this.addListener($('#synchronizeshowbtn'), 'activate', 'synchronizeShow'); - this.addListener($('#synchronize-single-button'), 'activate', 'synchronizeSingle'); - this.addListener($('#synchronize-all-button'), 'activate', 'synchronizeAll'); - this.addListener($('#synchronize-show-entries-button'), 'activate', 'synchronizeShowEntries'); - this.addListener($('#addshowsite'), 'activate', 'addShowSite'); - this.addListener($('#cleanallbtn'), 'activate', 'cleanGarbageEntries'); - - // Add Remove Button to Select - $( '#siteId-field .select' ).after( ' 
' ); - $( 'body' ).on( 'click', '.deletesite', function() { - self.deleteShowSite( $( this ).parents( '#siteId-field' ) ); - }) - }, - - addShowSite: function() { - - var siteField = $( '#siteId-field' ) - var clone = siteField.clone() - var modifiedClone = $( clone ).find( '.heading' ).remove().end() - - $( '#addshowsite' ).before( $( modifiedClone ).find( 'select' ).val( 1 ).end() ) - - }, - - deleteShowSite: function( target ) { - - if( $( 'select[name="siteId[]"]' ).length > 1 ) { - - target.remove(); - return - } - - Craft.cp.displayError(Craft.t('mediamanager', 'You need at least one associated site.') ); - - }, - - cleanGarbageEntries: function() { - - $( '#cleanallbtn' ).addClass( 'disabled' ); - - Craft.postActionRequest('mediamanager/synchronize/run-clean', [], $.proxy(function(response, textStatus) { - - if (textStatus === 'success') { - if (response.success) { - Craft.cp.displayNotice(Craft.t('mediamanager', 'Start cleaning '+ response.total +' entries.')); - setTimeout( function() { - location.href = Craft.getUrl( 'mediamanager/entries/'); - }, 1000); - } - else if (response.errors) { - $( '#cleanallbtn' ).removeClass( 'disabled' ); - var errors = this.flattenErrors(response.errors); - Craft.cp.displayError(Craft.t('mediamanager', 'Could not start cleaning:') + "\n\n" + errors.join("\n") ); - } - else { - $( '#cleanallbtn' ).removeClass( 'disabled' ); - Craft.cp.displayError(); - } - } else { - $( '#cleanallbtn' ).removeClass( 'disabled' ); - } - - }, this)); - - }, - - synchronizeShow: function() { - - var showId = $( '#showId' ).val() - var name = $( '#name' ).val() - var forceRegenerateThumbnail = $( '#forceRegenerateThumbnail' ).prop( 'checked' ) - var fieldsToSync = []; - var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function(index, field){ - fieldsToSync.push($(field).val()); - }) - - if( showId ) { - - var data = { - showId: showId, - forceRegenerateThumbnail: forceRegenerateThumbnail, - fieldsToSync: fieldsToSync, - }; - - $( '#synchronizeshowbtn' ).addClass( 'disabled' ); - - Craft.postActionRequest('mediamanager/synchronize/synchronize-show', data, $.proxy(function(response, textStatus) { - - if (textStatus === 'success') { - if (response.success) { - Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize "'+ name +'" started.')); - setTimeout( function() { - location.href = Craft.getUrl( 'mediamanager/entries/'); - }, 1000); - } - else if (response.errors) { - $( '#synchronizeshowbtn' ).removeClass( 'disabled' ); - var errors = this.flattenErrors(response.errors); - Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n") ); - } - else { - $( '#synchronizeshowbtn' ).removeClass( 'disabled' ); - Craft.cp.displayError(); - } - } else { - $( '#synchronizeshowbtn' ).removeClass( 'disabled' ); - } - - }, this)); - - } else { - - if( !showId ) { - Craft.cp.displayError(Craft.t('mediamanager', 'Something wrong, please reload the page')); - return - } - - Craft.cp.displayError(Craft.t('mediamanager', 'Site ID is required')); - } - }, - - synchronizeSingle: function() { - - var apiKey = $( '#apiKey' ).val() - var siteId = [] - var forceRegenerateThumbnail = $( '#forceRegenerateThumbnail' ).prop( 'checked' ) - var fieldsToSync = []; - var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function(index, field){ - fieldsToSync.push($(field).val()); - }) - - $( 'select[name="siteId[]"]' ).each( function() { - - var thisSiteId = $( this ).val() - - if( siteId.indexOf( thisSiteId ) === -1 ) { - siteId.push( thisSiteId ); - } - }) - - if( apiKey && siteId ) { - - var data = { - apiKey: apiKey, - siteId: siteId, - forceRegenerateThumbnail: forceRegenerateThumbnail, - fieldsToSync: fieldsToSync, - }; - - $( '#synchronize-single-button' ).addClass( 'disabled' ); - - Craft.postActionRequest('mediamanager/synchronize/synchronize-single', data, $.proxy(function(response, textStatus) { - - if (textStatus === 'success') { - if (response.success) { - Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize started.')); - setTimeout( function() { - location.href = Craft.getUrl( 'mediamanager/entries/'); - }, 1000); - } - else if (response.errors) { - $( '#synchronize-single-button' ).removeClass( 'disabled' ); - var errors = this.flattenErrors(response.errors); - Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n") ); - } - else { - $( '#synchronize-single-button' ).removeClass( 'disabled' ); - Craft.cp.displayError(); - } - } else { - $( '#synchronize-single-button' ).removeClass( 'disabled' ); - } - - }, this)); - - } else { - Craft.cp.displayError(Craft.t('mediamanager', 'Media Asset\'s Site and API Key are required')); - } - }, - - synchronizeAll: function() { - - $( '#synchronize-all-button' ).addClass( 'disabled' ); - - var forceRegenerateThumbnail = $( '#forceRegenerateThumbnail' ).prop( 'checked' ) - var fieldsToSync = []; - var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function(index, field){ - fieldsToSync.push($(field).val()); - }) - - var data = { - forceRegenerateThumbnail: forceRegenerateThumbnail, - fieldsToSync: fieldsToSync, - }; - - Craft.postActionRequest('mediamanager/synchronize/synchronize-all', data, $.proxy(function(response, textStatus) { - - if (textStatus === 'success') { - if (response.success) { - Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize for all show started.')); - setTimeout( function() { - location.href = Craft.getUrl( 'mediamanager/entries/'); - }, 1000); - } - else if (response.errors) { - $( '#synchronize-all-button' ).removeClass( 'disabled' ); - var errors = this.flattenErrors(response.errors); - Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n") ); - } - else { - $( '#synchronize-all-button' ).removeClass( 'disabled' ); - Craft.cp.displayError(); - } - } else { - $( '#synchronize-all-button' ).removeClass( 'disabled' ); - } - - }, this)); - }, - - synchronizeShowEntries: function() { - - $( '#synchronize-show-entries-button' ).addClass( 'disabled' ); - - var fieldsToSync = []; - var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function(index, field){ - fieldsToSync.push($(field).val()); - }) - - var data = { - fieldsToSync: fieldsToSync, - }; - - Craft.postActionRequest('mediamanager/synchronize/synchronize-show-entries', data, $.proxy(function(response, textStatus) { - - if (textStatus === 'success') { - if (response.success) { - Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize for show entries started.')); - setTimeout( function() { - location.href = Craft.getUrl( 'mediamanager/entries/'); - }, 1000); - } - else if (response.errors) { - $( '#synchronize-show-entries-button' ).removeClass( 'disabled' ); - var errors = this.flattenErrors(response.errors); - Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n") ); - } - else { - $( '#synchronize-show-entries-button' ).removeClass( 'disabled' ); - Craft.cp.displayError(); - } - } else { - $( '#synchronize-show-entries-button' ).removeClass( 'disabled' ); - } - - }, this)); - }, - - flattenErrors: function(responseErrors) { - var errors = []; - - for (var attribute in responseErrors) { - if (!responseErrors.hasOwnProperty(attribute)) { - continue; - } - - errors = errors.concat(responseErrors[attribute]); - } - - return errors; +(function ($) { + /** global: Craft */ + /** global: Garnish */ + Craft.SynchronizeAdmin = Garnish.Base.extend( + { + init: function () { + var self = this; + + this.addListener($('#synchronizeshowbtn'), 'activate', 'synchronizeShow'); + this.addListener($('#synchronize-single-button'), 'activate', 'synchronizeSingle'); + this.addListener($('#synchronize-all-button'), 'activate', 'synchronizeAll'); + this.addListener($('#synchronize-show-entries-button'), 'activate', 'synchronizeShowEntries'); + this.addListener($('#addshowsite'), 'activate', 'addShowSite'); + this.addListener($('#cleanallbtn'), 'activate', 'cleanGarbageEntries'); + + // Add Remove Button to Select + $('#siteId-field .select').after(' 
'); + $('body').on('click', '.deletesite', function () { + self.deleteShowSite($(this).parents('#siteId-field')); + }) + }, + + addShowSite: function () { + var siteField = $('#siteId-field') + var clone = siteField.clone() + var modifiedClone = $(clone).find('.heading').remove().end() + + $('#addshowsite').before($(modifiedClone).find('select').val(1).end()) + }, + + deleteShowSite: function (target) { + if ($('select[name="siteId[]"]').length > 1) { + target.remove(); + return + } + + Craft.cp.displayError(Craft.t('mediamanager', 'You need at least one associated site.')); + }, + + cleanGarbageEntries: function () { + + $('#cleanallbtn').addClass('disabled'); + + Craft.sendActionRequest('POST', 'mediamanager/synchronize/run-clean', {}) + .then((response) => { + if (response.data.success) { + Craft.cp.displayNotice(Craft.t('mediamanager', 'Start cleaning ' + response.data.total + ' entries.')); + setTimeout(function () { + location.href = Craft.getUrl('mediamanager/entries/'); + }, 1000); } - } - ); + else if (response.data.errors) { + $('#cleanallbtn').removeClass('disabled'); + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not start cleaning:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + $('#cleanallbtn').removeClass('disabled'); + Craft.cp.displayError(); + }) + }, + + synchronizeShow: function () { + var showId = $('#showId').val() + var name = $('#name').val() + var forceRegenerateThumbnail = $('#forceRegenerateThumbnail').prop('checked') + var fieldsToSync = []; + var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function (index, field) { + fieldsToSync.push($(field).val()); + }) + + if (showId) { + var data = { + showId: showId, + forceRegenerateThumbnail: forceRegenerateThumbnail, + fieldsToSync: fieldsToSync, + }; + + $('#synchronizeshowbtn').addClass('disabled'); + + Craft.sendActionRequest('POST', 'mediamanager/synchronize/synchronize-show', { data }) + .then((response) => { + if (response.data.success) { + Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize "' + name + '" started.')); + setTimeout(function () { + location.href = Craft.getUrl('mediamanager/entries/'); + }, 1000); + } + else if (response.data.errors) { + $('#synchronizeshowbtn').removeClass('disabled'); + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + $('#synchronizeshowbtn').removeClass('disabled'); + Craft.cp.displayError(); + }) + + } else { + + if (!showId) { + Craft.cp.displayError(Craft.t('mediamanager', 'Something wrong, please reload the page')); + return + } + + Craft.cp.displayError(Craft.t('mediamanager', 'Site ID is required')); + } + }, + + synchronizeSingle: function () { + var apiKey = $('#apiKey').val() + var siteId = [] + var forceRegenerateThumbnail = $('#forceRegenerateThumbnail').prop('checked') + var fieldsToSync = []; + var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function (index, field) { + fieldsToSync.push($(field).val()); + }) + + $('select[name="siteId[]"]').each(function () { + var thisSiteId = $(this).val() + + if (siteId.indexOf(thisSiteId) === -1) { + siteId.push(thisSiteId); + } + }) + + if (apiKey && siteId) { + + var data = { + apiKey: apiKey, + siteId: siteId, + forceRegenerateThumbnail: forceRegenerateThumbnail, + fieldsToSync: fieldsToSync, + }; + + $('#synchronize-single-button').addClass('disabled'); + + Craft.sendActionRequest('POST', 'mediamanager/synchronize/synchronize-single', { data }) + .then((response) => { + if (response.data.success) { + Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize started.')); + setTimeout(function () { + location.href = Craft.getUrl('mediamanager/entries/'); + }, 1000); + } + else if (response.data.errors) { + $('#synchronize-single-button').removeClass('disabled'); + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + $('#synchronize-single-button').removeClass('disabled'); + Craft.cp.displayError(); + }) + + } else { + Craft.cp.displayError(Craft.t('mediamanager', 'Media Asset\'s Site and API Key are required')); + } + }, + + synchronizeAll: function () { + $('#synchronize-all-button').addClass('disabled'); + + var forceRegenerateThumbnail = $('#forceRegenerateThumbnail').prop('checked') + var fieldsToSync = []; + var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function (index, field) { + fieldsToSync.push($(field).val()); + }) + + var data = { + forceRegenerateThumbnail: forceRegenerateThumbnail, + fieldsToSync: fieldsToSync, + }; + + Craft.sendActionRequest('POST', 'mediamanager/synchronize/synchronize-all', data) + .then((response) => { + if (response.data.success) { + Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize for all show started.')); + setTimeout(function () { + location.href = Craft.getUrl('mediamanager/entries/'); + }, 1000); + } + else if (response.data.errors) { + $('#synchronize-all-button').removeClass('disabled'); + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + $('#synchronize-all-button').removeClass('disabled'); + Craft.cp.displayError(); + }) + }, + + synchronizeShowEntries: function () { + $('#synchronize-show-entries-button').addClass('disabled'); + + var fieldsToSync = []; + var fieldsToSyncInputs = $('input[name="fieldsToSync[]"]:checked').each(function (index, field) { + fieldsToSync.push($(field).val()); + }) + + var data = { + fieldsToSync: fieldsToSync, + }; + + Craft.sendActionRequest('POST', 'mediamanager/synchronize/synchronize-show-entries', data) + .then((response) => { + if (response.data.success) { + Craft.cp.displayNotice(Craft.t('mediamanager', 'Synchronize for show entries started.')); + setTimeout(function () { + location.href = Craft.getUrl('mediamanager/entries/'); + }, 1000); + } + else if (response.data.errors) { + $('#synchronize-show-entries-button').removeClass('disabled'); + var errors = this.flattenErrors(response.data.errors); + Craft.cp.displayError(Craft.t('mediamanager', 'Could not start synchronize:') + "\n\n" + errors.join("\n")); + } + }) + .catch(({ response }) => { + $('#synchronize-show-entries-button').removeClass('disabled'); + Craft.cp.displayError(); + }) + }, + + flattenErrors: function (responseErrors) { + var errors = []; + + for (var attribute in responseErrors) { + if (!responseErrors.hasOwnProperty(attribute)) { + continue; + } + + errors = errors.concat(responseErrors[attribute]); + } + + return errors; + } + } + ); })(jQuery); diff --git a/src/base/ConstantAbstract.php b/src/base/ConstantAbstract.php index 62e806d..7b1566e 100644 --- a/src/base/ConstantAbstract.php +++ b/src/base/ConstantAbstract.php @@ -14,7 +14,12 @@ abstract class ConstantAbstract { // Constants // ========================================================================= + const DEPENDENCY_PLUGIN_CRAFT_RICHTEXT_PLUGINS = [ + 'ckeditor' => ['handle' => 'ckeditor', 'package' => 'craftcms/ckeditor', 'fieldtype' => 'craft\ckeditor\Field', 'version' => '^3.0.0'], + 'redactor' => ['handle' => 'redactor', 'package' => 'craftcms/redactor', 'fieldtype' => 'craft\redactor\Field', 'version' => '^3.0.0'] + ]; + const DEFAULT_RICHTEXT_TYPE = self::DEPENDENCY_PLUGIN_CRAFT_RICHTEXT_PLUGINS['redactor']; const DEPENDENCY_PLUGIN_CRAFT_REDACTOR_HANDLE = 'redactor'; const DEPENDENCY_PLUGIN_CRAFT_REDACTOR_PACKAGE = 'craftcms/redactor'; const DEPENDENCY_PLUGIN_CRAFT_REDACTOR_VERSION = '>=2.3.0'; @@ -34,7 +39,7 @@ abstract class ConstantAbstract // From PBS API Fields [ 'duration', '', 'Duration', 'duration', 'craft\fields\PlainText' ], - [ 'description_long', '', 'Description', 'description', 'craft\redactor\Field' ], + [ 'description_long', '', 'Description', 'description', self::DEFAULT_RICHTEXT_TYPE['fieldtype'] ], [ 'object_type', '', 'Media Type', 'mediaType', 'craft\fields\PlainText' ], [ 'player_code', '', 'Player Code', 'playerCode', 'craft\fields\PlainText' ], ]; @@ -45,8 +50,8 @@ abstract class ConstantAbstract [ 'show_media_manager_id', '', 'Media Manager ID', 'showMediaManagerId', 'craft\fields\PlainText' ], // From PBS API Fields - [ 'description_short', '', 'Description Short', 'showDescriptionShort', 'craft\redactor\Field' ], - [ 'description_long', '', 'Description Long', 'showDescriptionLong', 'craft\redactor\Field' ], + [ 'description_short', '', 'Description Short', 'showDescriptionShort', self::DEFAULT_RICHTEXT_TYPE['fieldtype'] ], + [ 'description_long', '', 'Description Long', 'showDescriptionLong', self::DEFAULT_RICHTEXT_TYPE['fieldtype'] ], ]; const REQUIRED_FIELDS = [ @@ -109,6 +114,7 @@ abstract class ConstantAbstract const API_COLUMN_FIELD_TYPE_INDEX = 4; const API_COLUMN_FIELD_RULE_INDEX = 5; + const DEFAULT_FIELD_GROUP = "Media Manager"; const SYNC_SCHEDULE = 'daily'; const SYNC_CUSTOM_SCHEDULE = ''; const SYNC_PING_CHANGELOG = 1; diff --git a/src/console/controllers/ScheduleController.php b/src/console/controllers/ScheduleController.php index 63882d1..e8ae709 100644 --- a/src/console/controllers/ScheduleController.php +++ b/src/console/controllers/ScheduleController.php @@ -1,46 +1,57 @@ scheduledSync; - $pushableSyncs = $scheduledSyncService->getPushableSyncs(); - - foreach ($pushableSyncs as $pushableSync) { - Craft::$app->getQueue()->push(new ShowSync([ - 'showId' => $pushableSync->showId, - 'regenerateThumbnails' => $pushableSync->regenerateThumbnail, - 'scheduledSync' => $pushableSync->id - ])); - - $pushableSync->processed = 1; - $scheduledSyncService->saveScheduledSync($pushableSync); - } - return ExitCode::OK; - } -} + /** + * Media Manager + * + * @package PaperTiger:MediaManager + * @author Paper Tiger + * @copyright Copyright (c) 2020 Paper Tiger + * @link https://www.papertiger.com/ + */ + + namespace papertiger\mediamanager\console\controllers; + + use Craft; + use papertiger\mediamanager\jobs\ShowSync; + use papertiger\mediamanager\MediaManager; + use yii\console\Controller; + use yii\console\ExitCode; + use yii\helpers\Console; + + use papertiger\mediamanager\helpers\SettingsHelper; + + + class ScheduleController extends Controller + { + public $defaultAction = 'index'; + protected $allowAnonymous = ['index', 'run']; + + public function actionIndex(): int + { + $scheduledSyncService = MediaManager::$plugin->scheduledSync; + $pushableSyncs = $scheduledSyncService->getPushableSyncs(); + echo "Checking for scheduled syncs... \n"; + + if(empty($pushableSyncs)) + { + echo "No scheduled syncs found. \n"; + return ExitCode::OK; + } + + foreach ($pushableSyncs as $pushableSync) { + Craft::$app->getQueue()->push(new ShowSync([ + 'showId' => $pushableSync->showId, + ])); + + $pushableSync->processed = 1; + $scheduledSyncService->saveScheduledSync($pushableSync); + echo "Pushed sync for show ' . $pushableSync->showId . ' to queue. \n"; + } + + return ExitCode::OK; + } + + public function actionRun(): int + { + return $this->actionIndex(); + } + } diff --git a/src/controllers/MainController.php b/src/controllers/MainController.php index 9cac6fa..0ae5754 100644 --- a/src/controllers/MainController.php +++ b/src/controllers/MainController.php @@ -34,7 +34,7 @@ class MainController extends Controller // ========================================================================= protected const INDEX_TEMPLATE_PATH = 'mediamanager/index'; protected const ENTRIES_TEMPLATE_PATH = 'mediamanager/entries'; - protected $allowAnonymous = [ 'index', 'entries' ]; + protected array|int|bool $allowAnonymous = [ 'index', 'entries' ]; // Public Methods // ========================================================================= diff --git a/src/controllers/ScheduledSyncController.php b/src/controllers/ScheduledSyncController.php index 432da94..f714083 100644 --- a/src/controllers/ScheduledSyncController.php +++ b/src/controllers/ScheduledSyncController.php @@ -22,7 +22,7 @@ class ScheduledSyncController extends Controller { - protected $allowAnonymous = []; + protected array|int|bool $allowAnonymous = []; public function actionIndex(): Response { diff --git a/src/controllers/ShowController.php b/src/controllers/ShowController.php index 7c134cd..d231f50 100644 --- a/src/controllers/ShowController.php +++ b/src/controllers/ShowController.php @@ -29,12 +29,12 @@ class ShowController extends Controller // Protected Properties // ========================================================================= protected const SHOW_TEMPLATE_PATH = 'mediamanager/show'; - protected $allowAnonymous = [ 'index', 'show', 'pbs' ]; + protected array|int|bool $allowAnonymous = [ 'index', 'show', 'pbs' ]; // Public Methods // ========================================================================= - + public function actionIndex( $entryId = null ) { @@ -54,7 +54,7 @@ public function actionIndex( $entryId = null ) ); } - public function actionSave() + public function actionSave(): ?Response { $request = Craft::$app->getRequest(); $name = $request->getBodyParam( 'name' ); @@ -65,7 +65,7 @@ public function actionSave() if( !$name ) { - return $this->asJson([ + return $this->asFailure('Show name is required', [ 'success' => false, 'errors' => [ 'Show name is required' ], ]); @@ -76,7 +76,7 @@ public function actionSave() if( !MediaManager::getInstance()->api->validateApiKey( $apiKey, 'show' ) ) { - return $this->asJson([ + return $this->asFailure('Invalid API Key', [ 'success' => false, 'errors' => [ 'Invalid API Key' ], ]); @@ -87,13 +87,13 @@ public function actionSave() if( $show->getErrors() ) { - return $this->asJson([ + return $this->asFailure('Unable to save show.', [ 'success' => false, 'errors' => $show->getErrors(), ]); } - return $this->asJson([ + return $this->asSuccess('Show saved.', [ 'success' => true, 'show' => [ 'id' => $show->id, diff --git a/src/controllers/SynchronizeController.php b/src/controllers/SynchronizeController.php index 332f7fe..5762a54 100644 --- a/src/controllers/SynchronizeController.php +++ b/src/controllers/SynchronizeController.php @@ -32,7 +32,7 @@ class SynchronizeController extends Controller protected const SYNCHRONIZE_TEMPLATE_PATH = 'mediamanager/synchronize'; protected const CLEAN_TEMPLATE_PATH = 'mediamanager/clean'; - protected $allowAnonymous = [ 'index', 'all', 'single', 'synchronize' ]; + protected array|int|bool $allowAnonymous = [ 'index', 'all', 'single', 'synchronize' ]; // Public Methods diff --git a/src/helpers/DependencyHelper.php b/src/helpers/DependencyHelper.php index 312dc6c..3b8af71 100644 --- a/src/helpers/DependencyHelper.php +++ b/src/helpers/DependencyHelper.php @@ -14,6 +14,7 @@ use Exception; use papertiger\mediamanager\base\ConstantAbstract; +use papertiger\mediamanager\MediaManager; class DependencyHelper { @@ -21,8 +22,8 @@ class DependencyHelper // ========================================================================= public static function installDependencies() - { - self::_installCraftRedactorPlugin(); + { + self::_installCraftRichtextPlugin(); } @@ -59,13 +60,24 @@ private static function checkPluginDisabled( $pluginHandle ): bool return false; } - private static function _installCraftRedactorPlugin() + private static function _installCraftRichtextPlugin(): void { - $pluginHandle = ConstantAbstract::DEPENDENCY_PLUGIN_CRAFT_REDACTOR_HANDLE; - - if( !self::checkPluginExists( $pluginHandle ) ) { - Craft::$app->getComposer()->install( [ ConstantAbstract::DEPENDENCY_PLUGIN_CRAFT_REDACTOR_PACKAGE => ConstantAbstract::DEPENDENCY_PLUGIN_CRAFT_REDACTOR_VERSION ] ); + $allowableRichtextPlugins = ConstantAbstract::DEPENDENCY_PLUGIN_CRAFT_RICHTEXT_PLUGINS; + + $hasAllowablePluginInstalled = collect($allowableRichtextPlugins)->first(function($plugin, $key){ + return self::checkPluginExists($plugin['handle']); + }); + + if($hasAllowablePluginInstalled) { + $plugin = MediaManager::getInstance(); + $plugin->settings->defaultRichtextField = $hasAllowablePluginInstalled; + + return; } + + $defaultPlugin = ConstantAbstract::DEFAULT_RICHTEXT_TYPE; + $pluginHandle = $defaultPlugin['handle']; + Craft::$app->getComposer()->install( [ $defaultPlugin['handle'] => $defaultPlugin['version'] ] ); if( self::checkPluginDisabled( $pluginHandle ) && Craft::$app->getPlugins()->getStoredPluginInfo( $pluginHandle ) ) { @@ -78,4 +90,4 @@ private static function _installCraftRedactorPlugin() } } -} \ No newline at end of file +} diff --git a/src/helpers/aftersavesettings/ApiColumnFieldsHelper.php b/src/helpers/aftersavesettings/ApiColumnFieldsHelper.php index 78d1202..8571d14 100644 --- a/src/helpers/aftersavesettings/ApiColumnFieldsHelper.php +++ b/src/helpers/aftersavesettings/ApiColumnFieldsHelper.php @@ -137,7 +137,9 @@ private static function updateCraftField( $field ) $fieldInformation = self::craftFieldInformation( $field ); $fieldInformation[ 'id' ] = $existingField->id; - + if(!isset($existingField->type)) { + $fieldInformation['type'] = end($field); + } $field = Craft::$app->getFields()->createField( $fieldInformation ); Craft::$app->getFields()->saveField( $field ); } @@ -202,7 +204,7 @@ private static function craftFieldInformation( $field ) if( method_exists( 'ElementHelper', 'generateSlug' ) ) { $tagGroupHandle = ElementHelper::generateSlug( $field[ ConstantAbstract::API_COLUMN_FIELD_NAME_INDEX ] ); } else { - $tagGroupHandle = ElementHelper::createSlug( $field[ ConstantAbstract::API_COLUMN_FIELD_NAME_INDEX ] ); + $tagGroupHandle = ElementHelper::normalizeSlug( $field[ ConstantAbstract::API_COLUMN_FIELD_NAME_INDEX ] ); } // Find tag group first @@ -219,6 +221,15 @@ private static function craftFieldInformation( $field ) $group->setFieldLayout( $fieldLayout ); Craft::$app->getTags()->saveTagGroup( $group ); + + try { + $fieldLayout = Craft::$app->getFields()->assembleLayoutFromPost(); + $fieldLayout->type = Tag::class; + $group->setFieldLayout( $fieldLayout ); + Craft::$app->getTags()->saveTagGroup( $group ); + } catch( \Throwable $e ) { + Craft::error( $e->getMessage(), __METHOD__ ); + } $tagGroupUid = $group->uid; diff --git a/src/helpers/aftersavesettings/ShowApiColumnFieldsHelper.php b/src/helpers/aftersavesettings/ShowApiColumnFieldsHelper.php index 3ecc390..c0459cd 100644 --- a/src/helpers/aftersavesettings/ShowApiColumnFieldsHelper.php +++ b/src/helpers/aftersavesettings/ShowApiColumnFieldsHelper.php @@ -202,7 +202,7 @@ private static function craftFieldInformation( $field ) if( method_exists( 'ElementHelper', 'generateSlug' ) ) { $tagGroupHandle = ElementHelper::generateSlug( $field[ ConstantAbstract::API_COLUMN_FIELD_NAME_INDEX ] ); } else { - $tagGroupHandle = ElementHelper::createSlug( $field[ ConstantAbstract::API_COLUMN_FIELD_NAME_INDEX ] ); + $tagGroupHandle = ElementHelper::normalizeSlug( $field[ ConstantAbstract::API_COLUMN_FIELD_NAME_INDEX ] ); } // Find tag group first @@ -229,8 +229,11 @@ private static function craftFieldInformation( $field ) $fieldInformation[ 'type' ] = Tags::class; $fieldInformation[ 'source' ] = 'taggroup:' . $tagGroupUid; break; + case 'craft\ckeditor\Field': + $fieldInformation[ 'type' ] = "craft\ckeditor\Field"; + break; } - + return $fieldInformation; } diff --git a/src/jobs/CancelStaleMedia.php b/src/jobs/CancelStaleMedia.php index f2fbfa2..22fb7ba 100644 --- a/src/jobs/CancelStaleMedia.php +++ b/src/jobs/CancelStaleMedia.php @@ -32,7 +32,7 @@ class CancelStaleMedia extends BaseJob // Public Methods // ========================================================================= - public function execute( $queue ) + public function execute( $queue ): void { $relatedMediaObjects = Entry::find()->markedForDeletion(1); diff --git a/src/jobs/IdentifyStaleMedia.php b/src/jobs/IdentifyStaleMedia.php index 8e55ad8..2be6060 100644 --- a/src/jobs/IdentifyStaleMedia.php +++ b/src/jobs/IdentifyStaleMedia.php @@ -52,7 +52,7 @@ class IdentifyStaleMedia extends BaseJob // Public Methods // ========================================================================= - public function execute( $queue ) + public function execute( $queue ): void { if (!$this->tags) { diff --git a/src/jobs/MarkStaleMedia.php b/src/jobs/MarkStaleMedia.php index 938b18c..6f49505 100644 --- a/src/jobs/MarkStaleMedia.php +++ b/src/jobs/MarkStaleMedia.php @@ -30,41 +30,41 @@ class MarkStaleMedia extends BaseJob { - + // Public Properties // ========================================================================= - + /** * @var int */ public $entryId; - + // Public Methods // ========================================================================= - - public function execute( $queue ) + + public function execute( $queue ): void { $entry = Entry::find()->id($this->entryId)->one(); - + if(!$entry) { return; } - + $markForDeletion = 0; // hit PBS API to check if there is data for this entry's api key $client = Craft::createGuzzleClient(); $baseUrl = MediaManager::$plugin->api->getApiBaseUrl(); $apiAuth = MediaManager::$plugin->api->getApiAuth(); - + try { $data = $client->get($baseUrl . "assets/" . $entry->mediaManagerId . "?platform-slug=bento&platform-slug=partnerplayer", $apiAuth); - + $asset = Json::decode($data->getBody(), false); if(isset($asset->data)){ if(!isset($asset->data->attributes->availabilities->public, $asset->data->attributes->availabilities->all_members)){ return; } - + if($asset->data->attributes->availabilities->public->start === null && $asset->data->attributes->availabilities->all_members->start === null){ $markForDeletion = 1; } @@ -77,22 +77,22 @@ public function execute( $queue ) Craft::error($e->getMessage(), __METHOD__); return; } - + // if data object is empty, return Craft::warning("Marking entry ID {$entry->id} for deletion.", __METHOD__); $entry->setFieldValue('markedForDeletion', $markForDeletion); $entry->setFieldValue('lastSynced', (new DateTime())); Craft::$app->getElements()->saveElement($entry); } - + // Protected Methods // ========================================================================= - + protected function defaultDescription(): string { return Craft::t( 'mediamanager', "Marking entry {$this->entryId} for deletion." ); } - + // Private Methods // ========================================================================= } diff --git a/src/jobs/MediaClean.php b/src/jobs/MediaClean.php index 6583262..ccf6ac9 100644 --- a/src/jobs/MediaClean.php +++ b/src/jobs/MediaClean.php @@ -34,7 +34,7 @@ class MediaClean extends BaseJob // Public Methods // ========================================================================= - public function execute( $queue ) + public function execute( $queue ): void { Craft::$app->getElements()->deleteElementById( $this->entryId, Entry::class ); $this->setProgress( $queue, $this->count / $this->total ); diff --git a/src/jobs/MediaSync.php b/src/jobs/MediaSync.php index 414c60b..6f928f8 100644 --- a/src/jobs/MediaSync.php +++ b/src/jobs/MediaSync.php @@ -79,7 +79,7 @@ class MediaSync extends BaseJob // Public Methods // ========================================================================= - public function execute( $queue ) + public function execute( $queue ): void { $this->apiBaseUrl = SettingsHelper::get( 'apiBaseUrl' ); $this->sectionId = SynchronizeHelper::getSectionId(); // SECTION_ID @@ -108,24 +108,40 @@ public function execute( $queue ) $availabilities = $assetAttributes->availabilities; $existingEntry = $this->findExistingMediaEntry( $mediaAsset->id ); - $entry = $this->chooseOrCreateMediaEntry( $assetAttributes->title, $existingEntry ); - $expirationStatus = $this->determineExpirationStatus( $availabilities->public->end ); + + // if all availabilities are null, early return + if( $availabilities->public->start === null && $availabilities->public->end === null && + $availabilities->all_members->start === null && $availabilities->all_members->end === null && + $availabilities->station_members->start === null && $availabilities->station_members->end === null + ){ + if($existingEntry){ + $existingEntry->setFieldValue('markedForDeletion', true); + + Craft::$app->getElements()->saveElement( $existingEntry ); + $this->setProgress( $queue, $count++ / $totalAssets ); + } + + continue; + } + + $entry = $this->chooseOrCreateMediaEntry( $assetAttributes->title, $existingEntry ); + $expirationStatus = $this->determineExpirationStatus( $availabilities->public->end ); $displayPassportIcon = $this->determinePassportStatus( $availabilities->all_members->start, $availabilities->all_members->end, $availabilities->public->start, $availabilities->public->end ); - - $isNew = !$existingEntry; + $isNew = !$existingEntry; + // Set default field Values $defaultFields = []; // Set field values based on API Column Fields on settings $apiColumnFields = SettingsHelper::get( 'apiColumnFields' ); - if($this->fieldsToSync === '*' || in_array('title', $this->fieldsToSync) || $isNew) { + if($this->fieldsToSync === '*' || in_array('title', $this->fieldsToSync) || $isNew ){ $entry->title = $assetAttributes->title; } @@ -134,7 +150,7 @@ public function execute( $queue ) $apiField = $apiColumnField[ 0 ]; // ensure the field to be updated from MM Settings is included in the fieldsToSync array - if($isNew && $this->fieldsToSync !== '*' && !in_array($apiField, $this->fieldsToSync) ) { + if(!$isNew && ($this->fieldsToSync !== '*' && !in_array($apiField, $this->fieldsToSync)) ) { continue; } @@ -216,11 +232,11 @@ public function execute( $queue ) if( $tag ) { array_push( $siteTags, $tag->id ); } - } - $this->siteTags = $siteTags; + } + $this->siteTags = $siteTags; $defaultFields[ $siteTagFieldHandle ] = $siteTags; - + break; case 'film_tags': @@ -254,8 +270,8 @@ public function execute( $queue ) $filmTags[] = $film->id; } } - - $this->filmTags = $filmTags; + + $this->filmTags = $filmTags; $defaultFields[ $filmTagFieldHandle ] = $filmTags; break; @@ -284,7 +300,7 @@ public function execute( $queue ) } } - $this->topicTags = $topicTags; + $this->topicTags = $topicTags; $defaultFields[ $topicTagFieldHandle ] = $topicTags; break; @@ -392,7 +408,7 @@ public function execute( $queue ) $markForDeletion = 1; } $entry->setFieldValue('markedForDeletion', $markForDeletion); - $entry->enabled = $this->isEntryEnabled( $availabilities->all_members->end ); + $entry->enabled = $this->isEntryEnabled( $availabilities ); Craft::$app->getElements()->saveElement( $entry ); $this->setProgress( $queue, $count++ / $totalAssets ); @@ -574,11 +590,11 @@ private function compareEnabledSupportedSites( $asset ) private function thumbnailNotAccessibleAcrossSites( $entry ) { // If thumbnail empty, don't overwrite it since it might be from the admin - if( !count( $entry->{ SynchronizeHelper::getThumbnailField() } ) ) { + if( !$entry->{ SynchronizeHelper::getThumbnailField() }->collect()->count() ) { return false; } - $asset = $entry->{ SynchronizeHelper::getThumbnailField() }[0]; + $asset = $entry->{ SynchronizeHelper::getThumbnailField() }->collect()->first(); if( !$asset ) { return false; @@ -637,8 +653,8 @@ private function createOrUpdateThumbnail( $entryTitle, $imageInfo ) { $imageUrl = $imageInfo->image; $extension = pathinfo( $imageUrl )[ 'extension' ]; - $slug = ElementHelper::createSlug( $entryTitle ); - $filename = $slug . '-' . md5( ElementHelper::createSlug( $imageUrl ) ) . '.' . $extension; + $slug = ElementHelper::normalizeSlug( $entryTitle ); + $filename = $slug . '-' . md5( ElementHelper::normalizeSlug( $imageUrl ) ) . '.' . $extension; $asset = Asset::findOne( [ 'filename' => $filename ] ); if( $asset ) { @@ -711,17 +727,29 @@ private function determinePassportStatus( $allMembersStartDate, $allMembersEndDa return $allMembersStart < $currentTime && $currentTime < $allMembersEnd; } - private function isEntryEnabled( $endDate ) + private function isEntryEnabled($availabilities) { - // No $endDate, enabled it - if( !$endDate || $endDate === false ) { + // previous logic used $availabilities->all_members->end to calculate status + // now we will check if all start/end dates are null and if so set as disabled + $public = $availabilities->public; + $allMembers = $availabilities->all_members; + $stationMembers = $availabilities->station_members; + + if( $public->start === null && $public->end === null && + $allMembers->start === null && $allMembers->end === null && + $stationMembers->start === null && $stationMembers->end === null + ) { + return 0; + } + + $endDate = $allMembers->end; + + if( $allMembers->start && !$endDate) { return 1; } - - $endDate = strtotime( $endDate ); - $currentTime = strtotime( 'now' ); - - return ( $endDate > $currentTime ) ? 1 : 0; + + $currentTime = strtotime('now'); + return (strtotime($endDate) > $currentTime) ? 1 : 0; } private function getMediaFolder() diff --git a/src/jobs/ShowEntriesSync.php b/src/jobs/ShowEntriesSync.php index b5c5350..7ac0f17 100644 --- a/src/jobs/ShowEntriesSync.php +++ b/src/jobs/ShowEntriesSync.php @@ -48,11 +48,11 @@ class ShowEntriesSync extends BaseJob // Public Properties // ========================================================================= - + public $title; public $auth; public $apiKey; - + /** * @var array|string */ @@ -61,22 +61,22 @@ class ShowEntriesSync extends BaseJob // Private Properties // ========================================================================= - + private $dateWithMs = 'Y-m-d\TH:i:s.uP'; - + private $_availabilityProcessed = false; private $availabilityPassport = 0; private $availabilityPublic = 0; // Public Methods // ========================================================================= - + /** * @throws Exception * @throws \Throwable * @throws ElementNotFoundException */ - public function execute( $queue ) + public function execute( $queue ): void { $this->apiBaseUrl = SettingsHelper::get( 'apiBaseUrl' ); $this->sectionId = SynchronizeHelper::getShowSectionId(); // SECTION_ID @@ -89,11 +89,11 @@ public function execute( $queue ) $url = $this->generateAPIUrl( $this->apiKey ); $showEntry = $this->fetchShowEntry($url, ''); - + $showAttributes = $showEntry->data->attributes; $existingEntry = $this->findExistingShowEntry( $showEntry->data->id ); - $isNew = !$existingEntry; + $isNew = !$existingEntry; $entry = $this->chooseOrCreateShowEntry( $showAttributes->title, $existingEntry ); // Set default field Values @@ -103,9 +103,9 @@ public function execute( $queue ) $apiColumnFields = SettingsHelper::get( 'showApiColumnFields' ); foreach( $apiColumnFields as $apiColumnField ) { - + $apiField = $apiColumnField[ 0 ]; - + // ensure the field to be updated from MM Settings is included in the fieldsToSync array if(!$isNew && ($this->fieldsToSync !== '*' && !in_array($apiField, $this->fieldsToSync))) { continue; @@ -118,7 +118,7 @@ public function execute( $queue ) $fieldRule = SynchronizeHelper::getApiFieldRule( $apiField, 'showApiColumnFields' ); if( isset( $showAttributes->images ) && is_array( $showAttributes->images ) ) { - + $assets = []; foreach( $showAttributes->images as $image ) { @@ -163,30 +163,30 @@ public function execute( $queue ) case 'show_media_manager_id': $defaultFields[ SynchronizeHelper::getShowMediaManagerIdField() ] = $showEntry->data->id; break; - case 'show_site_url': - if(isset( $showAttributes->links) && is_array($showAttributes->links)){ + case 'show_site_url': + if(isset( $showAttributes->links) && is_array($showAttributes->links)){ foreach($showAttributes->links as $link) { if($link->profile == 'producer') { - $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $link->value; - } + $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $link->value; + } } } - break; - case 'available_for_purchase': - $availableForPurchase = 0; - $purchasablePlatforms = ['itunes', 'amazon', 'buy-dvd', 'roku', 'apple-tv', 'ios']; - if(isset( $showAttributes->links) && is_array($showAttributes->links)){ + break; + case 'available_for_purchase': + $availableForPurchase = 0; + $purchasablePlatforms = ['itunes', 'amazon', 'buy-dvd', 'roku', 'apple-tv', 'ios']; + if(isset( $showAttributes->links) && is_array($showAttributes->links)){ foreach($showAttributes->links as $link) { if($availableForPurchase || !in_array($link->profile, $purchasablePlatforms)){ - continue; + continue; + } + if(in_array($link->profile, $purchasablePlatforms)){ + $availableForPurchase = 1; } - if(in_array($link->profile, $purchasablePlatforms)){ - $availableForPurchase = 1; - } } - $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $availableForPurchase; + $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $availableForPurchase; } - break; + break; case 'description_long': // Only if new entry add description if( !$existingEntry ) { @@ -245,22 +245,20 @@ public function execute( $queue ) $createTable[$count]['linkUpdatedAt'] = new \DateTime( $link->updated_at ); $count++; } - + $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $createTable; } break; case 'stream_with_passport': - $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $this->getShowAvailability('availabilityPassport', $showEntry); - break; - + $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $this->getShowAvailability('availabilityPassport', $showEntry); + break; + case 'available_to_public': - $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $this->getShowAvailability('availabilityPublic', $showEntry); - break; - - - + $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $this->getShowAvailability('availabilityPublic', $showEntry); + break; + default: $defaultFields[ SynchronizeHelper::getApiField( $apiField, 'showApiColumnFields' ) ] = $showAttributes->{ $apiField }; break; @@ -285,7 +283,7 @@ protected function defaultDescription(): string // Private Methods // ========================================================================= - + private function log( $message ) { if( $this->logProcess ) { @@ -293,7 +291,7 @@ private function log( $message ) FileHelper::writeToFile( Craft::getAlias( $this->logFile ), $log, [ 'append' => true ] ); } } - + private function generateAPIUrl( $apiKey ) { return $this->apiBaseUrl . 'shows/'. $apiKey . '/?platform-slug=bento&platform-slug=partnerplayer'; @@ -312,12 +310,12 @@ private function fetchShowEntry($url, $attribute = 'data', $params = []) $response = Json::decode($response->getBody(), false); if($attribute){ - return $response->{$attribute}; - } - + return $response->{$attribute}; + } + return $response; } - + /** * @throws \Exception */ @@ -327,71 +325,72 @@ private function getShowAvailability(string $attribute, $showEntry): int if($this->_availabilityProcessed){ return $this->$attribute; } - + // There is probably a much cleaner / more straightforward way of doing this // we need to loops through all assets of the show's first season to see if any of them are available for streaming // If any episode in season 1 is available to passport members, then we can say the show is in Passport. If any episode within Season 1 is available to the Public, then we can also say it is "available to everyone". // logic per https://github.com/pbs/pbs-media-manager-craft-plugin/issues/10#issuecomment-1791521258 - + $availableOnPassport = 0; $availableToPublic = 0; - + // get show's seasons $seasonsUrl = $showEntry->links->seasons; $seasonData = $this->fetchShowEntry($seasonsUrl); + if(!$seasonData){ Craft::error('No seasons found for show ' . $showEntry->data->id, __METHOD__); return 0; } - + // get first season's episodes $firstSeasonIndex = count($seasonData) - 1; $episodesUrl = $seasonData[$firstSeasonIndex]->links->episodes; $episodesData = $this->fetchShowEntry($episodesUrl); - + if(!$episodesData){ Craft::error('No episodes found for season ' . $seasonData[$firstSeasonIndex]->id, __METHOD__); return 0; } - + foreach($episodesData as $episode){ // if we've determined that both are true, we can stop looping if($availableOnPassport && $availableToPublic){ continue; } - + $episodeAssetsUrl = $episode->links->assets; - $episodeAssets = $this->fetchShowEntry($episodeAssetsUrl, 'data', ['type' => 'full_length']); + if(!$episodeAssets) { continue; } - + foreach($episodeAssets as $asset){ if($availableOnPassport && $availableToPublic){ continue; } - + $publicEndDate = new DateTime($asset->attributes->availabilities->public->end) ?? null; $passportEndDate = new DateTime($asset->attributes->availabilities->all_members->end) ?? null; - - if($publicEndDate instanceof DateTime){ + + if($publicEndDate instanceof DateTime){ $availableToPublic = DateTimeHelper::isInThePast($publicEndDate) ? 0 : 1; } - + if($passportEndDate instanceof DateTime){ $availableOnPassport = DateTimeHelper::isInThePast($passportEndDate) ? 0 : 1; } } } - + $this->availabilityPassport = $availableOnPassport; $this->availabilityPublic = $availableToPublic; $this->_availabilityProcessed = true; - + return $this->$attribute; } - + private function findExistingShowEntry( $mediaManagerId ) { // Find existing media @@ -413,7 +412,7 @@ private function chooseOrCreateShowEntry( $title, $entry ) if( $this->authorUsername ) { $user = Craft::$app->users->getUserByUsernameOrEmail( $this->authorUsername ); - + if( $user ) { $apiUserID = $user->id; } @@ -451,20 +450,20 @@ private function createOrUpdateImage( $entryTitle, $imageInfo, $profile ) { $imageUrl = $imageInfo->image; $extension = pathinfo( $imageUrl )[ 'extension' ]; - $slug = ElementHelper::createSlug( $entryTitle ); - $filename = $slug . '-' . md5( ElementHelper::createSlug( $imageUrl ) ) . '.' . $extension; + $slug = ElementHelper::normalizeSlug( $entryTitle ); + $filename = $slug . '-' . md5( ElementHelper::normalizeSlug( $imageUrl ) ) . '.' . $extension; $asset = Asset::findOne( [ 'filename' => $filename ] ); if( $asset ) { - + Craft::$app->elements->deleteElement($asset); /* if( $asset->mmAssetProfile ) { - + return $asset; - + } else { $asset->setFieldValue( 'mmAssetProfile', $profile); @@ -493,12 +492,12 @@ private function createImageAsset( $imageUrl, $filename, $profile ) $asset->avoidFilenameConflicts = true; $asset->setScenario( Asset::SCENARIO_CREATE ); - + // HINT: May no longer required - Plz double check //$asset->setFieldValues( $defaultFields ); if( $profile ) { - + if( Craft::$app->getFields()->getFieldByHandle( 'mmAssetProfile' ) ) { $asset->setFieldValue( 'mmAssetProfile', $profile); } diff --git a/src/jobs/ShowSync.php b/src/jobs/ShowSync.php index 3d7e770..585dd00 100644 --- a/src/jobs/ShowSync.php +++ b/src/jobs/ShowSync.php @@ -49,7 +49,7 @@ class ShowSync extends BaseJob // Public Methods // ========================================================================= - public function execute( $queue ) + public function execute( $queue ): void { $show = $this->_getShow(); $scheduledSync = MediaManager::getInstance()->scheduledSync->getScheduledSyncById($this->scheduledSync); diff --git a/src/migrations/m230705_151024_add_marked_for_deletion_field.php b/src/migrations/m230705_151024_add_marked_for_deletion_field.php index bba2659..648c168 100644 --- a/src/migrations/m230705_151024_add_marked_for_deletion_field.php +++ b/src/migrations/m230705_151024_add_marked_for_deletion_field.php @@ -6,15 +6,20 @@ use craft\db\Migration; use craft\helpers\ArrayHelper; use papertiger\mediamanager\helpers\SettingsHelper; +use yii\base\Exception; +use yii\base\InvalidConfigException; /** * m230705_151019_add_marked_for_deletion_field migration. */ class m230705_151024_add_marked_for_deletion_field extends Migration { - /** - * @inheritdoc - */ + /** + * @inheritdoc + * @throws InvalidConfigException + * @throws Exception + * @throws \Throwable + */ public function safeUp() { $schemaVersion = Craft::$app->projectConfig->get( @@ -46,17 +51,38 @@ public function safeUp() if($mediaSection) { $entryType = $mediaSection->getEntryTypes()[0]; $fieldLayout = $entryType->getFieldLayout(); - $allFields = $fieldLayout->getFields(); - $fieldLayout->setFields(ArrayHelper::merge([$field], $allFields)); $tabs = $fieldLayout->getTabs(); - + $fieldAdded = false; + + $newFieldLayoutElement = [ + 'type' => 'craft\fields\Lightswitch', + 'fieldUid' => $field->uid, + 'enabled' => true, + 'required' => false, + 'sortOrder' => 0, + ]; + foreach($tabs as $tab) { if ($tab->name === 'API'){ - $existingFields = $tab->getFields(); - $tab->setFields(ArrayHelper::merge([$field], $existingFields)); + $elements = $tab->elements; + foreach($elements as $element) { + if($element->uid === $field->uid) { + $fieldAdded = true; + } + } + if(!$fieldAdded){ + $tab->setElements(array_merge($elements, [$newFieldLayoutElement])); + } } } - + + if(!$fieldAdded) { + $elements = $tabs[0]->getElements(); + $tabs[0]->setElements(array_merge($elements, [$newFieldLayoutElement])); + } + + $fieldLayout->setTabs($tabs); + Craft::$app->fields->saveLayout($fieldLayout); $entryType->setFieldLayout($fieldLayout); Craft::$app->getSections()->saveEntryType($entryType); } diff --git a/src/models/SettingsModel.php b/src/models/SettingsModel.php index f0e6aff..0bf251a 100644 --- a/src/models/SettingsModel.php +++ b/src/models/SettingsModel.php @@ -42,12 +42,12 @@ class SettingsModel extends Model public $syncSchedule = ConstantAbstract::SYNC_SCHEDULE; public $syncCustomSchedule = ConstantAbstract::SYNC_CUSTOM_SCHEDULE; public $syncPingChangelog = ConstantAbstract::SYNC_PING_CHANGELOG; - + public $defaultRichtextField = ConstantAbstract::DEFAULT_RICHTEXT_TYPE; // Public Methods // ========================================================================= - public function rules() + public function rules(): array { return [ [ diff --git a/src/services/Api.php b/src/services/Api.php index d8d1fa9..a030079 100644 --- a/src/services/Api.php +++ b/src/services/Api.php @@ -31,7 +31,7 @@ class Api extends Component { // Private Properties // ========================================================================= - + protected static $sectionMediaHandle; protected static $sectionUsedMediaHandle; protected static $apiBaseUrl; @@ -135,7 +135,7 @@ public function synchronizeSingle( $apiKey, $siteId, $forceRegenerateThumbnail, public function synchronizeAll( $shows, $forceRegenerateThumbnail, $fieldsToSync = '*' ) { foreach( $shows as $show ) { - + if( $show->apiKey ) { $this->runSynchronizeShow( $show, $forceRegenerateThumbnail, $fieldsToSync ); } @@ -147,7 +147,7 @@ public function synchronizeAll( $shows, $forceRegenerateThumbnail, $fieldsToSync public function synchronizeShowEntries( $shows, $fieldsToSync = '*' ) { foreach( $shows as $show ) { - + if( $show->apiKey ) { Craft::$app->queue->push( new ShowEntriesSync([ @@ -155,19 +155,19 @@ public function synchronizeShowEntries( $shows, $fieldsToSync = '*' ) 'apiKey' => $show->apiKey, 'title' => $show->name . ' (Show)', 'auth' => self::$apiAuth, - 'fieldsToSync' => $fieldsToSync, + 'fieldsToSync' => $fieldsToSync, ])); } } return true; } - + public function getApiBaseUrl() { return self::$apiBaseUrl; } - + public function getApiAuth() { return self::$apiAuth; @@ -177,7 +177,7 @@ public function runClean() { try { - + // Check used media entries from pages $usedMedia = []; $sites = Craft::$app->sites->getAllSites(); @@ -194,7 +194,7 @@ public function runClean() foreach( $pages as $page ) { foreach( $page[ 'pageBuilder' ]->all() as $parentBlock ) { - + foreach( $parentBlock[ 'row' ]->all() as $component ) { switch( $component[ 'type' ] ) { @@ -212,7 +212,7 @@ public function runClean() } foreach( $component[ 'selectedMedia' ]->anyStatus()->all() as $entry ) { - + array_push( $usedMedia, [ 'id' => $entry[ 'id' ], 'title' => $entry[ 'title' ], @@ -251,7 +251,7 @@ public function runClean() foreach( $entries as $entry ) { $mediaManagerId = $entry[ 'mediaManagerId' ]; - + if( array_key_exists( $mediaManagerId, $duplicateCounter ) ) { $duplicateCounter[ $mediaManagerId ]++; } else { @@ -320,7 +320,7 @@ public function runClean() } return $total; - + } catch( Exception $e ) { return false; @@ -329,7 +329,7 @@ public function runClean() // Private Methods // ========================================================================= - + private function runSynchronizeShow( $show, $forceRegenerateThumbnail, $fieldsToSync = '*' ) { Craft::$app->queue->push( new MediaSync([ diff --git a/src/templates/entries.twig b/src/templates/entries.twig index ed4724d..e793b06 100644 --- a/src/templates/entries.twig +++ b/src/templates/entries.twig @@ -10,7 +10,7 @@ {% exit 404 %} {% endif %} -{% set sources = craft.app.elementIndexes.getSources(elementType, 'index') %} +{% set sources = craft.app.elementSources.getSources(elementType, 'index') %} {% set customizableSources = (sources is not empty and context == 'index' and currentUser.admin) %} {% set showSiteMenu = (craft.app.getIsMultiSite() ? (showSiteMenu ?? 'auto') : false) %} diff --git a/src/templates/settings.twig b/src/templates/settings.twig index 1c3dc43..15d392a 100644 --- a/src/templates/settings.twig +++ b/src/templates/settings.twig @@ -10,7 +10,6 @@ {% set tabs = [ { label: 'Base', url: '#settings-tab-base' }, { label: 'API Column & Fields', url: '#settings-tab-api-column-fields' }, - { label: 'Field Layout', url: '#settings-tab-field-layout' }, { label: 'Synchronize', url: '#settings-tab-synchronize' } ] %} @@ -32,7 +31,7 @@ ul.errors { list-style: none; padding-left: 0 !important; } ul.errors li { list-style-type: none !important; } .hud.info-hud { max-width: 300px; } - + {% if not isCraft35 %} .flex .field.flex-grow:last-of-type { margin-top: 0 !important; margin-bottom: 7px !important; } {% endif %} @@ -45,7 +44,6 @@ {% namespace 'settings' %} {% include 'mediamanager/settings/_base' %} {% include 'mediamanager/settings/_apicolumnfields' %} - {% include 'mediamanager/settings/_fieldlayout' %} {% include 'mediamanager/settings/_synchronize' %} {% endnamespace %} diff --git a/src/templates/settings/_apicolumnfields.twig b/src/templates/settings/_apicolumnfields.twig index 0d42cf8..4c5f1a3 100644 --- a/src/templates/settings/_apicolumnfields.twig +++ b/src/templates/settings/_apicolumnfields.twig @@ -48,6 +48,9 @@ addRowLabel: 'Add a field', rows: settings.apiColumnFields, errors: settings.getErrors( 'apiColumnFields' ), + allowAdd: true, + allowReorder: true, + allowDelete: true, cols: [ { heading: 'API Field', @@ -95,7 +98,8 @@ type: 'select', options: [ {"label":"— Select Field Type —"}, - {"value":"craft\\fields\\Assets","label":"Assets"},{"value":"craft\\fields\\Date","label":"Date/Time"},{"value":"craft\\fields\\Lightswitch","label":"Lightswitch"},{"value":"craft\\fields\\PlainText","label":"Plain Text"},{"value":"craft\\redactor\\Field","label":"Redactor"},{"value":"craft\\fields\\Tags","label":"Tags"} + {"value":"craft\\fields\\Assets","label":"Assets"},{"value":"craft\\fields\\Date","label":"Date/Time"},{"value":"craft\\fields\\Lightswitch","label":"Lightswitch"},{"value":"craft\\fields\\PlainText","label":"Plain Text"},{"value":"craft\\redactor\\Field","label":"Redactor"}, + {"value":"craft\\ckeditor\\Field","label":"CKEditor"},{"value":"craft\\fields\\Tags","label":"Tags"} ] } ] @@ -112,6 +116,9 @@ addRowLabel: 'Add a field', rows: settings.showApiColumnFields, errors: settings.getErrors( 'showApiColumnFields' ), + allowAdd: true, + allowReorder: true, + allowDelete: true, cols: [ { heading: 'API Field', @@ -140,7 +147,7 @@ "optgroup":"From PBS API", "label":"From PBS API" }, - { + { "value":"premiered_on", "label":"premiered_on" }, @@ -214,7 +221,8 @@ type: 'select', options: [ {"label":"— Select Field Type —"}, - {"value":"craft\\fields\\Assets","label":"Assets"},{"value":"craft\\fields\\Date","label":"Date/Time"},{"value":"craft\\fields\\Lightswitch","label":"Lightswitch"},{"value":"craft\\fields\\PlainText","label":"Plain Text"},{"value":"craft\\redactor\\Field","label":"Redactor"},{"value":"craft\\fields\\Tags","label":"Tags"} + {"value":"craft\\fields\\Assets","label":"Assets"},{"value":"craft\\fields\\Date","label":"Date/Time"},{"value":"craft\\fields\\Lightswitch","label":"Lightswitch"},{"value":"craft\\fields\\PlainText","label":"Plain Text"},{"value":"craft\\redactor\\Field","label":"Redactor"}, + {"value":"craft\\ckeditor\\Field","label":"CKEditor"},{"value":"craft\\fields\\Tags","label":"Tags"} ] } ] diff --git a/src/templates/settings/_fieldlayout.twig b/src/templates/settings/_fieldlayout.twig index 92e2787..e13eab2 100644 --- a/src/templates/settings/_fieldlayout.twig +++ b/src/templates/settings/_fieldlayout.twig @@ -1,123 +1,123 @@ -{% import '_includes/forms' as forms %} - -{% set groups = craft.app.fields.getAllGroups() %} -{% set settingFields = [] %} -{% set showSettingFields = [] %} -{% for tabName, tabFields in settings.fieldLayout %} - {% for tabField in tabFields %} - {% set settingFields = settingFields | merge( [ tabField ] ) %} - {% endfor %} -{% endfor %} -{% for tabName, tabFields in settings.showFieldLayout %} - {% for tabField in tabFields %} - {% set showSettingFields = showSettingFields | merge( [ tabField ] ) %} - {% endfor %} -{% endfor %} - - +{#{% import '_includes/forms' as forms %}#} + +{#{% set groups = craft.app.fields.getAllGroups() %}#} +{#{% set settingFields = [] %}#} +{#{% set showSettingFields = [] %}#} +{#{% for tabName, tabFields in settings.fieldLayout %}#} +{# {% for tabField in tabFields %}#} +{# {% set settingFields = settingFields | merge( [ tabField ] ) %}#} +{# {% endfor %}#} +{#{% endfor %}#} +{#{% for tabName, tabFields in settings.showFieldLayout %}#} +{# {% for tabField in tabFields %}#} +{# {% set showSettingFields = showSettingFields | merge( [ tabField ] ) %}#} +{# {% endfor %}#} +{#{% endfor %}#} + +{##} diff --git a/src/templates/show.twig b/src/templates/show.twig index 79152e4..c40498f 100644 --- a/src/templates/show.twig +++ b/src/templates/show.twig @@ -73,8 +73,8 @@ {{ forms.textField({ first: true, - label: 'Show Content ID'|t( 'mediamanager' ), - instructions: 'PBS Media Content ID used by this show.'|t( 'mediamanager' ), + label: 'Show API Key'|t( 'mediamanager' ), + instructions: 'PBS Media API Key used by this show.'|t( 'mediamanager' ), id: 'apiKey', name: 'apiKey', value: activeShow.apiKey, diff --git a/src/templates/stale-media.twig b/src/templates/stale-media.twig index cea7fef..eedc375 100644 --- a/src/templates/stale-media.twig +++ b/src/templates/stale-media.twig @@ -9,12 +9,12 @@ {% exit 404 %} {% endif %} -{% set sources = craft.app.elementIndexes.getSources(elementType, 'index') %} -{% set customizableSources = (sources is not empty and context == 'index' and currentUser.admin) %} +{% set sources = craft.app.elementSources.getSources(elementType, 'index', true) %} +{#{% set customizableSources = (sources is not empty and context == 'index' and currentUser.admin) %}#} {% set showSiteMenu = (craft.app.getIsMultiSite() ? (showSiteMenu ?? 'auto') : false) %} {% if showSiteMenu == 'auto' %} - {% set showSiteMenu = elementInstance.isLocalized() %} + {% set showSiteMenu = elementInstance.isLocalized() %} {% endif %} {% block contextMenu %} @@ -28,41 +28,55 @@ {% set crumbs = [ { label: "Media Manager", url: url( pluginCpUrl ) } ] %} {% block sidebar %} - {% if sources is not empty %} - - - {% if customizableSources %} -
- - {% endif %} - {% endif %} + {% if sources is not empty %} + + +
+ {% endif %} +{% endblock %} + +{% block toolbar %} + {% include '_elements/toolbar' with { + showSiteMenu: false, + } %} {% endblock %} {% block content %} -
- {% include "_elements/indexcontainer" with { - showSiteMenu: false - } %} -
+ {% endblock %} {% block footer %} -
 
-
{{ 'Export…'|t('app') }}
+ +
 
+
+
+ +
{% endblock %} {% block initJs %} - Craft.elementIndex = Craft.createElementIndex('{{ elementType|e("js") }}', $('#main'), { - elementTypeName: '{{ elementInstance.displayName()|e("js") }}', - elementTypePluralName: '{{ 'Entries'|e("js") }}', - context: '{{ context }}', - storageKey: 'elementindex.{{ elementType|e("js") }}', - criteria: {markedForDeletion: true, ...Craft.defaultIndexCriteria} + Craft.elementIndex = Craft.createElementIndex('{{ elementType|e("js") }}', $('#page-container'), { + elementTypeName: '{{ elementInstance.displayName()|e("js") }}', + elementTypePluralName: '{{ elementInstance.pluralDisplayName()|e("js") }}', + context: '{{ context }}', + storageKey: 'elementindex.{{ elementType|e("js") }}', + criteria: {markedForDeletion: true, ...Craft.defaultIndexCriteria}, + toolbarSelector: '#toolbar', + canHaveDrafts: {{ false|json_encode|raw }}, + defaultSource: {{ (defaultSource ?? null)|json_encode|raw }}, + defaultSourcePath: {{ (defaultSourcePath ?? null)|json_encode|raw }}, }); + var _mediaSource = $( '#sidebar nav ul li a[data-handle="{{ craft.app.getPlugins().getPlugin( 'mediamanager' ).getSettings().mediaSection }}"]' ).attr( 'data-key' ); Craft.elementIndex.selectSourceByKey( _mediaSource ); {% endblock %} diff --git a/src/templates/synchronize.twig b/src/templates/synchronize.twig index a2a9dcc..2dcb0a8 100644 --- a/src/templates/synchronize.twig +++ b/src/templates/synchronize.twig @@ -16,7 +16,7 @@ {% endfor %} {% set validatedShows = 0 %} -{% if shows | length %} +{% if shows|length %} {% for show in shows %} {% if show.apiKey %} {% set validatedShows = validatedShows + 1 %} @@ -26,31 +26,31 @@ {% block sidebar %} {% if craft.mediaManagerReady() %} - {% if shows | length %} + {% if shows|length %} {% endif %} {% endif %} {% endblock %} @@ -67,6 +67,19 @@ {% set apiColumnFields = craft.app.getPlugins().getPlugin( 'mediamanager' ).getSettings().apiColumnFields %}
+
+

+
+ + {% if validatedShows | length %} +
    + {% for show in shows %} + {% if show.apiKey %} +
  1. {{ show.name }}
  2. + {% endif %} + {% endfor %} +

+ {% endif %} {{ forms.checkboxField({ first: false, @@ -119,7 +132,7 @@
{{ 'Update All Media'|t('media-manager') }}
- {% set title = 'Synchronize All Shows' %} + {% case 'single' %}
@@ -186,9 +199,20 @@ values: '*', instructions: 'Choose which fields you would like to be updated during this sync.', }) }} + + {{ forms.selectField({ + first: false, + label: "Media Asset's Site", + instructions: "Site associated with this media asset."|t('media-manager'), + id: 'siteId', + name: 'siteId[]', + options: siteGroups, + value: activeShow.siteId, + required: true, + }) }}
{{ 'Update Media'|t('media-manager') }}
- {% set title = 'Synchronize Single Media' %} + {% case 'show-entries' %}
@@ -233,7 +257,7 @@
{{ 'Synchronize Show Entries'|t('media-manager') }}
- {% set title = 'Synchronize Show Entries' %} + {% default %} {% set apiColumnFields = craft.app.getPlugins().getPlugin( 'mediamanager' ).getSettings().apiColumnFields %} @@ -296,15 +320,14 @@ {% else %} {% if not activeShow.id and not activeShow.apiKey and not activeShow.name and not activeShow.siteId %} Nothing to see here, you might want to create New Show first.

- Create New Show + Create New Show {% else %} To start Synchronize, you need to set a valid API ID for {{ activeShow.name }} first.

- Set API Key Now + Set API Key Now {% endif %} {% endif %} {% endswitch %} - {% set title = 'Synchronize' %} {% else %} Nothing to see here, you might want to create New Show first. {% endif %} @@ -314,5 +337,5 @@ {% endset %} {% js on ready %} - new Craft.SynchronizeAdmin(); + new Craft.SynchronizeAdmin() {% endjs %} diff --git a/src/validators/ApiColumnFieldsValidator.php b/src/validators/ApiColumnFieldsValidator.php index ab12d01..2b082d9 100644 --- a/src/validators/ApiColumnFieldsValidator.php +++ b/src/validators/ApiColumnFieldsValidator.php @@ -51,9 +51,9 @@ public function validateAttribute( $model, $attribute ) } } - if( count( $checkFieldApis ) != count( array_unique( $checkFieldApis ) ) ) { - $this->addError( $model, $attribute, 'Special Field on API Field need only to be used once.' ); - } + // if( count( $checkFieldApis ) != count( array_unique( $checkFieldApis ) ) ) { + // $this->addError( $model, $attribute, 'Special Field on API Field need only to be used once.' ); + // } // Check if any duplication on fieldHandle if( count( $fieldHandles ) != count( array_unique( $fieldHandles ) ) ) {