From 396ea9a10abe46528735551f0dd71d631b0ad13b Mon Sep 17 00:00:00 2001 From: tchapi Date: Sat, 7 Mar 2026 22:10:09 +0100 Subject: [PATCH 1/6] chore --- src/Controller/Admin/CalendarController.php | 6 +++--- src/Plugins/PublicAwareDAVACLPlugin.php | 4 ++++ src/Repository/CalendarInstanceRepository.php | 13 +++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Controller/Admin/CalendarController.php b/src/Controller/Admin/CalendarController.php index 449e097..f99ab77 100644 --- a/src/Controller/Admin/CalendarController.php +++ b/src/Controller/Admin/CalendarController.php @@ -252,11 +252,11 @@ public function calendarDelete(ManagerRegistry $doctrine, int $userId, string $i $entityManager->remove($subscription); } - $schedulingObjects = $doctrine->getRepository(SchedulingObject::class)->findByPrincipalUri($instance->getPrincipalUri()); - foreach ($schedulingObjects ?? [] as $object) { + // Scheduling objects attached to the calendar objects of the calendar + $schedulingObjectsOfCalendarObjects = $doctrine->getRepository(CalendarInstance::class)->findAllSchedulingObjectsForCalendar($instance->getId()); + foreach ($schedulingObjectsOfCalendarObjects ?? [] as $object) { $entityManager->remove($object); } - foreach ($instance->getCalendar()->getObjects() ?? [] as $object) { $entityManager->remove($object); } diff --git a/src/Plugins/PublicAwareDAVACLPlugin.php b/src/Plugins/PublicAwareDAVACLPlugin.php index 6d71c3c..091eacd 100644 --- a/src/Plugins/PublicAwareDAVACLPlugin.php +++ b/src/Plugins/PublicAwareDAVACLPlugin.php @@ -48,6 +48,10 @@ public function getAcl($node): array $acl = parent::getAcl($node); if ($this->public_calendars_enabled) { + // We have nothing to handle here, but SchedulingObject extends Calendar so we bail out early + if ($node instanceof \Sabre\CalDAV\SchedulingObject) { + return $acl; + } // Handle both Calendar AND SharedCalendar (which extends Calendar) if ($node instanceof \Sabre\CalDAV\Calendar || $node instanceof \Sabre\CalDAV\CalendarObject) { // The property is private in \Sabre\CalDAV\CalendarObject and we don't want to create diff --git a/src/Repository/CalendarInstanceRepository.php b/src/Repository/CalendarInstanceRepository.php index 27c2c6c..c4897c4 100644 --- a/src/Repository/CalendarInstanceRepository.php +++ b/src/Repository/CalendarInstanceRepository.php @@ -74,6 +74,19 @@ public function hasDifferentOwner(int $calendarId, string $principalUri): bool ->getSingleScalarResult() > 0; } + public function findAllSchedulingObjectsForCalendar(int $calendarId): array + { + $objectRepository = $this->getEntityManager()->getRepository(\App\Entity\SchedulingObject::class); + + return $objectRepository->createQueryBuilder('s') + ->leftJoin(CalendarObject::class, 'c', \Doctrine\ORM\Query\Expr\Join::WITH, 'c.uri = s.uri') + ->where('c.calendarid = :id') + ->andWhere('s.principaluri = :principalUri') + ->setParameter('id', $calendarId) + ->getQuery() + ->getResult(); + } + /** * Get counts of calendar objects by component type for a calendar instance. * From bfe718b335f1210f1b29b7d16c1c2c78c55632db Mon Sep 17 00:00:00 2001 From: tchapi Date: Sat, 7 Mar 2026 22:34:13 +0100 Subject: [PATCH 2/6] chore --- src/Controller/Admin/CalendarController.php | 1 - src/Repository/CalendarInstanceRepository.php | 21 +++++++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/Controller/Admin/CalendarController.php b/src/Controller/Admin/CalendarController.php index f99ab77..cac897c 100644 --- a/src/Controller/Admin/CalendarController.php +++ b/src/Controller/Admin/CalendarController.php @@ -6,7 +6,6 @@ use App\Entity\CalendarInstance; use App\Entity\CalendarSubscription; use App\Entity\Principal; -use App\Entity\SchedulingObject; use App\Entity\User; use App\Form\CalendarInstanceType; use Doctrine\Persistence\ManagerRegistry; diff --git a/src/Repository/CalendarInstanceRepository.php b/src/Repository/CalendarInstanceRepository.php index c4897c4..d8a98e1 100644 --- a/src/Repository/CalendarInstanceRepository.php +++ b/src/Repository/CalendarInstanceRepository.php @@ -2,8 +2,11 @@ namespace App\Repository; +use App\Entity\Calendar; use App\Entity\CalendarInstance; +use App\Entity\CalendarObject; use App\Entity\Principal; +use App\Entity\SchedulingObject; use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; @@ -37,11 +40,11 @@ public function findSharedInstancesOfInstance(int $calendarId, bool $withCalenda return $query->addSelect('p.displayName', 'p.email') ->getQuery() ->getArrayResult(); - } else { - // Returns CalendarInstances as objects - return $query->getQuery() - ->getResult(); } + + // Returns CalendarInstances as objects + return $query->getQuery() + ->getResult(); } /** @@ -76,7 +79,7 @@ public function hasDifferentOwner(int $calendarId, string $principalUri): bool public function findAllSchedulingObjectsForCalendar(int $calendarId): array { - $objectRepository = $this->getEntityManager()->getRepository(\App\Entity\SchedulingObject::class); + $objectRepository = $this->getEntityManager()->getRepository(SchedulingObject::class); return $objectRepository->createQueryBuilder('s') ->leftJoin(CalendarObject::class, 'c', \Doctrine\ORM\Query\Expr\Join::WITH, 'c.uri = s.uri') @@ -96,7 +99,7 @@ public function findAllSchedulingObjectsForCalendar(int $calendarId): array */ public function getObjectCountsByComponentType(int $calendarId): array { - $objectRepository = $this->getEntityManager()->getRepository(\App\Entity\CalendarObject::class); + $objectRepository = $this->getEntityManager()->getRepository(CalendarObject::class); // Instead of three separate queries, get all counts in a single query $results = $objectRepository->createQueryBuilder('o') @@ -108,9 +111,9 @@ public function getObjectCountsByComponentType(int $calendarId): array ->getResult(); $componentTypeMap = [ - \App\Entity\Calendar::COMPONENT_EVENTS => 'events', - \App\Entity\Calendar::COMPONENT_NOTES => 'notes', - \App\Entity\Calendar::COMPONENT_TODOS => 'tasks', + Calendar::COMPONENT_EVENTS => 'events', + Calendar::COMPONENT_NOTES => 'notes', + Calendar::COMPONENT_TODOS => 'tasks', ]; $counts = [ From 00613998423811bb5431d4d90d4a648483624d40 Mon Sep 17 00:00:00 2001 From: tchapi Date: Sat, 7 Mar 2026 22:38:58 +0100 Subject: [PATCH 3/6] chore --- src/Controller/Admin/CalendarController.php | 8 +++++++- src/Repository/CalendarInstanceRepository.php | 5 ++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Controller/Admin/CalendarController.php b/src/Controller/Admin/CalendarController.php index cac897c..eea139e 100644 --- a/src/Controller/Admin/CalendarController.php +++ b/src/Controller/Admin/CalendarController.php @@ -239,6 +239,12 @@ public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, in #[Route('/{userId}/delete/{id}', name: 'delete', requirements: ['id' => "\d+"])] public function calendarDelete(ManagerRegistry $doctrine, int $userId, string $id, TranslatorInterface $trans): Response { + $user = $doctrine->getRepository(User::class)->findOneById($userId); + if (!$user) { + throw $this->createNotFoundException('User not found'); + } + $principalUri = Principal::PREFIX.$user->getUsername(); + $instance = $doctrine->getRepository(CalendarInstance::class)->findOneById($id); if (!$instance) { throw $this->createNotFoundException('Calendar not found'); @@ -252,7 +258,7 @@ public function calendarDelete(ManagerRegistry $doctrine, int $userId, string $i } // Scheduling objects attached to the calendar objects of the calendar - $schedulingObjectsOfCalendarObjects = $doctrine->getRepository(CalendarInstance::class)->findAllSchedulingObjectsForCalendar($instance->getId()); + $schedulingObjectsOfCalendarObjects = $doctrine->getRepository(CalendarInstance::class)->findAllSchedulingObjectsForCalendar($instance->getId(), $principalUri); foreach ($schedulingObjectsOfCalendarObjects ?? [] as $object) { $entityManager->remove($object); } diff --git a/src/Repository/CalendarInstanceRepository.php b/src/Repository/CalendarInstanceRepository.php index d8a98e1..435a2f2 100644 --- a/src/Repository/CalendarInstanceRepository.php +++ b/src/Repository/CalendarInstanceRepository.php @@ -77,15 +77,18 @@ public function hasDifferentOwner(int $calendarId, string $principalUri): bool ->getSingleScalarResult() > 0; } - public function findAllSchedulingObjectsForCalendar(int $calendarId): array + public function findAllSchedulingObjectsForCalendar(int $calendarId, string $principalUri): array { $objectRepository = $this->getEntityManager()->getRepository(SchedulingObject::class); return $objectRepository->createQueryBuilder('s') ->leftJoin(CalendarObject::class, 'c', \Doctrine\ORM\Query\Expr\Join::WITH, 'c.uri = s.uri') ->where('c.calendarid = :id') + // uri is not unique across calendars — two different calendars can have objects with the same uri. + // The join should also filter by principaluri as a consequence ->andWhere('s.principaluri = :principalUri') ->setParameter('id', $calendarId) + ->setParameter('principalUri', $principalUri) ->getQuery() ->getResult(); } From ec48c64359e3346a24df54b742947518f48d6b49 Mon Sep 17 00:00:00 2001 From: tchapi Date: Sat, 7 Mar 2026 22:44:19 +0100 Subject: [PATCH 4/6] chore --- src/Repository/CalendarInstanceRepository.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Repository/CalendarInstanceRepository.php b/src/Repository/CalendarInstanceRepository.php index 435a2f2..489e3be 100644 --- a/src/Repository/CalendarInstanceRepository.php +++ b/src/Repository/CalendarInstanceRepository.php @@ -77,17 +77,18 @@ public function hasDifferentOwner(int $calendarId, string $principalUri): bool ->getSingleScalarResult() > 0; } - public function findAllSchedulingObjectsForCalendar(int $calendarId, string $principalUri): array + + public function findAllSchedulingObjectsForCalendar(int $calendarInstanceId, string $principalUri): array { $objectRepository = $this->getEntityManager()->getRepository(SchedulingObject::class); - return $objectRepository->createQueryBuilder('s') ->leftJoin(CalendarObject::class, 'c', \Doctrine\ORM\Query\Expr\Join::WITH, 'c.uri = s.uri') - ->where('c.calendarid = :id') + ->leftJoin(CalendarInstance::class, 'ci', \Doctrine\ORM\Query\Expr\Join::WITH, 'ci.calendar = c.calendar') + ->where('ci.id = :id') // uri is not unique across calendars — two different calendars can have objects with the same uri. // The join should also filter by principaluri as a consequence ->andWhere('s.principaluri = :principalUri') - ->setParameter('id', $calendarId) + ->setParameter('id', $calendarInstanceId) ->setParameter('principalUri', $principalUri) ->getQuery() ->getResult(); From ecaf72c5d9ca1b70ddcda510b5ad8e7b0fe4894d Mon Sep 17 00:00:00 2001 From: tchapi Date: Sat, 7 Mar 2026 22:48:48 +0100 Subject: [PATCH 5/6] chore --- src/Repository/CalendarInstanceRepository.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Repository/CalendarInstanceRepository.php b/src/Repository/CalendarInstanceRepository.php index 489e3be..dd85434 100644 --- a/src/Repository/CalendarInstanceRepository.php +++ b/src/Repository/CalendarInstanceRepository.php @@ -87,7 +87,7 @@ public function findAllSchedulingObjectsForCalendar(int $calendarInstanceId, str ->where('ci.id = :id') // uri is not unique across calendars — two different calendars can have objects with the same uri. // The join should also filter by principaluri as a consequence - ->andWhere('s.principaluri = :principalUri') + ->andWhere('s.principalUri = :principalUri') ->setParameter('id', $calendarInstanceId) ->setParameter('principalUri', $principalUri) ->getQuery() From 6a41908e385fb76974b6aebbc410a087b775d63d Mon Sep 17 00:00:00 2001 From: tchapi Date: Sat, 7 Mar 2026 23:02:52 +0100 Subject: [PATCH 6/6] chore --- src/Plugins/PublicAwareDAVACLPlugin.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Plugins/PublicAwareDAVACLPlugin.php b/src/Plugins/PublicAwareDAVACLPlugin.php index 091eacd..6d71c3c 100644 --- a/src/Plugins/PublicAwareDAVACLPlugin.php +++ b/src/Plugins/PublicAwareDAVACLPlugin.php @@ -48,10 +48,6 @@ public function getAcl($node): array $acl = parent::getAcl($node); if ($this->public_calendars_enabled) { - // We have nothing to handle here, but SchedulingObject extends Calendar so we bail out early - if ($node instanceof \Sabre\CalDAV\SchedulingObject) { - return $acl; - } // Handle both Calendar AND SharedCalendar (which extends Calendar) if ($node instanceof \Sabre\CalDAV\Calendar || $node instanceof \Sabre\CalDAV\CalendarObject) { // The property is private in \Sabre\CalDAV\CalendarObject and we don't want to create