Merge branch 'main' into CALCOM-11196
commit
c28052d10f
|
@ -116,6 +116,7 @@ function ConnectedCalendarsList(props: Props) {
|
|||
type={item.integration.type}
|
||||
isChecked={cal.isSelected}
|
||||
destination={cal.externalId === props.destinationCalendarId}
|
||||
credentialId={cal.credentialId}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
@ -53,6 +53,7 @@ const ConnectedCalendarItem = (prop: IConnectedCalendarItem) => {
|
|||
<ul className="p-4">
|
||||
{calendars?.map((calendar, i) => (
|
||||
<CalendarSwitch
|
||||
credentialId={calendar.credentialId}
|
||||
key={calendar.externalId}
|
||||
externalId={calendar.externalId}
|
||||
title={calendar.name || "Nameless Calendar"}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@calcom/web",
|
||||
"version": "3.2.9",
|
||||
"version": "3.2.10",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"analyze": "ANALYZE=true next build",
|
||||
|
|
|
@ -9,6 +9,7 @@ import prisma from "@calcom/prisma";
|
|||
const selectedCalendarSelectSchema = z.object({
|
||||
integration: z.string(),
|
||||
externalId: z.string(),
|
||||
credentialId: z.number().optional(),
|
||||
});
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
|
@ -37,7 +38,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
const { credentials, ...user } = userWithCredentials;
|
||||
|
||||
if (req.method === "POST") {
|
||||
const { integration, externalId } = selectedCalendarSelectSchema.parse(req.body);
|
||||
const { integration, externalId, credentialId } = selectedCalendarSelectSchema.parse(req.body);
|
||||
await prisma.selectedCalendar.upsert({
|
||||
where: {
|
||||
userId_integration_externalId: {
|
||||
|
@ -50,6 +51,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
|||
userId: user.id,
|
||||
integration,
|
||||
externalId,
|
||||
credentialId,
|
||||
},
|
||||
// already exists
|
||||
update: {},
|
||||
|
|
|
@ -182,6 +182,7 @@ const CalendarsView = () => {
|
|||
{item.calendars.map((cal) => (
|
||||
<CalendarSwitch
|
||||
key={cal.externalId}
|
||||
credentialId={cal.credentialId}
|
||||
externalId={cal.externalId}
|
||||
title={cal.name || "Nameless calendar"}
|
||||
name={cal.name || "Nameless calendar"}
|
||||
|
|
|
@ -15,9 +15,10 @@ interface ICalendarSwitchProps {
|
|||
name: string;
|
||||
isLastItemInList?: boolean;
|
||||
destination?: boolean;
|
||||
credentialId: number;
|
||||
}
|
||||
const CalendarSwitch = (props: ICalendarSwitchProps) => {
|
||||
const { title, externalId, type, isChecked, name, isLastItemInList = false } = props;
|
||||
const { title, externalId, type, isChecked, name, isLastItemInList = false, credentialId } = props;
|
||||
const [checkedInternal, setCheckedInternal] = useState(isChecked);
|
||||
const utils = trpc.useContext();
|
||||
const { t } = useLocale();
|
||||
|
@ -40,7 +41,7 @@ const CalendarSwitch = (props: ICalendarSwitchProps) => {
|
|||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
body: JSON.stringify({ ...body, credentialId }),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "SelectedCalendar" ADD COLUMN "credentialId" INTEGER;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SelectedCalendar" ADD CONSTRAINT "SelectedCalendar_credentialId_fkey" FOREIGN KEY ("credentialId") REFERENCES "Credential"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -137,6 +137,7 @@ model Credential {
|
|||
// How to make it a required column?
|
||||
appId String?
|
||||
destinationCalendars DestinationCalendar[]
|
||||
selectedCalendars SelectedCalendar[]
|
||||
invalid Boolean? @default(false)
|
||||
|
||||
@@index([userId])
|
||||
|
@ -448,10 +449,12 @@ model Availability {
|
|||
}
|
||||
|
||||
model SelectedCalendar {
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId Int
|
||||
integration String
|
||||
externalId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId Int
|
||||
integration String
|
||||
externalId String
|
||||
credential Credential? @relation(fields: [credentialId], references: [id], onDelete: Cascade)
|
||||
credentialId Int?
|
||||
|
||||
@@id([userId, integration, externalId])
|
||||
@@index([userId])
|
||||
|
|
|
@ -307,38 +307,6 @@ export const deleteCredentialHandler = async ({ ctx, input }: DeleteCredentialOp
|
|||
}
|
||||
}
|
||||
|
||||
// If it's a calendar remove it from the SelectedCalendars
|
||||
if (credential.app?.categories.includes(AppCategories.calendar)) {
|
||||
const calendar = await getCalendar(credential);
|
||||
|
||||
const calendars = await calendar?.listCalendars();
|
||||
|
||||
if (calendars && calendars.length > 0) {
|
||||
calendars.map(async (cal) => {
|
||||
prisma.selectedCalendar
|
||||
.delete({
|
||||
where: {
|
||||
userId_integration_externalId: {
|
||||
userId: user.id,
|
||||
externalId: cal.externalId,
|
||||
integration: cal.integration as string,
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025") {
|
||||
console.log(
|
||||
`Error deleting selected calendars for user ${user.id} and calendar ${credential.appId}. Could not find selected calendar.`
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`Error deleting selected calendars for user ${user.id} and calendar ${credential.appId} with error: ${error}`
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// if zapier get disconnected, delete zapier apiKey, delete zapier webhooks and cancel all scheduled jobs from zapier
|
||||
if (credential.app?.slug === "zapier") {
|
||||
await prisma.apiKey.deleteMany({
|
||||
|
@ -372,4 +340,46 @@ export const deleteCredentialHandler = async ({ ctx, input }: DeleteCredentialOp
|
|||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
// Backwards compatibility. Selected calendars cascade on delete when deleting a credential
|
||||
// If it's a calendar remove it from the SelectedCalendars
|
||||
if (credential.app?.categories.includes(AppCategories.calendar)) {
|
||||
const selectedCalendars = await prisma.selectedCalendar.findMany({
|
||||
where: {
|
||||
userId: user.id,
|
||||
integration: credential.type as string,
|
||||
},
|
||||
});
|
||||
|
||||
if (selectedCalendars.length) {
|
||||
const calendar = await getCalendar(credential);
|
||||
|
||||
const calendars = await calendar?.listCalendars();
|
||||
|
||||
if (calendars && calendars.length > 0) {
|
||||
calendars.map(async (cal) => {
|
||||
prisma.selectedCalendar
|
||||
.delete({
|
||||
where: {
|
||||
userId_integration_externalId: {
|
||||
userId: user.id,
|
||||
externalId: cal.externalId,
|
||||
integration: cal.integration as string,
|
||||
},
|
||||
},
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === "P2025") {
|
||||
console.log(
|
||||
`Error deleting selected calendars for user ${user.id} and calendar ${credential.appId}. Could not find selected calendar.`
|
||||
);
|
||||
}
|
||||
console.log(
|
||||
`Error deleting selected calendars for user ${user.id} and calendar ${credential.appId} with error: ${error}`
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -214,7 +214,7 @@ export interface IntegrationCalendar extends Ensure<Partial<SelectedCalendar>, "
|
|||
// For displaying the connected email address
|
||||
email?: string;
|
||||
primaryEmail?: string;
|
||||
credentialId?: number;
|
||||
credentialId?: number | null;
|
||||
integrationTitle?: string;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue