Release 2.0.19 (#4022)

* prevent invoices with exceeding filename
* fixed invalid LDAP log level
* support locale switching in action events
This commit is contained in:
Kevin Papst
2023-05-12 14:45:51 +02:00
committed by GitHub
parent 1099e76244
commit 4b2a3669e6
12 changed files with 77 additions and 61 deletions

View File

@@ -25,8 +25,10 @@ and so much more.
There are two versions of Kimai existing:
- [Version 1](https://github.com/kimai/kimai/tree/1.x) — compatible with PHP 7.4, which is in maintenance mode since 2023
- [Version 2](https://github.com/kimai/kimai) — stable and "almost released" (waiting for some major plugins, which are not yet migrated)
- [Version 2](https://github.com/kimai/kimai) — the current stable release (PHP 8.1 only)
- [Version 1](https://github.com/kimai/kimai/tree/1.x) — the "old" version, in maintenance mode since Jan. 2023 (PHP 7.4, PHP 8.1)
If you start fresh, do **not** use Version 1, it won't receive any more updates.
### Links
@@ -72,7 +74,7 @@ It is open for changes and input from the community, your [ideas and questions](
Release versions will be created on a regular basis, every couple of weeks latest.
Every code change, whether it's a new feature or a bugfix, will be done on the `main` branch.
For the time being and until 2.0 is widely adopted, the [1.x branch](https://github.com/kimai/kimai/tree/1.x) will receive bug fixes.
Until 2.0 is widely adopted, the [1.x branch](https://github.com/kimai/kimai/tree/1.x) will receive (critical) bug and security fixes.
## Contributing

View File

@@ -2266,11 +2266,6 @@ parameters:
count: 9
path: src/Event/PageActionsEvent.php
-
message: "#^Property App\\\\Event\\\\PageActionsEvent\\:\\:\\$divider has no type specified\\.$#"
count: 1
path: src/Event/PageActionsEvent.php
-
message: "#^Property App\\\\Event\\\\PermissionSectionsEvent\\:\\:\\$sections type has no value type specified in iterable type array\\.$#"
count: 1
@@ -4531,11 +4526,6 @@ parameters:
count: 1
path: src/Invoice/Renderer/PdfRenderer.php
-
message: "#^Binary operation \"\\.\" between string and non\\-empty\\-list\\<string\\>\\|string results in an error\\.$#"
count: 2
path: src/Invoice/ServiceInvoice.php
-
message: "#^Cannot call method getCustomer\\(\\) on App\\\\Entity\\\\Project\\|null\\.$#"
count: 1
@@ -4581,11 +4571,6 @@ parameters:
count: 1
path: src/Invoice/ServiceInvoice.php
-
message: "#^Method App\\\\Invoice\\\\ServiceInvoice\\:\\:saveGeneratedInvoice\\(\\) should return string but returns array\\<int, string\\>\\|string\\.$#"
count: 1
path: src/Invoice/ServiceInvoice.php
-
message: "#^Parameter \\#1 \\$key of function array_key_exists expects int\\|string, int\\|null given\\.$#"
count: 1
@@ -4601,11 +4586,6 @@ parameters:
count: 1
path: src/Invoice/ServiceInvoice.php
-
message: "#^Parameter \\#2 \\$name of method Symfony\\\\Component\\\\HttpFoundation\\\\File\\\\File\\:\\:move\\(\\) expects string\\|null, array\\<int, string\\>\\|string given\\.$#"
count: 1
path: src/Invoice/ServiceInvoice.php
-
message: "#^Parameter \\#2 \\$string of function explode expects string, string\\|null given\\.$#"
count: 2
@@ -4621,11 +4601,6 @@ parameters:
count: 1
path: src/Invoice/ServiceInvoice.php
-
message: "#^Parameter \\#2 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, array\\<int, string\\>\\|string given\\.$#"
count: 1
path: src/Invoice/ServiceInvoice.php
-
message: "#^Property App\\\\Invoice\\\\ServiceInvoice\\:\\:\\$invoiceItemRepositories type has no value type specified in iterable type array\\.$#"
count: 1

View File

@@ -46,6 +46,7 @@ final class ActionsController extends BaseApiController
*/
private function convertEvent(PageActionsEvent $event, string $locale): array
{
$event->setLocale($locale);
$this->dispatcher->dispatch($event, $event->getEventName());
$translator = $this->translator;

View File

@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '2.0.18';
public const VERSION = '2.0.19';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 20018;
public const VERSION_ID = 20019;
/**
* The software name
*/

View File

@@ -18,9 +18,10 @@ use App\Entity\User;
*/
class PageActionsEvent extends ThemeEvent
{
private $action;
private $view;
private $divider = 0;
private string $action;
private string $view;
private int $divider = 0;
private ?string $locale = null;
public function __construct(User $user, array $payload, string $action, string $view)
{
@@ -195,4 +196,14 @@ class PageActionsEvent extends ThemeEvent
return \count($this->payload['actions']);
}
public function getLocale(): ?string
{
return $this->locale;
}
public function setLocale(?string $locale): void
{
$this->locale = $locale;
}
}

View File

@@ -52,8 +52,13 @@ class ThemeEvent extends Event
return $this->payload;
}
/**
* @deprecated since 2.0.19, will be removed with 2.1
*/
public function setPayload(mixed $payload): void
{
@trigger_error('ThemeEvent::setPayload() is deprecated, use AbstractActionsSubscriber instead.', E_USER_DEPRECATED);
$this->payload = $payload;
}
}

View File

@@ -19,6 +19,8 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
*/
abstract class AbstractActionsSubscriber implements EventSubscriberInterface
{
private ?string $locale = null;
public function __construct(private AuthorizationCheckerInterface $auth, private UrlGeneratorInterface $urlGenerator)
{
}
@@ -30,16 +32,27 @@ abstract class AbstractActionsSubscriber implements EventSubscriberInterface
protected function path(string $route, array $parameters = []): string
{
if ($this->locale !== null) {
$parameters['_locale'] = $this->locale;
}
return $this->urlGenerator->generate($route, $parameters);
}
public static function getSubscribedEvents(): array
{
return [
'actions.' . static::getActionName() => ['onActions', 1000],
'actions.' . static::getActionName() => ['handleEvent', 1000],
];
}
final public function handleEvent(PageActionsEvent $event): void
{
$this->locale = $event->getLocale();
$this->onActions($event);
}
public static function getActionName(): string
{
throw new \Exception('You need to overwrite getActionName() or getSubscribedEvents() in ' . static::class);

View File

@@ -197,16 +197,22 @@ final class ServiceInvoice
if (stripos($part, 'filename=') === false) {
continue;
}
$filename = explode('filename=', $part);
if (\count($filename) > 1) {
$filename = $filename[1];
$tmp = explode('filename=', $part);
if (\count($tmp) > 1) {
$filename = $tmp[1];
}
}
} else {
$disposition = $event->getResponse()->headers->get('Content-Type');
$parts = explode(';', $disposition);
$parts = explode('/', $parts[0]);
$filename .= '.' . $parts[1];
if (\count($parts) > 1) {
$filename .= '.' . $parts[1];
}
}
if (mb_strlen($filename) >= 150) {
throw new \Exception(sprintf('Invoice filename "%s" is too long, max. 150 characters allowed', $filename));
}
if (is_file($invoiceDirectory . $filename)) {

View File

@@ -118,6 +118,6 @@ class LdapDriver
if (null === $this->logger) {
return;
}
$this->logger->error($message, $context);
$this->logger->debug($message, $context);
}
}

View File

@@ -33,6 +33,7 @@ class PageActionsEventTest extends TestCase
$this->assertSame($user, $sut->getUser());
$this->assertEquals([], $sut->getActions());
$this->assertEquals(['actions' => [], 'view' => 'bar'], $sut->getPayload());
$this->assertNull($sut->getLocale());
$sut = new PageActionsEvent($user, ['hello' => 'world'], 'foo', 'bar');
$this->assertSame($user, $sut->getUser());
@@ -66,6 +67,12 @@ class PageActionsEventTest extends TestCase
$this->assertEquals(['foo' => ['url' => 'bar']], $sut->getActions());
$sut->replaceAction('foo', ['url' => 'xyz']);
$this->assertEquals(['foo' => ['url' => 'xyz']], $sut->getActions());
$sut->setLocale('de');
$this->assertEquals('de', $sut->getLocale());
$sut->setLocale(null);
$this->assertNull($sut->getLocale());
}
public function testSubmenu()

View File

@@ -18,7 +18,7 @@ use PHPUnit\Framework\TestCase;
*/
class ThemeEventTest extends TestCase
{
public function testEmpty()
public function testEmpty(): void
{
$sut = new ThemeEvent();
$this->assertNull($sut->getUser());
@@ -26,7 +26,7 @@ class ThemeEventTest extends TestCase
$this->assertEquals('', $sut->getContent());
}
public function testDefaultValues()
public function testDefaultValues(): void
{
$user = new User();
$user->setAlias('foo');
@@ -36,17 +36,13 @@ class ThemeEventTest extends TestCase
$this->assertSame($user, $sut->getUser());
}
public function testGetterAndSetter()
public function testGetterAndSetter(): void
{
$user = new User();
$user->setAlias('foo');
$payload = [null, '', 'test', new \stdClass()];
$sut = new ThemeEvent($user);
$sut->setPayload($payload);
$this->assertEquals($payload, $sut->getPayload());
$sut = new ThemeEvent($user, $payload);
$this->assertEquals($payload, $sut->getPayload());
@@ -57,4 +53,19 @@ class ThemeEventTest extends TestCase
$sut->addContent('<script>');
$this->assertEquals('foo<script>', $sut->getContent());
}
/**
* @group legacy
*/
public function testDeprecatedStuff(): void
{
$user = new User();
$user->setAlias('foo');
$payload = [null, '', 'test', new \stdClass()];
$sut = new ThemeEvent($user);
$sut->setPayload($payload);
$this->assertEquals($payload, $sut->getPayload());
}
}

View File

@@ -5187,21 +5187,6 @@ parameters:
count: 1
path: Event/SystemConfigurationEventTest.php
-
message: "#^Method App\\\\Tests\\\\Event\\\\ThemeEventTest\\:\\:testDefaultValues\\(\\) has no return type specified\\.$#"
count: 1
path: Event/ThemeEventTest.php
-
message: "#^Method App\\\\Tests\\\\Event\\\\ThemeEventTest\\:\\:testEmpty\\(\\) has no return type specified\\.$#"
count: 1
path: Event/ThemeEventTest.php
-
message: "#^Method App\\\\Tests\\\\Event\\\\ThemeEventTest\\:\\:testGetterAndSetter\\(\\) has no return type specified\\.$#"
count: 1
path: Event/ThemeEventTest.php
-
message: "#^Method App\\\\Tests\\\\Event\\\\ThemeJavascriptTranslationsEventTest\\:\\:testDefaultValues\\(\\) has no return type specified\\.$#"
count: 1