* feat: installing the app works * Update yarn.lock * feat: /api/callback now gets user auth info from basecamp * feat: updated basecamp logo * feat: added project dropdown on event apps page * feat: basecamp event creation and deletion working * feat: basecamp event rescheduling now works * refactor(CalendarService): basecamp CaldendarService code clean up * refactor: code cleanup for basecamp app API * feat: updated event summary text sent to basecamp * chore: updated basecamp images and contact info * fix: fixed typescript errors and added logic to refresh tokens on event settings * refactor(CaldendarService): used refreshAccessToken from helpers.ts instead * chore: updated basecamp description * fix: fixed incorrect import * fix: accidentally deleted props to toggle app for event * chore: updated .env.appStore.example and added README for app * Update .env.appStore.example Co-authored-by: Leo Giovanetti <hello@leog.me> * feat: added basecamp userAgent in env instead of hardcoded value * feat: updated README to include how to set basecamp user agent env * fix: removed unused import * feat: used URLSearchParams to construct url params * fix: fixed typescript errors * chore: updated README to include an example on how to set basecamp user-agent * feat: using TRPC instead of REST * chore: removed old projects REST code --------- Co-authored-by: Leo Giovanetti <hello@leog.me>
91 lines
2.7 KiB
TypeScript
91 lines
2.7 KiB
TypeScript
import type { NextApiRequest, NextApiResponse } from "next";
|
|
|
|
import { WEBAPP_URL } from "@calcom/lib/constants";
|
|
import prisma from "@calcom/prisma";
|
|
|
|
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
|
|
import getInstalledAppPath from "../../_utils/getInstalledAppPath";
|
|
import appConfig from "../config.json";
|
|
|
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
|
const { code } = req.query;
|
|
const { client_id, client_secret, user_agent } = await getAppKeysFromSlug("basecamp3");
|
|
|
|
const redirectUri = WEBAPP_URL + "/api/integrations/basecamp3/callback";
|
|
|
|
const params = new URLSearchParams({
|
|
type: "web_server",
|
|
client_id: client_id as string,
|
|
client_secret: client_secret as string,
|
|
redirect_uri: redirectUri,
|
|
code: code as string,
|
|
});
|
|
// gets access token
|
|
const accessTokenResponse = await fetch(
|
|
`https://launchpad.37signals.com/authorization/token?${params.toString()}`,
|
|
{
|
|
method: "POST",
|
|
}
|
|
);
|
|
|
|
if (accessTokenResponse.status !== 200) {
|
|
let errorMessage = "Error with Basecamp 3 API";
|
|
try {
|
|
const responseBody = await accessTokenResponse.json();
|
|
errorMessage = responseBody.error;
|
|
} catch (e) {}
|
|
|
|
res.status(400).json({ message: errorMessage });
|
|
return;
|
|
}
|
|
|
|
const tokenResponseBody = await accessTokenResponse.json();
|
|
|
|
if (tokenResponseBody.error) {
|
|
res.status(400).json({ message: tokenResponseBody.error });
|
|
return;
|
|
}
|
|
// expiry date of 2 weeks
|
|
tokenResponseBody["expires_at"] = Date.now() + 1000 * 3600 * 24 * 14;
|
|
// get user details such as projects and account info
|
|
const userAuthResponse = await fetch("https://launchpad.37signals.com/authorization.json", {
|
|
headers: {
|
|
"User-Agent": user_agent as string,
|
|
Authorization: `Bearer ${tokenResponseBody.access_token}`,
|
|
},
|
|
});
|
|
if (userAuthResponse.status !== 200) {
|
|
let errorMessage = "Error with Basecamp 3 API";
|
|
try {
|
|
const body = await userAuthResponse.json();
|
|
errorMessage = body.error;
|
|
} catch (e) {}
|
|
|
|
res.status(400).json({ message: errorMessage });
|
|
return;
|
|
}
|
|
|
|
const authResponseBody = await userAuthResponse.json();
|
|
const userId = req.session?.user.id;
|
|
if (!userId) {
|
|
return res.status(404).json({ message: "No user found" });
|
|
}
|
|
|
|
await prisma.user.update({
|
|
where: {
|
|
id: req.session?.user.id,
|
|
},
|
|
data: {
|
|
credentials: {
|
|
create: {
|
|
type: appConfig.type,
|
|
key: { ...tokenResponseBody, account: authResponseBody.accounts[0] },
|
|
appId: appConfig.slug,
|
|
},
|
|
},
|
|
},
|
|
});
|
|
|
|
res.redirect(getInstalledAppPath({ variant: appConfig.variant, slug: appConfig.slug }));
|
|
}
|