diff --git a/src/models/calendarTrashBin.js b/src/models/calendarTrashBin.js index f0fac8da..8f403207 100644 --- a/src/models/calendarTrashBin.js +++ b/src/models/calendarTrashBin.js @@ -9,7 +9,7 @@ import { DavCollection } from './davCollection.js' import * as NS from '../utility/namespaceUtility.js' -import { VObject } from './vobject.js' +import { DeletedCalendarObject } from './deletedCalendarObject.js' import * as XMLUtility from '../utility/xmlUtility.js' export class CalendarTrashBin extends DavCollection { @@ -20,7 +20,7 @@ export class CalendarTrashBin extends DavCollection { constructor(...args) { super(...args) - super._registerObjectFactory('text/calendar', VObject) + super._registerObjectFactory('text/calendar', DeletedCalendarObject) super._exposeProperty('retentionDuration', NS.NEXTCLOUD, 'trash-bin-retention-duration') } @@ -31,12 +31,8 @@ export class CalendarTrashBin extends DavCollection { ) skeleton.children.push({ name: [NS.DAV, 'prop'], - children: VObject.getPropFindList() - .map((p) => ({ name: p })) - .concat([ - { name: [NS.NEXTCLOUD, 'calendar-uri'] }, - { name: [NS.NEXTCLOUD, 'deleted-at'] }, - ]), + children: DeletedCalendarObject.getPropFindList() + .map((p) => ({ name: p })), }) skeleton.children.push({ name: [NS.IETF_CALDAV, 'filter'], diff --git a/src/models/deletedCalendarObject.js b/src/models/deletedCalendarObject.js new file mode 100644 index 00000000..31516f8b --- /dev/null +++ b/src/models/deletedCalendarObject.js @@ -0,0 +1,65 @@ +/** + * CDAV Library + * + * This library is part of the Nextcloud project + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { VObject } from './vobject.js' +import * as NS from '../utility/namespaceUtility.js' + +/** + * This class represents a deleted calendar object from a calendar trash bin. + * + * @augments VObject + */ +export class DeletedCalendarObject extends VObject { + + /** + * @inheritDoc + */ + constructor(...args) { + super(...args) + + super._exposeProperty('calendarUri', NS.NEXTCLOUD, 'calendar-uri') + super._exposeProperty('sourceCalendarUri', NS.NEXTCLOUD, 'source-calendar-uri') + super._exposeProperty('calendarOwnerPrincipalUri', NS.NEXTCLOUD, 'calendar-owner-principal-uri') + super._exposeProperty('deletedAt', NS.NEXTCLOUD, 'deleted-at') + } + + get calendarUri() { + return this._props[`{${NS.NEXTCLOUD}}calendar-uri`] + } + + get sourceCalendarUri() { + return this._props[`{${NS.NEXTCLOUD}}source-calendar-uri`] + } + + get calendarOwnerPrincipalUri() { + return this._props[`{${NS.NEXTCLOUD}}calendar-owner-principal-uri`] + } + + get deletedAt() { + return this._props[`{${NS.NEXTCLOUD}}deleted-at`] + } + + get delegator() { + return this._props[`{${NS.NEXTCLOUD}}delegator`] + } + + /** + * @inheritDoc + */ + static getPropFindList() { + return super.getPropFindList().concat([ + [NS.NEXTCLOUD, 'calendar-uri'], + [NS.NEXTCLOUD, 'source-calendar-uri'], + [NS.NEXTCLOUD, 'calendar-owner-principal-uri'], + [NS.NEXTCLOUD, 'deleted-at'], + [NS.NEXTCLOUD, 'delegator'], + ]) + } + +} diff --git a/src/parser.js b/src/parser.js index ec65cdce..149d174a 100644 --- a/src/parser.js +++ b/src/parser.js @@ -183,6 +183,9 @@ export default class Parser { this.registerParser('{http://nextcloud.com/ns}owner-displayname', Parser.text) this.registerParser('{http://nextcloud.com/ns}deleted-at', Parser.iso8601DateTime) this.registerParser('{http://nextcloud.com/ns}calendar-uri', Parser.text) + this.registerParser('{http://nextcloud.com/ns}source-calendar-uri', Parser.text) + this.registerParser('{http://nextcloud.com/ns}calendar-owner-principal-uri', Parser.text) + this.registerParser('{http://nextcloud.com/ns}delegator', Parser.text) this.registerParser('{http://nextcloud.com/ns}has-photo', Parser.bool) this.registerParser('{http://nextcloud.com/ns}favorite', Parser.bool) this.registerParser('{http://nextcloud.com/ns}trash-bin-retention-duration', Parser.decInt) diff --git a/test/unit/models/deletedCalendarObjectTest.js b/test/unit/models/deletedCalendarObjectTest.js new file mode 100644 index 00000000..437c8ae7 --- /dev/null +++ b/test/unit/models/deletedCalendarObjectTest.js @@ -0,0 +1,59 @@ +/** + * CDAV Library + * + * This library is part of the Nextcloud project + * + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { describe, expect, it } from 'vitest' + +import { DeletedCalendarObject } from '../../../src/models/deletedCalendarObject.js' +import { VObject } from '../../../src/models/vobject.js' +import RequestMock from '../../mocks/request.mock.js' +import { DavCollection as DavCollectionMock } from '../../mocks/davCollection.mock.js' + +describe('DeletedCalendarObject model', () => { + + it('should inherit from VObject', () => { + const parent = new DavCollectionMock() + const request = new RequestMock() + const url = '/trash-bin/objects/deleted.ics' + const props = { + '{DAV:}getetag': '"etag"', + '{DAV:}getcontenttype': 'text/calendar', + '{DAV:}resourcetype': [], + '{urn:ietf:params:xml:ns:caldav}calendar-data': 'BEGIN:VCALENDAR\nEND:VCALENDAR', + } + + const object = new DeletedCalendarObject(parent, request, url, props) + expect(object).toEqual(expect.any(VObject)) + }) + + it('should expose deleted calendar object properties', () => { + const parent = new DavCollectionMock() + const request = new RequestMock() + const url = '/trash-bin/objects/deleted.ics' + const props = { + '{DAV:}getetag': '"etag"', + '{DAV:}getcontenttype': 'text/calendar', + '{DAV:}resourcetype': [], + '{urn:ietf:params:xml:ns:caldav}calendar-data': 'BEGIN:VCALENDAR\nEND:VCALENDAR', + '{http://nextcloud.com/ns}calendar-uri': 'calendar-1', + '{http://nextcloud.com/ns}source-calendar-uri': 'source', + '{http://nextcloud.com/ns}calendar-owner-principal-uri': 'principals/users/user', + '{http://nextcloud.com/ns}deleted-at': new Date('2026-05-20T10:11:12Z'), + '{http://nextcloud.com/ns}delegator': 'principals/users/owner', + } + + const object = new DeletedCalendarObject(parent, request, url, props) + + expect(object.calendarUri).toEqual('calendar-1') + expect(object.sourceCalendarUri).toEqual('source') + expect(object.calendarOwnerPrincipalUri).toEqual('principals/users/user') + expect(object.deletedAt).toEqual(new Date('2026-05-20T10:11:12Z')) + expect(object.delegator).toEqual('principals/users/owner') + }) + +})