1
1
import type { Calendar as OfficeCalendar , User , Event } from "@microsoft/microsoft-graph-types-beta" ;
2
2
import type { DefaultBodyType } from "msw" ;
3
3
4
+ import { MSTeamsLocationType } from "@calcom/app-store/locations" ;
4
5
import dayjs from "@calcom/dayjs" ;
5
- import { getLocation } from "@calcom/lib/CalEventParser" ;
6
+ import { getLocation , getRichDescriptionHTML } from "@calcom/lib/CalEventParser" ;
6
7
import {
7
8
CalendarAppDelegationCredentialInvalidGrantError ,
8
9
CalendarAppDelegationCredentialConfigurationError ,
@@ -254,7 +255,13 @@ export default class Office365CalendarService implements Calendar {
254
255
body : JSON . stringify ( this . translateEvent ( event ) ) ,
255
256
} ) ;
256
257
257
- const responseJson = await handleErrorsJson < NewCalendarEventType & { iCalUId : string } > ( response ) ;
258
+ const responseJson = await handleErrorsJson <
259
+ NewCalendarEventType & { iCalUId : string ; onlineMeeting ?: { joinUrl ?: string } }
260
+ > ( response ) ;
261
+
262
+ if ( responseJson ?. onlineMeeting ?. joinUrl ) {
263
+ responseJson . url = responseJson ?. onlineMeeting ?. joinUrl ;
264
+ }
258
265
259
266
return { ...responseJson , iCalUID : responseJson . iCalUId } ;
260
267
} catch ( error ) {
@@ -266,12 +273,28 @@ export default class Office365CalendarService implements Calendar {
266
273
267
274
async updateEvent ( uid : string , event : CalendarServiceEvent ) : Promise < NewCalendarEventType > {
268
275
try {
276
+ let rescheduledEvent : Event | undefined ;
277
+ if ( event . location === MSTeamsLocationType ) {
278
+ // Extract the existing body content to preserve the meeting blob, otherwise it breaks and converts it into non-onlineMeeting
279
+ const response = await this . fetcher ( `${ await this . getUserEndpoint ( ) } /calendar/events/${ uid } ` , {
280
+ method : "GET" ,
281
+ } ) ;
282
+
283
+ rescheduledEvent = await handleErrorsJson < Event > ( response ) ;
284
+ }
285
+
269
286
const response = await this . fetcher ( `${ await this . getUserEndpoint ( ) } /calendar/events/${ uid } ` , {
270
287
method : "PATCH" ,
271
- body : JSON . stringify ( this . translateEvent ( event ) ) ,
288
+ body : JSON . stringify ( this . translateEvent ( event , rescheduledEvent ) ) ,
272
289
} ) ;
273
290
274
- const responseJson = await handleErrorsJson < NewCalendarEventType & { iCalUId : string } > ( response ) ;
291
+ const responseJson = await handleErrorsJson <
292
+ NewCalendarEventType & { iCalUId : string ; onlineMeeting ?: { joinUrl ?: string } }
293
+ > ( response ) ;
294
+
295
+ if ( responseJson ?. onlineMeeting ?. joinUrl ) {
296
+ responseJson . url = responseJson ?. onlineMeeting ?. joinUrl ;
297
+ }
275
298
276
299
return { ...responseJson , iCalUID : responseJson . iCalUId } ;
277
300
} catch ( error ) {
@@ -401,12 +424,30 @@ export default class Office365CalendarService implements Calendar {
401
424
} ) ;
402
425
}
403
426
404
- private translateEvent = ( event : CalendarServiceEvent ) => {
427
+ private translateEvent = ( event : CalendarServiceEvent , rescheduledEvent ?: Event ) => {
428
+ const isOnlineMeeting = event . location === MSTeamsLocationType ;
429
+ const isRescheduledOnlineMeeting = rescheduledEvent ? rescheduledEvent . isOnlineMeeting : false ;
430
+ const existingBody =
431
+ rescheduledEvent ?. body ?. contentType === "html" ? rescheduledEvent . body . content : undefined ;
432
+
433
+ let content = "" ;
434
+ if ( isOnlineMeeting ) {
435
+ if ( isRescheduledOnlineMeeting && existingBody ) {
436
+ content = `
437
+ ${ getRichDescriptionHTML ( event ) } <hr>
438
+ ${ existingBody } ` . trim ( ) ;
439
+ } else {
440
+ content = getRichDescriptionHTML ( event ) ;
441
+ }
442
+ } else {
443
+ content = event . calendarDescription ;
444
+ }
445
+
405
446
const office365Event : Event = {
406
447
subject : event . title ,
407
448
body : {
408
- contentType : "text" ,
409
- content : event . calendarDescription ,
449
+ contentType : isOnlineMeeting ? "html" : "text" ,
450
+ content,
410
451
} ,
411
452
start : {
412
453
dateTime : dayjs ( event . startTime ) . tz ( event . organizer . timeZone ) . format ( "YYYY-MM-DDTHH:mm:ss" ) ,
@@ -456,6 +497,17 @@ export default class Office365CalendarService implements Calendar {
456
497
if ( event . hideCalendarEventDetails ) {
457
498
office365Event . sensitivity = "private" ;
458
499
}
500
+ if ( isOnlineMeeting ) {
501
+ office365Event . isOnlineMeeting = true ;
502
+ office365Event . allowNewTimeProposals = true ;
503
+ office365Event . onlineMeetingProvider = "teamsForBusiness" ;
504
+ // MSTeams sets location as 'Microsoft Teams Meeting' by default, if location is undefined.
505
+ // For backward compatibility, setting explicitly.
506
+ office365Event . location =
507
+ rescheduledEvent && ! isRescheduledOnlineMeeting
508
+ ? { displayName : "Microsoft Teams Meeting" }
509
+ : undefined ;
510
+ }
459
511
return office365Event ;
460
512
} ;
461
513
0 commit comments