Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/mixins/PropertyMixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* See inline for more documentation
*/

import AccountPlusOutline from 'vue-material-design-icons/AccountPlusOutline.vue'
import Bell from 'vue-material-design-icons/BellOutline.vue'
import Briefcase from 'vue-material-design-icons/BriefcaseOutline.vue'
import Check from 'vue-material-design-icons/Check.vue'
Expand All @@ -21,6 +22,7 @@ import TextBoxOutline from 'vue-material-design-icons/TextBoxOutline.vue'

export default {
components: {
AccountPlusOutline,
Briefcase,
Check,
Eye,
Expand Down
10 changes: 10 additions & 0 deletions src/models/event.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ function getDefaultEventObject(props = {}) {
categories: [],
// Attachments of this event
attachments: [],
// Invitation forwarding
invitationForwarding: 'TRUE',
...props,
}
}
Expand Down Expand Up @@ -172,6 +174,10 @@ function mapEventComponentToEventObject(eventComponent) {
}
}

if (eventComponent.hasProperty('X-NC-INVITATION-FORWARDING')) {
eventObject.invitationForwarding = eventComponent.getFirstPropertyFirstValue('X-NC-INVITATION-FORWARDING')
}

return eventObject
}

Expand Down Expand Up @@ -221,6 +227,10 @@ function copyCalendarObjectInstanceIntoEventComponent(eventObject, eventComponen
eventComponent.addProperty(rule)
}

if (eventObject.eventComponent.hasProperty('X-NC-INVITATION-FORWARDING')) {
eventComponent.updatePropertyWithValue('X-NC-INVITATION-FORWARDING', eventObject.invitationForwarding)
}

if (eventObject.customColor) {
eventComponent.color = getClosestCSS3ColorNameForHex(eventObject.customColor)
}
Expand Down
12 changes: 12 additions & 0 deletions src/store/calendarObjectInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,18 @@ export default defineStore('calendarObjectInstance', {
calendarObjectInstance.timeTransparency = timeTransparency
},

/**
* Change the invitation-forwarding property of an event
*
* @param {object} data The destructuring object
* @param {object} data.calendarObjectInstance The calendarObjectInstance object
* @param {string} data.invitationForwarding Invitation forwarding value
*/
Comment thread
kesselb marked this conversation as resolved.
changeInvitationForwarding({ calendarObjectInstance, invitationForwarding }) {
calendarObjectInstance.eventComponent.updatePropertyWithValue('X-NC-INVITATION-FORWARDING', invitationForwarding)
calendarObjectInstance.invitationForwarding = invitationForwarding
},

/**
* Change the customized color of an event
*
Expand Down
41 changes: 41 additions & 0 deletions src/views/EditFull.vue
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@
:propModel="rfcProps.color"
:value="color"
@update:value="updateColor" />
<PropertySelect
v-if="showInvitationForwarding"
:isReadOnly="isReadOnly || isViewedByOrganizer === false"
:propModel="propInvitationForwarding"
:value="invitationForwarding"
@update:value="updateInvitationForwarding" />
</div>
</div>

Expand Down Expand Up @@ -333,6 +339,7 @@
import IconCancel from '@mdi/svg/svg/cancel.svg?raw'
import IconDelete from '@mdi/svg/svg/delete.svg?raw'
import { Parameter } from '@nextcloud/calendar-js'
import { translate as t } from '@nextcloud/l10n'
import moment from '@nextcloud/moment'
import { generateUrl } from '@nextcloud/router'
import {
Expand Down Expand Up @@ -378,6 +385,7 @@ import useCalendarObjectInstanceStore from '../store/calendarObjectInstance.js'
import usePrincipalsStore from '../store/principals.js'
import useSettingsStore from '../store/settings.js'
import logger from '../utils/logger.js'
import { isAfterVersion } from '../utils/nextcloudVersion.ts'

export default {
name: 'EditFull',
Expand Down Expand Up @@ -447,6 +455,19 @@ export default {

showCancelDialog: false,
showFullModal: true,

propInvitationForwarding: {
readableName: t('calendar', 'Allow forwarding'),
icon: 'AccountPlusOutline',
options: [
{ value: 'TRUE', label: t('calendar', 'Anyone with the invitation can respond') },
{ value: 'FALSE', label: t('calendar', 'Only invited attendees can respond') },
],

multiple: false,
info: t('calendar', 'Choose "Only invited attendees can respond" to prevent attendees from forwarding the invitation to others.'),
defaultValue: 'TRUE',
},
}
},

Expand Down Expand Up @@ -476,6 +497,10 @@ export default {
return this.calendarObjectInstance?.timeTransparency || null
},

invitationForwarding() {
return this.calendarObjectInstance?.invitationForwarding ?? null
},

subTitle() {
if (!this.calendarObjectInstance) {
return ''
Expand Down Expand Up @@ -506,6 +531,10 @@ export default {
return ['ROOM', 'RESOURCE'].includes(attendee.attendeeProperty.userType)
})
},

showInvitationForwarding() {
return isAfterVersion(34)
},
},

mounted() {
Expand Down Expand Up @@ -585,6 +614,18 @@ export default {
})
},

/**
* Allow or disallow forwarding of this invitation
*
* @param {string} invitationForwarding Invitation forwarding value
*/
updateInvitationForwarding(invitationForwarding) {
this.calendarObjectInstanceStore.changeInvitationForwarding({
calendarObjectInstance: this.calendarObjectInstance,
invitationForwarding,
})
},

/**
* Adds a category to the event
*
Expand Down
70 changes: 68 additions & 2 deletions tests/javascript/unit/models/event.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import { getDefaultEventObject, mapEventComponentToEventObject } from "../../../../src/models/event.js";
import { copyCalendarObjectInstanceIntoEventComponent, getDefaultEventObject, mapEventComponentToEventObject } from '../../../../src/models/event.js'
import { getDateFromDateTimeValue } from '../../../../src/utils/date.js'
import { getHexForColorName } from '../../../../src/utils/color.js'
import { mapAlarmComponentToAlarmObject } from '../../../../src/models/alarm.js'
Expand Down Expand Up @@ -62,6 +62,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDefaultRecurrenceRuleObject).toHaveBeenCalledTimes(1)
Expand Down Expand Up @@ -104,6 +105,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
otherProp: 'foo',
})

Expand Down Expand Up @@ -154,6 +156,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -221,7 +224,8 @@ describe('Test suite: Event model (models/event.js)', () => {
alarms: [],
customColor: null,
categories: [],
attachments: []
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -289,6 +293,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

const alarms = eventComponent.getAlarmList()
Expand Down Expand Up @@ -343,6 +348,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: ['BUSINESS', 'HUMAN RESOURCES'],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -399,6 +405,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: '#eeffee',
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -458,6 +465,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -514,6 +522,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -567,6 +576,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -620,6 +630,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -677,6 +688,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -733,6 +745,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -787,6 +800,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand Down Expand Up @@ -844,6 +858,7 @@ describe('Test suite: Event model (models/event.js)', () => {
customColor: null,
categories: [],
attachments: [],
invitationForwarding: 'TRUE',
})

expect(getDateFromDateTimeValue).toHaveBeenCalledTimes(2)
Expand All @@ -858,4 +873,55 @@ describe('Test suite: Event model (models/event.js)', () => {

expect(getDefaultRecurrenceRuleObject).toHaveBeenCalledTimes(1)
})

it('should default invitation forwarding to TRUE', () => {
getDefaultRecurrenceRuleObject
.mockReturnValueOnce({
defaultRecurrenceObject: true,
})

expect(getDefaultEventObject().invitationForwarding).toEqual('TRUE')
})

it('should map an event component custom invitation forwarding property', () => {
const recurrenceId = DateTimeValue.fromJSDate(new Date(Date.UTC(2016, 7, 16, 7, 0, 0)), true)
const eventComponent = getEventComponentFromAsset('vcalendars/vcalendar-event-timed', recurrenceId)
eventComponent.updatePropertyWithValue('X-NC-INVITATION-FORWARDING', 'FALSE')

const mockDate1 = new Date()
const mockDate2 = new Date()
getDateFromDateTimeValue
.mockReturnValueOnce(mockDate1)
.mockReturnValueOnce(mockDate2)

getDefaultRecurrenceRuleObject
.mockReturnValueOnce({
defaultRecurrenceObject: true,
})

expect(mapEventComponentToEventObject(eventComponent).invitationForwarding).toEqual('FALSE')
})

it('should copy the custom invitation forwarding property into a new event component', () => {
const recurrenceId = DateTimeValue.fromJSDate(new Date(Date.UTC(2016, 7, 16, 7, 0, 0)), true)
const sourceEventComponent = getEventComponentFromAsset('vcalendars/vcalendar-event-timed', recurrenceId)
const targetEventComponent = getEventComponentFromAsset('vcalendars/vcalendar-event-timed', recurrenceId)
sourceEventComponent.updatePropertyWithValue('X-NC-INVITATION-FORWARDING', 'FALSE')

const eventObject = getDefaultEventObject({
eventComponent: sourceEventComponent,
title: sourceEventComponent.title,
location: sourceEventComponent.location,
description: sourceEventComponent.description,
accessClass: sourceEventComponent.accessClass,
status: sourceEventComponent.status,
timeTransparency: sourceEventComponent.timeTransparency,
invitationForwarding: 'FALSE',
})

copyCalendarObjectInstanceIntoEventComponent(eventObject, targetEventComponent)

expect(targetEventComponent.hasProperty('X-NC-INVITATION-FORWARDING')).toBe(true)
expect(targetEventComponent.getFirstPropertyFirstValue('X-NC-INVITATION-FORWARDING')).toBe('FALSE')
})
})
Loading