import { eventToFullCalendarFormat, getCalendarVisibility } from '@/components/Calendar/utils/calendarUtils' import { Calendar, DelegationAccess } from '@/features/Calendars/CalendarTypes' import { AclEntry } from '@/features/Calendars/types/CalendarData' import { CalendarEvent } from '@/features/Events/EventsTypes' import { userOrganiser } from '@/features/User/userDataTypes' describe('getCalendarVisibility', () => { it("returns 'public' when {DAV:}authenticated has {DAV:}read", () => { const acl: AclEntry[] = [ { privilege: '{DAV:}read', principal: '{DAV:}authenticated', protected: true } ] expect(getCalendarVisibility(acl)).toBe('public') }) it("returns 'private' when {DAV:}authenticated only has read-free-busy", () => { const acl: AclEntry[] = [ { privilege: '{urn:ietf:params:xml:ns:caldav}read-free-busy', principal: '{DAV:}authenticated', protected: true } ] expect(getCalendarVisibility(acl)).toBe('private') }) it("returns 'private' when {DAV:}authenticated is not present", () => { const acl: AclEntry[] = [ { privilege: '{DAV:}read', principal: 'principals/users/123', protected: true } ] expect(getCalendarVisibility(acl)).toBe('private') }) it("ignores non-authenticated principals and still returns 'private'", () => { const acl: AclEntry[] = [ { privilege: '{DAV:}read', principal: 'principals/users/other', protected: true }, { privilege: '{DAV:}write', principal: 'principals/users/other', protected: true } ] expect(getCalendarVisibility(acl)).toBe('private') }) it('stops early when it finds a {DAV:}read for {DAV:}authenticated', () => { const acl: AclEntry[] = [ { privilege: '{DAV:}read', principal: '{DAV:}authenticated', protected: true }, { privilege: '{DAV:}write', principal: '{DAV:}authenticated', protected: true } ] expect(getCalendarVisibility(acl)).toBe('public') }) }) jest.mock('twake-i18n', () => ({ useI18n: () => ({ t: (key: string) => key }) })) const baseEvent: CalendarEvent = { uid: 'event-1', calId: 'user1/cal1', title: 'Test Event', start: '2024-01-15T10:00:00', end: '2024-01-15T11:00:00', allday: false, organizer: { cal_address: 'owner@example.com' } as userOrganiser, color: { light: '#FF0000' }, class: 'PUBLIC' } as unknown as CalendarEvent const makeCalendar = (overrides: Partial = {}): Calendar => ({ id: 'user1/cal1', name: 'Test Calendar', delegated: false, access: {} as DelegationAccess, owner: { emails: ['alice@example.com'], firstname: 'Alice' }, color: { light: '#FF0000' }, events: {}, ...overrides }) as Calendar const callFormat = ( event: CalendarEvent, calendars: Record, userAddress = 'alice@example.com', userId = 'user1' ) => eventToFullCalendarFormat([event], [], userId, userAddress, false, calendars) describe('eventToFullCalendarFormat - editable flag', () => { describe('personal calendar (non-delegated)', () => { const calendar = makeCalendar({ delegated: false }) it('is editable when user is organizer', () => { const event = { ...baseEvent, organizer: { cal_address: 'alice@example.com' } } as CalendarEvent const [result] = callFormat(event, { 'user1/cal1': calendar }) expect(result.editable).toBe(true) }) it('is not editable when user is not organizer', () => { const event = { ...baseEvent, organizer: { cal_address: 'other@example.com' } } as CalendarEvent const [result] = callFormat(event, { 'user1/cal1': calendar }) expect(result.editable).toBe(false) }) it('is not editable when pending', () => { const event = { ...baseEvent, organizer: { cal_address: 'alice@example.com' } } as CalendarEvent const [result] = eventToFullCalendarFormat( [event], [], 'user1', 'alice@example.com', true, { 'user1/cal1': calendar } ) expect(result.editable).toBe(false) }) }) describe('delegated calendar', () => { const writeDelegatedCalendar = makeCalendar({ id: 'user2/cal1', delegated: true, access: { write: true } as DelegationAccess, owner: { emails: ['owner@example.com'], firstname: 'Owner' } }) const readDelegatedCalendar = makeCalendar({ id: 'user2/cal1', delegated: true, access: { read: true } as DelegationAccess, owner: { emails: ['owner@example.com'], firstname: 'Owner' } }) const event = { ...baseEvent, calId: 'user2/cal1' } it('is editable when owner is organizer and delegated user has write rights', () => { const [result] = callFormat( { ...event, organizer: { cal_address: 'owner@example.com' } } as CalendarEvent, { 'user2/cal1': writeDelegatedCalendar } ) expect(result.editable).toBe(true) }) it('is not editable when owner is organizer but delegated user only has read access', () => { const [result] = callFormat( { ...event, organizer: { cal_address: 'owner@example.com' } } as CalendarEvent, { 'user2/cal1': readDelegatedCalendar } ) expect(result.editable).toBe(false) }) it('is not editable when owner is not organizer', () => { const [result] = callFormat( { ...event, organizer: { cal_address: 'someone-else@example.com' } } as CalendarEvent, { 'user2/cal1': writeDelegatedCalendar } ) expect(result.editable).toBe(false) }) it('is not editable when pending even if owner is organizer', () => { const [result] = eventToFullCalendarFormat( [ { ...event, organizer: { cal_address: 'owner@example.com' } } as CalendarEvent ], [], 'user1', 'alice@example.com', true, { 'user2/cal1': writeDelegatedCalendar } ) expect(result.editable).toBe(false) }) it('uses owner email not logged-in user email for organizer check', () => { // logged-in user is alice, owner is owner@example.com // organizer matches owner → editable const [result] = callFormat( { ...event, organizer: { cal_address: 'owner@example.com' } } as CalendarEvent, { 'user2/cal1': writeDelegatedCalendar }, 'alice@example.com' // logged-in user, should NOT be used for delegated ) expect(result.editable).toBe(true) }) }) })