From babc0200850cd802b3f715bb58461b926ba31b47 Mon Sep 17 00:00:00 2001 From: Dhruwang Jariwala <67850763+Dhruwang@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:25:52 +0530 Subject: [PATCH] chore: short url legacy removal (#6391) --- apps/web/app/[shortUrlId]/loading.tsx | 12 ---- apps/web/app/[shortUrlId]/page.tsx | 59 ------------------- apps/web/lib/shortUrl/service.ts | 44 -------------- apps/web/vite.config.mts | 2 - .../technical-handbook/database-model.mdx | 1 - .../migration.sql | 2 + packages/database/schema.prisma | 12 ---- packages/types/short-url.ts | 14 ----- sonar-project.properties | 4 +- 9 files changed, 4 insertions(+), 146 deletions(-) delete mode 100644 apps/web/app/[shortUrlId]/loading.tsx delete mode 100644 apps/web/app/[shortUrlId]/page.tsx delete mode 100644 apps/web/lib/shortUrl/service.ts create mode 100644 packages/database/migration/20250811123224_remove_short_url/migration.sql delete mode 100644 packages/types/short-url.ts diff --git a/apps/web/app/[shortUrlId]/loading.tsx b/apps/web/app/[shortUrlId]/loading.tsx deleted file mode 100644 index f49a67b31c..0000000000 --- a/apps/web/app/[shortUrlId]/loading.tsx +++ /dev/null @@ -1,12 +0,0 @@ -const Loading = () => { - return ( -
-
-
-
-
-
- ); -}; - -export default Loading; diff --git a/apps/web/app/[shortUrlId]/page.tsx b/apps/web/app/[shortUrlId]/page.tsx deleted file mode 100644 index 8a6a824d27..0000000000 --- a/apps/web/app/[shortUrlId]/page.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { getShortUrl } from "@/lib/shortUrl/service"; -import { getMetadataForLinkSurvey } from "@/modules/survey/link/metadata"; -import type { Metadata } from "next"; -import { notFound, redirect } from "next/navigation"; -import { logger } from "@formbricks/logger"; -import { TShortUrl, ZShortUrlId } from "@formbricks/types/short-url"; - -export const generateMetadata = async (props): Promise => { - const params = await props.params; - if (!params.shortUrlId) { - notFound(); - } - - if (ZShortUrlId.safeParse(params.shortUrlId).success !== true) { - notFound(); - } - - try { - const shortUrl = await getShortUrl(params.shortUrlId); - - if (!shortUrl) { - notFound(); - } - - const surveyId = shortUrl.url.substring(shortUrl.url.lastIndexOf("/") + 1); - return getMetadataForLinkSurvey(surveyId); - } catch (error) { - notFound(); - } -}; - -const Page = async (props) => { - const params = await props.params; - if (!params.shortUrlId) { - notFound(); - } - - if (ZShortUrlId.safeParse(params.shortUrlId).success !== true) { - // return not found if unable to parse short url id - notFound(); - } - - let shortUrl: TShortUrl | null = null; - - try { - shortUrl = await getShortUrl(params.shortUrlId); - } catch (error) { - logger.error(error, "Could not fetch short url"); - notFound(); - } - - if (shortUrl) { - redirect(shortUrl.url); - } - - notFound(); -}; - -export default Page; diff --git a/apps/web/lib/shortUrl/service.ts b/apps/web/lib/shortUrl/service.ts deleted file mode 100644 index 8c1df269d5..0000000000 --- a/apps/web/lib/shortUrl/service.ts +++ /dev/null @@ -1,44 +0,0 @@ -// DEPRECATED -// The ShortUrl feature is deprecated and only available for backward compatibility. -import { Prisma } from "@prisma/client"; -import { cache as reactCache } from "react"; -import { z } from "zod"; -import { prisma } from "@formbricks/database"; -import { DatabaseError } from "@formbricks/types/errors"; -import { TShortUrl, ZShortUrlId } from "@formbricks/types/short-url"; -import { validateInputs } from "../utils/validate"; - -// Get the full url from short url and return it -export const getShortUrl = reactCache(async (id: string): Promise => { - validateInputs([id, ZShortUrlId]); - try { - return await prisma.shortUrl.findUnique({ - where: { - id, - }, - }); - } catch (error) { - if (error instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseError(error.message); - } - - throw error; - } -}); - -export const getShortUrlByUrl = reactCache(async (url: string): Promise => { - validateInputs([url, z.string().url()]); - try { - return await prisma.shortUrl.findUnique({ - where: { - url, - }, - }); - } catch (error) { - if (error instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseError(error.message); - } - - throw error; - } -}); diff --git a/apps/web/vite.config.mts b/apps/web/vite.config.mts index 10dcd8544e..6e3bda203e 100644 --- a/apps/web/vite.config.mts +++ b/apps/web/vite.config.mts @@ -73,8 +73,6 @@ export default defineConfig({ "modules/setup/**/intro/**", // Setup intro pages "modules/setup/**/signup/**", // Setup signup pages "modules/setup/**/layout.tsx", // Setup layouts - "lib/shortUrl/**", // Short URL functionality - "app/[shortUrlId]", // Short URL pages "modules/ee/contacts/components/**", // Contact components // Third-party integrations diff --git a/docs/development/technical-handbook/database-model.mdx b/docs/development/technical-handbook/database-model.mdx index dd4f6625cd..2bf81d4e51 100644 --- a/docs/development/technical-handbook/database-model.mdx +++ b/docs/development/technical-handbook/database-model.mdx @@ -175,7 +175,6 @@ Formbricks stores all data in PostgreSQL tables. Here's a comprehensive list of | Response | Stores survey responses and associated metadata | | ResponseNote | Contains team member comments on survey responses | | Segment | Defines groups of contacts based on attributes | -| ShortUrl | Maps shortened URLs to their full destinations | | Survey | Stores survey configurations, questions, and display rules | | SurveyAttributeFilter | Defines targeting rules for surveys based on contact attributes | | SurveyFollowUp | Configures automated actions based on survey responses | diff --git a/packages/database/migration/20250811123224_remove_short_url/migration.sql b/packages/database/migration/20250811123224_remove_short_url/migration.sql new file mode 100644 index 0000000000..4800203aaf --- /dev/null +++ b/packages/database/migration/20250811123224_remove_short_url/migration.sql @@ -0,0 +1,2 @@ +-- Drop ShortUrl table +DROP TABLE IF EXISTS "ShortUrl"; diff --git a/packages/database/schema.prisma b/packages/database/schema.prisma index 4a075673ba..9429326367 100644 --- a/packages/database/schema.prisma +++ b/packages/database/schema.prisma @@ -874,18 +874,6 @@ model User { @@index([email]) } -/// Maps a short URL to its full destination. -/// Used for creating memorable, shortened URLs for surveys. -/// -/// @property id - Short identifier/slug for the URL -/// @property url - The full destination URL -model ShortUrl { - id String @id // generate nanoId in service - createdAt DateTime @default(now()) @map(name: "created_at") - updatedAt DateTime @updatedAt @map(name: "updated_at") - url String @unique -} - /// Defines a segment of contacts based on attributes. /// Used for targeting surveys to specific user groups. /// diff --git a/packages/types/short-url.ts b/packages/types/short-url.ts deleted file mode 100644 index 23ccd12620..0000000000 --- a/packages/types/short-url.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { z } from "zod"; - -export const ZShortUrlId = z.string().length(10); - -export type TShortUrlId = z.infer; - -export const ZShortUrl = z.object({ - id: ZShortUrlId, - createdAt: z.date(), - updatedAt: z.date(), - url: z.string().url(), -}); - -export type TShortUrl = z.infer; diff --git a/sonar-project.properties b/sonar-project.properties index 31aca3d5c7..b2fbde521e 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -21,5 +21,5 @@ sonar.scm.exclusions.disabled=false sonar.sourceEncoding=UTF-8 # Coverage -sonar.coverage.exclusions=**/*.test.*,**/*.spec.*,**/*.mdx,**/*.config.mts,**/*.config.ts,**/constants.ts,**/route.ts,**/route.tsx,**/types/**,**/types.ts,**/stories.*,**/*.mock.*,**/mocks/**,**/__mocks__/**,**/openapi.ts,**/openapi-document.ts,**/instrumentation.ts,scripts/openapi/merge-client-endpoints.ts,**/playwright/**,**/Dockerfile,**/*.config.cjs,**/*.css,**/templates.ts,**/actions.ts,apps/web/modules/ui/components/icons/*,**/*.json,apps/web/vitestSetup.ts,packages/js-core/src/index.ts,apps/web/tailwind.config.js,apps/web/postcss.config.js,apps/web/next.config.mjs,apps/web/scripts/**,packages/js-core/vitest.setup.ts,**/*.mjs,apps/web/modules/auth/lib/mock-data.ts,apps/web/modules/analysis/components/SingleResponseCard/components/Smileys.tsx,packages/surveys/src/components/general/smileys.tsx,**/cache.ts,apps/web/app/**/billing-confirmation/**,apps/web/modules/ee/billing/**,apps/web/modules/ee/multi-language-surveys/**,apps/web/modules/email/**,apps/web/modules/integrations/**,apps/web/modules/setup/**/intro/**,apps/web/modules/setup/**/signup/**,apps/web/modules/setup/**/layout.tsx,apps/web/modules/survey/follow-ups/**,apps/web/app/share/**,apps/web/lib/shortUrl/**,apps/web/modules/ee/contacts/[contactId]/**,apps/web/modules/ee/contacts/components/**,apps/web/modules/ee/two-factor-auth/**,apps/web/lib/posthogServer.ts,apps/web/lib/slack/**,apps/web/lib/notion/**,apps/web/lib/googleSheet/**,apps/web/app/api/google-sheet/**,apps/web/app/api/billing/**,apps/web/lib/airtable/**,apps/web/app/api/v1/integrations/**,apps/web/lib/env.ts,**/instrumentation-node.ts,**/cache/**,**/*.svg,apps/web/modules/ui/components/icons/**,apps/web/modules/ui/components/table/** -sonar.cpd.exclusions=**/*.test.*,**/*.spec.*,**/*.mdx,**/*.config.mts,**/*.config.ts,**/constants.ts,**/route.ts,**/route.tsx,**/types/**,**/types.ts,**/stories.*,**/*.mock.*,**/mocks/**,**/__mocks__/**,**/openapi.ts,**/openapi-document.ts,**/instrumentation.ts,scripts/openapi/merge-client-endpoints.ts,**/playwright/**,**/Dockerfile,**/*.config.cjs,**/*.css,**/templates.ts,**/actions.ts,apps/web/modules/ui/components/icons/*,**/*.json,apps/web/vitestSetup.ts,apps/web/tailwind.config.js,apps/web/postcss.config.js,apps/web/next.config.mjs,apps/web/scripts/**,packages/js-core/vitest.setup.ts,packages/js-core/src/index.ts,**/*.mjs,apps/web/modules/auth/lib/mock-data.ts,apps/web/modules/analysis/components/SingleResponseCard/components/Smileys.tsx,packages/surveys/src/components/general/smileys.tsx,**/cache.ts,apps/web/app/**/billing-confirmation/**,apps/web/modules/ee/billing/**,apps/web/modules/ee/multi-language-surveys/**,apps/web/modules/email/**,apps/web/modules/integrations/**,apps/web/modules/setup/**/intro/**,apps/web/modules/setup/**/signup/**,apps/web/modules/setup/**/layout.tsx,apps/web/modules/survey/follow-ups/**,apps/web/app/share/**,apps/web/lib/shortUrl/**,apps/web/modules/ee/contacts/[contactId]/**,apps/web/modules/ee/contacts/components/**,apps/web/modules/ee/two-factor-auth/**,apps/web/lib/posthogServer.ts,apps/web/lib/slack/**,apps/web/lib/notion/**,apps/web/lib/googleSheet/**,apps/web/app/api/google-sheet/**,apps/web/app/api/billing/**,apps/web/lib/airtable/**,apps/web/app/api/v1/integrations/**,apps/web/lib/env.ts,**/instrumentation-node.ts,**/cache/**,**/*.svg,apps/web/modules/ui/components/icons/**,apps/web/modules/ui/components/table/** +sonar.coverage.exclusions=**/*.test.*,**/*.spec.*,**/*.mdx,**/*.config.mts,**/*.config.ts,**/constants.ts,**/route.ts,**/route.tsx,**/types/**,**/types.ts,**/stories.*,**/*.mock.*,**/mocks/**,**/__mocks__/**,**/openapi.ts,**/openapi-document.ts,**/instrumentation.ts,scripts/openapi/merge-client-endpoints.ts,**/playwright/**,**/Dockerfile,**/*.config.cjs,**/*.css,**/templates.ts,**/actions.ts,apps/web/modules/ui/components/icons/*,**/*.json,apps/web/vitestSetup.ts,packages/js-core/src/index.ts,apps/web/tailwind.config.js,apps/web/postcss.config.js,apps/web/next.config.mjs,apps/web/scripts/**,packages/js-core/vitest.setup.ts,**/*.mjs,apps/web/modules/auth/lib/mock-data.ts,apps/web/modules/analysis/components/SingleResponseCard/components/Smileys.tsx,packages/surveys/src/components/general/smileys.tsx,**/cache.ts,apps/web/app/**/billing-confirmation/**,apps/web/modules/ee/billing/**,apps/web/modules/ee/multi-language-surveys/**,apps/web/modules/email/**,apps/web/modules/integrations/**,apps/web/modules/setup/**/intro/**,apps/web/modules/setup/**/signup/**,apps/web/modules/setup/**/layout.tsx,apps/web/modules/survey/follow-ups/**,apps/web/app/share/**,apps/web/modules/ee/contacts/[contactId]/**,apps/web/modules/ee/contacts/components/**,apps/web/modules/ee/two-factor-auth/**,apps/web/lib/posthogServer.ts,apps/web/lib/slack/**,apps/web/lib/notion/**,apps/web/lib/googleSheet/**,apps/web/app/api/google-sheet/**,apps/web/app/api/billing/**,apps/web/lib/airtable/**,apps/web/app/api/v1/integrations/**,apps/web/lib/env.ts,**/instrumentation-node.ts,**/cache/**,**/*.svg,apps/web/modules/ui/components/icons/**,apps/web/modules/ui/components/table/** +sonar.cpd.exclusions=**/*.test.*,**/*.spec.*,**/*.mdx,**/*.config.mts,**/*.config.ts,**/constants.ts,**/route.ts,**/route.tsx,**/types/**,**/types.ts,**/stories.*,**/*.mock.*,**/mocks/**,**/__mocks__/**,**/openapi.ts,**/openapi-document.ts,**/instrumentation.ts,scripts/openapi/merge-client-endpoints.ts,**/playwright/**,**/Dockerfile,**/*.config.cjs,**/*.css,**/templates.ts,**/actions.ts,apps/web/modules/ui/components/icons/*,**/*.json,apps/web/vitestSetup.ts,apps/web/tailwind.config.js,apps/web/postcss.config.js,apps/web/next.config.mjs,apps/web/scripts/**,packages/js-core/vitest.setup.ts,packages/js-core/src/index.ts,**/*.mjs,apps/web/modules/auth/lib/mock-data.ts,apps/web/modules/analysis/components/SingleResponseCard/components/Smileys.tsx,packages/surveys/src/components/general/smileys.tsx,**/cache.ts,apps/web/app/**/billing-confirmation/**,apps/web/modules/ee/billing/**,apps/web/modules/ee/multi-language-surveys/**,apps/web/modules/email/**,apps/web/modules/integrations/**,apps/web/modules/setup/**/intro/**,apps/web/modules/setup/**/signup/**,apps/web/modules/setup/**/layout.tsx,apps/web/modules/survey/follow-ups/**,apps/web/app/share/**,apps/web/modules/ee/contacts/[contactId]/**,apps/web/modules/ee/contacts/components/**,apps/web/modules/ee/two-factor-auth/**,apps/web/lib/posthogServer.ts,apps/web/lib/slack/**,apps/web/lib/notion/**,apps/web/lib/googleSheet/**,apps/web/app/api/google-sheet/**,apps/web/app/api/billing/**,apps/web/lib/airtable/**,apps/web/app/api/v1/integrations/**,apps/web/lib/env.ts,**/instrumentation-node.ts,**/cache/**,**/*.svg,apps/web/modules/ui/components/icons/**,apps/web/modules/ui/components/table/**