Release 2.26 (#5189)
* bring back deprecated methods * bump packages * fix SAML redirect * config flag for break times * use class constant instead of string in attributes * throw if all tags were not found - fixes #4792
This commit is contained in:
@@ -37,6 +37,7 @@ use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\Form\FormError;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
@@ -181,8 +182,11 @@ final class TimesheetController extends BaseApiController
|
||||
/** @var array<string> $tags */
|
||||
$tags = $paramFetcher->get('tags');
|
||||
if (\is_array($tags) && \count($tags) > 0) {
|
||||
$tags = $this->tagRepository->findTagsByName($tags, true);
|
||||
foreach ($tags as $tag) {
|
||||
$tagsByName = $this->tagRepository->findTagsByName($tags, true);
|
||||
if (\count($tagsByName) === 0) {
|
||||
throw new BadRequestHttpException('Given tags were not found');
|
||||
}
|
||||
foreach ($tagsByName as $tag) {
|
||||
$query->addTag($tag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use Symfony\Component\Intl\Locales;
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
#[AsCommand(name: 'kimai:reset:locales')]
|
||||
#[AsCommand(name: 'kimai:reset:locales', description: 'Regenerate the locale definition file')]
|
||||
final class RegenerateLocalesCommand extends Command
|
||||
{
|
||||
/**
|
||||
@@ -66,11 +66,6 @@ final class RegenerateLocalesCommand extends Command
|
||||
return $this->kernelEnvironment !== 'prod';
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setDescription('Regenerate the locale definition file');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.25.0';
|
||||
public const VERSION = '2.26.0';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 22500;
|
||||
public const VERSION_ID = 22600;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -12,18 +12,24 @@ namespace App\Controller\Auth;
|
||||
use App\Configuration\SamlConfigurationInterface;
|
||||
use App\Saml\SamlAuthFactory;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Http\SecurityRequestAttributes;
|
||||
use Symfony\Component\Security\Http\Util\TargetPathTrait;
|
||||
|
||||
#[Route(path: '/saml')]
|
||||
final class SamlController extends AbstractController
|
||||
{
|
||||
use TargetPathTrait;
|
||||
|
||||
public function __construct(
|
||||
private readonly SamlAuthFactory $authFactory,
|
||||
private readonly SamlConfigurationInterface $samlConfiguration
|
||||
private readonly SamlConfigurationInterface $samlConfiguration,
|
||||
private readonly Security $security,
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -54,8 +60,12 @@ final class SamlController extends AbstractController
|
||||
throw new \RuntimeException($error);
|
||||
}
|
||||
|
||||
// this does set headers and exit as $stay is not set to true
|
||||
$redirectTarget = $session->get('_security.main.target_path');
|
||||
$firewallName = $this->security->getFirewallConfig($request)?->getName();
|
||||
if ($firewallName === null || $firewallName === '') {
|
||||
throw new ServiceUnavailableHttpException(message: 'Unknown firewall.');
|
||||
}
|
||||
|
||||
$redirectTarget = $this->getTargetPath($session, $firewallName);
|
||||
if ($redirectTarget === null || $redirectTarget === '') {
|
||||
$redirectTarget = $this->generateUrl('homepage', [], UrlGeneratorInterface::ABSOLUTE_URL);
|
||||
}
|
||||
|
||||
@@ -253,7 +253,6 @@ final class DoctorController extends AbstractController
|
||||
'max_execution_time',
|
||||
'date.timezone',
|
||||
'allow_url_fopen',
|
||||
'allow_url_include',
|
||||
'default_charset',
|
||||
'default_mimetype',
|
||||
'display_errors',
|
||||
|
||||
@@ -331,6 +331,9 @@ final class Configuration implements ConfigurationInterface
|
||||
->booleanNode('require_activity')
|
||||
->defaultTrue()
|
||||
->end()
|
||||
->booleanNode('break_time_active')
|
||||
->defaultFalse()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
->end()
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\AccessTokenRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_access_token')]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\AccessTokenRepository')]
|
||||
#[ORM\Entity(repositoryClass: AccessTokenRepository::class)]
|
||||
#[ORM\UniqueConstraint(columns: ['token'])]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity(fields: ['token'])]
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace App\Entity;
|
||||
use App\Doctrine\Behavior\CreatedAt;
|
||||
use App\Doctrine\Behavior\CreatedTrait;
|
||||
use App\Export\Annotation as Exporter;
|
||||
use App\Repository\ActivityRepository;
|
||||
use App\Validator\Constraints as Constraints;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -24,7 +25,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
#[ORM\Index(columns: ['visible', 'project_id'])]
|
||||
#[ORM\Index(columns: ['visible', 'project_id', 'name'])]
|
||||
#[ORM\Index(columns: ['visible', 'name'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\ActivityRepository')]
|
||||
#[ORM\Entity(repositoryClass: ActivityRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
#[Serializer\VirtualProperty('ProjectName', exp: 'object.getProject() === null ? null : object.getProject().getName()', options: [new Serializer\SerializedName('parentTitle'), new Serializer\Type(name: 'string'), new Serializer\Groups(['Activity'])])]
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ActivityRateRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
@@ -16,7 +17,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_activities_rates')]
|
||||
#[ORM\UniqueConstraint(columns: ['user_id', 'activity_id'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\ActivityRateRepository')]
|
||||
#[ORM\Entity(repositoryClass: ActivityRateRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity(['user', 'activity'], ignoreNull: false)]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\BookmarkRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_bookmarks')]
|
||||
#[ORM\UniqueConstraint(columns: ['user_id', 'name'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\BookmarkRepository')]
|
||||
#[ORM\Entity(repositoryClass: BookmarkRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity(fields: ['user', 'name'])]
|
||||
class Bookmark
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ConfigurationRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_configuration')]
|
||||
#[ORM\UniqueConstraint(columns: ['name'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\ConfigurationRepository')]
|
||||
#[ORM\Entity(repositoryClass: ConfigurationRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity('name')]
|
||||
class Configuration
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace App\Entity;
|
||||
use App\Doctrine\Behavior\CreatedAt;
|
||||
use App\Doctrine\Behavior\CreatedTrait;
|
||||
use App\Export\Annotation as Exporter;
|
||||
use App\Repository\CustomerRepository;
|
||||
use App\Validator\Constraints as Constraints;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -22,7 +23,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_customers')]
|
||||
#[ORM\Index(columns: ['visible'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\CustomerRepository')]
|
||||
#[ORM\Entity(repositoryClass: CustomerRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
#[Exporter\Order(['id', 'name', 'company', 'number', 'vatId', 'address', 'contact', 'email', 'phone', 'mobile', 'fax', 'homepage', 'country', 'currency', 'timezone', 'budget', 'timeBudget', 'budgetType', 'color', 'visible', 'comment', 'billable'])]
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\CustomerRateRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
@@ -16,7 +17,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_customers_rates')]
|
||||
#[ORM\UniqueConstraint(columns: ['user_id', 'customer_id'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\CustomerRateRepository')]
|
||||
#[ORM\Entity(repositoryClass: CustomerRateRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity(['user', 'customer'], ignoreNull: false)]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
|
||||
@@ -11,17 +11,19 @@ namespace App\Entity;
|
||||
|
||||
use App\Export\Annotation as Exporter;
|
||||
use App\Invoice\InvoiceModel;
|
||||
use App\Repository\InvoiceRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use OpenApi\Attributes as OA;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_invoices')]
|
||||
#[ORM\UniqueConstraint(columns: ['invoice_number'])]
|
||||
#[ORM\UniqueConstraint(columns: ['invoice_filename'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\InvoiceRepository')]
|
||||
#[ORM\Entity(repositoryClass: InvoiceRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity('invoiceNumber')]
|
||||
#[UniqueEntity('invoiceFilename')]
|
||||
@@ -65,12 +67,14 @@ class Invoice implements EntityWithMetaFields
|
||||
#[Assert\NotNull]
|
||||
#[Serializer\Expose]
|
||||
#[Serializer\Groups(['Default'])]
|
||||
#[OA\Property(ref: '#/components/schemas/Customer')]
|
||||
private ?Customer $customer = null;
|
||||
#[ORM\ManyToOne(targetEntity: User::class)]
|
||||
#[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
|
||||
#[Assert\NotNull]
|
||||
#[Serializer\Expose]
|
||||
#[Serializer\Groups(['Default'])]
|
||||
#[OA\Property(ref: '#/components/schemas/User')]
|
||||
private ?User $user = null;
|
||||
#[ORM\Column(name: 'created_at', type: 'datetime', nullable: false)]
|
||||
#[Assert\NotNull]
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\InvoiceTemplateRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_invoice_templates')]
|
||||
#[ORM\UniqueConstraint(columns: ['name'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\InvoiceTemplateRepository')]
|
||||
#[ORM\Entity(repositoryClass: InvoiceTemplateRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity('name')]
|
||||
class InvoiceTemplate
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace App\Entity;
|
||||
use App\Doctrine\Behavior\CreatedAt;
|
||||
use App\Doctrine\Behavior\CreatedTrait;
|
||||
use App\Export\Annotation as Exporter;
|
||||
use App\Repository\ProjectRepository;
|
||||
use App\Validator\Constraints as Constraints;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
@@ -23,7 +24,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
#[ORM\Table(name: 'kimai2_projects')]
|
||||
#[ORM\Index(columns: ['customer_id', 'visible', 'name'])]
|
||||
#[ORM\Index(columns: ['customer_id', 'visible', 'id'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\ProjectRepository')]
|
||||
#[ORM\Entity(repositoryClass: ProjectRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
#[Serializer\VirtualProperty('CustomerName', exp: 'object.getCustomer() === null ? null : object.getCustomer().getName()', options: [new Serializer\SerializedName('parentTitle'), new Serializer\Type(name: 'string'), new Serializer\Groups(['Project'])])]
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\ProjectRateRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
@@ -16,7 +17,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_projects_rates')]
|
||||
#[ORM\UniqueConstraint(columns: ['user_id', 'project_id'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\ProjectRateRepository')]
|
||||
#[ORM\Entity(repositoryClass: ProjectRateRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity(['user', 'project'], ignoreNull: false)]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\RoleRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_roles')]
|
||||
#[ORM\UniqueConstraint(name: 'roles_name', columns: ['name'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\RoleRepository')]
|
||||
#[ORM\Entity(repositoryClass: RoleRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity('name')]
|
||||
class Role
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\RolePermissionRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_roles_permissions')]
|
||||
#[ORM\UniqueConstraint(name: 'role_permission', columns: ['role_id', 'permission'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\RolePermissionRepository')]
|
||||
#[ORM\Entity(repositoryClass: RolePermissionRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity(['role', 'permission'])]
|
||||
class RolePermission
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\TagRepository;
|
||||
use App\Utils\Color;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JMS\Serializer\Annotation as Serializer;
|
||||
@@ -17,7 +18,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
#[ORM\Table(name: 'kimai2_tags')]
|
||||
#[ORM\UniqueConstraint(columns: ['name'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\TagRepository')]
|
||||
#[ORM\Entity(repositoryClass: TagRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity('name')]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace App\Entity;
|
||||
|
||||
use App\Doctrine\Behavior\ModifiedAt;
|
||||
use App\Doctrine\Behavior\ModifiedTrait;
|
||||
use App\Repository\TimesheetRepository;
|
||||
use App\Validator\Constraints as Constraints;
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
@@ -37,7 +38,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
#[ORM\Index(columns: ['end_time', 'user', 'start_time'], name: 'IDX_TIMESHEET_TICKTAC')]
|
||||
#[ORM\Index(columns: ['user', 'project_id', 'activity_id'], name: 'IDX_TIMESHEET_RECENT_ACTIVITIES')]
|
||||
#[ORM\Index(columns: ['user', 'id', 'duration'], name: 'IDX_TIMESHEET_RESULT_STATS')]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\TimesheetRepository')]
|
||||
#[ORM\Entity(repositoryClass: TimesheetRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
#[Serializer\ExclusionPolicy('all')]
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Export\Annotation as Exporter;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Utils\StringHelper;
|
||||
use App\Validator\Constraints as Constraints;
|
||||
use App\WorkingTime\Mode\WorkingTimeModeNone;
|
||||
@@ -33,7 +34,7 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
#[ORM\Table(name: 'kimai2_users')]
|
||||
#[ORM\UniqueConstraint(columns: ['username'])]
|
||||
#[ORM\UniqueConstraint(columns: ['email'])]
|
||||
#[ORM\Entity(repositoryClass: 'App\Repository\UserRepository')]
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\ChangeTrackingPolicy('DEFERRED_EXPLICIT')]
|
||||
#[UniqueEntity('username')]
|
||||
#[UniqueEntity('email')]
|
||||
|
||||
@@ -66,6 +66,35 @@ class WorkingTimeRepository extends EntityRepository
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 2.25.0 - kept for BC with old plugin versions
|
||||
*/
|
||||
public function getLatestApproval(User $user): ?WorkingTime
|
||||
{
|
||||
$qb = $this->createQueryBuilder('w');
|
||||
$qb->select('MAX(DATE(w.date))')
|
||||
->where($qb->expr()->eq('w.user', ':user'))
|
||||
->setParameter('user', $user->getId())
|
||||
->andWhere($qb->expr()->isNotNull('w.approvedAt'))
|
||||
;
|
||||
|
||||
$date = $qb->getQuery()->getSingleScalarResult();
|
||||
|
||||
if ($date === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$qb = $this->createQueryBuilder('w');
|
||||
$qb->select('w')
|
||||
->where($qb->expr()->eq('w.user', ':user'))
|
||||
->setParameter('user', $user->getId())
|
||||
->andWhere($qb->expr()->eq('DATE(w.date)', 'DATE(:date)'))
|
||||
->setParameter('date', $date)
|
||||
;
|
||||
|
||||
return $qb->getQuery()->getOneOrNullResult();
|
||||
}
|
||||
|
||||
public function getLatestApprovalDate(User $user): ?\DateTimeInterface
|
||||
{
|
||||
$qb = $this->createQueryBuilder('w');
|
||||
|
||||
@@ -50,6 +50,10 @@ class SamlAuthenticator extends AbstractAuthenticator
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$request->isMethod(Request::METHOD_POST)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->httpUtils->checkRequestPath($request, $this->options['check_path'])) {
|
||||
return false;
|
||||
}
|
||||
@@ -81,7 +85,7 @@ class SamlAuthenticator extends AbstractAuthenticator
|
||||
|
||||
// file_put_contents(__DIR__ . '/../../var/log/saml.xml', $oneLoginAuth->getLastResponseXML());
|
||||
|
||||
if ($oneLoginAuth->getErrors()) {
|
||||
if (\count($oneLoginAuth->getErrors()) > 0) {
|
||||
throw new AuthenticationException($oneLoginAuth->getLastErrorReason());
|
||||
}
|
||||
|
||||
|
||||
@@ -24,15 +24,12 @@ final class SamlAuthenticationSuccessHandler extends DefaultAuthenticationSucces
|
||||
|
||||
protected function determineTargetUrl(Request $request): string
|
||||
{
|
||||
if ($this->options['always_use_default_target_path']) {
|
||||
return $this->options['default_target_path'];
|
||||
}
|
||||
|
||||
$relayState = $request->get('RelayState');
|
||||
$loginUrl = $this->httpUtils->generateUri($request, $this->options['login_path']);
|
||||
|
||||
if ($relayState !== null && $relayState !== '' && $relayState !== $loginUrl) {
|
||||
return $relayState;
|
||||
if (\is_scalar($relayState)) {
|
||||
$relayState = (string) $relayState;
|
||||
if ($relayState !== $this->httpUtils->generateUri($request, (string) $this->options['login_path'])) {
|
||||
return $relayState;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::determineTargetUrl($request);
|
||||
|
||||
@@ -15,7 +15,7 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
||||
final class TwoFactorCondition implements TwoFactorConditionInterface
|
||||
{
|
||||
public function __construct(private AuthorizationCheckerInterface $authorizationChecker)
|
||||
public function __construct(private readonly AuthorizationCheckerInterface $authorizationChecker)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -88,13 +88,12 @@ final class DataTable implements \Countable, \IteratorAggregate
|
||||
|
||||
/**
|
||||
* @param FormInterface<MultiUpdateTableDTO>|null $batchForm
|
||||
* @return void
|
||||
*/
|
||||
public function setBatchForm(?FormInterface $batchForm): void
|
||||
{
|
||||
$this->batchForm = $batchForm;
|
||||
|
||||
if (!\array_key_exists('id', $this->columns)) {
|
||||
if ($batchForm !== null && !\array_key_exists('id', $this->columns)) {
|
||||
$this->addColumn('id', [
|
||||
'class' => 'alwaysVisible multiCheckbox',
|
||||
'orderBy' => false,
|
||||
|
||||
@@ -32,6 +32,8 @@ final class WorkingTimeService
|
||||
{
|
||||
private const LATEST_APPROVAL_PREF = '_latest_approval';
|
||||
private const LATEST_APPROVAL_FORMAT = 'Y-m-d H:i:s';
|
||||
/** @var array<string, WorkingTime|null> */
|
||||
private array $latestApprovals = [];
|
||||
|
||||
public function __construct(
|
||||
private readonly TimesheetRepository $timesheetRepository,
|
||||
@@ -58,6 +60,24 @@ final class WorkingTimeService
|
||||
return $yearPerUserSummary;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 2.25.0 - kept for BC with old plugin versions
|
||||
*/
|
||||
public function getLatestApproval(User $user): ?WorkingTime
|
||||
{
|
||||
if ($user->getId() === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$key = 'u_' . $user->getId();
|
||||
|
||||
if (!\array_key_exists($key, $this->latestApprovals)) {
|
||||
$this->latestApprovals[$key] = $this->workingTimeRepository->getLatestApproval($user);
|
||||
}
|
||||
|
||||
return $this->latestApprovals[$key];
|
||||
}
|
||||
|
||||
public function getLatestApprovalDate(User $user): ?\DateTimeInterface
|
||||
{
|
||||
if ($user->getId() === null) {
|
||||
|
||||
Reference in New Issue
Block a user