diff options
author | Lukas Reschke <lukas@owncloud.com> | 2016-06-21 22:21:46 +0300 |
---|---|---|
committer | Lukas Reschke <lukas@owncloud.com> | 2016-06-27 11:26:23 +0300 |
commit | 27b699bdbcd080ec9d5400a2391cdb2b725f7ee1 (patch) | |
tree | 0cd0e124cb6e7ea4b6dfdf1958df4eafae48d240 /apps/theming | |
parent | cc321bc140f707257ffe1a11b4fa0238887e16fc (diff) |
Migrate logic to dynamic controller
Also adds support for having custom login backgrounds
Diffstat (limited to 'apps/theming')
-rw-r--r-- | apps/theming/appinfo/app.php | 31 | ||||
-rw-r--r-- | apps/theming/appinfo/info.xml | 2 | ||||
-rw-r--r-- | apps/theming/appinfo/routes.php | 17 | ||||
-rw-r--r-- | apps/theming/js/settings-admin.js | 32 | ||||
-rw-r--r-- | apps/theming/lib/controller/themingcontroller.php | 124 | ||||
-rw-r--r-- | apps/theming/lib/init.php | 94 | ||||
-rw-r--r-- | apps/theming/lib/template.php | 117 | ||||
-rw-r--r-- | apps/theming/settings/settings-admin.php | 32 | ||||
-rw-r--r-- | apps/theming/templates/settings-admin.php | 24 | ||||
-rw-r--r-- | apps/theming/tests/lib/TemplateTest.php | 301 | ||||
-rw-r--r-- | apps/theming/tests/lib/controller/ThemingControllerTest.php | 405 |
11 files changed, 955 insertions, 224 deletions
diff --git a/apps/theming/appinfo/app.php b/apps/theming/appinfo/app.php index ed7ea3e20f8..edf2c7d345a 100644 --- a/apps/theming/appinfo/app.php +++ b/apps/theming/appinfo/app.php @@ -1,23 +1,38 @@ <?php /** - * @author Björn Schießle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * - * @copyright Copyright (c) 2016, Bjoern Schiessle - * @license AGPL-3.0 + * @license GNU AGPL version 3 or any later version * - * This code is free software: you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your opinion) any later version. + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/> + * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ \OCP\App::registerAdmin('theming', 'settings/settings-admin'); + +$linkToCSS = \OC::$server->getURLGenerator()->linkToRoute( + 'theming.Theming.getStylesheet', + [ + 'v' => \OC::$server->getConfig()->getAppValue('theming', 'cachebuster', '0'), + ] +); +\OC_Util::addHeader( + 'link', + [ + 'rel' => 'stylesheet', + 'href' => $linkToCSS, + ] +); + diff --git a/apps/theming/appinfo/info.xml b/apps/theming/appinfo/info.xml index f0f2fb80afe..58c839f2758 100644 --- a/apps/theming/appinfo/info.xml +++ b/apps/theming/appinfo/info.xml @@ -4,7 +4,7 @@ <name>Theming</name> <description>Adjust the Nextcloud theme</description> <licence>AGPL</licence> - <author>Bjoern Schiessle</author> + <author>Nextcloud</author> <version>0.1.0</version> <namespace>Theming</namespace> <category>other</category> diff --git a/apps/theming/appinfo/routes.php b/apps/theming/appinfo/routes.php index 7a2ff1f9dbd..dbbae372ffd 100644 --- a/apps/theming/appinfo/routes.php +++ b/apps/theming/appinfo/routes.php @@ -1,6 +1,7 @@ <?php /** * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * @@ -19,7 +20,6 @@ * */ - namespace OCA\Theming\AppInfo; (new \OCP\AppFramework\App('theming'))->registerRoutes($this, array('routes' => array( @@ -38,5 +38,20 @@ namespace OCA\Theming\AppInfo; 'url' => '/ajax/updateLogo', 'verb' => 'POST' ], + [ + 'name' => 'Theming#getStylesheet', + 'url' => '/styles.css', + 'verb' => 'GET', + ], + [ + 'name' => 'Theming#getLogo', + 'url' => '/logo', + 'verb' => 'GET', + ], + [ + 'name' => 'Theming#getLoginBackground', + 'url' => '/loginbackground', + 'verb' => 'GET', + ], ))); diff --git a/apps/theming/js/settings-admin.js b/apps/theming/js/settings-admin.js index dd2f051163c..1acd6a97e96 100644 --- a/apps/theming/js/settings-admin.js +++ b/apps/theming/js/settings-admin.js @@ -36,22 +36,37 @@ function preview(setting, value) { var headerClass = document.getElementById('header'); headerClass.style.background = value; headerClass.style.backgroundImage = '../img/logo-icon.svg'; - } - if (setting === 'logoName') { + if (setting === 'logoMime') { + console.log(setting); var logos = document.getElementsByClassName('logo-icon'); - for (var i = 0; i < logos.length; i++) { - logos[i].style.background= "url('" + OC.getRootPath() + "/themes/theming-app/core/img/" + value + "')"; + if(value !== '') { + logos[0].style.background = "url('" + OC.generateUrl('/apps/theming/logo') + "')"; + } else { + logos[0].style.background = "url('" + OC.getRootPath() + '/core/img/logo-icon.svg'+"')"; } } } $(document).ready(function () { - var uploadparms = { + var uploadParamsLogo = { + pasteZone: null, + done: function (e, response) { + preview('logoMime', response.result.data.name); + OC.msg.finishedSaving('#theming_settings_msg', response.result); + }, + submit: function(e, response) { + OC.msg.startSaving('#theming_settings_msg'); + }, + fail: function (e, data){ + OC.msg.finishedSaving('#theming_settings_msg', response); + } + }; + var uploadParamsLogin = { pasteZone: null, done: function (e, response) { - preview('logoName', response.result.data.name); + preview('backgroundMime', response.result.data.name); OC.msg.finishedSaving('#theming_settings_msg', response.result); }, submit: function(e, response) { @@ -62,7 +77,8 @@ $(document).ready(function () { } }; - $('#uploadlogo').fileupload(uploadparms); + $('#uploadlogo').fileupload(uploadParamsLogo); + $('#upload-login-background').fileupload(uploadParamsLogin); $('#theming-name').keyup(function (e) { if (e.keyCode == 13) { @@ -102,7 +118,7 @@ $(document).ready(function () { var colorPicker = document.getElementById('theming-color'); colorPicker.style.backgroundColor = response.data.value; colorPicker.value = response.data.value.slice(1); - } else if (setting !== 'logoName') { + } else if (setting !== 'logoMime' && setting !== 'backgroundMime') { var input = document.getElementById('theming-'+setting); input.value = response.data.value; } diff --git a/apps/theming/lib/controller/themingcontroller.php b/apps/theming/lib/controller/themingcontroller.php index 5ffbbf71769..dd4ff821951 100644 --- a/apps/theming/lib/controller/themingcontroller.php +++ b/apps/theming/lib/controller/themingcontroller.php @@ -1,6 +1,7 @@ <?php /** * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * @@ -19,14 +20,13 @@ * */ - namespace OCA\Theming\Controller; - use OCA\Theming\Template; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\DataResponse; +use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; @@ -38,24 +38,26 @@ use OCP\IRequest; * @package OCA\Theming\Controller */ class ThemingController extends Controller { - /** @var Template */ private $template; - /** @var IL10N */ private $l; + /** @var IConfig */ + private $config; /** * ThemingController constructor. * * @param string $appName * @param IRequest $request + * @param IConfig $config * @param Template $template * @param IL10N $l */ public function __construct( $appName, IRequest $request, + IConfig $config, Template $template, IL10N $l ) { @@ -63,11 +65,12 @@ class ThemingController extends Controller { $this->template = $template; $this->l = $l; + $this->config = $config; } /** - * @param $setting - * @param $value + * @param string $setting + * @param string $value * @return DataResponse * @internal param string $color */ @@ -85,29 +88,39 @@ class ThemingController extends Controller { } /** - * update Nextcloud logo + * Update the logos and background image * * @return DataResponse */ public function updateLogo() { $newLogo = $this->request->getUploadedFile('uploadlogo'); - if (empty($newLogo)) { + $newBackgroundLogo = $this->request->getUploadedFile('upload-login-background'); + if (empty($newLogo) && empty($newBackgroundLogo)) { return new DataResponse( [ 'data' => [ - 'message' => $this->l->t('No logo uploaded') + 'message' => $this->l->t('No file uploaded') ] ], Http::STATUS_UNPROCESSABLE_ENTITY); } - $this->template->set('logoName', $newLogo['name']); - rename($newLogo['tmp_name'], \OC::$SERVERROOT . '/themes/theming-app/core/img/' . $newLogo['name']); - + $name = ''; + if(!empty($newLogo)) { + rename($newLogo['tmp_name'], $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/themedinstancelogo'); + $this->template->set('logoMime', $newLogo['type']); + $name = $newLogo['name']; + } + if(!empty($newBackgroundLogo)) { + rename($newBackgroundLogo['tmp_name'], $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/themedbackgroundlogo'); + $this->template->set('backgroundMime', $newBackgroundLogo['type']); + $name = $newBackgroundLogo['name']; + } + return new DataResponse( [ 'data' => [ - 'name' => $newLogo['name'], + 'name' => $name, 'message' => $this->l->t('Saved') ], 'status' => 'success' @@ -116,7 +129,7 @@ class ThemingController extends Controller { } /** - * revert setting to default value + * Revert setting to default value * * @param string $setting setting which should be reverted * @return DataResponse @@ -134,4 +147,87 @@ class ThemingController extends Controller { ] ); } + + /** + * @PublicPage + * @NoCSRFRequired + * + * @return Http\StreamResponse + */ + public function getLogo() { + $pathToLogo = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/') . '/themedinstancelogo'; + if(!file_exists($pathToLogo)) { + return new DataResponse(); + } + + \OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT'); + \OC_Response::enableCaching(); + $response = new Http\StreamResponse($pathToLogo); + $response->cacheFor(3600); + $response->addHeader('Content-Disposition', 'attachment'); + $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'logoMime', '')); + return $response; + } + + /** + * @PublicPage + * @NoCSRFRequired + * + * @return Http\StreamResponse + */ + public function getLoginBackground() { + $pathToLogo = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/') . '/themedbackgroundlogo'; + if(!file_exists($pathToLogo)) { + return new DataResponse(); + } + + \OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT'); + \OC_Response::enableCaching(); + $response = new Http\StreamResponse($pathToLogo); + $response->cacheFor(3600); + $response->addHeader('Content-Disposition', 'attachment'); + $response->addHeader('Content-Type', $this->config->getAppValue($this->appName, 'backgroundMime', '')); + return $response; + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @return Http\DataDownloadResponse + */ + public function getStylesheet() { + $cacheBusterValue = $this->config->getAppValue('theming', 'cachebuster', '0'); + $responseCss = ''; + $color = $this->config->getAppValue($this->appName, 'color'); + if($color !== '') { + $responseCss .= sprintf( + '#body-user #header,#body-settings #header,#body-public #header {background-color: %s}', + $color + ); + } + $logo = $this->config->getAppValue($this->appName, 'logoMime'); + if($logo !== '') { + $responseCss .= sprintf('#header .logo { + background-image: url(\'./logo?v='.$cacheBusterValue.'\'); + } + #header .logo-icon { + background-image: url(\'./logo?v='.$cacheBusterValue.'\'); + background-size: 62px 34px; + }' + ); + } + $backgroundLogo = $this->config->getAppValue($this->appName, 'backgroundMime'); + if($backgroundLogo !== '') { + $responseCss .= '#body-login { + background-image: url(\'./loginbackground?v='.$cacheBusterValue.'\'); + }'; + } + + \OC_Response::setExpiresHeader(gmdate('D, d M Y H:i:s', time() + (60*60*24*45)) . ' GMT'); + \OC_Response::enableCaching(); + $response = new Http\DataDownloadResponse($responseCss, 'style.css', 'text/css'); + $response->cacheFor(3600); + return $response; + } } diff --git a/apps/theming/lib/init.php b/apps/theming/lib/init.php deleted file mode 100644 index 287aa589cac..00000000000 --- a/apps/theming/lib/init.php +++ /dev/null @@ -1,94 +0,0 @@ -<?php -/** - * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - - -namespace OCA\Theming; - - -use OCP\App\ManagerEvent; -use OCP\IConfig; -use OCP\ILogger; - -/** - * Class Init - * - * Initialize the app and make sure that all directories and files exists - * - * @package OCA\Theming - */ -class Init { - - /** @var IConfig */ - private $config; - - /** @var ILogger */ - private $logger; - - /** - * Init constructor. - * - * @param IConfig $config - * @param ILogger $logger - */ - public function __construct(IConfig $config, ILogger $logger) { - $this->config = $config; - $this->logger = $logger; - } - - /** - * prepare folders with the theming app and add the default values to it - */ - public function prepareThemeFolder() { - - if ($this->config->getSystemValue('theme', 'default') === 'theming-app') { - return; - } - - if (!is_writable(\OC::$SERVERROOT . '/themes')) { - $this->logger->warning('Themes folder is read only, can not prepare the theming-app folder', - ['app' => 'theming'] - ); - } - - $this->config->setSystemValue('theme', 'theming-app'); - - if(!file_exists(\OC::$SERVERROOT . '/themes/theming-app')) { - mkdir(\OC::$SERVERROOT . '/themes/theming-app'); - } - - if(!file_exists(\OC::$SERVERROOT . '/themes/theming-app/core')) { - mkdir(\OC::$SERVERROOT . '/themes/theming-app/core'); - } - - if(!file_exists(\OC::$SERVERROOT . '/themes/theming-app/core/img')) { - mkdir(\OC::$SERVERROOT . '/themes/theming-app/core/img'); - } - - if(!file_exists(\OC::$SERVERROOT . '/themes/theming-app/core/css')) { - mkdir(\OC::$SERVERROOT . '/themes/theming-app/core/css'); - } - - if(!file_exists(\OC::$SERVERROOT . '/themes/theming-app/core/img/logo-icon.svg')) { - copy(\OC::$SERVERROOT . '/core/img/logo-icon.svg' ,\OC::$SERVERROOT . '/themes/theming-app/core/img/logo-icon.svg'); - } - } - -} diff --git a/apps/theming/lib/template.php b/apps/theming/lib/template.php index 177ead69889..741fc1daa6a 100644 --- a/apps/theming/lib/template.php +++ b/apps/theming/lib/template.php @@ -1,6 +1,7 @@ <?php /** * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * * @license GNU AGPL version 3 or any later version * @@ -19,10 +20,8 @@ * */ - namespace OCA\Theming; - use OCP\IConfig; use OCP\IL10N; use OCP\IURLGenerator; @@ -34,65 +33,55 @@ use OCP\IURLGenerator; * * @package OCA\Theming */ -class Template { - +class Template extends \OC_Defaults { /** @var IConfig */ private $config; - /** @var IL10N */ private $l; - /** @var IURLGenerator */ private $urlGenerator; - - /** @var Init */ - private $init; - /** @var string */ private $name; - /** @var string */ private $url; - /** @var string */ private $slogan; - /** @var string */ private $color; - /** @var string */ - private $logoName; - /** * Template constructor. * * @param IConfig $config * @param IL10N $l * @param IURLGenerator $urlGenerator - * @param Init $init + * @param \OC_Defaults $defaults */ public function __construct(IConfig $config, IL10N $l, IURLGenerator $urlGenerator, - Init $init + \OC_Defaults $defaults ) { + parent::__construct(); $this->config = $config; $this->l = $l; $this->urlGenerator = $urlGenerator; - $this->init = $init; - $this->name = 'Nextcloud'; - $this->url = 'https://nextcloud.com'; - $this->slogan = $this->l->t('a safe home for all your data'); - $this->color = '#0082c9'; - $this->logoName = 'logo-icon.svg'; + $this->name = $defaults->getName(); + $this->url = $defaults->getBaseUrl(); + $this->slogan = $defaults->getSlogan(); + $this->color = $defaults->getMailHeaderColor(); } public function getName() { return $this->config->getAppValue('theming', 'name', $this->name); } + + public function getEntity() { + return $this->config->getAppValue('theming', 'name', $this->name); + } - public function getUrl() { + public function getBaseUrl() { return $this->config->getAppValue('theming', 'url', $this->url); } @@ -100,73 +89,57 @@ class Template { return $this->config->getAppValue('theming', 'slogan', $this->slogan); } - public function getColor() { + public function getMailHeaderColor() { return $this->config->getAppValue('theming', 'color', $this->color); } - public function getLogoName() { - return $this->config->getAppValue('theming', 'logoName', $this->logoName); + /** + * Increases the cache buster key + */ + private function increaseCacheBuster() { + $cacheBusterKey = $this->config->getAppValue('theming', 'cachebuster', '0'); + $this->config->setAppValue('theming', 'cachebuster', (int)$cacheBusterKey+1); } /** - * update setting in the database + * Update setting in the database * - * @param $setting - * @param $value + * @param string $setting + * @param string $value */ public function set($setting, $value) { - $this->init->prepareThemeFolder(); $this->config->setAppValue('theming', $setting, $value); - $this->writeCSSFile(); + $this->increaseCacheBuster(); } /** - * revert settings to the default value + * Revert settings to the default value * * @param string $setting setting which should be reverted * @return string default value */ public function undo($setting) { - $returnValue = ''; - if ($this->$setting) { - $this->config->setAppValue('theming', $setting, $this->$setting); - $this->writeCSSFile(); - $returnValue = $this->$setting; + $this->config->deleteAppValue('theming', $setting); + $this->increaseCacheBuster(); + + switch ($setting) { + case 'name': + $returnValue = $this->getEntity(); + break; + case 'url': + $returnValue = $this->getBaseUrl(); + break; + case 'slogan': + $returnValue = $this->getSlogan(); + break; + case 'color': + $returnValue = $this->getMailHeaderColor(); + break; + default: + $returnValue = ''; + break; } return $returnValue; } - - /** - * write setting to a css file - */ - private function writeCSSFile() { - $logo = $this->getLogoName(); - $color = $this->getColor(); - - $css = " - #body-user #header, - #body-settings #header, - #body-public #header { - background-color: $color; - } - - - /* use logos from theme */ - #header .logo { - background-image: url('../img/$logo'); - width: 250px; - height: 121px; - } - #header .logo-icon { - background-image: url('../img/$logo'); - width: 62px; - height: 34px; - }"; - - $root = \OC::$SERVERROOT . '/themes/theming-app/core'; - - file_put_contents($root . '/css/styles.css', $css); - } - } diff --git a/apps/theming/settings/settings-admin.php b/apps/theming/settings/settings-admin.php index c79eb1475fb..59da90a47f8 100644 --- a/apps/theming/settings/settings-admin.php +++ b/apps/theming/settings/settings-admin.php @@ -1,22 +1,22 @@ <?php /** - * @author Björn Schießle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Bjoern Schiessle <bjoern@schiessle.org> + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> * - * @copyright Copyright (c) 2016, Bjoern Schiessle - * @license AGPL-3.0 + * @license GNU AGPL version 3 or any later version * - * This code is free software: you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your opinion) any later version. + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/> + * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ @@ -25,35 +25,31 @@ $config = \OC::$server->getConfig(); $l = \OC::$server->getL10N('theming'); $urlGenerator = \OC::$server->getURLGenerator(); -$init = new \OCA\Theming\Init($config, \OC::$server->getLogger()); $theming = new \OCA\Theming\Template( $config, $l, \OC::$server->getURLGenerator(), - $init + new OC_Defaults() ); $themable = true; $errorMessage = ''; -$theme = $config->getSystemValue('theme', 'default'); +$theme = $config->getSystemValue('theme', ''); -if ($theme !== 'theming-app' && $theme !== 'default') { +if ($theme !== '') { $themable = false; $errorMessage = $l->t('You already use a custom theme'); -} elseif (!is_writable(\OC::$SERVERROOT . '/themes')) { - $themable = false; - $errorMessage = $l->t('Themes folder is read-only, please update the permissions to read-write'); } $template = new OCP\Template('theming', 'settings-admin'); $template->assign('themable', $themable); $template->assign('errorMessage', $errorMessage); -$template->assign('name', $theming->getName()); -$template->assign('url', $theming->getUrl()); +$template->assign('name', $theming->getEntity()); +$template->assign('url', $theming->getBaseUrl()); $template->assign('slogan', $theming->getSlogan()); -$template->assign('color', $theming->getColor()); +$template->assign('color', $theming->getMailHeaderColor()); $path = $urlGenerator->linkToRoute('theming.Theming.updateLogo'); $template->assign('uploadLogoRoute', $path); diff --git a/apps/theming/templates/settings-admin.php b/apps/theming/templates/settings-admin.php index 4e2277b0533..3a55deca0ce 100644 --- a/apps/theming/templates/settings-admin.php +++ b/apps/theming/templates/settings-admin.php @@ -14,27 +14,35 @@ style('theming', 'settings-admin'); </p> <?php } else { ?> <p> - <span class="theming-label">Name:</span> <input id="theming-name" type="text" placeholder="<?php p($l->t('Name')); ?>" value="<?php p($_['name']) ?>"></input> + <span class="theming-label"><?php p($l->t('Name:')) ?></span> <input id="theming-name" type="text" placeholder="<?php p($l->t('Name')); ?>" value="<?php p($_['name']) ?>" /> <span data-setting="name" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> </p> <p> - <span class="theming-label">URL:</span> <input id="theming-url"type="text" placeholder="<?php p($l->t('Web address https://…')); ?>" value="<?php p($_['url']) ?>"></input> + <span class="theming-label"><?php p($l->t('URL:')) ?></span> <input id="theming-url" type="text" placeholder="<?php p($l->t('Web address https://…')); ?>" value="<?php p($_['url']) ?>" /> <span data-setting="url" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> </p> <p> - <span class="theming-label">Slogan:</span> <input id="theming-slogan" type="text" placeholder="<?php p($l->t('Slogan')); ?>" value="<?php p($_['slogan']) ?>"></input> + <span class="theming-label"><?php p($l->t('Slogan:')) ?></span> <input id="theming-slogan" type="text" placeholder="<?php p($l->t('Slogan')); ?>" value="<?php p($_['slogan']) ?>" /> <span data-setting="slogan" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> </p> <p> - <span class="theming-label">Color:</span> <input id="theming-color" class="jscolor" value="<?php p($_['color']) ?>"></input> + <span class="theming-label"><?php p($l->t('Color:')) ?></span> <input id="theming-color" class="jscolor" value="<?php p($_['color']) ?>" /> <span data-setting="color" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> </p> - <p> + <p> <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>"> - <span class="theming-label">Logo:</span> + <span class="theming-label"><?php p($l->t('Logo:')) ?></span> <input id="uploadlogo" class="upload-logo-field" name="uploadlogo" type="file"> - <label for="uploadlogo" class="button icon-upload svg" id="uploadlogo" title="Upload new logo"></label> - <span data-setting="logoName" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> + <label for="uploadlogo" class="button icon-upload svg" id="uploadlogo" title="<?php p($l->t('Upload new logo')) ?>"></label> + <span data-setting="logoMime" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> + </form> + </p> + <p> + <form class="uploadButton" method="post" action="<?php p($_['uploadLogoRoute']) ?>"> + <span class="theming-label"><?php p($l->t('Login img.:')) ?></span> + <input id="upload-login-background" class="upload-logo-field" name="upload-login-background" 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> + <span data-setting="backgroundMime" data-original-title="<?php p($l->t('revert to original value')); ?>" class="theme-undo icon icon-history"></span> </form> </p> <?php } ?> diff --git a/apps/theming/tests/lib/TemplateTest.php b/apps/theming/tests/lib/TemplateTest.php new file mode 100644 index 00000000000..b9623e437b7 --- /dev/null +++ b/apps/theming/tests/lib/TemplateTest.php @@ -0,0 +1,301 @@ +<?php +/** + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Tests; + +use OCA\Theming\Template; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IURLGenerator; +use Test\TestCase; + +class TemplateTest extends TestCase { + /** @var IConfig */ + private $config; + /** @var IL10N */ + private $l10n; + /** @var IURLGenerator */ + private $urlGenerator; + /** @var \OC_Defaults */ + private $defaults; + /** @var Template */ + private $template; + + public function setUp() { + $this->config = $this->getMock('\\OCP\\IConfig'); + $this->l10n = $this->getMock('\\OCP\\IL10N'); + $this->urlGenerator = $this->getMock('\\OCP\\IURLGenerator'); + $this->defaults = $this->getMockBuilder('\\OC_Defaults') + ->disableOriginalConstructor() + ->getMock(); + $this->defaults + ->expects($this->at(0)) + ->method('getName') + ->willReturn('Nextcloud'); + $this->defaults + ->expects($this->at(1)) + ->method('getBaseUrl') + ->willReturn('https://nextcloud.com/'); + $this->defaults + ->expects($this->at(2)) + ->method('getSlogan') + ->willReturn('Safe Data'); + $this->defaults + ->expects($this->at(3)) + ->method('getMailHeaderColor') + ->willReturn('#000'); + $this->template = new Template( + $this->config, + $this->l10n, + $this->urlGenerator, + $this->defaults + ); + + return parent::setUp(); + } + + public function testGetNameWithDefault() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'name', 'Nextcloud') + ->willReturn('Nextcloud'); + + $this->assertEquals('Nextcloud', $this->template->getName()); + } + + public function testGetNameWithCustom() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'name', 'Nextcloud') + ->willReturn('MyCustomCloud'); + + $this->assertEquals('MyCustomCloud', $this->template->getName()); + } + + public function testGetEntityWithDefault() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'name', 'Nextcloud') + ->willReturn('Nextcloud'); + + $this->assertEquals('Nextcloud', $this->template->getEntity()); + } + + public function testGetEntityWithCustom() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'name', 'Nextcloud') + ->willReturn('MyCustomCloud'); + + $this->assertEquals('MyCustomCloud', $this->template->getEntity()); + } + + public function testGetBaseUrlWithDefault() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'url', 'https://nextcloud.com/') + ->willReturn('https://nextcloud.com/'); + + $this->assertEquals('https://nextcloud.com/', $this->template->getBaseUrl()); + } + + public function testGetBaseUrlWithCustom() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'url', 'https://nextcloud.com/') + ->willReturn('https://example.com/'); + + $this->assertEquals('https://example.com/', $this->template->getBaseUrl()); + } + + public function testGetSloganWithDefault() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'slogan', 'Safe Data') + ->willReturn('Safe Data'); + + $this->assertEquals('Safe Data', $this->template->getSlogan()); + } + + public function testGetSloganWithCustom() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'slogan', 'Safe Data') + ->willReturn('My custom Slogan'); + + $this->assertEquals('My custom Slogan', $this->template->getSlogan()); + } + + public function testGetMailHeaderColorWithDefault() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'color', '#000') + ->willReturn('#000'); + + $this->assertEquals('#000', $this->template->getMailHeaderColor()); + } + + public function testGetMailHeaderColorWithCustom() { + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'color', '#000') + ->willReturn('#fff'); + + $this->assertEquals('#fff', $this->template->getMailHeaderColor()); + } + + public function testSet() { + $this->config + ->expects($this->at(0)) + ->method('setAppValue') + ->with('theming', 'MySetting', 'MyValue'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); + $this->config + ->expects($this->at(2)) + ->method('setAppValue') + ->with('theming', 'cachebuster', 16); + + $this->template->set('MySetting', 'MyValue'); + } + + public function testUndoName() { + $this->config + ->expects($this->at(0)) + ->method('deleteAppValue') + ->with('theming', 'name'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); + $this->config + ->expects($this->at(2)) + ->method('setAppValue') + ->with('theming', 'cachebuster', 16); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'name', 'Nextcloud') + ->willReturn('Nextcloud'); + + $this->assertSame('Nextcloud', $this->template->undo('name')); + } + + public function testUndoBaseUrl() { + $this->config + ->expects($this->at(0)) + ->method('deleteAppValue') + ->with('theming', 'url'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); + $this->config + ->expects($this->at(2)) + ->method('setAppValue') + ->with('theming', 'cachebuster', 16); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'url', 'https://nextcloud.com/') + ->willReturn('https://nextcloud.com/'); + + $this->assertSame('https://nextcloud.com/', $this->template->undo('url')); + } + + public function testUndoSlogan() { + $this->config + ->expects($this->at(0)) + ->method('deleteAppValue') + ->with('theming', 'slogan'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); + $this->config + ->expects($this->at(2)) + ->method('setAppValue') + ->with('theming', 'cachebuster', 16); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'slogan', 'Safe Data') + ->willReturn('Safe Data'); + + $this->assertSame('Safe Data', $this->template->undo('slogan')); + } + + public function testUndoColor() { + $this->config + ->expects($this->at(0)) + ->method('deleteAppValue') + ->with('theming', 'color'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); + $this->config + ->expects($this->at(2)) + ->method('setAppValue') + ->with('theming', 'cachebuster', 16); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'color', '#000') + ->willReturn('#000'); + + $this->assertSame('#000', $this->template->undo('color')); + } + + public function testUndoDefaultAction() { + $this->config + ->expects($this->at(0)) + ->method('deleteAppValue') + ->with('theming', 'defaultitem'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('15'); + $this->config + ->expects($this->at(2)) + ->method('setAppValue') + ->with('theming', 'cachebuster', 16); + + $this->assertSame('', $this->template->undo('defaultitem')); + } +} diff --git a/apps/theming/tests/lib/controller/ThemingControllerTest.php b/apps/theming/tests/lib/controller/ThemingControllerTest.php new file mode 100644 index 00000000000..82aa7d13818 --- /dev/null +++ b/apps/theming/tests/lib/controller/ThemingControllerTest.php @@ -0,0 +1,405 @@ +<?php +/** + * @copyright Copyright (c) 2016 Lukas Reschke <lukas@statuscode.ch> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ +namespace OCA\Theming\Tests\Controller; + +use OCA\Theming\Controller\ThemingController; +use OCA\Theming\Template; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IConfig; +use OCP\IL10N; +use OCP\IRequest; +use Test\TestCase; + +class ThemingControllerTest extends TestCase { + /** @var IRequest */ + private $request; + /** @var IConfig */ + private $config; + /** @var Template */ + private $template; + /** @var IL10N */ + private $l10n; + /** @var ThemingController */ + private $themingController; + + public function setUp() { + $this->request = $this->getMock('\\OCP\\IRequest'); + $this->config = $this->getMock('\\OCP\\IConfig'); + $this->template = $this->getMockBuilder('\\OCA\\Theming\\Template') + ->disableOriginalConstructor()->getMock(); + $this->l10n = $this->getMock('\\OCP\\IL10N'); + $this->themingController = new ThemingController( + 'theming', + $this->request, + $this->config, + $this->template, + $this->l10n + ); + + return parent::setUp(); + } + + public function testUpdateStylesheet() { + $this->template + ->expects($this->once()) + ->method('set') + ->with('MySetting', 'MyValue'); + $this->l10n + ->expects($this->once()) + ->method('t') + ->with('Saved') + ->willReturn('Saved'); + + $expected = new DataResponse( + [ + 'data' => + [ + 'message' => 'Saved', + ], + 'status' => 'success' + ] + ); + $this->assertEquals($expected, $this->themingController->updateStylesheet('MySetting', 'MyValue')); + } + + public function testUpdateLogoNoData() { + $this->request + ->expects($this->at(0)) + ->method('getUploadedFile') + ->with('uploadlogo') + ->willReturn(null); + $this->request + ->expects($this->at(1)) + ->method('getUploadedFile') + ->with('upload-login-background') + ->willReturn(null); + $this->l10n + ->expects($this->once()) + ->method('t') + ->with('No file uploaded') + ->willReturn('No file uploaded'); + + $expected = new DataResponse( + [ + 'data' => + [ + 'message' => 'No file uploaded', + ], + ], + Http::STATUS_UNPROCESSABLE_ENTITY + ); + + $this->assertEquals($expected, $this->themingController->updateLogo()); + } + + public function testUpdateLogoNormalLogoUpload() { + $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg'; + $destination = \OC::$server->getTempManager()->getTemporaryFolder(); + + touch($tmpLogo); + $this->request + ->expects($this->at(0)) + ->method('getUploadedFile') + ->with('uploadlogo') + ->willReturn([ + 'tmp_name' => $tmpLogo, + 'type' => 'text/svg', + 'name' => 'logo.svg', + ]); + $this->request + ->expects($this->at(1)) + ->method('getUploadedFile') + ->with('upload-login-background') + ->willReturn(null); + $this->config + ->expects($this->at(0)) + ->method('getSystemValue') + ->with('datadirectory', \OC::$SERVERROOT . '/data') + ->willReturn($destination); + $this->l10n + ->expects($this->once()) + ->method('t') + ->with('Saved') + ->willReturn('Saved'); + + $expected = new DataResponse( + [ + 'data' => + [ + 'name' => 'logo.svg', + 'message' => 'Saved', + ], + 'status' => 'success' + ] + ); + + $this->assertEquals($expected, $this->themingController->updateLogo()); + } + + public function testUpdateLogoLoginScreenUpload() { + $tmpLogo = \OC::$server->getTempManager()->getTemporaryFolder() . '/logo.svg'; + $destination = \OC::$server->getTempManager()->getTemporaryFolder(); + + touch($tmpLogo); + $this->request + ->expects($this->at(0)) + ->method('getUploadedFile') + ->with('uploadlogo') + ->willReturn(null); + $this->request + ->expects($this->at(1)) + ->method('getUploadedFile') + ->with('upload-login-background') + ->willReturn([ + 'tmp_name' => $tmpLogo, + 'type' => 'text/svg', + 'name' => 'logo.svg', + ]); + $this->config + ->expects($this->at(0)) + ->method('getSystemValue') + ->with('datadirectory', \OC::$SERVERROOT . '/data') + ->willReturn($destination); + $this->l10n + ->expects($this->once()) + ->method('t') + ->with('Saved') + ->willReturn('Saved'); + + $expected = new DataResponse( + [ + 'data' => + [ + 'name' => 'logo.svg', + 'message' => 'Saved', + ], + 'status' => 'success' + ] + ); + $this->assertEquals($expected, $this->themingController->updateLogo()); + } + + public function testUndo() { + $this->l10n + ->expects($this->once()) + ->method('t') + ->with('Saved') + ->willReturn('Saved'); + $this->template + ->expects($this->once()) + ->method('undo') + ->with('MySetting') + ->willReturn('MyValue'); + + $expected = new DataResponse( + [ + 'data' => + [ + 'value' => 'MyValue', + 'message' => 'Saved', + ], + 'status' => 'success' + ] + ); + $this->assertEquals($expected, $this->themingController->undo('MySetting')); + } + + public function testGetLogoNotExistent() { + $expected = new DataResponse(); + $this->assertEquals($expected, $this->themingController->getLogo()); + } + + public function testGetLogo() { + $dataFolder = \OC::$server->getTempManager()->getTemporaryFolder(); + $tmpLogo = $dataFolder . '/themedinstancelogo'; + touch($tmpLogo); + $this->config + ->expects($this->once()) + ->method('getSystemValue') + ->with('datadirectory', \OC::$SERVERROOT . '/data/') + ->willReturn($dataFolder); + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'logoMime', '') + ->willReturn('text/svg'); + + @$expected = new Http\StreamResponse($tmpLogo); + $expected->cacheFor(3600); + $expected->addHeader('Content-Disposition', 'attachment'); + $expected->addHeader('Content-Type', 'text/svg'); + @$this->assertEquals($expected, $this->themingController->getLogo()); + } + + + public function testGetLoginBackgroundNotExistent() { + $expected = new DataResponse(); + $this->assertEquals($expected, $this->themingController->getLoginBackground()); + } + + public function testGetLoginBackground() { + $dataFolder = \OC::$server->getTempManager()->getTemporaryFolder(); + $tmpLogo = $dataFolder . '/themedbackgroundlogo'; + touch($tmpLogo); + $this->config + ->expects($this->once()) + ->method('getSystemValue') + ->with('datadirectory', \OC::$SERVERROOT . '/data/') + ->willReturn($dataFolder); + $this->config + ->expects($this->once()) + ->method('getAppValue') + ->with('theming', 'backgroundMime', '') + ->willReturn('image/png'); + + @$expected = new Http\StreamResponse($tmpLogo); + $expected->cacheFor(3600); + $expected->addHeader('Content-Disposition', 'attachment'); + $expected->addHeader('Content-Type', 'image/png'); + @$this->assertEquals($expected, $this->themingController->getLoginBackground()); + } + + public function testGetStylesheetWithOnlyColor() { + $this->config + ->expects($this->at(0)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('0'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'color', '') + ->willReturn('#fff'); + $this->config + ->expects($this->at(2)) + ->method('getAppValue') + ->with('theming', 'logoMime', '') + ->willReturn(''); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'backgroundMime', '') + ->willReturn(''); + + $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #fff}', 'style.css', 'text/css'); + $expected->cacheFor(3600); + @$this->assertEquals($expected, $this->themingController->getStylesheet()); + } + + public function testGetStylesheetWithOnlyHeaderLogo() { + $this->config + ->expects($this->at(0)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('0'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'color', '') + ->willReturn(''); + $this->config + ->expects($this->at(2)) + ->method('getAppValue') + ->with('theming', 'logoMime', '') + ->willReturn('image/png'); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'backgroundMime', '') + ->willReturn(''); + + $expected = new Http\DataDownloadResponse('#header .logo { + background-image: url(\'./logo?v=0\'); + } + #header .logo-icon { + background-image: url(\'./logo?v=0\'); + background-size: 62px 34px; + }', 'style.css', 'text/css'); + $expected->cacheFor(3600); + @$this->assertEquals($expected, $this->themingController->getStylesheet()); + } + + public function testGetStylesheetWithOnlyBackgroundLogin() { + $this->config + ->expects($this->at(0)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('0'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'color', '') + ->willReturn(''); + $this->config + ->expects($this->at(2)) + ->method('getAppValue') + ->with('theming', 'logoMime', '') + ->willReturn(''); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'backgroundMime', '') + ->willReturn('text/svg'); + + $expected = new Http\DataDownloadResponse('#body-login { + background-image: url(\'./loginbackground?v=0\'); + }', 'style.css', 'text/css'); + $expected->cacheFor(3600); + @$this->assertEquals($expected, $this->themingController->getStylesheet()); + } + + public function testGetStylesheetWithAllCombined() { + $this->config + ->expects($this->at(0)) + ->method('getAppValue') + ->with('theming', 'cachebuster', '0') + ->willReturn('0'); + $this->config + ->expects($this->at(1)) + ->method('getAppValue') + ->with('theming', 'color', '') + ->willReturn('#abc'); + $this->config + ->expects($this->at(2)) + ->method('getAppValue') + ->with('theming', 'logoMime', '') + ->willReturn('text/svg'); + $this->config + ->expects($this->at(3)) + ->method('getAppValue') + ->with('theming', 'backgroundMime', '') + ->willReturn('image/png'); + + $expected = new Http\DataDownloadResponse('#body-user #header,#body-settings #header,#body-public #header {background-color: #abc}#header .logo { + background-image: url(\'./logo?v=0\'); + } + #header .logo-icon { + background-image: url(\'./logo?v=0\'); + background-size: 62px 34px; + }#body-login { + background-image: url(\'./loginbackground?v=0\'); + }', 'style.css', 'text/css'); + $expected->cacheFor(3600); + @$this->assertEquals($expected, $this->themingController->getStylesheet()); + } + +} |