diff --git a/composer.json b/composer.json index f960f7f8..ef9b7822 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "require": { "php": "^7.1.3", "ext-pdo_sqlite": "*", - "avanzu/admin-theme-bundle": "dev-symfony4", + "avanzu/admin-theme-bundle": "dev-kevinpapst", "beberlei/DoctrineExtensions": "^1.0", "dama/doctrine-test-bundle": "^4.0", "sensio/framework-extra-bundle": "^5.1", @@ -23,6 +23,7 @@ "symfony/security-bundle": "^4.0", "symfony/security-csrf": "^4.0", "symfony/swiftmailer-bundle": "^3.1", + "symfony/thanks": "^1.0", "symfony/translation": "^4.0", "symfony/twig-bundle": "^4.0", "symfony/validator": "^4.0", diff --git a/composer.lock b/composer.lock index 32b4d734..3744f3d6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "c8bbb84ec7e932d13852eab55f0306e2", + "content-hash": "fcf570204034bd83c84fd7f92fc3fab4", "packages": [ { "name": "almasaeed2010/adminlte", @@ -48,16 +48,16 @@ }, { "name": "avanzu/admin-theme-bundle", - "version": "dev-symfony4", + "version": "dev-kevinpapst", "source": { "type": "git", "url": "https://github.com/kevinpapst/AdminThemeBundle.git", - "reference": "f007e946f56295f447d0f1b75e5a7cf55145cf7c" + "reference": "1aa9b1637b2f827fe79ca1edff26092840e30716" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/kevinpapst/AdminThemeBundle/zipball/f007e946f56295f447d0f1b75e5a7cf55145cf7c", - "reference": "f007e946f56295f447d0f1b75e5a7cf55145cf7c", + "url": "https://api.github.com/repos/kevinpapst/AdminThemeBundle/zipball/1aa9b1637b2f827fe79ca1edff26092840e30716", + "reference": "1aa9b1637b2f827fe79ca1edff26092840e30716", "shasum": "" }, "require": { @@ -109,9 +109,9 @@ ], "description": "Admin Theme based on the AdminLTE Template for easy integration into symfony", "support": { - "source": "https://github.com/kevinpapst/AdminThemeBundle/tree/symfony4" + "source": "https://github.com/kevinpapst/AdminThemeBundle/tree/kevinpapst" }, - "time": "2018-01-12T20:01:56+00:00" + "time": "2018-01-15T19:14:46+00:00" }, { "name": "beberlei/DoctrineExtensions", @@ -177,16 +177,16 @@ }, { "name": "dama/doctrine-test-bundle", - "version": "v4.0.1", + "version": "v4.0.2", "source": { "type": "git", "url": "https://github.com/dmaicher/doctrine-test-bundle.git", - "reference": "8567a6ebfc73822f1d105ce852edec1b06748d8f" + "reference": "438346b3380cc7675e37fbcdca912fdc33471d32" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/8567a6ebfc73822f1d105ce852edec1b06748d8f", - "reference": "8567a6ebfc73822f1d105ce852edec1b06748d8f", + "url": "https://api.github.com/repos/dmaicher/doctrine-test-bundle/zipball/438346b3380cc7675e37fbcdca912fdc33471d32", + "reference": "438346b3380cc7675e37fbcdca912fdc33471d32", "shasum": "" }, "require": { @@ -230,7 +230,7 @@ "symfony 2", "tests" ], - "time": "2017-10-19T11:52:38+00:00" + "time": "2018-01-13T13:14:27+00:00" }, { "name": "doctrine/annotations", @@ -1714,16 +1714,16 @@ }, { "name": "sensio/framework-extra-bundle", - "version": "v5.1.3", + "version": "v5.1.4", "source": { "type": "git", "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", - "reference": "0696496cb3e2d23add645d424699e5c723238aad" + "reference": "072c00c52b947e88a1e619e9ff426cee6c8c482b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/0696496cb3e2d23add645d424699e5c723238aad", - "reference": "0696496cb3e2d23add645d424699e5c723238aad", + "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/072c00c52b947e88a1e619e9ff426cee6c8c482b", + "reference": "072c00c52b947e88a1e619e9ff426cee6c8c482b", "shasum": "" }, "require": { @@ -1779,7 +1779,7 @@ "annotations", "controllers" ], - "time": "2017-12-04T18:33:55+00:00" + "time": "2018-01-12T13:08:16+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -2508,16 +2508,16 @@ }, { "name": "symfony/flex", - "version": "v1.0.60", + "version": "v1.0.61", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "066fe955b1a134841cdcc068a9f843594fdb1adc" + "reference": "f872f8faccf5ff95678e1e428f460a333ba1e5d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/066fe955b1a134841cdcc068a9f843594fdb1adc", - "reference": "066fe955b1a134841cdcc068a9f843594fdb1adc", + "url": "https://api.github.com/repos/symfony/flex/zipball/f872f8faccf5ff95678e1e428f460a333ba1e5d0", + "reference": "f872f8faccf5ff95678e1e428f460a333ba1e5d0", "shasum": "" }, "require": { @@ -2550,7 +2550,7 @@ "email": "fabien.potencier@gmail.com" } ], - "time": "2018-01-10T07:00:13+00:00" + "time": "2018-01-12T13:09:44+00:00" }, { "name": "symfony/form", @@ -3982,6 +3982,49 @@ "homepage": "http://symfony.com", "time": "2017-10-23T15:15:11+00:00" }, + { + "name": "symfony/thanks", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/thanks.git", + "reference": "b637913a92664571afd1067fc645ecb30c9cf5b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/thanks/zipball/b637913a92664571afd1067fc645ecb30c9cf5b2", + "reference": "b637913a92664571afd1067fc645ecb30c9cf5b2", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1", + "php": "^5.5.9|^7.0.8" + }, + "type": "composer-plugin", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + }, + "class": "Symfony\\Thanks\\Thanks" + }, + "autoload": { + "psr-4": { + "Symfony\\Thanks\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + } + ], + "description": "Give thanks (in the form of a GitHub ⭐) to your fellow PHP package maintainers (not limited to Symfony components)!", + "time": "2018-01-03T09:30:52+00:00" + }, { "name": "symfony/translation", "version": "v4.0.3", @@ -5990,16 +6033,16 @@ }, { "name": "sebastian/comparator", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f" + "reference": "11c07feade1d65453e06df3b3b90171d6d982087" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/b11c729f95109b56a0fe9650c6a63a0fcd8c439f", - "reference": "b11c729f95109b56a0fe9650c6a63a0fcd8c439f", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/11c07feade1d65453e06df3b3b90171d6d982087", + "reference": "11c07feade1d65453e06df3b3b90171d6d982087", "shasum": "" }, "require": { @@ -6050,7 +6093,7 @@ "compare", "equality" ], - "time": "2017-12-22T14:50:35+00:00" + "time": "2018-01-12T06:34:42+00:00" }, { "name": "sebastian/diff", @@ -6942,49 +6985,6 @@ "homepage": "https://symfony.com", "time": "2018-01-04T17:20:09+00:00" }, - { - "name": "symfony/thanks", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/thanks.git", - "reference": "b637913a92664571afd1067fc645ecb30c9cf5b2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/thanks/zipball/b637913a92664571afd1067fc645ecb30c9cf5b2", - "reference": "b637913a92664571afd1067fc645ecb30c9cf5b2", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1", - "php": "^5.5.9|^7.0.8" - }, - "type": "composer-plugin", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - }, - "class": "Symfony\\Thanks\\Thanks" - }, - "autoload": { - "psr-4": { - "Symfony\\Thanks\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - } - ], - "description": "Give thanks (in the form of a GitHub ⭐) to your fellow PHP package maintainers (not limited to Symfony components)!", - "time": "2018-01-03T09:30:52+00:00" - }, { "name": "symfony/web-server-bundle", "version": "v4.0.3", diff --git a/config/packages/avanzu_admin_theme.yml b/config/packages/avanzu_admin_theme.yml index eb9940b0..2485c213 100644 --- a/config/packages/avanzu_admin_theme.yml +++ b/config/packages/avanzu_admin_theme.yml @@ -4,11 +4,6 @@ avanzu_admin_theme: bower_bin: "/usr/local/bin/bower" options: default_avatar: images/default_avatar.png - skin: skin-green-light - fixed_layout: false - boxed_layout: false - collapsed_sidebar: true - mini_sidebar: true control_sidebar: true knp_menu: enable: false diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 9654c6bb..29c33e2b 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -24,3 +24,8 @@ framework: # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) #app: cache.adapter.apcu + + #available with Symfony 4.1 + #validation: + # possible values: 'loose', 'strict', 'html5' + #email_validation_mode: 'html5' diff --git a/public/js/kimai.js b/public/js/kimai.js index 4a44b83b..7dedc039 100644 --- a/public/js/kimai.js +++ b/public/js/kimai.js @@ -1,5 +1,7 @@ $(document).ready(function() { + // $.AdminLTE.pushMenu.expandOnHover(); + (function( $ ) { var pubSub = $({}); diff --git a/src/Entity/User.php b/src/Entity/User.php index 261d3c1d..1e1716a5 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -379,7 +379,7 @@ class User implements UserInterface, AdvancedUserInterface */ public function isAccountNonExpired() { - return $this->isEnabled(); + return true; } /** @@ -387,7 +387,7 @@ class User implements UserInterface, AdvancedUserInterface */ public function isAccountNonLocked() { - return $this->isEnabled(); + return true; } /** @@ -395,7 +395,7 @@ class User implements UserInterface, AdvancedUserInterface */ public function isCredentialsNonExpired() { - return $this->isEnabled(); + return true; } /** diff --git a/src/Entity/UserPreference.php b/src/Entity/UserPreference.php index fefb125c..e574e704 100644 --- a/src/Entity/UserPreference.php +++ b/src/Entity/UserPreference.php @@ -3,7 +3,8 @@ namespace App\Entity; use Doctrine\ORM\Mapping as ORM; -use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints as Assert; @@ -59,7 +60,7 @@ class UserPreference /** * @var string */ - protected $type = TextType::class; + protected $type; /** * @var Constraint[] @@ -121,18 +122,25 @@ class UserPreference } /** - * @return string + * @return string|int|bool */ public function getValue() { + switch ($this->type) { + case CheckboxType::class: + return (bool) $this->value; + case IntegerType::class: + return (int) $this->value; + } + return $this->value; } /** - * @param string $value + * @param string|int|bool $value * @return UserPreference */ - public function setValue(string $value): UserPreference + public function setValue($value): UserPreference { $this->value = $value; return $this; diff --git a/src/EventSubscriber/ThemeOptionsSubscriber.php b/src/EventSubscriber/ThemeOptionsSubscriber.php new file mode 100644 index 00000000..e1d510bd --- /dev/null +++ b/src/EventSubscriber/ThemeOptionsSubscriber.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\EventSubscriber; + +use App\Entity\User; +use App\Entity\UserPreference; +use Avanzu\AdminThemeBundle\Helper\ContextHelper; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\KernelEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; + +/** + * @author Kevin Papst + */ +class ThemeOptionsSubscriber implements EventSubscriberInterface +{ + + /** + * @var TokenStorageInterface + */ + protected $storage; + + /** + * @var ContextHelper + */ + protected $helper; + + /** + * ThemeOptionsSubscriber constructor. + * @param TokenStorageInterface $storage + * @param ContextHelper $helper + */ + public function __construct(TokenStorageInterface $storage, ContextHelper $helper) + { + $this->storage = $storage; + $this->helper = $helper; + } + + /** + * @return array + */ + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::CONTROLLER => ['setThemeOptions', 100] + ]; + } + + /** + * @param KernelEvent $event + */ + public function setThemeOptions(KernelEvent $event) + { + if (!$this->canHandleEvent($event)) { + return; + } + + /** @var User $user */ + $user = $this->storage->getToken()->getUser(); + + $skin = ''; + foreach ($user->getPreferences() as $ref) { + $name = $ref->getName(); + if ($name === UserPreference::SKIN) { + $skin = 'skin-' . $ref->getValue(); + } + + if (strpos($name, 'theme.') !== false) { + $this->helper->setOption(str_replace('theme.', '', $name), $ref->getValue()); + } + } + + if (empty($skin)) { + $skin = 'skin-green'; + } + + $this->helper->setOption('skin', $skin); + } + + /** + * @param KernelEvent $event + * @return bool + */ + protected function canHandleEvent(KernelEvent $event): bool + { + // Ignore sub-requests + if (!$event->isMasterRequest()) { + return false; + } + + // ignore events like the toolbar where we do not have a token + if ($this->storage->getToken() === null) { + return false; + } + + /** @var User $user */ + $user = $this->storage->getToken()->getUser(); + + return ($user instanceof User); + } +} diff --git a/src/EventSubscriber/UserPreferenceSubscriber.php b/src/EventSubscriber/UserPreferenceSubscriber.php index 2460574d..6553d9ea 100644 --- a/src/EventSubscriber/UserPreferenceSubscriber.php +++ b/src/EventSubscriber/UserPreferenceSubscriber.php @@ -14,8 +14,10 @@ namespace App\EventSubscriber; use App\Entity\User; use App\Entity\UserPreference; use App\Event\UserPreferenceEvent; +use App\Form\Type\SkinType; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\KernelEvents; @@ -39,7 +41,7 @@ class UserPreferenceSubscriber implements EventSubscriberInterface protected $storage; /** - * PreferenceService constructor. + * UserPreferenceSubscriber constructor. * @param EventDispatcherInterface $dispatcher * @param TokenStorageInterface $storage */ @@ -55,7 +57,7 @@ class UserPreferenceSubscriber implements EventSubscriberInterface public static function getSubscribedEvents(): array { return [ - KernelEvents::CONTROLLER => ['onKernelEvent', -1], + KernelEvents::CONTROLLER => ['loadUserPreferences', 200] ]; } @@ -70,11 +72,33 @@ class UserPreferenceSubscriber implements EventSubscriberInterface ->setValue(0) ->setType(IntegerType::class) ->addConstraint(new Range(['min' => 0])), - /* + (new UserPreference()) ->setName(UserPreference::SKIN) - ->setValue('blue') + ->setValue('green') ->setType(SkinType::class), + + (new UserPreference()) + ->setName('theme.fixed_layout') + ->setValue(true) + ->setType(CheckboxType::class), + + (new UserPreference()) + ->setName('theme.boxed_layout') + ->setValue(false) + ->setType(CheckboxType::class), + + (new UserPreference()) + ->setName('theme.collapsed_sidebar') + ->setValue(false) + ->setType(CheckboxType::class), + + (new UserPreference()) + ->setName('theme.mini_sidebar') + ->setValue(true) + ->setType(CheckboxType::class), + + /* (new UserPreference()) ->setName('language') ->setValue('de') @@ -84,11 +108,17 @@ class UserPreferenceSubscriber implements EventSubscriberInterface } /** - * @param User $user - * @return User + * @param KernelEvent $event */ - public function setupUserPreferences(User $user) + public function loadUserPreferences(KernelEvent $event) { + if (!$this->canHandleEvent($event)) { + return; + } + + /** @var User $user */ + $user = $this->storage->getToken()->getUser(); + $prefs = []; foreach ($user->getPreferences() as $preference) { $prefs[$preference->getName()] = $preference; @@ -110,32 +140,27 @@ class UserPreferenceSubscriber implements EventSubscriberInterface } $user->setPreferences(array_values($prefs)); - - return $user; } /** * @param KernelEvent $event + * @return bool */ - public function onKernelEvent(KernelEvent $event): void + protected function canHandleEvent(KernelEvent $event): bool { // Ignore sub-requests if (!$event->isMasterRequest()) { - return; + return false; } // ignore events like the toolbar where we do not have a token if ($this->storage->getToken() === null) { - return; + return false; } /** @var User $user */ $user = $this->storage->getToken()->getUser(); - if (!($user instanceof User)) { - return; - } - - $this->setupUserPreferences($user); + return ($user instanceof User); } } diff --git a/src/Form/Type/UserPreferenceType.php b/src/Form/Type/UserPreferenceType.php index 6c97d8e4..f54746f6 100644 --- a/src/Form/Type/UserPreferenceType.php +++ b/src/Form/Type/UserPreferenceType.php @@ -13,6 +13,7 @@ namespace App\Form\Type; use App\Entity\UserPreference; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormEvent; @@ -45,9 +46,15 @@ class UserPreferenceType extends AbstractType return; } + $required = true; + if ($preference->getType() == CheckboxType::class) { + $required = false; + } + $event->getForm()->add('value', $preference->getType(), [ 'label' => 'label.' . $preference->getName(), - 'constraints' => $preference->getConstraints() + 'constraints' => $preference->getConstraints(), + 'required' => $required, ]); } } diff --git a/src/Repository/UserRepository.php b/src/Repository/UserRepository.php index 6923db1d..2c5dc258 100644 --- a/src/Repository/UserRepository.php +++ b/src/Repository/UserRepository.php @@ -40,17 +40,6 @@ class UserRepository extends AbstractRepository return $stats; } - /** - * Fetch a user by his username. - * - * @param $username - * @return null|User - */ - public function findByUsername($username) - { - return $this->findOneBy(['username' => $username]); - } - /** * @param UserQuery $query * @return \Pagerfanta\Pagerfanta diff --git a/templates/base.html.twig b/templates/base.html.twig index c2a40d75..db511c65 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -75,6 +75,7 @@ + {% block javascript_imports %}{% endblock %} {% endblock %} diff --git a/translations/messages.de.xliff b/translations/messages.de.xliff index 25065c8c..4b66b18b 100644 --- a/translations/messages.de.xliff +++ b/translations/messages.de.xliff @@ -377,6 +377,22 @@ profile.preferences Einstellungen + + label.theme.fixed_layout + Aktiviert das "statische Layout" (linke Navigationsleiste und Header bleiben beim Scrollen an ihrer Stelle) + + + label.theme.boxed_layout + Aktiviert das "Boxlayout" (gut für große Bildschirme, lässt sich aber nicht mit dem "statischen Layout" gemeinsam verwenden) + + + label.theme.collapsed_sidebar + Steuert den Status der linken Navigationsleiste (zugeklappt oder geöffnet) + + + label.theme.mini_sidebar + Aktiviert die minimierte Version der linken Navigationsleiste +