Release 2.0.30 (#4225)

This commit is contained in:
Kevin Papst
2023-08-16 18:20:14 +02:00
committed by GitHub
parent c7bc8fae73
commit adc0779912
21 changed files with 860 additions and 520 deletions

View File

@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '2.0.29';
public const VERSION = '2.0.30';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 20029;
public const VERSION_ID = 20030;
/**
* The software name
*/

View File

@@ -34,10 +34,16 @@ use InvalidArgumentException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Validator\ConstraintViolation;
use Symfony\Component\Validator\Validator\ValidatorInterface;
final class TimesheetService
{
/**
* @var array<string>
*/
private array $doNotValidateCodes = [];
public function __construct(
private SystemConfiguration $configuration,
private TimesheetRepository $repository,
@@ -236,10 +242,25 @@ final class TimesheetService
$errors = $this->validator->validate($timesheet, null, $groups);
if ($errors->count() > 0) {
throw new ValidationFailedException($errors, 'Validation Failed');
/** @var ConstraintViolation $error */
foreach ($errors as $error) {
if (\in_array($error->getCode(), $this->doNotValidateCodes, true)) {
continue;
}
throw new ValidationFailedException($errors, 'Validation Failed');
}
}
}
/**
* @param array<string> $validationCodes
*/
public function setIgnoreValidationCodes(array $validationCodes): void
{
$this->doNotValidateCodes = $validationCodes;
}
/**
* Makes sure, that the timesheet record has the timezone of the user.
*

View File

@@ -254,7 +254,7 @@ final class TimesheetStatisticService
return null;
}
return new DateTime($result, new \DateTimeZone($user->getTimezone()));
return new DateTime((string) $result, new \DateTimeZone($user->getTimezone()));
}
/**

View File

@@ -9,10 +9,8 @@
namespace App\Validator\Constraints;
use Symfony\Component\Validator\Constraint;
#[\Attribute(\Attribute::TARGET_CLASS)]
final class TimesheetDeactivated extends Constraint
final class TimesheetDeactivated extends TimesheetConstraint
{
public const DISABLED_ACTIVITY_ERROR = 'kimai-timesheet-deactivated-activity';
public const DISABLED_PROJECT_ERROR = 'kimai-timesheet-deactivated-project';

View File

@@ -9,15 +9,18 @@
namespace App\Validator\Constraints;
#[\Attribute(\Attribute::TARGET_CLASS)]
final class TimesheetFutureTimes extends TimesheetConstraint
{
public const BEGIN_IN_FUTURE_ERROR = 'kimai-timesheet-future-times-01';
public const END_IN_FUTURE_ERROR = 'kimai-timesheet-future-times-02';
protected const ERROR_NAMES = [
self::BEGIN_IN_FUTURE_ERROR => 'The begin date cannot be in the future.',
self::END_IN_FUTURE_ERROR => 'The end date cannot be in the future.',
];
public string $message = 'The begin date cannot be in the future.';
public string $message = 'The date cannot be in the future.';
public function getTargets(): string|array
{

View File

@@ -22,33 +22,44 @@ final class TimesheetFutureTimesValidator extends ConstraintValidator
}
/**
* @param TimesheetEntity $timesheet
* @param TimesheetEntity $value
* @param Constraint $constraint
*/
public function validate(mixed $timesheet, Constraint $constraint): void
public function validate(mixed $value, Constraint $constraint): void
{
if (!($constraint instanceof TimesheetFutureTimes)) {
throw new UnexpectedTypeException($constraint, TimesheetFutureTimes::class);
}
if (!\is_object($timesheet) || !($timesheet instanceof TimesheetEntity)) {
throw new UnexpectedTypeException($timesheet, TimesheetEntity::class);
if (!\is_object($value) || !($value instanceof TimesheetEntity)) {
throw new UnexpectedTypeException($value, TimesheetEntity::class);
}
if ($this->configuration->isTimesheetAllowFutureTimes()) {
return;
}
$now = new \DateTime('now', $timesheet->getBegin()->getTimezone());
$now = new \DateTime('now', $value->getBegin()->getTimezone());
// allow configured default rounding time + 1 minute - see #1295
$allowedDiff = ($this->configuration->getTimesheetDefaultRoundingBegin() * 60) + 60;
if (($now->getTimestamp() + $allowedDiff) < $timesheet->getBegin()->getTimestamp()) {
$this->context->buildViolation('The begin date cannot be in the future.')
$nowTs = $now->getTimestamp() + $allowedDiff;
if ($value->getBegin() !== null && $nowTs < $value->getBegin()->getTimestamp()) {
$this->context->buildViolation(TimesheetFutureTimes::getErrorName(TimesheetFutureTimes::BEGIN_IN_FUTURE_ERROR))
->atPath('begin_date')
->setTranslationDomain('validators')
->setCode(TimesheetFutureTimes::BEGIN_IN_FUTURE_ERROR)
->addViolation();
}
$allowedDiff = ($this->configuration->getTimesheetDefaultRoundingEnd() * 60) + 60;
$nowTs = $now->getTimestamp() + $allowedDiff;
if ($value->getEnd() !== null && $nowTs < $value->getEnd()->getTimestamp()) {
$this->context->buildViolation(TimesheetFutureTimes::getErrorName(TimesheetFutureTimes::END_IN_FUTURE_ERROR))
->atPath('end_time')
->setTranslationDomain('validators')
->setCode(TimesheetFutureTimes::END_IN_FUTURE_ERROR)
->addViolation();
}
}
}