diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index bcc25bd390..fa0d33dbca 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -31,9 +31,10 @@ Fixes # (issue) -- [ ] Added a screen recording or screenshots to this PR +### Required + - [ ] Filled out the "How to test" section in this PR -- [ ] Read the [contributing guide](https://github.com/formbricks/formbricks/blob/main/CONTRIBUTING.md) +- [ ] Read [How we Code at Formbricks](<[https://github.com/formbricks/formbricks/blob/main/CONTRIBUTING.md](https://formbricks.com/docs/contributing/how-we-code)>) - [ ] Self-reviewed my own code - [ ] Commented on my code in hard-to-understand bits - [ ] Ran `pnpm build` @@ -41,4 +42,8 @@ Fixes # (issue) - [ ] Removed all `console.logs` - [ ] Merged the latest changes from main onto my branch with `git pull origin main` - [ ] My changes don't cause any responsiveness issues + +### Appreciated + +- [ ] If a UI change was made: Added a screen recording or screenshots to this PR - [ ] Updated the Formbricks Docs if changes were necessary diff --git a/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx b/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx index af6407fd7e..90e8d14a35 100644 --- a/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/integrations/page.tsx @@ -6,82 +6,121 @@ import n8nLogo from "@/images/n8n.png"; import MakeLogo from "@/images/make-small.png"; import { Card } from "@formbricks/ui"; import Image from "next/image"; +import { getCountOfWebhooksBasedOnSource } from "@formbricks/lib/services/webhook"; +import { getEnvironment } from "@formbricks/lib/services/environment"; import { getIntegrations } from "@formbricks/lib/services/integrations"; export default async function IntegrationsPage({ params }) { - const integrations = await getIntegrations(params.environmentId); + const environmentId = params.environmentId; + + const [environment, integrations, userWebhooks, zapierWebhooks] = await Promise.all([ + getEnvironment(environmentId), + getIntegrations(environmentId), + getCountOfWebhooksBasedOnSource(environmentId, "user"), + getCountOfWebhooksBasedOnSource(environmentId, "zapier"), + ]); + const containsGoogleSheetIntegration = integrations.some( (integration) => integration.type === "googleSheets" ); + const integrationCards = [ + { + docsHref: "https://formbricks.com/docs/getting-started/framework-guides#next-js", + docsText: "Docs", + docsNewTab: true, + label: "Javascript Widget", + description: "Integrate Formbricks into your Webapp", + icon: Javascript Logo, + connected: environment?.widgetSetupCompleted, + statusText: environment?.widgetSetupCompleted ? "Connected" : "Not Connected", + }, + { + docsHref: "https://formbricks.com/docs/integrations/zapier", + docsText: "Docs", + docsNewTab: true, + connectHref: "https://zapier.com/apps/formbricks/integrations", + connectText: "Connect", + connectNewTab: true, + label: "Zapier", + description: "Integrate Formbricks with 5000+ apps via Zapier", + icon: Zapier Logo, + connected: zapierWebhooks > 0, + statusText: + zapierWebhooks === 1 ? "1 zap" : zapierWebhooks === 0 ? "Not Connected" : `${zapierWebhooks} zaps`, + }, + { + connectHref: `/environments/${params.environmentId}/integrations/webhooks`, + connectText: "Manage Webhooks", + connectNewTab: false, + docsHref: "https://formbricks.com/docs/webhook-api/overview", + docsText: "Docs", + docsNewTab: true, + label: "Webhooks", + description: "Trigger Webhooks based on actions in your surveys", + icon: Webhook Logo, + connected: userWebhooks > 0, + statusText: + userWebhooks === 1 ? "1 webhook" : userWebhooks === 0 ? "Not Connected" : `${userWebhooks} zaps`, + }, + { + connectHref: `/environments/${params.environmentId}/integrations/google-sheets`, + connectText: `${containsGoogleSheetIntegration ? "Manage Sheets" : "Connect"}`, + connectNewTab: false, + docsHref: "https://formbricks.com/docs/integrations/google-sheets", + docsText: "Docs", + docsNewTab: true, + label: "Google Sheets", + description: "Instantly populate your spreadsheets with survey data", + icon: Google sheets Logo, + connected: containsGoogleSheetIntegration ? true : false, + statusText: containsGoogleSheetIntegration ? "Connected" : "Not Connected", + }, + { + docsHref: "https://formbricks.com/docs/integrations/n8n", + docsText: "Docs", + docsNewTab: true, + connectHref: "https://n8n.io", + connectText: "Connect", + connectNewTab: true, + label: "n8n", + description: "Integrate Formbricks with 350+ apps via n8n", + icon: n8n Logo, + }, + { + docsHref: "https://formbricks.com/docs/integrations/make", + docsText: "Docs", + docsNewTab: true, + connectHref: "https://www.make.com/en/integrations/formbricks", + connectText: "Connect", + connectNewTab: true, + label: "Make.com", + description: "Integrate Formbricks with 1000+ apps via Make", + icon: Make Logo, + }, + ]; + return (

Integrations

Connect Formbricks with your favorite tools.

- } - /> - } - /> - } - /> - } - /> - } - /> - } - /> + {integrationCards.map((card) => ( + + ))}
); diff --git a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx index 0c801df40b..682fac982c 100644 --- a/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx +++ b/apps/web/app/(app)/environments/[environmentId]/settings/members/EditMemberships/EditMemberships.tsx @@ -2,7 +2,7 @@ import { TTeam } from "@formbricks/types/v1/teams"; import React from "react"; import MembersInfo from "@/app/(app)/environments/[environmentId]/settings/members/EditMemberships/MembersInfo"; import { getMembersByTeamId } from "@formbricks/lib/services/membership"; -import { getInviteesByTeamId } from "@formbricks/lib/services/invite"; +import { getInvitesByTeamId } from "@formbricks/lib/services/invite"; import { TMembership } from "@formbricks/types/v1/memberships"; type EditMembershipsProps = { @@ -18,7 +18,7 @@ export async function EditMemberships({ currentUserMembership: membership, }: EditMembershipsProps) { const members = await getMembersByTeamId(team.id); - const invites = await getInviteesByTeamId(team.id); + const invites = await getInvitesByTeamId(team.id); const currentUserRole = membership?.role; const isUserAdminOrOwner = membership?.role === "admin" || membership?.role === "owner"; diff --git a/packages/lib/actionClass/auth.ts b/packages/lib/actionClass/auth.ts index 1d7a431361..381d981b46 100644 --- a/packages/lib/actionClass/auth.ts +++ b/packages/lib/actionClass/auth.ts @@ -1,8 +1,11 @@ +import "server-only"; + import { ZId } from "@formbricks/types/v1/environment"; import { validateInputs } from "../utils/validate"; import { hasUserEnvironmentAccess } from "../environment/auth"; import { getActionClass } from "./service"; import { unstable_cache } from "next/cache"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const canUserAccessActionClass = async (userId: string, actionClassId: string): Promise => await unstable_cache( @@ -20,5 +23,5 @@ export const canUserAccessActionClass = async (userId: string, actionClassId: st }, [`users-${userId}-actionClasses-${actionClassId}`], - { revalidate: 30 * 60, tags: [`actionClasses-${actionClassId}`] } - )(); // 30 minutes + { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [`actionClasses-${actionClassId}`] } + )(); diff --git a/packages/lib/actionClass/service.ts b/packages/lib/actionClass/service.ts index f69cb1bb05..2631636ce0 100644 --- a/packages/lib/actionClass/service.ts +++ b/packages/lib/actionClass/service.ts @@ -2,14 +2,13 @@ import "server-only"; import { prisma } from "@formbricks/database"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; import { TActionClass, TActionClassInput, ZActionClassInput } from "@formbricks/types/v1/actionClasses"; import { ZId } from "@formbricks/types/v1/environment"; import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors"; import { revalidateTag, unstable_cache } from "next/cache"; import { validateInputs } from "../utils/validate"; -const halfHourInSeconds = 60 * 30; - export const getActionClassCacheTag = (name: string, environmentId: string): string => `environments-${environmentId}-actionClass-${name}`; @@ -50,7 +49,7 @@ export const getActionClasses = (environmentId: string): Promise [`environments-${environmentId}-actionClasses`], { tags: [getActionClassesCacheTag(environmentId)], - revalidate: halfHourInSeconds, + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); @@ -168,6 +167,6 @@ export const getActionClassCached = async (name: string, environmentId: string) [`environments-${environmentId}-actionClasses-${name}`], { tags: [getActionClassesCacheTag(environmentId)], - revalidate: halfHourInSeconds, + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); diff --git a/packages/lib/apiKey/auth.ts b/packages/lib/apiKey/auth.ts index 6699514ddc..1ba3027163 100644 --- a/packages/lib/apiKey/auth.ts +++ b/packages/lib/apiKey/auth.ts @@ -1,8 +1,11 @@ +import "server-only"; + import { ZId } from "@formbricks/types/v1/environment"; import { validateInputs } from "../utils/validate"; import { hasUserEnvironmentAccess } from "../environment/auth"; import { getApiKey } from "./service"; import { unstable_cache } from "next/cache"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Promise => await unstable_cache( @@ -19,5 +22,5 @@ export const canUserAccessApiKey = async (userId: string, apiKeyId: string): Pro }, [`users-${userId}-apiKeys-${apiKeyId}`], - { revalidate: 30 * 60, tags: [`apiKeys-${apiKeyId}`] } - )(); // 30 minutes + { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [`apiKeys-${apiKeyId}`] } + )(); diff --git a/packages/lib/apiKey/service.ts b/packages/lib/apiKey/service.ts index 89bfd03d80..e181dd3992 100644 --- a/packages/lib/apiKey/service.ts +++ b/packages/lib/apiKey/service.ts @@ -1,4 +1,5 @@ import "server-only"; + import z from "zod"; import { prisma } from "@formbricks/database"; import { TApiKey, TApiKeyCreateInput, ZApiKeyCreateInput } from "@formbricks/types/v1/apiKeys"; diff --git a/packages/lib/constants.ts b/packages/lib/constants.ts index b7a8ae1a36..b2c8a7c0a6 100644 --- a/packages/lib/constants.ts +++ b/packages/lib/constants.ts @@ -4,6 +4,7 @@ import { env } from "@/env.mjs"; export const RESPONSES_LIMIT_FREE = 100; export const IS_FORMBRICKS_CLOUD = env.IS_FORMBRICKS_CLOUD === "1"; export const REVALIDATION_INTERVAL = 0; //TODO: find a good way to cache and revalidate data when it changes +export const SERVICES_REVALIDATION_INTERVAL = 60 * 30; // 30 minutes export const MAU_LIMIT = IS_FORMBRICKS_CLOUD ? 5000 : 1000000; // URLs diff --git a/packages/lib/environment/auth.ts b/packages/lib/environment/auth.ts index 4a693e6ed0..b9186ef812 100644 --- a/packages/lib/environment/auth.ts +++ b/packages/lib/environment/auth.ts @@ -2,6 +2,7 @@ import { prisma } from "@formbricks/database"; import { ZId } from "@formbricks/types/v1/environment"; import { unstable_cache } from "next/cache"; import { validateInputs } from "../utils/validate"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const hasUserEnvironmentAccess = async (userId: string, environmentId: string) => { return await unstable_cache( @@ -31,6 +32,6 @@ export const hasUserEnvironmentAccess = async (userId: string, environmentId: st return environmentUsers.includes(userId); }, [`users-${userId}-environments-${environmentId}`], - { revalidate: 30 * 60, tags: [`environments-${environmentId}`] } - )(); // 30 minutes + { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [`environments-${environmentId}`] } + )(); }; diff --git a/packages/lib/response/auth.ts b/packages/lib/response/auth.ts index 48ea212553..f4adfe0858 100644 --- a/packages/lib/response/auth.ts +++ b/packages/lib/response/auth.ts @@ -1,9 +1,12 @@ +import "server-only"; + import { ZId } from "@formbricks/types/v1/environment"; import { validateInputs } from "../utils/validate"; import { hasUserEnvironmentAccess } from "../environment/auth"; import { getResponse, getResponseCacheTag } from "./service"; import { unstable_cache } from "next/cache"; import { getSurvey } from "../services/survey"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const canUserAccessResponse = async (userId: string, responseId: string): Promise => await unstable_cache( @@ -24,5 +27,5 @@ export const canUserAccessResponse = async (userId: string, responseId: string): return true; }, [`users-${userId}-responses-${responseId}`], - { revalidate: 30 * 60, tags: [getResponseCacheTag(responseId)] } - )(); // 30 minutes + { revalidate: SERVICES_REVALIDATION_INTERVAL, tags: [getResponseCacheTag(responseId)] } + )(); diff --git a/packages/lib/response/service.ts b/packages/lib/response/service.ts index b0f2595826..4e7f9a820f 100644 --- a/packages/lib/response/service.ts +++ b/packages/lib/response/service.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { TResponse, @@ -11,7 +13,6 @@ import { TPerson } from "@formbricks/types/v1/people"; import { TTag } from "@formbricks/types/v1/tags"; import { Prisma } from "@prisma/client"; import { cache } from "react"; -import "server-only"; import { getPerson, transformPrismaPerson } from "../services/person"; import { captureTelemetry } from "../telemetry"; import { validateInputs } from "../utils/validate"; diff --git a/packages/lib/services/attributeClass.ts b/packages/lib/services/attributeClass.ts index 5684995ca8..2a75547f9f 100644 --- a/packages/lib/services/attributeClass.ts +++ b/packages/lib/services/attributeClass.ts @@ -1,5 +1,6 @@ "use server"; import "server-only"; + import { prisma } from "@formbricks/database"; import { TAttributeClass, @@ -12,6 +13,7 @@ import { validateInputs } from "../utils/validate"; import { DatabaseError } from "@formbricks/types/v1/errors"; import { cache } from "react"; import { revalidateTag, unstable_cache } from "next/cache"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; const attributeClassesCacheTag = (environmentId: string): string => `environments-${environmentId}-attributeClasses`; @@ -99,7 +101,7 @@ export const getAttributeClassByNameCached = async (environmentId: string, name: getAttributeClassesCacheKey(environmentId), { tags: getAttributeClassesCacheKey(environmentId), - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); diff --git a/packages/lib/services/displays.ts b/packages/lib/services/displays.ts index e07d0f54a5..5cbe1983d9 100644 --- a/packages/lib/services/displays.ts +++ b/packages/lib/services/displays.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { TDisplay, diff --git a/packages/lib/services/environment.ts b/packages/lib/services/environment.ts index be03a3a159..87714c5f19 100644 --- a/packages/lib/services/environment.ts +++ b/packages/lib/services/environment.ts @@ -1,4 +1,5 @@ import "server-only"; + import { prisma } from "@formbricks/database"; import { z } from "zod"; import { Prisma, EnvironmentType } from "@prisma/client"; @@ -8,6 +9,7 @@ import { populateEnvironment } from "../utils/createDemoProductHelpers"; import { ZEnvironment, ZEnvironmentUpdateInput, ZId } from "@formbricks/types/v1/environment"; import { validateInputs } from "../utils/validate"; import { unstable_cache, revalidateTag } from "next/cache"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const getEnvironmentCacheTag = (environmentId: string) => `environments-${environmentId}`; export const getEnvironmentsCacheTag = (productId: string) => `products-${productId}-environments`; @@ -45,7 +47,7 @@ export const getEnvironment = (environmentId: string) => [`environments-${environmentId}`], { tags: [getEnvironmentCacheTag(environmentId)], - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); @@ -92,7 +94,7 @@ export const getEnvironments = async (productId: string): Promise => { +export const getInvitesByTeamId = cache(async (teamId: string): Promise => { const invites = await prisma.invite.findMany({ where: { teamId }, select: inviteSelect, diff --git a/packages/lib/services/membership.ts b/packages/lib/services/membership.ts index dee3b587ec..c1e2ab07ed 100644 --- a/packages/lib/services/membership.ts +++ b/packages/lib/services/membership.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { ResourceNotFoundError } from "@formbricks/types/v1/errors"; import { TMember, TMembership, TMembershipUpdateInput } from "@formbricks/types/v1/memberships"; diff --git a/packages/lib/services/person.ts b/packages/lib/services/person.ts index c8e80598ae..bc2ca3f203 100644 --- a/packages/lib/services/person.ts +++ b/packages/lib/services/person.ts @@ -10,6 +10,7 @@ import { cache } from "react"; import { PEOPLE_PER_PAGE } from "../constants"; import { validateInputs } from "../utils/validate"; import { getAttributeClassByName } from "./attributeClass"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const selectPerson = { id: true, @@ -100,7 +101,7 @@ export const getPersonCached = async (personId: string) => getPersonCacheKey(personId), { tags: getPersonCacheKey(personId), - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); diff --git a/packages/lib/services/product.ts b/packages/lib/services/product.ts index db57c09b29..8072f3a88e 100644 --- a/packages/lib/services/product.ts +++ b/packages/lib/services/product.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { ZId } from "@formbricks/types/v1/environment"; import { DatabaseError, ValidationError } from "@formbricks/types/v1/errors"; @@ -6,12 +8,12 @@ import { ZProduct, ZProductUpdateInput } from "@formbricks/types/v1/product"; import { Prisma } from "@prisma/client"; import { revalidateTag, unstable_cache } from "next/cache"; import { cache } from "react"; -import "server-only"; import { z } from "zod"; import { validateInputs } from "../utils/validate"; import { EnvironmentType } from "@prisma/client"; import { EventType } from "@prisma/client"; import { getEnvironmentCacheTag, getEnvironmentsCacheTag } from "./environment"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const getProductsCacheTag = (teamId: string): string => `teams-${teamId}-products`; const getProductCacheTag = (environmentId: string): string => `environments-${environmentId}-product`; @@ -85,7 +87,7 @@ export const getProducts = async (teamId: string): Promise => [`teams-${teamId}-products`], { tags: [getProductsCacheTag(teamId)], - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); @@ -124,7 +126,7 @@ export const getProductByEnvironmentIdCached = (environmentId: string) => getProductCacheKey(environmentId), { tags: getProductCacheKey(environmentId), - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); diff --git a/packages/lib/services/profile.ts b/packages/lib/services/profile.ts index dc6e4d8dc5..b176dff86f 100644 --- a/packages/lib/services/profile.ts +++ b/packages/lib/services/profile.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { ZId } from "@formbricks/types/v1/environment"; import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors"; @@ -8,6 +10,7 @@ import { unstable_cache, revalidateTag } from "next/cache"; import { validateInputs } from "../utils/validate"; import { deleteTeam } from "./team"; import { z } from "zod"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; const responseSelection = { id: true, @@ -50,7 +53,7 @@ export const getProfile = async (userId: string): Promise => [`profiles-${userId}`], { tags: [getProfileByEmailCacheTag(userId)], - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); @@ -82,7 +85,7 @@ export const getProfileByEmail = async (email: string): Promise [`profiles-${email}`], { tags: [getProfileCacheTag(email)], - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); @@ -195,29 +198,3 @@ export const deleteProfile = async (userId: string): Promise => { throw error; } }; -export async function getUserIdFromEnvironment(environmentId: string) { - const environment = await prisma.environment.findUnique({ - where: { id: environmentId }, - select: { - product: { - select: { - team: { - select: { - memberships: { - select: { - user: { - select: { - id: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }); - - return environment?.product.team.memberships[0].user.id; -} diff --git a/packages/lib/services/survey.ts b/packages/lib/services/survey.ts index c7466cdb00..6deb20e1e0 100644 --- a/packages/lib/services/survey.ts +++ b/packages/lib/services/survey.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { ZId } from "@formbricks/types/v1/environment"; import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors"; @@ -10,7 +12,6 @@ import { } from "@formbricks/types/v1/surveys"; import { Prisma } from "@prisma/client"; import { revalidateTag, unstable_cache } from "next/cache"; -import "server-only"; import { z } from "zod"; import { captureTelemetry } from "../telemetry"; import { validateInputs } from "../utils/validate"; diff --git a/packages/lib/services/tagOnResponse.ts b/packages/lib/services/tagOnResponse.ts index 4e22c16afb..0ee7952999 100644 --- a/packages/lib/services/tagOnResponse.ts +++ b/packages/lib/services/tagOnResponse.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { TTagsCount } from "@formbricks/types/v1/tags"; import { cache } from "react"; diff --git a/packages/lib/services/team.ts b/packages/lib/services/team.ts index 9288851fb7..a9417cd90a 100644 --- a/packages/lib/services/team.ts +++ b/packages/lib/services/team.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { ZId } from "@formbricks/types/v1/environment"; import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors"; @@ -24,6 +26,7 @@ import { updateEnvironmentArgs, } from "../utils/createDemoProductHelpers"; import { validateInputs } from "../utils/validate"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const select = { id: true, @@ -64,7 +67,7 @@ export const getTeamsByUserId = async (userId: string): Promise => [`users-${userId}-teams`], { tags: [getTeamsByUserIdCacheTag(userId)], - revalidate: 30 * 60, // 30 minutes + revalidate: SERVICES_REVALIDATION_INTERVAL, } )(); @@ -100,7 +103,7 @@ export const getTeamByEnvironmentId = async (environmentId: string): Promise { export const createDemoProduct = async (teamId: string) => { validateInputs([teamId, ZId]); - const productWithEnvironment = Prisma.validator()({ - include: { - environments: true, - }, - }); - type ProductWithEnvironment = Prisma.ProductGetPayload; - - const demoProduct: ProductWithEnvironment = await prisma.product.create({ + const demoProduct = await prisma.product.create({ data: { name: "Demo Product", team: { diff --git a/packages/lib/services/teamDetails.ts b/packages/lib/services/teamDetails.ts index 02dcb90832..c3704f9dfc 100644 --- a/packages/lib/services/teamDetails.ts +++ b/packages/lib/services/teamDetails.ts @@ -1,3 +1,5 @@ +import "server-only"; + import { prisma } from "@formbricks/database"; import { Prisma } from "@prisma/client"; import { validateInputs } from "../utils/validate"; diff --git a/packages/lib/services/webhook.ts b/packages/lib/services/webhook.ts index 7427f46687..404bec267d 100644 --- a/packages/lib/services/webhook.ts +++ b/packages/lib/services/webhook.ts @@ -22,6 +22,24 @@ export const getWebhooks = cache(async (environmentId: string): Promise => { + validateInputs([environmentId, ZId], [source, ZId]); + try { + const count = await prisma.webhook.count({ + where: { + environmentId, + source, + }, + }); + return count; + } catch (error) { + throw new DatabaseError(`Database error when fetching webhooks for environment ${environmentId}`); + } +}; + export const getWebhook = async (id: string): Promise => { validateInputs([id, ZId]); const webhook = await prisma.webhook.findUnique({ diff --git a/packages/lib/tag/auth.ts b/packages/lib/tag/auth.ts index d9c3b85543..2c5874f723 100644 --- a/packages/lib/tag/auth.ts +++ b/packages/lib/tag/auth.ts @@ -1,8 +1,11 @@ +import "server-only"; + import { validateInputs } from "../utils/validate"; import { hasUserEnvironmentAccess } from "../environment/auth"; import { getTag } from "./service"; import { unstable_cache } from "next/cache"; import { ZId } from "@formbricks/types/v1/environment"; +import { SERVICES_REVALIDATION_INTERVAL } from "../constants"; export const canUserAccessTag = async (userId: string, tagId: string): Promise => await unstable_cache( @@ -19,6 +22,6 @@ export const canUserAccessTag = async (userId: string, tagId: string): Promise setHoveredNumber(number)} onMouseLeave={() => setHoveredNumber(0)} - className="max-w-10 relative max-h-10 flex-1 cursor-pointer bg-white text-center text-sm leading-10"> + className="max-w-10 relative flex max-h-10 flex-1 cursor-pointer justify-center bg-white text-center text-sm leading-10"> {question.scale === "number" ? (