diff --git a/config/services.yaml b/config/services.yaml index 15b91c8f..09d38b05 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -56,10 +56,6 @@ services: arguments: $settings: '%kimai.config%' - App\Configuration\ThemeConfiguration: - arguments: - $settings: '%kimai.theme%' - App\Utils\MPdfConverter: arguments: ['%kernel.cache_dir%'] diff --git a/src/Configuration/MailConfiguration.php b/src/Configuration/MailConfiguration.php index fd186fc4..32ae2b4d 100644 --- a/src/Configuration/MailConfiguration.php +++ b/src/Configuration/MailConfiguration.php @@ -9,7 +9,7 @@ namespace App\Configuration; -class MailConfiguration +final class MailConfiguration { /** * @var string diff --git a/src/Configuration/StringAccessibleConfigTrait.php b/src/Configuration/StringAccessibleConfigTrait.php index 217298b2..6852bf63 100644 --- a/src/Configuration/StringAccessibleConfigTrait.php +++ b/src/Configuration/StringAccessibleConfigTrait.php @@ -11,6 +11,9 @@ namespace App\Configuration; use App\Entity\Configuration; +/** + * @internal do NOT use this trait, but access your configs via SystemConfiguration + */ trait StringAccessibleConfigTrait { /** diff --git a/src/Configuration/SystemConfiguration.php b/src/Configuration/SystemConfiguration.php index a8f26686..647ac758 100644 --- a/src/Configuration/SystemConfiguration.php +++ b/src/Configuration/SystemConfiguration.php @@ -376,4 +376,21 @@ class SystemConfiguration implements SystemBundleConfiguration return $this->default('theme.color_choices'); } + + // ========== Branding configurations ========== + + public function getBrandingTitle(): ?string + { + return $this->find('theme.branding.title'); + } + + public function getBrandingCompany(): ?string + { + return $this->find('theme.branding.company'); + } + + public function isAllowTagCreation(): bool + { + return (bool) $this->find('theme.tags_create'); + } } diff --git a/src/Configuration/ThemeConfiguration.php b/src/Configuration/ThemeConfiguration.php index f7ff7d41..cc64c2b2 100644 --- a/src/Configuration/ThemeConfiguration.php +++ b/src/Configuration/ThemeConfiguration.php @@ -10,43 +10,66 @@ namespace App\Configuration; /** - * @internal will be deprecated soon, use SystemConfiguration instead + * @internal might be deprecated in the future, use SystemConfiguration instead */ -class ThemeConfiguration implements SystemBundleConfiguration, \ArrayAccess +final class ThemeConfiguration implements \ArrayAccess { - use StringAccessibleConfigTrait; + private $systemConfiguration; - public function getPrefix(): string + public function __construct(SystemConfiguration $systemConfiguration) { - return 'theme'; - } - - public function isAutoReloadDatatable(): bool - { - @trigger_error('The configuration auto_reload_datatable is deprecated and was removed with 1.4', E_USER_DEPRECATED); - - return false; - } - - public function isAllowTagCreation(): bool - { - return (bool) $this->find('tags_create'); + $this->systemConfiguration = $systemConfiguration; } /** - * Currently unused, as JS selects are always activated. - * @deprecated since 1.7 will be removed with 2.0 + * @return bool */ - public function getSelectPicker(): string + public function offsetExists($offset) { - @trigger_error('getSelectPicker() is deprecated and will be removed with 2.0', E_USER_DEPRECATED); - - return (string) $this->find('select_type'); + return $this->systemConfiguration->has('theme.' . $offset); } + /** + * @return mixed + */ + public function offsetGet($offset) + { + return $this->systemConfiguration->find('theme.' . $offset); + } + + /** + * @param mixed $offset + * @param mixed $value + * @throws \BadMethodCallException + */ + public function offsetSet($offset, $value) + { + throw new \BadMethodCallException('ThemeConfiguration does not support offsetSet()'); + } + + /** + * @param mixed $offset + * @throws \BadMethodCallException + */ + public function offsetUnset($offset) + { + throw new \BadMethodCallException('ThemeConfiguration does not support offsetUnset()'); + } + + /** + * @deprecated since 1.15 + */ + public function isAllowTagCreation(): bool + { + return (bool) $this->offsetGet('tags_create'); + } + + /** + * @deprecated since 1.15 + */ public function getTitle(): ?string { - $title = $this->find('branding.title'); + $title = $this->offsetGet('branding.title'); if (null === $title) { return null; } diff --git a/src/DependencyInjection/AppExtension.php b/src/DependencyInjection/AppExtension.php index ad93d694..c1cd5fec 100644 --- a/src/DependencyInjection/AppExtension.php +++ b/src/DependencyInjection/AppExtension.php @@ -69,7 +69,7 @@ class AppExtension extends Extension $container->setParameter('kimai.defaults', $config['defaults']); // @deprecated since 1.13 $this->createPermissionParameter($config['permissions'], $container); - $this->createThemeParameter($config['theme'], $container); + $container->setParameter('kimai.theme', $config['theme']); // @deprecated since 1.15 $container->setParameter('kimai.timesheet', $config['timesheet']); // @deprecated since 1.13 $container->setParameter('kimai.timesheet.rates', $config['timesheet']['rates']); $container->setParameter('kimai.timesheet.rounding', $config['timesheet']['rounding']); @@ -211,17 +211,6 @@ class AppExtension extends Extension return $result; } - /** - * @param array $config - * @param ContainerBuilder $container - */ - protected function createThemeParameter(array $config, ContainerBuilder $container) - { - $container->setParameter('kimai.theme', $config); - $container->setParameter('kimai.theme.select_type', $config['select_type']); - $container->setParameter('kimai.theme.show_about', $config['show_about']); - } - /** * @return string */ diff --git a/src/Form/Type/TagsType.php b/src/Form/Type/TagsType.php index a738c472..bd0a70a9 100644 --- a/src/Form/Type/TagsType.php +++ b/src/Form/Type/TagsType.php @@ -9,17 +9,14 @@ namespace App\Form\Type; -use App\Configuration\ThemeConfiguration; +use App\Configuration\SystemConfiguration; use Symfony\Component\Form\AbstractType; -class TagsType extends AbstractType +final class TagsType extends AbstractType { - /** - * @var ThemeConfiguration - */ private $configuration; - public function __construct(ThemeConfiguration $configuration) + public function __construct(SystemConfiguration $configuration) { $this->configuration = $configuration; } diff --git a/src/Twig/ConfigExtension.php b/src/Twig/ConfigExtension.php deleted file mode 100644 index 1536fc75..00000000 --- a/src/Twig/ConfigExtension.php +++ /dev/null @@ -1,62 +0,0 @@ -configuration = $configuration; - } - - /** - * {@inheritdoc} - */ - public function getFunctions() - { - return [ - new TwigFunction('theme_config', [$this, 'getThemeConfig']), - ]; - } - - /** - * @param string $name - * @return mixed - */ - public function getThemeConfig(string $name) - { - @trigger_error('The twig function "theme_config" was deprecated with 1.15, replace it with the global "kimai_config" variable.', E_USER_DEPRECATED); - - switch ($name) { - case 'auto_reload_datatable': - @trigger_error('The configuration auto_reload_datatable is deprecated and was removed with 1.4', E_USER_DEPRECATED); - - return false; - - case 'soft_limit': - return $this->configuration->getTimesheetActiveEntriesHardLimit(); - - default: - $name = 'theme.' . $name; - break; - } - - return $this->configuration->find($name); - } -} diff --git a/src/Twig/Runtime/ThemeExtension.php b/src/Twig/Runtime/ThemeExtension.php index e78a16e6..d562463f 100644 --- a/src/Twig/Runtime/ThemeExtension.php +++ b/src/Twig/Runtime/ThemeExtension.php @@ -9,25 +9,29 @@ namespace App\Twig\Runtime; +use App\Configuration\SystemConfiguration; +use App\Constants; use App\Entity\User; use App\Event\PageActionsEvent; use App\Event\ThemeEvent; use App\Event\ThemeJavascriptTranslationsEvent; use Symfony\Bridge\Twig\AppVariable; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; use Twig\Extension\RuntimeExtensionInterface; final class ThemeExtension implements RuntimeExtensionInterface { - /** - * @var EventDispatcherInterface - */ private $eventDispatcher; + private $translator; + private $configuration; - public function __construct(EventDispatcherInterface $dispatcher) + public function __construct(EventDispatcherInterface $dispatcher, TranslatorInterface $translator, SystemConfiguration $configuration) { $this->eventDispatcher = $dispatcher; + $this->translator = $translator; + $this->configuration = $configuration; } /** @@ -95,4 +99,40 @@ final class ThemeExtension implements RuntimeExtensionInterface return $class; } + + public function generateTitle(?string $prefix = null, string $delimiter = ' – '): string + { + $title = $this->configuration->getBrandingTitle(); + if (null === $title || \strlen($title) === 0) { + $title = Constants::SOFTWARE; + } + + return ($prefix ?? '') . $title . $delimiter . $this->translator->trans('time_tracking', [], 'messages'); + } + + /** + * @param string $name + * @return mixed + * @deprecated since 1.15 + */ + public function getThemeConfig(string $name) + { + @trigger_error('The twig function "theme_config" was deprecated with 1.15, replace it with the global "kimai_config" variable.', E_USER_DEPRECATED); + + switch ($name) { + case 'auto_reload_datatable': + @trigger_error('The configuration auto_reload_datatable is deprecated and was removed with 1.4', E_USER_DEPRECATED); + + return false; + + case 'soft_limit': + return $this->configuration->getTimesheetActiveEntriesHardLimit(); + + default: + $name = 'theme.' . $name; + break; + } + + return $this->configuration->find($name); + } } diff --git a/src/Twig/RuntimeExtensions.php b/src/Twig/RuntimeExtensions.php index 7f8b8a88..cc5db7e2 100644 --- a/src/Twig/RuntimeExtensions.php +++ b/src/Twig/RuntimeExtensions.php @@ -28,8 +28,10 @@ class RuntimeExtensions extends AbstractExtension return [ new TwigFunction('trigger', [ThemeExtension::class, 'trigger'], ['needs_environment' => true]), new TwigFunction('actions', [ThemeExtension::class, 'actions']), + new TwigFunction('get_title', [ThemeExtension::class, 'generateTitle']), new TwigFunction('progressbar_color', [ThemeExtension::class, 'getProgressbarClass']), new TwigFunction('javascript_translations', [ThemeExtension::class, 'getJavascriptTranslations']), + new TwigFunction('theme_config', [ThemeExtension::class, 'getThemeConfig']), new TwigFunction('active_timesheets', [TimesheetExtension::class, 'activeEntries']), new TwigFunction('encore_entry_css_source', [EncoreExtension::class, 'getEncoreEntryCssSource']), new TwigFunction('render_widget', [WidgetExtension::class, 'renderWidget'], ['is_safe' => ['html']]), diff --git a/src/Twig/TitleExtension.php b/src/Twig/TitleExtension.php deleted file mode 100644 index a74126c7..00000000 --- a/src/Twig/TitleExtension.php +++ /dev/null @@ -1,50 +0,0 @@ -translator = $translator; - $this->configuration = $configuration; - } - - /** - * {@inheritdoc} - */ - public function getFunctions() - { - return [ - new TwigFunction('get_title', [$this, 'generateTitle']), - ]; - } - - public function generateTitle(?string $prefix = null, string $delimiter = ' – '): string - { - $title = $this->configuration->getTitle() ?? 'Kimai'; - - return ($prefix ?? '') . ($title) . $delimiter . $this->translator->trans('time_tracking', [], 'messages'); - } -} diff --git a/tests/Configuration/SystemConfigurationTest.php b/tests/Configuration/SystemConfigurationTest.php index cb033fad..f306c5be 100644 --- a/tests/Configuration/SystemConfigurationTest.php +++ b/tests/Configuration/SystemConfigurationTest.php @@ -98,7 +98,15 @@ class SystemConfigurationTest extends TestCase ], 'theme' => [ 'color_choices' => 'Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,#ffffff,,|#000000', - 'colors_limited' => true + 'colors_limited' => true, + 'tags_create' => true, + 'branding' => [ + 'logo' => null, + 'mini' => null, + 'company' => 'Acme Corp.', + 'title' => 'Fantastic Time-Tracking', + 'translation' => null, + ], ], ]; } @@ -137,6 +145,9 @@ class SystemConfigurationTest extends TestCase $this->assertTrue($sut->find('theme.colors_limited')); $this->assertTrue($sut->isThemeColorsLimited()); $this->assertEquals('Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,#ffffff,,|#000000', $sut->getThemeColorChoices()); + $this->assertEquals('Acme Corp.', $sut->getBrandingCompany()); + $this->assertEquals('Fantastic Time-Tracking', $sut->getBrandingTitle()); + $this->assertTrue($sut->isAllowTagCreation()); } public function testDefaultWithLoader() diff --git a/tests/Configuration/ThemeConfigurationTest.php b/tests/Configuration/ThemeConfigurationTest.php index 52c18caa..49a14347 100644 --- a/tests/Configuration/ThemeConfigurationTest.php +++ b/tests/Configuration/ThemeConfigurationTest.php @@ -9,20 +9,22 @@ namespace App\Tests\Configuration; +use App\Configuration\SystemConfiguration; use App\Configuration\ThemeConfiguration; use PHPUnit\Framework\TestCase; /** * @covers \App\Configuration\ThemeConfiguration - * @covers \App\Configuration\StringAccessibleConfigTrait + * @covers \App\Configuration\SystemConfiguration */ class ThemeConfigurationTest extends TestCase { protected function getSut(array $settings, array $loaderSettings = []): ThemeConfiguration { $loader = new TestConfigLoader($loaderSettings); + $config = new SystemConfiguration($loader, ['theme' => $settings]); - return new ThemeConfiguration($loader, $settings); + return new ThemeConfiguration($config); } /** @@ -51,26 +53,13 @@ class ThemeConfigurationTest extends TestCase ]; } - public function testPrefix() - { - $sut = $this->getSut($this->getDefaultSettings(), []); - $this->assertEquals('theme', $sut->getPrefix()); - } - - public function testConfigs() - { - $sut = $this->getSut($this->getDefaultSettings(), []); - $this->assertTrue($sut->isAllowTagCreation()); - $this->assertNull($sut->getTitle()); - } - /** * @group legacy */ public function testDeprecations() { $sut = $this->getSut($this->getDefaultSettings(), []); - $this->assertEquals('', $sut->getSelectPicker()); - $this->assertFalse($sut->isAutoReloadDatatable()); + $this->assertTrue($sut->isAllowTagCreation()); + $this->assertNull($sut->getTitle()); } } diff --git a/tests/Controller/CalendarControllerTest.php b/tests/Controller/CalendarControllerTest.php index 9e97debf..4ab4017f 100644 --- a/tests/Controller/CalendarControllerTest.php +++ b/tests/Controller/CalendarControllerTest.php @@ -48,7 +48,7 @@ class CalendarControllerTest extends ControllerBaseTest $client = $this->getClientForAuthenticatedUser(); static::$kernel->getContainer()->set(SystemConfiguration::class, $config); $this->request($client, '/calendar/'); - $this->assertTrue($client->getResponse()->isSuccessful()); + $this->assertSuccessResponse($client); $crawler = $client->getCrawler(); $calendar = $crawler->filter('div#timesheet_calendar'); @@ -61,9 +61,35 @@ class CalendarControllerTest extends ControllerBaseTest $this->assertStringContainsString("name: 'holidays_en'", $content); } - protected function getDefaultSettings() + protected function getDefaultSettings(): array { return [ + 'theme' => [ + 'active_warning' => 3, + 'box_color' => 'blue', + 'select_type' => 'selectpicker', + 'show_about' => true, + 'chart' => [ + 'background_color' => '#3c8dbc', + 'border_color' => '#3b8bba', + 'grid_color' => 'rgba(0,0,0,.05)', + 'height' => '200', + ], + 'branding' => [ + 'logo' => null, + 'mini' => null, + 'company' => null, + 'title' => null, + 'translation' => null, + ], + 'autocomplete_chars' => 3, + 'tags_create' => true, + 'calendar' => [ + 'background_color' => '#d2d6de' + ], + 'colors_limited' => true, + 'color_choices' => 'Silver|#c0c0c0,Gray|#808080,Black|#000000,Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,Gold|#ffd700,Yellow|#ffff00,Peach|#ffdab9,Khaki|#f0e68c,Olive|#808000,Lime|#00ff00,Jelly|#9acd32,Green|#008000,Teal|#008080,Aqua|#00ffff,LightBlue|#add8e6,DeepSky|#00bfff,Dodger|#1e90ff,Blue|#0000ff,Navy|#000080,Purple|#800080,Fuchsia|#ff00ff,Violet|#ee82ee,Rose|#ffe4e1,Lavender|#E6E6FA' + ], 'defaults' => [ 'user' => [ 'language' => 'en' diff --git a/tests/Controller/ControllerBaseTest.php b/tests/Controller/ControllerBaseTest.php index 2e62a6be..ce92dfeb 100644 --- a/tests/Controller/ControllerBaseTest.php +++ b/tests/Controller/ControllerBaseTest.php @@ -18,6 +18,7 @@ use App\Tests\KernelTestTrait; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Test\Constraint as ResponseConstraint; use Symfony\Component\HttpKernel\HttpKernelBrowser; /** @@ -161,6 +162,12 @@ abstract class ControllerBaseTest extends WebTestCase ); } + protected function assertSuccessResponse(HttpKernelBrowser $client, string $message = '') + { + $response = $client->getResponse(); + self::assertThat($response, new ResponseConstraint\ResponseIsSuccessful(), 'Response is not successful, got code: ' . $response->getStatusCode()); + } + /** * @param string $url * @param string $method @@ -381,26 +388,26 @@ abstract class ControllerBaseTest extends WebTestCase * @param HttpKernelBrowser $client * @param string $url */ - protected function assertIsRedirect(HttpKernelBrowser $client, $url = null, $endsWith = true) + protected function assertIsRedirect(HttpKernelBrowser $client, $url = null) { - self::assertTrue($client->getResponse()->isRedirect(), 'Response is not a redirect'); + self::assertResponseRedirects(); + if (null === $url) { return; } + $this->assertRedirectUrl($client, $url); + } + + protected function assertRedirectUrl(HttpKernelBrowser $client, $url = null, $endsWith = true) + { self::assertTrue($client->getResponse()->headers->has('Location'), 'Could not find "Location" header'); + $location = $client->getResponse()->headers->get('Location'); + if ($endsWith) { - self::assertStringEndsWith( - $url, - $client->getResponse()->headers->get('Location'), - 'Redirect URL does not match' - ); + self::assertStringEndsWith($url, $location, 'Redirect URL does not match'); } else { - self::assertStringContainsString( - $url, - $client->getResponse()->headers->get('Location'), - 'Redirect URL does not match' - ); + self::assertStringContainsString($url, $location, 'Redirect URL does not match'); } } diff --git a/tests/Controller/InvoiceControllerTest.php b/tests/Controller/InvoiceControllerTest.php index c9575a07..8c252e4d 100644 --- a/tests/Controller/InvoiceControllerTest.php +++ b/tests/Controller/InvoiceControllerTest.php @@ -192,7 +192,8 @@ class InvoiceControllerTest extends ControllerBaseTest $action = '/invoice/save-invoice/1/' . $template->getId() . '?' . http_build_query($urlParams); $this->request($client, $action); - $this->assertIsRedirect($client, '/invoice/show?id=', false); + $this->assertIsRedirect($client); + $this->assertRedirectUrl($client, '/invoice/show?id=', false); $client->followRedirect(); $this->assertDataTableRowCount($client, 'datatable_invoices', 1); diff --git a/tests/DependencyInjection/AppExtensionTest.php b/tests/DependencyInjection/AppExtensionTest.php index 12c9c0ff..54d03448 100644 --- a/tests/DependencyInjection/AppExtensionTest.php +++ b/tests/DependencyInjection/AppExtensionTest.php @@ -177,8 +177,6 @@ class AppExtensionTest extends TestCase 'colors_limited' => true, 'color_choices' => 'Silver|#c0c0c0,Gray|#808080,Black|#000000,Maroon|#800000,Brown|#a52a2a,Red|#ff0000,Orange|#ffa500,Gold|#ffd700,Yellow|#ffff00,Peach|#ffdab9,Khaki|#f0e68c,Olive|#808000,Lime|#00ff00,Jelly|#9acd32,Green|#008000,Teal|#008080,Aqua|#00ffff,LightBlue|#add8e6,DeepSky|#00bfff,Dodger|#1e90ff,Blue|#0000ff,Navy|#000080,Purple|#800080,Fuchsia|#ff00ff,Violet|#ee82ee,Rose|#ffe4e1,Lavender|#E6E6FA' ], - 'kimai.theme.select_type' => 'selectpicker', - 'kimai.theme.show_about' => true, 'kimai.timesheet' => [ 'mode' => 'default', 'markdown_content' => false, diff --git a/tests/Mail/KimaiMailerTest.php b/tests/Mail/KimaiMailerTest.php index 53541601..fdbbf26d 100644 --- a/tests/Mail/KimaiMailerTest.php +++ b/tests/Mail/KimaiMailerTest.php @@ -24,8 +24,7 @@ class KimaiMailerTest extends TestCase { public function getSut(): KimaiMailer { - $config = $this->createMock(MailConfiguration::class); - $config->expects($this->any())->method('getFromAddress')->willReturn('zippel@example.com'); + $config = new MailConfiguration('zippel@example.com'); $mailer = $this->createMock(MailerInterface::class); diff --git a/tests/Twig/ConfigExtensionTest.php b/tests/Twig/ConfigExtensionTest.php deleted file mode 100644 index c25f7395..00000000 --- a/tests/Twig/ConfigExtensionTest.php +++ /dev/null @@ -1,82 +0,0 @@ - $settings]); - - return new ConfigExtension($config); - } - - public function testGetFunctions() - { - $functions = ['theme_config']; - $sut = $this->getSut([], []); - $twigFunctions = $sut->getFunctions(); - self::assertCount(\count($functions), $twigFunctions); - $i = 0; - /** @var TwigFunction $filter */ - foreach ($twigFunctions as $filter) { - self::assertInstanceOf(TwigFunction::class, $filter); - self::assertEquals($functions[$i++], $filter->getName()); - } - } - - private function getDefaultSettings(): array - { - return [ - 'active_warning' => 3, - 'box_color' => 'green', - 'select_type' => null, - 'show_about' => true, - 'chart' => [ - 'background_color' => 'rgba(0,115,183,0.7)', - 'border_color' => '#3b8bba', - 'grid_color' => 'rgba(0,0,0,.05)', - 'height' => '200' - ], - 'branding' => [ - 'logo' => null, - 'mini' => null, - 'company' => null, - 'title' => null, - ], - ]; - } - - public function testPrefix() - { - $sut = $this->getSut($this->getDefaultSettings(), []); - self::assertEquals(3, $sut->getThemeConfig('active_warning')); - self::assertEquals('green', $sut->getThemeConfig('box_color')); - } - - /** - * @group legacy - */ - public function testDeprecation() - { - $sut = $this->getSut($this->getDefaultSettings(), []); - self::assertFalse($sut->getThemeConfig('auto_reload_datatable')); - } -} diff --git a/tests/Twig/Runtime/ThemeEventExtensionTest.php b/tests/Twig/Runtime/ThemeEventExtensionTest.php index 3ae9496c..ff3d2d45 100644 --- a/tests/Twig/Runtime/ThemeEventExtensionTest.php +++ b/tests/Twig/Runtime/ThemeEventExtensionTest.php @@ -9,15 +9,18 @@ namespace App\Tests\Twig\Runtime; +use App\Configuration\SystemConfiguration; +use App\Entity\Configuration; use App\Entity\User; use App\Event\ThemeEvent; -use App\Tests\Mocks\Security\CurrentUserFactory; +use App\Tests\Configuration\TestConfigLoader; use App\Twig\Runtime\ThemeExtension; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Twig\AppVariable; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Contracts\Translation\TranslatorInterface; use Twig\Environment; use Twig\Loader\FilesystemLoader; @@ -26,15 +29,46 @@ use Twig\Loader\FilesystemLoader; */ class ThemeEventExtensionTest extends TestCase { - protected function getSut(bool $hasListener = true): ThemeExtension + private function getDefaultSettings(): array + { + return [ + 'theme' => [ + 'active_warning' => 3, + 'box_color' => 'green', + 'select_type' => null, + 'show_about' => true, + 'chart' => [ + 'background_color' => 'rgba(0,115,183,0.7)', + 'border_color' => '#3b8bba', + 'grid_color' => 'rgba(0,0,0,.05)', + 'height' => '200' + ], + 'branding' => [ + 'logo' => null, + 'mini' => null, + 'company' => null, + 'title' => null, + ], + ], + ]; + } + + protected function getSut(bool $hasListener = true, string $title = null): ThemeExtension { $dispatcher = $this->createMock(EventDispatcherInterface::class); $dispatcher->method('hasListeners')->willReturn($hasListener); $dispatcher->expects($hasListener ? $this->once() : $this->never())->method('dispatch'); - $user = (new CurrentUserFactory($this))->create(new User()); + $translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); + $translator->method('trans')->willReturn('foo'); - return new ThemeExtension($dispatcher); + $configs = [ + (new Configuration())->setName('theme.branding.title')->setValue($title) + ]; + $loader = new TestConfigLoader($configs); + $configuration = new SystemConfiguration($loader, $this->getDefaultSettings()); + + return new ThemeExtension($dispatcher, $translator, $configuration); } protected function getEnvironment(): Environment @@ -119,4 +153,33 @@ class ThemeEventExtensionTest extends TestCase $sut = $this->getSut(false); self::assertEquals($expected, $sut->getProgressbarClass($percent, $reverseColors)); } + + public function testGetTitle() + { + $sut = $this->getSut(false); + $this->assertEquals('Kimai – foo', $sut->generateTitle()); + $this->assertEquals('sdfsdf | Kimai – foo', $sut->generateTitle('sdfsdf | ')); + $this->assertEquals('Kimai ... foo', $sut->generateTitle('', ' ... ')); + $this->assertEquals('Kimai | foo', $sut->generateTitle(null, ' | ')); + } + + public function testGetBrandedTitle() + { + $sut = $this->getSut(false, 'MyCompany'); + $this->assertEquals('MyCompany – foo', $sut->generateTitle()); + $this->assertEquals('sdfsdf | MyCompany – foo', $sut->generateTitle('sdfsdf | ')); + $this->assertEquals('MyCompany ... foo', $sut->generateTitle('', ' ... ')); + $this->assertEquals('MyCompany | foo', $sut->generateTitle(null, ' | ')); + } + + /** + * @group legacy + */ + public function testThemeConfig() + { + $sut = $this->getSut(false); + self::assertEquals(3, $sut->getThemeConfig('active_warning')); + self::assertEquals('green', $sut->getThemeConfig('box_color')); + self::assertFalse($sut->getThemeConfig('auto_reload_datatable')); + } } diff --git a/tests/Twig/RuntimeExtensionsTest.php b/tests/Twig/RuntimeExtensionsTest.php index 1e622d6a..4c481552 100644 --- a/tests/Twig/RuntimeExtensionsTest.php +++ b/tests/Twig/RuntimeExtensionsTest.php @@ -40,8 +40,10 @@ class RuntimeExtensionsTest extends TestCase $expected = [ 'trigger', 'actions', + 'get_title', 'progressbar_color', 'javascript_translations', + 'theme_config', 'active_timesheets', 'encore_entry_css_source', 'render_widget', diff --git a/tests/Twig/TitleExtensionTest.php b/tests/Twig/TitleExtensionTest.php deleted file mode 100644 index c6261b4c..00000000 --- a/tests/Twig/TitleExtensionTest.php +++ /dev/null @@ -1,72 +0,0 @@ -getMockBuilder(TranslatorInterface::class)->getMock(); - $translator->method('trans')->willReturn('foo'); - - $configs = [ - (new Configuration())->setName('theme.branding.title')->setValue($title) - ]; - - $loader = new TestConfigLoader($configs); - - $configuration = new ThemeConfiguration($loader, ['branding' => ['title' => null]]); - - return new TitleExtension($translator, $configuration); - } - - public function testGetFunctions() - { - $functions = ['get_title']; - $sut = $this->getSut(); - $twigFunctions = $sut->getFunctions(); - $this->assertCount(\count($functions), $twigFunctions); - $i = 0; - /** @var TwigFunction $function */ - foreach ($twigFunctions as $function) { - $this->assertInstanceOf(TwigFunction::class, $function); - $this->assertEquals($functions[$i++], $function->getName()); - } - } - - public function testGetTitle() - { - $sut = $this->getSut(); - $this->assertEquals('Kimai – foo', $sut->generateTitle()); - $this->assertEquals('sdfsdf | Kimai – foo', $sut->generateTitle('sdfsdf | ')); - $this->assertEquals('Kimai ... foo', $sut->generateTitle('', ' ... ')); - $this->assertEquals('Kimai | foo', $sut->generateTitle(null, ' | ')); - } - - public function testGetBrandedTitle() - { - $sut = $this->getSut('MyCompany'); - $this->assertEquals('MyCompany – foo', $sut->generateTitle()); - $this->assertEquals('sdfsdf | MyCompany – foo', $sut->generateTitle('sdfsdf | ')); - $this->assertEquals('MyCompany ... foo', $sut->generateTitle('', ' ... ')); - $this->assertEquals('MyCompany | foo', $sut->generateTitle(null, ' | ')); - } -}