Files
formbricks/apps/web/modules/ee/role-management/actions.ts
T
victorvhs017 665c7c6bf1 chore: add tests to api V1 (#5593)
Co-authored-by: Piyush Gupta <piyushguptaa2z123@gmail.com>
2025-05-05 05:38:16 +00:00

119 lines
4.1 KiB
TypeScript

"use server";
import { DISABLE_USER_MANAGEMENT, IS_FORMBRICKS_CLOUD } from "@/lib/constants";
import { getMembershipByUserIdOrganizationId } from "@/lib/membership/service";
import { getOrganization } from "@/lib/organization/service";
import { authenticatedActionClient } from "@/lib/utils/action-client";
import { checkAuthorizationUpdated } from "@/lib/utils/action-client-middleware";
import { getRoleManagementPermission } from "@/modules/ee/license-check/lib/utils";
import { updateInvite } from "@/modules/ee/role-management/lib/invite";
import { updateMembership } from "@/modules/ee/role-management/lib/membership";
import { ZInviteUpdateInput } from "@/modules/ee/role-management/types/invites";
import { z } from "zod";
import { ZId, ZUuid } from "@formbricks/types/common";
import { AuthenticationError, OperationNotAllowedError, ValidationError } from "@formbricks/types/errors";
import { ZMembershipUpdateInput } from "@formbricks/types/memberships";
export const checkRoleManagementPermission = async (organizationId: string) => {
const organization = await getOrganization(organizationId);
if (!organization) {
throw new Error("Organization not found");
}
const isRoleManagementAllowed = await getRoleManagementPermission(organization.billing.plan);
if (!isRoleManagementAllowed) {
throw new OperationNotAllowedError("Role management is not allowed for this organization");
}
};
const ZUpdateInviteAction = z.object({
inviteId: ZUuid,
organizationId: ZId,
data: ZInviteUpdateInput,
});
export type TUpdateInviteAction = z.infer<typeof ZUpdateInviteAction>;
export const updateInviteAction = authenticatedActionClient
.schema(ZUpdateInviteAction)
.action(async ({ ctx, parsedInput }) => {
const currentUserMembership = await getMembershipByUserIdOrganizationId(
ctx.user.id,
parsedInput.organizationId
);
if (!currentUserMembership) {
throw new AuthenticationError("User not a member of this organization");
}
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId: parsedInput.organizationId,
access: [
{
data: parsedInput.data,
schema: ZInviteUpdateInput,
type: "organization",
roles: ["owner", "manager"],
},
],
});
if (!IS_FORMBRICKS_CLOUD && parsedInput.data.role === "billing") {
throw new ValidationError("Billing role is not allowed");
}
if (currentUserMembership.role === "manager" && parsedInput.data.role !== "member") {
throw new OperationNotAllowedError("Managers can only invite members");
}
await checkRoleManagementPermission(parsedInput.organizationId);
return await updateInvite(parsedInput.inviteId, parsedInput.data);
});
const ZUpdateMembershipAction = z.object({
userId: ZId,
organizationId: ZId,
data: ZMembershipUpdateInput,
});
export const updateMembershipAction = authenticatedActionClient
.schema(ZUpdateMembershipAction)
.action(async ({ ctx, parsedInput }) => {
const currentUserMembership = await getMembershipByUserIdOrganizationId(
ctx.user.id,
parsedInput.organizationId
);
if (!currentUserMembership) {
throw new AuthenticationError("User not a member of this organization");
}
if (DISABLE_USER_MANAGEMENT) {
throw new OperationNotAllowedError("User management is disabled");
}
await checkAuthorizationUpdated({
userId: ctx.user.id,
organizationId: parsedInput.organizationId,
access: [
{
data: parsedInput.data,
schema: ZMembershipUpdateInput,
type: "organization",
roles: ["owner", "manager"],
},
],
});
if (!IS_FORMBRICKS_CLOUD && parsedInput.data.role === "billing") {
throw new ValidationError("Billing role is not allowed");
}
if (currentUserMembership.role === "manager" && parsedInput.data.role !== "member") {
throw new OperationNotAllowedError("Managers can only assign users to the member role");
}
await checkRoleManagementPermission(parsedInput.organizationId);
return await updateMembership(parsedInput.userId, parsedInput.organizationId, parsedInput.data);
});