fix: add membership checks in [environmentId] route (#5020)

Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
This commit is contained in:
victorvhs017
2025-03-20 06:07:19 -03:00
committed by GitHub
parent 452709dec7
commit ed886e1794
31 changed files with 234 additions and 667 deletions
@@ -1,5 +1,6 @@
import { WidgetStatusIndicator } from "@/app/(app)/environments/[environmentId]/components/WidgetStatusIndicator";
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
import { EnvironmentIdField } from "@/modules/projects/settings/(setup)/components/environment-id-field";
import { SetupInstructions } from "@/modules/projects/settings/(setup)/components/setup-instructions";
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
@@ -8,24 +9,12 @@ import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper
import { PageHeader } from "@/modules/ui/components/page-header";
import { getTranslate } from "@/tolgee/server";
import { WEBAPP_URL } from "@formbricks/lib/constants";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
export const AppConnectionPage = async (props) => {
const params = await props.params;
const t = await getTranslate();
const [environment, organization] = await Promise.all([
getEnvironment(params.environmentId),
getOrganizationByEnvironmentId(params.environmentId),
]);
if (!environment) {
throw new Error(t("common.environment_not_found"));
}
if (!organization) {
throw new Error(t("common.organization_not_found"));
}
const { environment } = await getEnvironmentAuth(params.environmentId);
return (
<PageContentWrapper>
@@ -1,54 +1,22 @@
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
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 { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
import { EnvironmentNotice } from "@/modules/ui/components/environment-notice";
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 { 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 { findMatchingLocale } from "@formbricks/lib/utils/locale";
import { ApiKeyList } from "./components/api-key-list";
export const APIKeysPage = async (props) => {
const params = await props.params;
const t = await getTranslate();
const [session, environment, organization, project] = await Promise.all([
getServerSession(authOptions),
getEnvironment(params.environmentId),
getOrganizationByEnvironmentId(params.environmentId),
getProjectByEnvironmentId(params.environmentId),
]);
if (!environment) {
throw new Error(t("common.environment_not_found"));
}
if (!organization) {
throw new Error(t("common.organization_not_found"));
}
if (!session) {
throw new Error(t("common.session_not_found"));
}
// Use the new utility to get all required data with authorization checks
const { environment, isReadOnly } = await getEnvironmentAuth(params.environmentId);
const locale = await findMatchingLocale();
if (!project) {
throw new Error(t("common.project_not_found"));
}
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
const { isMember } = getAccessFlags(currentUserMembership?.role);
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
const { hasManageAccess } = getTeamPermissionFlags(projectPermission);
const isReadOnly = isMember && !hasManageAccess;
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.project_configuration")}>
@@ -1,19 +1,13 @@
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
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 { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
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 packageJson from "@/package.json";
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 { getAccessFlags } from "@formbricks/lib/membership/utils";
import { getOrganizationByEnvironmentId } from "@formbricks/lib/organization/service";
import { getProjectByEnvironmentId, getProjects } from "@formbricks/lib/project/service";
import { getProjects } from "@formbricks/lib/project/service";
import { DeleteProject } from "./components/delete-project";
import { EditProjectNameForm } from "./components/edit-project-name-form";
import { EditWaitingTimeForm } from "./components/edit-waiting-time-form";
@@ -21,32 +15,13 @@ import { EditWaitingTimeForm } from "./components/edit-waiting-time-form";
export const GeneralSettingsPage = async (props: { params: Promise<{ environmentId: string }> }) => {
const params = await props.params;
const t = await getTranslate();
const [project, session, organization] = await Promise.all([
getProjectByEnvironmentId(params.environmentId),
getServerSession(authOptions),
getOrganizationByEnvironmentId(params.environmentId),
]);
if (!project) {
throw new Error(t("common.project_not_found"));
}
if (!session) {
throw new Error(t("common.session_not_found"));
}
if (!organization) {
throw new Error(t("common.organization_not_found"));
}
const { isReadOnly, isOwner, isManager, project, organization } = await getEnvironmentAuth(
params.environmentId
);
const organizationProjects = await getProjects(organization.id);
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
const { isMember, isOwner, isManager } = getAccessFlags(currentUserMembership?.role);
const { hasManageAccess } = getTeamPermissionFlags(projectPermission);
const isReadOnly = isMember && !hasManageAccess;
const isOwnerOrManager = isOwner || isManager;
return (
+12 -33
View File
@@ -1,12 +1,6 @@
import { authOptions } from "@/modules/auth/lib/authOptions";
import { getTranslate } from "@/tolgee/server";
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
import { Metadata } from "next";
import { getServerSession } from "next-auth";
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";
import { getProjectByEnvironmentId } from "@formbricks/lib/project/service";
export const metadata: Metadata = {
title: "Configuration",
@@ -14,35 +8,20 @@ export const metadata: Metadata = {
export const ProjectSettingsLayout = async (props) => {
const params = await props.params;
const { children } = props;
const t = await getTranslate();
try {
// Use the new utility to get all required data with authorization checks
const { isBilling } = await getEnvironmentAuth(params.environmentId);
const [organization, session] = await Promise.all([
getOrganizationByEnvironmentId(params.environmentId),
getServerSession(authOptions),
]);
// Redirect billing users
if (isBilling) {
return redirect(`/environments/${params.environmentId}/settings/billing`);
}
if (!organization) {
throw new Error(t("common.organization_not_found"));
return children;
} catch (error) {
// The error boundary will catch this
throw error;
}
if (!session) {
throw new Error(t("common.session_not_found"));
}
const currentUserMembership = await getMembershipByUserIdOrganizationId(session.user.id, organization.id);
const { isBilling } = getAccessFlags(currentUserMembership?.role);
if (isBilling) {
return redirect(`/environments/${params.environmentId}/settings/billing`);
}
const project = await getProjectByEnvironmentId(params.environmentId);
if (!project) {
throw new Error("Project not found");
}
return children;
};
@@ -1,52 +1,32 @@
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
import { authOptions } from "@/modules/auth/lib/authOptions";
import { getWhiteLabelPermission } from "@/modules/ee/license-check/lib/utils";
import { getProjectPermissionByUserId } from "@/modules/ee/teams/lib/roles";
import { getTeamPermissionFlags } from "@/modules/ee/teams/utils/teams";
import { BrandingSettingsCard } from "@/modules/ee/whitelabel/remove-branding/components/branding-settings-card";
import { getEnvironmentAuth } from "@/modules/environments/lib/utils";
import { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
import { EditLogo } from "@/modules/projects/settings/look/components/edit-logo";
import { getProjectByEnvironmentId } from "@/modules/projects/settings/look/lib/project";
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 { cn } from "@formbricks/lib/cn";
import { SURVEY_BG_COLORS, UNSPLASH_ACCESS_KEY } 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 { EditPlacementForm } from "./components/edit-placement-form";
import { ThemeStyling } from "./components/theme-styling";
export const ProjectLookSettingsPage = async (props: { params: Promise<{ environmentId: string }> }) => {
const params = await props.params;
const t = await getTranslate();
const [session, organization, project] = await Promise.all([
getServerSession(authOptions),
getOrganizationByEnvironmentId(params.environmentId),
getProjectByEnvironmentId(params.environmentId),
]);
const { isReadOnly, organization } = await getEnvironmentAuth(params.environmentId);
const project = await getProjectByEnvironmentId(params.environmentId);
if (!project) {
throw new Error(t("common.project_not_found"));
}
if (!session) {
throw new Error(t("common.session_not_found"));
}
if (!organization) {
throw new Error(t("common.organization_not_found"));
throw new Error("Project not found");
}
const canRemoveBranding = await getWhiteLabelPermission(organization.billing.plan);
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
const { isMember } = getAccessFlags(currentUserMembership?.role);
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
const { hasManageAccess } = getTeamPermissionFlags(projectPermission);
const isReadOnly = isMember && !hasManageAccess;
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.project_configuration")}>
@@ -60,7 +40,7 @@ export const ProjectLookSettingsPage = async (props: { params: Promise<{ environ
environmentId={params.environmentId}
project={project}
colors={SURVEY_BG_COLORS}
isUnsplashConfigured={UNSPLASH_ACCESS_KEY ? true : false}
isUnsplashConfigured={!!UNSPLASH_ACCESS_KEY}
isReadOnly={isReadOnly}
/>
</SettingsCard>
@@ -1,17 +1,9 @@
import { SettingsCard } from "@/app/(app)/environments/[environmentId]/settings/components/SettingsCard";
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 { ProjectConfigNavigation } from "@/modules/projects/settings/components/project-config-navigation";
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 { 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 { getTagsByEnvironmentId } from "@formbricks/lib/tag/service";
import { getTagsOnResponsesCount } from "@formbricks/lib/tagOnResponse/service";
import { EditTagsWrapper } from "./components/edit-tags-wrapper";
@@ -19,42 +11,14 @@ import { EditTagsWrapper } from "./components/edit-tags-wrapper";
export const TagsPage = async (props) => {
const params = await props.params;
const t = await getTranslate();
const environment = await getEnvironment(params.environmentId);
if (!environment) {
throw new Error(t("common.environment_not_found"));
}
const [tags, environmentTagsCount, organization, session, project] = await Promise.all([
const { isReadOnly, environment } = await getEnvironmentAuth(params.environmentId);
const [tags, environmentTagsCount] = await Promise.all([
getTagsByEnvironmentId(params.environmentId),
getTagsOnResponsesCount(params.environmentId),
getOrganizationByEnvironmentId(params.environmentId),
getServerSession(authOptions),
getProjectByEnvironmentId(params.environmentId),
]);
if (!environment) {
throw new Error(t("common.environment_not_found"));
}
if (!organization) {
throw new Error(t("common.organization_not_found"));
}
if (!session) {
throw new Error(t("common.session_not_found"));
}
if (!project) {
throw new Error(t("common.project_not_found"));
}
const currentUserMembership = await getMembershipByUserIdOrganizationId(session?.user.id, organization.id);
const { isMember } = getAccessFlags(currentUserMembership?.role);
const projectPermission = await getProjectPermissionByUserId(session.user.id, project.id);
const { hasManageAccess } = getTeamPermissionFlags(projectPermission);
const isReadOnly = isMember && !hasManageAccess;
return (
<PageContentWrapper>
<PageHeader pageTitle={t("common.project_configuration")}>