Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Zoho Calendar #8144

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
68ab3bf
feat: add zoho calendar
murtajaziad Apr 8, 2023
3d7a699
remove log.debug
murtajaziad Apr 8, 2023
8a51e76
Merge branch 'main' into app/zohocalendar
murtajaziad Apr 8, 2023
c64440e
fix types
murtajaziad Apr 8, 2023
3d8c819
lint
murtajaziad Apr 8, 2023
9ee3b12
fix types and lint
murtajaziad Apr 8, 2023
6b861fd
lint
murtajaziad Apr 8, 2023
b046b4e
Apply suggestions from code review
hariombalhara Apr 19, 2023
e6c3772
Make changes to comply with new app structure - followed by app-store…
hariombalhara Apr 19, 2023
10bf10d
Add dead import
hariombalhara Apr 19, 2023
d56a491
Merge remote-tracking branch 'origin/main' into app/zohocalendar
hariombalhara Apr 19, 2023
a91e12f
More cleanup
hariombalhara Apr 19, 2023
2cfc402
Use slug as dirName if not explicilty set
hariombalhara Apr 19, 2023
62c38e9
Added instructions for obtaining Zoho Calendar Client ID and Secret
murtajaziad May 1, 2023
0e65ec8
Merge remote-tracking branch 'origin/main' into app/zohocalendar
hariombalhara May 10, 2023
86c235f
Reuse code
hariombalhara May 10, 2023
249b54c
Fix TS error
hariombalhara May 11, 2023
29e7384
Merge remote-tracking branch 'origin/main' into app/zohocalendar
hariombalhara May 11, 2023
37518ee
fix missing title and missing uemail
murtajaziad Jun 22, 2023
5935818
Merge branch 'main' into app/zohocalendar
alannnc Jun 27, 2023
735d9bf
Fixing app seed, event start end time on zoho app missmatch and fetch…
alannnc Jun 28, 2023
436020e
Merge branch 'main' into app/zohocalendar
alannnc Jun 28, 2023
0451429
Merge branch 'main' into app/zohocalendar
alannnc Jun 28, 2023
0788823
Merge branch 'main' into app/zohocalendar
alannnc Jun 29, 2023
6ce4754
Adjust CalendarService to match code style
alannnc Jun 29, 2023
1cb5334
Merge branch 'main' into app/zohocalendar
joeauyeung Jul 6, 2023
86e00c6
Merge branch 'main' into app/zohocalendar
joeauyeung Jul 18, 2023
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
4 changes: 2 additions & 2 deletions .env.appStore.example
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ LARK_OPEN_VERIFICATION_TOKEN=""
SALESFORCE_CONSUMER_KEY=""
SALESFORCE_CONSUMER_SECRET=""

# - ZOHOCRM
# Used for the Zoho CRM integration
# - ZOHOCRM And Calendar
# Used for the Zoho CRM integration and Zoho Calendar integration that uses Zoho API
ZOHOCRM_CLIENT_ID=""
ZOHOCRM_CLIENT_SECRET=""

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@ following
9. Click the "Save"/ "UPDATE" button at the bottom footer.
10. You're good to go. Now you can easily add your ZohoCRM integration in the Cal.com settings.

### Obtaining Zoho Calendar Client ID and Secret

[Follow these steps](./packages/app-store/zohocalendar/)
### Obtaining Zoho Bigin Client ID and Secret

[Follow these steps](./packages/app-store/zoho-bigin/)
Expand Down
2 changes: 2 additions & 0 deletions packages/app-store/apps.keys-schemas.generated.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

Auto-generated files shouldn't be committed.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { appKeysSchema as webex_zod_ts } from "./webex/zod";
import { appKeysSchema as wordpress_zod_ts } from "./wordpress/zod";
import { appKeysSchema as zapier_zod_ts } from "./zapier/zod";
import { appKeysSchema as zoho_bigin_zod_ts } from "./zoho-bigin/zod";
import { appKeysSchema as zohocalendar_zod_ts } from "./zohocalendar/zod";
import { appKeysSchema as zohocrm_zod_ts } from "./zohocrm/zod";
import { appKeysSchema as zoomvideo_zod_ts } from "./zoomvideo/zod";

Expand Down Expand Up @@ -56,6 +57,7 @@ export const appKeysSchemas = {
wordpress: wordpress_zod_ts,
zapier: zapier_zod_ts,
"zoho-bigin": zoho_bigin_zod_ts,
zohocalendar: zohocalendar_zod_ts,
zohocrm: zohocrm_zod_ts,
zoomvideo: zoomvideo_zod_ts,
};
2 changes: 2 additions & 0 deletions packages/app-store/apps.metadata.generated.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

Auto-generated files shouldn't be committed.

Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import { metadata as wipemycalother__metadata_ts } from "./wipemycalother/_metad
import wordpress_config_json from "./wordpress/config.json";
import { metadata as zapier__metadata_ts } from "./zapier/_metadata";
import zoho_bigin_config_json from "./zoho-bigin/config.json";
import zohocalendar_config_json from "./zohocalendar/config.json";
import zohocrm_config_json from "./zohocrm/config.json";
import { metadata as zoomvideo__metadata_ts } from "./zoomvideo/_metadata";

Expand Down Expand Up @@ -128,6 +129,7 @@ export const appStoreMetadata = {
wordpress: wordpress_config_json,
zapier: zapier__metadata_ts,
"zoho-bigin": zoho_bigin_config_json,
zohocalendar: zohocalendar_config_json,
zohocrm: zohocrm_config_json,
zoomvideo: zoomvideo__metadata_ts,
};
2 changes: 2 additions & 0 deletions packages/app-store/apps.schemas.generated.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

Auto-generated files shouldn't be committed.

Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { appDataSchema as webex_zod_ts } from "./webex/zod";
import { appDataSchema as wordpress_zod_ts } from "./wordpress/zod";
import { appDataSchema as zapier_zod_ts } from "./zapier/zod";
import { appDataSchema as zoho_bigin_zod_ts } from "./zoho-bigin/zod";
import { appDataSchema as zohocalendar_zod_ts } from "./zohocalendar/zod";
import { appDataSchema as zohocrm_zod_ts } from "./zohocrm/zod";
import { appDataSchema as zoomvideo_zod_ts } from "./zoomvideo/zod";

Expand Down Expand Up @@ -56,6 +57,7 @@ export const appDataSchemas = {
wordpress: wordpress_zod_ts,
zapier: zapier_zod_ts,
"zoho-bigin": zoho_bigin_zod_ts,
zohocalendar: zohocalendar_zod_ts,
zohocrm: zohocrm_zod_ts,
zoomvideo: zoomvideo_zod_ts,
};
1 change: 1 addition & 0 deletions packages/app-store/apps.server.generated.ts
Copy link
Contributor

Choose a reason for hiding this comment

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

Auto-generated files shouldn't be committed.

Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ export const apiHandlers = {
wordpress: import("./wordpress/api"),
zapier: import("./zapier/api"),
"zoho-bigin": import("./zoho-bigin/api"),
zohocalendar: import("./zohocalendar/api"),
zohocrm: import("./zohocrm/api"),
zoomvideo: import("./zoomvideo/api"),
};
1 change: 1 addition & 0 deletions packages/app-store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const appStore = {
exchangecalendar: () => import("./exchangecalendar"),
facetime: () => import("./facetime"),
sylapsvideo: () => import("./sylapsvideo"),
zohocalendar: () => import("./zohocalendar"),
"zoho-bigin": () => import("./zoho-bigin"),
telegramvideo: () => import("./telegram"),
};
Expand Down
6 changes: 6 additions & 0 deletions packages/app-store/zohocalendar/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
items:
- ZCal1.jpg
---

Zoho Calendar is an online business calendar that makes scheduling easy for you. You can use it to stay on top of your schedule and also share calendars with your team to keep everyone on the same page.
Copy link
Member

Choose a reason for hiding this comment

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

@sydwardrae @Jaibles Please review App description

14 changes: 14 additions & 0 deletions packages/app-store/zohocalendar/README.md
murtajaziad marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this approach of adding instructions in the app package.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Zoho Calendar

### Obtaining Zoho Calendar Client ID and Secret

1. Open [Zoho API Console](https://api-console.zoho.com/) and sign into your account, or create a new one.
2. From within the API console page, go to "Applications".
3. Click "ADD CLIENT" button top right and select "Server-based Applications".
4. Fill in any information you want in the "Client Details" tab
5. Go to tab "Client Secret" tab.
6. Now copy the Client ID and Client Secret into your app keys in the Cal.com admin panel (`<Cal.com>/settings/admin/apps`).
7. Back in Zoho API Console, set the Redirect URL for OAuth `<Cal.com URL>/api/integrations/zohocalendar/callback` replacing Cal.com URL with the URI at which your application runs.
8. In the "Settings" section check the "Multi-DC" option if you wish to use the same OAuth credentials for all data centers.
9. Click the "Save"/ "UPDATE" button at the bottom footer.
10. You're good to go. Now you can easily add your Zoho Calendar integration in the Cal.com settings.
40 changes: 40 additions & 0 deletions packages/app-store/zohocalendar/api/add.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { stringify } from "querystring";

import { WEBAPP_URL } from "@calcom/lib/constants";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";

import { encodeOAuthState } from "../../_utils/encodeOAuthState";
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
import config from "../config.json";
import { appKeysSchema as zohoKeysSchema } from "../zod";

async function getHandler(req: NextApiRequest, res: NextApiResponse) {
const appKeys = await getAppKeysFromSlug(config.slug);
const { client_id } = zohoKeysSchema.parse(appKeys);

const state = encodeOAuthState(req);

const params = {
client_id,
response_type: "code",
redirect_uri: WEBAPP_URL + "/api/integrations/zohocalendar/callback",
scope: [
"ZohoCalendar.calendar.ALL",
"ZohoCalendar.event.ALL",
"ZohoCalendar.freebusy.READ",
"AaaServer.profile.READ",
],
access_type: "offline",
state,
prompt: "consent",
};

const query = stringify(params);

res.status(200).json({ url: `https://accounts.zoho.com/oauth/v2/auth?${query}` });
}

export default defaultHandler({
Copy link
Member

Choose a reason for hiding this comment

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

Wrapped up endpoints in defaultHandler

GET: Promise.resolve({ default: defaultResponder(getHandler) }),
});
87 changes: 87 additions & 0 deletions packages/app-store/zohocalendar/api/callback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import type { NextApiRequest, NextApiResponse } from "next";
import { stringify } from "querystring";
import { z } from "zod";

import { WEBAPP_URL } from "@calcom/lib/constants";
import { getSafeRedirectUrl } from "@calcom/lib/getSafeRedirectUrl";
import logger from "@calcom/lib/logger";
import { defaultHandler, defaultResponder } from "@calcom/lib/server";
import prisma from "@calcom/prisma";

import { decodeOAuthState } from "../../_utils/decodeOAuthState";
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
import getInstalledAppPath from "../../_utils/getInstalledAppPath";
import config from "../config.json";
import type { ZohoAuthCredentials } from "../types/ZohoCalendar";

const log = logger.getChildLogger({ prefix: [`[[zohocalendar/api/callback]`] });

const zohoKeysSchema = z.object({
hariombalhara marked this conversation as resolved.
Show resolved Hide resolved
client_id: z.string(),
client_secret: z.string(),
});

async function getHandler(req: NextApiRequest, res: NextApiResponse) {
const { code } = req.query;
const state = decodeOAuthState(req);

if (code && typeof code !== "string") {
res.status(400).json({ message: "`code` must be a string" });
return;
}

if (!req.session?.user?.id) {
return res.status(401).json({ message: "You must be logged in to do this" });
}

const appKeys = await getAppKeysFromSlug(config.slug);
const { client_id, client_secret } = zohoKeysSchema.parse(appKeys);

const params = {
client_id,
grant_type: "authorization_code",
client_secret,
redirect_uri: `${WEBAPP_URL}/api/integrations/${config.slug}/callback`,
code,
};

const query = stringify(params);

const response = await fetch(`https://accounts.zoho.com/oauth/v2/token?${query}`, {
method: "POST",
headers: {
"Content-Type": "application/json; charset=utf-8",
},
});

const responseBody = await response.json();
console.log(responseBody);

if (!response.ok || responseBody.error) {
log.error("get access_token failed", responseBody);
return res.redirect("/apps/installed?error=" + JSON.stringify(responseBody));
}

const key: ZohoAuthCredentials = {
access_token: responseBody.access_token,
refresh_token: responseBody.refresh_token,
expires_in: Math.round(+new Date() / 1000 + responseBody.expires_in),
};

await prisma.credential.create({
data: {
type: config.type,
key,
userId: req.session.user.id,
appId: config.slug,
},
});

res.redirect(
getSafeRedirectUrl(state?.returnTo) ?? getInstalledAppPath({ variant: config.variant, slug: config.slug })
);
}

export default defaultHandler({
GET: Promise.resolve({ default: defaultResponder(getHandler) }),
});
2 changes: 2 additions & 0 deletions packages/app-store/zohocalendar/api/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as add } from "./add";
export { default as callback } from "./callback";
16 changes: 16 additions & 0 deletions packages/app-store/zohocalendar/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "Zoho Calendar",
"description": "Zoho Calendar is an online business calendar that makes scheduling easy for you. You can use it to stay on top of your schedule and also share calendars with your team to keep everyone on the same page.",
"slug": "zohocalendar",
"type": "zoho_calendar",
"title": "Zoho Calendar",
"variant": "calendar",
"category": "calendar",
"categories": [
"calendar"
],
"logo": "icon.svg",
"publisher": "Cal.com",
"url": "https://cal.com/",
"email": "[email protected]"
}
2 changes: 2 additions & 0 deletions packages/app-store/zohocalendar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * as api from "./api";
export * as lib from "./lib";
Loading