From 3bb42f276e99d54bf8c0c78f441f00368cca676a Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Wed, 1 Nov 2023 09:34:05 -0400 Subject: [PATCH 01/10] fix: Attach `credentialId` to location option (#12086) Co-authored-by: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Co-authored-by: Udit Takkar --- .../components/dialog/EditLocationDialog.tsx | 6 ++--- .../components/eventtype/EventSetupTab.tsx | 24 ++++++++++++++++--- .../web/components/ui/form/LocationSelect.tsx | 4 ++-- packages/app-store/server.ts | 8 ++++++- 4 files changed, 33 insertions(+), 9 deletions(-) diff --git a/apps/web/components/dialog/EditLocationDialog.tsx b/apps/web/components/dialog/EditLocationDialog.tsx index b891235c65..252d5fcf92 100644 --- a/apps/web/components/dialog/EditLocationDialog.tsx +++ b/apps/web/components/dialog/EditLocationDialog.tsx @@ -356,9 +356,9 @@ export const EditLocationDialog = (props: ISetLocationDialog) => { onChange={(val) => { if (val) { locationFormMethods.setValue("locationType", val.value); - if (val.credential) { - locationFormMethods.setValue("credentialId", val.credential.id); - locationFormMethods.setValue("teamName", val.credential.team?.name); + if (!!val.credentialId) { + locationFormMethods.setValue("credentialId", val.credentialId); + locationFormMethods.setValue("teamName", val.teamName); } locationFormMethods.unregister([ diff --git a/apps/web/components/eventtype/EventSetupTab.tsx b/apps/web/components/eventtype/EventSetupTab.tsx index 754f060868..559762f9cf 100644 --- a/apps/web/components/eventtype/EventSetupTab.tsx +++ b/apps/web/components/eventtype/EventSetupTab.tsx @@ -298,9 +298,21 @@ export const EventSetupTab = ( !validLocations.find((location) => location.type === newLocationType); if (canAddLocation) { - updateLocationField(index, { type: newLocationType }); + updateLocationField(index, { + type: newLocationType, + ...(e.credentialId && { + credentialId: e.credentialId, + teamName: e.teamName, + }), + }); } else { - updateLocationField(index, { type: field.type }); + updateLocationField(index, { + type: field.type, + ...(field.credentialId && { + credentialId: field.credentialId, + teamName: field.teamName, + }), + }); showToast(t("location_already_exists"), "warning"); } } @@ -382,7 +394,13 @@ export const EventSetupTab = ( !validLocations.find((location) => location.type === newLocationType); if (canAppendLocation) { - append({ type: newLocationType }); + append({ + type: newLocationType, + ...(e.credentialId && { + credentialId: e.credentialId, + teamName: e.teamName, + }), + }); setSelectedNewOption(e); } else { showToast(t("location_already_exists"), "warning"); diff --git a/apps/web/components/ui/form/LocationSelect.tsx b/apps/web/components/ui/form/LocationSelect.tsx index 5eed7c3b8e..1e3ede2341 100644 --- a/apps/web/components/ui/form/LocationSelect.tsx +++ b/apps/web/components/ui/form/LocationSelect.tsx @@ -2,7 +2,6 @@ import type { GroupBase, Props, SingleValue } from "react-select"; import { components } from "react-select"; import type { EventLocationType } from "@calcom/app-store/locations"; -import type { CredentialDataWithTeamName } from "@calcom/app-store/utils"; import { classNames } from "@calcom/lib"; import invertLogoOnDark from "@calcom/lib/invertLogoOnDark"; import { Select } from "@calcom/ui"; @@ -13,7 +12,8 @@ export type LocationOption = { icon?: string; disabled?: boolean; address?: string; - credential?: CredentialDataWithTeamName; + credentialId?: number; + teamName?: string; }; export type SingleValueLocationOption = SingleValue; diff --git a/packages/app-store/server.ts b/packages/app-store/server.ts index f88ec7597f..9bea796991 100644 --- a/packages/app-store/server.ts +++ b/packages/app-store/server.ts @@ -88,7 +88,13 @@ export async function getLocationGroupedOptions( teamName: credential.team?.name, }))) { const label = `${app.locationOption.label} ${teamName ? `(${teamName})` : ""}`; - const option = { ...app.locationOption, label, icon: app.logo, slug: app.slug }; + const option = { + ...app.locationOption, + label, + icon: app.logo, + slug: app.slug, + ...(app.credential ? { credentialId: app.credential.id, teamName: app.credential.team?.name } : {}), + }; if (apps[groupByCategory]) { apps[groupByCategory] = [...apps[groupByCategory], option]; } else { From c3537f32907815a090be69571247aaa237b0298c Mon Sep 17 00:00:00 2001 From: Lauris Skraucis Date: Wed, 1 Nov 2023 15:52:11 +0100 Subject: [PATCH 02/10] docs: needs approval label (#12177) Our CI workflow doesn't allow merging for only .md changes because the required check doesn't clear based on file filters. --- .github/ISSUE_TEMPLATE/feature_request.md | 6 ++++++ .github/PULL_REQUEST_TEMPLATE.md | 2 +- CONTRIBUTING.md | 13 ++++++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 0040d6d364..7c266e0957 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -47,3 +47,9 @@ assignees: "" --> (Share it here.) + +--- +##### House rules +- If this issue has a `🚨 needs approval` label, don't start coding yet. Wait until a core member approves feature request by removing this label, then you can start coding. + - For clarity: Non-core member issues automatically get the `🚨 needs approval` label. + - Your feature ideas are invaluable to us! However, they undergo review to ensure alignment with the product's direction. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 2ef5c789ea..0b19591ddd 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -40,7 +40,7 @@ Fixes # (issue) ## Checklist - + - I haven't read the [contributing guide](https://github.com/calcom/cal.com/blob/main/CONTRIBUTING.md) - My code doesn't follow the style guidelines of this project diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 520107e0dc..eb52da8d6f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,18 @@ Contributions are what makes the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. -- Before jumping into a PR be sure to search [existing PRs](https://github.com/calcom/cal.com/pulls) or [issues](https://github.com/calcom/cal.com/issues) for an open or closed item that relates to your submission. +## House rules + +- Before submitting a new issue or PR, check if it already exists in [issues](https://github.com/calcom/cal.com/issues) or [PRs](https://github.com/calcom/cal.com/pulls). +- GitHub issues: take note of the `🚨 needs approval` label. + - **For Contributors**: + - Feature Requests: Wait for a core member to approve and remove the `🚨 needs approval` label before you start coding or submit a PR. + - Bugs, Security, Performance, Documentation, etc.: You can start coding immediately, even if the `🚨 needs approval` label is present. This label mainly concerns feature requests. + - **Our Process**: + - Issues from non-core members automatically receive the `🚨 needs approval` label. + - We greatly value new feature ideas. To ensure consistency in the product's direction, they undergo review and approval. + + ## Priorities From 01fb3dd03b162bc2a358ca411a372ba3cb529d7c Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Thu, 2 Nov 2023 15:04:25 +0530 Subject: [PATCH 03/10] fix: hide Check for recording (#12184) --- apps/web/components/booking/BookingListItem.tsx | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/web/components/booking/BookingListItem.tsx b/apps/web/components/booking/BookingListItem.tsx index 32bb2ca515..fe33b6e9df 100644 --- a/apps/web/components/booking/BookingListItem.tsx +++ b/apps/web/components/booking/BookingListItem.tsx @@ -261,13 +261,11 @@ function BookingListItem(booking: BookingItemProps) { const title = booking.title; const showRecordingsButtons = !!(booking.isRecorded && isPast && isConfirmed); - const checkForRecordingsButton = - !showRecordingsButtons && (booking.location === "integrations:daily" || booking?.location?.trim() === ""); const showRecordingActions: ActionType[] = [ { - id: checkForRecordingsButton ? "check_for_recordings" : "view_recordings", - label: checkForRecordingsButton ? t("check_for_recordings") : t("view_recordings"), + id: "view_recordings", + label: t("view_recordings"), onClick: () => { setViewRecordingsDialogIsOpen(true); }, @@ -298,7 +296,7 @@ function BookingListItem(booking: BookingItemProps) { paymentCurrency={booking.payment[0].currency} /> )} - {(showRecordingsButtons || checkForRecordingsButton) && ( + {showRecordingsButtons && ( ) : null} {isPast && isPending && !isConfirmed ? : null} - {(showRecordingsButtons || checkForRecordingsButton) && ( - - )} + {showRecordingsButtons && } {isCancelled && booking.rescheduled && (
From 968e782dbe902879fe1745b0e3ffb42d32e65d40 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:34:59 +0400 Subject: [PATCH 04/10] Update README.md (#12176) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b19c6a3fe..97aa6d93d7 100644 --- a/README.md +++ b/README.md @@ -221,7 +221,7 @@ echo 'NEXT_PUBLIC_DEBUG=1' >> .env 1. Copy and paste your `DATABASE_URL` from `.env` to `.env.appStore`. -1. Set a 32 character random string in your `.env` file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like `openssl rand -base64 24` to generate one). +1. Set a 24 character random string in your `.env` file for the `CALENDSO_ENCRYPTION_KEY` (You can use a command like `openssl rand -base64 24` to generate one). 1. Set up the database using the Prisma schema (found in `packages/prisma/schema.prisma`) In a development environment, run: From 5d77e4ce1dbb19f739365d4531f6b2c9cb2a4ca8 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Thu, 2 Nov 2023 09:36:00 +0000 Subject: [PATCH 05/10] chore: changed readme (#12171) --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 97aa6d93d7..e089b26d15 100644 --- a/README.md +++ b/README.md @@ -597,8 +597,6 @@ Distributed under the [AGPLv3 License](https://github.com/calcom/cal.com/blob/ma Special thanks to these amazing projects which help power Cal.com: -[](https://vercel.com/?utm_source=calend-so&utm_campaign=oss) - - [Vercel](https://vercel.com/?utm_source=calend-so&utm_campaign=oss) - [Next.js](https://nextjs.org/) - [Day.js](https://day.js.org/) From 9348279818c17855533ec3c983eb2fabfaa17362 Mon Sep 17 00:00:00 2001 From: Alexander Zeitler Date: Thu, 2 Nov 2023 10:36:47 +0100 Subject: [PATCH 06/10] docs(README): remove unpaired symbol (#12133) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e089b26d15..a617a65b1f 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ Here is what you need to be able to run Cal.com. ### Setup -1. Clone the repo into a public GitHub repository (or fork https://github.com/calcom/cal.com/fork). If you plan to distribute the code, keep the source code public to comply with [AGPLv3](https://github.com/calcom/cal.com/blob/main/LICENSE). To clone in a private repository, [acquire a commercial license](https://cal.com/sales)) +1. Clone the repo into a public GitHub repository (or fork https://github.com/calcom/cal.com/fork). If you plan to distribute the code, keep the source code public to comply with [AGPLv3](https://github.com/calcom/cal.com/blob/main/LICENSE). To clone in a private repository, [acquire a commercial license](https://cal.com/sales) ```sh git clone https://github.com/calcom/cal.com.git From d8356e9a5bf217f6d6175566ba21ef08d56f61a4 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Thu, 2 Nov 2023 17:52:16 +0530 Subject: [PATCH 07/10] fix: Make sure if header is set already, it isn't set again (#12194) --- packages/lib/server/defaultResponder.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/lib/server/defaultResponder.ts b/packages/lib/server/defaultResponder.ts index 7caf1e1b51..b70f99cd04 100644 --- a/packages/lib/server/defaultResponder.ts +++ b/packages/lib/server/defaultResponder.ts @@ -13,7 +13,9 @@ export function defaultResponder(f: Handle) { performance.mark("Start"); const result = await f(req, res); ok = true; - if (result) res.json(result); + if (result && !res.writableEnded) { + res.json(result); + } } catch (err) { console.error(err); const error = getServerErrorFromUnknown(err); From d4d96eb5cd5bee02ddb113c8ce897075a60fe0c3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 2 Nov 2023 16:29:15 +0400 Subject: [PATCH 08/10] fix admin check (#12175) --- apps/api/pages/api/event-types/_post.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/api/pages/api/event-types/_post.ts b/apps/api/pages/api/event-types/_post.ts index 79a537c420..1531485e7b 100644 --- a/apps/api/pages/api/event-types/_post.ts +++ b/apps/api/pages/api/event-types/_post.ts @@ -316,8 +316,9 @@ async function checkPermissions(req: NextApiRequest) { statusCode: 401, message: "ADMIN required for `userId`", }); - /* Admin users are required to pass in a userId */ - if (isAdmin && !body.userId) throw new HttpError({ statusCode: 400, message: "`userId` required" }); + /* Admin users are required to pass in a userId or teamId */ + if (isAdmin && (!body.userId || !body.teamId)) + throw new HttpError({ statusCode: 400, message: "`userId` or `teamId` required" }); } export default defaultResponder(postHandler); From 703bcd861e6f0bdaaa50ba476b89ddc33365ce7a Mon Sep 17 00:00:00 2001 From: Somay Chauhan Date: Fri, 3 Nov 2023 00:07:19 +0530 Subject: [PATCH 09/10] fix: should allow org owners and admins to delete members from subteams (#11710) Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> --- .../ee/teams/components/MemberListItem.tsx | 4 +++- .../features/ee/teams/pages/team-members-view.tsx | 14 +++++++++++--- .../routers/viewer/teams/removeMember.handler.ts | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/features/ee/teams/components/MemberListItem.tsx b/packages/features/ee/teams/components/MemberListItem.tsx index 936732b7dc..2b356747ca 100644 --- a/packages/features/ee/teams/components/MemberListItem.tsx +++ b/packages/features/ee/teams/components/MemberListItem.tsx @@ -37,6 +37,7 @@ import TeamPill, { TeamRole } from "./TeamPill"; interface Props { team: RouterOutputs["viewer"]["teams"]["get"]; member: RouterOutputs["viewer"]["teams"]["get"]["members"][number]; + isOrgAdminOrOwner: boolean | undefined; } /** TODO: Migrate the one in apps/web to tRPC package */ @@ -109,7 +110,8 @@ export default function MemberListItem(props: Props) { (props.member.role !== MembershipRole.OWNER || ownersInTeam() > 1 || props.member.id !== currentUserId)) || - (props.team.membership?.role === MembershipRole.ADMIN && props.member.role !== MembershipRole.OWNER); + (props.team.membership?.role === MembershipRole.ADMIN && props.member.role !== MembershipRole.OWNER) || + props.isOrgAdminOrOwner; const impersonationMode = editMode && !props.member.disableImpersonation && diff --git a/packages/features/ee/teams/pages/team-members-view.tsx b/packages/features/ee/teams/pages/team-members-view.tsx index ca73614763..227c213f08 100644 --- a/packages/features/ee/teams/pages/team-members-view.tsx +++ b/packages/features/ee/teams/pages/team-members-view.tsx @@ -22,13 +22,14 @@ type Team = RouterOutputs["viewer"]["teams"]["get"]; interface MembersListProps { team: Team | undefined; + isOrgAdminOrOwner: boolean | undefined; } const checkIfExist = (comp: string, query: string) => comp.toLowerCase().replace(/\s+/g, "").includes(query.toLowerCase().replace(/\s+/g, "")); function MembersList(props: MembersListProps) { - const { team } = props; + const { team, isOrgAdminOrOwner } = props; const { t } = useLocale(); const [query, setQuery] = useState(""); @@ -56,7 +57,14 @@ function MembersList(props: MembersListProps) { {membersList?.length && team ? (
    {membersList.map((member) => { - return ; + return ( + + ); })}
) : null} @@ -161,7 +169,7 @@ const MembersView = () => { {((team?.isPrivate && isAdmin) || !team?.isPrivate || isOrgAdminOrOwner) && ( <> - +
)} diff --git a/packages/trpc/server/routers/viewer/teams/removeMember.handler.ts b/packages/trpc/server/routers/viewer/teams/removeMember.handler.ts index 9f9ed4bbb6..96b7b3cc9d 100644 --- a/packages/trpc/server/routers/viewer/teams/removeMember.handler.ts +++ b/packages/trpc/server/routers/viewer/teams/removeMember.handler.ts @@ -23,7 +23,8 @@ export const removeMemberHandler = async ({ ctx, input }: RemoveMemberOptions) = const isOrgAdmin = ctx.user.organizationId ? await isTeamAdmin(ctx.user.id, ctx.user.organizationId) : false; - if (!isAdmin && ctx.user.id !== input.memberId) throw new TRPCError({ code: "UNAUTHORIZED" }); + if (!(isAdmin || isOrgAdmin) && ctx.user.id !== input.memberId) + throw new TRPCError({ code: "UNAUTHORIZED" }); // Only a team owner can remove another team owner. if ((await isTeamOwner(input.memberId, input.teamId)) && !(await isTeamOwner(ctx.user.id, input.teamId))) throw new TRPCError({ code: "UNAUTHORIZED" }); From f044c2d7c7e9fd5a3bf1a21f959641fa9122975b Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Fri, 3 Nov 2023 01:09:58 +0530 Subject: [PATCH 10/10] fix: Embed: data-cal-origin not used by modal(which is used by both element click popup and floating button popup) (#12075) --- packages/embeds/embed-core/src/embed.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/embeds/embed-core/src/embed.ts b/packages/embeds/embed-core/src/embed.ts index df9f27e2e5..0cb67b3a05 100644 --- a/packages/embeds/embed-core/src/embed.ts +++ b/packages/embeds/embed-core/src/embed.ts @@ -236,7 +236,7 @@ export class Cal { }: { calLink: string; queryObject?: PrefillAndIframeAttrsConfig & { guest?: string | string[] }; - calOrigin?: string; + calOrigin: string | null; }) { const iframe = (this.iframe = document.createElement("iframe")); iframe.className = "cal-embed"; @@ -473,10 +473,12 @@ class CalApi { } config.embedType = "inline"; + const calConfig = this.cal.getConfig(); const iframe = this.cal.createIframe({ calLink, queryObject: withColorScheme(Cal.getQueryObject(config), containerEl), + calOrigin: calConfig.calOrigin, }); iframe.style.height = "100%"; @@ -555,6 +557,7 @@ class CalApi { modal({ calLink, config = {}, + calOrigin, __prerender = false, }: { calLink: string; @@ -607,6 +610,7 @@ class CalApi { iframe = this.cal.createIframe({ calLink, queryObject, + calOrigin: calOrigin || null, }); }