diff --git a/CHANGELOG.md b/CHANGELOG.md
index 543d5f4d7a40613c9b616ad7b81639fd795793ee..b64cf20c88521b7f26aff72b189af1bcaf3ced32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,16 @@
# Changelog
+## 3.5.4 - 2022-12-22
+### Fixed
+- Handling of Email VALARMs
+
+## 3.5.3 - 2022-12-15
+### Fixed
+- Delete X-ALT-DESC property on changing description
+- Contrast issue with share icon
+- Location in booking VEVENT
+
## 3.5.2 - 2022-10-27
### Fixed
- Event calendar picker out of sync after moving event
diff --git a/appinfo/info.xml b/appinfo/info.xml
index 64487f58e7ab7f7d2b58921472693f76efab9148..195c859c98ff72c11baf5cbff4251033fa851f9b 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -15,7 +15,7 @@
* ☑️ Tasks! See tasks with a due date directly in the calendar
* 🙈 **We’re not reinventing the wheel!** Based on the great [c-dav library](https://github.com/nextcloud/cdav-library), [ical.js](https://github.com/mozilla-comm/ical.js) and [fullcalendar](https://github.com/fullcalendar/fullcalendar) libraries.
]]>
- 3.5.2
+ 3.5.4
agpl
Anna Larch
Nextcloud Groupware Team
diff --git a/lib/Service/Appointments/BookingCalendarWriter.php b/lib/Service/Appointments/BookingCalendarWriter.php
index 9559d514e4764d70645df9709d7a245f024bc9db..1857f3a89dbd5e7b6bb4914bf83ee317e35e85b5 100644
--- a/lib/Service/Appointments/BookingCalendarWriter.php
+++ b/lib/Service/Appointments/BookingCalendarWriter.php
@@ -166,6 +166,10 @@ class BookingCalendarWriter {
$vcalendar->VEVENT->add($alarm);
}
+ if ($config->getLocation() !== null) {
+ $vcalendar->VEVENT->add('LOCATION', $config->getLocation());
+ }
+
$vcalendar->VEVENT->add('X-NC-APPOINTMENT', $config->getToken());
$filename = $this->random->generate(32, ISecureRandom::CHAR_ALPHANUMERIC);
diff --git a/package-lock.json b/package-lock.json
index 7289a41867adecb0ddf1244f874b1d5d598e2b29..48205b81d5428790b9b524984f6a43ee0d6474c7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "calendar",
- "version": "3.5.2",
+ "version": "3.5.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "calendar",
- "version": "3.5.2",
+ "version": "3.5.4",
"license": "agpl",
"dependencies": {
"@fullcalendar/core": "5.11.0",
diff --git a/package.json b/package.json
index 98ecf87203f80886e1fff834eaedb0e5908d3e7c..b4067d429cffeeee6394285c13d2007717319ad3 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "calendar",
"description": "A calendar app for Nextcloud. Easily sync events from various devices, share and edit them online.",
- "version": "3.5.2",
+ "version": "3.5.4",
"author": "Georg Ehrke ",
"contributors": [
"Georg Ehrke ",
diff --git a/src/components/AppNavigation/CalendarList/CalendarListItem.vue b/src/components/AppNavigation/CalendarList/CalendarListItem.vue
index 25d30fedf9c3aa4f011ba2c9b88dc541782eab38..0d5106b1549814e67eb42395c78877de752c2679 100644
--- a/src/components/AppNavigation/CalendarList/CalendarListItem.vue
+++ b/src/components/AppNavigation/CalendarList/CalendarListItem.vue
@@ -517,6 +517,6 @@ export default {
diff --git a/src/store/calendarObjectInstance.js b/src/store/calendarObjectInstance.js
index d43260af09c92f604de87d4797172d69c78c26a6..a23e95f8f678b8a794443a1b208c5d4e379625ab 100644
--- a/src/store/calendarObjectInstance.js
+++ b/src/store/calendarObjectInstance.js
@@ -34,7 +34,9 @@ import {
import {
getAmountAndUnitForTimedEvents,
getAmountHoursMinutesAndUnitForAllDayEvents,
- getTotalSecondsFromAmountAndUnitForTimedEvents, getTotalSecondsFromAmountHourMinutesAndUnitForAllDayEvents,
+ getTotalSecondsFromAmountAndUnitForTimedEvents,
+ getTotalSecondsFromAmountHourMinutesAndUnitForAllDayEvents,
+ updateEmailAlarms,
} from '../utils/alarms.js'
import {
getClosestCSS3ColorNameForHex,
@@ -332,6 +334,9 @@ const mutations = {
}
}
+ // Delete custom description properties
+ calendarObjectInstance.eventComponent.deleteAllProperties('X-ALT-DESC')
+
calendarObjectInstance.eventComponent.description = description
calendarObjectInstance.description = description
},
@@ -1538,6 +1543,8 @@ const actions = {
const eventComponent = state.calendarObjectInstance.eventComponent
const calendarObject = state.calendarObject
+ updateEmailAlarms(eventComponent)
+
if (eventComponent.isDirty()) {
const isForkedItem = eventComponent.primaryItem !== null
let original = null
diff --git a/src/utils/alarms.js b/src/utils/alarms.js
index 254a664dd9a9f2524b1b1375ccbfc64e2b3239dd..a77be36803c47585fe246c3bf859e959b7579756 100644
--- a/src/utils/alarms.js
+++ b/src/utils/alarms.js
@@ -2,6 +2,7 @@
* @copyright Copyright (c) 2019 Georg Ehrke
*
* @author Georg Ehrke
+ * @author Richard Steinmetz
*
* @license AGPL-3.0-or-later
*
@@ -20,6 +21,9 @@
*
*/
+import { AttendeeProperty, Property } from '@nextcloud/calendar-js'
+import { translate as t } from '@nextcloud/l10n'
+
/**
* Get the factor for a given unit
*
@@ -212,3 +216,44 @@ export function getTotalSecondsFromAmountHourMinutesAndUnitForAllDayEvents(amoun
return amount
}
+
+/**
+ * Propagate data from an event component to all EMAIL alarm components.
+ * An alarm component must contain a description, summary and all attendees to be notified.
+ * We don't have a separate UI for maintaining attendees of an alarm, so we just copy them from the event.
+ *
+ * https://www.rfc-editor.org/rfc/rfc5545#section-3.6.6
+ *
+ * @param {AbstractRecurringComponent} eventComponent
+ */
+export function updateEmailAlarms(eventComponent) {
+ for (const alarmComponent of eventComponent.getAlarmIterator()) {
+ if (alarmComponent.action !== 'EMAIL') {
+ continue
+ }
+
+ alarmComponent.deleteAllProperties('SUMMARY')
+ const summaryProperty = eventComponent.getFirstProperty('SUMMARY')
+ if (summaryProperty) {
+ alarmComponent.addProperty(summaryProperty.clone())
+ } else {
+ const defaultSummary = t('calendar', 'Untitled event')
+ alarmComponent.addProperty(new Property('SUMMARY', defaultSummary))
+ }
+
+ if (!alarmComponent.hasProperty('DESCRIPTION')) {
+ const defaultDescription = t('calendar', 'This is an event reminder.')
+ alarmComponent.addProperty(new Property('DESCRIPTION', defaultDescription))
+ }
+
+ alarmComponent.deleteAllProperties('ATTENDEE')
+ for (const attendee of eventComponent.getAttendeeIterator()) {
+ if (['RESOURCE', 'ROOM'].includes(attendee.userType)) {
+ continue
+ }
+
+ // Only copy the email address (value) of the attendee
+ alarmComponent.addProperty(new AttendeeProperty('ATTENDEE', attendee.value))
+ }
+ }
+}