Skip to content

Commit a555baa

Browse files
author
tchapi
committed
chore
1 parent 9343f05 commit a555baa

File tree

7 files changed

+106
-55
lines changed

7 files changed

+106
-55
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
/**
11+
* Add public flag on calendar instance.
12+
*/
13+
final class Version20260131161930 extends AbstractMigration
14+
{
15+
public function getDescription(): string
16+
{
17+
return 'Add public flag on CalendarInstance (replacing ACCESS_PUBLIC flag)';
18+
}
19+
20+
public function up(Schema $schema): void
21+
{
22+
$engine = $this->connection->getDatabasePlatform()->getName();
23+
24+
if ('mysql' === $engine) {
25+
$this->addSql('ALTER TABLE calendarinstances ADD public TINYINT(1) DEFAULT 0 NOT NULL');
26+
} elseif ('postgresql' === $engine) {
27+
$this->addSql('ALTER TABLE calendarinstances ADD public BOOLEAN DEFAULT FALSE NOT NULL');
28+
} elseif ('sqlite' === $engine) {
29+
$this->addSql('ALTER TABLE calendarinstances ADD public BOOLEAN DEFAULT 0 NOT NULL');
30+
}
31+
32+
// Migrate ACCESS_PUBLIC (10) to ACCESS_SHAREDOWNER (1) + public = true
33+
$this->addSql('UPDATE calendarinstances SET public = 1, access = 1 WHERE access = 10');
34+
}
35+
36+
public function down(Schema $schema): void
37+
{
38+
$engine = $this->connection->getDatabasePlatform()->getName();
39+
40+
// Revert is_public = true back to ACCESS_PUBLIC (10)
41+
$this->addSql('UPDATE calendarinstances SET access = 10 WHERE public = 1');
42+
43+
if ('mysql' === $engine) {
44+
$this->addSql('ALTER TABLE calendarinstances DROP public');
45+
} elseif ('postgresql' === $engine) {
46+
$this->addSql('ALTER TABLE calendarinstances DROP COLUMN public');
47+
} elseif ('sqlite' === $engine) {
48+
$this->addSql('ALTER TABLE calendarinstances DROP COLUMN public');
49+
}
50+
}
51+
}

src/Controller/Admin/CalendarController.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use App\Entity\SchedulingObject;
1010
use App\Form\CalendarInstanceType;
1111
use Doctrine\Persistence\ManagerRegistry;
12+
use Sabre\DAV\Sharing\Plugin as SharingPlugin;
1213
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
1314
use Symfony\Component\HttpFoundation\JsonResponse;
1415
use Symfony\Component\HttpFoundation\Request;
@@ -100,9 +101,6 @@ public function calendarEdit(ManagerRegistry $doctrine, Request $request, string
100101
$form->get('events')->setData(in_array(Calendar::COMPONENT_EVENTS, $components));
101102
$form->get('todos')->setData(in_array(Calendar::COMPONENT_TODOS, $components));
102103
$form->get('notes')->setData(in_array(Calendar::COMPONENT_NOTES, $components));
103-
if ($arePublicCalendarsEnabled) {
104-
$form->get('public')->setData($calendarInstance->isPublic());
105-
}
106104
$form->get('principalUri')->setData(Principal::PREFIX.$username);
107105

108106
$form->handleRequest($request);
@@ -123,9 +121,9 @@ public function calendarEdit(ManagerRegistry $doctrine, Request $request, string
123121
$components[] = Calendar::COMPONENT_NOTES;
124122
}
125123
if ($arePublicCalendarsEnabled && true === $form->get('public')->getData()) {
126-
$calendarInstance->setAccess(CalendarInstance::ACCESS_PUBLIC);
124+
$calendarInstance->setIsPublic(true);
127125
} else {
128-
$calendarInstance->setAccess(CalendarInstance::ACCESS_SHAREDOWNER);
126+
$calendarInstance->setIsPublic(false);
129127
}
130128

131129
$calendarInstance->getCalendar()->setComponents(implode(',', $components));
@@ -168,7 +166,7 @@ public function calendarShares(ManagerRegistry $doctrine, string $username, stri
168166
'displayName' => $instance['displayName'],
169167
'email' => $instance['email'],
170168
'accessText' => $trans->trans('calendar.share_access.'.$instance[0]['access']),
171-
'isWriteAccess' => CalendarInstance::ACCESS_READWRITE === $instance[0]['access'],
169+
'isWriteAccess' => SharingPlugin::ACCESS_READWRITE === $instance[0]['access'],
172170
'revokeUrl' => $this->generateUrl('calendar_revoke', ['username' => $username, 'id' => $instance[0]['id']]),
173171
];
174172
}
@@ -197,7 +195,7 @@ public function calendarShareAdd(ManagerRegistry $doctrine, Request $request, st
197195
// already existing first, so we can update it:
198196
$existingSharedInstance = $doctrine->getRepository(CalendarInstance::class)->findSharedInstanceOfInstanceFor($instance->getCalendar()->getId(), $newShareeToAdd->getUri());
199197

200-
$writeAccess = ('true' === $request->get('write') ? CalendarInstance::ACCESS_READWRITE : CalendarInstance::ACCESS_READ);
198+
$writeAccess = ('true' === $request->get('write') ? SharingPlugin::ACCESS_READWRITE : SharingPlugin::ACCESS_READ);
201199

202200
$entityManager = $doctrine->getManager();
203201

src/Entity/CalendarInstance.php

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Constants;
66
use Doctrine\ORM\Mapping as ORM;
7+
use Sabre\DAV\Sharing\Plugin as SharingPlugin;
78
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
89
use Symfony\Component\Validator\Constraints as Assert;
910

@@ -12,27 +13,11 @@
1213
#[UniqueEntity(fields: ['principalUri', 'uri'], errorPath: 'uri', message: 'form.uri.unique')]
1314
class CalendarInstance
1415
{
15-
public const INVITE_NORESPONSE = 1;
16-
public const INVITE_ACCEPTED = 2;
17-
public const INVITE_DECLINED = 3;
18-
public const INVITE_INVALID = 4;
19-
20-
public const ACCESS_NOTSHARED = 0;
21-
public const ACCESS_SHAREDOWNER = 1;
22-
public const ACCESS_READ = 2;
23-
public const ACCESS_READWRITE = 3;
24-
public const ACCESS_NOACCESS = 4;
25-
26-
// Used to identify a public calendar, available to anyone without logging in.
27-
// It can't be shared, and it's owned by the principal.
28-
public const ACCESS_PUBLIC = 10;
29-
3016
public static function getOwnerAccesses(): array
3117
{
3218
return [
33-
self::ACCESS_NOTSHARED,
34-
self::ACCESS_SHAREDOWNER,
35-
self::ACCESS_PUBLIC,
19+
SharingPlugin::ACCESS_NOTSHARED,
20+
SharingPlugin::ACCESS_SHAREDOWNER,
3621
];
3722
}
3823

@@ -83,12 +68,16 @@ public static function getOwnerAccesses(): array
8368
#[ORM\Column(name: 'share_invitestatus', type: 'integer', options: ['default' => 2])]
8469
private $shareInviteStatus;
8570

71+
#[ORM\Column(name: 'public', type: 'boolean', options: ['default' => false])]
72+
private $public;
73+
8674
public function __construct()
8775
{
88-
$this->shareInviteStatus = self::INVITE_ACCEPTED;
76+
$this->shareInviteStatus = SharingPlugin::INVITE_ACCEPTED;
8977
$this->transparent = 0;
9078
$this->calendarOrder = 0;
91-
$this->access = self::ACCESS_SHAREDOWNER;
79+
$this->access = SharingPlugin::ACCESS_SHAREDOWNER;
80+
$this->public = false;
9281
}
9382

9483
public function getId(): ?int
@@ -137,9 +126,16 @@ public function isShared(): bool
137126
return !in_array($this->access, self::getOwnerAccesses());
138127
}
139128

129+
public function setIsPublic(bool $public): self
130+
{
131+
$this->public = $public;
132+
133+
return $this;
134+
}
135+
140136
public function isPublic(): bool
141137
{
142-
return self::ACCESS_PUBLIC === $this->access;
138+
return $this->public;
143139
}
144140

145141
public function isAutomaticallyGenerated(): bool

src/Form/CalendarInstanceType.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
2929
])
3030
->add('public', ChoiceType::class, [
3131
'label' => 'form.public',
32-
'mapped' => false,
3332
'disabled' => $options['shared'],
3433
'help' => 'form.public.help.caldav',
3534
'required' => true,

src/Plugins/PublicAwareDAVACLPlugin.php

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,33 +41,39 @@ public function beforeMethod(RequestInterface $request, ResponseInterface $respo
4141

4242
public function getAcl($node): array
4343
{
44+
// Note:
45+
// '{DAV:}unauthenticated' - only unauthenticated users
46+
// '{DAV:}all' - all users (both authenticated and unauthenticated)
47+
// '{DAV:}authenticated' - only authenticated users
4448
$acl = parent::getAcl($node);
4549

46-
if ($node instanceof \Sabre\CalDAV\Calendar) {
47-
if (CalendarInstance::ACCESS_PUBLIC === $node->getShareAccess() && $this->public_calendars_enabled) {
48-
// We must add the ACL on the calendar itself
49-
$acl[] = [
50-
'principal' => '{DAV:}unauthenticated',
51-
'privilege' => '{DAV:}read',
52-
'protected' => false,
53-
];
54-
}
55-
} elseif ($node instanceof \Sabre\CalDAV\CalendarObject) {
56-
// The property is private in \Sabre\CalDAV\CalendarObject and we don't want to create
57-
// a new class just to access it, so we use a closure.
58-
$calendarInfo = (fn () => $this->calendarInfo)->call($node);
59-
// [0] is the calendarId, [1] is the calendarInstanceId
60-
$calendarInstanceId = $calendarInfo['id'][1];
50+
if ($this->public_calendars_enabled) {
51+
if ($node instanceof \Sabre\CalDAV\Calendar) {
52+
if ($node->isPublic()) {
53+
// We must add the ACL on the calendar itself
54+
$acl[] = [
55+
'principal' => '{DAV:}unauthenticated',
56+
'privilege' => '{DAV:}read',
57+
'protected' => false,
58+
];
59+
}
60+
} elseif ($node instanceof \Sabre\CalDAV\CalendarObject) {
61+
// The property is private in \Sabre\CalDAV\CalendarObject and we don't want to create
62+
// a new class just to access it, so we use a closure.
63+
$calendarInfo = (fn () => $this->calendarInfo)->call($node);
64+
// [0] is the calendarId, [1] is the calendarInstanceId
65+
$calendarInstanceId = $calendarInfo['id'][1];
6166

62-
$calendar = $this->em->getRepository(CalendarInstance::class)->findOneById($calendarInstanceId);
67+
$calendar = $this->em->getRepository(CalendarInstance::class)->findOneById($calendarInstanceId);
6368

64-
if ($calendar && $calendar->isPublic() && $this->public_calendars_enabled) {
65-
// We must add the ACL on the object itself
66-
$acl[] = [
67-
'principal' => '{DAV:}unauthenticated',
68-
'privilege' => '{DAV:}read',
69-
'protected' => false,
70-
];
69+
if ($calendar && $calendar->isPublic()) {
70+
// We must add the ACL on the object itself
71+
$acl[] = [
72+
'principal' => '{DAV:}unauthenticated',
73+
'privilege' => '{DAV:}read',
74+
'protected' => false,
75+
];
76+
}
7177
}
7278
}
7379

src/Services/BirthdayService.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use App\Entity\Card;
2020
use App\Entity\Principal;
2121
use Doctrine\Persistence\ManagerRegistry;
22+
use Sabre\DAV\Sharing\Plugin as SharingPlugin;
2223
use Sabre\VObject\Component\VCalendar;
2324
use Sabre\VObject\Component\VCard;
2425
use Sabre\VObject\DateTimeParser;
@@ -94,7 +95,7 @@ public function ensureBirthdayCalendarExists(string $principalUri): CalendarInst
9495
->setPrincipalUri($principalUri)
9596
->setDisplayName('🎁 Birthdays')
9697
->setDescription('Birthdays')
97-
->setAccess(CalendarInstance::ACCESS_READ)
98+
->setAccess(SharingPlugin::ACCESS_READ)
9899
->setCalendarOrder(0)
99100
->setCalendar($calendar)
100101
->setTransparent(1)

templates/calendars/index.html.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<div class="d-flex w-100 justify-content-between">
1616
<h5 class="mb-1 me-auto">
1717
{{ calendar.displayName }}
18-
{% if calendar.access == constant('\\App\\Entity\\CalendarInstance::ACCESS_PUBLIC') %}
18+
{% if calendar.isPublic() %}
1919
<span class="badge bg-success ml-1">{{ ('calendar.share_access.' ~ calendar.access)|trans }}</span>
2020
{% endif %}
2121
<a href="#" tabindex="0" class="badge badge-indicator" role="button" data-bs-toggle="popover" data-bs-title="{{ 'calendars.setup.title'|trans }}" data-bs-html='true' data-bs-content="URI: <code>{{ calendar.uri }}</code><br />Absolute path: <code>{{ davUri }}</code>">ⓘ</a>
@@ -79,7 +79,7 @@
7979
<div class="d-flex w-100 justify-content-between">
8080
<h5 class="mb-1 me-auto">
8181
{{ calendar.displayName }}
82-
{% if calendar.access == constant('\\App\\Entity\\CalendarInstance::ACCESS_READWRITE') %}
82+
{% if calendar.access == constant('Sabre\\DAV\\Sharing\\Plugin::ACCESS_READWRITE') %}
8383
<span class="badge bg-success ms-1">{{ ('calendar.share_access.' ~ calendar.access)|trans }}</span>
8484
{% else %}
8585
<span class="badge bg-info ms-1">{{ ('calendar.share_access.' ~ calendar.access)|trans }}</span>

0 commit comments

Comments
 (0)