mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-24 11:39:22 -05:00
fix: add membership checks in remaining routes (#5026)
This commit is contained in:
@@ -1,27 +1,25 @@
|
||||
import { LandingSidebar } from "@/app/(app)/(onboarding)/organizations/[organizationId]/landing/components/landing-sidebar";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getEnterpriseLicense } from "@/modules/ee/license-check/lib/utils";
|
||||
import { getOrganizationAuth } from "@/modules/organization/lib/utils";
|
||||
import { Header } from "@/modules/ui/components/header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { getOrganization, getOrganizationsByUserId } from "@formbricks/lib/organization/service";
|
||||
import { getOrganizationsByUserId } from "@formbricks/lib/organization/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
|
||||
const Page = async (props) => {
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || !session.user) {
|
||||
|
||||
const { session, organization } = await getOrganizationAuth(params.organizationId);
|
||||
|
||||
if (!session?.user) {
|
||||
return redirect(`/auth/login`);
|
||||
}
|
||||
|
||||
const user = await getUser(session.user.id);
|
||||
if (!user) return notFound();
|
||||
|
||||
const organization = await getOrganization(params.organizationId);
|
||||
if (!organization) return notFound();
|
||||
|
||||
const organizations = await getOrganizationsByUserId(session.user.id);
|
||||
|
||||
const { features } = await getEnterpriseLicense();
|
||||
|
||||
+5
-4
@@ -1,10 +1,9 @@
|
||||
import { OnboardingOptionsContainer } from "@/app/(app)/(onboarding)/organizations/components/OnboardingOptionsContainer";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getOrganizationAuth } from "@/modules/organization/lib/utils";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { Header } from "@/modules/ui/components/header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { PictureInPicture2Icon, SendIcon, XIcon } from "lucide-react";
|
||||
import { getServerSession } from "next-auth";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getUserProjects } from "@formbricks/lib/project/service";
|
||||
@@ -17,8 +16,10 @@ interface ChannelPageProps {
|
||||
|
||||
const Page = async (props: ChannelPageProps) => {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || !session.user) {
|
||||
|
||||
const { session } = await getOrganizationAuth(params.organizationId);
|
||||
|
||||
if (!session?.user) {
|
||||
return redirect(`/auth/login`);
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -1,10 +1,9 @@
|
||||
import { OnboardingOptionsContainer } from "@/app/(app)/(onboarding)/organizations/components/OnboardingOptionsContainer";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getOrganizationAuth } from "@/modules/organization/lib/utils";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { Header } from "@/modules/ui/components/header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { HeartIcon, ListTodoIcon, XIcon } from "lucide-react";
|
||||
import { getServerSession } from "next-auth";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getUserProjects } from "@formbricks/lib/project/service";
|
||||
@@ -17,8 +16,10 @@ interface ModePageProps {
|
||||
|
||||
const Page = async (props: ModePageProps) => {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || !session.user) {
|
||||
|
||||
const { session } = await getOrganizationAuth(params.organizationId);
|
||||
|
||||
if (!session?.user) {
|
||||
return redirect(`/auth/login`);
|
||||
}
|
||||
|
||||
|
||||
+7
-14
@@ -1,16 +1,14 @@
|
||||
import { getTeamsByOrganizationId } from "@/app/(app)/(onboarding)/lib/onboarding";
|
||||
import { ProjectSettings } from "@/app/(app)/(onboarding)/organizations/[organizationId]/projects/new/settings/components/ProjectSettings";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getRoleManagementPermission } from "@/modules/ee/license-check/lib/utils";
|
||||
import { getOrganizationAuth } from "@/modules/organization/lib/utils";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { Header } from "@/modules/ui/components/header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { XIcon } from "lucide-react";
|
||||
import { getServerSession } from "next-auth";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { DEFAULT_BRAND_COLOR } from "@formbricks/lib/constants";
|
||||
import { getOrganization } from "@formbricks/lib/organization/service";
|
||||
import { getUserProjects } from "@formbricks/lib/project/service";
|
||||
import { TProjectConfigChannel, TProjectConfigIndustry, TProjectMode } from "@formbricks/types/project";
|
||||
|
||||
@@ -29,25 +27,20 @@ const Page = async (props: ProjectSettingsPageProps) => {
|
||||
const searchParams = await props.searchParams;
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
|
||||
if (!session || !session.user) {
|
||||
const { session, organization } = await getOrganizationAuth(params.organizationId);
|
||||
|
||||
if (!session?.user) {
|
||||
return redirect(`/auth/login`);
|
||||
}
|
||||
|
||||
const channel = searchParams.channel || null;
|
||||
const industry = searchParams.industry || null;
|
||||
const mode = searchParams.mode || "surveys";
|
||||
const channel = searchParams.channel ?? null;
|
||||
const industry = searchParams.industry ?? null;
|
||||
const mode = searchParams.mode ?? "surveys";
|
||||
const projects = await getUserProjects(session.user.id, params.organizationId);
|
||||
|
||||
const organizationTeams = await getTeamsByOrganizationId(params.organizationId);
|
||||
|
||||
const organization = await getOrganization(params.organizationId);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
|
||||
if (!organizationTeams) {
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
|
||||
const EnvironmentPage = async (props) => {
|
||||
const params = await props.params;
|
||||
const session = await getServerSession(authOptions);
|
||||
const t = await getTranslate();
|
||||
const organization = await getOrganizationByEnvironmentId(params.environmentId);
|
||||
|
||||
if (!session) {
|
||||
return redirect(`/auth/login`);
|
||||
}
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
const { session, organization } = await getEnvironmentAuth(params.environmentId);
|
||||
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
const { isBilling } = getAccessFlags(currentUserMembership?.role);
|
||||
|
||||
+23
-46
@@ -3,15 +3,11 @@ import {
|
||||
getIsOrganizationAIReady,
|
||||
getWhiteLabelPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { TEnvironmentAuth } from "@/modules/environments/types/environment-auth";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { TMembership } from "@formbricks/types/memberships";
|
||||
import { TOrganization } from "@formbricks/types/organizations";
|
||||
import { TUser } from "@formbricks/types/user";
|
||||
import Page from "./page";
|
||||
|
||||
@@ -45,10 +41,6 @@ vi.mock("@formbricks/lib/constants", () => ({
|
||||
AI_AZURE_EMBEDDINGS_DEPLOYMENT_ID: "mock-azure-embeddings-deployment-id",
|
||||
}));
|
||||
|
||||
vi.mock("next-auth", () => ({
|
||||
getServerSession: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/tolgee/server", () => ({
|
||||
getTranslate: vi.fn(),
|
||||
}));
|
||||
@@ -57,16 +49,8 @@ vi.mock("@formbricks/lib/user/service", () => ({
|
||||
getUser: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@formbricks/lib/organization/service", () => ({
|
||||
getOrganizationByEnvironmentId: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@formbricks/lib/membership/service", () => ({
|
||||
getMembershipByUserIdOrganizationId: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@formbricks/lib/membership/utils", () => ({
|
||||
getAccessFlags: vi.fn(),
|
||||
vi.mock("@/modules/environments/lib/utils", () => ({
|
||||
getEnvironmentAuth: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("@/modules/ee/license-check/lib/utils", () => ({
|
||||
@@ -76,26 +60,21 @@ vi.mock("@/modules/ee/license-check/lib/utils", () => ({
|
||||
}));
|
||||
|
||||
describe("Page", () => {
|
||||
const mockParams = { environmentId: "test-environment-id" };
|
||||
const mockSession = { user: { id: "test-user-id" } };
|
||||
let mockEnvironmentAuth = {
|
||||
session: { user: { id: "test-user-id" } },
|
||||
currentUserMembership: { role: "owner" },
|
||||
organization: { id: "test-organization-id", billing: { plan: "free" } },
|
||||
isOwner: true,
|
||||
isManager: false,
|
||||
} as unknown as TEnvironmentAuth;
|
||||
|
||||
const mockUser = { id: "test-user-id" } as TUser;
|
||||
const mockOrganization = { id: "test-organization-id", billing: { plan: "free" } } as TOrganization;
|
||||
const mockMembership = { role: "owner" } as TMembership;
|
||||
const mockTranslate = vi.fn((key) => key);
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.mocked(getServerSession).mockResolvedValue(mockSession);
|
||||
vi.mocked(getTranslate).mockResolvedValue(mockTranslate);
|
||||
vi.mocked(getUser).mockResolvedValue(mockUser);
|
||||
vi.mocked(getOrganizationByEnvironmentId).mockResolvedValue(mockOrganization);
|
||||
vi.mocked(getMembershipByUserIdOrganizationId).mockResolvedValue(mockMembership);
|
||||
vi.mocked(getAccessFlags).mockReturnValue({
|
||||
isOwner: true,
|
||||
isManager: false,
|
||||
isBilling: false,
|
||||
isMember: false,
|
||||
});
|
||||
vi.mocked(getEnvironmentAuth).mockResolvedValue(mockEnvironmentAuth);
|
||||
vi.mocked(getIsMultiOrgEnabled).mockResolvedValue(true);
|
||||
vi.mocked(getIsOrganizationAIReady).mockResolvedValue(true);
|
||||
vi.mocked(getWhiteLabelPermission).mockResolvedValue(true);
|
||||
@@ -111,8 +90,10 @@ describe("Page", () => {
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it("renders if session user id is null", async () => {
|
||||
vi.mocked(getServerSession).mockResolvedValue({ user: { id: null } });
|
||||
it("renders if session user id empty", async () => {
|
||||
mockEnvironmentAuth.session.user.id = "";
|
||||
|
||||
vi.mocked(getEnvironmentAuth).mockResolvedValue(mockEnvironmentAuth);
|
||||
|
||||
const props = {
|
||||
params: Promise.resolve({ environmentId: "env-123" }),
|
||||
@@ -123,17 +104,13 @@ describe("Page", () => {
|
||||
expect(result).toBeTruthy();
|
||||
});
|
||||
|
||||
it("throws an error if the session is not found", async () => {
|
||||
vi.mocked(getServerSession).mockResolvedValue(null);
|
||||
it("handles getEnvironmentAuth error", async () => {
|
||||
vi.mocked(getEnvironmentAuth).mockRejectedValue(new Error("Authentication error"));
|
||||
|
||||
await expect(Page({ params: Promise.resolve(mockParams) })).rejects.toThrow("common.session_not_found");
|
||||
});
|
||||
const props = {
|
||||
params: Promise.resolve({ environmentId: "env-123" }),
|
||||
};
|
||||
|
||||
it("throws an error if the organization is not found", async () => {
|
||||
vi.mocked(getOrganizationByEnvironmentId).mockResolvedValue(null);
|
||||
|
||||
await expect(Page({ params: Promise.resolve(mockParams) })).rejects.toThrow(
|
||||
"common.organization_not_found"
|
||||
);
|
||||
await expect(Page(props)).rejects.toThrow("Authentication error");
|
||||
});
|
||||
});
|
||||
|
||||
+6
-17
@@ -1,21 +1,17 @@
|
||||
import { OrganizationSettingsNavbar } from "@/app/(app)/environments/[environmentId]/settings/(organization)/components/OrganizationSettingsNavbar";
|
||||
import { AIToggle } from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/components/AIToggle";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import {
|
||||
getIsMultiOrgEnabled,
|
||||
getIsOrganizationAIReady,
|
||||
getWhiteLabelPermission,
|
||||
} from "@/modules/ee/license-check/lib/utils";
|
||||
import { EmailCustomizationSettings } from "@/modules/ee/whitelabel/email-customization/components/email-customization-settings";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { SettingsId } from "@/modules/ui/components/settings-id";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { FB_LOGO_URL, IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
import { SettingsCard } from "../../components/SettingsCard";
|
||||
import { DeleteOrganization } from "./components/DeleteOrganization";
|
||||
@@ -24,20 +20,13 @@ import { EditOrganizationNameForm } from "./components/EditOrganizationNameForm"
|
||||
const Page = async (props: { params: Promise<{ environmentId: string }> }) => {
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
|
||||
const { session, currentUserMembership, organization, isOwner, isManager } = await getEnvironmentAuth(
|
||||
params.environmentId
|
||||
);
|
||||
|
||||
const user = session?.user?.id ? await getUser(session.user.id) : null;
|
||||
|
||||
const organization = await getOrganizationByEnvironmentId(params.environmentId);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
const { isOwner, isManager } = getAccessFlags(currentUserMembership?.role);
|
||||
const isMultiOrgEnabled = await getIsMultiOrgEnabled();
|
||||
const hasWhiteLabelPermission = await getWhiteLabelPermission(organization.billing.plan);
|
||||
|
||||
|
||||
+7
-37
@@ -3,24 +3,16 @@ import { ResponsePage } from "@/app/(app)/environments/[environmentId]/surveys/[
|
||||
import { EnableInsightsBanner } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/EnableInsightsBanner";
|
||||
import { SurveyAnalysisCTA } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SurveyAnalysisCTA";
|
||||
import { needsInsightsGeneration } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/utils";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getIsAIEnabled } from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import {
|
||||
MAX_RESPONSES_FOR_INSIGHT_GENERATION,
|
||||
RESPONSES_PER_PAGE,
|
||||
WEBAPP_URL,
|
||||
} from "@formbricks/lib/constants";
|
||||
import { getEnvironment } from "@formbricks/lib/environment/service";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
import { getProjectByEnvironmentId } from "@formbricks/lib/project/service";
|
||||
import { getResponseCountBySurveyId } from "@formbricks/lib/response/service";
|
||||
import { getSurvey } from "@formbricks/lib/survey/service";
|
||||
import { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
|
||||
@@ -30,47 +22,25 @@ import { findMatchingLocale } from "@formbricks/lib/utils/locale";
|
||||
const Page = async (props) => {
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
const [survey, environment] = await Promise.all([
|
||||
getSurvey(params.surveyId),
|
||||
getEnvironment(params.environmentId),
|
||||
]);
|
||||
|
||||
if (!environment) {
|
||||
throw new Error(t("common.environment_not_found"));
|
||||
}
|
||||
const { session, environment, organization, isReadOnly } = await getEnvironmentAuth(params.environmentId);
|
||||
|
||||
const survey = await getSurvey(params.surveyId);
|
||||
|
||||
if (!survey) {
|
||||
throw new Error(t("common.survey_not_found"));
|
||||
}
|
||||
const project = await getProjectByEnvironmentId(environment.id);
|
||||
if (!project) {
|
||||
throw new Error(t("common.project_not_found"));
|
||||
}
|
||||
|
||||
const user = await getUser(session.user.id);
|
||||
|
||||
if (!user) {
|
||||
throw new Error(t("common.user_not_found"));
|
||||
}
|
||||
|
||||
const tags = await getTagsByEnvironmentId(params.environmentId);
|
||||
const organization = await getOrganizationByEnvironmentId(params.environmentId);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
const totalResponseCount = await getResponseCountBySurveyId(params.surveyId);
|
||||
|
||||
const { isMember } = getAccessFlags(currentUserMembership?.role);
|
||||
|
||||
const permission = await getProjectPermissionByUserId(session.user.id, project.id);
|
||||
const { hasReadAccess } = getTeamPermissionFlags(permission);
|
||||
|
||||
const isReadOnly = isMember && hasReadAccess;
|
||||
|
||||
const isAIEnabled = await getIsAIEnabled({
|
||||
isAIEnabled: organization.isAIEnabled,
|
||||
billing: organization.billing,
|
||||
|
||||
+6
-37
@@ -3,14 +3,11 @@ import { EnableInsightsBanner } from "@/app/(app)/environments/[environmentId]/s
|
||||
import { SummaryPage } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SummaryPage";
|
||||
import { SurveyAnalysisCTA } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/SurveyAnalysisCTA";
|
||||
import { needsInsightsGeneration } from "@/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/utils";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getIsAIEnabled } from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { notFound } from "next/navigation";
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
@@ -18,11 +15,6 @@ import {
|
||||
MAX_RESPONSES_FOR_INSIGHT_GENERATION,
|
||||
WEBAPP_URL,
|
||||
} from "@formbricks/lib/constants";
|
||||
import { getEnvironment } from "@formbricks/lib/environment/service";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
import { getProjectByEnvironmentId } from "@formbricks/lib/project/service";
|
||||
import { getResponseCountBySurveyId } from "@formbricks/lib/response/service";
|
||||
import { getSurvey } from "@formbricks/lib/survey/service";
|
||||
import { getUser } from "@formbricks/lib/user/service";
|
||||
@@ -30,10 +22,8 @@ import { getUser } from "@formbricks/lib/user/service";
|
||||
const SurveyPage = async (props: { params: Promise<{ environmentId: string; surveyId: string }> }) => {
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
|
||||
const { session, environment, organization, isReadOnly } = await getEnvironmentAuth(params.environmentId);
|
||||
|
||||
const surveyId = params.surveyId;
|
||||
|
||||
@@ -41,41 +31,20 @@ const SurveyPage = async (props: { params: Promise<{ environmentId: string; surv
|
||||
return notFound();
|
||||
}
|
||||
|
||||
const [survey, environment] = await Promise.all([
|
||||
getSurvey(params.surveyId),
|
||||
getEnvironment(params.environmentId),
|
||||
]);
|
||||
if (!environment) {
|
||||
throw new Error(t("common.environment_not_found"));
|
||||
}
|
||||
const survey = await getSurvey(params.surveyId);
|
||||
|
||||
if (!survey) {
|
||||
throw new Error(t("common.survey_not_found"));
|
||||
}
|
||||
|
||||
const project = await getProjectByEnvironmentId(environment.id);
|
||||
if (!project) {
|
||||
throw new Error(t("common.project_not_found"));
|
||||
}
|
||||
|
||||
const user = await getUser(session.user.id);
|
||||
|
||||
if (!user) {
|
||||
throw new Error(t("common.user_not_found"));
|
||||
}
|
||||
|
||||
const organization = await getOrganizationByEnvironmentId(params.environmentId);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
const totalResponseCount = await getResponseCountBySurveyId(params.surveyId);
|
||||
|
||||
const { isMember } = getAccessFlags(currentUserMembership?.role);
|
||||
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
|
||||
const { hasReadAccess } = getTeamPermissionFlags(projectPermission);
|
||||
|
||||
const isReadOnly = isMember && hasReadAccess;
|
||||
|
||||
// I took this out cause it's cloud only right?
|
||||
// const { active: isEnterpriseEdition } = await getEnterpriseLicense();
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { cache } from "react";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getOrganization } from "@formbricks/lib/organization/service";
|
||||
import { TOrganizationAuth } from "../types/organization-auth";
|
||||
|
||||
/**
|
||||
* Common utility to fetch organization data and perform authorization checks
|
||||
*
|
||||
* Usage:
|
||||
* const { session, organization, ... } = await getOrganizationAuth(params.organizationId);
|
||||
*/
|
||||
export const getOrganizationAuth = cache(async (organizationId: string): Promise<TOrganizationAuth> => {
|
||||
const t = await getTranslate();
|
||||
|
||||
// Perform all fetches in parallel
|
||||
const [session, organization] = await Promise.all([
|
||||
getServerSession(authOptions),
|
||||
getOrganization(organizationId),
|
||||
]);
|
||||
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
if (!currentUserMembership) {
|
||||
throw new Error(t("common.membership_not_found"));
|
||||
}
|
||||
|
||||
const { isMember, isOwner, isManager, isBilling } = getAccessFlags(currentUserMembership?.role);
|
||||
|
||||
return {
|
||||
organization,
|
||||
session,
|
||||
currentUserMembership,
|
||||
isMember,
|
||||
isOwner,
|
||||
isManager,
|
||||
isBilling,
|
||||
};
|
||||
});
|
||||
@@ -1,31 +1,20 @@
|
||||
import { OrganizationSettingsNavbar } from "@/app/(app)/environments/[environmentId]/settings/(organization)/components/OrganizationSettingsNavbar";
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getRoleManagementPermission } from "@/modules/ee/license-check/lib/utils";
|
||||
import { TeamsView } from "@/modules/ee/teams/team-list/components/teams-view";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { MembersView } from "@/modules/organization/settings/teams/components/members-view";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
|
||||
import { getMembershipByUserIdOrganizationId } from "@formbricks/lib/membership/service";
|
||||
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
|
||||
|
||||
export const TeamsPage = async (props) => {
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
const organization = await getOrganizationByEnvironmentId(params.environmentId);
|
||||
|
||||
if (!organization) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
const { session, currentUserMembership, organization } = await getEnvironmentAuth(params.environmentId);
|
||||
|
||||
const canDoRoleManagement = await getRoleManagementPermission(organization.billing.plan);
|
||||
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { z } from "zod";
|
||||
import { ZMembership } from "@formbricks/types/memberships";
|
||||
import { ZOrganization } from "@formbricks/types/organizations";
|
||||
import { ZUser } from "@formbricks/types/user";
|
||||
|
||||
export const ZOrganizationAuth = z.object({
|
||||
organization: ZOrganization,
|
||||
session: z.object({
|
||||
user: ZUser.pick({ id: true }),
|
||||
expires: z.string(),
|
||||
}),
|
||||
currentUserMembership: ZMembership,
|
||||
isMember: z.boolean(),
|
||||
isOwner: z.boolean(),
|
||||
isManager: z.boolean(),
|
||||
isBilling: z.boolean(),
|
||||
});
|
||||
|
||||
export type TOrganizationAuth = z.infer<typeof ZOrganizationAuth>;
|
||||
@@ -1,21 +1,16 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getContactAttributeKeys } from "@/modules/ee/contacts/lib/contact-attribute-keys";
|
||||
import { getSegments } from "@/modules/ee/contacts/segments/lib/segments";
|
||||
import { getIsContactsEnabled, getMultiLanguagePermission } from "@/modules/ee/license-check/lib/utils";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { getProjectLanguages } from "@/modules/survey/editor/lib/project";
|
||||
import { getUserEmail } from "@/modules/survey/editor/lib/user";
|
||||
import { getSurveyFollowUpsPermission } from "@/modules/survey/follow-ups/lib/utils";
|
||||
import { getActionClasses } from "@/modules/survey/lib/action-class";
|
||||
import { getEnvironment } from "@/modules/survey/lib/environment";
|
||||
import { getMembershipRoleByUserIdOrganizationId } from "@/modules/survey/lib/membership";
|
||||
import { getProjectByEnvironmentId } from "@/modules/survey/lib/project";
|
||||
import { getResponseCountBySurveyId } from "@/modules/survey/lib/response";
|
||||
import { getOrganizationBilling, getSurvey } from "@/modules/survey/lib/survey";
|
||||
import { ErrorComponent } from "@/modules/ui/components/error-component";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import {
|
||||
DEFAULT_LOCALE,
|
||||
IS_FORMBRICKS_CLOUD,
|
||||
@@ -23,7 +18,6 @@ import {
|
||||
SURVEY_BG_COLORS,
|
||||
UNSPLASH_ACCESS_KEY,
|
||||
} from "@formbricks/lib/constants";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { SurveyEditor } from "./components/survey-editor";
|
||||
import { getUserLocale } from "./lib/user";
|
||||
|
||||
@@ -38,31 +32,20 @@ export const generateMetadata = async (props) => {
|
||||
export const SurveyEditorPage = async (props) => {
|
||||
const searchParams = await props.searchParams;
|
||||
const params = await props.params;
|
||||
|
||||
const { session, isMember, environment, hasReadAccess, currentUserMembership, projectPermission } =
|
||||
await getEnvironmentAuth(params.environmentId);
|
||||
|
||||
const t = await getTranslate();
|
||||
const [
|
||||
survey,
|
||||
project,
|
||||
environment,
|
||||
actionClasses,
|
||||
contactAttributeKeys,
|
||||
responseCount,
|
||||
session,
|
||||
segments,
|
||||
] = await Promise.all([
|
||||
const [survey, project, actionClasses, contactAttributeKeys, responseCount, segments] = await Promise.all([
|
||||
getSurvey(params.surveyId),
|
||||
getProjectByEnvironmentId(params.environmentId),
|
||||
getEnvironment(params.environmentId),
|
||||
getActionClasses(params.environmentId),
|
||||
getContactAttributeKeys(params.environmentId),
|
||||
getResponseCountBySurveyId(params.surveyId),
|
||||
getServerSession(authOptions),
|
||||
getSegments(params.environmentId),
|
||||
]);
|
||||
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
|
||||
if (!project) {
|
||||
throw new Error(t("common.project_not_found"));
|
||||
}
|
||||
@@ -72,16 +55,6 @@ export const SurveyEditorPage = async (props) => {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
|
||||
const membershipRole = await getMembershipRoleByUserIdOrganizationId(
|
||||
session?.user.id,
|
||||
project.organizationId
|
||||
);
|
||||
const { isMember } = getAccessFlags(membershipRole);
|
||||
|
||||
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
|
||||
|
||||
const { hasReadAccess } = getTeamPermissionFlags(projectPermission);
|
||||
|
||||
const isSurveyCreationDeletionDisabled = isMember && hasReadAccess;
|
||||
const locale = session.user.id ? await getUserLocale(session.user.id) : undefined;
|
||||
|
||||
@@ -115,7 +88,7 @@ export const SurveyEditorPage = async (props) => {
|
||||
actionClasses={actionClasses}
|
||||
contactAttributeKeys={contactAttributeKeys}
|
||||
responseCount={responseCount}
|
||||
membershipRole={membershipRole}
|
||||
membershipRole={currentUserMembership.role}
|
||||
projectPermission={projectPermission}
|
||||
colors={SURVEY_BG_COLORS}
|
||||
segments={segments}
|
||||
@@ -124,7 +97,7 @@ export const SurveyEditorPage = async (props) => {
|
||||
projectLanguages={projectLanguages}
|
||||
plan={organizationBilling.plan}
|
||||
isFormbricksCloud={IS_FORMBRICKS_CLOUD}
|
||||
isUnsplashConfigured={UNSPLASH_ACCESS_KEY ? true : false}
|
||||
isUnsplashConfigured={!!UNSPLASH_ACCESS_KEY}
|
||||
isCxMode={isCxMode}
|
||||
locale={locale ?? DEFAULT_LOCALE}
|
||||
mailFrom={MAIL_FROM ?? "hola@formbricks.com"}
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { TemplateList } from "@/modules/survey/components/template-list";
|
||||
import { getMembershipRoleByUserIdOrganizationId } from "@/modules/survey/lib/membership";
|
||||
import { getProjectByEnvironmentId } from "@/modules/survey/lib/project";
|
||||
import { SurveysList } from "@/modules/survey/list/components/survey-list";
|
||||
import { getEnvironment } from "@/modules/survey/list/lib/environment";
|
||||
import { getOrganizationIdByEnvironmentId } from "@/modules/survey/list/lib/organization";
|
||||
import { getSurveyCount } from "@/modules/survey/list/lib/survey";
|
||||
import { Button } from "@/modules/ui/components/button";
|
||||
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
|
||||
@@ -14,11 +9,9 @@ import { PageHeader } from "@/modules/ui/components/page-header";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { PlusIcon } from "lucide-react";
|
||||
import { Metadata } from "next";
|
||||
import { getServerSession } from "next-auth";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { DEFAULT_LOCALE, SURVEYS_PER_PAGE, WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { getUserLocale } from "@formbricks/lib/user/service";
|
||||
import { TTemplateRole } from "@formbricks/types/templates";
|
||||
|
||||
@@ -41,42 +34,22 @@ export const SurveysPage = async ({
|
||||
}: SurveyTemplateProps) => {
|
||||
const searchParams = await searchParamsProps;
|
||||
const params = await paramsProps;
|
||||
|
||||
const session = await getServerSession(authOptions);
|
||||
const project = await getProjectByEnvironmentId(params.environmentId);
|
||||
const organizationId = await getOrganizationIdByEnvironmentId(params.environmentId);
|
||||
const t = await getTranslate();
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
|
||||
const project = await getProjectByEnvironmentId(params.environmentId);
|
||||
|
||||
if (!project) {
|
||||
throw new Error(t("common.project_not_found"));
|
||||
}
|
||||
|
||||
if (!organizationId) {
|
||||
throw new Error(t("common.organization_not_found"));
|
||||
}
|
||||
const { session, isBilling, environment, isReadOnly } = await getEnvironmentAuth(params.environmentId);
|
||||
|
||||
const prefilledFilters = [project?.config.channel, project.config.industry, searchParams.role ?? null];
|
||||
|
||||
const membershipRole = await getMembershipRoleByUserIdOrganizationId(session?.user.id, organizationId);
|
||||
const { isMember, isBilling } = getAccessFlags(membershipRole);
|
||||
|
||||
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
|
||||
const { hasReadAccess } = getTeamPermissionFlags(projectPermission);
|
||||
|
||||
const isReadOnly = isMember && hasReadAccess;
|
||||
|
||||
if (isBilling) {
|
||||
return redirect(`/environments/${params.environmentId}/settings/billing`);
|
||||
}
|
||||
|
||||
const environment = await getEnvironment(params.environmentId);
|
||||
if (!environment) {
|
||||
throw new Error(t("common.environment_not_found"));
|
||||
}
|
||||
|
||||
const surveyCount = await getSurveyCount(params.environmentId);
|
||||
|
||||
const currentProjectChannel = project.config.channel ?? null;
|
||||
@@ -92,44 +65,55 @@ export const SurveysPage = async ({
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<PageContentWrapper>
|
||||
{surveyCount > 0 ? (
|
||||
<>
|
||||
<PageHeader pageTitle={t("common.surveys")} cta={isReadOnly ? <></> : <CreateSurveyButton />} />
|
||||
<SurveysList
|
||||
environmentId={environment.id}
|
||||
isReadOnly={isReadOnly}
|
||||
WEBAPP_URL={WEBAPP_URL}
|
||||
userId={session.user.id}
|
||||
surveysPerPage={SURVEYS_PER_PAGE}
|
||||
currentProjectChannel={currentProjectChannel}
|
||||
locale={locale}
|
||||
/>
|
||||
</>
|
||||
) : isReadOnly ? (
|
||||
<>
|
||||
<h1 className="px-6 text-3xl font-extrabold text-slate-700">
|
||||
{t("environments.surveys.no_surveys_created_yet")}
|
||||
</h1>
|
||||
const projectWithRequiredProps = {
|
||||
...project,
|
||||
brandColor: project.styling?.brandColor?.light ?? null,
|
||||
highlightBorderColor: null,
|
||||
};
|
||||
|
||||
<h2 className="px-6 text-lg font-medium text-slate-500">
|
||||
{t("environments.surveys.read_only_user_not_allowed_to_create_survey_warning")}
|
||||
</h2>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<h1 className="px-6 text-3xl font-extrabold text-slate-700">
|
||||
{t("environments.surveys.all_set_time_to_create_first_survey")}
|
||||
</h1>
|
||||
<TemplateList
|
||||
environmentId={environment.id}
|
||||
project={project}
|
||||
userId={session.user.id}
|
||||
prefilledFilters={prefilledFilters}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</PageContentWrapper>
|
||||
);
|
||||
let content;
|
||||
if (surveyCount > 0) {
|
||||
content = (
|
||||
<>
|
||||
<PageHeader pageTitle={t("common.surveys")} cta={isReadOnly ? <></> : <CreateSurveyButton />} />
|
||||
<SurveysList
|
||||
environmentId={environment.id}
|
||||
isReadOnly={isReadOnly}
|
||||
WEBAPP_URL={WEBAPP_URL}
|
||||
userId={session.user.id}
|
||||
surveysPerPage={SURVEYS_PER_PAGE}
|
||||
currentProjectChannel={currentProjectChannel}
|
||||
locale={locale}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
} else if (isReadOnly) {
|
||||
content = (
|
||||
<>
|
||||
<h1 className="px-6 text-3xl font-extrabold text-slate-700">
|
||||
{t("environments.surveys.no_surveys_created_yet")}
|
||||
</h1>
|
||||
|
||||
<h2 className="px-6 text-lg font-medium text-slate-500">
|
||||
{t("environments.surveys.read_only_user_not_allowed_to_create_survey_warning")}
|
||||
</h2>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
content = (
|
||||
<>
|
||||
<h1 className="px-6 text-3xl font-extrabold text-slate-700">
|
||||
{t("environments.surveys.all_set_time_to_create_first_survey")}
|
||||
</h1>
|
||||
<TemplateList
|
||||
environmentId={environment.id}
|
||||
project={projectWithRequiredProps}
|
||||
userId={session.user.id}
|
||||
prefilledFilters={prefilledFilters}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return <PageContentWrapper>{content}</PageContentWrapper>;
|
||||
};
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
import { authOptions } from "@/modules/auth/lib/authOptions";
|
||||
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
|
||||
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
|
||||
import { getEnvironment } from "@/modules/survey/lib/environment";
|
||||
import { getMembershipRoleByUserIdOrganizationId } from "@/modules/survey/lib/membership";
|
||||
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
|
||||
import { getProjectByEnvironmentId } from "@/modules/survey/lib/project";
|
||||
import { getTranslate } from "@/tolgee/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getAccessFlags } from "@formbricks/lib/membership/utils";
|
||||
import { TProjectConfigChannel, TProjectConfigIndustry } from "@formbricks/types/project";
|
||||
import { TTemplateRole } from "@formbricks/types/templates";
|
||||
import { TemplateContainerWithPreview } from "./components/template-container";
|
||||
@@ -25,37 +19,18 @@ interface SurveyTemplateProps {
|
||||
|
||||
export const SurveyTemplatesPage = async (props: SurveyTemplateProps) => {
|
||||
const searchParams = await props.searchParams;
|
||||
const params = await props.params;
|
||||
const t = await getTranslate();
|
||||
const session = await getServerSession(authOptions);
|
||||
const params = await props.params;
|
||||
const environmentId = params.environmentId;
|
||||
|
||||
if (!session) {
|
||||
throw new Error(t("common.session_not_found"));
|
||||
}
|
||||
const { session, environment, isReadOnly } = await getEnvironmentAuth(environmentId);
|
||||
|
||||
const [environment, project] = await Promise.all([
|
||||
getEnvironment(environmentId),
|
||||
getProjectByEnvironmentId(environmentId),
|
||||
]);
|
||||
const project = await getProjectByEnvironmentId(environmentId);
|
||||
|
||||
if (!project) {
|
||||
throw new Error(t("common.project_not_found"));
|
||||
}
|
||||
|
||||
if (!environment) {
|
||||
throw new Error(t("common.environment_not_found"));
|
||||
}
|
||||
const membershipRole = await getMembershipRoleByUserIdOrganizationId(
|
||||
session?.user.id,
|
||||
project.organizationId
|
||||
);
|
||||
const { isMember } = getAccessFlags(membershipRole);
|
||||
|
||||
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
|
||||
const { hasReadAccess } = getTeamPermissionFlags(projectPermission);
|
||||
|
||||
const isReadOnly = isMember && hasReadAccess;
|
||||
if (isReadOnly) {
|
||||
return redirect(`/environments/${environment.id}/surveys`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user