Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
91 commits
Select commit Hold shift + click to select a range
1e3308a
WIP close.com app
leog Jun 16, 2022
d55d5d3
Merge branch 'main' into feat/closecom-app
leog Aug 4, 2022
73d5d27
Removing leaked dev key (now invalid)
leog Aug 4, 2022
4d1c09c
Misspelled env variable
leog Aug 4, 2022
1b9469d
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 5, 2022
761f18e
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 5, 2022
0f29f1e
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 5, 2022
6bb2991
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 5, 2022
a643736
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 5, 2022
8964274
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 5, 2022
ab789d5
Making progress still WIP
leog Aug 5, 2022
da7cf23
Merge branch 'main' into feat/closecom-app
leog Aug 6, 2022
34705e0
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 7, 2022
ee41a4b
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 7, 2022
657bcc8
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
6b0efbf
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
442f068
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
21e2bfd
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
4db9cff
Progress + tests
leog Aug 8, 2022
ba55ea1
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
33ae79e
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
b82bb95
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
10b2b68
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
0154340
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 8, 2022
8088768
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
0719cea
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
88394a5
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
56c7ae3
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
1e6c3f9
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
ade1890
Final touches
leog Aug 9, 2022
fe82fcb
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
f4b28fd
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
188afc0
More unit tests
leog Aug 9, 2022
eeaf865
Merge branch 'feat/closecom-app' of github.com:calcom/cal.com into fe…
leog Aug 9, 2022
bf5a221
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
d7e532e
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 9, 2022
74a5499
Finished up tests
leog Aug 10, 2022
563310a
Merge branch 'feat/closecom-app' of github.com:calcom/cal.com into fe…
leog Aug 10, 2022
0699187
Merge branch 'main' into feat/closecom-app
leog Aug 10, 2022
25f91d4
Merge main
leog Aug 10, 2022
fdd01ee
Removing unneeded stuff + submodules
leog Aug 10, 2022
7b61fd0
Removing static props, fields fix
leog Aug 10, 2022
1c29518
Removing unneeded stuff p2
leog Aug 10, 2022
51df1db
Commenting
leog Aug 10, 2022
239e43f
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 10, 2022
c9ff368
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 11, 2022
66859af
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 11, 2022
44f75af
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 11, 2022
72c3397
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 11, 2022
bce1609
Refactoring Close.com Calendar Service + initial structure
leog Aug 11, 2022
da825d7
Merge branch 'main' into chore/sync-services
leog Aug 12, 2022
c19a3d6
Merge branch 'main' into feat/closecom-app
zomars Aug 12, 2022
91d84d3
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 12, 2022
4accdd0
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 12, 2022
d9e4d5e
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 12, 2022
fb49252
Merge branch 'main' into feat/closecom-app
kodiakhq[bot] Aug 12, 2022
0eea4ec
Progress con CloseComService
leog Aug 13, 2022
79e90b5
Merge branch 'main' into chore/sync-services
leog Aug 13, 2022
f3a3c32
Standarizing APIs
leog Aug 13, 2022
53c7f15
Zodifying
leog Aug 13, 2022
a784f1a
Merge branch 'feat/closecom-app' into chore/sync-services
leog Aug 13, 2022
1a245ec
Expanding sync services
leog Aug 14, 2022
b129292
Sendgrid Sync Service
leog Aug 15, 2022
12c4004
using own request for sendgrid + debug logs
leog Aug 16, 2022
4327134
Making get last booking work for console
leog Aug 16, 2022
02385f0
Helpscout dynamic app API
leog Aug 17, 2022
ab4135d
Standarizing calls + adding call from booking creation
leog Aug 17, 2022
970063a
Merge branch 'main' into chore/sync-services
leog Aug 17, 2022
0161856
Strategy change for last booking
leog Aug 18, 2022
44c37d6
Merge branch 'main' into chore/sync-services
leog Aug 18, 2022
45ea0dd
Strategy change for last booking on help scout api
leog Aug 18, 2022
679ddad
Fixing failing build
leog Aug 18, 2022
8d8fe6e
Implementing user deletion
leog Aug 18, 2022
10d5550
Merge branch 'main' into chore/sync-services
leog Aug 18, 2022
7b7ae7e
Fix linting + slight cleaning
leog Aug 19, 2022
8b597c4
Undoing eslint disable
leog Aug 19, 2022
69b8d3e
Removing more unsupported eslint properties
leog Aug 19, 2022
b1174a4
Merge branch 'main' into chore/sync-services
leog Aug 24, 2022
8d648e6
Closecom as non-standard sync service
leog Aug 25, 2022
b1abd74
Merge branch 'main' into chore/sync-services
leog Aug 25, 2022
1922d91
Merge branch 'main' into chore/sync-services
leog Aug 26, 2022
8acb1dd
Finishing closecom lead operations
leog Aug 26, 2022
4530b93
Fixing lint
leog Aug 26, 2022
f6c46e4
Guarding app from sync services
leog Aug 26, 2022
d361db8
Merge branch 'main' into chore/sync-services
leog Aug 26, 2022
73a48c8
Reverting submodules
leog Aug 26, 2022
f830426
Merge branch 'main' into chore/sync-services
zomars Aug 26, 2022
268b994
Merge branch 'main' into chore/sync-services
leog Aug 26, 2022
e557950
Applying PR feedback
leog Aug 26, 2022
c283eac
Reverting API to be plain handler
leog Aug 26, 2022
9fc920e
Cleaning notes
leog Aug 26, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,9 @@ EMAIL_SERVER_PASSWORD='<office365_password>'

# Set the following value to true if you wish to enable Team Impersonation
NEXT_PUBLIC_TEAM_IMPERSONATION=false

# Close.com internal CRM
CLOSECOM_API_KEY=

# Sendgrid internal email sender
SENDGRID_API_KEY=
Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are needed if you want to hook up Sendgrid and Close.com Sync Services. It remains optional for any self-hoster. Documentation will be done to explain Sync Services and its purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are the ones I mentioned @zomars, only for internal use and available for any self-hoster who wants to track down key info from their users in Sendgrid and Close.com

1 change: 1 addition & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"nodemailer": "^6.7.7",
"otplib": "^12.0.1",
"qrcode": "^1.5.1",
"raw-body": "^2.5.1",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used to calculate the signature from the request from Help Scout in its dedicated API

"react": "^18.2.0",
"react-colorful": "^5.5.1",
"react-date-picker": "^8.3.6",
Expand Down
24 changes: 17 additions & 7 deletions apps/web/pages/api/auth/signup.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IdentityProvider } from "@prisma/client";
import { NextApiRequest, NextApiResponse } from "next";

import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";

import { hashPassword } from "@lib/auth";
Expand Down Expand Up @@ -71,14 +72,23 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

// If user has been invitedTo a team, we accept the membership
if (user.invitedTo) {
await prisma.membership.update({
where: {
userId_teamId: { userId: user.id, teamId: user.invitedTo },
},
data: {
accepted: true,
},
const team = await prisma.team.findFirst({
where: { id: user.invitedTo },
});

if (team) {
const membership = await prisma.membership.update({
where: {
userId_teamId: { userId: user.id, teamId: user.invitedTo },
},
data: {
accepted: true,
},
});

// Sync Services: Close.com
closeComUpsertTeamUser(team, user, membership.role);
}
}

res.status(201).json({ message: "Created user" });
Expand Down
9 changes: 9 additions & 0 deletions apps/web/pages/api/book/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import isOutOfBounds, { BookingDateInPastError } from "@calcom/lib/isOutOfBounds
import logger from "@calcom/lib/logger";
import { getLuckyUser } from "@calcom/lib/server";
import { defaultResponder } from "@calcom/lib/server";
import { updateWebUser as syncServicesUpdateWebUser } from "@calcom/lib/sync/SyncServiceManager";
import prisma, { userSelect } from "@calcom/prisma";
import { extendedBookingCreateBody } from "@calcom/prisma/zod-utils";
import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime";
Expand Down Expand Up @@ -673,6 +674,14 @@ async function handler(req: NextApiRequest) {
let booking: Booking | null = null;
try {
booking = await createBooking();
// Sync Services
await syncServicesUpdateWebUser(
currentUser &&
(await prisma.user.findFirst({
where: { id: currentUser.id },
select: { id: true, email: true, name: true, plan: true, username: true, createdDate: true },
}))
);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updating sync services when a new booking is created, in order to make it update last booking custom field.

evt.uid = booking?.uid ?? null;
} catch (_err) {
const err = getErrorFromUnknown(_err);
Expand Down
89 changes: 89 additions & 0 deletions apps/web/pages/api/sync/helpscout/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { createHmac } from "crypto";
import type { NextApiRequest, NextApiResponse } from "next";
import getRawBody from "raw-body";
import z from "zod";

import { default as webPrisma } from "@calcom/prisma";

export const config = {
api: {
bodyParser: false,
},
};

const helpscoutRequestBodySchema = z.object({
customer: z.object({
email: z.string().email(),
}),
});

/**
* API for Helpscout to retrieve key information about a user from a ticket
* Note: HelpScout expects a JSON with a `html` prop to show its content as HTML
*/
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" });

const hsSignature = req.headers["x-helpscout-signature"];
if (!hsSignature) return res.status(400).end();

if (!process.env.CALENDSO_ENCRYPTION_KEY) return res.status(500).end();

const rawBody = await getRawBody(req);
const parsedBody = helpscoutRequestBodySchema.safeParse(JSON.parse(rawBody.toString()));

if (!parsedBody.success) return res.status(400).end();

const calculatedSig = createHmac("sha1", process.env.CALENDSO_ENCRYPTION_KEY)
.update(rawBody)
.digest("base64");

if (req.headers["x-helpscout-signature"] !== calculatedSig) return res.status(400).end();

const user = await webPrisma.user.findFirst({
where: {
email: parsedBody.data.customer.email,
},
select: {
username: true,
id: true,
plan: true,
createdDate: true,
},
});

if (!user) return res.status(200).json({ html: "User not found" });

const lastBooking = await webPrisma.attendee.findFirst({
where: {
email: parsedBody.data.customer.email,
},
select: {
booking: {
select: {
createdAt: true,
},
},
},
orderBy: {
booking: {
createdAt: "desc",
},
},
});

return res.status(200).json({
html: `
<ul>
<li><b>Username:</b>&nbsp;${user.username}</li>
<li><b>Last booking:</b>&nbsp;${
lastBooking && lastBooking.booking
? new Date(lastBooking.booking.createdAt).toLocaleDateString("en-US")
: "No info"
}</li>
<li><b>Plan:</b>&nbsp;${user.plan}</li>
<li><b>Account created:</b>&nbsp;${new Date(user.createdDate).toLocaleDateString("en-US")}</li>
</ul>
`,
});
}
21 changes: 20 additions & 1 deletion apps/web/pages/api/teams.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { MembershipRole } from "@prisma/client";
import type { NextApiRequest, NextApiResponse } from "next";

import { closeComUpsertTeamUser } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";

import { getSession } from "@lib/auth";
Expand All @@ -13,6 +15,20 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
return;
}

const ownerUser = await prisma.user.findFirst({
where: {
id: session.user.id,
},
select: {
id: true,
username: true,
createdDate: true,
name: true,
plan: true,
email: true,
},
});

if (req.method === "POST") {
const slug = slugify(req.body.name);

Expand All @@ -37,11 +53,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
data: {
teamId: createTeam.id,
userId: session.user.id,
role: "OWNER",
role: MembershipRole.OWNER,
accepted: true,
},
});

// Sync Services: Close.com
closeComUpsertTeamUser(createTeam, ownerUser, MembershipRole.OWNER);

return res.status(201).json({ message: "Team created" });
}

Expand Down
7 changes: 6 additions & 1 deletion apps/web/pages/api/teams/[team]/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";

import { getTeamWithMembers } from "@calcom/lib/server/queries/teams";
import { closeComDeleteTeam } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";

import { getSession } from "@lib/auth";
Expand Down Expand Up @@ -45,11 +46,15 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
userId_teamId: { userId: session.user.id, teamId },
},
});
await prisma.team.delete({
const deletedTeam = await prisma.team.delete({
where: {
id: teamId,
},
});

// Sync Services: Close.com
closeComDeleteTeam(deletedTeam);

return res.status(204).send(null);
}
}
9 changes: 9 additions & 0 deletions apps/web/pages/api/teams/[team]/membership.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { NextApiRequest, NextApiResponse } from "next";

import { closeComDeleteTeamMembership } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";

import { getSession } from "@lib/auth";
Expand Down Expand Up @@ -63,11 +64,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)

// Cancel a membership (invite)
if (req.method === "DELETE") {
const user = await prisma.user.findFirst({
where: {
id: req.body.userId,
},
});
await prisma.membership.delete({
where: {
userId_teamId: { userId: req.body.userId, teamId: parseInt(req.query.team as string) },
},
});
// Sync Services: Close.com
closeComDeleteTeamMembership(user);

return res.status(204).send(null);
}

Expand Down
9 changes: 9 additions & 0 deletions apps/web/pages/api/user/me.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { NextApiRequest, NextApiResponse } from "next";

import { deleteStripeCustomer } from "@calcom/app-store/stripepayment/lib/customer";
import { deleteWebUser as syncServicesDeleteWebUser } from "@calcom/lib/sync/SyncServiceManager";
import prisma from "@calcom/prisma";

import { getSession } from "@lib/auth";
Expand All @@ -24,8 +25,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
id: session.user?.id,
},
select: {
id: true,
email: true,
metadata: true,
username: true,
createdDate: true,
name: true,
plan: true,
},
});
// Delete from stripe
Expand All @@ -37,6 +43,9 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
},
});

// Sync Services
syncServicesDeleteWebUser(user);

return res.status(204).end();
}
}
Loading