From eedc7d14a962fe7f3c83c944bcb50996ccd84d58 Mon Sep 17 00:00:00 2001 From: Dhruwang Date: Tue, 7 Nov 2023 18:47:33 +0530 Subject: [PATCH 1/2] replaced NextResponse with responses --- .env.example | 2 +- .../app/docs/integrations/airtable/page.mdx | 4 +-- .../integrations/airtable/lib/airtable.ts | 6 ++-- .../integrations/airtable/page.tsx | 4 +-- .../integrations/google-sheets/lib/google.ts | 2 +- .../app/api/google-sheet/callback/route.ts | 30 +++++-------------- apps/web/app/api/google-sheet/route.ts | 17 ++++++----- .../integrations/airtable/callback/route.ts | 24 +++++++-------- .../app/api/v1/integrations/airtable/route.ts | 20 ++++++------- .../v1/integrations/airtable/tables/route.ts | 16 +++++----- apps/web/env.mjs | 4 +-- packages/lib/airtable/service.ts | 4 +-- packages/lib/constants.ts | 2 +- turbo.json | 2 +- 14 files changed, 62 insertions(+), 75 deletions(-) diff --git a/.env.example b/.env.example index 4b75aeef611..82c2e0a64cf 100644 --- a/.env.example +++ b/.env.example @@ -122,7 +122,7 @@ GOOGLE_SHEETS_CLIENT_SECRET= GOOGLE_SHEETS_REDIRECT_URL= # Oauth credentials for Airtable integration -AIR_TABLE_CLIENT_ID= +AIRTABLE_CLIENT_ID= # Enterprise License Key ENTERPRISE_LICENSE_KEY= diff --git a/apps/formbricks-com/app/docs/integrations/airtable/page.mdx b/apps/formbricks-com/app/docs/integrations/airtable/page.mdx index e8bdf49ac84..a1cd24ed050 100644 --- a/apps/formbricks-com/app/docs/integrations/airtable/page.mdx +++ b/apps/formbricks-com/app/docs/integrations/airtable/page.mdx @@ -160,8 +160,8 @@ Enabling the Airtable Integration in a self-hosted environment requires creating ### By now, your environment variables should include the below ones: -- `AIR_TABLE_CLIENT_ID` -- `AIR_TABLE_REDIRECT_URL` +- `AIRTABLE_CLIENT_ID` +- `AIRTABLE_REDIRECT_URL` Voila! You have successfully enabled the Airtable integration in your self-hosted Formbricks instance. Now you can follow the steps mentioned in the [Formbricks Cloud](#formbricks-cloud) section to link an Airtable with Formbricks. diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/lib/airtable.ts b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/lib/airtable.ts index bbb61a25d06..cbeff6da6c1 100644 --- a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/lib/airtable.ts +++ b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/lib/airtable.ts @@ -6,8 +6,8 @@ export const fetchTables = async (environmentId: string, baseId: string) => { headers: { environmentId: environmentId }, cache: "no-store", }); - - return res.json() as Promise; + const resJson = await res.json(); + return resJson.data as Promise; }; export const authorize = async (environmentId: string, apiHost: string): Promise => { @@ -21,6 +21,6 @@ export const authorize = async (environmentId: string, apiHost: string): Promise throw new Error("Could not create response"); } const resJSON = await res.json(); - const authUrl = resJSON.authUrl; + const authUrl = resJSON.data.authUrl; return authUrl; }; diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx index 2f014c7d8c0..405b83b143d 100644 --- a/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/integrations/airtable/page.tsx @@ -1,6 +1,6 @@ import AirtableWrapper from "@/app/(app)/environments/[environmentId]/integrations/airtable/components/AirtableWrapper"; import { getAirtableTables } from "@formbricks/lib/airtable/service"; -import { AIR_TABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants"; +import { AIRTABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants"; import { getEnvironment } from "@formbricks/lib/environment/service"; import { getIntegrations } from "@formbricks/lib/integration/service"; import { getSurveys } from "@formbricks/lib/survey/service"; @@ -9,7 +9,7 @@ import { TIntegrationAirtable } from "@formbricks/types/integration/airtable"; import GoBackButton from "@formbricks/ui/GoBackButton"; export default async function Airtable({ params }) { - const enabled = !!AIR_TABLE_CLIENT_ID; + const enabled = !!AIRTABLE_CLIENT_ID; const [surveys, integrations, environment] = await Promise.all([ getSurveys(params.environmentId), getIntegrations(params.environmentId), diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/lib/google.ts b/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/lib/google.ts index 5238eeca753..dd7d6b03b4a 100644 --- a/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/lib/google.ts +++ b/apps/web/app/(app)/environments/[environmentId]/integrations/google-sheets/lib/google.ts @@ -9,6 +9,6 @@ export const authorize = async (environmentId: string, apiHost: string): Promise throw new Error("Could not create response"); } const resJSON = await res.json(); - const authUrl = resJSON.authUrl; + const authUrl = resJSON.data.authUrl; return authUrl; }; diff --git a/apps/web/app/api/google-sheet/callback/route.ts b/apps/web/app/api/google-sheet/callback/route.ts index e2c4540adc6..0e90fcb2761 100644 --- a/apps/web/app/api/google-sheet/callback/route.ts +++ b/apps/web/app/api/google-sheet/callback/route.ts @@ -1,10 +1,11 @@ -import { prisma } from "@formbricks/database"; +import { responses } from "@/app/lib/api/response"; import { GOOGLE_SHEETS_CLIENT_ID, WEBAPP_URL, GOOGLE_SHEETS_CLIENT_SECRET, GOOGLE_SHEETS_REDIRECT_URL, } from "@formbricks/lib/constants"; +import { createOrUpdateIntegration } from "@formbricks/lib/integration/service"; import { google } from "googleapis"; import { NextRequest, NextResponse } from "next/server"; @@ -15,19 +16,19 @@ export async function GET(req: NextRequest) { const code = queryParams.get("code"); if (!environmentId) { - return NextResponse.json({ error: "Invalid environmentId" }); + return responses.badRequestResponse("Invalid environmentId"); } if (code && typeof code !== "string") { - return NextResponse.json({ message: "`code` must be a string" }, { status: 400 }); + return responses.badRequestResponse("`code` must be a string"); } const client_id = GOOGLE_SHEETS_CLIENT_ID; const client_secret = GOOGLE_SHEETS_CLIENT_SECRET; const redirect_uri = GOOGLE_SHEETS_REDIRECT_URL; - if (!client_id) return NextResponse.json({ Error: "Google client id is missing" }, { status: 400 }); - if (!client_secret) return NextResponse.json({ Error: "Google client secret is missing" }, { status: 400 }); - if (!redirect_uri) return NextResponse.json({ Error: "Google redirect url is missing" }, { status: 400 }); + if (!client_id) return responses.internalServerErrorResponse("Google client id is missing"); + if (!client_secret) return responses.internalServerErrorResponse("Google client secret is missing"); + if (!redirect_uri) return responses.internalServerErrorResponse("Google redirect url is missing"); const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uri); let key; @@ -61,22 +62,7 @@ export async function GET(req: NextRequest) { }, }; - const result = await prisma.integration.upsert({ - where: { - type_environmentId: { - environmentId, - type: "googleSheets", - }, - }, - update: { - ...googleSheetIntegration, - environment: { connect: { id: environmentId } }, - }, - create: { - ...googleSheetIntegration, - environment: { connect: { id: environmentId } }, - }, - }); + const result = await createOrUpdateIntegration(environmentId, googleSheetIntegration); if (result) { return NextResponse.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/google-sheets`); diff --git a/apps/web/app/api/google-sheet/route.ts b/apps/web/app/api/google-sheet/route.ts index 306deefcf5a..2bf28d40e87 100644 --- a/apps/web/app/api/google-sheet/route.ts +++ b/apps/web/app/api/google-sheet/route.ts @@ -1,11 +1,12 @@ import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth"; +import { responses } from "@/app/lib/api/response"; import { GOOGLE_SHEETS_CLIENT_ID, GOOGLE_SHEETS_CLIENT_SECRET, GOOGLE_SHEETS_REDIRECT_URL, } from "@formbricks/lib/constants"; import { google } from "googleapis"; -import { NextRequest, NextResponse } from "next/server"; +import { NextRequest } from "next/server"; import { authOptions } from "@formbricks/lib/authOptions"; import { getServerSession } from "next-auth"; @@ -20,24 +21,24 @@ export async function GET(req: NextRequest) { const session = await getServerSession(authOptions); if (!environmentId) { - return NextResponse.json({ Error: "environmentId is missing" }, { status: 400 }); + return responses.badRequestResponse("environmentId is missing"); } if (!session) { - return NextResponse.json({ Error: "Invalid session" }, { status: 400 }); + return responses.notAuthenticatedResponse(); } const canUserAccessEnvironment = await hasUserEnvironmentAccess(session?.user.id, environmentId); if (!canUserAccessEnvironment) { - return NextResponse.json({ Error: "You dont have access to environment" }, { status: 401 }); + return responses.unauthorizedResponse(); } const client_id = GOOGLE_SHEETS_CLIENT_ID; const client_secret = GOOGLE_SHEETS_CLIENT_SECRET; const redirect_uri = GOOGLE_SHEETS_REDIRECT_URL; - if (!client_id) return NextResponse.json({ Error: "Google client id is missing" }, { status: 400 }); - if (!client_secret) return NextResponse.json({ Error: "Google client secret is missing" }, { status: 400 }); - if (!redirect_uri) return NextResponse.json({ Error: "Google redirect url is missing" }, { status: 400 }); + if (!client_id) return responses.internalServerErrorResponse("Google client id is missing"); + if (!client_secret) return responses.internalServerErrorResponse("Google client secret is missing"); + if (!redirect_uri) return responses.internalServerErrorResponse("Google redirect url is missing"); const oAuth2Client = new google.auth.OAuth2(client_id, client_secret, redirect_uri); const authUrl = oAuth2Client.generateAuthUrl({ @@ -47,5 +48,5 @@ export async function GET(req: NextRequest) { state: environmentId!, }); - return NextResponse.json({ authUrl }, { status: 200 }); + return responses.successResponse({ authUrl }); } diff --git a/apps/web/app/api/v1/integrations/airtable/callback/route.ts b/apps/web/app/api/v1/integrations/airtable/callback/route.ts index da6f287a4d4..97c2bba96dc 100644 --- a/apps/web/app/api/v1/integrations/airtable/callback/route.ts +++ b/apps/web/app/api/v1/integrations/airtable/callback/route.ts @@ -1,9 +1,10 @@ import { authOptions } from "@formbricks/lib/authOptions"; import { connectAirtable, fetchAirtableAuthToken } from "@formbricks/lib/airtable/service"; -import { AIR_TABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants"; +import { AIRTABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants"; import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth"; import { getServerSession } from "next-auth"; import { NextRequest, NextResponse } from "next/server"; +import { responses } from "@/app/lib/api/response"; import * as z from "zod"; async function getEmail(token: string) { @@ -26,27 +27,27 @@ export async function GET(req: NextRequest) { const session = await getServerSession(authOptions); if (!environmentId) { - return NextResponse.json({ error: "Invalid environmentId" }); + return responses.badRequestResponse("Invalid environmentId"); } if (!session) { - return NextResponse.json({ Error: "Invalid session" }, { status: 400 }); + return responses.notAuthenticatedResponse(); } if (code && typeof code !== "string") { - return NextResponse.json({ message: "`code` must be a string" }, { status: 400 }); + return responses.badRequestResponse("`code` must be a string"); } const canUserAccessEnvironment = await hasUserEnvironmentAccess(session?.user.id, environmentId); if (!canUserAccessEnvironment) { - return NextResponse.json({ Error: "You dont have access to environment" }, { status: 401 }); + return responses.unauthorizedResponse(); } - const client_id = AIR_TABLE_CLIENT_ID; + const client_id = AIRTABLE_CLIENT_ID; const redirect_uri = WEBAPP_URL + "/api/v1/integrations/airtable/callback"; const code_verifier = Buffer.from(environmentId + session.user.id + environmentId).toString("base64"); - if (!client_id) return NextResponse.json({ Error: "Airtable client id is missing" }, { status: 400 }); - if (!redirect_uri) return NextResponse.json({ Error: "Airtable redirect url is missing" }, { status: 400 }); + if (!client_id) return responses.internalServerErrorResponse("Airtable client id is missing"); + if (!redirect_uri) return responses.internalServerErrorResponse("Airtable redirect url is missing"); const formData = { grant_type: "authorization_code", @@ -59,7 +60,7 @@ export async function GET(req: NextRequest) { try { const key = await fetchAirtableAuthToken(formData); if (!key) { - return NextResponse.json({ Error: "Failed to fetch Airtable auth token" }, { status: 500 }); + return responses.notFoundResponse("airtable auth token", key); } const email = await getEmail(key.access_token); @@ -71,8 +72,7 @@ export async function GET(req: NextRequest) { return NextResponse.redirect(`${WEBAPP_URL}/environments/${environmentId}/integrations/airtable`); } catch (error) { console.error(error); - NextResponse.json({ Error: error }, { status: 500 }); + responses.internalServerErrorResponse(error); } - - NextResponse.json({ Error: "unknown error occurred" }, { status: 400 }); + responses.badRequestResponse("unknown error occurred"); } diff --git a/apps/web/app/api/v1/integrations/airtable/route.ts b/apps/web/app/api/v1/integrations/airtable/route.ts index 6734e42d208..85775af47f7 100644 --- a/apps/web/app/api/v1/integrations/airtable/route.ts +++ b/apps/web/app/api/v1/integrations/airtable/route.ts @@ -1,10 +1,11 @@ -import { NextRequest, NextResponse } from "next/server"; +import { NextRequest } from "next/server"; import { authOptions } from "@formbricks/lib/authOptions"; import { getServerSession } from "next-auth"; +import { responses } from "@/app/lib/api/response"; import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth"; import crypto from "crypto"; -import { AIR_TABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants"; +import { AIRTABLE_CLIENT_ID, WEBAPP_URL } from "@formbricks/lib/constants"; const scope = `data.records:read data.records:write schema.bases:read schema.bases:write user.email:read`; @@ -13,23 +14,22 @@ export async function GET(req: NextRequest) { const session = await getServerSession(authOptions); if (!environmentId) { - return NextResponse.json({ Error: "environmentId is missing" }, { status: 400 }); + return responses.badRequestResponse("environmentId is missing"); } if (!session) { - return NextResponse.json({ Error: "Invalid session" }, { status: 400 }); + return responses.notAuthenticatedResponse(); } const canUserAccessEnvironment = await hasUserEnvironmentAccess(session?.user.id, environmentId); if (!canUserAccessEnvironment) { - return NextResponse.json({ Error: "You dont have access to environment" }, { status: 401 }); + return responses.unauthorizedResponse(); } - const client_id = AIR_TABLE_CLIENT_ID; + const client_id = AIRTABLE_CLIENT_ID; const redirect_uri = WEBAPP_URL + "/api/v1/integrations/airtable/callback"; - if (!client_id) return NextResponse.json({ Error: "Airtable client id is missing" }, { status: 400 }); - if (!redirect_uri) return NextResponse.json({ Error: "Airtable redirect url is missing" }, { status: 400 }); - + if (!client_id) return responses.internalServerErrorResponse("Airtable client id is missing"); + if (!redirect_uri) return responses.internalServerErrorResponse("Airtable redirect url is missing"); const codeVerifier = Buffer.from(environmentId + session.user.id + environmentId).toString("base64"); const codeChallengeMethod = "S256"; @@ -51,5 +51,5 @@ export async function GET(req: NextRequest) { authUrl.searchParams.append("code_challenge_method", codeChallengeMethod); authUrl.searchParams.append("code_challenge", codeChallenge); - return NextResponse.json({ authUrl: authUrl.toString() }, { status: 200 }); + return responses.successResponse({ authUrl: authUrl.toString() }); } diff --git a/apps/web/app/api/v1/integrations/airtable/tables/route.ts b/apps/web/app/api/v1/integrations/airtable/tables/route.ts index 23f5520d8a0..bd532e737a2 100644 --- a/apps/web/app/api/v1/integrations/airtable/tables/route.ts +++ b/apps/web/app/api/v1/integrations/airtable/tables/route.ts @@ -4,7 +4,8 @@ import { hasUserEnvironmentAccess } from "@formbricks/lib/environment/auth"; import { getIntegrationByType } from "@formbricks/lib/integration/service"; import { TIntegrationAirtable } from "@formbricks/types/integration/airtable"; import { getServerSession } from "next-auth"; -import { NextRequest, NextResponse } from "next/server"; +import { NextRequest } from "next/server"; +import { responses } from "@/app/lib/api/response"; import * as z from "zod"; export async function GET(req: NextRequest) { @@ -15,30 +16,29 @@ export async function GET(req: NextRequest) { const baseId = z.string().safeParse(queryParams.get("baseId")); if (!baseId.success) { - return NextResponse.json({ Error: "Base Id is Required" }, { status: 400 }); + return responses.missingFieldResponse("Base Id is Required"); } if (!session) { - return NextResponse.json({ Error: "Invalid session" }, { status: 400 }); + return responses.notAuthenticatedResponse(); } if (!environmentId) { - return NextResponse.json({ Error: "environmentId is missing" }, { status: 400 }); + return responses.badRequestResponse("environmentId is missing"); } const canUserAccessEnvironment = await hasUserEnvironmentAccess(session?.user.id, environmentId); if (!canUserAccessEnvironment || !environmentId) { - return NextResponse.json({ Error: "You dont have access to environment" }, { status: 401 }); + return responses.unauthorizedResponse(); } const integration = (await getIntegrationByType(environmentId, "airtable")) as TIntegrationAirtable; console.log(integration); if (!integration) { - return NextResponse.json({ Error: "integration not found" }, { status: 401 }); + return responses.notFoundResponse("Integration not found", environmentId); } const tables = await getTables(integration.config.key, baseId.data); - - return NextResponse.json(tables, { status: 200 }); + return responses.successResponse(tables); } diff --git a/apps/web/env.mjs b/apps/web/env.mjs index af273585172..e7358258f48 100644 --- a/apps/web/env.mjs +++ b/apps/web/env.mjs @@ -54,7 +54,7 @@ export const env = createEnv({ GOOGLE_SHEETS_CLIENT_ID: z.string().optional(), GOOGLE_SHEETS_CLIENT_SECRET: z.string().optional(), GOOGLE_SHEETS_REDIRECT_URL: z.string().optional(), - AIR_TABLE_CLIENT_ID: z.string().optional(), + AIRTABLE_CLIENT_ID: z.string().optional(), AWS_ACCESS_KEY: z.string().optional(), AWS_SECRET_KEY: z.string().optional(), S3_ACCESS_KEY: z.string().optional(), @@ -139,7 +139,7 @@ export const env = createEnv({ AZUREAD_CLIENT_ID: process.env.AZUREAD_CLIENT_ID, AZUREAD_CLIENT_SECRET: process.env.AZUREAD_CLIENT_SECRET, AZUREAD_TENANT_ID: process.env.AZUREAD_TENANT_ID, - AIR_TABLE_CLIENT_ID: process.env.AIR_TABLE_CLIENT_ID, + AIRTABLE_CLIENT_ID: process.env.AIRTABLE_CLIENT_ID, ENTERPRISE_LICENSE_KEY: process.env.ENTERPRISE_LICENSE_KEY, }, }); diff --git a/packages/lib/airtable/service.ts b/packages/lib/airtable/service.ts index 3672ff272da..85e26615f51 100644 --- a/packages/lib/airtable/service.ts +++ b/packages/lib/airtable/service.ts @@ -13,7 +13,7 @@ import { ZIntegrationAirtableTokenSchema, } from "@formbricks/types/integration/airtable"; import { Prisma } from "@prisma/client"; -import { AIR_TABLE_CLIENT_ID } from "../constants"; +import { AIRTABLE_CLIENT_ID } from "../constants"; import { createOrUpdateIntegration, deleteIntegration, getIntegrationByType } from "../integration/service"; interface ConnectAirtableOptions { @@ -122,7 +122,7 @@ export const getAirtableToken = async (environmentId: string) => { const currentDate = new Date(); if (currentDate >= expiryDate) { - const client_id = AIR_TABLE_CLIENT_ID; + const client_id = AIRTABLE_CLIENT_ID; const newToken = await fetchAirtableAuthToken({ grant_type: "refresh_token", diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts index 76e8257c1d3..dce561ed901 100644 --- a/packages/lib/constants.ts +++ b/packages/lib/constants.ts @@ -47,7 +47,7 @@ export const GOOGLE_SHEETS_CLIENT_ID = process.env.GOOGLE_SHEETS_CLIENT_ID; export const GOOGLE_SHEETS_CLIENT_SECRET = process.env.GOOGLE_SHEETS_CLIENT_SECRET; export const GOOGLE_SHEETS_REDIRECT_URL = process.env.GOOGLE_SHEETS_REDIRECT_URL; -export const AIR_TABLE_CLIENT_ID = process.env.AIR_TABLE_CLIENT_ID; +export const AIRTABLE_CLIENT_ID = process.env.AIRTABLE_CLIENT_ID; export const SMTP_HOST = process.env.SMTP_HOST; export const SMTP_PORT = process.env.SMTP_PORT; diff --git a/turbo.json b/turbo.json index d4927a38797..3e69f5a8769 100644 --- a/turbo.json +++ b/turbo.json @@ -112,7 +112,7 @@ "TELEMETRY_DISABLED", "VERCEL_URL", "WEBAPP_URL", - "AIR_TABLE_CLIENT_ID", + "AIRTABLE_CLIENT_ID", "AWS_ACCESS_KEY", "AWS_SECRET_KEY", "S3_ACCESS_KEY", From 7b34b10384c0e13bc231c27aeafe28e954dbf2cb Mon Sep 17 00:00:00 2001 From: Dhruwang Date: Tue, 7 Nov 2023 18:49:54 +0530 Subject: [PATCH 2/2] removed console log --- apps/web/app/api/v1/integrations/airtable/tables/route.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/app/api/v1/integrations/airtable/tables/route.ts b/apps/web/app/api/v1/integrations/airtable/tables/route.ts index bd532e737a2..d83afd2103f 100644 --- a/apps/web/app/api/v1/integrations/airtable/tables/route.ts +++ b/apps/web/app/api/v1/integrations/airtable/tables/route.ts @@ -33,7 +33,6 @@ export async function GET(req: NextRequest) { } const integration = (await getIntegrationByType(environmentId, "airtable")) as TIntegrationAirtable; - console.log(integration); if (!integration) { return responses.notFoundResponse("Integration not found", environmentId);