diff options
author | Morris Jobke <hey@morrisjobke.de> | 2018-04-25 08:47:14 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-04-25 08:47:14 +0200 |
commit | b3a0dec8d54e28aa9f3e91cd93877946f58d696a (patch) | |
tree | 6c603a06c82d42f9817800a332af1e26c2e4c433 /apps | |
parent | 3e14f21ae76a591902fddae74cafa958a0b4a0a8 (diff) | |
parent | d771f6591153ff1ceabe69e0e1f91e99a1873eb0 (diff) | |
download | nextcloud-server-b3a0dec8d54e28aa9f3e91cd93877946f58d696a.tar.gz nextcloud-server-b3a0dec8d54e28aa9f3e91cd93877946f58d696a.zip |
Merge pull request #8540 from nextcloud/theming-advanced
Add option for header logo and favicon in theming app
Diffstat (limited to 'apps')
-rw-r--r-- | apps/theming/appinfo/routes.php | 13 | ||||
-rw-r--r-- | apps/theming/css/settings-admin.css | 107 | ||||
-rw-r--r-- | apps/theming/css/settings-admin.scss | 120 | ||||
-rw-r--r-- | apps/theming/css/theming.scss | 47 | ||||
-rw-r--r-- | apps/theming/js/settings-admin.js | 114 | ||||
-rw-r--r-- | apps/theming/lib/Controller/IconController.php | 46 | ||||
-rw-r--r-- | apps/theming/lib/Controller/ThemingController.php | 173 | ||||
-rw-r--r-- | apps/theming/lib/ImageManager.php | 85 | ||||
-rw-r--r-- | apps/theming/lib/Settings/Admin.php | 24 | ||||
-rw-r--r-- | apps/theming/lib/ThemingDefaults.php | 53 | ||||
-rw-r--r-- | apps/theming/templates/settings-admin.php | 44 | ||||
-rw-r--r-- | apps/theming/tests/Controller/IconControllerTest.php | 44 | ||||
-rw-r--r-- | apps/theming/tests/Controller/ThemingControllerTest.php | 198 | ||||
-rw-r--r-- | apps/theming/tests/ImageManagerTest.php | 111 | ||||
-rw-r--r-- | apps/theming/tests/Settings/AdminTest.php | 31 | ||||
-rw-r--r-- | apps/theming/tests/ThemingDefaultsTest.php | 123 |
16 files changed, 713 insertions, 620 deletions
diff --git a/apps/theming/appinfo/routes.php b/apps/theming/appinfo/routes.php index a69ddc1a6c9..f3483dbf99b 100644 --- a/apps/theming/appinfo/routes.php +++ b/apps/theming/appinfo/routes.php @@ -39,8 +39,8 @@ return ['routes' => [ 'verb' => 'POST' ], [ - 'name' => 'Theming#updateLogo', - 'url' => '/ajax/updateLogo', + 'name' => 'Theming#uploadImage', + 'url' => '/ajax/uploadImage', 'verb' => 'POST' ], [ @@ -49,13 +49,8 @@ return ['routes' => [ 'verb' => 'GET', ], [ - 'name' => 'Theming#getLogo', - 'url' => '/logo', - 'verb' => 'GET', - ], - [ - 'name' => 'Theming#getLoginBackground', - 'url' => '/loginbackground', + 'name' => 'Theming#getImage', + 'url' => '/image/{key}', 'verb' => 'GET', ], [ diff --git a/apps/theming/css/settings-admin.css b/apps/theming/css/settings-admin.css deleted file mode 100644 index b0fdb79b291..00000000000 --- a/apps/theming/css/settings-admin.css +++ /dev/null @@ -1,107 +0,0 @@ -#theming input { - width: 230px; -} - -#theming input:focus, -#theming input:active { - padding-right: 30px; -} - -#theming .upload-logo-field { - display: none; -} - -#theming div > label { - position: relative; -} - -#theming .theme-undo { - position: absolute; - top: -7px; - right: 7px; - cursor: pointer; - opacity: .3; - padding: 7px; - vertical-align: top; - display: inline-block; - visibility: hidden; -} -form.uploadButton { - width: 356px; -} -#theming form .theme-undo, -#theming .theme-remove-bg { - cursor: pointer; - opacity: .3; - padding: 7px; - vertical-align: top; - display: inline-block; - float: right; - position: relative; - top: 4px; - right: 0px; - visibility: visible; -} -#theming input[type='text']:hover + .theme-undo, -#theming input[type='text'] + .theme-undo:hover, -#theming input[type='text']:focus + .theme-undo, -#theming input[type='text']:active + .theme-undo { - visibility: visible; -} - -#theming label span { - display: inline-block; - min-width: 120px; - padding: 8px 0px; - vertical-align: top; -} - -#theming .icon-upload, -#theming .uploadButton .icon-loading-small { - padding: 8px 20px; - width: 20px; - margin: 2px 0px; - min-height: 32px; - display: inline-block; -} - -#theming_settings_status { - height: 26px; - margin: 10px; -} - -#theming_settings_loading { - display: inline-block; - vertical-align: middle; - margin-right: 10px; -} - -#theming_settings_msg { - vertical-align: middle; - border-radius: 3px; -} - -#theming-preview-logo { - cursor: pointer; -} - -#theming-preview { - width: 230px; - height: 140px; - background-size: cover; - background-position: center center; - text-align: center; - margin-left: 123px; - margin-top: 10px; - cursor: pointer; -} - -#theming-preview img { - max-width: 20%; - max-height: 20%; - margin-top: 20px; -} - -.theming-hints { - margin-top: 20px; -}
\ No newline at end of file diff --git a/apps/theming/css/settings-admin.scss b/apps/theming/css/settings-admin.scss new file mode 100644 index 00000000000..ceb560f0f02 --- /dev/null +++ b/apps/theming/css/settings-admin.scss @@ -0,0 +1,120 @@ +#theming { + input { + width: 230px; + } + + input:focus, + input:active { + padding-right: 30px; + } + + .fileupload { + display: none; + } + + div > label { + position: relative; + } + + .theme-undo { + position: absolute; + top: -7px; + right: 7px; + cursor: pointer; + opacity: .3; + padding: 7px; + vertical-align: top; + display: inline-block; + visibility: hidden; + } + form.uploadButton { + width: 356px; + } + form .theme-undo, + .theme-remove-bg { + cursor: pointer; + opacity: .3; + padding: 7px; + vertical-align: top; + display: inline-block; + float: right; + position: relative; + top: 4px; + right: 0px; + visibility: visible; + } + input[type='text']:hover + .theme-undo, + input[type='text'] + .theme-undo:hover, + input[type='text']:focus + .theme-undo, + input[type='text']:active + .theme-undo { + visibility: visible; + } + + label span { + display: inline-block; + min-width: 120px; + padding: 8px 0px; + vertical-align: top; + } + + .icon-upload, + .uploadButton .icon-loading-small { + padding: 8px 20px; + width: 20px; + margin: 2px 0px; + min-height: 32px; + display: inline-block; + } + + #theming_settings_status { + height: 26px; + margin: 10px; + } + + #theming_settings_loading { + display: inline-block; + vertical-align: middle; + margin-right: 10px; + } + + #theming_settings_msg { + vertical-align: middle; + border-radius: 3px; + } + + #theming-preview { + width: 230px; + height: 140px; + background-size: cover; + background-position: center center; + text-align: center; + margin-left: 123px; + margin-top: 10px; + margin-bottom: 20px; + cursor: pointer; + + #theming-preview-logo { + cursor: pointer; + width: 20%; + height: 20%; + margin-top: 20px; + display: inline-block; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + } + } + + .theming-hints { + margin-top: 20px; + } + + .image-preview { + display: inline-block; + width: 80px; + height: 36px; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + } +}
\ No newline at end of file diff --git a/apps/theming/css/theming.scss b/apps/theming/css/theming.scss index 3bb26a14814..f65e20fa9b7 100644 --- a/apps/theming/css/theming.scss +++ b/apps/theming/css/theming.scss @@ -92,6 +92,7 @@ /* override styles for login screen in guest.css */ @if variable_exists('theming-logo-mime') and $theming-logo-mime != '' { + #theming-preview-logo, #header .logo { background-image: url(#{$image-logo}); background-size: contain; @@ -99,13 +100,45 @@ #body-login #header .logo { margin-bottom: 22px; } +} @else { + #theming-preview-logo { + background-image: url(#{$image-logo}); + } } -#body-login, -#firstrunwizard .firstrunwizard-header, -#theming-preview { - background-image: url(#{$image-login-background}); - background-color: $color-primary; +@if variable_exists('theming-background-mime') and $theming-background-mime != '' { + #body-login, + #firstrunwizard .firstrunwizard-header, + #theming-preview { + background-image: url(#{$image-login-background}); + background-color: $color-primary; + } +} @else { + #theming-preview { + background-image: url(#{$image-login-background}); + background-color: $color-primary; + } +} + +@if variable_exists('theming-logoheader-mime') and $theming-logoheader-mime != '' { + #theming .advanced-option-logoheader .image-preview, + body:not(#body-login) #header .logo { + background-image: url(#{$image-logoheader}); + } +} @else { + #theming .advanced-option-favicon .image-preview { + background-image: none; + } +} + +@if variable_exists('theming-favicon-mime') and $theming-favicon-mime != '' { + #theming .advanced-option-favicon .image-preview { + background-image: url(#{$image-favicon}); + } +} @else { + #theming .advanced-option-favicon .image-preview { + background-image: none; + } } input.primary, @@ -134,6 +167,10 @@ input.primary, } } +} @else { + #body-login { + background-color: $color-primary; + } } @if ($color-primary == #ffffff) { diff --git a/apps/theming/js/settings-admin.js b/apps/theming/js/settings-admin.js index 1f416bb2940..25ac092a964 100644 --- a/apps/theming/js/settings-admin.js +++ b/apps/theming/js/settings-admin.js @@ -35,7 +35,6 @@ function setThemingValue(setting, value) { OC.msg.finishedSaving('#theming_settings_msg', response); $('#theming_settings_loading').hide(); }); - } function preview(setting, value, serverCssUrl) { @@ -69,17 +68,6 @@ function preview(setting, value, serverCssUrl) { } reloadStylesheets(OC.generateUrl('/apps/theming/styles')); - // Preview images - var timestamp = new Date().getTime(); - if (setting === 'logoMime') { - var previewImageLogo = document.getElementById('theming-preview-logo'); - if (value !== '') { - previewImageLogo.src = OC.generateUrl('/apps/theming/logo') + "?v" + timestamp; - } else { - previewImageLogo.src = OC.getRootPath() + '/core/img/logo.svg?v' + timestamp; - } - } - if (setting === 'name') { window.document.title = t('core', 'Admin') + " - " + value; } @@ -119,53 +107,36 @@ $(document).ready(function () { $('#theming .theme-undo').each(function() { var setting = $(this).data('setting'); var value = $('#theming-'+setting).val(); - if(setting === 'logoMime' || setting === 'backgroundMime') { - var value = $('#current-'+setting).val(); - } hideUndoButton(setting, value); }); - var uploadParamsLogo = { - pasteZone: null, - dropZone: null, - done: function (e, response) { - preview('logoMime', response.result.data.name); - OC.msg.finishedSaving('#theming_settings_msg', response.result); - $('label#uploadlogo').addClass('icon-upload').removeClass('icon-loading-small'); - $('.theme-undo[data-setting=logoMime]').show(); - }, - submit: function(e, response) { - startLoading(); - $('label#uploadlogo').removeClass('icon-upload').addClass('icon-loading-small'); - }, - fail: function (e, response){ - OC.msg.finishedError('#theming_settings_msg', response._response.jqXHR.responseJSON.data.message); - $('label#uploadlogo').addClass('icon-upload').removeClass('icon-loading-small'); - $('#theming_settings_loading').hide(); - } - }; - var uploadParamsLogin = { + $('.fileupload').fileupload({ pasteZone: null, dropZone: null, done: function (e, response) { - preview('backgroundMime', response.result.data.name); + var $form = $(e.target).closest('form'); + var key = $form.data('image-key'); + + preview(key + 'Mime', response.result.data.name, response.result.data.serverCssUrl); + $form.find('.image-preview').css('backgroundImage', response.result.data.url + '?v=' + new Date().getTime()); OC.msg.finishedSaving('#theming_settings_msg', response.result); - $('label#upload-login-background').addClass('icon-upload').removeClass('icon-loading-small'); - $('.theme-undo[data-setting=backgroundMime]').show(); + $form.find('label.button').addClass('icon-upload').removeClass('icon-loading-small'); + $form.find('.theme-undo').show(); }, submit: function(e, response) { + var $form = $(e.target).closest('form'); + var key = $form.data('image-key'); startLoading(); - $('label#upload-login-background').removeClass('icon-upload').addClass('icon-loading-small'); + $form.find('label.button').removeClass('icon-upload').addClass('icon-loading-small'); }, fail: function (e, response){ - $('label#upload-login-background').removeClass('icon-loading-small').addClass('icon-upload'); + var $form = $(e.target).closest('form'); OC.msg.finishedError('#theming_settings_msg', response._response.jqXHR.responseJSON.data.message); + $form.find('label.button').addClass('icon-upload').removeClass('icon-loading-small'); $('#theming_settings_loading').hide(); } - }; + }); - $('#uploadlogo').fileupload(uploadParamsLogo); - $('#upload-login-background').fileupload(uploadParamsLogin); // clicking preview should also trigger file upload dialog $('#theming-preview-logo').on('click', function(e) { e.stopPropagation(); @@ -202,46 +173,42 @@ $(document).ready(function () { $('#theming-name').change(function(e) { var el = $(this); - if(checkName()){ - $.when(el.focusout()).then(function() { - setThemingValue('name', $(this).val()); - }); - if (e.keyCode == 13) { - setThemingValue('name', $(this).val()); - } - } }); - $('#theming-url').change(function(e) { + $('#theming input[type=text]').change(function(e) { var el = $(this); - $.when(el.focusout()).then(function() { - setThemingValue('url', $(this).val()); - }); - if (e.keyCode == 13) { - setThemingValue('url', $(this).val()); + var setting = el.parent().find('div[data-setting]').data('setting'); + var value = $(this).val(); + + if(setting === 'color') { + if (value.indexOf('#') !== 0) { + value = '#' + value; + } + } + if(setting === 'name') { + if(checkName()){ + $.when(el.focusout()).then(function() { + setThemingValue('name', value); + }); + if (e.keyCode == 13) { + setThemingValue('name', value); + } + } } - }); - $('#theming-slogan').change(function(e) { - var el = $(this); $.when(el.focusout()).then(function() { - setThemingValue('slogan', $(this).val()); + setThemingValue(setting, value); }); if (e.keyCode == 13) { - setThemingValue('slogan', $(this).val()); + setThemingValue(setting, value); } }); - $('#theming-color').change(function (e) { - var color = $(this).val(); - if (color.indexOf('#') !== 0) { - color = '#' + color; - } - setThemingValue('color', color); - }); - $('.theme-undo').click(function (e) { var setting = $(this).data('setting'); + var $form = $(this).closest('form'); + var image = $form.data('image-key'); + startLoading(); $('.theme-undo[data-setting=' + setting + ']').hide(); $.post( @@ -251,7 +218,7 @@ $(document).ready(function () { var colorPicker = document.getElementById('theming-color'); colorPicker.style.backgroundColor = response.data.value; colorPicker.value = response.data.value.slice(1).toUpperCase(); - } else if (setting !== 'logoMime' && setting !== 'backgroundMime') { + } else if (!image) { var input = document.getElementById('theming-'+setting); input.value = response.data.value; } @@ -262,11 +229,12 @@ $(document).ready(function () { $('.theme-remove-bg').click(function() { startLoading(); $.post( - OC.generateUrl('/apps/theming/ajax/updateLogo'), {'backgroundColor' : true} + OC.generateUrl('/apps/theming/ajax/updateStylesheet'), {'setting' : 'backgroundMime', 'value' : 'backgroundColor'} ).done(function(response) { - preview('backgroundMime', 'backgroundColor'); + preview('backgroundMime', 'backgroundColor', response.data.serverCssUrl); }).fail(function(response) { OC.msg.finishedSaving('#theming_settings_msg', response); + $('#theming_settings_loading').hide(); }); }); diff --git a/apps/theming/lib/Controller/IconController.php b/apps/theming/lib/Controller/IconController.php index 7a5f76de6b6..61df7b0b353 100644 --- a/apps/theming/lib/Controller/IconController.php +++ b/apps/theming/lib/Controller/IconController.php @@ -33,21 +33,16 @@ use OCP\AppFramework\Http; use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Http\FileDisplayResponse; use OCP\AppFramework\Http\DataDisplayResponse; +use OCP\AppFramework\Http\Response; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Files\NotFoundException; use OCP\IRequest; -use OCA\Theming\Util; -use OCP\IConfig; class IconController extends Controller { /** @var ThemingDefaults */ private $themingDefaults; - /** @var Util */ - private $util; /** @var ITimeFactory */ private $timeFactory; - /** @var IConfig */ - private $config; /** @var IconBuilder */ private $iconBuilder; /** @var ImageManager */ @@ -61,19 +56,16 @@ class IconController extends Controller { * @param string $appName * @param IRequest $request * @param ThemingDefaults $themingDefaults - * @param Util $util * @param ITimeFactory $timeFactory - * @param IConfig $config * @param IconBuilder $iconBuilder * @param ImageManager $imageManager + * @param FileAccessHelper $fileAccessHelper */ public function __construct( $appName, IRequest $request, ThemingDefaults $themingDefaults, - Util $util, ITimeFactory $timeFactory, - IConfig $config, IconBuilder $iconBuilder, ImageManager $imageManager, FileAccessHelper $fileAccessHelper @@ -81,9 +73,7 @@ class IconController extends Controller { parent::__construct($appName, $request); $this->themingDefaults = $themingDefaults; - $this->util = $util; $this->timeFactory = $timeFactory; - $this->config = $config; $this->iconBuilder = $iconBuilder; $this->imageManager = $imageManager; $this->fileAccessHelper = $fileAccessHelper; @@ -96,16 +86,17 @@ class IconController extends Controller { * @param $app string app name * @param $image string image file name (svg required) * @return FileDisplayResponse|NotFoundResponse + * @throws \Exception */ - public function getThemedIcon($app, $image) { + public function getThemedIcon(string $app, string $image): Response { try { - $iconFile = $this->imageManager->getCachedImage("icon-" . $app . '-' . str_replace("/","_",$image)); + $iconFile = $this->imageManager->getCachedImage('icon-' . $app . '-' . str_replace('/', '_',$image)); } catch (NotFoundException $exception) { $icon = $this->iconBuilder->colorSvg($app, $image); - if ($icon === false || $icon === "") { + if ($icon === false || $icon === '') { return new NotFoundResponse(); } - $iconFile = $this->imageManager->setCachedImage("icon-" . $app . '-' . str_replace("/","_",$image), $icon); + $iconFile = $this->imageManager->setCachedImage('icon-' . $app . '-' . str_replace('/', '_',$image), $icon); } if ($iconFile !== false) { $response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); @@ -116,9 +107,9 @@ class IconController extends Controller { $response->addHeader('Expires', $expires->format(\DateTime::RFC2822)); $response->addHeader('Pragma', 'cache'); return $response; - } else { - return new NotFoundResponse(); } + + return new NotFoundResponse(); } /** @@ -129,10 +120,17 @@ class IconController extends Controller { * * @param $app string app name * @return FileDisplayResponse|DataDisplayResponse + * @throws \Exception */ - public function getFavicon($app = "core") { + public function getFavicon(string $app = 'core'): Response { $response = null; - if ($this->themingDefaults->shouldReplaceIcons()) { + $iconFile = null; + try { + $iconFile = $this->imageManager->getImage('favicon'); + $response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); + } catch (NotFoundException $e) { + } + if ($iconFile === null && $this->themingDefaults->shouldReplaceIcons()) { try { $iconFile = $this->imageManager->getCachedImage('favIcon-' . $app); } catch (NotFoundException $exception) { @@ -164,9 +162,15 @@ class IconController extends Controller { * * @param $app string app name * @return FileDisplayResponse|NotFoundResponse + * @throws \Exception */ - public function getTouchIcon($app = "core") { + public function getTouchIcon(string $app = 'core'): Response { $response = null; + try { + $iconFile = $this->imageManager->getImage('favicon'); + $response = new FileDisplayResponse($iconFile, Http::STATUS_OK, ['Content-Type' => 'image/x-icon']); + } catch (NotFoundException $e) { + } if ($this->themingDefaults->shouldReplaceIcons()) { try { $iconFile = $this->imageManager->getCachedImage('touchIcon-' . $app); diff --git a/apps/theming/lib/Controller/ThemingController.php b/apps/theming/lib/Controller/ThemingController.php index 47f806d16f9..421af051998 100644 --- a/apps/theming/lib/Controller/ThemingController.php +++ b/apps/theming/lib/Controller/ThemingController.php @@ -33,6 +33,7 @@ namespace OCA\Theming\Controller; use OC\Template\SCSSCacher; +use OCA\Theming\ImageManager; use OCA\Theming\ThemingDefaults; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; @@ -81,6 +82,8 @@ class ThemingController extends Controller { private $urlGenerator; /** @var IAppManager */ private $appManager; + /** @var ImageManager */ + private $imageManager; /** * ThemingController constructor. @@ -97,6 +100,7 @@ class ThemingController extends Controller { * @param SCSSCacher $scssCacher * @param IURLGenerator $urlGenerator * @param IAppManager $appManager + * @param ImageManager $imageManager */ public function __construct( $appName, @@ -110,7 +114,8 @@ class ThemingController extends Controller { IAppData $appData, SCSSCacher $scssCacher, IURLGenerator $urlGenerator, - IAppManager $appManager + IAppManager $appManager, + ImageManager $imageManager ) { parent::__construct($appName, $request); @@ -124,13 +129,14 @@ class ThemingController extends Controller { $this->scssCacher = $scssCacher; $this->urlGenerator = $urlGenerator; $this->appManager = $appManager; + $this->imageManager = $imageManager; } /** * @param string $setting * @param string $value * @return DataResponse - * @internal param string $color + * @throws NotPermittedException */ public function updateStylesheet($setting, $value) { $value = trim($value); @@ -195,27 +201,15 @@ class ThemingController extends Controller { } /** - * Update the logos and background image - * * @return DataResponse + * @throws NotPermittedException */ - public function updateLogo() { - $backgroundColor = $this->request->getParam('backgroundColor', false); - if($backgroundColor) { - $this->themingDefaults->set('backgroundMime', 'backgroundColor'); - return new DataResponse( - [ - 'data' => - [ - 'name' => 'backgroundColor', - 'message' => $this->l10n->t('Saved') - ], - 'status' => 'success' - ] - ); - } - $newLogo = $this->request->getUploadedFile('uploadlogo'); - $newBackgroundLogo = $this->request->getUploadedFile('upload-login-background'); + public function uploadImage(): DataResponse { + // logo / background + // new: favicon logo-header + // + $key = $this->request->getParam('key'); + $image = $this->request->getUploadedFile('image'); $error = null; $phpFileUploadErrors = [ UPLOAD_ERR_OK => $this->l10n->t('The file was uploaded'), @@ -227,14 +221,11 @@ class ThemingController extends Controller { UPLOAD_ERR_CANT_WRITE => $this->l10n->t('Could not write file to disk'), UPLOAD_ERR_EXTENSION => $this->l10n->t('A PHP extension stopped the file upload'), ]; - if (empty($newLogo) && empty($newBackgroundLogo)) { + if (empty($image)) { $error = $this->l10n->t('No file uploaded'); } - if (!empty($newLogo) && array_key_exists('error', $newLogo) && $newLogo['error'] !== UPLOAD_ERR_OK) { - $error = $phpFileUploadErrors[$newLogo['error']]; - } - if (!empty($newBackgroundLogo) && array_key_exists('error', $newBackgroundLogo) && $newBackgroundLogo['error'] !== UPLOAD_ERR_OK) { - $error = $phpFileUploadErrors[$newBackgroundLogo['error']]; + if (!empty($image) && array_key_exists('error', $image) && $image['error'] !== UPLOAD_ERR_OK) { + $error = $phpFileUploadErrors[$image['error']]; } if ($error !== null) { @@ -256,61 +247,53 @@ class ThemingController extends Controller { $folder = $this->appData->newFolder('images'); } - if (!empty($newLogo)) { - $target = $folder->newFile('logo'); - $supportedFormats = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'text/svg']; - if (!in_array($newLogo['type'], $supportedFormats)) { - return new DataResponse( - [ - 'data' => [ - 'message' => $this->l10n->t('Unsupported image type'), - ], - 'status' => 'failure', + $target = $folder->newFile($key); + $supportedFormats = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'text/svg']; + if (!in_array($image['type'], $supportedFormats)) { + return new DataResponse( + [ + 'data' => [ + 'message' => $this->l10n->t('Unsupported image type'), ], - Http::STATUS_UNPROCESSABLE_ENTITY - ); - } - $target->putContent(file_get_contents($newLogo['tmp_name'], 'r')); - $this->themingDefaults->set('logoMime', $newLogo['type']); - $name = $newLogo['name']; + 'status' => 'failure', + ], + Http::STATUS_UNPROCESSABLE_ENTITY + ); } - if (!empty($newBackgroundLogo)) { - $target = $folder->newFile('background'); - $image = @imagecreatefromstring(file_get_contents($newBackgroundLogo['tmp_name'], 'r')); - if ($image === false) { - return new DataResponse( - [ - 'data' => [ - 'message' => $this->l10n->t('Unsupported image type'), - ], - 'status' => 'failure', - ], - Http::STATUS_UNPROCESSABLE_ENTITY - ); - } + $resizeKeys = ['background']; + if (in_array($key, $resizeKeys, true)) { // Optimize the image since some people may upload images that will be // either to big or are not progressive rendering. + $newImage = @imagecreatefromstring(file_get_contents($image['tmp_name'], 'r')); + $tmpFile = $this->tempManager->getTemporaryFile(); - $newWidth = imagesx($image) < 4096 ? imagesx($image) : 4096; - $newHeight = imagesy($image) / (imagesx($image) / $newWidth); - $image = imagescale($image, $newWidth, $newHeight); + $newWidth = imagesx($newImage) < 4096 ? imagesx($newImage) : 4096; + $newHeight = imagesy($newImage) / (imagesx($newImage) / $newWidth); + $outputImage = imagescale($newImage, $newWidth, $newHeight); - imageinterlace($image, 1); - imagejpeg($image, $tmpFile, 75); - imagedestroy($image); + imageinterlace($outputImage, 1); + imagejpeg($outputImage, $tmpFile, 75); + imagedestroy($outputImage); $target->putContent(file_get_contents($tmpFile, 'r')); - $this->themingDefaults->set('backgroundMime', $newBackgroundLogo['type']); - $name = $newBackgroundLogo['name']; + } else { + $target->putContent(file_get_contents($image['tmp_name'], 'r')); } + $name = $image['name']; + + $this->themingDefaults->set($key.'Mime', $image['type']); + + $cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core'); return new DataResponse( [ 'data' => [ 'name' => $name, - 'message' => $this->l10n->t('Saved') + 'url' => $this->imageManager->getImageUrl($key), + 'message' => $this->l10n->t('Saved'), + 'serverCssUrl' => $this->urlGenerator->linkTo('', $this->scssCacher->getCachedSCSS('core', '/core/css/server.scss')) ], 'status' => 'success' ] @@ -322,27 +305,16 @@ class ThemingController extends Controller { * * @param string $setting setting which should be reverted * @return DataResponse + * @throws NotPermittedException */ - public function undo($setting) { + public function undo(string $setting): DataResponse { $value = $this->themingDefaults->undo($setting); // reprocess server scss for preview $cssCached = $this->scssCacher->process(\OC::$SERVERROOT, 'core/css/server.scss', 'core'); - if($setting === 'logoMime') { - try { - $file = $this->appData->getFolder('images')->getFile('logo'); - $file->delete(); - } catch (NotFoundException $e) { - } catch (NotPermittedException $e) { - } - } - if($setting === 'backgroundMime') { - try { - $file = $this->appData->getFolder('images')->getFile('background'); - $file->delete(); - } catch (NotFoundException $e) { - } catch (NotPermittedException $e) { - } + if (strpos($setting, 'Mime') !== -1) { + $imageKey = str_replace('Mime', '', $setting); + $this->imageManager->delete($imageKey); } return new DataResponse( @@ -362,37 +334,13 @@ class ThemingController extends Controller { * @PublicPage * @NoCSRFRequired * + * @param string $key * @return FileDisplayResponse|NotFoundResponse + * @throws \Exception */ - public function getLogo() { - try { - /** @var File $file */ - $file = $this->appData->getFolder('images')->getFile('logo'); - } catch (NotFoundException $e) { - return new NotFoundResponse(); - } - - $response = new FileDisplayResponse($file); - $response->cacheFor(3600); - $expires = new \DateTime(); - $expires->setTimestamp($this->timeFactory->getTime()); - $expires->add(new \DateInterval('PT24H')); - $response->addHeader('Expires', $expires->format(\DateTime::RFC2822)); - $response->addHeader('Pragma', 'cache'); - $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', '')); - return $response; - } - - /** - * @PublicPage - * @NoCSRFRequired - * - * @return FileDisplayResponse|NotFoundResponse - */ - public function getLoginBackground() { + public function getImage(string $key) { try { - /** @var File $file */ - $file = $this->appData->getFolder('images')->getFile('background'); + $file = $this->imageManager->getImage($key); } catch (NotFoundException $e) { return new NotFoundResponse(); } @@ -404,7 +352,7 @@ class ThemingController extends Controller { $expires->add(new \DateInterval('PT24H')); $response->addHeader('Expires', $expires->format(\DateTime::RFC2822)); $response->addHeader('Pragma', 'cache'); - $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', '')); + $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, $key . 'Mime', '')); return $response; } @@ -413,6 +361,9 @@ class ThemingController extends Controller { * @PublicPage * * @return FileDisplayResponse|NotFoundResponse + * @throws NotPermittedException + * @throws \Exception + * @throws \OCP\App\AppPathNotFoundException */ public function getStylesheet() { $appPath = $this->appManager->getAppPath('theming'); diff --git a/apps/theming/lib/ImageManager.php b/apps/theming/lib/ImageManager.php index 14dba0d0742..830ed7f34a9 100644 --- a/apps/theming/lib/ImageManager.php +++ b/apps/theming/lib/ImageManager.php @@ -24,11 +24,17 @@ namespace OCA\Theming; +use OCP\Files\SimpleFS\ISimpleFile; +use OCP\Files\SimpleFS\ISimpleFolder; use OCP\IConfig; use OCP\Files\IAppData; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; +use OCP\IURLGenerator; +/** + * @property IURLGenerator urlGenerator + */ class ImageManager { /** @var IConfig */ @@ -36,27 +42,79 @@ class ImageManager { /** @var IAppData */ private $appData; + /** @var array */ + private $supportedImageKeys = ['background', 'logo', 'logoheader', 'favicon']; + /** * ImageManager constructor. * * @param IConfig $config * @param IAppData $appData + * @param IURLGenerator $urlGenerator */ public function __construct(IConfig $config, - IAppData $appData + IAppData $appData, + IURLGenerator $urlGenerator ) { $this->config = $config; $this->appData = $appData; + $this->urlGenerator = $urlGenerator; + } + + public function getImageUrl(string $key): string { + $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); + try { + $this->getImage($key); + return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => $key ]) . '?v=' . $cacheBusterCounter; + } catch (NotFoundException $e) { + } + + switch ($key) { + case 'logo': + case 'logoheader': + case 'favicon': + return $this->urlGenerator->imagePath('core', 'logo.png') . '?v=' . $cacheBusterCounter; + case 'background': + return $this->urlGenerator->imagePath('core', 'background.png') . '?v=' . $cacheBusterCounter; + } + } + + public function getImageUrlAbsolute(string $key): string { + return $this->urlGenerator->getAbsoluteURL($this->getImageUrl($key)); + } + + /** + * @param $key + * @return ISimpleFile + * @throws NotFoundException + */ + public function getImage(string $key): ISimpleFile { + $logo = $this->config->getAppValue('theming', $key . 'Mime', false); + if ($logo === false) { + throw new NotFoundException(); + } + $folder = $this->appData->getFolder('images'); + return $folder->getFile($key); + } + + public function getCustomImages(): array { + $images = []; + foreach ($this->supportedImageKeys as $key) { + $images[$key] = [ + 'mime' => $this->config->getAppValue('theming', $key . 'Mime', ''), + 'url' => $this->getImageUrl($key), + ]; + } + return $images; } /** * Get folder for current theming files * - * @return \OCP\Files\SimpleFS\ISimpleFolder + * @return ISimpleFolder * @throws NotPermittedException - * @throws \RuntimeException */ - public function getCacheFolder() { + public function getCacheFolder(): ISimpleFolder { $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); try { $folder = $this->appData->getFolder($cacheBusterValue); @@ -73,8 +131,9 @@ class ImageManager { * @param string $filename * @throws NotFoundException * @return \OCP\Files\SimpleFS\ISimpleFile + * @throws NotPermittedException */ - public function getCachedImage($filename) { + public function getCachedImage(string $filename): ISimpleFile { $currentFolder = $this->getCacheFolder(); return $currentFolder->getFile($filename); } @@ -85,8 +144,10 @@ class ImageManager { * @param string $filename * @param string $data * @return \OCP\Files\SimpleFS\ISimpleFile + * @throws NotFoundException + * @throws NotPermittedException */ - public function setCachedImage($filename, $data) { + public function setCachedImage(string $filename, string $data): ISimpleFile { $currentFolder = $this->getCacheFolder(); if ($currentFolder->fileExists($filename)) { $file = $currentFolder->getFile($filename); @@ -97,8 +158,20 @@ class ImageManager { return $file; } + public function delete(string $key) { + try { + $file = $this->appData->getFolder('images')->getFile($key); + $file->delete(); + } catch (NotFoundException $e) { + } catch (NotPermittedException $e) { + } + } + /** * remove cached files that are not required any longer + * + * @throws NotPermittedException + * @throws NotFoundException */ public function cleanup() { $currentFolder = $this->getCacheFolder(); diff --git a/apps/theming/lib/Settings/Admin.php b/apps/theming/lib/Settings/Admin.php index d26a5680637..7c937f19790 100644 --- a/apps/theming/lib/Settings/Admin.php +++ b/apps/theming/lib/Settings/Admin.php @@ -29,6 +29,7 @@ namespace OCA\Theming\Settings; +use OCA\Theming\ImageManager; use OCA\Theming\ThemingDefaults; use OCP\AppFramework\Http\TemplateResponse; use OCP\IConfig; @@ -45,23 +46,25 @@ class Admin implements ISettings { private $themingDefaults; /** @var IURLGenerator */ private $urlGenerator; + /** @var ImageManager */ + private $imageManager; public function __construct(IConfig $config, IL10N $l, ThemingDefaults $themingDefaults, - IURLGenerator $urlGenerator) { + IURLGenerator $urlGenerator, + ImageManager $imageManager) { $this->config = $config; $this->l = $l; $this->themingDefaults = $themingDefaults; $this->urlGenerator = $urlGenerator; + $this->imageManager = $imageManager; } /** * @return TemplateResponse */ - public function getForm() { - $path = $this->urlGenerator->linkToRoute('theming.Theming.updateLogo'); - + public function getForm(): TemplateResponse { $themable = true; $errorMessage = ''; $theme = $this->config->getSystemValue('theme', ''); @@ -77,13 +80,10 @@ class Admin implements ISettings { 'url' => $this->themingDefaults->getBaseUrl(), 'slogan' => $this->themingDefaults->getSlogan(), 'color' => $this->themingDefaults->getColorPrimary(), - 'logo' => $this->themingDefaults->getLogo(), - 'logoMime' => $this->config->getAppValue('theming', 'logoMime', ''), - 'background' => $this->themingDefaults->getBackground(), - 'backgroundMime' => $this->config->getAppValue('theming', 'backgroundMime', ''), - 'uploadLogoRoute' => $path, + 'uploadLogoRoute' => $this->urlGenerator->linkToRoute('theming.Theming.uploadImage'), 'canThemeIcons' => $this->themingDefaults->shouldReplaceIcons(), - 'iconDocs' => $this->urlGenerator->linkToDocs('admin-theming-icons') + 'iconDocs' => $this->urlGenerator->linkToDocs('admin-theming-icons'), + 'images' => $this->imageManager->getCustomImages(), ]; return new TemplateResponse('theming', 'settings-admin', $parameters, ''); @@ -92,7 +92,7 @@ class Admin implements ISettings { /** * @return string the section ID, e.g. 'sharing' */ - public function getSection() { + public function getSection(): string { return 'theming'; } @@ -103,7 +103,7 @@ class Admin implements ISettings { * * E.g.: 70 */ - public function getPriority() { + public function getPriority(): int { return 5; } diff --git a/apps/theming/lib/ThemingDefaults.php b/apps/theming/lib/ThemingDefaults.php index ce4ab0abb55..2e6b667b1f6 100644 --- a/apps/theming/lib/ThemingDefaults.php +++ b/apps/theming/lib/ThemingDefaults.php @@ -36,7 +36,7 @@ namespace OCA\Theming; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; -use OCP\Files\IAppData; +use OCP\Files\NotFoundException; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IL10N; @@ -48,10 +48,10 @@ class ThemingDefaults extends \OC_Defaults { private $config; /** @var IL10N */ private $l; + /** @var ImageManager */ + private $imageManager; /** @var IURLGenerator */ private $urlGenerator; - /** @var IAppData */ - private $appData; /** @var ICacheFactory */ private $cacheFactory; /** @var Util */ @@ -83,9 +83,8 @@ class ThemingDefaults extends \OC_Defaults { * * @param IConfig $config * @param IL10N $l + * @param ImageManager $imageManager * @param IURLGenerator $urlGenerator - * @param \OC_Defaults $defaults - * @param IAppData $appData * @param ICacheFactory $cacheFactory * @param Util $util * @param IAppManager $appManager @@ -93,16 +92,16 @@ class ThemingDefaults extends \OC_Defaults { public function __construct(IConfig $config, IL10N $l, IURLGenerator $urlGenerator, - IAppData $appData, ICacheFactory $cacheFactory, Util $util, + ImageManager $imageManager, IAppManager $appManager ) { parent::__construct(); $this->config = $config; $this->l = $l; + $this->imageManager = $imageManager; $this->urlGenerator = $urlGenerator; - $this->appData = $appData; $this->cacheFactory = $cacheFactory; $this->util = $util; $this->appManager = $appManager; @@ -166,12 +165,12 @@ class ThemingDefaults extends \OC_Defaults { * @param bool $useSvg Whether to point to the SVG image or a fallback * @return string */ - public function getLogo($useSvg = true) { + public function getLogo($useSvg = true): string { $logo = $this->config->getAppValue('theming', 'logoMime', false); $logoExists = true; try { - $this->appData->getFolder('images')->getFile('logo'); + $this->imageManager->getImage('logo'); } catch (\Exception $e) { $logoExists = false; } @@ -187,7 +186,7 @@ class ThemingDefaults extends \OC_Defaults { return $logo . '?v=' . $cacheBusterCounter; } - return $this->urlGenerator->linkToRoute('theming.Theming.getLogo') . '?v=' . $cacheBusterCounter; + return $this->urlGenerator->linkToRoute('theming.Theming.getImage', [ 'key' => 'logo' ]) . '?v=' . $cacheBusterCounter; } /** @@ -195,14 +194,8 @@ class ThemingDefaults extends \OC_Defaults { * * @return string */ - public function getBackground() { - $cacheBusterCounter = $this->config->getAppValue('theming', 'cachebuster', '0'); - - if($this->util->isBackgroundThemed()) { - return $this->urlGenerator->linkToRoute('theming.Theming.getLoginBackground') . '?v=' . $cacheBusterCounter; - } - - return $this->urlGenerator->imagePath('core','background.png') . '?v=' . $cacheBusterCounter; + public function getBackground(): string { + return $this->imageManager->getImageUrl('background'); } /** @@ -238,12 +231,16 @@ class ThemingDefaults extends \OC_Defaults { $variables = [ 'theming-cachebuster' => "'" . $this->config->getAppValue('theming', 'cachebuster', '0') . "'", - 'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime', '') . "'", - 'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime', '') . "'" + 'theming-logo-mime' => "'" . $this->config->getAppValue('theming', 'logoMime') . "'", + 'theming-background-mime' => "'" . $this->config->getAppValue('theming', 'backgroundMime') . "'", + 'theming-logoheader-mime' => "'" . $this->config->getAppValue('theming', 'logoheaderMime') . "'", + 'theming-favicon-mime' => "'" . $this->config->getAppValue('theming', 'faviconMime') . "'" ]; - $variables['image-logo'] = "'".$this->getLogo()."'"; - $variables['image-login-background'] = "'".$this->getBackground()."'"; + $variables['image-logo'] = "'".$this->imageManager->getImageUrl('logo')."'"; + $variables['image-logoheader'] = "'".$this->imageManager->getImageUrl('logoheader')."'"; + $variables['image-favicon'] = "'".$this->imageManager->getImageUrl('favicon')."'"; + $variables['image-login-background'] = "'".$this->imageManager->getImageUrl('background')."'"; $variables['image-login-plain'] = 'false'; if ($this->config->getAppValue('theming', 'color', null) !== null) { @@ -273,10 +270,16 @@ class ThemingDefaults extends \OC_Defaults { } $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); - if ($image === 'favicon.ico' && $this->shouldReplaceIcons()) { + try { + $customFavicon = $this->imageManager->getImage('favicon'); + } catch (NotFoundException $e) { + $customFavicon = null; + } + + if ($image === 'favicon.ico' && ($customFavicon !== null || $this->shouldReplaceIcons())) { return $this->urlGenerator->linkToRoute('theming.Icon.getFavicon', ['app' => $app]) . '?v=' . $cacheBusterValue; } - if ($image === 'favicon-touch.png' && $this->shouldReplaceIcons()) { + if ($image === 'favicon-touch.png' && ($customFavicon !== null || $this->shouldReplaceIcons())) { return $this->urlGenerator->linkToRoute('theming.Icon.getTouchIcon', ['app' => $app]) . '?v=' . $cacheBusterValue; } if ($image === 'manifest.json') { @@ -321,6 +324,8 @@ class ThemingDefaults extends \OC_Defaults { $cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0'); $this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1); $this->cacheFactory->createDistributed('theming-')->clear(); + $this->cacheFactory->createDistributed('imagePath')->clear(); + } /** diff --git a/apps/theming/templates/settings-admin.php b/apps/theming/templates/settings-admin.php index 7e489199927..cb117c72a2b 100644 --- a/apps/theming/templates/settings-admin.php +++ b/apps/theming/templates/settings-admin.php @@ -67,27 +67,57 @@ style('theming', 'settings-admin'); </label> </div> <div> - <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>"> - <input type="hidden" id="current-logoMime" name="current-logoMime" value="<?php p($_['logoMime']); ?>" /> + <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="logo"> + <input type="hidden" id="theming-logoMime" value="<?php p($_['images']['logo']['mime']); ?>" /> + <input type="hidden" name="key" value="logo" /> <label for="uploadlogo"><span><?php p($l->t('Logo')) ?></span></label> - <input id="uploadlogo" class="upload-logo-field" name="uploadlogo" type="file" /> + <input id="uploadlogo" class="fileupload" name="image" type="file" /> <label for="uploadlogo" class="button icon-upload svg" id="uploadlogo" title="<?php p($l->t('Upload new logo')) ?>"></label> <div data-setting="logoMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div> </form> </div> <div> - <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>"> - <input type="hidden" id="current-backgroundMime" name="current-backgroundMime" value="<?php p($_['backgroundMime']); ?>" /> + <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="background"> + <input type="hidden" id="theming-backgroundMime" value="<?php p($_['images']['background']['mime']); ?>" /> + <input type="hidden" name="key" value="background" /> <label for="upload-login-background"><span><?php p($l->t('Login image')) ?></span></label> - <input id="upload-login-background" class="upload-logo-field" name="upload-login-background" type="file"> + <input id="upload-login-background" class="fileupload" name="image" type="file"> <label for="upload-login-background" class="button icon-upload svg" id="upload-login-background" title="<?php p($l->t("Upload new login background")) ?>"></label> <div data-setting="backgroundMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div> <div class="theme-remove-bg icon icon-delete" data-toggle="tooltip" data-original-title="<?php p($l->t('Remove background image')); ?>"></div> </form> </div> <div id="theming-preview"> - <img src="<?php p($_['logo']); ?>" id="theming-preview-logo" /> + <div id="theming-preview-logo"></div> </div> + + <h2 class="inlineblock"><?php p($l->t('Advanced options')); ?></h2> + + <div class="advanced-options"> + <div class="advanced-option-logoheader"> + <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="logoheader"> + <input type="hidden" id="theming-logoheaderMime" value="<?php p($_['images']['logoheader']['mime']); ?>" /> + <input type="hidden" name="key" value="logoheader" /> + <label for="upload-login-logoheader"><span><?php p($l->t('Header logo')) ?></span></label> + <input id="upload-login-logoheader" class="fileupload" name="image" type="file"> + <label for="upload-login-logoheader" class="button icon-upload svg" id="upload-login-logoheader" title="<?php p($l->t("Upload new header logo")) ?>"></label> + <div class="image-preview"></div> + <div data-setting="logoheaderMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div> + </form> + </div> + <div class="advanced-option-favicon"> + <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>" data-image-key="favicon"> + <input type="hidden" id="theming-faviconMime" value="<?php p($_['images']['favicon']['mime']); ?>" /> + <input type="hidden" name="key" value="favicon" /> + <label for="upload-login-favicon"><span><?php p($l->t('Favicon')) ?></span></label> + <input id="upload-login-favicon" class="fileupload" name="image" type="file"> + <label for="upload-login-favicon" class="button icon-upload svg" id="upload-login-favicon" title="<?php p($l->t("Upload new favion")) ?>"></label> + <div class="image-preview"></div> + <div data-setting="faviconMime" data-toggle="tooltip" data-original-title="<?php p($l->t('Reset to default')); ?>" class="theme-undo icon icon-history"></div> + </form> + </div> + </div> + <div class="theming-hints"> <?php if (!$_['canThemeIcons']) { ?> <p class="info"> diff --git a/apps/theming/tests/Controller/IconControllerTest.php b/apps/theming/tests/Controller/IconControllerTest.php index d92677e1f84..6539c6e0209 100644 --- a/apps/theming/tests/Controller/IconControllerTest.php +++ b/apps/theming/tests/Controller/IconControllerTest.php @@ -33,7 +33,6 @@ use OCA\Theming\ImageManager; use OCA\Theming\ThemingDefaults; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataDisplayResponse; -use OCP\AppFramework\Http\NotFoundResponse; use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\IRequest; @@ -41,6 +40,7 @@ use Test\TestCase; use OCA\Theming\Util; use OCA\Theming\Controller\IconController; use OCP\AppFramework\Http\FileDisplayResponse; +use OCP\AppFramework\Utility\ITimeFactory; class IconControllerTest extends TestCase { @@ -48,8 +48,6 @@ class IconControllerTest extends TestCase { private $request; /** @var ThemingDefaults|\PHPUnit_Framework_MockObject_MockObject */ private $themingDefaults; - /** @var Util */ - private $util; /** @var \OCP\AppFramework\Utility\ITimeFactory */ private $timeFactory; /** @var IconController|\PHPUnit_Framework_MockObject_MockObject */ @@ -64,18 +62,11 @@ class IconControllerTest extends TestCase { private $imageManager; public function setUp() { - $this->request = $this->getMockBuilder(IRequest::class)->getMock(); - $this->themingDefaults = $this->getMockBuilder('OCA\Theming\ThemingDefaults') - ->disableOriginalConstructor()->getMock(); - $this->util = $this->getMockBuilder('\OCA\Theming\Util')->disableOriginalConstructor() - ->setMethods(['getAppImage', 'getAppIcon', 'elementColor'])->getMock(); - $this->timeFactory = $this->getMockBuilder('OCP\AppFramework\Utility\ITimeFactory') - ->disableOriginalConstructor() - ->getMock(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->iconBuilder = $this->getMockBuilder('OCA\Theming\IconBuilder') - ->disableOriginalConstructor()->getMock(); - $this->imageManager = $this->getMockBuilder('OCA\Theming\ImageManager')->disableOriginalConstructor()->getMock(); + $this->request = $this->createMock(IRequest::class); + $this->themingDefaults = $this->createMock(ThemingDefaults::class); + $this->timeFactory = $this->createMock(ITimeFactory::class); + $this->iconBuilder = $this->createMock(IconBuilder::class); + $this->imageManager = $this->createMock(ImageManager::class); $this->fileAccessHelper = $this->createMock(FileAccessHelper::class); $this->timeFactory->expects($this->any()) ->method('getTime') @@ -85,9 +76,7 @@ class IconControllerTest extends TestCase { 'theming', $this->request, $this->themingDefaults, - $this->util, $this->timeFactory, - $this->config, $this->iconBuilder, $this->imageManager, $this->fileAccessHelper @@ -129,18 +118,21 @@ class IconControllerTest extends TestCase { if (count($checkImagick->queryFormats('SVG')) < 1) { $this->markTestSkipped('No SVG provider present.'); } + $file = $this->iconFileMock('filename', 'filecontent'); + $this->imageManager->expects($this->once()) + ->method('getImage') + ->with('favicon') + ->will($this->throwException(new NotFoundException())); $this->themingDefaults->expects($this->any()) ->method('shouldReplaceIcons') ->willReturn(true); - + $this->imageManager->expects($this->once()) + ->method('getCachedImage') + ->will($this->throwException(new NotFoundException())); $this->iconBuilder->expects($this->once()) ->method('getFavicon') ->with('core') ->willReturn('filecontent'); - $file = $this->iconFileMock('filename', 'filecontent'); - $this->imageManager->expects($this->once()) - ->method('getCachedImage') - ->will($this->throwException(new NotFoundException())); $this->imageManager->expects($this->once()) ->method('setCachedImage') ->willReturn($file); @@ -156,6 +148,10 @@ class IconControllerTest extends TestCase { } public function testGetFaviconFail() { + $this->imageManager->expects($this->once()) + ->method('getImage') + ->with('favicon') + ->will($this->throwException(new NotFoundException())); $this->themingDefaults->expects($this->any()) ->method('shouldReplaceIcons') ->willReturn(false); @@ -209,6 +205,10 @@ class IconControllerTest extends TestCase { } public function testGetTouchIconFail() { + $this->imageManager->expects($this->once()) + ->method('getImage') + ->with('favicon') + ->will($this->throwException(new NotFoundException())); $this->themingDefaults->expects($this->any()) ->method('shouldReplaceIcons') ->willReturn(false); diff --git a/apps/theming/tests/Controller/ThemingControllerTest.php b/apps/theming/tests/Controller/ThemingControllerTest.php index 08af13f994b..dda881525f0 100644 --- a/apps/theming/tests/Controller/ThemingControllerTest.php +++ b/apps/theming/tests/Controller/ThemingControllerTest.php @@ -34,6 +34,7 @@ use OC\Files\AppData\Factory; use OC\L10N\L10N; use OC\Template\SCSSCacher; use OCA\Theming\Controller\ThemingController; +use OCA\Theming\ImageManager; use OCA\Theming\Util; use OCP\App\IAppManager; use OCP\AppFramework\Http; @@ -74,6 +75,8 @@ class ThemingControllerTest extends TestCase { private $appManager; /** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */ private $appData; + /** @var ImageManager|\PHPUnit_Framework_MockObject_MockObject */ + private $imageManager; /** @var SCSSCacher */ private $scssCacher; /** @var IURLGenerator */ @@ -94,6 +97,7 @@ class ThemingControllerTest extends TestCase { $this->tempManager = \OC::$server->getTempManager(); $this->scssCacher = $this->createMock(SCSSCacher::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->imageManager = $this->createMock(ImageManager::class); $this->themingController = new ThemingController( 'theming', @@ -107,7 +111,8 @@ class ThemingControllerTest extends TestCase { $this->appData, $this->scssCacher, $this->urlGenerator, - $this->appManager + $this->appManager, + $this->imageManager ); return parent::setUp(); @@ -211,17 +216,12 @@ class ThemingControllerTest extends TestCase { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('logo'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') - ->willReturn(null); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') + ->with('image') ->willReturn(null); $this->l10n ->expects($this->any()) @@ -241,30 +241,25 @@ class ThemingControllerTest extends TestCase { Http::STATUS_UNPROCESSABLE_ENTITY ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } public function testUpdateLogoInvalidMimeType() { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('logo'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') + ->with('image') ->willReturn([ 'tmp_name' => 'logo.pdf', 'type' => 'application/pdf', 'name' => 'logo.pdf', 'error' => 0, ]); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') - ->willReturn(null); $this->l10n ->expects($this->any()) ->method('t') @@ -290,30 +285,7 @@ class ThemingControllerTest extends TestCase { Http::STATUS_UNPROCESSABLE_ENTITY ); - $this->assertEquals($expected, $this->themingController->updateLogo()); - } - - public function testUpdateBackgroundColor() { - $this->request - ->expects($this->at(0)) - ->method('getParam') - ->with('backgroundColor') - ->willReturn(true); - $this->themingDefaults - ->expects($this->once()) - ->method('set') - ->with('backgroundMime', 'backgroundColor'); - $expected = new DataResponse( - [ - 'data' => - [ - 'name' => 'backgroundColor', - 'message' => $this->l10n->t('Saved') - ], - 'status' => 'success' - ] - ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } public function dataUpdateImages() { @@ -336,23 +308,18 @@ class ThemingControllerTest extends TestCase { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('logo'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') + ->with('image') ->willReturn([ 'tmp_name' => $tmpLogo, 'type' => $mimeType, 'name' => 'logo.svg', 'error' => 0, ]); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') - ->willReturn(null); $this->l10n ->expects($this->any()) ->method('t') @@ -385,18 +352,27 @@ class ThemingControllerTest extends TestCase { ->method('newFile') ->with('logo') ->willReturn($file); + $this->urlGenerator->expects($this->once()) + ->method('linkTo') + ->willReturn('serverCss'); + $this->imageManager->expects($this->once()) + ->method('getImageUrl') + ->with('logo') + ->willReturn('imageUrl'); $expected = new DataResponse( [ 'data' => [ 'name' => 'logo.svg', 'message' => 'Saved', + 'url' => 'imageUrl', + 'serverCssUrl' => 'serverCss' ], 'status' => 'success' ] ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } /** @dataProvider dataUpdateImages */ @@ -408,17 +384,12 @@ class ThemingControllerTest extends TestCase { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('background'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') - ->willReturn(null); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') + ->with('image') ->willReturn([ 'tmp_name' => $tmpLogo, 'type' => 'text/svg', @@ -457,17 +428,26 @@ class ThemingControllerTest extends TestCase { ->with('background') ->willReturn($file); + $this->urlGenerator->expects($this->once()) + ->method('linkTo') + ->willReturn('serverCss'); + $this->imageManager->expects($this->once()) + ->method('getImageUrl') + ->with('background') + ->willReturn('imageUrl'); $expected = new DataResponse( [ 'data' => [ 'name' => 'logo.svg', 'message' => 'Saved', + 'url' => 'imageUrl', + 'serverCssUrl' => 'serverCss' ], 'status' => 'success' ] ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } public function testUpdateLogoLoginScreenUploadWithInvalidImage() { @@ -478,20 +458,15 @@ class ThemingControllerTest extends TestCase { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('logo'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') - ->willReturn(null); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') + ->with('image') ->willReturn([ 'tmp_name' => $tmpLogo, - 'type' => 'text/svg', + 'type' => 'foobar', 'name' => 'logo.svg', 'error' => 0, ]); @@ -519,7 +494,7 @@ class ThemingControllerTest extends TestCase { ], Http::STATUS_UNPROCESSABLE_ENTITY ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } public function dataPhpUploadErrors() { @@ -541,17 +516,12 @@ class ThemingControllerTest extends TestCase { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('background'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') - ->willReturn(null); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') + ->with('image') ->willReturn([ 'tmp_name' => '', 'type' => 'text/svg', @@ -575,7 +545,7 @@ class ThemingControllerTest extends TestCase { ], Http::STATUS_UNPROCESSABLE_ENTITY ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } /** @@ -585,23 +555,18 @@ class ThemingControllerTest extends TestCase { $this->request ->expects($this->at(0)) ->method('getParam') - ->with('backgroundColor') - ->willReturn(false); + ->with('key') + ->willReturn('background'); $this->request ->expects($this->at(1)) ->method('getUploadedFile') - ->with('uploadlogo') + ->with('image') ->willReturn([ 'tmp_name' => '', 'type' => 'text/svg', 'name' => 'logo.svg', 'error' => $error, ]); - $this->request - ->expects($this->at(2)) - ->method('getUploadedFile') - ->with('upload-login-background') - ->willReturn(null); $this->l10n ->expects($this->any()) ->method('t') @@ -619,7 +584,7 @@ class ThemingControllerTest extends TestCase { ], Http::STATUS_UNPROCESSABLE_ENTITY ); - $this->assertEquals($expected, $this->themingController->updateLogo()); + $this->assertEquals($expected, $this->themingController->uploadImage()); } public function testUndo() { @@ -687,21 +652,9 @@ class ThemingControllerTest extends TestCase { ->method('linkTo') ->with('', '/core/css/someHash-server.scss') ->willReturn('/nextcloudWebroot/core/css/someHash-server.scss'); - $folder = $this->createMock(ISimpleFolder::class); - $file = $this->createMock(ISimpleFile::class); - $this->appData - ->expects($this->once()) - ->method('getFolder') - ->with('images') - ->willReturn($folder); - $folder - ->expects($this->once()) - ->method('getFile') - ->with($filename) - ->willReturn($file); - $file - ->expects($this->once()) - ->method('delete'); + $this->imageManager->expects($this->once()) + ->method('delete') + ->with($filename); $expected = new DataResponse( [ @@ -720,27 +673,19 @@ class ThemingControllerTest extends TestCase { public function testGetLogoNotExistent() { - $this->appData->method('getFolder') - ->with($this->equalTo('images')) + $this->imageManager->method('getImage') + ->with($this->equalTo('logo')) ->willThrowException(new NotFoundException()); $expected = new Http\NotFoundResponse(); - $this->assertEquals($expected, $this->themingController->getLogo()); + $this->assertEquals($expected, $this->themingController->getImage('logo')); } public function testGetLogo() { $file = $this->createMock(ISimpleFile::class); - $folder = $this->createMock(ISimpleFolder::class); - $this->appData - ->expects($this->once()) - ->method('getFolder') - ->with('images') - ->willReturn($folder); - $folder->expects($this->once()) - ->method('getFile') - ->with('logo') + $this->imageManager->expects($this->once()) + ->method('getImage') ->willReturn($file); - $this->config ->expects($this->once()) ->method('getAppValue') @@ -755,29 +700,22 @@ class ThemingControllerTest extends TestCase { $expected->addHeader('Expires', $expires->format(\DateTime::RFC2822)); $expected->addHeader('Pragma', 'cache'); $expected->addHeader('Content-Type', 'text/svg'); - @$this->assertEquals($expected, $this->themingController->getLogo()); + @$this->assertEquals($expected, $this->themingController->getImage('logo')); } public function testGetLoginBackgroundNotExistent() { - $this->appData->method('getFolder') - ->with($this->equalTo('images')) + $this->imageManager->method('getImage') + ->with($this->equalTo('background')) ->willThrowException(new NotFoundException()); $expected = new Http\NotFoundResponse(); - $this->assertEquals($expected, $this->themingController->getLoginBackground()); + $this->assertEquals($expected, $this->themingController->getImage('background')); } public function testGetLoginBackground() { $file = $this->createMock(ISimpleFile::class); - $folder = $this->createMock(ISimpleFolder::class); - $this->appData - ->expects($this->once()) - ->method('getFolder') - ->with('images') - ->willReturn($folder); - $folder->expects($this->once()) - ->method('getFile') - ->with('background') + $this->imageManager->expects($this->once()) + ->method('getImage') ->willReturn($file); $this->config @@ -794,7 +732,7 @@ class ThemingControllerTest extends TestCase { $expected->addHeader('Expires', $expires->format(\DateTime::RFC2822)); $expected->addHeader('Pragma', 'cache'); $expected->addHeader('Content-Type', 'image/png'); - @$this->assertEquals($expected, $this->themingController->getLoginBackground()); + @$this->assertEquals($expected, $this->themingController->getImage('background')); } diff --git a/apps/theming/tests/ImageManagerTest.php b/apps/theming/tests/ImageManagerTest.php index 6c0b31528fc..4e258ce7162 100644 --- a/apps/theming/tests/ImageManagerTest.php +++ b/apps/theming/tests/ImageManagerTest.php @@ -23,14 +23,16 @@ */ namespace OCA\Theming\Tests; +use OCA\Theming\ImageManager; use OCP\Files\SimpleFS\ISimpleFile; use OCP\IConfig; +use OCP\IURLGenerator; use Test\TestCase; use OCP\Files\SimpleFS\ISimpleFolder; use OCP\Files\IAppData; use OCP\Files\NotFoundException; -class ImageManager extends TestCase { +class ImageManagerTest extends TestCase { /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ protected $config; @@ -38,17 +40,112 @@ class ImageManager extends TestCase { protected $appData; /** @var ImageManager */ protected $imageManager; + /** @var IURLGenerator|\PHPUnit_Framework_MockObject_MockObject */ + private $urlGenerator; protected function setUp() { parent::setUp(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->appData = $this->getMockBuilder('OCP\Files\IAppData')->getMock(); - $this->imageManager = new \OCA\Theming\ImageManager( + $this->config = $this->createMock(IConfig::class); + $this->appData = $this->createMock(IAppData::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->imageManager = new ImageManager( $this->config, - $this->appData + $this->appData, + $this->urlGenerator ); } + public function mockGetImage($key, $file) { + /** @var \PHPUnit_Framework_MockObject_MockObject $folder */ + $folder = $this->createMock(ISimpleFolder::class); + if ($file === null) { + $folder->expects($this->once()) + ->method('getFile') + ->with('logo') + ->willThrowException(new NotFoundException()); + } else { + $folder->expects($this->once()) + ->method('getFile') + ->with('logo') + ->willReturn($file); + $this->appData->expects($this->once()) + ->method('getFolder') + ->with('images') + ->willReturn($folder); + } + } + + public function testGetImageUrl() { + $file = $this->createMock(ISimpleFile::class); + $this->config->expects($this->exactly(2)) + ->method('getAppValue') + ->withConsecutive( + ['theming', 'cachebuster', '0'], + ['theming', 'logoMime', false] + ) + ->willReturn(0); + $this->mockGetImage('logo', $file); + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->willReturn('url-to-image'); + $this->assertEquals('url-to-image?v=0', $this->imageManager->getImageUrl('logo')); + } + + public function testGetImageUrlDefault() { + $this->config->expects($this->exactly(2)) + ->method('getAppValue') + ->withConsecutive( + ['theming', 'cachebuster', '0'], + ['theming', 'logoMime', false] + ) + ->willReturnOnConsecutiveCalls(0, false); + $this->urlGenerator->expects($this->once()) + ->method('imagePath') + ->with('core', 'logo.png') + ->willReturn('logo.png'); + $this->assertEquals('logo.png?v=0', $this->imageManager->getImageUrl('logo')); + } + + public function testGetImageUrlAbsolute() { + $file = $this->createMock(ISimpleFile::class); + $this->config->expects($this->exactly(2)) + ->method('getAppValue') + ->withConsecutive( + ['theming', 'cachebuster', '0'], + ['theming', 'logoMime', false] + ) + ->willReturn(0); + $this->mockGetImage('logo', $file); + $this->urlGenerator->expects($this->at(0)) + ->method('linkToRoute') + ->willReturn('url-to-image'); + $this->urlGenerator->expects($this->at(1)) + ->method('getAbsoluteUrl') + ->with('url-to-image?v=0') + ->willReturn('url-to-image-absolute?v=0'); + $this->assertEquals('url-to-image-absolute?v=0', $this->imageManager->getImageUrlAbsolute('logo')); + + } + + public function testGetImage() { + $this->config->expects($this->once()) + ->method('getAppValue')->with('theming', 'logoMime', false) + ->willReturn('png'); + $file = $this->createMock(ISimpleFile::class); + $this->mockGetImage('logo', $file); + $this->assertEquals($file, $this->imageManager->getImage('logo')); + } + + /** + * @expectedException OCP\Files\NotFoundException + */ + public function testGetImageUnset() { + $this->config->expects($this->once()) + ->method('getAppValue')->with('theming', 'logoMime', false) + ->willReturn(false); + $this->imageManager->getImage('logo'); + } + public function testGetCacheFolder() { $folder = $this->createMock(ISimpleFolder::class); $this->config->expects($this->once()) @@ -85,12 +182,12 @@ class ImageManager extends TestCase { } public function testGetCachedImage() { + $expected = $this->createMock(ISimpleFile::class); $folder = $this->setupCacheFolder(); $folder->expects($this->once()) ->method('getFile') ->with('filename') - ->willReturn('filecontent'); - $expected = 'filecontent'; + ->willReturn($expected); $this->assertEquals($expected, $this->imageManager->getCachedImage('filename')); } diff --git a/apps/theming/tests/Settings/AdminTest.php b/apps/theming/tests/Settings/AdminTest.php index ee49cf0f1f6..4eac689fb3f 100644 --- a/apps/theming/tests/Settings/AdminTest.php +++ b/apps/theming/tests/Settings/AdminTest.php @@ -27,6 +27,7 @@ namespace OCA\Theming\Tests\Settings; +use OCA\Theming\ImageManager; use OCA\Theming\Settings\Admin; use OCA\Theming\ThemingDefaults; use OCP\AppFramework\Http\TemplateResponse; @@ -44,21 +45,25 @@ class AdminTest extends TestCase { private $themingDefaults; /** @var IURLGenerator */ private $urlGenerator; + /** @var ImageManager */ + private $imageManager; /** @var IL10N */ private $l10n; public function setUp() { parent::setUp(); - $this->config = $this->getMockBuilder(IConfig::class)->getMock(); - $this->l10n = $this->getMockBuilder(IL10N::class)->getMock(); - $this->themingDefaults = $this->getMockBuilder('\OCA\Theming\ThemingDefaults')->disableOriginalConstructor()->getMock(); - $this->urlGenerator = $this->getMockBuilder(IURLGenerator::class)->getMock(); + $this->config = $this->createMock(IConfig::class); + $this->l10n = $this->createMock(IL10N::class); + $this->themingDefaults = $this->createMock(ThemingDefaults::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->imageManager = $this->createMock(ImageManager::class); $this->admin = new Admin( $this->config, $this->l10n, $this->themingDefaults, - $this->urlGenerator + $this->urlGenerator, + $this->imageManager ); } @@ -87,7 +92,7 @@ class AdminTest extends TestCase { $this->urlGenerator ->expects($this->once()) ->method('linkToRoute') - ->with('theming.Theming.updateLogo') + ->with('theming.Theming.uploadImage') ->willReturn('/my/route'); $params = [ 'themable' => true, @@ -97,12 +102,9 @@ class AdminTest extends TestCase { 'slogan' => 'MySlogan', 'color' => '#fff', 'uploadLogoRoute' => '/my/route', - 'logo' => null, - 'logoMime' => null, - 'background' => null, - 'backgroundMime' => null, 'canThemeIcons' => null, 'iconDocs' => null, + 'images' => [], ]; $expected = new TemplateResponse('theming', 'settings-admin', $params, ''); @@ -139,7 +141,7 @@ class AdminTest extends TestCase { $this->urlGenerator ->expects($this->once()) ->method('linkToRoute') - ->with('theming.Theming.updateLogo') + ->with('theming.Theming.uploadImage') ->willReturn('/my/route'); $params = [ 'themable' => false, @@ -149,12 +151,9 @@ class AdminTest extends TestCase { 'slogan' => 'MySlogan', 'color' => '#fff', 'uploadLogoRoute' => '/my/route', - 'logo' => null, - 'logoMime' => null, - 'background' => null, - 'backgroundMime' => null, 'canThemeIcons' => null, - 'iconDocs' => null, + 'iconDocs' => '', + 'images' => [], ]; $expected = new TemplateResponse('theming', 'settings-admin', $params, ''); diff --git a/apps/theming/tests/ThemingDefaultsTest.php b/apps/theming/tests/ThemingDefaultsTest.php index 2485a471bf4..c943af01c6c 100644 --- a/apps/theming/tests/ThemingDefaultsTest.php +++ b/apps/theming/tests/ThemingDefaultsTest.php @@ -29,6 +29,7 @@ */ namespace OCA\Theming\Tests; +use OCA\Theming\ImageManager; use OCA\Theming\ThemingDefaults; use OCP\App\IAppManager; use OCP\Files\IAppData; @@ -64,30 +65,31 @@ class ThemingDefaultsTest extends TestCase { private $cache; /** @var IAppManager|\PHPUnit_Framework_MockObject_MockObject */ private $appManager; + /** @var ImageManager|\PHPUnit_Framework_MockObject_MockObject */ + private $imageManager; public function setUp() { parent::setUp(); $this->config = $this->createMock(IConfig::class); $this->l10n = $this->createMock(IL10N::class); $this->urlGenerator = $this->createMock(IURLGenerator::class); - $this->appData = $this->createMock(IAppData::class); $this->cacheFactory = $this->createMock(ICacheFactory::class); $this->cache = $this->createMock(ICache::class); $this->util = $this->createMock(Util::class); + $this->imageManager = $this->createMock(ImageManager::class); $this->appManager = $this->createMock(IAppManager::class); $this->defaults = new \OC_Defaults(); - $this->cacheFactory + $this->urlGenerator ->expects($this->any()) - ->method('createDistributed') - ->with('theming-') - ->willReturn($this->cache); + ->method('getBaseUrl') + ->willReturn(''); $this->template = new ThemingDefaults( $this->config, $this->l10n, $this->urlGenerator, - $this->appData, $this->cacheFactory, $this->util, + $this->imageManager, $this->appManager ); } @@ -273,8 +275,18 @@ class ThemingDefaultsTest extends TestCase { ->expects($this->at(2)) ->method('setAppValue') ->with('theming', 'cachebuster', 16); + $this->cacheFactory + ->expects($this->at(0)) + ->method('createDistributed') + ->with('theming-') + ->willReturn($this->cache); + $this->cacheFactory + ->expects($this->at(1)) + ->method('createDistributed') + ->with('imagePath') + ->willReturn($this->cache); $this->cache - ->expects($this->once()) + ->expects($this->any()) ->method('clear') ->with(''); $this->template->set('MySetting', 'MyValue'); @@ -390,41 +402,19 @@ class ThemingDefaultsTest extends TestCase { $this->assertSame('', $this->template->undo('defaultitem')); } - public function testGetBackgroundDefault() { - $this->config + public function testGetBackground() { + $this->imageManager ->expects($this->once()) - ->method('getAppValue') - ->with('theming', 'cachebuster', '0') - ->willReturn('0'); - $this->util->expects($this->once()) - ->method('isBackgroundThemed') - ->willReturn(false); - $this->urlGenerator->expects($this->once()) - ->method('imagePath') - ->with('core', 'background.png') - ->willReturn('core-background'); - $this->assertEquals('core-background?v=0', $this->template->getBackground()); - } - - public function testGetBackgroundCustom() { - $this->config - ->expects($this->once()) - ->method('getAppValue') - ->with('theming', 'cachebuster', '0') - ->willReturn('0'); - $this->util->expects($this->once()) - ->method('isBackgroundThemed') - ->willReturn(true); - $this->urlGenerator->expects($this->once()) - ->method('linkToRoute') - ->with('theming.Theming.getLoginBackground') - ->willReturn('custom-background'); + ->method('getImageUrl') + ->with('background') + ->willReturn('custom-background?v=0'); $this->assertEquals('custom-background?v=0', $this->template->getBackground()); } private function getLogoHelper($withName, $useSvg) { - $this->appData->expects($this->once()) - ->method('getFolder') + $this->imageManager->expects($this->any()) + ->method('getImage') + ->with('logo') ->willThrowException(new NotFoundException()); $this->config ->expects($this->at(0)) @@ -436,11 +426,6 @@ class ThemingDefaultsTest extends TestCase { ->method('getAppValue') ->with('theming', 'cachebuster', '0') ->willReturn('0'); - $this->appData - ->expects($this->once()) - ->method('getFolder') - ->with('images') - ->willThrowException(new \Exception()); $this->urlGenerator->expects($this->once()) ->method('imagePath') ->with('core', $withName) @@ -457,14 +442,11 @@ class ThemingDefaultsTest extends TestCase { } public function testGetLogoCustom() { - $folder = $this->createMock(ISimpleFolder::class); $file = $this->createMock(ISimpleFile::class); - $folder->expects($this->once()) - ->method('getFile') + $this->imageManager->expects($this->once()) + ->method('getImage') + ->with('logo') ->willReturn($file); - $this->appData->expects($this->once()) - ->method('getFolder') - ->willReturn($folder); $this->config ->expects($this->at(0)) ->method('getAppValue') @@ -477,12 +459,16 @@ class ThemingDefaultsTest extends TestCase { ->willReturn('0'); $this->urlGenerator->expects($this->once()) ->method('linkToRoute') - ->with('theming.Theming.getLogo') + ->with('theming.Theming.getImage') ->willReturn('custom-logo'); $this->assertEquals('custom-logo' . '?v=0', $this->template->getLogo()); } public function testGetScssVariablesCached() { + $this->cacheFactory->expects($this->once()) + ->method('createDistributed') + ->with('theming-') + ->willReturn($this->cache); $this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(['foo'=>'bar']); $this->assertEquals(['foo'=>'bar'], $this->template->getScssVariables()); } @@ -491,31 +477,25 @@ class ThemingDefaultsTest extends TestCase { $this->config->expects($this->at(0))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0'); $this->config->expects($this->at(1))->method('getAppValue')->with('theming', 'logoMime', false)->willReturn('jpeg'); $this->config->expects($this->at(2))->method('getAppValue')->with('theming', 'backgroundMime', false)->willReturn('jpeg'); - $this->config->expects($this->at(3))->method('getAppValue')->with('theming', 'logoMime', false)->willReturn('jpeg'); - $this->config->expects($this->at(4))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0'); - $this->util->expects($this->once())->method('isBackgroundThemed')->willReturn(true); - $this->config->expects($this->at(5))->method('getAppValue')->with('theming', 'cachebuster', '0')->willReturn('0'); - $this->config->expects($this->at(6))->method('getAppValue')->with('theming', 'color', null)->willReturn($this->defaults->getColorPrimary()); + $this->config->expects($this->at(3))->method('getAppValue')->with('theming', 'logoheaderMime', false)->willReturn('jpeg'); + $this->config->expects($this->at(4))->method('getAppValue')->with('theming', 'faviconMime', false)->willReturn('jpeg'); + + $this->config->expects($this->at(5))->method('getAppValue')->with('theming', 'color', null)->willReturn($this->defaults->getColorPrimary()); + $this->config->expects($this->at(6))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); $this->config->expects($this->at(7))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); $this->config->expects($this->at(8))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); - $this->config->expects($this->at(9))->method('getAppValue')->with('theming', 'color', $this->defaults->getColorPrimary())->willReturn($this->defaults->getColorPrimary()); $this->util->expects($this->any())->method('invertTextColor')->with($this->defaults->getColorPrimary())->willReturn(false); $this->util->expects($this->any())->method('elementColor')->with($this->defaults->getColorPrimary())->willReturn('#aaaaaa'); + $this->cacheFactory->expects($this->once()) + ->method('createDistributed') + ->with('theming-') + ->willReturn($this->cache); $this->cache->expects($this->once())->method('get')->with('getScssVariables')->willReturn(null); - $folder = $this->createMock(ISimpleFolder::class); - $file = $this->createMock(ISimpleFile::class); - $folder->expects($this->any())->method('getFile')->willReturn($file); - $this->appData->expects($this->any()) - ->method('getFolder') - ->willReturn($folder); - - $this->urlGenerator->expects($this->exactly(2)) - ->method('linkToRoute') - ->willReturnMap([ - ['theming.Theming.getLogo', [], 'custom-logo'], - ['theming.Theming.getLoginBackground', [], 'custom-background'], - ]); + $this->imageManager->expects($this->at(0))->method('getImageUrl')->with('logo')->willReturn('custom-logo?v=0'); + $this->imageManager->expects($this->at(1))->method('getImageUrl')->with('logoheader')->willReturn('custom-logoheader?v=0'); + $this->imageManager->expects($this->at(2))->method('getImageUrl')->with('favicon')->willReturn('custom-favicon?v=0'); + $this->imageManager->expects($this->at(3))->method('getImageUrl')->with('background')->willReturn('custom-background?v=0'); $expected = [ 'theming-cachebuster' => '\'0\'', @@ -526,8 +506,11 @@ class ThemingDefaultsTest extends TestCase { 'color-primary' => $this->defaults->getColorPrimary(), 'color-primary-text' => '#ffffff', 'image-login-plain' => 'false', - 'color-primary-element' => '#aaaaaa' - + 'color-primary-element' => '#aaaaaa', + 'theming-logoheader-mime' => '\'jpeg\'', + 'theming-favicon-mime' => '\'jpeg\'', + 'image-logoheader' => '\'custom-logoheader?v=0\'', + 'image-favicon' => '\'custom-favicon?v=0\'' ]; $this->assertEquals($expected, $this->template->getScssVariables()); } |