mirror of
https://github.com/formbricks/formbricks.git
synced 2026-05-04 11:30:38 -05:00
c7faa29437
Co-authored-by: Dhruwang <dhruwangjariwala18@gmail.com>
141 lines
5.3 KiB
TypeScript
141 lines
5.3 KiB
TypeScript
"use server";
|
|
|
|
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";
|
|
import { IS_FORMBRICKS_CLOUD, USER_MANAGEMENT_MINIMUM_ROLE } from "@/lib/constants";
|
|
import { getMembershipByUserIdOrganizationId } from "@/lib/membership/service";
|
|
import { getUserManagementAccess } from "@/lib/membership/utils";
|
|
import { getOrganization } from "@/lib/organization/service";
|
|
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
|
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
|
|
import { getOrganizationIdFromInviteId } from "@/lib/utils/helper";
|
|
import { withAuditLogging } from "@/modules/ee/audit-logs/lib/handler";
|
|
import { getAccessControlPermission } 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 { getInvite } from "@/modules/organization/settings/teams/lib/invite";
|
|
|
|
export const checkRoleManagementPermission = async (organizationId: string) => {
|
|
const organization = await getOrganization(organizationId);
|
|
if (!organization) {
|
|
throw new Error("Organization not found");
|
|
}
|
|
|
|
const isAccessControlAllowed = await getAccessControlPermission(organizationId);
|
|
if (!isAccessControlAllowed) {
|
|
throw new OperationNotAllowedError("Role management is not allowed for this organization");
|
|
}
|
|
};
|
|
|
|
const ZUpdateInviteAction = z.object({
|
|
inviteId: ZUuid,
|
|
data: ZInviteUpdateInput,
|
|
});
|
|
|
|
export type TUpdateInviteAction = z.infer<typeof ZUpdateInviteAction>;
|
|
|
|
export const updateInviteAction = authenticatedActionClient.inputSchema(ZUpdateInviteAction).action(
|
|
withAuditLogging("updated", "invite", async ({ ctx, parsedInput }) => {
|
|
const organizationId = await getOrganizationIdFromInviteId(parsedInput.inviteId);
|
|
|
|
const currentUserMembership = await getMembershipByUserIdOrganizationId(ctx.user.id, organizationId);
|
|
if (!currentUserMembership) {
|
|
throw new AuthenticationError("User not a member of this organization");
|
|
}
|
|
|
|
await checkAuthorizationUpdated({
|
|
userId: ctx.user.id,
|
|
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(organizationId);
|
|
|
|
ctx.auditLoggingCtx.organizationId = organizationId;
|
|
ctx.auditLoggingCtx.inviteId = parsedInput.inviteId;
|
|
ctx.auditLoggingCtx.oldObject = { ...(await getInvite(parsedInput.inviteId)) };
|
|
|
|
const result = await updateInvite(parsedInput.inviteId, parsedInput.data);
|
|
|
|
ctx.auditLoggingCtx.newObject = { ...(await getInvite(parsedInput.inviteId)) };
|
|
return result;
|
|
})
|
|
);
|
|
|
|
const ZUpdateMembershipAction = z.object({
|
|
userId: ZId,
|
|
organizationId: ZId,
|
|
data: ZMembershipUpdateInput,
|
|
});
|
|
|
|
export const updateMembershipAction = authenticatedActionClient.inputSchema(ZUpdateMembershipAction).action(
|
|
withAuditLogging("updated", "membership", async ({ ctx, parsedInput }) => {
|
|
const currentUserMembership = await getMembershipByUserIdOrganizationId(
|
|
ctx.user.id,
|
|
parsedInput.organizationId
|
|
);
|
|
if (!currentUserMembership) {
|
|
throw new AuthenticationError("User not a member of this organization");
|
|
}
|
|
const hasUserManagementAccess = getUserManagementAccess(
|
|
currentUserMembership.role,
|
|
USER_MANAGEMENT_MINIMUM_ROLE
|
|
);
|
|
|
|
if (!hasUserManagementAccess) {
|
|
throw new OperationNotAllowedError("User management is not allowed for your role");
|
|
}
|
|
|
|
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);
|
|
|
|
ctx.auditLoggingCtx.organizationId = parsedInput.organizationId;
|
|
ctx.auditLoggingCtx.membershipId = `${parsedInput.userId}-${parsedInput.organizationId}`;
|
|
ctx.auditLoggingCtx.oldObject = await getMembershipByUserIdOrganizationId(
|
|
parsedInput.userId,
|
|
parsedInput.organizationId
|
|
);
|
|
const result = await updateMembership(parsedInput.userId, parsedInput.organizationId, parsedInput.data);
|
|
ctx.auditLoggingCtx.newObject = result;
|
|
return result;
|
|
})
|
|
);
|