Compare commits

...
174 Commits
Author SHA1 Message Date
Alex van Andel 0c2d1bff2b v3.9.0
release.yml / release (push) Canceled after 0s
2024-03-15 18:55:46 +00:00
Joe Au-Yeung 7a790aaabe refactor: Moving credential syncing to API (#13963)
* Implement credential sync secret

* Create auth middleware for credential syncing

* Create GET endpoint

* Update swagger comment

* Add verifyCredentialSyncEnabled middleware

* Fix middleware input

* Fix APP_CREDENTIAL_SHARING_ENABLED to return boolean

* Add check for admin API key

* Add GET method

* Middleware require credential sync secret

* Return only the credentialId

* Update default CALCOM_CREDENTIAL_SYNC_HEADER_NAME value

* Add post endpoint

* Return credential object for get endpoint

* Require a userId in the param

* POST add keys to body

* Add PATCH endpoint

* Add DELETE endpoint

* Fix minimumTokenResponseSchema

* Add encrypted key

* Remove prototype

* Add swagger doc comments

* Fix parsing and error handling

* Add create selectedCalendar and destinationCalendar params
2024-03-15 16:03:49 +00:00
Hariom Balhara 8fe8beb686 fix: Avoid CSP related warnings in console on booking pages. (#14072) 2024-03-15 15:42:10 +00:00
Carina WollendorferandCarinaWolli 71b0dd2aa3 fix: don't show 'send event details to' for team events (#14093)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-03-14 16:12:21 +00:00
Amit Sharma 28c793c3fe fix: Exclude current rescheduled booking from limit (#13870)
* fix: Exclude current rescheduled booking from limit

* fix: type check

* chore: test for rescheduling during limit
2024-03-14 11:53:30 -04:00
Gabbar af6899d122 Fix Misspelled in .github/PULL_REQUEST_TEMPLATE (#14081) 2024-03-14 13:40:36 +00:00
Crowdin Bot f4baf88ed5 New Crowdin translations by Github Action 2024-03-14 09:11:51 +00:00
09ca75eb1f feat: lock event types for org users (#14000)
* chroe: org settings schema

* wip: UI work + modal on toggle

* chore: update i18n

* fix: list handler

* fix: update handler on untoggle

* chore: extract

* feat: update handler for hide and delete logic

* chore: radio translations

* chore: fix modal state from flickering

* feat: update copy & add danger colour on delete focus

* chore: update copy

* design: remove modal icon

* chore: include more seeds

* fix: update handler

* feat: hide create for profile user

* feat: use readonly instead

* feat: hide personal event type header when read only

* chore: move away form readOnly as it was used in other ways

* chore: fix read-only bug

* fix: hide readonly create screen

* fix: show managed event types when events are locked

* fix: hide if not admin

* Update packages/trpc/server/routers/viewer/eventTypes/create.handler.ts

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>

* fix: feedback

* fix: lock eventtype single switch

* fix: empty state create button

* fix: more profileGroup check outside CTA to pass value to filter too

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-03-14 09:07:37 +00:00
Joe Au-Yeung 3aff79e7d1 fix: Get dsyncData based on database (#14067)
* Set unique tenant

* Rely on current DB for dsync data

* Fix rendering dsync config

* Remove console.log

* Address feedback

* Add relationship between dsync data and team group mapping

* Fix `dsyncData` and `organizationSetting` relationship
2024-03-14 01:25:50 +00:00
Omar López a7405db0d4 refactor: removes deprecated customPrisma for API (#14069) 2024-03-13 23:57:19 +00:00
Joe Au-Yeung 802fbdf491 fix: Do not refund payments when cancelling bookings (#13924)
* Remove logic that refunds on cancel booking

* Remove cancelled refund booking test
2024-03-13 21:46:07 +00:00
Alex van Andelandzomars 2803b5072c fix: Remove the right date override on removal (#13988)
Co-authored-by: zomars <zomars@me.com>
2024-03-13 20:30:28 +00:00
502a3241e4 chore: run migrations conditionally (#13925)
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-13 19:52:27 +00:00
a4bc0793d7 chore: update to see webhook creation error handling to see error in prod (#14071)
* chore: update to see erorr in prod

* fix: keep try ctach

* chore: add logger from lib

* chore: improvement

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-13 17:55:53 +00:00
Crowdin Bot 4af209fc9d New Crowdin translations by Github Action 2024-03-13 16:00:31 +00:00
Udit Takkar 76b33165e5 fix: hide hidden fields on booking page (#13843)
* fix: hide hidden fields on booking page

* fix: only display for organizer

* fix: hide response

* chore: fix type err

* fix: type err

* fix: unit tests
2024-03-13 11:54:11 -04:00
Keith Williams 5109075494 v3.8.9
release.yml / release (push) Canceled after 0s
2024-03-12 16:31:33 -03:00
Keith Williams 52791599e1 Revert "fix: view team bookings (#13591)" (#14066)
This reverts commit 4585199b5e.
2024-03-12 19:01:41 +00:00
Anwar SadathandAlex van Andel 54db9a42a9 fix: Create team events using admin token (#14044)
* fix: Create team events using admin token

* Revert `import {` to `import type {`

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-12 16:39:01 +00:00
Crowdin Bot ce204d7a98 New Crowdin translations by Github Action 2024-03-12 16:27:29 +00:00
Candous 44170b267f chore: add pt-BR translations (#14022) 2024-03-12 16:22:15 +00:00
cb30e5f1e0 fix: metadata for seats in webhooks (#14025)
* add metadata to seats for workflows and webhooks

* add test

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-12 16:15:19 +00:00
d6d2aae67f fix event length in webhooks payload (#14039)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-12 16:07:07 +00:00
Keith Williams b06e46342c v3.8.8
release.yml / release (push) Canceled after 0s
2024-03-12 13:03:00 -03:00
Crowdin Bot 4cf482f860 New Crowdin translations by Github Action 2024-03-12 16:00:52 +00:00
f2478ea7d3 feat: new privacy settings for orgs (#13693)
* moved privacy setting to new tab

* i18n

* added more privacy switches

* fix: hide org teams and members

* fix: use i18n

* fix: privacy page

* feat: also hide team mebers when org is private

* chore: remove log

* fix type error

* chore: type err

* chore: feedback

* chore: type err

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-03-12 15:56:43 +00:00
0e110022fb fix: open reporting in new tab full screen (#13659)
* open reporting in new tab full screen

* nit

* fixed type

* Fix failing test

* Update packages/app-store/routing-forms/pages/reporting/[...appPages].tsx

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Hariom <hariombalhara@gmail.com>
2024-03-12 11:46:24 -04:00
Somay Chauhan ee80577cc3 fix: username inconsistency (#14034)
* fix: username inconsistency

* added comment

* code refactor
2024-03-12 15:37:53 +00:00
Udit Takkar 8402dfa3a2 fix: display all responses (#13999)
* fix: display all responses

* fix: type err

* chore: rename variable
2024-03-12 15:30:02 +00:00
Somay ChauhanandUdit Takkar 4585199b5e fix: view team bookings (#13591)
* fix: view team bookings

* fix: edge case- common user across 2 different teams

* @SomayChauhan fix: edge case- common user across 2 different teams v2.0

* feat: added booking list test for collective event-types

* feat: added booking list test for round-robin event-types

* feat: added test for managed event types bookings

* feat: added test for individual events bookings

* refactor code

* added comments

* added isFixed to collective event hosts

* better function naming

* code refactor

* fix: assertBookingVisibleFor ignoring today's meetings

* fix: handling case for organizations

* fix: non org bookings-list test

* feat: added tests for organisations booking list

* added comments for better clarity

* booking-list in org tests

* uncommented doOnOrgDomain

* removed extra selectors

* fix: failing tests

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-12 11:54:07 -03:00
Udit TakkarandJoe Au-Yeung ae2446f42f fix: pending payment in mobile (#14011)
* fix: pending payment in mobile

* fix: pending paymeny badge

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2024-03-12 14:36:25 +00:00
Crowdin Bot 2f6d109a70 New Crowdin translations by Github Action 2024-03-12 14:30:43 +00:00
Udit Takkar 7ff884ca7d chore: remove idle state from test (#14063) 2024-03-12 14:26:10 +00:00
9230b2d2ca feat: update event types for default availability change (#13964)
* feat: update event types for default availability change

* chore: add toast

---------

Co-authored-by: sean-brydon <sean@cal.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-12 13:42:57 +00:00
Albert Borsos 1a645f3110 fix: update to cancel_event dictionary key in an event related context (#14047)
to fix context for other languages than english
2024-03-12 11:48:39 +00:00
4eb11e76ea fix: Booking confirmation: Cancelled event icon regression (#14018)
* fix: #14016

* fix: #14016

* Update yarn.lock

* fix: #14016

* fix: cancelled icon

* chore: remove svg

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-03-12 10:08:12 +00:00
Alex van Andel e3a5ce5f6e fix: Timezone Select invalid labels as DST unsupported in spacetime (#14056)
* Fix: Timezone Select invalid labels as DST unsupported in spacetime

* Missed a _ -> (empty string) replace causing invalid TZs

* fix: getTimezone tests didnt support DST
2024-03-12 04:58:52 +00:00
Crowdin Bot 12e171823b New Crowdin translations by Github Action 2024-03-12 00:14:16 +00:00
3c723d6f5b feat: Managed Events V2 (#12320)
* init

* Fix event limit interlinked switches

* wip

* WIP

* fix bugs

* lock hashed link until further notice

* lock private url for managed type to stop confusion

* fix recurring

* prettier fix

* early review fixes ...

* --WIP to send only changed form fields in updateMutation

* WIP with some type fixes

* Revert "WIP with some type fixes"

This reverts commit 00f10b772d6d08af17e7c9bd2d3601d93035d9b3.

* post merge conflict resolution fixes

* further type fix

* fixed test

* fixing e2e tests

* fix test --WIP

* attempt fix test & type --WIP

* fix duplicate locale en entry

* fix locked state persistence

* adds private URL locked/unlocked functionality

* fix tests

* Fix issue where locked labels showed up in non-managed events

* adds e2e test step

* update new test

* minor fixes

* fix test

* address changes request Part 1

fixed width on the lock badge
members default location as default selection
bugfix for offset toggle duplicate within itself

* fixes locked/unlocked label for child event types

* enable choice of destination calendar for children

* Fixes width for simple lock badge

* fix type

* fixes workflows list and apps for managed event type

* restricts creation of managed event types to EE only

* further fixes --WIP

* fix unit test for handleChildrenEventTypes

* fix test --WIP

* fix type err --WIP

* fix type err in test

* fix childevent payload

* fixes hashedLink bug

* fix test step title

* lock workflow create button when workflow is locked

* fix workflow detail

* Don't rely on parameter ordering, use object instead

* Removed console.log

* Missed one

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-12 00:10:08 +00:00
Udit Takkar 1482d9a9af fix: duplicate dialog (#14055) 2024-03-11 15:16:32 +00:00
Udit Takkar 0efe25feb4 fix: org banner (#14041)
* fix: org banner

* fix: type error
2024-03-11 12:16:27 +00:00
Crowdin Bot 602192e026 New Crowdin translations by Github Action 2024-03-11 10:06:54 +00:00
Joe Au-Yeung aeb54e6401 fix: Dsync bugs (#14027)
* Fix dsync create mutation

* Small fixes

* Don't throw error when deleting dsync data

* Change to deleteMany
2024-03-11 10:02:06 +00:00
Peer Richelsen b8c1d623f3 Update Tips.tsx (#14038) 2024-03-08 12:45:49 -03:00
sean-brydonandPeer Richelsen 30e4d769e3 feat: gtm push signup event (#14031)
* feat: gtm push signup event

* chore: fire only if gtm id is defined

---------

Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2024-03-08 15:13:29 +00:00
3babfa7cf3 feat: add pending to role filter (#14013)
* feat: add pending to role filter

* fix: logic

* chore: remove log

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-08 15:09:45 +00:00
sean-brydonandAlex van Andel e45ee8fab3 fix: update handler (#14032)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-08 14:41:05 +00:00
Alex van Andel 3c96e122b4 fix: Broken timezone-select.test.tsx after DST change (#14035)
* fix: Broken timezone-select.test.tsx after DST change

* Surpress minor lint error
2024-03-08 13:37:53 +00:00
Crowdin Bot f21a915814 New Crowdin translations by Github Action 2024-03-08 10:50:48 +00:00
Udit Takkar 3467e2272f fix: seed organization (#14030) 2024-03-08 10:47:11 +00:00
Omar López 844592e15e v3.8.7
release.yml / release (push) Canceled after 0s
2024-03-07 16:21:10 -07:00
Crowdin Bot bdacb18d5c New Crowdin translations by Github Action 2024-03-07 23:20:39 +00:00
1b5d50c45c feat: SCIM Group Provisioning To Teams Within An Org (#13850)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Kiran K <mailtokirankk@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2024-03-07 16:16:53 -07:00
Omar López 1c39dbad3d fix: avatar upload flakyness (#14021) 2024-03-07 19:14:06 +00:00
Alex van AndelandOmar López e60454750e fix: Implement new avatars in insights (#13996)
* fix: Implement new avatars in insights

* fix: Exposed type errors, previously hidden by any,any type

---------

Co-authored-by: Omar López <zomars@me.com>
2024-03-07 17:00:11 +00:00
Omar LópezandPeer Richelsen 286f696302 build: adds action to manually remove faulty cache entries (#14017)
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2024-03-07 13:53:57 -03:00
Crowdin Bot 8deaea3edd New Crowdin translations by Github Action 2024-03-07 16:39:18 +00:00
Udit TakkarandErik 7d497a621f fix: duplicate event types (#14007)
* fix: duplicate event types

* test: add test for duplicate event type

* fix: type error

* chore: pass error message

---------

Co-authored-by: Erik <erik@erosemberg.com>
2024-03-07 16:34:42 +00:00
Somay Chauhan 5c8e0483b1 fix: add future team members toggle (#14008)
* fix: add future team members toggle

fix: add future team members toggle

* code refactor

* removed updateNewTeamMemberEventTypes for regularUsers
2024-03-07 16:18:45 +00:00
Omar López 3cefa94a94 Update base.json (#13997) 2024-03-07 11:38:40 -03:00
Kedar Choudharyandsean-brydon 30549d5c14 This commit fixes #13928 (#13962)
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
2024-03-07 14:07:33 +00:00
Crowdin Bot b87972399e New Crowdin translations by Github Action 2024-03-07 13:38:37 +00:00
sean-brydonandUdit Takkar 0784df6a31 fix: slugify from creating double+ dashes (#14002)
* fix: slugify

* fix: strip emojis

* fix: remove emojis

* fix: remove emojis

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-07 13:34:18 +00:00
fc062878ed add videoCallUrl from link based video apps to metadata (#13995)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-07 04:03:09 +00:00
Crowdin Bot 33c1d80a42 New Crowdin translations by Github Action 2024-03-06 23:38:10 +00:00
1064e1181d feat: SCIM 2.0 Automatic User provisioning (#11169)
Co-authored-by: Alex van Andel <me@alexvanandel.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-06 16:34:21 -07:00
Peer Richelsen dfd683ffc4 feat: added banner for orgs (#13644)
Use this banner to test https://pbs.twimg.com/profile_banners/1063089191565905920/1685635865/1500x500

- [x] add backend
- [x] add file upload (require 1500x500px) in Organization/Appearance
- [x] for now, apply this to all Org event types. later we could think about sub-team overwrites, but for now org is enough


1) Upload Banner Screen

<img width="1512" alt="Screenshot 2024-02-15 at 10 26 36 PM" src="https://github.com/calcom/cal.com/assets/53316345/3c7417ee-7ef7-4138-b5f8-38f255a407fa">

2) 

<img width="1512" alt="Screenshot 2024-02-15 at 10 27 02 PM" src="https://github.com/calcom/cal.com/assets/53316345/a74dffbf-3727-4b2f-82d5-fefd55c12901">


3) Go to Org Team Event Types

<img width="1512" alt="Screenshot 2024-02-15 at 10 27 21 PM" src="https://github.com/calcom/cal.com/assets/53316345/5f188bd7-8a66-4da7-be73-1b5e178b5b3b">


__________________________________________________

DESIGNS


![CleanShot 2024-02-12 at 15 02 37@2x](https://github.com/calcom/cal.com/assets/8019099/85602120-1ced-4627-ae7c-375d33ccf1e9)


__


![CleanShot 2024-02-12 at 14 55 23@2x](https://github.com/calcom/cal.com/assets/8019099/e8a9e9c3-4e01-4a07-a2e0-7259027feb36)


![CleanShot 2024-02-12 at 14 55 34@2x](https://github.com/calcom/cal.com/assets/8019099/56500809-6c6e-49a6-9229-43190dd711b7)

mobile:
![CleanShot 2024-02-12 at 14 56 00@2x](https://github.com/calcom/cal.com/assets/8019099/f90b58b2-3104-4c00-bc18-a2a54ac8e7e7)
2024-03-06 16:18:56 -07:00
Amit Sharma 0972307998 fix: unable to remove single recurring instance from gCal (#13960) 2024-03-06 13:46:58 -05:00
Keith Williams 157f633ef2 chore: Reduce insights range to 7 days (#13991) 2024-03-06 13:02:02 +00:00
Peer RichelsenandAlex van Andel cc1c3b210a chore: added new .env for script tags (#13765)
* added new .env for script tags

* Update turbo.json

* removed meticulous

* added body script .env

* nit

* fixed injection

* Update apps/web/app/layout.tsx

Co-authored-by: Alex van Andel <me@alexvanandel.com>

* Ensure NEXT_PUBLIC_BODY_SCRIPTS is casted to bool

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-06 12:00:19 +00:00
Crowdin Bot fcfd47e7d2 New Crowdin translations by Github Action 2024-03-06 10:14:02 +00:00
Udit Takkar 284c4c9084 fix: Email Embed for team event types (#13990)
* fix: embeds for team event types

* chore: remove unused
2024-03-06 07:05:39 -03:00
Swain MolsterandCarina Wollendorfer 9fd3594f6c fix: add the X-Cal-Signature-256 header to MEETING_ENDED webhook requests (#13986)
* add the X-Cal-Signature-256 header to MEETING_ENDED webhook requests

* take care of null value for appId

---------

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2024-03-06 00:29:30 +00:00
Udit Takkar 531371bf55 fix: team event type error when when no one is assigned (#13888)
* fix: team event when when no one is assigned

* chore: test

* chore: unfo

* chore: remove host while creating

* fix: unit tests

* fix: event in booking form

* chore: undo tests

* fix: type

* fix: move it inside
2024-03-05 16:42:35 -03:00
Morgan 99fd4fe7a4 v3.8.6
release.yml / release (push) Canceled after 0s
2024-03-05 16:20:21 -03:00
a677d0d2c4 fix: Organization Migration - Prevent the redirected username from being claimed by others. (#13675)
* Check for migrated username

* Add e2e for reserved username due to migration

* Add username change test

* Update username.ts

* fixed type checks

* Refactor to use isOrganization

* Typing

* Typing

* Removed the isOrganization function

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-03-05 17:08:44 +00:00
Crowdin Bot d8cee20d0c New Crowdin translations by Github Action 2024-03-05 14:04:30 +00:00
a7ce12e22f fix: event type redirect for orgs in preview test (routing-forms) (#13686)
* fix event type url for orgs

* fix type errors

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2024-03-05 13:55:50 +00:00
Crowdin Bot 88b67a8121 New Crowdin translations by Github Action 2024-03-05 11:59:20 +00:00
Crowdin Bot 7e2a1a23b9 New Crowdin translations by Github Action 2024-03-05 11:55:45 +00:00
Crowdin Bot a115a3458e New Crowdin translations by Github Action 2024-03-05 11:51:32 +00:00
Crowdin Bot ae503acccc New Crowdin translations by Github Action 2024-03-05 11:48:07 +00:00
Crowdin Bot 61e7c89f36 New Crowdin translations by Github Action 2024-03-05 11:44:09 +00:00
Crowdin Bot 60ba7a5ca2 New Crowdin translations by Github Action 2024-03-05 11:40:01 +00:00
Crowdin Bot bfa718e193 New Crowdin translations by Github Action 2024-03-05 11:36:19 +00:00
Crowdin Bot b29a52d0b0 New Crowdin translations by Github Action 2024-03-05 11:31:48 +00:00
Crowdin Bot c21d9d08ab New Crowdin translations by Github Action 2024-03-05 11:27:28 +00:00
Crowdin Bot 615e1dcfe8 New Crowdin translations by Github Action 2024-03-05 11:23:48 +00:00
Crowdin Bot a24f9b76f6 New Crowdin translations by Github Action 2024-03-05 11:19:36 +00:00
Crowdin Bot 62f8ac1c6d New Crowdin translations by Github Action 2024-03-05 11:15:32 +00:00
PritamandJoe Au-Yeung 09b91d5a7e fix: Bug with recurring bookings with seats enabled (#13840)
* fix CAL-3165

* fix wrong change

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2024-03-05 11:09:35 +00:00
01ac2e640a feat: improvement org member list (#13859)
* fix: sticky action bar and align checkbox

* feat: make teams filterable and clickable, total members

* fix: update members count

---------

Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-03-05 11:09:14 +00:00
Udit TakkarandJoe Au-Yeung e39bf37f91 chore: remove CF-region (#13828)
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2024-03-05 02:42:56 +05:30
Joe Au-YeungandKeith Williams 1f845944ac chore: Add credential sync secret when requesting a token (#13907)
* Rename .env variables

* Remove instances of old variable names

* Add credential sync secret to request for new token

* Update invalid secret message

Co-authored-by: Keith Williams <keithwillcode@gmail.com>

---------

Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-03-04 19:02:48 +00:00
Keith Williams 7f53db601d chore: Add index to Team.parentId (#13950) 2024-03-04 15:19:24 -03:00
Keith Williams 1cc9f1d25d chore: Increase API rate limit (#13970) 2024-03-04 16:44:39 +00:00
Udit Takkar c6ee482478 fix: email embed for org (#13917)
* fix: email embed for org

* chore: use orgslig

* chore: remove unused

* fix: org details

* test: add tests

* chore: type err

* fix: import missing

* fix: check timeslots
2024-03-04 15:48:13 +00:00
sean-brydonandAlex van Andel 5292dd2e66 fix: add org settings into seed (#13968)
* fix: add org settings into seed

* fix: Invalid seeded team event (missing schedulingType)

---------

Co-authored-by: Alex van Andel <me@alexvanandel.com>
2024-03-04 15:11:10 +00:00
Hiten Vats f59d62f03c refactor: Removed use of depracted functions from langchain (#13953) 2024-03-04 14:38:36 +00:00
Crowdin Bot cb02268e7f New Crowdin translations by Github Action 2024-03-04 14:09:47 +00:00
Peer Richelsen e33453c50d hide terms and privacy on self-hosted (#13966) 2024-03-04 14:04:18 +00:00
Crowdin Bot 15ffeec745 New Crowdin translations by Github Action 2024-03-04 12:48:39 +00:00
Crowdin Bot b7252ed79c New Crowdin translations by Github Action 2024-03-04 12:45:40 +00:00
Crowdin Bot 9b04df9bbe New Crowdin translations by Github Action 2024-03-04 12:41:18 +00:00
Crowdin Bot 657be16a4e New Crowdin translations by Github Action 2024-03-04 12:37:08 +00:00
Crowdin Bot b0afb15939 New Crowdin translations by Github Action 2024-03-04 12:33:30 +00:00
Vikas VermaandVikas Verma 3a9b8a9bf6 fix: url input field inconsistent (#13956)
* fix:Url Input feild Inconsistent UI/UX #13955

* Lint issue fixes

* Update UsernameTextfield.tsx

* Update UsernameTextfield.tsx

Lint issue fix

---------

Co-authored-by: Vikas Verma <inboxvikasverma@gmail.com>
2024-03-04 12:29:35 +00:00
92a919069d feat: Implement secondary email (#13678)
* Implement secondary email

* Fix already existing tests failing

* Added tests for secondary email feature

* Skip email verification if user is changing the primary email to a verified secondary email

* Fix type errors in tests

* Fix email becoming unverified when switched between primary and secondary email

* Added a check to prevent prisma error from throwing up due to duplicate records

* Improved error handling when adding a secondary email

* Add test for resend verification email flow for secondary emails and validation of invite link

* Add a new column to link secondary emails with verification tokens

* Fix failing to update email to an unverified secondary email of the same user

* Fix failing tests

* Change text of resend verification email

* Add ability to use the verified secondary emails to get the event details to

* Fix type errors

* Fix failing e2e tests

* Fix failing unit tests

* Fix failing type checks

* Fix secondary verification email subject

* Fix failing e2e tests

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2024-03-02 22:29:40 +00:00
zomars 0071d16575 Update yarn.lock 2024-03-01 13:26:00 -07:00
Joe Au-Yeung 23d22ee7ea Add missing lock file (#13949) 2024-03-01 14:28:10 -05:00
3a4f944aac feat: jelly integration (#13929)
* v1

* don't need to search DB for user

* return early if no user

* use one deleteMany to ensure only 1 credential

* rm expiration

* fix API request

* proper type

* Update packages/app-store/jelly/lib/VideoApiAdapter.ts

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>

* Update packages/app-store/jelly/lib/VideoApiAdapter.ts

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>

* Update packages/app-store/jelly/lib/VideoApiAdapter.ts

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>

* Update packages/app-store/jelly/api/callback.ts

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>

* Fix callback URL

---------

Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
Co-authored-by: Joe Au-Yeung <j.auyeung419@gmail.com>
2024-03-01 16:45:41 +00:00
Crowdin Bot 3eadae0aad New Crowdin translations by Github Action 2024-03-01 15:53:12 +00:00
Crowdin Bot 0cc2fe2d7f New Crowdin translations by Github Action 2024-03-01 15:42:22 +00:00
0970c77009 fix: Revert -> "Revert "chore: Chore team metadata table + isOrganization migration (#13700)
* Revert "Revert "chore: Chore team metadata table + isOrganization migration from metadata (#12828)""

This reverts commit 2408338ed4.

* Remove constraint slug,isOrganization and reset migration

* fix: conflicts

* change schema to bust cache

* Fix issues reported by TS

* change schema to bust cache

* Review fixes

* Colaesce for orgAutoAcceptEmail as well

* Fix missing negation

---------

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com>
2024-03-01 15:04:28 +00:00
David Somers 5b733765f4 Update api image Dockerfile (#13890)
- Add DATABASE_URL and DATABASE_DIRECT_URL, used during build
- Copy tests folder, referenced by code run during build.
2024-03-01 09:18:02 -03:00
Yash RajandCarina Wollendorfer 83fe4d6625 fix: font bold font semibold (#13939)
* Fixed issue#13879 changed font-bold to font-semibold with font-cal

* Revert yarn.lock changes

---------

Co-authored-by: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com>
2024-03-01 06:53:16 -03:00
Joe Au-Yeungandzomars 91beeeb525 fix: Google Profile Picture Update Race Condition (#13711)
* Minor fixes

* Discard changes to packages/app-store/ics-feedcalendar/config.json

* Add comment

* refactor: denesting and conditional profile update

---------

Co-authored-by: zomars <zomars@me.com>
2024-02-29 20:01:13 +00:00
81c0b1ffe9 fix: broken google account avatar fix (#13892)
* fix: broken google account avatar fix

* fix: use zod for checking absolute url

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-02-29 19:59:23 +00:00
Hitesh SisaraandUdit Takkar aedc88f975 feat: show top banner for broken integrations [Cal 3125] (#13720)
* added InvalidAppCredentialBanner

* Create InvalidAppCredentialsBanner.tsx

* Update getUserTopBanners.handler.ts

* Create checkForInvalidAppCredentials.ts

* Update common.json

* Update common.json

* Update getUserTopBanners.handler.ts

* Update checkForInvalidAppCredentials.ts

* also included team's credentials

* reverse yarnlock changes

* fix .env

* fixed types

* chore: translation

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-02-29 19:58:46 +00:00
sean-brydonandOmar López 67256b5b6e fix: toLowercase on emailChangeWaitingForVerification (#13940)
Co-authored-by: Omar López <zomars@me.com>
2024-02-29 19:43:48 +00:00
Carina WollendorferandCarinaWolli ef02d64f90 fix: workfow e2e tests (#13938)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-02-29 11:16:36 -07:00
Omar López 8685862617 v3.8.5
release.yml / release (push) Canceled after 0s
2024-02-29 10:26:06 -07:00
zomars 7422488b5d Update yarn.lock 2024-02-28 15:51:40 -07:00
zomars c3e1481d6a Update yarn.lock 2024-02-28 15:41:35 -07:00
Rushikesh a1d1883b34 Large padding on small screens for embedded booking widgets. (#13855) 2024-02-28 14:17:06 +00:00
Crowdin Bot f2ae94a190 New Crowdin translations by Github Action 2024-02-28 14:12:14 +00:00
Alex van Andel b82a597645 fix: invalid type check occupied seats (#13830)
* fix: Type check failure in occupiedSeats

* fix: Invalid handling of occupied seats hidden by earlier error
2024-02-28 11:07:34 -03:00
sean-brydonandUdit Takkar 5ba0ee8e85 fix: impersonation detecting orgs correctly. (#13889)
* feat:fix correctly detect impersonation organization

* chore: remove logs

* Update packages/features/ee/impersonation/lib/ImpersonationProvider.ts

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-02-28 12:16:46 +00:00
PritamandUdit Takkar 1463f97f14 fix: Currency Not Reflecting Correctly #13845 (#13847)
* fix currency problem

* fix type errors

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-02-28 17:14:26 +05:30
Nikhil Anand 34fea35e83 fix: text overflowing in username change popup #13846 (#13911) 2024-02-28 15:06:41 +05:30
Alex van AndelandUdit Takkar 2d75048037 fix: Test flakiness due to unfilled name/email (#13900)
* fix: Test flakiness due to unfilled name/email

* Better toast-success checks

* Revert "test: Create E2E tests for bookings with custom/required Phone + other questions (#11502)"

This reverts commit 614741d207.

* Revert "test: Create E2E tests for bookings with custom/required Multiple Emails + other questions  (teste2e-multipleEmailQuestion) (#11565)"

This reverts commit d1d50b0d91.

* Revert "test: Create E2E tests for bookings with custom/required Long Text + other questions (teste2e-longTextQuestion) (#11559)"

This reverts commit 96810b5ba1.

* Revert "test: Check the webhook event tab and your funtionalities (#12433)"

This reverts commit 9db9204088.

* Re-instate regularBookings

* Fixtures used by other tests

* Removed dead code from regularBookings.ts

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-02-28 06:07:32 +00:00
Carina WollendorferandCarinaWolli b549735334 santize right before sending mail (#13876)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-02-27 17:57:26 -03:00
Anwar SadathandCarinaWolli 86c379817e fix: Fix calendar event included in the workflow, doesn't show the meeting link (#13872)
* Fix calendar event included in the workflow, doesn't show the meeting link

* Fix type error

* fix public video call url

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-02-27 15:50:40 +00:00
Udit Takkar 5d1976295c fix: hover state (#13862)
release.yml / release (push) Canceled after 0s
2024-02-27 14:32:59 +00:00
Morgan e9b1fa1f50 v3.8.4 2024-02-27 16:31:14 +02:00
Udit Takkar 80080dda7a fix: missing userPrimaryEmail in workflows (#13875)
* fix: missing userPrimaryEmail in workflows

* chore

* fix: type err
2024-02-27 09:17:34 -05:00
Udit Takkar 27c25e1f95 chore: use transaction (#13874)
* fix: use transaction

* chore
2024-02-27 10:17:46 -03:00
Shyam Raghuwanshi 858be0f5d8 fix ics-feedcalendar logo not showing (#13886) 2024-02-27 11:43:25 +00:00
Hariom Balhara 68d0090f50 Make sure that state doesnt reset (#13880) 2024-02-27 07:51:11 -03:00
Udit Takkar a43fa13b11 fix: infinite rendering in event setup tab (#13877) 2024-02-26 22:18:58 +00:00
Pritam 2bf6da30b3 fix periodDays dirtystate (#13851) 2024-02-26 19:17:53 +00:00
Alex van Andel d85e0b51e4 fix: Prevent duplicate bookings with idempotency key (#13865)
* fix: Prevent duplicate bookings with idempotency key

* Add idempotencyKey to builder.ts type fix

* Add tests for new idempotency key (booking create)

* Add endTime to idempotency key, it should be possible to book different durations

* Move reschedule before the create so the idempotency key is unset
2024-02-26 18:33:22 +00:00
Carina WollendorferandCarinaWolli 55a317d677 fix: video call url in event location for recurring events (#13842)
Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-02-26 10:44:07 -05:00
Crowdin Bot 5fff8fc58c New Crowdin translations by Github Action 2024-02-26 14:36:48 +00:00
Udit Takkar 0d68767d0a fix: seed script (#13868) 2024-02-26 14:31:25 +00:00
Shyam Raghuwanshi 2051e87436 fix: username overflow (#13832) 2024-02-23 23:01:43 +00:00
Udit Takkar 77a157a12b fix: show go back button after expiry (#13833) 2024-02-23 22:20:46 +00:00
Omar López c4f25f2c44 build: deploy script for gradual migration (#13834) 2024-02-23 12:38:13 -07:00
Peer Richelsen d967facb63 feat: demodesk app (#13733) 2024-02-23 10:14:37 -05:00
c6dad39fb0 test: Create E2E tests for Analytics Apps (teste2e-analyticsApps) (#13695)
* refactor

* refactor

* refactor

* refactor

* fix failing check

* Update apps.ts

* fix failing check

* fix failing check

* fix failing check

---------

Co-authored-by: gitstart-calcom <gitstart-calcom@users.noreply.github.com>
Co-authored-by: GitStart-Cal.com <121884634+gitstart-calcom@users.noreply.github.com>
2024-02-22 21:54:49 -03:00
zomars eec7f4d7d4 Update yarn.lock 2024-02-22 15:00:52 -07:00
Udit Takkar 95d5824ba9 fix: og image (#13829) 2024-02-22 10:46:33 -07:00
Somay Chauhan 5f95a4d041 fix: New Team Members Join Org as OWNER/ADMIN (#13822) 2024-02-22 11:46:28 -05:00
Keith Williams 8e97444129 v3.8.3
release.yml / release (push) Canceled after 0s
2024-02-22 10:16:18 -03:00
Crowdin Bot 8d8264b5f5 New Crowdin translations by Github Action 2024-02-22 12:48:57 +00:00
2ad81221d0 chore: Added a period after undone (#13824)
* Added period after undone

* chore: undo yarn.lock

* Revert yarn.lock

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
2024-02-22 09:44:43 -03:00
3d1ac4523f fix: Update credentialId when null for a given selectedCalendar (#13735)
* fix: Update credentialId when null for a given selectedCalendar

* Add returnTo return path

* chore

* chore: undo return

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-02-22 12:05:46 +00:00
Alex van Andel b38807cb0f fix: Type check failure in occupiedSeats (#13805) 2024-02-22 10:27:55 +00:00
Peer Richelsen 11fb387370 feat: let org admins change usernames (#13384) 2024-02-22 07:48:46 +00:00
Crowdin Bot 1546f9115d New Crowdin translations by Github Action 2024-02-22 07:42:13 +00:00
Peer RichelsenandUdit Takkar 40ecd5dd9d chore: removing wrong translations about {{consoleUrl}} (#13802)
* removing wrong translations

* fixed source string

* revert: eng translation

* chore: remove translation

* chore

---------

Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-02-22 07:38:47 +00:00
Omar López ac6ac14a23 fix: more og avatar fixes (#13817) 2024-02-22 07:25:31 +00:00
Bailey Pumfleet c6534160e4 chore: Shorten "aplicaciones instaladas" to "apps instaladas" (#13806) 2024-02-22 07:21:43 +00:00
Keith Williams aa2db562b8 fix: Bookings API (#13815) 2024-02-21 16:05:53 -07:00
Carina WollendorferandCarinaWolli b7ed314be2 fix: log more info on sendEmail error (#13813)
* add from and subject to error message

* remove comment

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-02-21 20:59:45 +00:00
Udit TakkarandCarinaWolli d102268b33 fix: sdk action events (#13755)
* fix: sdk action events

* fix: type error

* fix: type err

* fix: reschedule event

* chore: remove timezone

* fix: feedback

* chore: use bookingInfo

* fix type error

* fix type errror

* add cancellation reason

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
2024-02-21 14:25:24 -05:00
Somay ChauhanandUdit Takkar f4397d6593 fix: error on signup page while inviting a member to an org (#13807)
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-02-21 18:49:51 +00:00
Keith Williams 192603a1fa fix: No available users found near midnight (#13801)
* fix: No available users found near midnight

* Update date-ranges.ts
2024-02-21 10:58:38 -07:00
Keith Williams a3d969680f chore: Including original start and end dates from request in log (#13800) 2024-02-21 13:22:42 -03:00
Crowdin Bot adc3b3aec6 New Crowdin translations by Github Action 2024-02-21 15:27:50 +00:00
sean-brydonandUdit Takkar 92286e2453 feat: signup redirect query param after onboarding (#13761)
* feat:redirect - if signup url has url to goto

* fix: dont throw if url is invalid - just dont set

---------

Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
2024-02-21 20:53:09 +05:30
51b2a15cb0 feat: Settings for dashboard theme that is separate from system (#13779)
* feat(db): add new col: user appTheme

* feat(event-types page): apply appTheme color

* add appTheme for trpc

* feat: mutate main page theme

* feat: add english translation for app theme update section

* modify keys in common (en)

* add woring

* Revert yarn.lock to its state before unintended changes

* feat(i18n): add back the i18n string (for dark/light mode switching)

* refactor: refactor ThemeLabel

* fix: add new user field "appTheme" to test files

* chore: modify TODO comment

* chore: update common.json (en) for "theme"

since we had appTheme now, I think it's better to update the wording here to avoid confusion

* fix: update button's data-testid to fix e2e test error

* chore: remove comment

* fix: fix brand-color-not-apply bug

* solve type error

* fix: fix type error

* fix: use correct storageKey for booker / dashboard

* fix: tidy up

* fix: skeleton

---------

Co-authored-by: swh00tw <a6140000@gmail.com>
Co-authored-by: Peer Richelsen <peeroke@gmail.com>
Co-authored-by: Keith Williams <keithwillcode@gmail.com>
Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com>
Co-authored-by: Udit Takkar <udit222001@gmail.com>
2024-02-21 13:02:40 +00:00
Morgan fa9a099dd6 fix: prefillFormParams guest type (#13798) 2024-02-21 12:36:48 +00:00
ErikandOmar López 83ceb46cca chore: Refactor feature flags (#13734)
Co-authored-by: Omar López <zomars@me.com>
2024-02-20 21:49:48 -03:00
553 changed files with 11710 additions and 7656 deletions
+3 -2
View File
@@ -232,6 +232,7 @@ NEXT_PUBLIC_COMPANY_NAME="Cal.com, Inc."
# NEXT_PUBLIC_DISABLE_SIGNUP=true
NEXT_PUBLIC_DISABLE_SIGNUP=
# Set this to 'non-strict' to enable CSP for support pages. 'strict' isn't supported yet. Also, check the README for details.
# Content Security Policy
CSP_POLICY=
@@ -294,9 +295,9 @@ E2E_TEST_CALCOM_GCAL_KEYS=
# Used for self-hosters that are implementing Cal.com into their applications that already have certain integrations
# Under settings/admin/apps ensure that all app secrets are set the same as the parent application
# You can use: `openssl rand -base64 32` to generate one
CALCOM_WEBHOOK_SECRET=""
CALCOM_CREDENTIAL_SYNC_SECRET=""
# This is the header name that will be used to verify the webhook secret. Should be in lowercase
CALCOM_WEBHOOK_HEADER_NAME="calcom-webhook-secret"
CALCOM_CREDENTIAL_SYNC_HEADER_NAME="calcom-credential-sync-secret"
CALCOM_CREDENTIAL_SYNC_ENDPOINT=""
# Key should match on Cal.com and your application
# must be 24 bytes for AES256 encryption algorithm
+1 -1
View File
@@ -13,7 +13,7 @@ Fixes # (issue)
<!-- Please provide all documents that are important to understand the reason of that PR. -->
- If there is a requirement document, please, share it here.
- If there is ab UI/UX design document, please, share it here.
- If there is a UI/UX design document, please, share it here.
## Type of change
@@ -0,0 +1,17 @@
name: Manually Delete BuildJet Cache
on:
workflow_dispatch:
inputs:
cache_key:
description: "BuildJet Cache Key to Delete"
required: true
type: string
jobs:
manually-delete-buildjet-cache:
runs-on: buildjet-2vcpu-ubuntu-2204
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: buildjet/cache-delete@v1
with:
cache_key: ${{ inputs.cache_key }}
+63 -57
View File
@@ -1,5 +1,6 @@
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatOpenAI } from "@langchain/openai";
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { env } from "../env.mjs";
import createBookingIfAvailable from "../tools/createBooking";
@@ -47,67 +48,72 @@ const agent = async (
/**
* Initialize the agent executor with arguments.
*/
const executor = await initializeAgentExecutorWithOptions(tools, model, {
agentArgs: {
prefix: `You are Cal.ai - a bleeding edge scheduling assistant that interfaces via email.
Make sure your final answers are definitive, complete and well formatted.
Sometimes, tools return errors. In this case, try to handle the error intelligently or ask the user for more information.
Tools will always handle times in UTC, but times sent to users should be formatted per that user's timezone.
In responses to users, always summarize necessary context and open the door to follow ups. For example "I have booked your chat with @username for 3pm on Wednesday, December 20th, 2023 EST. Please let me know if you need to reschedule."
If you can't find a referenced user, ask the user for their email or @username. Make sure to specify that usernames require the @username format. Users don't know other users' userIds.
const prompt =
ChatPromptTemplate.fromTemplate(`You are Cal.ai - a bleeding edge scheduling assistant that interfaces via email.
Make sure your final answers are definitive, complete and well formatted.
Sometimes, tools return errors. In this case, try to handle the error intelligently or ask the user for more information.
Tools will always handle times in UTC, but times sent to users should be formatted per that user's timezone.
In responses to users, always summarize necessary context and open the door to follow ups. For example "I have booked your chat with @username for 3pm on Wednesday, December 20th, 2023 EST. Please let me know if you need to reschedule."
If you can't find a referenced user, ask the user for their email or @username. Make sure to specify that usernames require the @username format. Users don't know other users' userIds.
The primary user's id is: ${userId}
The primary user's username is: ${user.username}
The current time in the primary user's timezone is: ${now(user.timeZone, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
})}
The primary user's time zone is: ${user.timeZone}
The primary user's event types are: ${user.eventTypes
.map((e: EventType) => `ID: ${e.id}, Slug: ${e.slug}, Title: ${e.title}, Length: ${e.length};`)
.join("\n")}
The primary user's working hours are: ${user.workingHours
.map(
(w: WorkingHours) =>
`Days: ${w.days.join(", ")}, Start Time (minutes in UTC): ${
w.startTime
}, End Time (minutes in UTC): ${w.endTime};`
)
.join("\n")}
${
users.length
? `The email references the following @usernames and emails: ${users
.map(
(u) =>
`${
(u.id ? `, id: ${u.id}` : "id: (non user)") +
(u.username
? u.type === "fromUsername"
? `, username: @${u.username}`
: ", username: REDACTED"
: ", (no username)") +
(u.email
? u.type === "fromEmail"
? `, email: ${u.email}`
: ", email: REDACTED"
: ", (no email)")
};`
)
.join("\n")}`
: ""
}`);
const agent = await createOpenAIFunctionsAgent({
llm: model,
prompt,
tools,
});
The primary user's id is: ${userId}
The primary user's username is: ${user.username}
The current time in the primary user's timezone is: ${now(user.timeZone, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "numeric",
minute: "numeric",
})}
The primary user's time zone is: ${user.timeZone}
The primary user's event types are: ${user.eventTypes
.map((e: EventType) => `ID: ${e.id}, Slug: ${e.slug}, Title: ${e.title}, Length: ${e.length};`)
.join("\n")}
The primary user's working hours are: ${user.workingHours
.map(
(w: WorkingHours) =>
`Days: ${w.days.join(", ")}, Start Time (minutes in UTC): ${
w.startTime
}, End Time (minutes in UTC): ${w.endTime};`
)
.join("\n")}
${
users.length
? `The email references the following @usernames and emails: ${users
.map(
(u) =>
`${
(u.id ? `, id: ${u.id}` : "id: (non user)") +
(u.username
? u.type === "fromUsername"
? `, username: @${u.username}`
: ", username: REDACTED"
: ", (no username)") +
(u.email
? u.type === "fromEmail"
? `, email: ${u.email}`
: ", email: REDACTED"
: ", (no email)")
};`
)
.join("\n")}`
: ""
}
`,
},
agentType: "openai-functions",
const executor = new AgentExecutor({
agent,
tools,
returnIntermediateSteps: env.NODE_ENV === "development",
verbose: env.NODE_ENV === "development",
});
const result = await executor.call({ input });
const result = await executor.invoke({ input });
const { output } = result;
return output;
-43
View File
@@ -1,43 +0,0 @@
import type { NextMiddleware } from "next-api-middleware";
import { CONSOLE_URL } from "@calcom/lib/constants";
import { customPrisma } from "@calcom/prisma";
const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL;
// This replaces the prisma client for the custom one if the key is valid
export const customPrismaClient: NextMiddleware = async (req, res, next) => {
const {
query: { key },
} = req;
// If no custom api Id is provided, attach to request the regular cal.com prisma client.
if (!key) {
req.prisma = customPrisma();
await next();
return;
}
// If we have a key, we check if the deployment matching the key, has a databaseUrl value set.
const databaseUrl = await fetch(`${LOCAL_CONSOLE_URL}/api/deployments/database?key=${key}`)
.then((res) => res.json())
.then((res) => res.databaseUrl);
if (!databaseUrl) {
res.status(400).json({ error: "no databaseUrl set up at your instance yet" });
return;
}
req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } });
/* @note:
In order to skip verifyApiKey for customPrisma requests,
we pass isAdmin true, and userId 0, if we detect them later,
we skip verifyApiKey logic and pass onto next middleware instead.
*/
req.isAdmin = true;
req.isCustomPrisma = true;
// We don't need the key from here and on. Prevents unrecognized key errors.
delete req.query.key;
await next();
await req.prisma.$disconnect();
// @ts-expect-error testing
delete req.prisma;
};
+1 -7
View File
@@ -3,6 +3,7 @@ import type { NextMiddleware } from "next-api-middleware";
import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys";
import checkLicense from "@calcom/features/ee/common/server/checkLicense";
import { IS_PRODUCTION } from "@calcom/lib/constants";
import prisma from "@calcom/prisma";
import { isAdminGuard } from "../utils/isAdmin";
@@ -16,15 +17,9 @@ export const dateNotInPast = function (date: Date) {
// This verifies the apiKey and sets the user if it is valid.
export const verifyApiKey: NextMiddleware = async (req, res, next) => {
const { prisma, isCustomPrisma, isAdmin } = req;
const hasValidLicense = await checkLicense(prisma);
if (!hasValidLicense && IS_PRODUCTION)
return res.status(401).json({ error: "Invalid or missing CALCOM_LICENSE_KEY environment variable" });
// If the user is an admin and using a license key (from customPrisma), skip the apiKey check.
if (isCustomPrisma && isAdmin) {
await next();
return;
}
// Check if the apiKey query param is provided.
if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" });
// remove the prefix from the user provided api_key. If no env set default to "cal_"
@@ -43,6 +38,5 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => {
req.userId = apiKey.userId;
// save the isAdmin boolean here for later use
req.isAdmin = await isAdminGuard(req);
req.isCustomPrisma = false;
await next();
};
@@ -0,0 +1,24 @@
import type { NextMiddleware } from "next-api-middleware";
import { APP_CREDENTIAL_SHARING_ENABLED } from "@calcom/lib/constants";
export const verifyCredentialSyncEnabled: NextMiddleware = async (req, res, next) => {
const { isAdmin } = req;
if (!isAdmin) {
return res.status(403).json({ error: "Only admin API keys can access credential syncing endpoints" });
}
if (!APP_CREDENTIAL_SHARING_ENABLED) {
return res.status(501).json({ error: "Credential syncing is not enabled" });
}
if (
req.headers[process.env.CALCOM_CREDENTIAL_SYNC_HEADER_NAME || "calcom-credential-sync-secret"] !==
process.env.CALCOM_CREDENTIAL_SYNC_SECRET
) {
return res.status(401).json({ message: "Invalid credential sync secret" });
}
await next();
};
+9 -12
View File
@@ -2,7 +2,6 @@ import { label } from "next-api-middleware";
import { addRequestId } from "./addRequestid";
import { captureErrors } from "./captureErrors";
import { customPrismaClient } from "./customPrisma";
import { extendRequest } from "./extendRequest";
import {
HTTP_POST,
@@ -14,6 +13,7 @@ import {
} from "./httpMethods";
import { rateLimitApiKey } from "./rateLimitApiKey";
import { verifyApiKey } from "./verifyApiKey";
import { verifyCredentialSyncEnabled } from "./verifyCredentialSyncEnabled";
import { withPagination } from "./withPagination";
const middleware = {
@@ -26,25 +26,22 @@ const middleware = {
addRequestId,
verifyApiKey,
rateLimitApiKey,
customPrismaClient,
extendRequest,
pagination: withPagination,
captureErrors,
verifyCredentialSyncEnabled,
};
type Middleware = keyof typeof middleware;
const middlewareOrder =
const middlewareOrder = [
// The order here, determines the order of execution
[
"extendRequest",
"captureErrors",
// - Put customPrismaClient before verifyApiKey always.
"customPrismaClient",
"verifyApiKey",
"rateLimitApiKey",
"addRequestId",
] as Middleware[]; // <-- Provide a list of middleware to call automatically
"extendRequest",
"captureErrors",
"verifyApiKey",
"rateLimitApiKey",
"addRequestId",
] as Middleware[]; // <-- Provide a list of middleware to call automatically
const withMiddleware = label(middleware, middlewareOrder);
+2 -1
View File
@@ -1,9 +1,10 @@
import type { NextApiRequest } from "next";
import prisma from "@calcom/prisma";
import { UserPermissionRole } from "@calcom/prisma/enums";
export const isAdminGuard = async (req: NextApiRequest) => {
const { userId, prisma } = req;
const { userId } = req;
const user = await prisma.user.findUnique({ where: { id: userId } });
return user?.role === UserPermissionRole.ADMIN;
};
@@ -0,0 +1,64 @@
import { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
const userId = z.string().transform((val) => {
const userIdInt = parseInt(val);
if (isNaN(userIdInt)) {
throw new HttpError({ message: "userId is not a valid number", statusCode: 400 });
}
return userIdInt;
});
const appSlug = z.string();
const credentialId = z.string().transform((val) => {
const credentialIdInt = parseInt(val);
if (isNaN(credentialIdInt)) {
throw new HttpError({ message: "credentialId is not a valid number", statusCode: 400 });
}
return credentialIdInt;
});
const encryptedKey = z.string();
export const schemaCredentialGetParams = z.object({
userId,
appSlug: appSlug.optional(),
});
export const schemaCredentialPostParams = z.object({
userId,
createSelectedCalendar: z
.string()
.optional()
.transform((val) => {
return val === "true";
}),
createDestinationCalendar: z
.string()
.optional()
.transform((val) => {
return val === "true";
}),
});
export const schemaCredentialPostBody = z.object({
appSlug,
encryptedKey,
});
export const schemaCredentialPatchParams = z.object({
userId,
credentialId,
});
export const schemaCredentialPatchBody = z.object({
encryptedKey,
});
export const schemaCredentialDeleteParams = z.object({
userId,
credentialId,
});
+4
View File
@@ -74,6 +74,7 @@ export const schemaUserBaseBodyParams = User.pick({
timeZone: true,
weekStart: true,
theme: true,
appTheme: true,
defaultScheduleId: true,
locale: true,
hideBranding: true,
@@ -100,6 +101,7 @@ const schemaUserEditParams = z.object({
hideBranding: z.boolean().optional(),
timeZone: timeZone.optional(),
theme: z.nativeEnum(theme).optional().nullable(),
appTheme: z.nativeEnum(theme).optional().nullable(),
timeFormat: z.nativeEnum(timeFormat).optional(),
defaultScheduleId: z
.number()
@@ -122,6 +124,7 @@ const schemaUserCreateParams = z.object({
hideBranding: z.boolean().optional(),
timeZone: timeZone.optional(),
theme: z.nativeEnum(theme).optional().nullable(),
appTheme: z.nativeEnum(theme).optional().nullable(),
timeFormat: z.nativeEnum(timeFormat).optional(),
defaultScheduleId: z
.number()
@@ -159,6 +162,7 @@ export const schemaUserReadPublic = User.pick({
weekStart: true,
endTime: true,
bufferTime: true,
appTheme: true,
theme: true,
defaultScheduleId: true,
locale: true,
-4
View File
@@ -1,8 +1,6 @@
import type { Session } from "next-auth";
import type { NextApiRequest as BaseNextApiRequest } from "next/types";
import type { PrismaClient } from "@calcom/prisma";
export type * from "next/types";
export declare module "next" {
@@ -11,11 +9,9 @@ export declare module "next" {
userId: number;
method: string;
prisma: PrismaClient;
// session: { user: { id: number } };
// query: Partial<{ [key: string]: string | string[] }>;
isAdmin: boolean;
isCustomPrisma: boolean;
pagination: { take: number; skip: number };
}
}
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
export async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdAsString.parse(req.query);
// Admin can check any api key
if (isAdmin) return;
+2 -1
View File
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdAsString.parse(query);
await prisma.apiKey.delete({ where: { id } });
return { message: `ApiKey with id: ${id} deleted` };
+2 -1
View File
@@ -1,12 +1,13 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { apiKeyPublicSchema } from "~/lib/validations/api-key";
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdAsString.parse(query);
const api_key = await prisma.apiKey.findUniqueOrThrow({ where: { id } });
return { api_key: apiKeyPublicSchema.parse(api_key) };
+2 -1
View File
@@ -1,12 +1,13 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { apiKeyEditBodySchema, apiKeyPublicSchema } from "~/lib/validations/api-key";
import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString";
async function patchHandler(req: NextApiRequest) {
const { prisma, body } = req;
const { body } = req;
const { id } = schemaQueryIdAsString.parse(req.query);
const data = apiKeyEditBodySchema.parse(body);
const api_key = await prisma.apiKey.update({ where: { id }, data });
+2 -1
View File
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import type { Ensure } from "@calcom/types/utils";
import { apiKeyPublicSchema } from "~/lib/validations/api-key";
@@ -29,7 +30,7 @@ function hasReqArgs(req: CustomNextApiRequest): req is Ensure<CustomNextApiReque
}
async function getHandler(req: CustomNextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
req.args = isAdmin ? {} : { where: { userId } };
// Proof of concept: allowing mutation in exchange of composability
handleAdminRequests(req);
+2 -1
View File
@@ -5,11 +5,12 @@ import { v4 } from "uuid";
import { generateUniqueAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { apiKeyCreateBodySchema, apiKeyPublicSchema } from "~/lib/validations/api-key";
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { neverExpires, userId: bodyUserId, ...input } = apiKeyCreateBodySchema.parse(req.body);
const [hashedKey, apiKey] = generateUniqueAPIKey();
const args: Prisma.ApiKeyCreateArgs = {
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const query = schemaQueryIdParseInt.parse(req.query);
// @note: Here we make sure to only return attendee's of the user's own bookings if the user is not an admin.
if (isAdmin) return;
+2 -1
View File
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -34,7 +35,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
await prisma.attendee.delete({ where: { id } });
return { message: `Attendee with id: ${id} deleted successfully` };
+2 -1
View File
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaAttendeeReadPublic } from "~/lib/validations/attendee";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -35,7 +36,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Attendee was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const attendee = await prisma.attendee.findUnique({ where: { id } });
return { attendee: schemaAttendeeReadPublic.parse(attendee) };
+3 -2
View File
@@ -3,6 +3,7 @@ import type { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "~/lib/validations/attendee";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -53,7 +54,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query, body } = req;
const { query, body } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = schemaAttendeeEditBodyParams.parse(body);
await checkPermissions(req, data);
@@ -62,7 +63,7 @@ export async function patchHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest, body: z.infer<typeof schemaAttendeeEditBodyParams>) {
const { isAdmin, prisma } = req;
const { isAdmin } = req;
if (isAdmin) return;
const { userId } = req;
const { bookingId } = body;
+2 -1
View File
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaAttendeeReadPublic } from "~/lib/validations/attendee";
@@ -30,7 +31,7 @@ import { schemaAttendeeReadPublic } from "~/lib/validations/attendee";
* description: No attendees were found
*/
async function handler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const args: Prisma.AttendeeFindManyArgs = isAdmin ? {} : { where: { booking: { userId } } };
const data = await prisma.attendee.findMany(args);
const attendees = data.map((attendee) => schemaAttendeeReadPublic.parse(attendee));
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "~/lib/validations/attendee";
@@ -51,7 +52,7 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "~/lib/
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const body = schemaAttendeeCreateBodyParams.parse(req.body);
if (!isAdmin) {
@@ -1,9 +1,11 @@
import type { NextApiRequest } from "next";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, prisma, isAdmin, query } = req;
const { userId, isAdmin, query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
/** Admins can skip the ownership verification */
if (isAdmin) return;
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -36,7 +37,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
await prisma.availability.delete({ where: { id } });
return { message: `Availability with id: ${id} deleted successfully` };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaAvailabilityReadPublic } from "~/lib/validations/availability";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -37,7 +38,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Availability not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const availability = await prisma.availability.findUnique({
where: { id },
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaAvailabilityEditBodyParams,
@@ -72,7 +73,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query, body } = req;
const { query, body } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = schemaAvailabilityEditBodyParams.parse(body);
const availability = await prisma.availability.update({
+2 -2
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaAvailabilityCreateBodyParams,
@@ -71,7 +72,6 @@ import {
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { prisma } = req;
const data = schemaAvailabilityCreateBodyParams.parse(req.body);
await checkPermissions(req);
const availability = await prisma.availability.create({
@@ -86,7 +86,7 @@ async function postHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
if (isAdmin) return;
const data = schemaAvailabilityCreateBodyParams.parse(req.body);
const schedule = await prisma.schedule.findFirst({
+2 -1
View File
@@ -4,6 +4,7 @@ import { z } from "zod";
import { getUserAvailability } from "@calcom/core/getUserAvailability";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { availabilityUserSelect } from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import { stringOrNumber } from "@calcom/prisma/zod-utils";
@@ -188,7 +189,7 @@ const availabilitySchema = z
);
async function handler(req: NextApiRequest) {
const { prisma, isAdmin, userId: reqUserId } = req;
const { isAdmin, userId: reqUserId } = req;
const { username, userId, eventTypeId, dateTo, dateFrom, teamId } = availabilitySchema.parse(req.query);
if (!teamId)
return getUserAvailability({
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
// Here we make sure to only return references of the user's own bookings if the user is not an admin.
if (isAdmin) return;
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -34,7 +35,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
await prisma.bookingReference.delete({ where: { id } });
return { message: `BookingReference with id: ${id} deleted` };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaBookingReferenceReadPublic } from "~/lib/validations/booking-reference";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -35,7 +36,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: BookingReference was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const booking_reference = await prisma.bookingReference.findUniqueOrThrow({ where: { id } });
return { booking_reference: schemaBookingReferenceReadPublic.parse(booking_reference) };
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaBookingEditBodyParams,
@@ -59,7 +60,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query, body, isAdmin, userId } = req;
const { query, body, isAdmin, userId } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = schemaBookingEditBodyParams.parse(body);
/* If user tries to update bookingId, we run extra checks */
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaBookingReferenceReadPublic } from "~/lib/validations/booking-reference";
@@ -29,7 +30,7 @@ import { schemaBookingReferenceReadPublic } from "~/lib/validations/booking-refe
* description: No booking references were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const args: Prisma.BookingReferenceFindManyArgs = isAdmin ? {} : { where: { booking: { userId } } };
const data = await prisma.bookingReference.findMany(args);
return { booking_references: data.map((br) => schemaBookingReferenceReadPublic.parse(br)) };
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaBookingCreateBodyParams,
@@ -61,7 +62,7 @@ import {
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const body = schemaBookingCreateBodyParams.parse(req.body);
const args: Prisma.BookingFindFirstOrThrowArgs = isAdmin
? /* If admin, we only check that the booking exists */
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, prisma, isAdmin, query } = req;
const { userId, isAdmin, query } = req;
if (isAdmin) {
return;
}
+2 -1
View File
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaBookingReadPublic } from "~/lib/validations/booking";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -86,7 +87,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const booking = await prisma.booking.findUnique({
where: { id },
+2 -1
View File
@@ -3,6 +3,7 @@ import type { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "~/lib/validations/booking";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -99,7 +100,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query, body } = req;
const { query, body } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = schemaBookingEditBodyParams.parse(body);
await checkPermissions(req, data);
+2 -1
View File
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaBookingGetParams, schemaBookingReadPublic } from "~/lib/validations/booking";
import { schemaQuerySingleOrMultipleAttendeeEmails } from "~/lib/validations/shared/queryAttendeeEmail";
@@ -161,7 +162,7 @@ function buildWhereClause(
}
async function handler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { dateFrom, dateTo } = schemaBookingGetParams.parse(req.query);
@@ -0,0 +1,64 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import { schemaCredentialDeleteParams } from "~/lib/validations/credential-sync";
/**
* @swagger
* /credential-sync:
* delete:
* operationId: deleteUserAppCredential
* summary: Delete a credential record for a user
* parameters:
* - in: query
* name: apiKey
* required: true
* schema:
* type: string
* description: Your API key
* - in: query
* name: userId
* required: true
* schema:
* type: string
* description: ID of the user to fetch the credentials for
* - in: query
* name: credentialId
* required: true
* schema:
* type: string
* description: ID of the credential to update
* tags:
* - credentials
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 505:
* description: Credential syncing not enabled
*/
async function handler(req: NextApiRequest) {
const { prisma } = req;
const { userId: reqUserId, credentialId: reqCredentialId } = schemaCredentialDeleteParams.parse(req.query);
const userId = parseInt(reqUserId);
const credentialId = parseInt(reqCredentialId);
const credential = await prisma.credential.delete({
where: {
id: credentialId,
userId,
},
select: {
id: true,
appId: true,
},
});
return { credentialDeleted: credential };
}
export default defaultResponder(handler);
@@ -0,0 +1,63 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import { schemaCredentialGetParams } from "~/lib/validations/credential-sync";
/**
* @swagger
* /credential-sync:
* get:
* operationId: getUserAppCredentials
* summary: Get all app credentials for a user
* parameters:
* - in: query
* name: apiKey
* required: true
* schema:
* type: string
* description: Your API key
* - in: query
* name: userId
* required: true
* schema:
* type: string
* description: ID of the user to fetch the credentials for
* tags:
* - credentials
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 505:
* description: Credential syncing not enabled
*/
async function handler(req: NextApiRequest) {
const { prisma } = req;
const { appSlug, userId } = schemaCredentialGetParams.parse(req.query);
let credentials = await prisma.credential.findMany({
where: {
userId,
...(appSlug && { appId: appSlug }),
},
select: {
id: true,
appId: true,
},
});
// For apps we're transitioning to using the term slug to keep things consistent
credentials = credentials.map((credential) => {
return {
...credential,
appSlug: credential.appId,
};
});
return { credentials };
}
export default defaultResponder(handler);
@@ -0,0 +1,86 @@
import type { NextApiRequest } from "next";
import { minimumTokenResponseSchema } from "@calcom/app-store/_utils/oauth/parseRefreshTokenResponse";
import { symmetricDecrypt } from "@calcom/lib/crypto";
import { defaultResponder } from "@calcom/lib/server";
import { schemaCredentialPatchParams, schemaCredentialPatchBody } from "~/lib/validations/credential-sync";
/**
* @swagger
* /credential-sync:
* patch:
* operationId: updateUserAppCredential
* summary: Update a credential record for a user
* parameters:
* - in: query
* name: apiKey
* required: true
* schema:
* type: string
* description: Your API key
* - in: query
* name: userId
* required: true
* schema:
* type: string
* description: ID of the user to fetch the credentials for
* - in: query
* name: credentialId
* required: true
* schema:
* type: string
* description: ID of the credential to update
* tags:
* - credentials
* requestBody:
* description: Update a new credential
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - encryptedKey
* properties:
* encryptedKey:
* type: string
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 505:
* description: Credential syncing not enabled
*/
async function handler(req: NextApiRequest) {
const { prisma } = req;
const { userId, credentialId } = schemaCredentialPatchParams.parse(req.query);
const { encryptedKey } = schemaCredentialPatchBody.parse(req.body);
const decryptedKey = JSON.parse(
symmetricDecrypt(encryptedKey, process.env.CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY || "")
);
const key = minimumTokenResponseSchema.parse(decryptedKey);
const credential = await prisma.credential.update({
where: {
id: credentialId,
userId,
},
data: {
key,
},
select: {
id: true,
appId: true,
},
});
return { credential };
}
export default defaultResponder(handler);
+142
View File
@@ -0,0 +1,142 @@
import type { NextApiRequest } from "next";
import { getCalendar } from "@calcom/app-store/_utils/getCalendar";
import { minimumTokenResponseSchema } from "@calcom/app-store/_utils/oauth/parseRefreshTokenResponse";
import { appStoreMetadata } from "@calcom/app-store/appStoreMetaData";
import { symmetricDecrypt } from "@calcom/lib/crypto";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import { schemaCredentialPostParams, schemaCredentialPostBody } from "~/lib/validations/credential-sync";
/**
* @swagger
* /credential-sync:
* post:
* operationId: createUserAppCredential
* summary: Create a credential record for a user
* parameters:
* - in: query
* name: apiKey
* required: true
* schema:
* type: string
* description: Your API key
* - in: query
* name: userId
* required: true
* schema:
* type: string
* description: ID of the user to fetch the credentials for
* tags:
* - credentials
* requestBody:
* description: Create a new credential
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - encryptedKey
* - appSlug
* properties:
* encryptedKey:
* type: string
* appSlug:
* type: string
* responses:
* 200:
* description: OK
* 401:
* description: Authorization information is missing or invalid.
* 505:
* description: Credential syncing not enabled
*/
async function handler(req: NextApiRequest) {
const { prisma } = req;
if (!req.body) {
throw new HttpError({ message: "Request body is missing", statusCode: 400 });
}
const { userId, createSelectedCalendar, createDestinationCalendar } = schemaCredentialPostParams.parse(
req.query
);
const { appSlug, encryptedKey } = schemaCredentialPostBody.parse(req.body);
const decryptedKey = JSON.parse(
symmetricDecrypt(encryptedKey, process.env.CALCOM_APP_CREDENTIAL_ENCRYPTION_KEY || "")
);
const key = minimumTokenResponseSchema.parse(decryptedKey);
// Need to get app type
const app = await prisma.app.findUnique({
where: { slug: appSlug },
select: { dirName: true, categories: true },
});
if (!app) {
throw new HttpError({ message: "App not found", statusCode: 500 });
}
const createCalendarResources =
app.categories.some((category) => category === "calendar") &&
(createSelectedCalendar || createDestinationCalendar);
const appMetadata = appStoreMetadata[app.dirName as keyof typeof appStoreMetadata];
const credential = await prisma.credential.create({
data: {
userId,
appId: appSlug,
key,
type: appMetadata.type,
},
include: {
user: {
select: {
email: true,
},
},
},
});
if (createCalendarResources) {
const calendar = await getCalendar(credential);
const calendars = await calendar.listCalendars();
const calendarToCreate = calendars.find((calendar) => calendar.primary) || calendars[0];
if (createSelectedCalendar) {
await prisma.selectedCalendar.createMany({
data: [
{
userId,
integration: appMetadata.type,
externalId: calendarToCreate.externalId,
credentialId: credential.id,
},
],
skipDuplicates: true,
});
}
if (createDestinationCalendar) {
await prisma.destinationCalendar.create({
data: {
integration: appMetadata.type,
externalId: calendarToCreate.externalId,
credential: { connect: { id: credential.id } },
primaryEmail: calendarToCreate.email || credential.user.email,
user: { connect: { id: userId } },
},
});
}
}
return { credential: { id: credential.id, type: credential.type } };
}
export default defaultResponder(handler);
@@ -0,0 +1,12 @@
import { defaultHandler } from "@calcom/lib/server";
import { withMiddleware } from "~/lib/helpers/withMiddleware";
export default withMiddleware("verifyCredentialSyncEnabled")(
defaultHandler({
GET: import("./_get"),
POST: import("./_post"),
PATCH: import("./_patch"),
DELETE: import("./_delete"),
})
);
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
// Admins can just skip this check
if (isAdmin) return;
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -33,7 +34,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
await prisma.eventTypeCustomInput.delete({ where: { id } });
return { message: `CustomInputEventType with id: ${id} deleted successfully` };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaEventTypeCustomInputPublic } from "~/lib/validations/event-type-custom-input";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -34,7 +35,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: EventType was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = await prisma.eventTypeCustomInput.findUniqueOrThrow({ where: { id } });
return { event_type_custom_input: schemaEventTypeCustomInputPublic.parse(data) };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaEventTypeCustomInputEditBodyParams,
@@ -76,7 +77,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = schemaEventTypeCustomInputEditBodyParams.parse(req.body);
const result = await prisma.eventTypeCustomInput.update({ where: { id }, data });
+2 -1
View File
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaEventTypeCustomInputPublic } from "~/lib/validations/event-type-custom-input";
@@ -28,7 +29,7 @@ import { schemaEventTypeCustomInputPublic } from "~/lib/validations/event-type-c
* description: No eventTypeCustomInputs were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const args: Prisma.EventTypeCustomInputFindManyArgs = isAdmin ? {} : { where: { eventType: { userId } } };
const data = await prisma.eventTypeCustomInput.findMany(args);
return { event_type_custom_inputs: data.map((v) => schemaEventTypeCustomInputPublic.parse(v)) };
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaEventTypeCustomInputBodyParams,
@@ -79,7 +80,7 @@ import {
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { eventTypeId, ...body } = schemaEventTypeCustomInputBodyParams.parse(req.body);
if (!isAdmin) {
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
if (isAdmin) return;
const userEventTypes = await prisma.eventType.findMany({
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -33,7 +34,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Destination calendar not found
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
await prisma.destinationCalendar.delete({ where: { id } });
return { message: `OK, Destination Calendar removed successfully` };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaDestinationCalendarReadPublic } from "~/lib/validations/destination-calendar";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -34,7 +35,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Destination calendar not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const destinationCalendar = await prisma.destinationCalendar.findUnique({
@@ -5,6 +5,7 @@ import type { z } from "zod";
import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import type { PrismaClient } from "@calcom/prisma";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
@@ -82,7 +83,7 @@ type UserCredentialType = {
};
export async function patchHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma, query, body } = req;
const { userId, isAdmin, query, body } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const parsedBody = schemaDestinationCalendarEditBodyParams.parse(body);
const assignedUserId = isAdmin ? parsedBody.userId || userId : userId;
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { extractUserIdsFromQuery } from "~/lib/utils/extractUserIdsFromQuery";
import { schemaDestinationCalendarReadPublic } from "~/lib/validations/destination-calendar";
@@ -29,7 +30,7 @@ import { schemaDestinationCalendarReadPublic } from "~/lib/validations/destinati
* description: No destination calendars were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, prisma } = req;
const { userId } = req;
const userIds = req.query.userId ? extractUserIdsFromQuery(req) : [userId];
const userEventTypes = await prisma.eventType.findMany({
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { getCalendarCredentials, getConnectedCalendars } from "@calcom/core/CalendarManager";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
import {
@@ -60,7 +61,7 @@ import {
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma, body } = req;
const { userId, isAdmin, body } = req;
const parsedBody = schemaDestinationCalendarCreateBodyParams.parse(body);
await checkPermissions(req, userId);
@@ -132,7 +133,7 @@ async function checkPermissions(req: NextApiRequest, userId: number) {
if (isAdmin && !body.userId) throw new HttpError({ statusCode: 400, message: "`userId` required" });
/* User should only be able to create for their own destination calendars*/
if (!isAdmin && body.eventTypeId) {
const ownsEventType = await req.prisma.eventType.findFirst({ where: { id: body.eventTypeId, userId } });
const ownsEventType = await prisma.eventType.findFirst({ where: { id: body.eventTypeId, userId } });
if (!ownsEventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" });
}
// TODO:: Add support for team event types with validation
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
if (isAdmin) return;
const eventType = await prisma.eventType.findFirst({
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -37,7 +38,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
await checkPermissions(req);
await prisma.eventType.delete({ where: { id } });
@@ -45,7 +46,7 @@ export async function deleteHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
if (isAdmin) return;
/** Only event type owners can delete it */
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
@@ -43,7 +44,7 @@ import getCalLink from "../_utils/getCalLink";
* description: EventType was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const eventType = await prisma.eventType.findUnique({
@@ -4,6 +4,7 @@ import type { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { SchedulingType } from "@calcom/prisma/enums";
import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type";
@@ -203,7 +204,7 @@ import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query, body } = req;
const { query, body } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const {
hosts = [],
@@ -236,7 +237,7 @@ export async function patchHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest, body: z.infer<typeof schemaEventTypeBaseBodyParams>) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
if (isAdmin) return;
/** Only event type owners can modify it */
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import type { PrismaClient } from "@calcom/prisma";
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
@@ -42,7 +43,7 @@ import getCalLink from "./_utils/getCalLink";
* description: No event types were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
const userIds = req.query.userId ? extractUserIdsFromQuery(req) : [userId];
const { slug } = schemaQuerySlug.parse(req.query);
const shouldUseUserId = !isAdmin || !slug || !!req.query.userId;
+3 -2
View File
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/client";
import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type";
@@ -264,7 +265,7 @@ import ensureOnlyMembersAsHosts from "./_utils/ensureOnlyMembersAsHosts";
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma, body } = req;
const { userId, isAdmin, body } = req;
const {
hosts = [],
@@ -321,7 +322,7 @@ async function checkPermissions(req: NextApiRequest) {
if (
body.teamId &&
!isAdmin &&
!(await canUserAccessTeamWithRole(req.prisma, req.userId, isAdmin, body.teamId, {
!(await canUserAccessTeamWithRole(req.userId, isAdmin, body.teamId, {
in: [MembershipRole.OWNER, MembershipRole.ADMIN],
}))
)
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
/**
* Checks if a user, identified by the provided userId, has ownership (or admin rights) over
@@ -13,7 +14,7 @@ import { HttpError } from "@calcom/lib/http-error";
* or if the user doesn't have ownership or admin rights to the associated team.
*/
export default async function checkParentEventOwnership(req: NextApiRequest) {
const { userId, prisma, body } = req;
const { userId, body } = req;
/** These are already parsed upstream, we can assume they're good here. */
const parentId = Number(body.parentId);
const parentEventType = await prisma.eventType.findUnique({
@@ -2,14 +2,19 @@ import type { NextApiRequest } from "next";
import type { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type";
import type { schemaEventTypeCreateBodyParams } from "~/lib/validations/event-type";
export default async function checkTeamEventEditPermission(
req: NextApiRequest,
body: Pick<z.infer<typeof schemaEventTypeBaseBodyParams>, "teamId">
body: Pick<z.infer<typeof schemaEventTypeCreateBodyParams>, "teamId" | "userId">
) {
const { prisma, userId } = req;
const { isAdmin } = req;
let userId = req.userId;
if (isAdmin && body.userId) {
userId = body.userId;
}
if (body.teamId) {
const membership = await prisma.membership.findFirst({
where: {
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
/**
* Checks if a user, identified by the provided userId, is a member of the team associated
@@ -13,7 +14,7 @@ import { HttpError } from "@calcom/lib/http-error";
* or if the user isn't a member of the associated team.
*/
export default async function checkUserMembership(req: NextApiRequest) {
const { prisma, body } = req;
const { body } = req;
/** These are already parsed upstream, we can assume they're good here. */
const parentId = Number(body.parentId);
const userId = Number(body.userId);
@@ -1,6 +1,8 @@
import type { NextApiRequest } from "next";
import type { z } from "zod";
import prisma from "@calcom/prisma";
import type { schemaEventTypeCreateBodyParams } from "~/lib/validations/event-type";
export default async function ensureOnlyMembersAsHosts(
@@ -8,7 +10,7 @@ export default async function ensureOnlyMembersAsHosts(
body: Pick<z.infer<typeof schemaEventTypeCreateBodyParams>, "hosts" | "teamId">
) {
if (body.teamId && body.hosts && body.hosts.length > 0) {
const teamMemberCount = await req.prisma.membership.count({
const teamMemberCount = await prisma.membership.count({
where: {
teamId: body.teamId,
userId: { in: body.hosts.map((host) => host.userId) },
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { createContext } from "@calcom/trpc/server/createContext";
import { viewerTeamsRouter } from "@calcom/trpc/server/routers/viewer/teams/_router";
import type { TInviteMemberInputSchema } from "@calcom/trpc/server/routers/viewer/teams/inviteMember/inviteMember.schema";
@@ -57,7 +58,7 @@ async function postHandler(req: NextApiRequest, res: NextApiResponse) {
}
async function checkPermissions(req: NextApiRequest, body: TInviteMemberInputSchema) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
if (isAdmin) return;
// To prevent auto-accepted invites, limit it to ADMIN users
if (!isAdmin && "accepted" in body)
+2 -1
View File
@@ -1,10 +1,11 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaUserReadPublic } from "~/lib/validations/user";
async function handler({ userId, prisma }: NextApiRequest) {
async function handler({ userId }: NextApiRequest) {
const data = await prisma.user.findUniqueOrThrow({ where: { id: userId } });
return { user: schemaUserReadPublic.parse(data) };
}
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { membershipIdSchema } from "~/lib/validations/membership";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { teamId } = membershipIdSchema.parse(req.query);
// Admins can just skip this check
if (isAdmin) return;
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { membershipIdSchema } from "~/lib/validations/membership";
@@ -34,7 +35,7 @@ import { membershipIdSchema } from "~/lib/validations/membership";
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const userId_teamId = membershipIdSchema.parse(query);
await checkPermissions(req);
await prisma.membership.delete({ where: { userId_teamId } });
@@ -42,7 +43,7 @@ export async function deleteHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest) {
const { prisma, isAdmin, userId, query } = req;
const { isAdmin, userId, query } = req;
const userId_teamId = membershipIdSchema.parse(query);
// Admin User can do anything including deletion of Admin Team Member in any team
if (isAdmin) {
+2 -1
View File
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { membershipIdSchema, schemaMembershipPublic } from "~/lib/validations/membership";
@@ -34,7 +35,7 @@ import { membershipIdSchema, schemaMembershipPublic } from "~/lib/validations/me
* description: Membership was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const userId_teamId = membershipIdSchema.parse(query);
const args: Prisma.MembershipFindUniqueOrThrowArgs = { where: { userId_teamId } };
// Just in case the user want to get more info about the team itself
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
membershipEditBodySchema,
@@ -39,7 +40,7 @@ import {
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const userId_teamId = membershipIdSchema.parse(query);
const data = membershipEditBodySchema.parse(req.body);
const args: Prisma.MembershipUpdateArgs = { where: { userId_teamId }, data };
@@ -51,7 +52,7 @@ export async function patchHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { userId: queryUserId, teamId } = membershipIdSchema.parse(req.query);
const data = membershipEditBodySchema.parse(req.body);
// Admins can just skip this check
+1 -1
View File
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaMembershipPublic } from "~/lib/validations/membership";
import {
@@ -26,7 +27,6 @@ import {
* description: No memberships were found
*/
async function getHandler(req: NextApiRequest) {
const { prisma } = req;
const args: Prisma.MembershipFindManyArgs = {
where: {
/** Admins can query multiple users */
+2 -2
View File
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { membershipCreateBodySchema, schemaMembershipPublic } from "~/lib/validations/membership";
@@ -22,7 +23,6 @@ import { membershipCreateBodySchema, schemaMembershipPublic } from "~/lib/valida
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { prisma } = req;
const data = membershipCreateBodySchema.parse(req.body);
const args: Prisma.MembershipCreateArgs = { data };
@@ -37,7 +37,7 @@ async function postHandler(req: NextApiRequest) {
}
async function checkPermissions(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
if (isAdmin) return;
const body = membershipCreateBodySchema.parse(req.body);
// To prevent auto-accepted invites, limit it to ADMIN users
+3 -1
View File
@@ -1,5 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "~/lib/helpers/withMiddleware";
import type { PaymentResponse } from "~/lib/types";
import { schemaPaymentPublic } from "~/lib/validations/payment";
@@ -37,7 +39,7 @@ import {
* description: Payment was not found
*/
export async function paymentById(
{ method, query, userId, prisma }: NextApiRequest,
{ method, query, userId }: NextApiRequest,
res: NextApiResponse<PaymentResponse>
) {
const safeQuery = schemaQueryIdParseInt.safeParse(query);
+3 -1
View File
@@ -1,5 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";
import prisma from "@calcom/prisma";
import { withMiddleware } from "~/lib/helpers/withMiddleware";
import type { PaymentsResponse } from "~/lib/types";
import { schemaPaymentPublic } from "~/lib/validations/payment";
@@ -19,7 +21,7 @@ import { schemaPaymentPublic } from "~/lib/validations/payment";
* 404:
* description: No payments were found
*/
async function allPayments({ userId, prisma }: NextApiRequest, res: NextApiResponse<PaymentsResponse>) {
async function allPayments({ userId }: NextApiRequest, res: NextApiResponse<PaymentsResponse>) {
const userWithBookings = await prisma.user.findUnique({
where: { id: userId },
include: { bookings: true },
@@ -1,11 +1,12 @@
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
async function authMiddleware(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { id } = schemaQueryIdParseInt.parse(req.query);
// Admins can just skip this check
if (isAdmin) return;
+2 -1
View File
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -34,7 +35,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
/* If we're deleting any default user schedule, we unset it */
+2 -1
View File
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaSchedulePublic } from "~/lib/validations/schedule";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -72,7 +73,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = await prisma.schedule.findUniqueOrThrow({ where: { id }, include: { availability: true } });
return { schedule: schemaSchedulePublic.parse(data) };
+2 -1
View File
@@ -3,6 +3,7 @@ import type { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaSchedulePublic, schemaSingleScheduleBodyParams } from "~/lib/validations/schedule";
import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt";
@@ -81,7 +82,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { id } = schemaQueryIdParseInt.parse(query);
const data = schemaSingleScheduleBodyParams.parse(req.body);
await checkPermissions(req, data);
+2 -1
View File
@@ -4,6 +4,7 @@ import { z } from "zod";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaSchedulePublic } from "~/lib/validations/schedule";
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
@@ -76,7 +77,7 @@ export const schemaUserIds = z
*/
async function handler(req: NextApiRequest) {
const { prisma, userId, isAdmin } = req;
const { userId, isAdmin } = req;
const args: Prisma.ScheduleFindManyArgs = isAdmin ? {} : { where: { userId } };
args.include = { availability: true };
+2 -1
View File
@@ -4,6 +4,7 @@ import type { NextApiRequest } from "next";
import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/validations/schedule";
@@ -79,7 +80,7 @@ import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/vali
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const body = schemaCreateScheduleBodyParams.parse(req.body);
let args: Prisma.ScheduleCreateArgs = { data: { ...body, userId } };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { selectedCalendarIdSchema } from "~/lib/validations/selected-calendar";
@@ -46,7 +47,7 @@ import { selectedCalendarIdSchema } from "~/lib/validations/selected-calendar";
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const userId_integration_externalId = selectedCalendarIdSchema.parse(query);
await prisma.selectedCalendar.delete({ where: { userId_integration_externalId } });
return { message: `Selected Calendar with id: ${query.id} deleted successfully` };
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaSelectedCalendarPublic, selectedCalendarIdSchema } from "~/lib/validations/selected-calendar";
@@ -46,7 +47,7 @@ import { schemaSelectedCalendarPublic, selectedCalendarIdSchema } from "~/lib/va
* description: SelectedCalendar was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const userId_integration_externalId = selectedCalendarIdSchema.parse(query);
const data = await prisma.selectedCalendar.findUniqueOrThrow({
where: { userId_integration_externalId },
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaSelectedCalendarPublic,
@@ -52,7 +53,7 @@ import {
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, query, isAdmin } = req;
const { query, isAdmin } = req;
const userId_integration_externalId = selectedCalendarIdSchema.parse(query);
const { userId: bodyUserId, ...data } = schemaSelectedCalendarUpdateBodyParams.parse(req.body);
const args: Prisma.SelectedCalendarUpdateArgs = { where: { userId_integration_externalId }, data };
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaSelectedCalendarPublic } from "~/lib/validations/selected-calendar";
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";
@@ -31,7 +32,7 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que
* description: No selected calendars were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
/* Admin gets all selected calendar by default, otherwise only the user's ones */
const args: Prisma.SelectedCalendarFindManyArgs = isAdmin ? {} : { where: { userId } };
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import {
schemaSelectedCalendarBodyParams,
@@ -49,7 +50,7 @@ import {
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { userId: bodyUserId, ...body } = schemaSelectedCalendarBodyParams.parse(req.body);
const args: Prisma.SelectedCalendarCreateArgs = { data: { ...body, userId } };
@@ -2,12 +2,13 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import prisma from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
async function authMiddleware(req: NextApiRequest) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
const { teamId } = schemaQueryTeamId.parse(req.query);
/** Admins can skip the ownership verification */
if (isAdmin) return;
@@ -21,17 +22,16 @@ export async function checkPermissions(
req: NextApiRequest,
role: Prisma.MembershipWhereInput["role"] = MembershipRole.OWNER
) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
const { teamId } = schemaQueryTeamId.parse({
teamId: req.query.teamId,
version: req.query.version,
apiKey: req.query.apiKey,
});
return canUserAccessTeamWithRole(prisma, userId, isAdmin, teamId, role);
return canUserAccessTeamWithRole(userId, isAdmin, teamId, role);
}
export async function canUserAccessTeamWithRole(
prisma: NextApiRequest["prisma"],
userId: number,
isAdmin: boolean,
teamId: number,
+2 -1
View File
@@ -1,6 +1,7 @@
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
@@ -36,7 +37,7 @@ import { checkPermissions } from "./_auth-middleware";
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, query } = req;
const { query } = req;
const { teamId } = schemaQueryTeamId.parse(query);
await checkPermissions(req);
await prisma.team.delete({ where: { id: teamId } });
+2 -1
View File
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId";
import { schemaTeamReadPublic } from "~/lib/validations/team";
@@ -36,7 +37,7 @@ import { schemaTeamReadPublic } from "~/lib/validations/team";
* description: Team was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, isAdmin, userId } = req;
const { isAdmin, userId } = req;
const { teamId } = schemaQueryTeamId.parse(req.query);
const where: Prisma.TeamWhereInput = { id: teamId };
// Non-admins can only query the teams they're part of
+2 -1
View File
@@ -5,6 +5,7 @@ import { purchaseTeamSubscription } from "@calcom/features/ee/teams/lib/payments
import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { TRPCError } from "@trpc/server";
@@ -55,7 +56,7 @@ import { schemaTeamReadPublic, schemaTeamUpdateBodyParams } from "~/lib/validati
* description: Authorization information is missing or invalid.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, body, userId } = req;
const { body, userId } = req;
const data = schemaTeamUpdateBodyParams.parse(body);
const { teamId } = schemaQueryTeamId.parse(req.query);
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { z } from "zod";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
@@ -41,7 +42,7 @@ const querySchema = z.object({
* description: No event types were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, isAdmin, prisma } = req;
const { userId, isAdmin } = req;
const { teamId } = querySchema.parse(req.query);
+2 -1
View File
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaTeamsReadPublic } from "~/lib/validations/team";
@@ -29,7 +30,7 @@ import { schemaTeamsReadPublic } from "~/lib/validations/team";
* description: No teams were found
*/
async function getHandler(req: NextApiRequest) {
const { userId, prisma, isAdmin } = req;
const { userId, isAdmin } = req;
const where: Prisma.TeamWhereInput = {};
// If user is not ADMIN, return only his data.
if (!isAdmin) where.members = { some: { userId } };
+2 -1
View File
@@ -5,6 +5,7 @@ import stripe from "@calcom/app-store/stripepayment/lib/server";
import { IS_TEAM_BILLING_ENABLED, WEBAPP_URL } from "@calcom/lib/constants";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { MembershipRole } from "@calcom/prisma/enums";
import { schemaMembershipPublic } from "~/lib/validations/membership";
@@ -78,7 +79,7 @@ import { schemaTeamCreateBodyParams, schemaTeamReadPublic } from "~/lib/validati
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { prisma, body, userId, isAdmin } = req;
const { body, userId, isAdmin } = req;
const { ownerId, ...data } = schemaTeamCreateBodyParams.parse(body);
await checkPermissions(req);
+2 -1
View File
@@ -3,6 +3,7 @@ import type { NextApiRequest } from "next";
import { deleteUser } from "@calcom/features/users/lib/userDeletionService";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId";
@@ -37,7 +38,7 @@ import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId";
* description: Authorization information is missing or invalid.
*/
export async function deleteHandler(req: NextApiRequest) {
const { prisma, isAdmin } = req;
const { isAdmin } = req;
const query = schemaQueryUserId.parse(req.query);
// Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user
if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" });
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId";
import { schemaUserReadPublic } from "~/lib/validations/user";
@@ -37,7 +38,7 @@ import { schemaUserReadPublic } from "~/lib/validations/user";
* description: User was not found
*/
export async function getHandler(req: NextApiRequest) {
const { prisma, isAdmin } = req;
const { isAdmin } = req;
const query = schemaQueryUserId.parse(req.query);
// Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId";
import { schemaUserEditBodyParams, schemaUserReadPublic } from "~/lib/validations/user";
@@ -94,7 +95,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "~/lib/validation
* description: Insufficient permissions to access resource.
*/
export async function patchHandler(req: NextApiRequest) {
const { prisma, isAdmin } = req;
const { isAdmin } = req;
const query = schemaQueryUserId.parse(req.query);
// Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user
if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" });
+1 -1
View File
@@ -2,6 +2,7 @@ import type { Prisma } from "@prisma/client";
import type { NextApiRequest } from "next";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { withMiddleware } from "~/lib/helpers/withMiddleware";
import { schemaQuerySingleOrMultipleUserEmails } from "~/lib/validations/shared/queryUserEmail";
@@ -44,7 +45,6 @@ import { schemaUsersReadPublic } from "~/lib/validations/user";
export async function getHandler(req: NextApiRequest) {
const {
userId,
prisma,
isAdmin,
pagination: { take, skip },
} = req;
+2 -1
View File
@@ -2,6 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";
import { schemaUserCreateBodyParams } from "~/lib/validations/user";
@@ -87,7 +88,7 @@ import { schemaUserCreateBodyParams } from "~/lib/validations/user";
* description: Authorization information is missing or invalid.
*/
async function postHandler(req: NextApiRequest) {
const { prisma, isAdmin } = req;
const { isAdmin } = req;
// If user is not ADMIN, return unauthorized.
if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" });
const data = await schemaUserCreateBodyParams.parseAsync(req.body);

Some files were not shown because too many files have changed in this diff Show More