Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit23a8efc

Browse files
test: Add tests for team admin request reschedule with organizer credentials
- Add test for team admin requesting reschedule with proper permissions- Add test verifying organizer's credentials are used (not requester's)- Add test for team member without permissions (should fail)These tests cover the fix in PR#24645 which ensures that when a team adminrequests a reschedule, the booking organizer's credentials are used to deletecalendar events instead of the requester's credentials.Co-Authored-By: joe@cal.com <j.auyeung419@gmail.com>
1 parent7b3061b commit23a8efc

File tree

1 file changed

+294
-2
lines changed

1 file changed

+294
-2
lines changed

‎apps/web/test/handlers/requestReschedule.test.ts‎

Lines changed: 294 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ import {
99
getScenarioData,
1010
getMockBookingAttendee,
1111
getDate,
12+
mockCalendar,
1213
}from"@calcom/web/test/utils/bookingScenario/bookingScenario";
1314
import{expectBookingRequestRescheduledEmails}from"@calcom/web/test/utils/bookingScenario/expects";
1415

1516
importtype{Request,Response}from"express";
1617
importtype{NextApiRequest,NextApiResponse}from"next";
17-
import{describe}from"vitest";
18+
import{describe,expect}from"vitest";
1819

19-
import{SchedulingType}from"@calcom/prisma/enums";
20+
import{SchedulingType,MembershipRole}from"@calcom/prisma/enums";
2021
import{BookingStatus}from"@calcom/prisma/enums";
2122
importtype{TRequestRescheduleInputSchema}from"@calcom/trpc/server/routers/viewer/bookings/requestReschedule.schema";
2223
importtype{TrpcSessionUser}from"@calcom/trpc/server/types";
@@ -253,6 +254,297 @@ describe("Handler: requestReschedule", () => {
253254
bookNewTimePath:"/team/team-1/event-type-1",
254255
});
255256
});
257+
258+
test(`should allow team admin to request-reschedule for a team booking and use organizer's credentials
259+
1. Team admin (non-organizer) can request reschedule with proper permissions
260+
2. Organizer's credentials are used to delete calendar events`,async({ emails})=>{
261+
const{ requestRescheduleHandler}=awaitimport(
262+
"@calcom/trpc/server/routers/viewer/bookings/requestReschedule.handler"
263+
);
264+
265+
constbooker=getBooker({
266+
email:"booker@example.com",
267+
name:"Booker",
268+
});
269+
270+
constorganizer=getOrganizer({
271+
name:"Organizer",
272+
email:"organizer@example.com",
273+
id:101,
274+
teams:[
275+
{
276+
membership:{
277+
accepted:true,
278+
role:"MEMBER",
279+
},
280+
team:{
281+
id:1,
282+
name:"Team 1",
283+
slug:"team-1",
284+
},
285+
},
286+
],
287+
schedules:[TestData.schedules.IstWorkHours],
288+
credentials:[getGoogleCalendarCredential()],
289+
selectedCalendars:[TestData.selectedCalendars.google],
290+
});
291+
292+
constteamAdmin={
293+
id:102,
294+
username:"team-admin",
295+
name:"Team Admin",
296+
email:"team-admin@example.com",
297+
locale:"en",
298+
timeZone:"America/New_York",
299+
teams:[
300+
{
301+
membership:{
302+
accepted:true,
303+
role:MembershipRole.ADMIN,
304+
},
305+
team:{
306+
id:1,
307+
name:"Team 1",
308+
slug:"team-1",
309+
},
310+
},
311+
],
312+
schedules:[TestData.schedules.IstWorkHours],
313+
credentials:[],// No credentials
314+
selectedCalendars:[],
315+
};
316+
317+
const{dateString:plus1DateString}=getDate({dateIncrement:1});
318+
constbookingUid="MOCKED_BOOKING_UID_TEAM_ADMIN";
319+
consteventTypeSlug="event-type-1";
320+
321+
constcalendarMock=awaitmockCalendar("googlecalendar");
322+
323+
awaitcreateBookingScenario(
324+
getScenarioData({
325+
webhooks:[
326+
{
327+
userId:organizer.id,
328+
eventTriggers:["BOOKING_CREATED"],
329+
subscriberUrl:"http://my-webhook.example.com",
330+
active:true,
331+
eventTypeId:1,
332+
appId:null,
333+
},
334+
],
335+
eventTypes:[
336+
{
337+
id:1,
338+
slug:eventTypeSlug,
339+
slotInterval:45,
340+
teamId:1,
341+
schedulingType:SchedulingType.COLLECTIVE,
342+
length:45,
343+
users:[
344+
{
345+
id:101,
346+
},
347+
],
348+
},
349+
],
350+
bookings:[
351+
{
352+
uid:bookingUid,
353+
eventTypeId:1,
354+
userId:101,// Booking belongs to organizer
355+
status:BookingStatus.ACCEPTED,
356+
startTime:`${plus1DateString}T05:00:00.000Z`,
357+
endTime:`${plus1DateString}T05:15:00.000Z`,
358+
references:[
359+
{
360+
type:"google_calendar",
361+
uid:"MOCK_CALENDAR_EVENT_UID",
362+
meetingId:"MOCK_MEETING_ID",
363+
meetingPassword:"MOCK_PASSWORD",
364+
meetingUrl:"https://UNUSED_URL",
365+
credentialId:1,
366+
},
367+
],
368+
attendees:[
369+
getMockBookingAttendee({
370+
id:2,
371+
name:booker.name,
372+
email:booker.email,
373+
locale:"hi",
374+
timeZone:"Asia/Kolkata",
375+
noShow:false,
376+
}),
377+
],
378+
},
379+
],
380+
organizer,
381+
usersApartFromOrganizer:[teamAdmin],
382+
apps:[TestData.apps["google-calendar"],TestData.apps["daily-video"]],
383+
})
384+
);
385+
386+
constloggedInTeamAdmin={
387+
organizationId:null,
388+
id:102,// Team admin ID
389+
username:"team-admin",
390+
name:"Team Admin",
391+
email:"team-admin@example.com",
392+
};
393+
394+
awaitrequestRescheduleHandler(
395+
getTrpcHandlerData({
396+
user:loggedInTeamAdmin,
397+
input:{
398+
bookingUid,
399+
rescheduleReason:"Team admin requesting reschedule",
400+
},
401+
})
402+
);
403+
404+
expectBookingRequestRescheduledEmails({
405+
booking:{
406+
uid:bookingUid,
407+
},
408+
booker,
409+
organizer:organizer,
410+
loggedInUser:loggedInTeamAdmin,
411+
emails,
412+
bookNewTimePath:"/team/team-1/event-type-1",
413+
});
414+
415+
constdeleteEventCalls=calendarMock.deleteEventCalls;
416+
expect(deleteEventCalls.length).toBe(1);
417+
418+
constcredentialUsed=deleteEventCalls[0].calendarServiceConstructorArgs.credential;
419+
expect(credentialUsed.userId).toBe(organizer.id);
420+
expect(credentialUsed.id).toBe(1);
421+
});
422+
423+
test(`should reject request-reschedule from team member without proper permissions`,async()=>{
424+
const{ requestRescheduleHandler}=awaitimport(
425+
"@calcom/trpc/server/routers/viewer/bookings/requestReschedule.handler"
426+
);
427+
428+
constbooker=getBooker({
429+
email:"booker@example.com",
430+
name:"Booker",
431+
});
432+
433+
constorganizer=getOrganizer({
434+
name:"Organizer",
435+
email:"organizer@example.com",
436+
id:101,
437+
teams:[
438+
{
439+
membership:{
440+
accepted:true,
441+
role:"MEMBER",
442+
},
443+
team:{
444+
id:1,
445+
name:"Team 1",
446+
slug:"team-1",
447+
},
448+
},
449+
],
450+
schedules:[TestData.schedules.IstWorkHours],
451+
credentials:[getGoogleCalendarCredential()],
452+
selectedCalendars:[TestData.selectedCalendars.google],
453+
});
454+
455+
constteamMember={
456+
id:103,
457+
username:"team-member",
458+
name:"Team Member",
459+
email:"team-member@example.com",
460+
locale:"en",
461+
timeZone:"America/New_York",
462+
teams:[
463+
{
464+
membership:{
465+
accepted:true,
466+
role:MembershipRole.MEMBER,
467+
},
468+
team:{
469+
id:1,
470+
name:"Team 1",
471+
slug:"team-1",
472+
},
473+
},
474+
],
475+
schedules:[TestData.schedules.IstWorkHours],
476+
credentials:[],
477+
selectedCalendars:[],
478+
};
479+
480+
const{dateString:plus1DateString}=getDate({dateIncrement:1});
481+
constbookingUid="MOCKED_BOOKING_UID_MEMBER";
482+
consteventTypeSlug="event-type-1";
483+
484+
awaitcreateBookingScenario(
485+
getScenarioData({
486+
eventTypes:[
487+
{
488+
id:1,
489+
slug:eventTypeSlug,
490+
slotInterval:45,
491+
teamId:1,
492+
schedulingType:SchedulingType.COLLECTIVE,
493+
length:45,
494+
users:[
495+
{
496+
id:101,
497+
},
498+
],
499+
},
500+
],
501+
bookings:[
502+
{
503+
uid:bookingUid,
504+
eventTypeId:1,
505+
userId:101,// Booking belongs to organizer
506+
status:BookingStatus.ACCEPTED,
507+
startTime:`${plus1DateString}T05:00:00.000Z`,
508+
endTime:`${plus1DateString}T05:15:00.000Z`,
509+
attendees:[
510+
getMockBookingAttendee({
511+
id:2,
512+
name:booker.name,
513+
email:booker.email,
514+
locale:"hi",
515+
timeZone:"Asia/Kolkata",
516+
noShow:false,
517+
}),
518+
],
519+
},
520+
],
521+
organizer,
522+
usersApartFromOrganizer:[teamMember],
523+
apps:[TestData.apps["google-calendar"],TestData.apps["daily-video"]],
524+
})
525+
);
526+
527+
constloggedInTeamMember={
528+
organizationId:null,
529+
id:103,// Team member ID
530+
username:"team-member",
531+
name:"Team Member",
532+
email:"team-member@example.com",
533+
};
534+
535+
awaitexpect(
536+
requestRescheduleHandler(
537+
getTrpcHandlerData({
538+
user:loggedInTeamMember,
539+
input:{
540+
bookingUid,
541+
rescheduleReason:"Team member trying to reschedule",
542+
},
543+
})
544+
)
545+
).rejects.toThrow("User does not have permission to request reschedule for this booking");
546+
});
547+
256548
test.todo("Verify that the email should go to organizer as well as the team members");
257549
});
258550
});

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp