Version 2.0.1 (#3853)

* configure email validation mode to fix deprecation message
* allow to use non brand icon in saml provider
* new method getCalculatedDuration()
* getRawData() by id
* only stop entries if new one is running
* fix validator tampering with timesheet duration
* fix allow setting null as customer
* bump packages
This commit is contained in:
Kevin Papst
2023-02-18 14:19:16 +01:00
committed by GitHub
parent 75aea7c51b
commit e474087257
20 changed files with 253 additions and 363 deletions

View File

@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '2.0.0';
public const VERSION = '2.0.1';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 20000;
public const VERSION_ID = 20001;
/**
* The software name
*/

View File

@@ -21,12 +21,13 @@ final class UTCDateTimeType extends DateTimeType
private static ?\DateTimeZone $utc = null;
/**
* @param mixed $value
* @param T $value
* @param AbstractPlatform $platform
* @return mixed|string
* @return (T is null ? null : string)
* @template T<\DateTime>
* @throws ConversionException
*/
public function convertToDatabaseValue($value, AbstractPlatform $platform): mixed
public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string
{
if ($value instanceof \DateTime) {
$value = clone $value;

View File

@@ -184,7 +184,7 @@ class Project implements EntityWithMetaFields, EntityWithBudget
return $this->customer;
}
public function setCustomer(Customer $customer): Project
public function setCustomer(?Customer $customer): Project
{
$this->customer = $customer;

View File

@@ -322,12 +322,21 @@ class Timesheet implements EntityWithMetaFields, ExportableItem
{
// only auto calculate if manually set duration is null - the result is important for eg. validations
if ($calculate && $this->duration === null && $this->begin !== null && $this->end !== null) {
return $this->end->getTimestamp() - $this->begin->getTimestamp();
return $this->getCalculatedDuration();
}
return $this->duration;
}
public function getCalculatedDuration(): ?int
{
if ($this->begin !== null && $this->end !== null) {
return $this->end->getTimestamp() - $this->begin->getTimestamp();
}
return null;
}
/**
* @param User $user
* @return Timesheet

View File

@@ -51,10 +51,10 @@ class TimesheetRepository extends EntityRepository
/**
* Fetches the raw data of a timesheet, to allow comparison e.g. of submitted and previously stored data.
*
* @param Timesheet $id
* @param int $id
* @return array
*/
public function getRawData(Timesheet $id): array
public function getRawData(int $id): array
{
$qb = $this->createQueryBuilder('t');
$qb

View File

@@ -28,7 +28,7 @@ final class DurationCalculator implements CalculatorInterface
return;
}
$duration = $record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp();
$duration = $record->getCalculatedDuration();
$record->setDuration($duration);
$this->roundings->applyRoundings($record);

View File

@@ -116,7 +116,7 @@ final class RoundingService
$rounder->roundEnd($record, $rounding['end']);
if ($record->getBegin() !== null) {
$duration = $record->getEnd()->getTimestamp() - $record->getBegin()->getTimestamp();
$duration = $record->getCalculatedDuration();
$record->setDuration($duration);
$rounder->roundDuration($record, $rounding['duration']);

View File

@@ -127,14 +127,16 @@ final class TimesheetService
$this->repository->save($timesheet);
$this->dispatcher->dispatch(new TimesheetCreatePostEvent($timesheet));
// TODO really stop always or only if $timesheet->getEnd() === null
try {
$this->stopActiveEntries($timesheet);
} catch (ValidationFailedException $vex) {
// could happen for timesheets that were started in the future (end before begin)
// or if you try to create a new timesheet while an old one is running for too long
throw new ValidationFailedException($vex->getViolations(), 'Cannot stop running timesheet');
if ($timesheet->isRunning()) {
try {
$this->stopActiveEntries($timesheet);
} catch (ValidationFailedException $vex) {
// could happen for timesheets that were started in the future (end before begin)
// or if you try to create a new timesheet while an old one is running for too long
throw new ValidationFailedException($vex->getViolations(), 'Cannot stop running timesheet');
}
}
$this->repository->commit();
} catch (\Exception $ex) {
$this->repository->rollback();

View File

@@ -73,10 +73,24 @@ final class TimesheetBudgetUsedValidator extends ConstraintValidator
return;
}
$id = $timesheet->getId();
// when changing the date via the calendar and/or the API, the duration will not be reset by the
// duration calculator (which runs after validation!) so we manually reset the duration before
$timesheet->setDuration(null);
$duration = $timesheet->getDuration();
// ------------------------------------------------------------------------
// Old solution (buggy) - duration MAY NOT BE RESET!
// this will cause the timesheet to be deleted in the Weekly-QuickEntry-Flow
// ------------------------------------------------------------------------
// $timesheet->setDuration(null);
// $duration = $timesheet->getDuration();
// another possible solution is cloning the timesheet
// $timesheet = clone $timesheet;
// $timesheet->setDuration(null);
// $duration = $timesheet->getDuration();
$duration = $timesheet->getCalculatedDuration();
$timeRate = $this->rateService->calculate($timesheet);
$rate = $timeRate->getRate();
@@ -89,8 +103,8 @@ final class TimesheetBudgetUsedValidator extends ConstraintValidator
$customerRate = $rate;
$monthWasChanged = false;
if ($timesheet->getId() !== null) {
$rawData = $this->timesheetRepository->getRawData($timesheet);
if ($id !== null) {
$rawData = $this->timesheetRepository->getRawData($id);
$activityId = (int) $rawData['activity'];
$projectId = (int) $rawData['project'];

View File

@@ -39,9 +39,12 @@ final class TimesheetLongRunningValidator extends ConstraintValidator
return;
}
/** @var int $duration */
$duration = $timesheet->getCalculatedDuration();
// one year is currently the maximum that can be logged (which is already not logically)
// the database column could hold more data, but let's limit it here
if ($timesheet->getDuration() > 31536000) {
if ($duration > 31536000) {
$this->context->buildViolation($constraint->maximumMessage)
->setTranslationDomain('validators')
->atPath('duration')
@@ -57,7 +60,6 @@ final class TimesheetLongRunningValidator extends ConstraintValidator
return;
}
$duration = $timesheet->getEnd()->getTimestamp() - $timesheet->getBegin()->getTimestamp();
// float on purpose, because one second more than the configured minutes is already too long
$minutes = $duration / 60;

View File

@@ -45,7 +45,7 @@ final class TimesheetZeroDurationValidator extends ConstraintValidator
$duration = 0;
if ($timesheet->getEnd() !== null && $timesheet->getBegin() !== null) {
$duration = $timesheet->getEnd()->getTimestamp() - $timesheet->getBegin()->getTimestamp();
$duration = $timesheet->getCalculatedDuration();
}
if ($duration <= 0) {