From ea4d703419d9a7b7fc467071c760d7541af7af14 Mon Sep 17 00:00:00 2001 From: SebastianKrupinski Date: Sun, 1 Feb 2026 11:37:17 -0500 Subject: [PATCH 1/2] feat: read calendar ACL properly Signed-off-by: SebastianKrupinski --- .../EditCalendarModal/ShareItem.vue | 3 +- src/mixins/EditorMixin.js | 2 +- src/models/calendar.js | 12 ++++ tests/javascript/unit/models/calendar.test.js | 68 ++++++++++++++++--- 4 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/components/AppNavigation/EditCalendarModal/ShareItem.vue b/src/components/AppNavigation/EditCalendarModal/ShareItem.vue index c05fb059e3..07c8b2c7ea 100644 --- a/src/components/AppNavigation/EditCalendarModal/ShareItem.vue +++ b/src/components/AppNavigation/EditCalendarModal/ShareItem.vue @@ -107,8 +107,7 @@ export default { * @return {boolean} */ canBeSharedWritable() { - // TODO: read-write sharing is not implemented for federated calendars yet - return !this.sharee.isRemoteUser + return this.calendar.canCreateObject || this.calendar.canModifyObject }, }, diff --git a/src/mixins/EditorMixin.js b/src/mixins/EditorMixin.js index 85c746f6a2..ad327c4dcd 100644 --- a/src/mixins/EditorMixin.js +++ b/src/mixins/EditorMixin.js @@ -195,7 +195,7 @@ export default { return true } - return calendar.readOnly + return !calendar.canCreateObject && !calendar.canModifyObject }, isSharedWithMe() { if (!this.calendarObject) { diff --git a/src/models/calendar.js b/src/models/calendar.js index 6eec4d0d90..aec0ba750c 100644 --- a/src/models/calendar.js +++ b/src/models/calendar.js @@ -48,6 +48,12 @@ function getDefaultCalendarObject(props = {}) { canBeShared: false, // Whether or not the calendar can be published by me canBePublished: false, + // Whether or not I can create objects in this calendar + canCreateObject: false, + // Whether or not I can modify objects in this calendar + canModifyObject: false, + // Whether or not I can delete objects in this calendar + canDeleteObject: false, // Reference to cdav-lib object dav: false, // All calendar-objects from this calendar that have already been fetched @@ -86,6 +92,9 @@ function mapDavCollectionToCalendar(calendar, currentUserPrincipal) { const readOnly = !calendar.isWriteable() const canBeShared = calendar.isShareable() const canBePublished = calendar.isPublishable() + const canCreateObject = calendar.currentUserPrivilegeSet.includes('{DAV:}bind') || calendar.currentUserPrivilegeSet.includes('{DAV:}write') || calendar.currentUserPrivilegeSet.includes('{DAV:}all') === true + const canModifyObject = calendar.currentUserPrivilegeSet.includes('{DAV:}write-content') || calendar.currentUserPrivilegeSet.includes('{DAV:}write') || calendar.currentUserPrivilegeSet.includes('{DAV:}all') === true + const canDeleteObject = calendar.currentUserPrivilegeSet.includes('{DAV:}unbind') || calendar.currentUserPrivilegeSet.includes('{DAV:}write') || calendar.currentUserPrivilegeSet.includes('{DAV:}all') === true const order = calendar.order || 0 const url = calendar.url const publishURL = calendar.publishURL || null @@ -146,6 +155,9 @@ function mapDavCollectionToCalendar(calendar, currentUserPrincipal) { publishURL, canBeShared, canBePublished, + canCreateObject, + canModifyObject, + canDeleteObject, shares, timezone, transparency, diff --git a/tests/javascript/unit/models/calendar.test.js b/tests/javascript/unit/models/calendar.test.js index abc803a4d3..8c25ba382f 100644 --- a/tests/javascript/unit/models/calendar.test.js +++ b/tests/javascript/unit/models/calendar.test.js @@ -35,6 +35,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isSharedWithMe: false, canBeShared: false, canBePublished: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, dav: false, calendarObjects: [], fetchedTimeRanges: [], @@ -66,6 +69,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isSharedWithMe: false, canBeShared: false, canBePublished: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, dav: false, calendarObjects: [], fetchedTimeRanges: [], @@ -88,6 +94,7 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { enabled: true, timezone: 'BEGIN:VCALENDAR...END:VCALENDAR', transparency: 'opaque', + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -109,6 +116,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: 'BEGIN:VCALENDAR...END:VCALENDAR', transparency: 'opaque', url: '/foo/bar', @@ -135,6 +145,7 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { timezone: 'BEGIN:VCALENDAR...END:VCALENDAR', transparency: 'transparent', enabled: false, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -156,6 +167,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: 'BEGIN:VCALENDAR...END:VCALENDAR', transparency: 'transparent', url: '/foo/bar', @@ -179,7 +193,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isPublishable: () => true, order: undefined, publishURL: undefined, - enabled: undefined + enabled: undefined, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -201,6 +216,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -224,7 +242,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isPublishable: () => true, order: undefined, publishURL: undefined, - enabled: undefined + enabled: undefined, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -246,6 +265,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: true, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -269,7 +291,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isPublishable: () => true, order: undefined, publishURL: undefined, - enabled: true + enabled: true, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -291,6 +314,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -314,7 +340,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isPublishable: () => true, order: undefined, publishURL: undefined, - enabled: true + enabled: true, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -336,6 +363,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -359,7 +389,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isPublishable: () => true, order: undefined, publishURL: undefined, - enabled: true + enabled: true, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -381,6 +412,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -404,7 +438,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { isPublishable: () => true, order: undefined, publishURL: undefined, - enabled: true + enabled: true, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -426,6 +461,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -499,7 +537,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { '{http://owncloud.org/ns}read' ] } - ] + ], + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -527,6 +566,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -624,7 +666,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { '{http://owncloud.org/ns}read' ] } - ] + ], + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject)).toEqual({ @@ -644,6 +687,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: true, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: null, transparency: 'opaque', url: '/foo/bar', @@ -668,7 +714,8 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { order: undefined, publishURL: undefined, timezone: 'BEGIN:VCALENDAR...END:VCALENDAR', - enabled: false + enabled: false, + currentUserPrivilegeSet: [], } expect(mapDavCollectionToCalendar(cdavObject, { @@ -690,6 +737,9 @@ describe('Test suite: Calendar model (models/calendar.js)', () => { supportsJournals: false, supportsTasks: false, isSharedWithMe: false, + canCreateObject: false, + canDeleteObject: false, + canModifyObject: false, timezone: 'BEGIN:VCALENDAR...END:VCALENDAR', transparency: 'opaque', url: '/remote.php/dav/calendars/admin/personal/', From d06ae0f785aa1a0bece1272f3de0ea0216e3e15e Mon Sep 17 00:00:00 2001 From: SebastianKrupinski Date: Fri, 13 Feb 2026 12:29:55 -0500 Subject: [PATCH 2/2] fix: node test Signed-off-by: SebastianKrupinski --- vitest.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vitest.config.js b/vitest.config.js index 3b06614426..b2933a1f9b 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -25,7 +25,7 @@ export default defineConfig({ // Required for transforming CSS files pool: 'vmForks', // Increase timeouts for slow CI environments - testTimeout: 120000, // 2 minutes per test - hookTimeout: 30000, // 30 seconds for hooks + testTimeout: 300000, // 2 minutes per test + hookTimeout: 60000, // 60 seconds for hooks }, });