Skip to content

fix: disregarding already booked spots or blocked calendar times#2029

Merged
zomars merged 16 commits intocalcom:mainfrom
LouisHaftmann:fix/double-booking
Mar 7, 2022
Merged

fix: disregarding already booked spots or blocked calendar times#2029
zomars merged 16 commits intocalcom:mainfrom
LouisHaftmann:fix/double-booking

Conversation

@LouisHaftmann
Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes double-booking issue

Fixes #1271, #1450

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  1. Try booking the same time spot multiple times
  2. Should displays error message

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 2, 2022

@LouisHaftmann is attempting to deploy a commit to the cal Team on Vercel.

A member of the Team first needs to authorize it.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 2, 2022

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployments, click below or on the icon next to each commit.

docs – ./apps/docs

🔍 Inspect: https://vercel.com/cal/docs/3k2rWuuS5FKWw3skci5RvR8VhaJf
✅ Preview: https://docs-git-fork-louishaftmann-fix-double-booking-cal.vercel.app

[Deployment for ed8ee19 canceled]

calendso – ./apps/web

🔍 Inspect: https://vercel.com/cal/calendso/DCyWNY8VYBC2x7Yt7BC9SeBu2DTC
✅ Preview: https://calendso-git-fork-louishaftmann-fix-double-booking-cal.vercel.app

@vercel vercel bot temporarily deployed to Preview – docs March 2, 2022 13:09 Inactive
@vercel vercel bot temporarily deployed to Preview – docs March 2, 2022 13:17 Inactive
@vercel vercel bot temporarily deployed to Preview – docs March 2, 2022 17:30 Inactive
@LouisHaftmann LouisHaftmann changed the title fix: double booking fix: booking same time spot multiple times without error Mar 2, 2022
@LouisHaftmann LouisHaftmann changed the title fix: booking same time spot multiple times without error fix: disregarding already booked spots or blocked calendar times Mar 2, 2022
@vercel vercel bot temporarily deployed to Preview – docs March 3, 2022 07:16 Inactive
@vercel vercel bot temporarily deployed to Preview – docs March 3, 2022 17:54 Inactive
@vercel vercel bot temporarily deployed to Preview – docs March 4, 2022 07:24 Inactive
Copy link
Copy Markdown
Contributor

@alannnc alannnc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! It's working properly now

@agustif agustif self-requested a review March 5, 2022 23:20
Copy link
Copy Markdown
Contributor

@agustif agustif left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's not working for me?
image

Maybe I'm doing something wrong. I just go back to the previous tab and book again and it works, no error.

I only see a change in an api endpoint, in the files changed, but I cannot reproduce/test it properly

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

are you using any calendar integrations (google/apple/microsoft)?

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

yea that's the problem, i'll look into it

@vercel vercel bot temporarily deployed to Preview – docs March 6, 2022 08:53 Inactive
@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

I just noticed that we aren't checking for conflicts before creating the booking, not even whether the time slot is out of bounds. Any reason for that?

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

i believe this line is supposed create a unique seed for each time slot but why does it use new Date().getTime()?

const seed = `${users[0].username}:${dayjs(req.body.start).utc().format()}:${new Date().getTime()}`;

@PeerRich PeerRich requested review from emrysal and zomars March 6, 2022 11:17
@PeerRich
Copy link
Copy Markdown
Member

PeerRich commented Mar 6, 2022

since this touches quite a bit of core, @emrysal and @zomars can you test this?

@emrysal
Copy link
Copy Markdown
Contributor

emrysal commented Mar 6, 2022

@LouisHaftmann

i believe this line is supposed create a unique seed for each time slot but why does it use new Date().getTime()?

const seed = `${users[0].username}:${dayjs(req.body.start).utc().format()}:${new Date().getTime()}`;

You are entirely right about this; this is a bug that still exists and was a "hack" whilst integrating Daily to get it to work. (Not quite sure what broke, maybe @baileypumfleet remembers, or @lunchpaillola.

The idea of this seed before then was to prevent conflicts on database level (which was disabled causing the bugs). When this seed works, it would create a unique seed for each slot, causing a P2002 on database level (unique constraint violation). Database was originally deemed to be the ideal place of doing this as any other location would cause race conditions in times of high traffic.

Edit: It used to be: https://github.com/calcom/cal.com/blame/58de9209512c45e253ba3737311a0e21e0d1cf10/pages/api/book/event.ts#L252

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

Even with the old seed it wouldn't be 100% safe because it doesn't include any info about end time or time slot duration. Changing an event type's duration (eg: from 30min to 15min) would break this conflict check because a booking could be created without conflict error although it conflicts with the old booking.

Example (event type duration: 30min):

  1. Create booking at 1pm
  2. Trying to book event at 1pm again will result in conflict
  3. Change event type duration to 15min
  4. Trying to book event at 1pm still results in conflict
  5. Trying to book event at 1:15pm works although it should conflict with old events

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

In this commit I made it so it fetches all existing bookings for the user and event type and checks for conflicts (including integration and video busy times) before even trying to create a booking in the db.

@emrysal
Copy link
Copy Markdown
Contributor

emrysal commented Mar 6, 2022

Yeah this is an improvement on the current broken logic, but does need further development.

The event type duration isn't as much of a problem as the seed logic is intended to detect double bookings made at the same time, it's not meant to check freebusy - that happens before then.

Reasons for future (Approving this in principle) development are:

  • Booking becomes slower because of conflict checking
  • Higher chance of integration failure
  • Still can be a race condition - but there is a smaller window.

Virtual calendar is a feature that will focus on improving this

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

A seed like

userId:eventTypeId:startTime

would probably work for now. It doesn't cover all edge cases but would atleast prevent simple double booking

@LouisHaftmann
Copy link
Copy Markdown
Contributor Author

Prisma's @@unique constraint could also work

@PeerRich
Copy link
Copy Markdown
Member

PeerRich commented Mar 6, 2022

A seed like

userId:eventTypeId:startTime

would probably work for now. It doesn't cover all edge cases but would atleast prevent simple double booking

once @zomars reviewed this PR, he can merge it

@vercel vercel bot temporarily deployed to Preview – docs March 7, 2022 07:24 Inactive
@zomars
Copy link
Copy Markdown
Contributor

zomars commented Mar 7, 2022

Checking...

@zomars zomars added the ♻️ autoupdate tells kodiak to keep this branch up-to-date label Mar 7, 2022
@vercel vercel bot temporarily deployed to Preview – docs March 7, 2022 16:38 Inactive
});

const credentials = currentUser.credentials;
const calendarBusyTimes: EventBusyDate[] = await prisma.booking
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocking issue but we should strive to rely on inferred types as much as possible.

@vercel vercel bot temporarily deployed to Preview – docs March 7, 2022 17:42 Inactive
Copy link
Copy Markdown
Contributor

@zomars zomars left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Just left some minor comments in there 🙏🏽

Comment on lines -34 to -38

// @TODO: Find a better way to make test wait for full month change render to end
// so it can click up on the right day, also when resolve remove other todos
// Waiting for full month increment
await page.waitForTimeout(400);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was removed by mistake. This is a temporal fix made by @alannnc so tests aren't randomly failing due to loading times.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sry, removed this by accident

@vercel vercel bot temporarily deployed to Preview – docs March 7, 2022 17:47 Inactive
@vercel vercel bot temporarily deployed to Preview – calendso March 7, 2022 17:47 Inactive
Copy link
Copy Markdown
Contributor

@zomars zomars left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed fixes to prevent further delays. Thank you for your contribution 🙏

@zomars zomars merged commit b143498 into calcom:main Mar 7, 2022
@lunchpaillola
Copy link
Copy Markdown
Contributor

@LouisHaftmann

i believe this line is supposed create a unique seed for each time slot but why does it use new Date().getTime()?

const seed = `${users[0].username}:${dayjs(req.body.start).utc().format()}:${new Date().getTime()}`;

You are entirely right about this; this is a bug that still exists and was a "hack" whilst integrating Daily to get it to work. (Not quite sure what broke, maybe @baileypumfleet remembers, or @lunchpaillola.

The idea of this seed before then was to prevent conflicts on database level (which was disabled causing the bugs). When this seed works, it would create a unique seed for each slot, causing a P2002 on database level (unique constraint violation). Database was originally deemed to be the ideal place of doing this as any other location would cause race conditions in times of high traffic.

Edit: It used to be: https://github.com/calcom/cal.com/blame/58de9209512c45e253ba3737311a0e21e0d1cf10/pages/api/book/event.ts#L252

It's been a while so I don't know if that hack is still relevant since I'm sure the code has changed a bit. But for some historical context the new date had to do with rebooking a time that had been previously canceled. Without the hack if you had canceled a time you wouldn't be able to rebook that time even if the slot had been canceled.

Sounds like it's all sorted now though!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

♻️ autoupdate tells kodiak to keep this branch up-to-date

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disregarding already booked spots or blocked calendar times

8 participants