fix: build issues in environment service on some systems (#1160)

This commit is contained in:
Matti Nannt
2023-10-14 19:51:32 +02:00
committed by GitHub
parent 52837417bf
commit c162037446
14 changed files with 375 additions and 1944 deletions

View File

@@ -28,7 +28,6 @@
"@paralleldrive/cuid2": "^2.2.2",
"@sindresorhus/slugify": "^2.2.1",
"@tailwindcss/typography": "^0.5.10",
"@types/node": "20.6.0",
"@types/react-highlight-words": "^0.16.5",
"acorn": "^8.10.0",
"autoprefixer": "^10.4.15",

View File

@@ -15,9 +15,11 @@
"dependencies": {
"@formbricks/ui": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"react-dom": "^18.2.0",
"storybook": "^7.4.6"
},
"devDependencies": {
"@formbricks/tsconfig": "workspace:*",
"@storybook/addon-essentials": "^7.5.0-alpha.5",
"@storybook/addon-interactions": "^7.5.0-alpha.5",
"@storybook/addon-links": "^7.5.0-alpha.5",
@@ -26,22 +28,11 @@
"@storybook/react": "^7.5.0-alpha.5",
"@storybook/react-vite": "^7.5.0-alpha.5",
"@storybook/testing-library": "^0.2.2",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.16",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"@vitejs/plugin-react": "^4.1.0",
"esbuild": "^0.19.4",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-storybook": "^0.6.15",
"storybook": "^7.5.0-alpha.5",
"tailwindcss": "^3.3.3",
"tsup": "^7.2.0",
"postcss": "^8.4.31",
"vite": "^4.4.5",
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.4.1",
"@formbricks/tsconfig": "workspace:*"
"vite": "^4.4.11"
}
}

View File

@@ -1,13 +1,8 @@
import { env } from "@/env.mjs";
import { verifyPassword } from "@/app/lib/auth";
import { env } from "@/env.mjs";
import { prisma } from "@formbricks/database";
import { EMAIL_VERIFICATION_DISABLED, ENCRYPTION_KEY } from "@formbricks/lib/constants";
import { symmetricDecrypt, symmetricEncrypt } from "@formbricks/lib/crypto";
import {
EMAIL_VERIFICATION_DISABLED,
ENCRYPTION_KEY,
INTERNAL_SECRET,
WEBAPP_URL,
} from "@formbricks/lib/constants";
import { verifyToken } from "@formbricks/lib/jwt";
import { getProfileByEmail } from "@formbricks/lib/profile/service";
import type { IdentityProvider } from "@prisma/client";
@@ -288,7 +283,7 @@ export const authOptions: NextAuthOptions = {
return "/auth/login?error=A%20user%20with%20this%20email%20exists%20already.";
}
const createdUser = await prisma.user.create({
await prisma.user.create({
data: {
name: user.name,
email: user.email,
@@ -401,16 +396,6 @@ export const authOptions: NextAuthOptions = {
},
});
const teamId = createdUser.memberships?.[0]?.teamId;
if (teamId) {
fetch(`${WEBAPP_URL}/api/v1/teams/${teamId}/add_demo_product`, {
method: "POST",
headers: {
"x-api-key": INTERNAL_SECRET,
},
});
}
return true;
}

View File

@@ -1,25 +0,0 @@
import { INTERNAL_SECRET } from "@formbricks/lib/constants";
import { createDemoProduct } from "@formbricks/lib/team/service";
import { NextResponse } from "next/server";
import { headers } from "next/headers";
import { responses } from "@/app/lib/api/response";
export async function POST(_: Request, { params }: { params: { teamId: string } }) {
// Check Authentication
if (headers().get("x-api-key") !== INTERNAL_SECRET) {
return responses.notAuthenticatedResponse();
}
const teamId = params.teamId;
if (teamId === undefined) {
return responses.badRequestResponse("Missing teamId");
}
try {
const demoProduct = await createDemoProduct(teamId);
return NextResponse.json(demoProduct);
} catch (err) {
throw new Error(err);
}
}

View File

@@ -4,8 +4,8 @@
"private": true,
"scripts": {
"clean": "rimraf .turbo node_modules .next",
"dev": "next dev",
"go": "next dev",
"dev": "next dev -p 3000",
"go": "next dev -p 3000",
"build": "next build",
"start": "next start",
"lint": "next lint"
@@ -30,7 +30,6 @@
"@t3-oss/env-nextjs": "^0.7.0",
"bcryptjs": "^2.4.3",
"encoding": "^0.1.13",
"eslint-config-next": "^13.5.3",
"framer-motion": "10.16.4",
"googleapis": "^126.0.1",
"jsonwebtoken": "^9.0.2",

View File

@@ -12,6 +12,9 @@
"eslint-config-next": "^13.5.4",
"eslint-config-prettier": "^9.0.0",
"eslint-config-turbo": "latest",
"eslint-plugin-react": "7.33.2"
"eslint-plugin-react": "7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"eslint-plugin-storybook": "^0.6.15"
}
}

View File

@@ -13,7 +13,7 @@ import {
ZId,
} from "@formbricks/types/v1/environment";
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors";
import { EventType, Prisma } from "@prisma/client";
import { Prisma } from "@prisma/client";
import { revalidateTag, unstable_cache } from "next/cache";
import "server-only";
import { z } from "zod";
@@ -172,35 +172,30 @@ export const createEnvironment = async (
product: { connect: { id: productId } },
widgetSetupCompleted: environmentInput.widgetSetupCompleted || false,
eventClasses: {
create: populateEnvironment.eventClasses,
create: [
{
name: "New Session",
description: "Gets fired when a new session is created",
type: "automatic",
},
{
name: "Exit Intent (Desktop)",
description: "A user on Desktop leaves the website with the cursor.",
type: "automatic",
},
{
name: "50% Scroll",
description: "A user scrolled 50% of the current page",
type: "automatic",
},
],
},
attributeClasses: {
create: populateEnvironment.attributeClasses,
create: [
{ name: "userId", description: "The internal ID of the person", type: "automatic" },
{ name: "email", description: "The email of the person", type: "automatic" },
],
},
},
});
};
export const populateEnvironment = {
eventClasses: [
{
name: "New Session",
description: "Gets fired when a new session is created",
type: EventType.automatic,
},
{
name: "Exit Intent (Desktop)",
description: "A user on Desktop leaves the website with the cursor.",
type: EventType.automatic,
},
{
name: "50% Scroll",
description: "A user scrolled 50% of the current page",
type: EventType.automatic,
},
],
attributeClasses: [
{ name: "userId", description: "The internal ID of the person", type: EventType.automatic },
{ name: "email", description: "The email of the person", type: EventType.automatic },
],
};

View File

@@ -2,33 +2,13 @@ import "server-only";
import { prisma } from "@formbricks/database";
import { ZId } from "@formbricks/types/v1/environment";
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors";
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
import { TTeam, TTeamUpdateInput } from "@formbricks/types/v1/teams";
import { TProductUpdateInput } from "@formbricks/types/v1/product";
import { createId } from "@paralleldrive/cuid2";
import { Prisma } from "@prisma/client";
import { revalidateTag, unstable_cache } from "next/cache";
import {
ChurnResponses,
ChurnSurvey,
DEMO_COMPANIES,
DEMO_NAMES,
EASResponses,
EASSurvey,
InterviewPromptResponses,
InterviewPromptSurvey,
OnboardingResponses,
OnboardingSurvey,
PMFResponses,
PMFSurvey,
generateAttributeValue,
generateResponsesAndDisplays,
populateEnvironment,
updateEnvironmentArgs,
} from "../utils/createDemoProductHelpers";
import { validateInputs } from "../utils/validate";
import { SERVICES_REVALIDATION_INTERVAL } from "../constants";
import { getEnvironmentCacheTag } from "../environment/service";
import { validateInputs } from "../utils/validate";
export const select = {
id: true,
@@ -198,181 +178,3 @@ export const deleteTeam = async (teamId: string): Promise<TTeam> => {
throw error;
}
};
export const createDemoProduct = async (teamId: string): Promise<TProductUpdateInput> => {
validateInputs([teamId, ZId]);
const demoProduct = await prisma.product.create({
data: {
name: "Demo Product",
team: {
connect: {
id: teamId,
},
},
environments: {
create: [
{
type: "production",
...populateEnvironment,
},
{
type: "development",
...populateEnvironment,
},
],
},
},
include: {
environments: true,
},
});
const prodEnvironment = demoProduct.environments.find((environment) => environment.type === "production");
// add attributes to each environment of the product
// dont add dev environment
const updatedEnvironment = await prisma.environment.update({
where: { id: prodEnvironment?.id },
data: {
...updateEnvironmentArgs,
},
include: {
attributeClasses: true, // include attributeClasses
eventClasses: true, // include eventClasses
},
});
const eventClasses = updatedEnvironment.eventClasses;
// check if updatedEnvironment exists and it has attributeClasses
if (!updatedEnvironment || !updatedEnvironment.attributeClasses) {
throw new ValidationError("Attribute classes could not be created");
}
const attributeClasses = updatedEnvironment.attributeClasses;
// create an array for all the events that will be created
const eventPromises: {
eventClassId: string;
sessionId: string;
}[] = [];
// create an array for all the attributes that will be created
const generatedAttributes: {
attributeClassId: string;
value: string;
personId: string;
}[] = [];
// create an array containing all the person ids to be created
const personIds = Array.from({ length: 20 }).map((_) => createId());
// create an array containing all the session ids to be created
const sessionIds = Array.from({ length: 20 }).map((_) => createId());
// loop over the person ids and create attributes for each person
personIds.forEach((personId, i: number) => {
generatedAttributes.push(
...attributeClasses.map((attributeClass) => {
let value = generateAttributeValue(
attributeClass.name,
DEMO_NAMES[i],
DEMO_COMPANIES[i],
`${DEMO_COMPANIES[i].toLowerCase().split(" ").join("")}.com`,
i
);
return {
attributeClassId: attributeClass.id,
value: value,
personId,
};
})
);
});
sessionIds.forEach((sessionId) => {
for (let eventClass of eventClasses) {
// create a random number of events for each event class
const eventCount = Math.floor(Math.random() * 5) + 1;
for (let j = 0; j < eventCount; j++) {
eventPromises.push({
eventClassId: eventClass.id,
sessionId,
});
}
}
});
// create the people, sessions, attributes, and events in a transaction
// the order of the queries is important because of foreign key constraints
try {
await prisma.$transaction([
prisma.person.createMany({
data: personIds.map((personId) => ({
id: personId,
environmentId: demoProduct.environments[0].id,
})),
}),
prisma.session.createMany({
data: sessionIds.map((sessionId, idx) => ({
id: sessionId,
personId: personIds[idx],
})),
}),
prisma.attribute.createMany({
data: generatedAttributes,
}),
prisma.event.createMany({
data: eventPromises.map((eventPromise) => ({
eventClassId: eventPromise.eventClassId,
sessionId: eventPromise.sessionId,
})),
}),
]);
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError("Database operation failed");
}
throw error;
}
// Create a function that creates a survey
const createSurvey = async (surveyData: any, responses: any, displays: any) => {
return await prisma.survey.create({
data: {
...surveyData,
environment: { connect: { id: demoProduct.environments[0].id } },
questions: surveyData.questions as any,
responses: { create: responses },
displays: { create: displays },
},
});
};
const people = personIds.map((personId) => ({ id: personId }));
const PMFResults = generateResponsesAndDisplays(people, PMFResponses);
const OnboardingResults = generateResponsesAndDisplays(people, OnboardingResponses);
const ChurnResults = generateResponsesAndDisplays(people, ChurnResponses);
const EASResults = generateResponsesAndDisplays(people, EASResponses);
const InterviewPromptResults = generateResponsesAndDisplays(people, InterviewPromptResponses);
// Create the surveys
await createSurvey(PMFSurvey, PMFResults.responses, PMFResults.displays);
await createSurvey(OnboardingSurvey, OnboardingResults.responses, OnboardingResults.displays);
await createSurvey(ChurnSurvey, ChurnResults.responses, ChurnResults.displays);
await createSurvey(EASSurvey, EASResults.responses, EASResults.displays);
await createSurvey(
InterviewPromptSurvey,
InterviewPromptResults.responses,
InterviewPromptResults.displays
);
return demoProduct;
};

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"private": true,
"license": "MIT",
"scripts": {
"clean": "rimraf node_modules"
"clean": "rimraf node_modules .turbo"
},
"devDependencies": {
"prettier": "^3.0.3",

View File

@@ -4,7 +4,7 @@
"private": true,
"main": "index.js",
"scripts": {
"clean": "rimraf node_modules"
"clean": "rimraf node_modules .turbo"
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.6",

View File

@@ -3,10 +3,9 @@ module.exports = {
// app content
"./app/**/*.{js,ts,jsx,tsx}", // Note the addition of the `app` directory.
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./lib/**/*.{js,ts,jsx,tsx}",
// include packages if not transpiling
"../../packages/ui/**/*.{js,ts,jsx,tsx}",
"../../packages/ui/**/*.{ts,tsx}",
"!../../packages/ui/node_modules/**/*.{js,ts,jsx,tsx}",
],
theme: {

View File

@@ -10,6 +10,6 @@
"@types/node": "20.8.6",
"@types/react": "18.2.28",
"@types/react-dom": "18.2.13",
"typescript": "^5.2.2"
"typescript": "^5.1.6"
}
}

878
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff