summaryrefslogtreecommitdiff
path: root/plugins/Customizer/Controller
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/Customizer/Controller')
-rw-r--r--plugins/Customizer/Controller/CustomizerConfigController.php388
-rw-r--r--plugins/Customizer/Controller/CustomizerFileController.php313
2 files changed, 701 insertions, 0 deletions
diff --git a/plugins/Customizer/Controller/CustomizerConfigController.php b/plugins/Customizer/Controller/CustomizerConfigController.php
new file mode 100644
index 00000000..d816384d
--- /dev/null
+++ b/plugins/Customizer/Controller/CustomizerConfigController.php
@@ -0,0 +1,388 @@
+<?php
+
+namespace Kanboard\Plugin\Customizer\Controller;
+
+require_once __DIR__.'/../vendor/autoload.php';
+
+use Kanboard\Model\ConfigModel;
+use Kanboard\Model\LanguageModel;
+use Kanboard\Controller\BaseController;
+use luizbills\CSS_Generator\Generator as CSS_Generator;
+
+/**
+ * Config Controller
+ *
+ * @package Customizer/Controller
+ * @author creecros
+ */
+class CustomizerConfigController extends BaseController
+{
+
+ /**
+ * Save settings
+ *
+ */
+ public function save()
+ {
+ if (isset($_POST['remove'])) {
+ $values = $this->request->getValues();
+ $this->remove($values['themeSelection']);
+ } else {
+
+ $values = $this->request->getValues();
+
+ if (array_key_exists('use_custom_login', $values) === false) { $this->configModel->save(['use_custom_login' => '']); }
+ if (array_key_exists('enable_cache', $values) === false) { $this->configModel->save(['enable_cache' => '']); }
+
+ if ($this->configModel->save($values)) {
+ $this->languageModel->loadCurrentLanguage();
+ $this->flash->success(t('Settings saved successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to save your settings.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('CustomizerFileController', 'show', array('plugin' => 'Customizer')));
+ }
+ }
+
+ /**
+ * Save user theme
+ *
+ */
+ public function usertheme()
+ {
+ $user = $this->getUser();
+ $values = $this->request->getValues();
+
+ if ($this->userMetadataModel->save($user['id'], $values)) {
+ $this->languageModel->loadCurrentLanguage();
+ $this->flash->success(t('Settings saved successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to save your settings.'));
+ }
+
+ $this->response->redirect($this->helper->url->to('UserViewController', 'show', array('user_id' => $user['id'])), true);
+
+ }
+
+ /**
+ * Reset all User themes
+ *
+ */
+ public function resetUserThemes()
+ {
+ $users = $this->userModel->getAll();
+ foreach ($users as $user) {
+ $this->userMetadataModel->remove($user['id'], 'themeSelection');
+ }
+ $this->response->redirect($this->helper->url->to('CustomizerFileController', 'show', array('plugin' => 'Customizer')));
+ }
+
+ /**
+ * Toggle User themes
+ *
+ */
+ public function enableDisableThemes()
+ {
+ $status = $this->configModel->get('toggle_user_themes', 'disable');
+
+ if ($status == 'disable') { $this->configModel->save(['toggle_user_themes' => 'enable']); } else { $this->configModel->save(['toggle_user_themes' => 'disable']); }
+ $this->response->redirect($this->helper->url->to('CustomizerFileController', 'show', array('plugin' => 'Customizer')));
+ }
+
+
+ /**
+ * Upload css theme
+ *
+ */
+ public function uploadcss()
+ {
+ $target_dir = DATA_DIR . '/files/customizer/themes/';
+ $target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
+ $uploadOk = 1;
+ $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
+ // Check if file already exists
+ if (file_exists($target_file)) {
+ $this->flash->failure(t('Sorry, file already exists.'));
+ $uploadOk = 0;
+ }
+ // Check file size
+ if ($_FILES["fileToUpload"]["size"] > 1000000) {
+ $this->flash->failure(t('Sorry, your file is too large.'));
+ $uploadOk = 0;
+ }
+ // Allow certain file formats
+ if($imageFileType != "css") {
+ $this->flash->failure(t('Sorry, only CSS files are allowed.'));
+ $uploadOk = 0;
+ }
+ // Check if $uploadOk is set to 0 by an error
+ if ($uploadOk == 0) {
+ $this->flash->failure(t('Sorry, your file was not uploaded.'));
+ // if everything is ok, try to upload file
+ } else {
+ if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
+ $this->flash->success(t('Theme file uploaded successfully.'));
+ } else {
+ $this->flash->failure(t('Sorry, there was an error uploading your file.'));
+ }
+ }
+
+ $this->response->redirect($this->helper->url->to('CustomizerFileController', 'show', array('plugin' => 'Customizer')));
+ }
+
+ public function remove($file)
+ {
+ $filename = basename($file);
+ if (file_exists(DATA_DIR . '/files/customizer/themes/' . $filename)) { unlink(DATA_DIR . '/files/customizer/themes/' . $filename); }
+ unlink($file);
+ $this->response->redirect($this->helper->url->to('CustomizerFileController', 'show', array('plugin' => 'Customizer')));
+ }
+
+ public function create_theme()
+ {
+ $values = $this->request->getValues();
+
+ $options = [
+ // default values
+ // 'indentation' => ' ', // 4 spaces
+ ];
+
+ $css = new CSS_Generator($options);
+
+ // Header
+ $css->add_rule('header',
+ [
+ 'background-color' => $values['header_background'],
+ 'background-image' => 'linear-gradient(-180deg, transparent 0%, '.$values['header_shade'].' 90%)'
+ ]
+ );
+ $css->add_rule(['header h1', 'header a .fa'],
+ [
+ 'color' => $values['header_title']
+ ]
+ );
+ $css->add_rule('a i.web-notification-icon',
+ [
+ 'color' => $values['notification_icon']
+ ]
+ );
+ // Body
+ $css->add_rule('body',
+ [
+ 'background' => $values['background_color'],
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule(['ul.dropdown-submenu-open', '.accordion-title h3'],
+ [
+ 'background-color' => $values['background_color']
+ ]
+ );
+ $css->add_rule('.dropdown-submenu-open a',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('a:hover',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('a .fa',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule(['h1', 'h2', 'h3', '.accordion-toggle'],
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.table-list-header a',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.table-list-header .table-list-header-count',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.table-list-row .table-list-title a',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.table-list-row .table-list-details strong',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.dropdown-menu-link-icon',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.page-header h2 a',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.sidebar>ul a:hover',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.sidebar>ul li.active a',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.task-list-icons a:hover',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.task-list-icons a:hover i',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('.subtask-cell a',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule('a',
+ [
+ 'color' => $values['font_link']
+ ]
+ );
+ $css->add_rule('.table-list-category a:hover',
+ [
+ 'color' => $values['font_link']
+ ]
+ );
+ $css->add_rule(['.subtask-cell a:hover', '.subtask-cell a:focus'],
+ [
+ 'color' => $values['font_link']
+ ]
+ );
+ $css->add_rule(['a:focus', 'a:hover'],
+ [
+ 'color' => $values['font_link_focus']
+ ]
+ );
+ $css->add_rule(['.table-list-header a:hover', '.table-list-header a:focus', '.task-board a'],
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule('.table-list-row .table-list-details',
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule('.input-addon-field',
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule(['.page-header h2 a:focus', '.page-header h2 a:hover', 'code'],
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule('.sidebar>ul a',
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule('.task-list-avatars .task-avatar-assignee',
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule(['.task-list-icons a', '.task-list-icons span', '.task-list-icons i', '.task-date'],
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule('span.task-date-overdue',
+ [
+ 'color' => $values['font_overdue']
+ ]
+ );
+ $css->add_rule('.sidebar>ul li.active',
+ [
+ 'border-left' => '5px solid '.$values['font_main']
+ ]
+ );
+ $css->add_rule(['.sidebar>ul li.active a:focus', '.sidebar>ul li.active a:hover'],
+ [
+ 'color' => $values['font_secondary']
+ ]
+ );
+ $css->add_rule('.sidebar>ul li:hover',
+ [
+ 'border-left' => '5px solid '.$values['font_secondary']
+ ]
+ );
+ $css->add_rule('.panel',
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+ $css->add_rule(['td a.dropdown-menu strong', 'td a.dropdown-menu strong i'],
+ [
+ 'color' => $values['font_main']
+ ]
+ );
+
+ $css->add_raw('
+ #task-summary h2 {color: unset;}
+ .comments .comment:hover {background: #efefef40;}
+ .comments .comment:nth-child(even):not(.comment-highlighted):hover {background: #efefef40;}
+ .comments .comment:nth-child(even):not(.comment-highlighted) {background: #efefef40;}
+ table.table-striped tr:nth-child(odd) {background: #efefef40;}
+ header {box-shadow: 0px -1px 5px 1px;border-bottom: none;}
+ .project-header {margin-bottom: 8px;margin-top: 8px;}
+ .panel{background-color: #efefef40;border: 1px solid #efefef40;}
+ .task-board{border-width: 2px;background: #efefef22!important;}
+ div.task-board-recent {border-width: 2px;}
+ table td {border:none;}
+ table th:first-child {border-top-left-radius:8px;}
+ table th:last-child {border-top-right-radius:8px;}
+ .table-list-header{background:#efefef40;border:1px solid #efefef40;border-radius:5px 5px 0 0;line-height:28px;padding-left:3px;padding-right:3px;}
+ .table-list-row{padding-left:3px;padding-right:3px;border-bottom:1px solid #efefef40;border-right:1px solid #efefef40;}
+ .table-list-row.table-border-left{border-left:1px solid #efefef40;}
+ .table-list-row:nth-child(odd){background:#efefef30;}
+ .table-list-row:hover{background:#efefef32;border-bottom:1px solid #efefef32;border-right:1px solid #efefef32;}
+ .dropdown-menu-link-icon{text-decoration:none;}
+ .dropdown-submenu-open li{border-bottom:1px solid #efefef40;}
+ .page-header h2{margin:0;padding:0;font-weight:bold;border-bottom:1px dotted #efefef40;}
+ .sidebar>ul li{list-style-type:none;line-height:35px;border-bottom:1px dotted #efefef40;padding-left:13px;}
+ span.task-icon-age-total{border:1px solid #efefef40;padding:1px 3px 1px 3px;border-top-left-radius:3px;border-bottom-left-radius:3px;}
+ span.task-icon-age-column{border:1px solid #efefef40;border-left:none;margin-left:-5px;padding:1px 3px 1px 3px;border-top-right-radius:3px;border-bottom-right-radius:3px;}
+ .subtask-cell{padding:4px 10px;border-top:1px dotted #efefef42;border-left:1px dotted #efefef40;display:table-cell;vertical-align:middle;}
+ table th {text-align: left;padding: 0.5em 3px;border:none;background: #efefef40;}
+ .views li {white-space: nowrap;background: #efefef40;border:none;border-right: none;padding: 4px 8px;display: inline;}
+ ');
+
+
+ $minify = true;
+
+ $extension = '.css';
+ $rename = str_replace('.', '', $values['theme_name']);
+
+ if (file_exists(DATA_DIR . '/files/customizer/themes')) {
+ file_put_contents(DATA_DIR . '/files/customizer/themes/' . $rename . $extension, $css->get_output($minify));
+ } else {
+ mkdir(DATA_DIR . '/files/customizer/themes', 0755);
+ file_put_contents(DATA_DIR . '/files/customizer/themes/' . $rename . $extension, $css->get_output($minify));
+ }
+
+ $this->response->redirect($this->helper->url->to('CustomizerFileController', 'show', array('plugin' => 'Customizer')));
+ }
+}
diff --git a/plugins/Customizer/Controller/CustomizerFileController.php b/plugins/Customizer/Controller/CustomizerFileController.php
new file mode 100644
index 00000000..75271320
--- /dev/null
+++ b/plugins/Customizer/Controller/CustomizerFileController.php
@@ -0,0 +1,313 @@
+<?php
+
+namespace Kanboard\Plugin\Customizer\Controller;
+
+use Kanboard\Plugin\Customizer\Model\CustomizerFileModel;
+use Kanboard\Core\ObjectStorage\ObjectStorageException;
+use Kanboard\Controller\BaseController;
+use Kanboard\Model\ConfigModel;
+
+/**
+ * Customizer Controller
+ *
+ * @package Customizer\Controller
+ * @author creecros
+ */
+class CustomizerFileController extends BaseController
+{
+ /**
+ * Get file content from object storage
+ *
+ * @access protected
+ * @param array $file
+ * @return string
+ */
+ protected function getFileContent(array $file)
+ {
+ $content = '';
+
+ try {
+ if ($file['is_image'] == 0) {
+ $content = $this->objectStorage->get($file['path']);
+ }
+ } catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
+
+ return $content;
+ }
+
+ /**
+ * Output file with cache
+ *
+ * @param array $file
+ * @param $mimetype
+ */
+ protected function renderFileWithCache(array $file, $mimetype)
+ {
+ $etag = md5($file['path']);
+
+ if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') {
+ $this->response->status(304);
+ } else {
+ try {
+ $this->response->withContentType($mimetype);
+ $this->response->withCache(5 * 86400, $etag);
+ $this->response->send();
+ $this->objectStorage->output($file['path']);
+ } catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
+ }
+ }
+
+ /**
+ * Output file without cache
+ *
+ * @param array $file
+ * @param $mimetype
+ */
+ protected function renderFileWithoutCache(array $file, $mimetype)
+ {
+ $etag = md5($file['path']);
+
+ if ($this->request->getHeader('If-None-Match') === '"'.$etag.'"') {
+ $this->response->status(304);
+ } else {
+ try {
+ $this->response->withContentType($mimetype);
+ $this->response->withOutCache();
+ $this->response->send();
+ $this->objectStorage->output($file['path']);
+ } catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
+ }
+ }
+
+ public function show()
+ {
+ $logo = $this->customizerFileModel->getByType(1);
+ $flavicon = $this->customizerFileModel->getByType(2);
+ $loginlogo = $this->customizerFileModel->getByType(3);
+ $logopath = $logo['path'];
+ $flaviconpath = $flavicon['path'];
+ $this->response->html($this->helper->layout->config('customizer:file/show', array(
+ 'logo' => $logo,
+ 'title' => t('Settings').' &gt; '.t('Customizer'),
+ 'flavicon' => $flavicon,
+ 'logopath' => $logopath,
+ 'flaviconpath' => $flaviconpath,
+ 'loginlogo' => $loginlogo
+ )));
+
+ }
+
+ public function logo()
+ {
+ if ($this->logoexists()) {
+ $file = $this->customizerFileModel->getByType(1);
+ if ($this->configModel->get('enable_cache', '') == 'checked') {
+ $this->renderFileWithCache($file, $this->helper->file->getImageMimeType($file['name']));
+ } else {
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+ }
+
+ public function logo_setting()
+ {
+ if ($this->logoexists()) {
+ $file = $this->customizerFileModel->getByType(1);
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+
+ public function loginlogo()
+ {
+ if ($this->loginlogoexists()) {
+ $file = $this->customizerFileModel->getByType(3);
+ if ($this->configModel->get('enable_cache', '') == 'checked') {
+ $this->renderFileWithCache($file, $this->helper->file->getImageMimeType($file['name']));
+ } else {
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+ }
+
+ public function loginlogo_setting()
+ {
+ if ($this->loginlogoexists()) {
+ $file = $this->customizerFileModel->getByType(3);
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+
+ public function icon()
+ {
+ if ($this->iconexists()) {
+ $file = $this->customizerFileModel->getByType(2);
+ if ($this->configModel->get('enable_cache', '') == 'checked') {
+ $this->renderFileWithCache($file, $this->helper->file->getImageMimeType($file['name']));
+ } else {
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+ }
+
+ public function icon_setting()
+ {
+ if ($this->iconexists()) {
+ $file = $this->customizerFileModel->getByType(2);
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+
+ public function link()
+ {
+ if ($this->logoexists() && $this->linkexists()) {
+ return $this->response->redirect($this->configModel->get('login_link', 'https://kanboard.org'));
+ } else {
+ return $this->response->redirect($this->configModel->get('application_url', '') . 'login');
+ }
+ }
+
+ public function logoexists()
+ {
+ if (null !== $this->customizerFileModel->getByType(1)) { return true; } else { return false; }
+ }
+
+ public function loginlogoexists()
+ {
+ if (null !== $this->customizerFileModel->getByType(3)) {
+ $customizer['loginCheck'] = true;
+ return true;
+ } else {
+ $customizer['loginCheck'] = false;
+ return false;
+ }
+ }
+
+ public function linkexists()
+ {
+ if ($this->configModel->exists('login_link')) { return true; } else { return false; }
+ }
+
+ public function iconexists()
+ {
+ if (null !== $this->customizerFileModel->getByType(2)) { return true; } else { return false; }
+ }
+
+ public function image()
+ {
+ $file = $this->customizerFileModel->getById($this->request->getIntegerParam('file_id'));
+ if ($this->configModel->get('enable_cache', '') == 'checked') {
+ $this->renderFileWithCache($file, $this->helper->file->getImageMimeType($file['name']));
+ } else {
+ $this->renderFileWithoutCache($file, $this->helper->file->getImageMimeType($file['name']));
+ }
+ }
+
+ /**
+ * File upload form
+ *
+ * @access public
+ */
+ public function create()
+ {
+ ini_set('display_errors', 1);
+ ini_set('display_startup_errors', 1);
+ error_reporting(E_ALL);
+ $custom_id = $this->request->getIntegerParam('custom_id');
+ if ($custom_id == 1) {
+ $this->response->html($this->template->render('customizer:file/upload_logo', array(
+ 'custom_id' => $custom_id,
+ 'multiple' => false,
+ )));
+ } else if ($custom_id == 2) {
+ $this->response->html($this->template->render('customizer:file/upload_flavicon', array(
+ 'custom_id' => $custom_id,
+ 'multiple' => false,
+ )));
+ } else if ($custom_id == 3) {
+ $this->response->html($this->template->render('customizer:file/upload_loginlogo', array(
+ 'custom_id' => $custom_id,
+ 'multiple' => false,
+ )));
+ }
+ }
+
+ /**
+ * File upload (save files)
+ *
+ * @access public
+ */
+ public function save()
+ {
+ ini_set('display_errors', 1);
+ ini_set('display_startup_errors', 1);
+ error_reporting(E_ALL);
+ $custom_id = $this->request->getIntegerParam('custom_id');
+ if ($custom_id ==3) { $loginCheck = true; }
+
+ $result = $this->customizerFileModel->uploadFiles($custom_id, $this->request->getFileInfo('files'));
+ if ($this->request->isAjax()) {
+ if (!$result) {
+ $this->response->json(array('message' => t('Unable to upload files, check the permissions of your data folder.')), 500);
+ } else {
+ $this->response->json(array('message' => 'OK'));
+ }
+ } else {
+ if (!$result) {
+ $this->flash->failure(t('Unable to upload files, check the permissions of your data folder.'));
+ }
+ }
+ }
+ /**
+ * Remove a file
+ *
+ * @access public
+ */
+ public function remove()
+ {
+ $this->checkCSRFParam();
+ $custom_id = $this->request->getIntegerParam('custom_id');
+ $file = $this->customizerFileModel->getById($this->request->getIntegerParam('file_id'));
+ if ($this->customizerFileModel->remove($file['id'])) {
+ $this->flash->success(t('File removed successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to remove this file.'));
+ }
+
+ }
+
+ public function removeform()
+ {
+ $this->checkCSRFParam();
+ $custom_id = $this->request->getIntegerParam('custom_id');
+ if ($custom_id == 3) { $loginCheck = false; }
+ $file = $this->customizerFileModel->getById($this->request->getIntegerParam('file_id'));
+ if ($this->customizerFileModel->remove($file['id'])) {
+ $this->flash->success(t('File removed successfully.'));
+ } else {
+ $this->flash->failure(t('Unable to remove this file.'));
+ }
+
+ return $this->response->redirect($this->configModel->get('application_url', '') . 'settings/customizer');
+
+ }
+ /**
+ * Confirmation dialog before removing a file
+ *
+ * @access public
+ */
+ public function confirm()
+ {
+ $custom_id = $this->request->getIntegerParam('custom_id');
+ $file = $this->customizerFileModel->getById($this->request->getIntegerParam('file_id'));
+ $this->response->html($this->template->render('customizer:file/remove', array(
+ 'custom_id' => $custom_id,
+ 'file' => $file,
+ )));
+ }
+}