Release 2.0.8 (#3914)
* support parsing negative durations in JS * bump luxon dependency * make sure that 2FA is not required for session based API calls * show name of items to delete * fix permission issue for recent activity items
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\API\Authentication;
|
||||
|
||||
use Scheb\TwoFactorBundle\Security\Http\Authenticator\TwoFactorAuthenticator;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
@@ -24,6 +25,19 @@ final class SessionAuthenticator extends AbstractAuthenticator
|
||||
{
|
||||
}
|
||||
|
||||
public function createToken(Passport $passport, string $firewallName): TokenInterface
|
||||
{
|
||||
$token = parent::createToken($passport, $firewallName);
|
||||
|
||||
// this should not be necessary, as /api/ is excluded from 2FA process, but just to make sure this
|
||||
// authenticator never triggers 2FA, we add the attribute to the token
|
||||
|
||||
// https://symfony.com/bundles/SchebTwoFactorBundle/6.x/custom_conditions.html
|
||||
$token->setAttribute(TwoFactorAuthenticator::FLAG_2FA_COMPLETE, true);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
public function supports(Request $request): ?bool
|
||||
{
|
||||
if (str_contains($request->getRequestUri(), '/api/')) {
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.7';
|
||||
public const VERSION = '2.0.8';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20007;
|
||||
public const VERSION_ID = 20008;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -358,7 +358,9 @@ class TimesheetRepository extends EntityRepository
|
||||
*
|
||||
* Should a teamlead:
|
||||
* 1. see all records of his team-members, even if they recorded times for projects invisible to him
|
||||
* 2. only see records for projects which can be accessed by hom (current situation)
|
||||
* 2. only see records for projects which can be accessed by him (current situation)
|
||||
*
|
||||
* @param array<Team> $teams
|
||||
*/
|
||||
private function addPermissionCriteria(QueryBuilder $qb, ?User $user = null, array $teams = []): bool
|
||||
{
|
||||
@@ -637,6 +639,7 @@ class TimesheetRepository extends EntityRepository
|
||||
public function getRecentActivities(User $user, DateTime $startFrom = null, int $limit = 10): array
|
||||
{
|
||||
return $this->findTimesheetsById(
|
||||
$user,
|
||||
$this->getRecentActivityIds($user, $startFrom, $limit)
|
||||
);
|
||||
}
|
||||
@@ -653,13 +656,11 @@ class TimesheetRepository extends EntityRepository
|
||||
|
||||
// do NOT join the customer and do NOT check the customer visibility, as this
|
||||
// will dramatically increase the speed of this (otherwise slow) query
|
||||
// ->join('p.customer', 'c')
|
||||
// ->andWhere($qb->expr()->eq('c.visible', ':visible'))
|
||||
|
||||
// you might want to join activity and project to check their visibility
|
||||
// but for now this is way slower than simply fetching more items
|
||||
//
|
||||
// ->join('t.project', 'p')
|
||||
// ->andWhere($qb->expr()->eq('p.visible', ':visible'))
|
||||
// ->join('t.activity', 'a')
|
||||
// ->andWhere($qb->expr()->eq('a.visible', ':visible'))
|
||||
@@ -680,6 +681,11 @@ class TimesheetRepository extends EntityRepository
|
||||
->setParameter('begin', $startFrom);
|
||||
}
|
||||
|
||||
$qb->join('t.project', 'p');
|
||||
$qb->join('p.customer', 'c');
|
||||
|
||||
$this->addPermissionCriteria($qb, $user);
|
||||
|
||||
$results = $qb->getQuery()->getScalarResult();
|
||||
|
||||
if (empty($results)) {
|
||||
@@ -690,10 +696,13 @@ class TimesheetRepository extends EntityRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param array<int> $ids
|
||||
* @param bool $fullyHydrated
|
||||
* @param bool $basicHydrated
|
||||
* @return array<Timesheet>
|
||||
*/
|
||||
public function findTimesheetsById(array $ids, bool $fullyHydrated = false, bool $basicHydrated = true): array
|
||||
public function findTimesheetsById(User $user, array $ids, bool $fullyHydrated = false, bool $basicHydrated = true): array
|
||||
{
|
||||
if (\count($ids) === 0) {
|
||||
return [];
|
||||
@@ -706,6 +715,11 @@ class TimesheetRepository extends EntityRepository
|
||||
->orderBy('t.end', 'DESC')
|
||||
;
|
||||
|
||||
$qb->join('t.project', 'p');
|
||||
$qb->join('p.customer', 'c');
|
||||
|
||||
$this->addPermissionCriteria($qb, $user);
|
||||
|
||||
return $this->getHydratedResultsByQuery($qb, $fullyHydrated, $basicHydrated);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ final class FavoriteRecordService
|
||||
$recentIds = $this->repository->getRecentActivityIds($user, null, $limit);
|
||||
}
|
||||
/** @var array<int> $ids */
|
||||
$ids = \array_slice(array_unique(array_merge($favIds, $recentIds)), 0, $limit);
|
||||
$ids = array_unique(array_merge($favIds, $recentIds));
|
||||
|
||||
/** @var array<int, bool|FavoriteTimesheet> $favorites */
|
||||
$favorites = [];
|
||||
@@ -49,7 +49,7 @@ final class FavoriteRecordService
|
||||
|
||||
$all = [];
|
||||
if (\count($ids) > 0) {
|
||||
$timesheets = $this->repository->findTimesheetsById($ids, false, false);
|
||||
$timesheets = $this->repository->findTimesheetsById($user, $ids, false, false);
|
||||
foreach ($timesheets as $timesheet) {
|
||||
$id = $timesheet->getId();
|
||||
if ($id === null) {
|
||||
@@ -69,7 +69,7 @@ final class FavoriteRecordService
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($all);
|
||||
return \array_slice(array_values($all), 0, $limit);
|
||||
}
|
||||
|
||||
private function getBookmark(User $user): Bookmark
|
||||
|
||||
Reference in New Issue
Block a user