Skip to content

Commit 5f2afad

Browse files
Merge pull request #30438 from nextcloud/fix/caldav-trash-bin-deleted-at-int
Fix column/property types in CalDAV
2 parents d3d5349 + 288f07a commit 5f2afad

1 file changed

Lines changed: 79 additions & 72 deletions

File tree

apps/dav/lib/CalDAV/CalDavBackend.php

Lines changed: 79 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,15 @@
9797
use Sabre\VObject\Recur\EventIterator;
9898
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
9999
use Symfony\Component\EventDispatcher\GenericEvent;
100+
use function array_column;
100101
use function array_merge;
101102
use function array_values;
102103
use function explode;
103104
use function is_array;
104105
use function is_resource;
105106
use function pathinfo;
106107
use function rewind;
108+
use function settype;
107109
use function sprintf;
108110
use function str_replace;
109111
use function strtolower;
@@ -142,20 +144,19 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
142144
public const CLASSIFICATION_CONFIDENTIAL = 2;
143145

144146
/**
145-
* List of CalDAV properties, and how they map to database field names
147+
* List of CalDAV properties, and how they map to database field names and their type
146148
* Add your own properties by simply adding on to this array.
147149
*
148-
* Note that only string-based properties are supported here.
149-
*
150150
* @var array
151+
* @psalm-var array<string, string[]>
151152
*/
152153
public $propertyMap = [
153-
'{DAV:}displayname' => 'displayname',
154-
'{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description',
155-
'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone',
156-
'{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
157-
'{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
158-
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}deleted-at' => 'deleted_at',
154+
'{DAV:}displayname' => ['displayname', 'string'],
155+
'{urn:ietf:params:xml:ns:caldav}calendar-description' => ['description', 'string'],
156+
'{urn:ietf:params:xml:ns:caldav}calendar-timezone' => ['timezone', 'string'],
157+
'{http://apple.com/ns/ical/}calendar-order' => ['calendarorder', 'int'],
158+
'{http://apple.com/ns/ical/}calendar-color' => ['calendarcolor', 'string'],
159+
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}deleted-at' => ['deleted_at', 'int'],
159160
];
160161

161162
/**
@@ -164,13 +165,13 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription
164165
* @var array
165166
*/
166167
public $subscriptionPropertyMap = [
167-
'{DAV:}displayname' => 'displayname',
168-
'{http://apple.com/ns/ical/}refreshrate' => 'refreshrate',
169-
'{http://apple.com/ns/ical/}calendar-order' => 'calendarorder',
170-
'{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor',
171-
'{http://calendarserver.org/ns/}subscribed-strip-todos' => 'striptodos',
172-
'{http://calendarserver.org/ns/}subscribed-strip-alarms' => 'stripalarms',
173-
'{http://calendarserver.org/ns/}subscribed-strip-attachments' => 'stripattachments',
168+
'{DAV:}displayname' => ['displayname', 'string'],
169+
'{http://apple.com/ns/ical/}refreshrate' => ['refreshrate', 'string'],
170+
'{http://apple.com/ns/ical/}calendar-order' => ['calendarorder', 'int'],
171+
'{http://apple.com/ns/ical/}calendar-color' => ['calendarcolor', 'string'],
172+
'{http://calendarserver.org/ns/}subscribed-strip-todos' => ['striptodos', 'bool'],
173+
'{http://calendarserver.org/ns/}subscribed-strip-alarms' => ['stripalarms', 'string'],
174+
'{http://calendarserver.org/ns/}subscribed-strip-attachments' => ['stripattachments', 'string'],
174175
];
175176

176177
/**
@@ -351,7 +352,7 @@ public function getDeletedCalendars(int $deletedBefore): array {
351352
public function getCalendarsForUser($principalUri) {
352353
$principalUriOriginal = $principalUri;
353354
$principalUri = $this->convertPrincipal($principalUri, true);
354-
$fields = array_values($this->propertyMap);
355+
$fields = array_column($this->propertyMap, 0);
355356
$fields[] = 'id';
356357
$fields[] = 'uri';
357358
$fields[] = 'synctoken';
@@ -392,10 +393,7 @@ public function getCalendarsForUser($principalUri) {
392393
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}owner-principal' => $this->convertPrincipal($principalUri, !$this->legacyEndpoint),
393394
];
394395

395-
foreach ($this->propertyMap as $xmlName => $dbName) {
396-
$calendar[$xmlName] = $row[$dbName];
397-
}
398-
396+
$calendar = $this->rowToCalendar($row, $calendar);
399397
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
400398
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
401399

@@ -411,7 +409,7 @@ public function getCalendarsForUser($principalUri) {
411409

412410
$principals[] = $principalUri;
413411

414-
$fields = array_values($this->propertyMap);
412+
$fields = array_column($this->propertyMap, 0);
415413
$fields[] = 'a.id';
416414
$fields[] = 'a.uri';
417415
$fields[] = 'a.synctoken';
@@ -469,10 +467,7 @@ public function getCalendarsForUser($principalUri) {
469467
$readOnlyPropertyName => $readOnly,
470468
];
471469

472-
foreach ($this->propertyMap as $xmlName => $dbName) {
473-
$calendar[$xmlName] = $row[$dbName];
474-
}
475-
470+
$calendar = $this->rowToCalendar($row, $calendar);
476471
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
477472
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
478473

@@ -489,7 +484,7 @@ public function getCalendarsForUser($principalUri) {
489484
*/
490485
public function getUsersOwnCalendars($principalUri) {
491486
$principalUri = $this->convertPrincipal($principalUri, true);
492-
$fields = array_values($this->propertyMap);
487+
$fields = array_column($this->propertyMap, 0);
493488
$fields[] = 'id';
494489
$fields[] = 'uri';
495490
$fields[] = 'synctoken';
@@ -518,10 +513,8 @@ public function getUsersOwnCalendars($principalUri) {
518513
'{' . Plugin::NS_CALDAV . '}supported-calendar-component-set' => new SupportedCalendarComponentSet($components),
519514
'{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
520515
];
521-
foreach ($this->propertyMap as $xmlName => $dbName) {
522-
$calendar[$xmlName] = $row[$dbName];
523-
}
524516

517+
$calendar = $this->rowToCalendar($row, $calendar);
525518
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
526519
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
527520

@@ -556,7 +549,7 @@ private function getUserDisplayName($uid) {
556549
* @return array
557550
*/
558551
public function getPublicCalendars() {
559-
$fields = array_values($this->propertyMap);
552+
$fields = array_column($this->propertyMap, 0);
560553
$fields[] = 'a.id';
561554
$fields[] = 'a.uri';
562555
$fields[] = 'a.synctoken';
@@ -595,10 +588,7 @@ public function getPublicCalendars() {
595588
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}public' => (int)$row['access'] === self::ACCESS_PUBLIC,
596589
];
597590

598-
foreach ($this->propertyMap as $xmlName => $dbName) {
599-
$calendar[$xmlName] = $row[$dbName];
600-
}
601-
591+
$calendar = $this->rowToCalendar($row, $calendar);
602592
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
603593
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
604594

@@ -617,7 +607,7 @@ public function getPublicCalendars() {
617607
* @throws NotFound
618608
*/
619609
public function getPublicCalendar($uri) {
620-
$fields = array_values($this->propertyMap);
610+
$fields = array_column($this->propertyMap, 0);
621611
$fields[] = 'a.id';
622612
$fields[] = 'a.uri';
623613
$fields[] = 'a.synctoken';
@@ -663,10 +653,7 @@ public function getPublicCalendar($uri) {
663653
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_OWNCLOUD . '}public' => (int)$row['access'] === self::ACCESS_PUBLIC,
664654
];
665655

666-
foreach ($this->propertyMap as $xmlName => $dbName) {
667-
$calendar[$xmlName] = $row[$dbName];
668-
}
669-
656+
$calendar = $this->rowToCalendar($row, $calendar);
670657
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
671658
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
672659

@@ -679,7 +666,7 @@ public function getPublicCalendar($uri) {
679666
* @return array|null
680667
*/
681668
public function getCalendarByUri($principal, $uri) {
682-
$fields = array_values($this->propertyMap);
669+
$fields = array_column($this->propertyMap, 0);
683670
$fields[] = 'id';
684671
$fields[] = 'uri';
685672
$fields[] = 'synctoken';
@@ -717,10 +704,7 @@ public function getCalendarByUri($principal, $uri) {
717704
'{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
718705
];
719706

720-
foreach ($this->propertyMap as $xmlName => $dbName) {
721-
$calendar[$xmlName] = $row[$dbName];
722-
}
723-
707+
$calendar = $this->rowToCalendar($row, $calendar);
724708
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
725709
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
726710

@@ -732,7 +716,7 @@ public function getCalendarByUri($principal, $uri) {
732716
* @return array|null
733717
*/
734718
public function getCalendarById($calendarId) {
735-
$fields = array_values($this->propertyMap);
719+
$fields = array_column($this->propertyMap, 0);
736720
$fields[] = 'id';
737721
$fields[] = 'uri';
738722
$fields[] = 'synctoken';
@@ -769,10 +753,7 @@ public function getCalendarById($calendarId) {
769753
'{' . Plugin::NS_CALDAV . '}schedule-calendar-transp' => new ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'),
770754
];
771755

772-
foreach ($this->propertyMap as $xmlName => $dbName) {
773-
$calendar[$xmlName] = $row[$dbName];
774-
}
775-
756+
$calendar = $this->rowToCalendar($row, $calendar);
776757
$calendar = $this->addOwnerPrincipalToCalendar($calendar);
777758
$calendar = $this->addResourceTypeToCalendar($row, $calendar);
778759

@@ -783,7 +764,7 @@ public function getCalendarById($calendarId) {
783764
* @param $subscriptionId
784765
*/
785766
public function getSubscriptionById($subscriptionId) {
786-
$fields = array_values($this->subscriptionPropertyMap);
767+
$fields = array_column($this->subscriptionPropertyMap, 0);
787768
$fields[] = 'id';
788769
$fields[] = 'uri';
789770
$fields[] = 'source';
@@ -815,13 +796,7 @@ public function getSubscriptionById($subscriptionId) {
815796
'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
816797
];
817798

818-
foreach ($this->subscriptionPropertyMap as $xmlName => $dbName) {
819-
if (!is_null($row[$dbName])) {
820-
$subscription[$xmlName] = $row[$dbName];
821-
}
822-
}
823-
824-
return $subscription;
799+
return $this->rowToSubscription($row, $subscription);
825800
}
826801

827802
/**
@@ -863,7 +838,7 @@ public function createCalendar($principalUri, $calendarUri, array $properties) {
863838
$values['transparent'] = (int) ($properties[$transp]->getValue() === 'transparent');
864839
}
865840

866-
foreach ($this->propertyMap as $xmlName => $dbName) {
841+
foreach ($this->propertyMap as $xmlName => [$dbName, $type]) {
867842
if (isset($properties[$xmlName])) {
868843
$values[$dbName] = $properties[$xmlName];
869844
}
@@ -912,7 +887,7 @@ public function updateCalendar($calendarId, PropPatch $propPatch) {
912887
$newValues[$fieldName] = (int) ($propertyValue->getValue() === 'transparent');
913888
break;
914889
default:
915-
$fieldName = $this->propertyMap[$propertyName];
890+
$fieldName = $this->propertyMap[$propertyName][0];
916891
$newValues[$fieldName] = $propertyValue;
917892
break;
918893
}
@@ -1109,7 +1084,7 @@ public function getDeletedCalendarObjects(int $deletedBefore): array {
11091084
'size' => (int) $row['size'],
11101085
'component' => strtolower($row['componenttype']),
11111086
'classification' => (int) $row['classification'],
1112-
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}deleted-at' => $row['deleted_at'],
1087+
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}deleted-at' => $row['deleted_at'] === null ? $row['deleted_at'] : (int) $row['deleted_at'],
11131088
];
11141089
}
11151090
$stmt->closeCursor();
@@ -1148,7 +1123,7 @@ public function getDeletedCalendarObjectsByPrincipal(string $principalUri): arra
11481123
'size' => (int)$row['size'],
11491124
'component' => strtolower($row['componenttype']),
11501125
'classification' => (int)$row['classification'],
1151-
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}deleted-at' => $row['deleted_at'],
1126+
'{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}deleted-at' => $row['deleted_at'] === null ? $row['deleted_at'] : (int) $row['deleted_at'],
11521127
];
11531128
}
11541129
$stmt->closeCursor();
@@ -2452,7 +2427,7 @@ public function getChangesForCalendar($calendarId, $syncToken, $syncLevel, $limi
24522427
* @return array
24532428
*/
24542429
public function getSubscriptionsForUser($principalUri) {
2455-
$fields = array_values($this->subscriptionPropertyMap);
2430+
$fields = array_column($this->subscriptionPropertyMap, 0);
24562431
$fields[] = 'id';
24572432
$fields[] = 'uri';
24582433
$fields[] = 'source';
@@ -2480,13 +2455,7 @@ public function getSubscriptionsForUser($principalUri) {
24802455
'{http://sabredav.org/ns}sync-token' => $row['synctoken']?$row['synctoken']:'0',
24812456
];
24822457

2483-
foreach ($this->subscriptionPropertyMap as $xmlName => $dbName) {
2484-
if (!is_null($row[$dbName])) {
2485-
$subscription[$xmlName] = $row[$dbName];
2486-
}
2487-
}
2488-
2489-
$subscriptions[] = $subscription;
2458+
$subscriptions[] = $this->rowToSubscription($row, $subscription);
24902459
}
24912460

24922461
return $subscriptions;
@@ -2517,7 +2486,7 @@ public function createSubscription($principalUri, $uri, array $properties) {
25172486

25182487
$propertiesBoolean = ['striptodos', 'stripalarms', 'stripattachments'];
25192488

2520-
foreach ($this->subscriptionPropertyMap as $xmlName => $dbName) {
2489+
foreach ($this->subscriptionPropertyMap as $xmlName => [$dbName, $type]) {
25212490
if (array_key_exists($xmlName, $properties)) {
25222491
$values[$dbName] = $properties[$xmlName];
25232492
if (in_array($dbName, $propertiesBoolean)) {
@@ -2579,7 +2548,7 @@ public function updateSubscription($subscriptionId, PropPatch $propPatch) {
25792548
if ($propertyName === '{http://calendarserver.org/ns/}source') {
25802549
$newValues['source'] = $propertyValue->getHref();
25812550
} else {
2582-
$fieldName = $this->subscriptionPropertyMap[$propertyName];
2551+
$fieldName = $this->subscriptionPropertyMap[$propertyName][0];
25832552
$newValues[$fieldName] = $propertyValue;
25842553
}
25852554
}
@@ -3263,4 +3232,42 @@ private function addResourceTypeToCalendar(array $row, array $calendar): array {
32633232
}
32643233
return $calendar;
32653234
}
3235+
3236+
/**
3237+
* Amend the calendar info with database row data
3238+
*
3239+
* @param array $row
3240+
* @param array $calendar
3241+
*
3242+
* @return array
3243+
*/
3244+
private function rowToCalendar($row, array $calendar): array {
3245+
foreach ($this->propertyMap as $xmlName => [$dbName, $type]) {
3246+
$value = $row[$dbName];
3247+
if ($value !== null) {
3248+
settype($value, $type);
3249+
}
3250+
$calendar[$xmlName] = $value;
3251+
}
3252+
return $calendar;
3253+
}
3254+
3255+
/**
3256+
* Amend the subscription info with database row data
3257+
*
3258+
* @param array $row
3259+
* @param array $subscription
3260+
*
3261+
* @return array
3262+
*/
3263+
private function rowToSubscription($row, array $subscription): array {
3264+
foreach ($this->subscriptionPropertyMap as $xmlName => [$dbName, $type]) {
3265+
$value = $row[$dbName];
3266+
if ($value !== null) {
3267+
settype($value, $type);
3268+
}
3269+
$subscription[$xmlName] = $value;
3270+
}
3271+
return $subscription;
3272+
}
32663273
}

0 commit comments

Comments
 (0)