-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
feat(dav): store multiple default calendar alarms as JSON #61832
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -138,6 +138,15 @@ class CalDavBackend extends AbstractBackend implements SyncSupport, Subscription | |
| public const CLASSIFICATION_PRIVATE = 1; | ||
| public const CLASSIFICATION_CONFIDENTIAL = 2; | ||
|
|
||
| public const DEFAULT_ALARMS_PART_DAY_PROPERTY = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}default-alarms-part-day'; | ||
| public const DEFAULT_ALARMS_FULL_DAY_PROPERTY = '{' . \OCA\DAV\DAV\Sharing\Plugin::NS_NEXTCLOUD . '}default-alarms-full-day'; | ||
|
|
||
| /** @var string[] DB columns for calendar properties outside propertyMap (custom serialization). */ | ||
| private const SERIALIZED_CALENDAR_DB_COLUMNS = [ | ||
| 'default_alarms_pday', | ||
| 'default_alarms_fday', | ||
| ]; | ||
|
|
||
| /** | ||
| * List of CalDAV properties, and how they map to database field names and their type | ||
| * Add your own properties by simply adding on to this array. | ||
|
|
@@ -326,7 +335,7 @@ public function getCalendarsForUser($principalUri) { | |
| return $this->atomic(function () use ($principalUri) { | ||
| $principalUriOriginal = $principalUri; | ||
| $principalUri = $this->convertPrincipal($principalUri, true); | ||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = $this->getCalendarMergeSerializedProperties(); | ||
| $fields[] = 'id'; | ||
| $fields[] = 'uri'; | ||
| $fields[] = 'synctoken'; | ||
|
|
@@ -382,10 +391,9 @@ public function getCalendarsForUser($principalUri) { | |
| $principals = array_merge($principals, $this->principalBackend->getCircleMembership($principalUriOriginal)); | ||
| $principals[] = $principalUri; | ||
|
|
||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = array_map(function (string $field) { | ||
| return 'a.' . $field; | ||
| }, $fields); | ||
| }, $this->getCalendarMergeSerializedProperties()); | ||
| $fields[] = 'a.id'; | ||
| $fields[] = 'a.uri'; | ||
| $fields[] = 'a.synctoken'; | ||
|
|
@@ -468,7 +476,7 @@ public function getCalendarsForUser($principalUri) { | |
| */ | ||
| public function getUsersOwnCalendars($principalUri) { | ||
| $principalUri = $this->convertPrincipal($principalUri, true); | ||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = $this->getCalendarMergeSerializedProperties(); | ||
| $fields[] = 'id'; | ||
| $fields[] = 'uri'; | ||
| $fields[] = 'synctoken'; | ||
|
|
@@ -514,7 +522,7 @@ public function getUsersOwnCalendars($principalUri) { | |
| * @return array | ||
| */ | ||
| public function getPublicCalendars() { | ||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = array_map(static fn (string $field): string => 'a.' . $field, $this->getCalendarMergeSerializedProperties()); | ||
| $fields[] = 'a.id'; | ||
| $fields[] = 'a.uri'; | ||
| $fields[] = 'a.synctoken'; | ||
|
|
@@ -572,7 +580,7 @@ public function getPublicCalendars() { | |
| * @throws NotFound | ||
| */ | ||
| public function getPublicCalendar($uri) { | ||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = array_map(static fn (string $field): string => 'a.' . $field, $this->getCalendarMergeSerializedProperties()); | ||
| $fields[] = 'a.id'; | ||
| $fields[] = 'a.uri'; | ||
| $fields[] = 'a.synctoken'; | ||
|
|
@@ -631,7 +639,7 @@ public function getPublicCalendar($uri) { | |
| * @return array|null | ||
| */ | ||
| public function getCalendarByUri($principal, $uri) { | ||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = $this->getCalendarMergeSerializedProperties(); | ||
| $fields[] = 'id'; | ||
| $fields[] = 'uri'; | ||
| $fields[] = 'synctoken'; | ||
|
|
@@ -681,7 +689,7 @@ public function getCalendarByUri($principal, $uri) { | |
| * @return array|null | ||
| */ | ||
| public function getCalendarById(int $calendarId): ?array { | ||
| $fields = array_column($this->propertyMap, 0); | ||
| $fields = $this->getCalendarMergeSerializedProperties(); | ||
| $fields[] = 'id'; | ||
| $fields[] = 'uri'; | ||
| $fields[] = 'synctoken'; | ||
|
|
@@ -850,9 +858,29 @@ public function createCalendar($principalUri, $calendarUri, array $properties) { | |
| foreach ($this->propertyMap as $xmlName => [$dbName, $type]) { | ||
| if (isset($properties[$xmlName])) { | ||
| $values[$dbName] = $properties[$xmlName]; | ||
| if ($dbName === 'default_alarm_pday') { | ||
| $values['default_alarms_pday'] = DefaultCalendarAlarms::encodeFromLegacyInt( | ||
| $properties[$xmlName] !== null ? (int)$properties[$xmlName] : null, | ||
| ); | ||
| } elseif ($dbName === 'default_alarm_fday') { | ||
| $values['default_alarms_fday'] = DefaultCalendarAlarms::encodeFromLegacyInt( | ||
| $properties[$xmlName] !== null ? (int)$properties[$xmlName] : null, | ||
| ); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if (isset($properties[self::DEFAULT_ALARMS_PART_DAY_PROPERTY])) { | ||
| $encoded = DefaultCalendarAlarms::validateAndEncode($properties[self::DEFAULT_ALARMS_PART_DAY_PROPERTY]); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should not be validating data in the storage backend, the job of the storage backed in to store and retrieve data, not to make sure that that data is correct. |
||
| $values['default_alarms_pday'] = $encoded; | ||
| $values['default_alarm_pday'] = DefaultCalendarAlarms::legacyIntFromJson($encoded); | ||
| } | ||
| if (isset($properties[self::DEFAULT_ALARMS_FULL_DAY_PROPERTY])) { | ||
| $encoded = DefaultCalendarAlarms::validateAndEncode($properties[self::DEFAULT_ALARMS_FULL_DAY_PROPERTY]); | ||
| $values['default_alarms_fday'] = $encoded; | ||
| $values['default_alarm_fday'] = DefaultCalendarAlarms::legacyIntFromJson($encoded); | ||
| } | ||
|
|
||
| [$calendarId, $calendarData] = $this->atomic(function () use ($values) { | ||
| $query = $this->db->getQueryBuilder(); | ||
| $query->insert('calendars'); | ||
|
|
@@ -891,18 +919,42 @@ public function createCalendar($principalUri, $calendarUri, array $properties) { | |
| public function updateCalendar($calendarId, PropPatch $propPatch) { | ||
| $supportedProperties = array_keys($this->propertyMap); | ||
| $supportedProperties[] = '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp'; | ||
| $supportedProperties[] = self::DEFAULT_ALARMS_PART_DAY_PROPERTY; | ||
| $supportedProperties[] = self::DEFAULT_ALARMS_FULL_DAY_PROPERTY; | ||
|
|
||
| $propPatch->handle($supportedProperties, function ($mutations) use ($calendarId) { | ||
| $storedDefaultAlarmsJson = $this->getCalendarDefaultAlarmsJson($calendarId); | ||
| $newValues = []; | ||
| foreach ($mutations as $propertyName => $propertyValue) { | ||
| switch ($propertyName) { | ||
| case '{' . Plugin::NS_CALDAV . '}schedule-calendar-transp': | ||
| $fieldName = 'transparent'; | ||
| $newValues[$fieldName] = (int)($propertyValue->getValue() === 'transparent'); | ||
| break; | ||
| case self::DEFAULT_ALARMS_PART_DAY_PROPERTY: | ||
| $encoded = DefaultCalendarAlarms::validateAndEncode($propertyValue); | ||
| $newValues['default_alarms_pday'] = $encoded; | ||
| $newValues['default_alarm_pday'] = DefaultCalendarAlarms::legacyIntFromJson($encoded); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove all the legacy encodings. |
||
| break; | ||
| case self::DEFAULT_ALARMS_FULL_DAY_PROPERTY: | ||
| $encoded = DefaultCalendarAlarms::validateAndEncode($propertyValue); | ||
| $newValues['default_alarms_fday'] = $encoded; | ||
| $newValues['default_alarm_fday'] = DefaultCalendarAlarms::legacyIntFromJson($encoded); | ||
| break; | ||
| default: | ||
| $fieldName = $this->propertyMap[$propertyName][0]; | ||
| $newValues[$fieldName] = $propertyValue; | ||
| if ($fieldName === 'default_alarm_pday') { | ||
| $newValues['default_alarms_pday'] = DefaultCalendarAlarms::mergeLegacyIntIntoJson( | ||
| $storedDefaultAlarmsJson['default_alarms_pday'], | ||
| $propertyValue !== null ? (int)$propertyValue : null, | ||
| ); | ||
| } elseif ($fieldName === 'default_alarm_fday') { | ||
| $newValues['default_alarms_fday'] = DefaultCalendarAlarms::mergeLegacyIntIntoJson( | ||
| $storedDefaultAlarmsJson['default_alarms_fday'], | ||
| $propertyValue !== null ? (int)$propertyValue : null, | ||
| ); | ||
| } | ||
| break; | ||
| } | ||
| } | ||
|
|
@@ -3968,9 +4020,56 @@ private function rowToCalendar($row, array $calendar): array { | |
| } | ||
| $calendar[$xmlName] = $value; | ||
| } | ||
|
|
||
| $calendar[self::DEFAULT_ALARMS_PART_DAY_PROPERTY] = DefaultCalendarAlarms::formatForCalDav( | ||
| isset($row['default_alarms_pday']) ? (string)$row['default_alarms_pday'] : null, | ||
| isset($row['default_alarm_pday']) && $row['default_alarm_pday'] !== null ? (int)$row['default_alarm_pday'] : null, | ||
| ); | ||
| $calendar[self::DEFAULT_ALARMS_FULL_DAY_PROPERTY] = DefaultCalendarAlarms::formatForCalDav( | ||
| isset($row['default_alarms_fday']) ? (string)$row['default_alarms_fday'] : null, | ||
| isset($row['default_alarm_fday']) && $row['default_alarm_fday'] !== null ? (int)$row['default_alarm_fday'] : null, | ||
| ); | ||
|
|
||
| return $calendar; | ||
| } | ||
|
|
||
| /** | ||
| * calendars-table SELECT columns: propertyMap DB fields plus columns for | ||
| * CalDAV properties stored outside propertyMap (custom serialization). | ||
| * | ||
| * @return string[] | ||
| */ | ||
| private function getCalendarMergeSerializedProperties(): array { | ||
| return array_merge( | ||
| array_column($this->propertyMap, 0), | ||
| self::SERIALIZED_CALENDAR_DB_COLUMNS, | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * @return array{default_alarms_pday: ?string, default_alarms_fday: ?string} | ||
| */ | ||
| private function getCalendarDefaultAlarmsJson(int $calendarId): array { | ||
| $query = $this->db->getQueryBuilder(); | ||
| $query->select('default_alarms_pday', 'default_alarms_fday') | ||
| ->from('calendars') | ||
| ->where($query->expr()->eq('id', $query->createNamedParameter($calendarId, IQueryBuilder::PARAM_INT))) | ||
| ->setMaxResults(1); | ||
| $row = $query->executeQuery()->fetchAssociative(); | ||
|
|
||
| if ($row === false) { | ||
| return [ | ||
| 'default_alarms_pday' => null, | ||
| 'default_alarms_fday' => null, | ||
| ]; | ||
| } | ||
|
|
||
| return [ | ||
| 'default_alarms_pday' => $row['default_alarms_pday'] !== null ? (string)$row['default_alarms_pday'] : null, | ||
| 'default_alarms_fday' => $row['default_alarms_fday'] !== null ? (string)$row['default_alarms_fday'] : null, | ||
| ]; | ||
| } | ||
|
|
||
| /** | ||
| * Amend the subscription info with database row data | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be part of the property map below.