Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/config/packages/http_cache.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
parameters:
app.httpCache.matchPath: '^/?($|index.jsonhal$|content_types|camps/[0-9a-f]*/categories)'
app.httpCache.matchPath: '^/?($|index.jsonhal$|content_types|camps/[0-9a-f]*/categories|periods/[0-9a-f]*/schedule_entries)'

fos_http_cache:
debug:
Expand Down
8 changes: 0 additions & 8 deletions api/migrations/dev-data/Version202504121559.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ public function getDescription(): string {

public function up(Schema $schema): void {
// START PHP CODE
$this->addSql(createTruncateDatabaseCommand());

$statements = getStatementsForMigrationFile();
foreach ($statements as $statement) {
if (trim($statement)) {
$this->addSql($statement);
}
}
// END PHP CODE
}

Expand Down
31 changes: 31 additions & 0 deletions api/migrations/dev-data/Version202504130046.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace DataMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

require_once __DIR__.'/helpers.php';

final class Version202504130046 extends AbstractMigration {
public function getDescription(): string {
return 'Add 2nd period to Harry Potter camp';
}

public function up(Schema $schema): void {
// START PHP CODE
$this->addSql(createTruncateDatabaseCommand());

$statements = getStatementsForMigrationFile();
foreach ($statements as $statement) {
if (trim($statement)) {
$this->addSql($statement);
}
}
// END PHP CODE
}

public function down(Schema $schema): void {}
}
7 changes: 5 additions & 2 deletions api/migrations/dev-data/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1976,7 +1976,8 @@ INSERT INTO public.period (id, description, start, "end", createtime, updatetime
('c085d1d5ddfa', 'Die Jedi-Akademie', '2026-07-14', '2026-07-16', '2023-08-13 06:32:29', '2023-08-13 06:32:29', '0969e3c95dfc'),
('7fa4564a5d5d', 'Main', '2031-01-24', '2031-01-30', '2023-09-29 23:24:38', '2023-09-29 23:24:38', '70ca971c992f'),
('88f1f55a69d7', 'Hauptlager', '2025-07-13', '2025-07-20', '2023-08-08 09:22:58', '2023-08-08 09:48:01', '5d28f99890bc'),
('05938f2a5372', 'Hauptlager', '2022-01-02', '2022-01-02', '2024-09-28 21:19:13', '2024-09-28 21:22:24', '25a82475e0b7');
('05938f2a5372', 'Hauptlager', '2022-01-02', '2022-01-02', '2024-09-28 21:19:13', '2024-09-28 21:22:24', '25a82475e0b7'),
('c550b8707c26', 'Nachweekend', '2025-08-09', '2025-08-10', '2025-04-12 22:30:55', '2025-04-12 22:30:55', '6973c230d6b1');



Expand Down Expand Up @@ -2020,7 +2021,9 @@ INSERT INTO public.day (id, dayoffset, createtime, updatetime, periodid) VALUES
('273358ce9d70', 5, '2023-08-08 09:22:58', '2023-08-08 09:22:58', '88f1f55a69d7'),
('40e3a286dc08', 6, '2023-08-08 09:22:58', '2023-08-08 09:22:58', '88f1f55a69d7'),
('485e190f4852', 7, '2023-08-08 09:22:58', '2023-08-08 09:22:58', '88f1f55a69d7'),
('fb406d22f8b9', 0, '2024-09-28 21:19:13', '2024-09-28 21:19:13', '05938f2a5372');
('fb406d22f8b9', 0, '2024-09-28 21:19:13', '2024-09-28 21:19:13', '05938f2a5372'),
('be09cc00bfb5', 0, '2025-04-12 22:30:55', '2025-04-12 22:30:55', 'c550b8707c26'),
('ee1a47697fd0', 1, '2025-04-12 22:30:55', '2025-04-12 22:30:55', 'c550b8707c26');



Expand Down
21 changes: 13 additions & 8 deletions api/src/State/PeriodPersistProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
use App\Entity\Period;
use App\State\Util\AbstractPersistProcessor;
use App\Util\DateTimeUtil;
use FOS\HttpCacheBundle\CacheManager;

/**
* @template-extends AbstractPersistProcessor<Period>
*/
class PeriodPersistProcessor extends AbstractPersistProcessor {
public function __construct(
ProcessorInterface $decorated
ProcessorInterface $decorated,
private readonly CacheManager $cacheManager
) {
parent::__construct($decorated);
}
Expand All @@ -23,26 +25,29 @@ public function __construct(
* @param Period $data
*/
public function onBefore($data, Operation $operation, array $uriVariables = [], array $context = []): Period {
self::moveDaysAndScheduleEntries($data, $context['previous_data'] ?? null);
$this->moveDaysAndScheduleEntries($data, $context['previous_data'] ?? null);
self::removeExtraDays($data);
self::addMissingDays($data);

return $data;
}

public static function moveDaysAndScheduleEntries(Period $period, ?Period $originalPeriod = null) {
public function moveDaysAndScheduleEntries(Period $period, ?Period $originalPeriod = null) {
if (!$originalPeriod) {
return;
}

// moveScheduleEntries === true: scheduleEntries move relative to the start date (no change of offset needed -> return)
// moveScheduleEntries === false: scheduleEntries stay absolutely on the scheduled calendar date (change of offset needed)
if ($period->moveScheduleEntries) {
$deltaMinutes = DateTimeUtil::differenceInMinutes($originalPeriod->start, $period->start);
if (0 === $deltaMinutes) {
return;
}

$deltaMinutes = DateTimeUtil::differenceInMinutes($originalPeriod->start, $period->start);
if (0 === $deltaMinutes) {
// start date shifts --> purge schedule_entries subresource to reflect changes in dates + numbers
$this->cacheManager->invalidateTags(["/api/periods/{$period->getId()}/schedule_entries"]);

// moveScheduleEntries === true: scheduleEntries move relative to the start date (no change of offset needed -> return)
// moveScheduleEntries === false: scheduleEntries stay absolutely on the scheduled calendar date (change of offset needed)
if ($period->moveScheduleEntries) {
return;
}

Expand Down
9 changes: 3 additions & 6 deletions api/tests/State/PeriodPersistProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
use App\Entity\Period;
use App\Entity\ScheduleEntry;
use App\State\PeriodPersistProcessor;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\MockObject\MockObject;
use FOS\HttpCacheBundle\CacheManager;
use PHPUnit\Framework\TestCase;

/**
Expand All @@ -23,8 +22,6 @@ class PeriodPersistProcessorTest extends TestCase {
private ScheduleEntry $scheduleEntry;
private DayResponsible $dayResponsible;

private EntityManagerInterface|MockObject $em;

private PeriodPersistProcessor $processor;

/**
Expand Down Expand Up @@ -53,11 +50,11 @@ protected function setUp(): void {
$day2->addDayResponsible($this->dayResponsible);

$decoratedProcessor = $this->createMock(ProcessorInterface::class);
$this->em = $this->createMock(EntityManagerInterface::class);
$cacheManager = $this->createMock(CacheManager::class);

$this->processor = new PeriodPersistProcessor(
$decoratedProcessor,
$this->em
$cacheManager
);
}

Expand Down
6 changes: 6 additions & 0 deletions e2e/specs/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ export const cachedEndpoint = Cypress.env('API_ROOT_URL_CACHED')
export const grgrCampId = '3c79b99ab424'
export const loremIpsumCampId = '9c2447aefe38'

export const skilagerPeriodId = '7fa4564a5d5d'
export const grgrPeriodId = '76be24bce434'

export const harryMainPeriodId = 'fe47dfd2b541'
export const harrySecondPeriodId = 'c550b8707c26'

export const bipiUser = 'test@example.com'
export const castorUser = 'castor@example.com'
export const felicitySmoakUser = 'felicity@smoak.com'
Expand Down
203 changes: 203 additions & 0 deletions e2e/specs/httpCache/responses/schedule_entries_collection.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
{
"_links": {
"self": {
"href": "/api/periods/7fa4564a5d5d/schedule_entries.jsonhal"
},
"items": [
{
"href": "/api/schedule_entries/e68f4e47517a"
},
{
"href": "/api/schedule_entries/f0883e931649"
},
{
"href": "/api/schedule_entries/29c9e9a07d82"
},
{
"href": "/api/schedule_entries/ee85308a97d1"
},
{
"href": "/api/schedule_entries/f08d69cae18a"
},
{
"href": "/api/schedule_entries/7e8086d94633"
},
{
"href": "/api/schedule_entries/f89a1501dbb6"
}
]
},
"totalItems": 7,
"_embedded": {
"items": [
{
"_links": {
"self": {
"href": "/api/schedule_entries/e68f4e47517a"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/b29d387cc403"
},
"day": {
"href": "/api/days/27ad4212466a"
}
},
"left": 0,
"width": 1,
"id": "e68f4e47517a",
"start": "2031-01-24T08:00:00+00:00",
"end": "2031-01-24T18:00:00+00:00",
"dayNumber": 1,
"scheduleEntryNumber": 1,
"number": "1.1"
},
{
"_links": {
"self": {
"href": "/api/schedule_entries/f0883e931649"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/b29d387cc403"
},
"day": {
"href": "/api/days/69426b72ce46"
}
},
"left": 0,
"width": 1,
"id": "f0883e931649",
"start": "2031-01-25T08:00:00+00:00",
"end": "2031-01-25T18:00:00+00:00",
"dayNumber": 2,
"scheduleEntryNumber": 1,
"number": "2.1"
},
{
"_links": {
"self": {
"href": "/api/schedule_entries/29c9e9a07d82"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/a13fadc97610"
},
"day": {
"href": "/api/days/5dc6586312e0"
}
},
"left": 0,
"width": 1,
"id": "29c9e9a07d82",
"start": "2031-01-26T08:00:00+00:00",
"end": "2031-01-26T19:00:00+00:00",
"dayNumber": 3,
"scheduleEntryNumber": 1,
"number": "3.A"
},
{
"_links": {
"self": {
"href": "/api/schedule_entries/ee85308a97d1"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/b29d387cc403"
},
"day": {
"href": "/api/days/839d27065403"
}
},
"left": 0,
"width": 1,
"id": "ee85308a97d1",
"start": "2031-01-27T08:00:00+00:00",
"end": "2031-01-27T18:00:00+00:00",
"dayNumber": 4,
"scheduleEntryNumber": 1,
"number": "4.1"
},
{
"_links": {
"self": {
"href": "/api/schedule_entries/f08d69cae18a"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/a13fadc97610"
},
"day": {
"href": "/api/days/755cbc1d9852"
}
},
"left": 0,
"width": 1,
"id": "f08d69cae18a",
"start": "2031-01-28T08:00:00+00:00",
"end": "2031-01-28T19:00:00+00:00",
"dayNumber": 5,
"scheduleEntryNumber": 1,
"number": "5.A"
},
{
"_links": {
"self": {
"href": "/api/schedule_entries/7e8086d94633"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/a13fadc97610"
},
"day": {
"href": "/api/days/3a84cfaf795c"
}
},
"left": 0,
"width": 1,
"id": "7e8086d94633",
"start": "2031-01-29T08:00:00+00:00",
"end": "2031-01-29T19:00:00+00:00",
"dayNumber": 6,
"scheduleEntryNumber": 1,
"number": "6.A"
},
{
"_links": {
"self": {
"href": "/api/schedule_entries/f89a1501dbb6"
},
"period": {
"href": "/api/periods/7fa4564a5d5d"
},
"activity": {
"href": "/api/activities/b29d387cc403"
},
"day": {
"href": "/api/days/5e0c146f4a75"
}
},
"left": 0,
"width": 1,
"id": "f89a1501dbb6",
"start": "2031-01-30T08:00:00+00:00",
"end": "2031-01-30T18:00:00+00:00",
"dayNumber": 7,
"scheduleEntryNumber": 1,
"number": "7.1"
}
]
}
}
Loading
Loading