allow to configure default values for users (#919)
This commit is contained in:
@@ -283,6 +283,10 @@ kimai:
|
|||||||
# timezone: Europe/Berlin
|
# timezone: Europe/Berlin
|
||||||
# country: DE
|
# country: DE
|
||||||
# currency: EUR
|
# currency: EUR
|
||||||
|
# user:
|
||||||
|
# timezone: Europe/Berlin
|
||||||
|
# language: de
|
||||||
|
# theme: blue-light
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@@ -293,12 +297,3 @@ kimai:
|
|||||||
data_dir: '%kernel.project_dir%/var/data'
|
data_dir: '%kernel.project_dir%/var/data'
|
||||||
plugin_dir: '%kernel.project_dir%/var/plugins'
|
plugin_dir: '%kernel.project_dir%/var/plugins'
|
||||||
# --------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------
|
|
||||||
# LDAP
|
|
||||||
# Connect to your companies directory server, see https://www.kimai.org/documentation/ldap.html
|
|
||||||
# --------------------------------------------------------------------------------
|
|
||||||
# ldap:
|
|
||||||
# active: true
|
|
||||||
# --------------------------------------------------------------------------------
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class FormConfiguration implements SystemBundleConfiguration
|
|||||||
return 'defaults';
|
return 'defaults';
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCustomerDefaultTimezone(): string
|
public function getCustomerDefaultTimezone(): ?string
|
||||||
{
|
{
|
||||||
return $this->find('customer.timezone');
|
return $this->find('customer.timezone');
|
||||||
}
|
}
|
||||||
@@ -32,4 +32,19 @@ class FormConfiguration implements SystemBundleConfiguration
|
|||||||
{
|
{
|
||||||
return $this->find('customer.country');
|
return $this->find('customer.country');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUserDefaultTimezone(): ?string
|
||||||
|
{
|
||||||
|
return $this->find('user.timezone');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserDefaultTheme(): ?string
|
||||||
|
{
|
||||||
|
return $this->find('user.theme');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserDefaultLanguage(): string
|
||||||
|
{
|
||||||
|
return $this->find('user.language');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,10 +111,15 @@ class CustomerController extends AbstractController
|
|||||||
*/
|
*/
|
||||||
public function createAction(Request $request)
|
public function createAction(Request $request)
|
||||||
{
|
{
|
||||||
|
$timezone = date_default_timezone_get();
|
||||||
|
if (null !== $this->configuration->getCustomerDefaultTimezone()) {
|
||||||
|
$timezone = $this->configuration->getCustomerDefaultTimezone();
|
||||||
|
}
|
||||||
|
|
||||||
$customer = new Customer();
|
$customer = new Customer();
|
||||||
$customer->setCountry($this->configuration->getCustomerDefaultCountry());
|
$customer->setCountry($this->configuration->getCustomerDefaultCountry());
|
||||||
$customer->setCurrency($this->configuration->getCustomerDefaultCurrency());
|
$customer->setCurrency($this->configuration->getCustomerDefaultCurrency());
|
||||||
$customer->setTimezone($this->configuration->getCustomerDefaultTimezone());
|
$customer->setTimezone($timezone);
|
||||||
|
|
||||||
return $this->renderCustomerForm($customer, $request);
|
return $this->renderCustomerForm($customer, $request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ use App\Form\Model\Configuration;
|
|||||||
use App\Form\Model\SystemConfiguration as SystemConfigurationModel;
|
use App\Form\Model\SystemConfiguration as SystemConfigurationModel;
|
||||||
use App\Form\SystemConfigurationForm;
|
use App\Form\SystemConfigurationForm;
|
||||||
use App\Form\Type\EnhancedSelectboxType;
|
use App\Form\Type\EnhancedSelectboxType;
|
||||||
|
use App\Form\Type\LanguageType;
|
||||||
|
use App\Form\Type\SkinType;
|
||||||
use App\Form\Type\TrackingModeType;
|
use App\Form\Type\TrackingModeType;
|
||||||
use App\Repository\ConfigurationRepository;
|
use App\Repository\ConfigurationRepository;
|
||||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
|
||||||
@@ -171,7 +173,10 @@ class SystemConfigurationController extends AbstractController
|
|||||||
|
|
||||||
foreach ($event->getConfigurations() as $configs) {
|
foreach ($event->getConfigurations() as $configs) {
|
||||||
foreach ($configs->getConfiguration() as $config) {
|
foreach ($configs->getConfiguration() as $config) {
|
||||||
$config->setValue($this->configurations->find($config->getName()));
|
$configValue = $this->configurations->find($config->getName());
|
||||||
|
if (null !== $configValue) {
|
||||||
|
$config->setValue($configValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +221,8 @@ class SystemConfigurationController extends AbstractController
|
|||||||
(new Configuration())
|
(new Configuration())
|
||||||
->setName('defaults.customer.timezone')
|
->setName('defaults.customer.timezone')
|
||||||
->setLabel('timezone')
|
->setLabel('timezone')
|
||||||
->setType(TimezoneType::class),
|
->setType(TimezoneType::class)
|
||||||
|
->setValue(date_default_timezone_get()),
|
||||||
(new Configuration())
|
(new Configuration())
|
||||||
->setName('defaults.customer.country')
|
->setName('defaults.customer.country')
|
||||||
->setLabel('country')
|
->setLabel('country')
|
||||||
@@ -226,6 +232,23 @@ class SystemConfigurationController extends AbstractController
|
|||||||
->setLabel('currency')
|
->setLabel('currency')
|
||||||
->setType(CurrencyType::class),
|
->setType(CurrencyType::class),
|
||||||
]),
|
]),
|
||||||
|
(new SystemConfigurationModel())
|
||||||
|
->setSection(SystemConfigurationModel::SECTION_FORM_USER)
|
||||||
|
->setConfiguration([
|
||||||
|
(new Configuration())
|
||||||
|
->setName('defaults.user.timezone')
|
||||||
|
->setLabel('timezone')
|
||||||
|
->setType(TimezoneType::class)
|
||||||
|
->setValue(date_default_timezone_get()),
|
||||||
|
(new Configuration())
|
||||||
|
->setName('defaults.user.language')
|
||||||
|
->setLabel('language')
|
||||||
|
->setType(LanguageType::class),
|
||||||
|
(new Configuration())
|
||||||
|
->setName('defaults.user.theme')
|
||||||
|
->setLabel('skin')
|
||||||
|
->setType(SkinType::class),
|
||||||
|
]),
|
||||||
(new SystemConfigurationModel())
|
(new SystemConfigurationModel())
|
||||||
->setSection(SystemConfigurationModel::SECTION_THEME)
|
->setSection(SystemConfigurationModel::SECTION_THEME)
|
||||||
->setConfiguration([
|
->setConfiguration([
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace App\DependencyInjection;
|
namespace App\DependencyInjection;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
use App\Timesheet\Rounding\RoundingInterface;
|
use App\Timesheet\Rounding\RoundingInterface;
|
||||||
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
|
||||||
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
|
||||||
@@ -435,11 +436,20 @@ class Configuration implements ConfigurationInterface
|
|||||||
->arrayNode('customer')
|
->arrayNode('customer')
|
||||||
->addDefaultsIfNotSet()
|
->addDefaultsIfNotSet()
|
||||||
->children()
|
->children()
|
||||||
->scalarNode('timezone')->defaultValue('Europe/Berlin')->end()
|
->scalarNode('timezone')->defaultNull()->end()
|
||||||
->scalarNode('country')->defaultValue('DE')->end()
|
->scalarNode('country')->defaultValue('DE')->end()
|
||||||
->scalarNode('currency')->defaultValue('EUR')->end()
|
->scalarNode('currency')->defaultValue('EUR')->end()
|
||||||
->end()
|
->end()
|
||||||
->end()
|
->end()
|
||||||
|
->arrayNode('user')
|
||||||
|
->addDefaultsIfNotSet()
|
||||||
|
->children()
|
||||||
|
->scalarNode('timezone')->defaultNull()->end()
|
||||||
|
->scalarNode('language')->defaultValue(User::DEFAULT_LANGUAGE)->end()
|
||||||
|
->scalarNode('theme')->defaultNull()->end()
|
||||||
|
->end()
|
||||||
|
->end()
|
||||||
|
|
||||||
->end()
|
->end()
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
namespace App\EventSubscriber;
|
namespace App\EventSubscriber;
|
||||||
|
|
||||||
|
use App\Configuration\FormConfiguration;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Entity\UserPreference;
|
use App\Entity\UserPreference;
|
||||||
use App\Event\PrepareUserEvent;
|
use App\Event\PrepareUserEvent;
|
||||||
@@ -32,32 +33,27 @@ class UserPreferenceSubscriber implements EventSubscriberInterface
|
|||||||
* @var EventDispatcherInterface
|
* @var EventDispatcherInterface
|
||||||
*/
|
*/
|
||||||
protected $eventDispatcher;
|
protected $eventDispatcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var AuthorizationCheckerInterface
|
* @var AuthorizationCheckerInterface
|
||||||
*/
|
*/
|
||||||
protected $voter;
|
protected $voter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var TokenStorageInterface
|
* @var TokenStorageInterface
|
||||||
*/
|
*/
|
||||||
protected $storage;
|
protected $storage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param EventDispatcherInterface $dispatcher
|
* @var FormConfiguration
|
||||||
* @param TokenStorageInterface $storage
|
|
||||||
* @param AuthorizationCheckerInterface $voter
|
|
||||||
*/
|
*/
|
||||||
public function __construct(EventDispatcherInterface $dispatcher, TokenStorageInterface $storage, AuthorizationCheckerInterface $voter)
|
protected $formConfig;
|
||||||
|
|
||||||
|
public function __construct(EventDispatcherInterface $dispatcher, TokenStorageInterface $storage, AuthorizationCheckerInterface $voter, FormConfiguration $formConfig)
|
||||||
{
|
{
|
||||||
$this->eventDispatcher = $dispatcher;
|
$this->eventDispatcher = $dispatcher;
|
||||||
$this->storage = $storage;
|
$this->storage = $storage;
|
||||||
$this->voter = $voter;
|
$this->voter = $voter;
|
||||||
|
$this->formConfig = $formConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getSubscribedEvents(): array
|
public static function getSubscribedEvents(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
@@ -65,6 +61,26 @@ class UserPreferenceSubscriber implements EventSubscriberInterface
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getDefaultTheme(): ?string
|
||||||
|
{
|
||||||
|
return $this->formConfig->getUserDefaultTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDefaultLanguage(): string
|
||||||
|
{
|
||||||
|
return $this->formConfig->getUserDefaultLanguage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getDefaultTimezone(): string
|
||||||
|
{
|
||||||
|
$timezone = $this->formConfig->getUserDefaultTimezone();
|
||||||
|
if (null === $timezone) {
|
||||||
|
$timezone = date_default_timezone_get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $timezone;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param User $user
|
* @param User $user
|
||||||
* @return UserPreference[]
|
* @return UserPreference[]
|
||||||
@@ -87,16 +103,17 @@ class UserPreferenceSubscriber implements EventSubscriberInterface
|
|||||||
|
|
||||||
(new UserPreference())
|
(new UserPreference())
|
||||||
->setName(UserPreference::TIMEZONE)
|
->setName(UserPreference::TIMEZONE)
|
||||||
->setValue(date_default_timezone_get())
|
->setValue($this->getDefaultTimezone())
|
||||||
->setType(TimezoneType::class),
|
->setType(TimezoneType::class),
|
||||||
|
|
||||||
(new UserPreference())
|
(new UserPreference())
|
||||||
->setName(UserPreference::LOCALE)
|
->setName(UserPreference::LOCALE)
|
||||||
->setValue(User::DEFAULT_LANGUAGE)
|
->setValue($this->getDefaultLanguage())
|
||||||
->setType(LanguageType::class),
|
->setType(LanguageType::class),
|
||||||
|
|
||||||
(new UserPreference())
|
(new UserPreference())
|
||||||
->setName(UserPreference::SKIN)
|
->setName(UserPreference::SKIN)
|
||||||
|
->setValue($this->getDefaultTheme())
|
||||||
->setType(SkinType::class),
|
->setType(SkinType::class),
|
||||||
|
|
||||||
(new UserPreference())
|
(new UserPreference())
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class SystemConfiguration
|
|||||||
{
|
{
|
||||||
public const SECTION_TIMESHEET = 'timesheet';
|
public const SECTION_TIMESHEET = 'timesheet';
|
||||||
public const SECTION_FORM_CUSTOMER = 'form_customer';
|
public const SECTION_FORM_CUSTOMER = 'form_customer';
|
||||||
|
public const SECTION_FORM_USER = 'form_user';
|
||||||
public const SECTION_THEME = 'theme';
|
public const SECTION_THEME = 'theme';
|
||||||
public const SECTION_CALENDAR = 'calendar';
|
public const SECTION_CALENDAR = 'calendar';
|
||||||
|
|
||||||
|
|||||||
@@ -61,11 +61,12 @@ class CustomerControllerTest extends ControllerBaseTest
|
|||||||
$kernel = self::bootKernel();
|
$kernel = self::bootKernel();
|
||||||
$container = $kernel->getContainer();
|
$container = $kernel->getContainer();
|
||||||
$defaults = $container->getParameter('kimai.defaults')['customer'];
|
$defaults = $container->getParameter('kimai.defaults')['customer'];
|
||||||
|
$this->assertNull($defaults['timezone']);
|
||||||
|
|
||||||
$editForm = $client->getCrawler()->filter('form[name=customer_edit_form]')->form();
|
$editForm = $client->getCrawler()->filter('form[name=customer_edit_form]')->form();
|
||||||
$this->assertEquals($defaults['country'], $editForm->get('customer_edit_form[country]')->getValue());
|
$this->assertEquals($defaults['country'], $editForm->get('customer_edit_form[country]')->getValue());
|
||||||
$this->assertEquals($defaults['currency'], $editForm->get('customer_edit_form[currency]')->getValue());
|
$this->assertEquals($defaults['currency'], $editForm->get('customer_edit_form[currency]')->getValue());
|
||||||
$this->assertEquals($defaults['timezone'], $editForm->get('customer_edit_form[timezone]')->getValue());
|
$this->assertEquals(date_default_timezone_get(), $editForm->get('customer_edit_form[timezone]')->getValue());
|
||||||
|
|
||||||
$client->submit($form, [
|
$client->submit($form, [
|
||||||
'customer_edit_form' => [
|
'customer_edit_form' => [
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
|
|||||||
return [
|
return [
|
||||||
['form[name=system_configuration_form_timesheet]', $this->createUrl('/admin/system-config/update/timesheet')],
|
['form[name=system_configuration_form_timesheet]', $this->createUrl('/admin/system-config/update/timesheet')],
|
||||||
['form[name=system_configuration_form_form_customer]', $this->createUrl('/admin/system-config/update/form_customer')],
|
['form[name=system_configuration_form_form_customer]', $this->createUrl('/admin/system-config/update/form_customer')],
|
||||||
|
['form[name=system_configuration_form_form_user]', $this->createUrl('/admin/system-config/update/form_user')],
|
||||||
['form[name=system_configuration_form_theme]', $this->createUrl('/admin/system-config/update/theme')],
|
['form[name=system_configuration_form_theme]', $this->createUrl('/admin/system-config/update/theme')],
|
||||||
['form[name=system_configuration_form_calendar]', $this->createUrl('/admin/system-config/update/calendar')],
|
['form[name=system_configuration_form_calendar]', $this->createUrl('/admin/system-config/update/calendar')],
|
||||||
];
|
];
|
||||||
@@ -121,7 +122,7 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
|
|||||||
$this->assertAccessIsGranted($client, '/admin/system-config/');
|
$this->assertAccessIsGranted($client, '/admin/system-config/');
|
||||||
|
|
||||||
$configService = $client->getContainer()->get(SystemConfiguration::class);
|
$configService = $client->getContainer()->get(SystemConfiguration::class);
|
||||||
$this->assertEquals('Europe/Berlin', $configService->find('defaults.customer.timezone'));
|
$this->assertNull($configService->find('defaults.customer.timezone'));
|
||||||
$this->assertEquals('DE', $configService->find('defaults.customer.country'));
|
$this->assertEquals('DE', $configService->find('defaults.customer.country'));
|
||||||
$this->assertEquals('EUR', $configService->find('defaults.customer.currency'));
|
$this->assertEquals('EUR', $configService->find('defaults.customer.currency'));
|
||||||
|
|
||||||
@@ -147,6 +148,38 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
|
|||||||
$this->assertEquals('GBP', $configService->find('defaults.customer.currency'));
|
$this->assertEquals('GBP', $configService->find('defaults.customer.currency'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUpdateUserConfig()
|
||||||
|
{
|
||||||
|
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
|
||||||
|
$this->assertAccessIsGranted($client, '/admin/system-config/');
|
||||||
|
|
||||||
|
$configService = $client->getContainer()->get(SystemConfiguration::class);
|
||||||
|
$this->assertNull($configService->find('defaults.user.timezone'));
|
||||||
|
$this->assertNull($configService->find('defaults.user.theme'));
|
||||||
|
$this->assertEquals('en', $configService->find('defaults.user.language'));
|
||||||
|
|
||||||
|
$form = $client->getCrawler()->filter('form[name=system_configuration_form_form_user]')->form();
|
||||||
|
$client->submit($form, [
|
||||||
|
'system_configuration_form_form_user' => [
|
||||||
|
'configuration' => [
|
||||||
|
['name' => 'defaults.user.timezone', 'value' => 'Pacific/Tahiti'],
|
||||||
|
['name' => 'defaults.user.language', 'value' => 'ru'],
|
||||||
|
['name' => 'defaults.user.theme', 'value' => 'purple'],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertIsRedirect($client, $this->createUrl('/admin/system-config/'));
|
||||||
|
$client->followRedirect();
|
||||||
|
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||||
|
$this->assertHasFlashSaveSuccess($client);
|
||||||
|
|
||||||
|
$configService = $client->getContainer()->get(SystemConfiguration::class);
|
||||||
|
$this->assertEquals('Pacific/Tahiti', $configService->find('defaults.user.timezone'));
|
||||||
|
$this->assertEquals('purple', $configService->find('defaults.user.theme'));
|
||||||
|
$this->assertEquals('ru', $configService->find('defaults.user.language'));
|
||||||
|
}
|
||||||
|
|
||||||
public function testUpdateCustomerConfigValidation()
|
public function testUpdateCustomerConfigValidation()
|
||||||
{
|
{
|
||||||
$this->assertFormHasValidationError(
|
$this->assertFormHasValidationError(
|
||||||
|
|||||||
@@ -86,9 +86,14 @@ class AppExtensionTest extends TestCase
|
|||||||
],
|
],
|
||||||
'kimai.defaults' => [
|
'kimai.defaults' => [
|
||||||
'customer' => [
|
'customer' => [
|
||||||
'timezone' => 'Europe/Berlin',
|
'timezone' => null,
|
||||||
'country' => 'DE',
|
'country' => 'DE',
|
||||||
'currency' => 'EUR',
|
'currency' => 'EUR',
|
||||||
|
],
|
||||||
|
'user' => [
|
||||||
|
'timezone' => null,
|
||||||
|
'language' => 'en',
|
||||||
|
'theme' => null,
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
<source>form_customer</source>
|
<source>form_customer</source>
|
||||||
<target>Kunden anlegen - Standard Werte</target>
|
<target>Kunden anlegen - Standard Werte</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="form_user">
|
||||||
|
<source>form_user</source>
|
||||||
|
<target>Benutzer - Standard Werte</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="theme">
|
<trans-unit id="theme">
|
||||||
<source>theme</source>
|
<source>theme</source>
|
||||||
<target>Darstellung</target>
|
<target>Darstellung</target>
|
||||||
|
|||||||
@@ -18,6 +18,10 @@
|
|||||||
<source>form_customer</source>
|
<source>form_customer</source>
|
||||||
<target>Create customer - default values</target>
|
<target>Create customer - default values</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="form_user">
|
||||||
|
<source>form_user</source>
|
||||||
|
<target>User - default values</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="theme">
|
<trans-unit id="theme">
|
||||||
<source>theme</source>
|
<source>theme</source>
|
||||||
<target>Theme</target>
|
<target>Theme</target>
|
||||||
|
|||||||
Reference in New Issue
Block a user