mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 10:19:51 -06:00
Compare commits
3 Commits
fix/e2e-ci
...
v2.7.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b849d325c | ||
|
|
0728a373a5 | ||
|
|
2191d62c70 |
@@ -3,6 +3,7 @@
|
|||||||
import {
|
import {
|
||||||
deleteMembership,
|
deleteMembership,
|
||||||
getMembershipsByUserId,
|
getMembershipsByUserId,
|
||||||
|
getOrganizationOwnerCount,
|
||||||
} from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/lib/membership";
|
} from "@/app/(app)/environments/[environmentId]/settings/(organization)/general/lib/membership";
|
||||||
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
import { authenticatedActionClient } from "@/lib/utils/action-client";
|
||||||
import { checkAuthorizationUpdated } from "@/lib/utils/action-client-middleware";
|
import { checkAuthorizationUpdated } from "@/lib/utils/action-client-middleware";
|
||||||
@@ -119,9 +120,9 @@ export const deleteMembershipAction = authenticatedActionClient
|
|||||||
throw new AuthenticationError("Not a member of this organization");
|
throw new AuthenticationError("Not a member of this organization");
|
||||||
}
|
}
|
||||||
|
|
||||||
const memberships = await getMembershipsByUserId(ctx.user.id);
|
const ownerCount = await getOrganizationOwnerCount(parsedInput.organizationId);
|
||||||
const isLastOwner = memberships?.filter((m) => m.role === "owner").length === 1;
|
|
||||||
if (membership.role === "owner" && isLastOwner) {
|
if (ownerCount <= 1) {
|
||||||
throw new ValidationError("You cannot delete the last owner of the organization");
|
throw new ValidationError("You cannot delete the last owner of the organization");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,36 @@ import { ZOptionalNumber, ZString } from "@formbricks/types/common";
|
|||||||
import { DatabaseError, UnknownError } from "@formbricks/types/errors";
|
import { DatabaseError, UnknownError } from "@formbricks/types/errors";
|
||||||
import { TMember, TMembership } from "@formbricks/types/memberships";
|
import { TMember, TMembership } from "@formbricks/types/memberships";
|
||||||
|
|
||||||
|
export const getOrganizationOwnerCount = reactCache(
|
||||||
|
async (organizationId: string): Promise<number> =>
|
||||||
|
cache(
|
||||||
|
async () => {
|
||||||
|
validateInputs([organizationId, ZString]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ownersCount = await prisma.membership.count({
|
||||||
|
where: {
|
||||||
|
organizationId,
|
||||||
|
role: "owner",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return ownersCount;
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||||
|
throw new DatabaseError(error.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[`getOrganizationOwnerCount-${organizationId}`],
|
||||||
|
{
|
||||||
|
tags: [membershipCache.tag.byOrganizationId(organizationId)],
|
||||||
|
}
|
||||||
|
)()
|
||||||
|
);
|
||||||
|
|
||||||
export const getMembersByOrganizationId = reactCache(
|
export const getMembersByOrganizationId = reactCache(
|
||||||
async (organizationId: string, page?: number): Promise<TMember[]> =>
|
async (organizationId: string, page?: number): Promise<TMember[]> =>
|
||||||
cache(
|
cache(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { sendInviteAcceptedEmail } from "@/modules/email";
|
import { sendInviteAcceptedEmail } from "@/modules/email";
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
import { getTranslations } from "next-intl/server";
|
import { getTranslations } from "next-intl/server";
|
||||||
|
import { unstable_after as after } from "next/server";
|
||||||
import { authOptions } from "@formbricks/lib/authOptions";
|
import { authOptions } from "@formbricks/lib/authOptions";
|
||||||
import { DEFAULT_LOCALE, WEBAPP_URL } from "@formbricks/lib/constants";
|
import { DEFAULT_LOCALE, WEBAPP_URL } from "@formbricks/lib/constants";
|
||||||
import { deleteInvite, getInvite } from "@formbricks/lib/invite/service";
|
import { deleteInvite, getInvite } from "@formbricks/lib/invite/service";
|
||||||
@@ -32,6 +33,37 @@ const Page = async (props) => {
|
|||||||
|
|
||||||
const isInviteExpired = new Date(invite.expiresAt) < new Date();
|
const isInviteExpired = new Date(invite.expiresAt) < new Date();
|
||||||
|
|
||||||
|
const createMembershipAction = async () => {
|
||||||
|
"use server";
|
||||||
|
|
||||||
|
if (!session || !user) return;
|
||||||
|
|
||||||
|
await createMembership(invite.organizationId, session.user.id, {
|
||||||
|
accepted: true,
|
||||||
|
role: invite.role,
|
||||||
|
});
|
||||||
|
await deleteInvite(inviteId);
|
||||||
|
await sendInviteAcceptedEmail(
|
||||||
|
invite.creator.name ?? "",
|
||||||
|
user?.name ?? "",
|
||||||
|
invite.creator.email,
|
||||||
|
user?.locale ?? DEFAULT_LOCALE
|
||||||
|
);
|
||||||
|
await updateUser(session.user.id, {
|
||||||
|
notificationSettings: {
|
||||||
|
...user.notificationSettings,
|
||||||
|
alert: user.notificationSettings.alert ?? {},
|
||||||
|
weeklySummary: user.notificationSettings.weeklySummary ?? {},
|
||||||
|
unsubscribedOrganizationIds: Array.from(
|
||||||
|
new Set([
|
||||||
|
...(user.notificationSettings?.unsubscribedOrganizationIds || []),
|
||||||
|
invite.organizationId,
|
||||||
|
])
|
||||||
|
),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
if (isInviteExpired) {
|
if (isInviteExpired) {
|
||||||
return (
|
return (
|
||||||
<ContentLayout
|
<ContentLayout
|
||||||
@@ -68,30 +100,8 @@ const Page = async (props) => {
|
|||||||
</ContentLayout>
|
</ContentLayout>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await createMembership(invite.organizationId, session.user.id, {
|
after(async () => {
|
||||||
accepted: true,
|
await createMembershipAction();
|
||||||
role: invite.role,
|
|
||||||
});
|
|
||||||
await deleteInvite(inviteId);
|
|
||||||
|
|
||||||
await sendInviteAcceptedEmail(
|
|
||||||
invite.creator.name ?? "",
|
|
||||||
user?.name ?? "",
|
|
||||||
invite.creator.email,
|
|
||||||
user?.locale ?? DEFAULT_LOCALE
|
|
||||||
);
|
|
||||||
await updateUser(session.user.id, {
|
|
||||||
notificationSettings: {
|
|
||||||
...user.notificationSettings,
|
|
||||||
alert: user.notificationSettings.alert ?? {},
|
|
||||||
weeklySummary: user.notificationSettings.weeklySummary ?? {},
|
|
||||||
unsubscribedOrganizationIds: Array.from(
|
|
||||||
new Set([
|
|
||||||
...(user.notificationSettings?.unsubscribedOrganizationIds || []),
|
|
||||||
invite.organizationId,
|
|
||||||
])
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,12 +20,11 @@ const nextConfig = {
|
|||||||
assetPrefix: process.env.ASSET_PREFIX_URL || undefined,
|
assetPrefix: process.env.ASSET_PREFIX_URL || undefined,
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
poweredByHeader: false,
|
poweredByHeader: false,
|
||||||
|
outputFileTracingIncludes: {
|
||||||
|
"app/api/packages": ["../../packages/js-core/dist/*", "../../packages/surveys/dist/*"],
|
||||||
|
},
|
||||||
experimental: {
|
experimental: {
|
||||||
serverComponentsExternalPackages: ["@aws-sdk"],
|
after: true,
|
||||||
instrumentationHook: true,
|
|
||||||
outputFileTracingIncludes: {
|
|
||||||
"app/api/packages": ["../../packages/js-core/dist/*", "../../packages/surveys/dist/*"],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
transpilePackages: ["@formbricks/database", "@formbricks/ee", "@formbricks/ui", "@formbricks/lib"],
|
transpilePackages: ["@formbricks/database", "@formbricks/ee", "@formbricks/ui", "@formbricks/lib"],
|
||||||
images: {
|
images: {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@formbricks/web",
|
"name": "@formbricks/web",
|
||||||
"version": "2.7.1",
|
"version": "2.7.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf .turbo node_modules .next",
|
"clean": "rimraf .turbo node_modules .next",
|
||||||
|
|||||||
Reference in New Issue
Block a user