Skip to content
Open
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
47 changes: 47 additions & 0 deletions src/models/principal.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ function getDefaultPrincipalObject(props) {
principalId: null,
// The url of the default calendar for invitations
scheduleDefaultCalendarUrl: null,
// Room-specific properties (only for calendar-rooms)
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
...props,
}
}
Expand Down Expand Up @@ -91,6 +99,38 @@ function mapDavToPrincipal(dav) {
const url = dav.principalUrl
const userId = dav.userId

// Extract room-specific properties from DAV object, trimming string values defensively
const roomSeatingCapacity = dav.roomSeatingCapacity ?? null
const roomType = (dav.roomType ?? '').toString().trim() || null
const roomFeatures = (dav.roomFeatures ?? '').toString().trim() || null
// Strip leading/trailing whitespace and commas from building address to handle empty
// building-name fields, e.g. ", Science Park 140, 1098 XG, Amsterdam" → "Science Park 140, 1098 XG, Amsterdam"
const rawBuildingAddress = dav.roomBuildingAddress ?? null
const roomBuildingAddress = rawBuildingAddress
? rawBuildingAddress.replace(/^[\s,]+|[\s,]+$/g, '').trim() || null
: null
// Derive building name from address (everything before first comma): "Poppodium, Kerkstraat 10" → "Poppodium"
const roomBuildingName = roomBuildingAddress ? roomBuildingAddress.split(',')[0].trim() || null : null
// Room number (floor.room format, e.g. "2.17") is stored in room-building-room-number
const roomNumber = (dav.roomBuildingRoomNumber ?? '').toString().trim() || null

// Construct roomAddress for event LOCATION field from available properties
// Format: "Street (Building, Room X.XX)" — street-first for map/navigation apps
let roomAddress = null
if (roomBuildingAddress) {
const commaIdx = roomBuildingAddress.indexOf(',')
if (commaIdx > 0) {
const building = roomBuildingAddress.substring(0, commaIdx).trim()
const street = roomBuildingAddress.substring(commaIdx + 1).trim()
const detail = roomNumber ? building + ', Room ' + roomNumber : building
roomAddress = street + ' (' + detail + ')'
} else {
roomAddress = roomNumber
? roomBuildingAddress + ' (Room ' + roomNumber + ')'
: roomBuildingAddress
}
}

return getDefaultPrincipalObject({
id,
calendarUserType,
Expand All @@ -107,6 +147,13 @@ function mapDavToPrincipal(dav) {
principalId,
userId,
scheduleDefaultCalendarUrl,
roomSeatingCapacity,
roomType,
roomAddress,
roomFeatures,
roomBuildingName,
roomBuildingAddress,
roomNumber,
})
}

Expand Down
130 changes: 130 additions & 0 deletions tests/javascript/unit/models/principal.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: false,
principalId: null,
scheduleDefaultCalendarUrl: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

Expand All @@ -48,6 +55,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
principalId: 'bar',
otherProp: 'foo',
scheduleDefaultCalendarUrl: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

Expand Down Expand Up @@ -82,6 +96,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: false,
principalId: 'jane.doe',
userId: 'legacy-jane-doe-uid',
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

Expand Down Expand Up @@ -116,6 +137,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: false,
principalId: 'jane.doe',
userId: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

Expand Down Expand Up @@ -150,6 +178,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: false,
principalId: 'CGAH82BAS285H',
userId: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

Expand Down Expand Up @@ -184,6 +219,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: false,
principalId: 'projector-123',
userId: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

Expand Down Expand Up @@ -218,9 +260,90 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: true,
principalId: 'room-123',
userId: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})

it('should properly map a calendar-room-principal with room properties', () => {
const dav = {
addressBookHomes: undefined,
calendarHomes: [],
calendarUserAddressSet: [],
calendarUserType: 'ROOM',
displayname: 'Conference Room A',
email: 'conf-a@example.com',
principalScheme: 'principal:principals/calendar-rooms/conf-a',
principalUrl: '/remote.php/dav/principals/calendar-rooms/conf-a/',
scheduleInbox: null,
scheduleOutbox: null,
url: '/remote.php/dav/principals/calendar-rooms/conf-a/',
userId: null,
roomSeatingCapacity: 20,
roomType: 'conference-room',
roomFeatures: 'PROJECTOR,WHITEBOARD',
roomBuildingAddress: 'Building A, Main Street 1',
roomBuildingRoomNumber: '2.17',
}

expect(mapDavToPrincipal(dav)).toEqual({
id: 'L3JlbW90ZS5waHAvZGF2L3ByaW5jaXBhbHMvY2FsZW5kYXItcm9vbXMvY29uZi1hLw==',
dav,
calendarUserType: 'ROOM',
principalScheme: 'principal:principals/calendar-rooms/conf-a',
emailAddress: 'conf-a@example.com',
displayname: 'Conference Room A',
url: '/remote.php/dav/principals/calendar-rooms/conf-a/',
isUser: false,
isGroup: false,
isCircle: false,
isCalendarResource: false,
isCalendarRoom: true,
principalId: 'conf-a',
userId: null,
roomSeatingCapacity: 20,
roomType: 'conference-room',
roomFeatures: 'PROJECTOR,WHITEBOARD',
roomBuildingName: 'Building A',
roomBuildingAddress: 'Building A, Main Street 1',
roomNumber: '2.17',
roomAddress: 'Main Street 1 (Building A, Room 2.17)',
})
})

it('should strip leading commas and whitespace from roomBuildingAddress', () => {
const dav = {
addressBookHomes: undefined,
calendarHomes: [],
calendarUserAddressSet: [],
calendarUserType: 'ROOM',
displayname: 'AMS 0.11',
email: 'ams-011@example.com',
principalScheme: 'principal:principals/calendar-rooms/ams-011',
principalUrl: '/remote.php/dav/principals/calendar-rooms/ams-011/',
scheduleInbox: null,
scheduleOutbox: null,
url: '/remote.php/dav/principals/calendar-rooms/ams-011/',
userId: null,
roomSeatingCapacity: 1,
roomType: 'meeting-room',
roomFeatures: ' ',
roomBuildingAddress: ', Science Park 140, 1098 XG, Amsterdam',
roomBuildingRoomNumber: '0.11',
}

const result = mapDavToPrincipal(dav)
expect(result.roomBuildingAddress).toBe('Science Park 140, 1098 XG, Amsterdam')
expect(result.roomBuildingName).toBe('Science Park 140')
expect(result.roomFeatures).toBe(null)
expect(result.roomAddress).toBe('1098 XG, Amsterdam (Science Park 140, Room 0.11)')
})

it('should properly map a principal from an unknown backend to principal-object', () => {
const dav = {
addressBookHomes: undefined,
Expand Down Expand Up @@ -252,6 +375,13 @@ describe('Test suite: Principal model (models/principal.js)', () => {
isCalendarRoom: false,
principalId: null,
userId: null,
roomSeatingCapacity: null,
roomType: null,
roomAddress: null,
roomFeatures: null,
roomBuildingName: null,
roomBuildingAddress: null,
roomNumber: null,
})
})
})
Loading