refactor: consolidate unifyFeedback into feedbackDirectories license flag (#8034)

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Matti Nannt
2026-05-18 07:28:29 +02:00
committed by GitHub
parent a7370ac4a0
commit 3e5a4ca4c8
18 changed files with 43 additions and 104 deletions
@@ -11,7 +11,6 @@ export const CLOUD_STRIPE_FEATURE_LOOKUP_KEYS = {
CONTACTS: "contacts",
AI_SMART_TOOLS: "ai-smart-tools",
AI_DATA_ANALYSIS: "ai-data-analysis",
UNIFY_FEEDBACK: "unify-feedback",
FEEDBACK_DIRECTORIES: "feedback-directories",
DASHBOARDS: "dashboards",
} as const;
@@ -152,7 +152,6 @@ describe("License Core Logic", () => {
auditLogs: true,
accessControl: true,
quotas: true,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
};
@@ -293,7 +292,6 @@ describe("License Core Logic", () => {
auditLogs: false,
accessControl: false,
quotas: false,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -318,7 +316,6 @@ describe("License Core Logic", () => {
auditLogs: false,
accessControl: false,
quotas: false,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -352,7 +349,6 @@ describe("License Core Logic", () => {
auditLogs: false,
accessControl: false,
quotas: false,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
};
@@ -545,7 +541,6 @@ describe("License Core Logic", () => {
auditLogs: true,
accessControl: true,
quotas: true,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -613,7 +608,6 @@ describe("License Core Logic", () => {
auditLogs: true,
accessControl: true,
quotas: true,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -672,7 +666,6 @@ describe("License Core Logic", () => {
auditLogs: true,
accessControl: true,
quotas: true,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -879,7 +872,6 @@ describe("License Core Logic", () => {
auditLogs: false,
accessControl: false,
quotas: false,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -1063,7 +1055,6 @@ describe("License Core Logic", () => {
auditLogs: true,
accessControl: true,
quotas: true,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -1193,7 +1184,6 @@ describe("License Core Logic", () => {
auditLogs: true,
accessControl: true,
quotas: true,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
},
@@ -89,7 +89,6 @@ const LicenseFeaturesSchema = z.object({
auditLogs: z.boolean(),
accessControl: z.boolean(),
quotas: z.boolean(),
unifyFeedback: z.boolean().default(false),
feedbackDirectories: z.boolean().default(false),
dashboards: z.boolean().default(false),
});
@@ -160,7 +159,6 @@ const DEFAULT_FEATURES: TEnterpriseLicenseFeatures = {
auditLogs: false,
accessControl: false,
quotas: false,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
};
@@ -21,7 +21,6 @@ import {
getIsSpamProtectionEnabled,
getIsSsoEnabled,
getIsTwoFactorAuthEnabled,
getIsUnifyFeedbackEnabled,
getOrganizationWorkspacesLimit,
getRemoveBrandingPermission,
getWhiteLabelPermission,
@@ -65,7 +64,6 @@ const defaultFeatures: TEnterpriseLicenseFeatures = {
auditLogs: false,
accessControl: false,
quotas: false,
unifyFeedback: false,
feedbackDirectories: false,
dashboards: false,
};
@@ -271,20 +269,6 @@ describe("License Utils", () => {
expect(dataAnalysis).toBe(false);
});
test("uses cloud unify feedback entitlement", async () => {
vi.mocked(constants).IS_FORMBRICKS_CLOUD = true;
vi.mocked(hasOrganizationEntitlementWithLicenseGuard).mockResolvedValueOnce(true);
const result = await getIsUnifyFeedbackEnabled("org_1");
expect(result).toBe(true);
expect(hasOrganizationEntitlementWithLicenseGuard).toHaveBeenCalledWith(
"org_1",
CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.UNIFY_FEEDBACK
);
expect(getEnterpriseLicense).not.toHaveBeenCalled();
});
test("uses cloud feedback record directories entitlement", async () => {
vi.mocked(constants).IS_FORMBRICKS_CLOUD = true;
vi.mocked(hasOrganizationEntitlementWithLicenseGuard).mockResolvedValueOnce(true);
@@ -313,44 +297,39 @@ describe("License Utils", () => {
expect(getEnterpriseLicense).not.toHaveBeenCalled();
});
test("returns self-hosted unify feedback / FRD / dashboards from license", async () => {
test("returns self-hosted FRD / dashboards from license", async () => {
vi.mocked(constants).IS_FORMBRICKS_CLOUD = false;
vi.mocked(getEnterpriseLicense).mockResolvedValue({
...defaultLicense,
features: {
...defaultFeatures,
unifyFeedback: true,
feedbackDirectories: true,
dashboards: true,
},
});
const [unify, frd, dashboards] = await Promise.all([
getIsUnifyFeedbackEnabled("org_1"),
const [frd, dashboards] = await Promise.all([
getIsFeedbackDirectoriesEnabled("org_1"),
getIsDashboardsEnabled("org_1"),
]);
expect(unify).toBe(true);
expect(frd).toBe(true);
expect(dashboards).toBe(true);
expect(hasOrganizationEntitlementWithLicenseGuard).not.toHaveBeenCalled();
});
test("returns false for self-hosted unify feedback / FRD / dashboards when not enabled", async () => {
test("returns false for self-hosted FRD / dashboards when not enabled", async () => {
vi.mocked(constants).IS_FORMBRICKS_CLOUD = false;
vi.mocked(getEnterpriseLicense).mockResolvedValue({
...defaultLicense,
features: defaultFeatures,
});
const [unify, frd, dashboards] = await Promise.all([
getIsUnifyFeedbackEnabled("org_1"),
const [frd, dashboards] = await Promise.all([
getIsFeedbackDirectoriesEnabled("org_1"),
getIsDashboardsEnabled("org_1"),
]);
expect(unify).toBe(false);
expect(frd).toBe(false);
expect(dashboards).toBe(false);
expect(hasOrganizationEntitlementWithLicenseGuard).not.toHaveBeenCalled();
@@ -36,7 +36,6 @@ const getCustomPlanFeaturePermission = async (
| "contacts"
| "aiSmartTools"
| "aiDataAnalysis"
| "unifyFeedback"
| "feedbackDirectories"
| "dashboards"
>
@@ -48,7 +47,6 @@ const getCustomPlanFeaturePermission = async (
contacts: CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.CONTACTS,
aiSmartTools: CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.AI_SMART_TOOLS,
aiDataAnalysis: CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.AI_DATA_ANALYSIS,
unifyFeedback: CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.UNIFY_FEEDBACK,
feedbackDirectories: CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.FEEDBACK_DIRECTORIES,
dashboards: CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.DASHBOARDS,
};
@@ -164,10 +162,6 @@ export const getAccessControlPermission = async (organizationId: string): Promis
return getCustomPlanFeaturePermission(organizationId, "accessControl");
};
export const getIsUnifyFeedbackEnabled = async (organizationId: string): Promise<boolean> => {
return getCustomPlanFeaturePermission(organizationId, "unifyFeedback");
};
export const getIsFeedbackDirectoriesEnabled = async (organizationId: string): Promise<boolean> => {
return getCustomPlanFeaturePermission(organizationId, "feedbackDirectories");
};
@@ -19,7 +19,6 @@ const ZEnterpriseLicenseFeatures = z.object({
auditLogs: z.boolean(),
accessControl: z.boolean(),
quotas: z.boolean(),
unifyFeedback: z.boolean().default(false),
feedbackDirectories: z.boolean().default(false),
dashboards: z.boolean().default(false),
});
@@ -6,7 +6,7 @@ import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-clie
import { AuthenticatedActionClientCtx } from "@/lib/utils/action-client/types/context";
import { getOrganizationIdFromWorkspaceId } from "@/lib/utils/helper";
import { getFeedbackDirectoriesByWorkspaceId } from "@/modules/ee/feedback-directory/lib/feedback-directory";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import {
createFeedbackRecord,
deleteFeedbackRecord,
@@ -30,8 +30,8 @@ const ensureAccess = async (
minPermission: "read" | "readWrite"
): Promise<void> => {
const organizationId = await getOrganizationIdFromWorkspaceId(workspaceId);
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(organizationId);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(organizationId);
if (!isFeedbackDirectoriesAllowed) {
throw new OperationNotAllowedError("Unify Feedback is not enabled for this organization");
}
await checkAuthorizationUpdated({
+4 -4
View File
@@ -4,7 +4,7 @@ import { ENTERPRISE_LICENSE_REQUEST_FORM_URL, IS_FORMBRICKS_CLOUD } from "@/lib/
import { getTranslate } from "@/lingodotdev/server";
import { NoFeedbackDirectoryEmptyState } from "@/modules/ee/feedback-directory/components/no-feedback-directory-empty-state";
import { getFeedbackDirectoriesByWorkspaceId } from "@/modules/ee/feedback-directory/lib/feedback-directory";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import { UnifyConfigNavigation } from "@/modules/ee/unify-feedback/components/unify-config-navigation";
import { listFeedbackRecords } from "@/modules/hub/service";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
@@ -34,8 +34,8 @@ export default async function UnifyFeedbackRecordsPage(
return notFound();
}
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(organization.id);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(organization.id);
if (!isFeedbackDirectoriesAllowed) {
return (
<PageContentWrapper>
<PageHeader pageTitle={t("workspace.unify.feedback_records")}>
@@ -45,7 +45,7 @@ export default async function UnifyFeedbackRecordsPage(
<UpgradePrompt
title={t("workspace.unify.upgrade_prompt_title")}
description={t("workspace.unify.upgrade_prompt_description")}
feature="unify-feedback"
feature="feedback-directories"
buttons={[
{
text: IS_FORMBRICKS_CLOUD ? t("common.upgrade_plan") : t("common.request_trial_license"),
@@ -7,7 +7,7 @@ import { getSurveys } from "@/lib/survey/service";
import { authenticatedActionClient } from "@/lib/utils/action-client";
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
import { getOrganizationIdFromWorkspaceId } from "@/lib/utils/helper";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import { transformToUnifySurvey } from "./lib";
import { TUnifySurvey } from "./types";
@@ -19,8 +19,8 @@ export const getSurveysForUnifyAction = authenticatedActionClient
.schema(ZGetSurveysForUnifyAction)
.action(async ({ ctx, parsedInput }): Promise<TUnifySurvey[]> => {
const organizationId = await getOrganizationIdFromWorkspaceId(parsedInput.workspaceId);
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(organizationId);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(organizationId);
if (!isFeedbackDirectoriesAllowed) {
throw new OperationNotAllowedError("Unify Feedback is not enabled for this organization");
}
await checkAuthorizationUpdated({
@@ -4,7 +4,7 @@ import { ENTERPRISE_LICENSE_REQUEST_FORM_URL, IS_FORMBRICKS_CLOUD } from "@/lib/
import { getSurveys } from "@/lib/survey/service";
import { getTranslate } from "@/lingodotdev/server";
import { getFeedbackDirectoriesByWorkspaceId } from "@/modules/ee/feedback-directory/lib/feedback-directory";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { UpgradePrompt } from "@/modules/ui/components/upgrade-prompt";
import { getWorkspaceAuth } from "@/modules/workspaces/lib/utils";
@@ -37,15 +37,15 @@ export const WorkspaceFeedbackSourcesPage = async (
return notFound();
}
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(organization.id);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(organization.id);
if (!isFeedbackDirectoriesAllowed) {
return (
<PageContentWrapper>
<div className="flex items-center justify-center">
<UpgradePrompt
title={t("workspace.unify.upgrade_prompt_title")}
description={t("workspace.unify.upgrade_prompt_description")}
feature="unify-feedback"
feature="feedback-directories"
buttons={[
{
text: IS_FORMBRICKS_CLOUD ? t("common.upgrade_plan") : t("common.request_trial_license"),
@@ -8,7 +8,7 @@ import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-clie
import { AuthenticatedActionClientCtx } from "@/lib/utils/action-client/types/context";
import { getOrganizationIdFromWorkspaceId } from "@/lib/utils/helper";
import { getFeedbackDirectoriesByWorkspaceId } from "@/modules/ee/feedback-directory/lib/feedback-directory";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import { semanticSearchFeedbackRecords } from "@/modules/hub/service";
import type { SemanticSearchResultItem } from "@/modules/hub/types";
@@ -35,8 +35,8 @@ export type TTopicsPreviewSearchActionResult = {
const ensureReadAccess = async (userId: string, workspaceId: string): Promise<void> => {
const organizationId = await getOrganizationIdFromWorkspaceId(workspaceId);
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(organizationId);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(organizationId);
if (!isFeedbackDirectoriesAllowed) {
throw new OperationNotAllowedError("Unify Feedback is not enabled for this organization");
}
await checkAuthorizationUpdated({
@@ -3,7 +3,7 @@ import { ENTERPRISE_LICENSE_REQUEST_FORM_URL, IS_FORMBRICKS_CLOUD } from "@/lib/
import { getTranslate } from "@/lingodotdev/server";
import { NoFeedbackDirectoryEmptyState } from "@/modules/ee/feedback-directory/components/no-feedback-directory-empty-state";
import { getFeedbackDirectoriesByWorkspaceId } from "@/modules/ee/feedback-directory/lib/feedback-directory";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import { UnifyConfigNavigation } from "@/modules/ee/unify-feedback/components/unify-config-navigation";
import { PageContentWrapper } from "@/modules/ui/components/page-content-wrapper";
import { PageHeader } from "@/modules/ui/components/page-header";
@@ -29,8 +29,8 @@ export const UnifyTopicsSubtopicsPage = async (
return notFound();
}
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(organization.id);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(organization.id);
if (!isFeedbackDirectoriesAllowed) {
return (
<PageContentWrapper>
<PageHeader pageTitle={t("workspace.unify.feedback_records")}>
@@ -40,7 +40,7 @@ export const UnifyTopicsSubtopicsPage = async (
<UpgradePrompt
title={t("workspace.unify.upgrade_prompt_title")}
description={t("workspace.unify.upgrade_prompt_description")}
feature="unify-feedback"
feature="feedback-directories"
buttons={[
{
text: IS_FORMBRICKS_CLOUD ? t("common.upgrade_plan") : t("common.request_trial_license"),
@@ -12,7 +12,6 @@ const LICENSE_GUARDED_ENTITLEMENTS: Partial<Record<string, keyof TEnterpriseLice
contacts: "contacts",
"ai-smart-tools": "aiSmartTools",
"ai-data-analysis": "aiDataAnalysis",
"unify-feedback": "unifyFeedback",
"feedback-directories": "feedbackDirectories",
dashboards: "dashboards",
};
@@ -142,21 +142,6 @@ describe("getSelfHostedOrganizationEntitlementsContext", () => {
expect(result.features).toContain("ai-data-analysis");
});
test("maps unifyFeedback feature to unify-feedback entitlement", async () => {
mockGetOrg.mockResolvedValue({ id: "org1" } as any);
mockGetLicense.mockResolvedValue({
status: "active",
active: true,
features: { unifyFeedback: true },
} as any);
const result = await getSelfHostedOrganizationEntitlementsContext("org1");
expect(result.features).toContain("unify-feedback");
expect(result.features).not.toContain("feedback-directories");
expect(result.features).not.toContain("dashboards");
});
test("maps feedbackDirectories feature to feedback-directories entitlement", async () => {
mockGetOrg.mockResolvedValue({ id: "org1" } as any);
mockGetLicense.mockResolvedValue({
@@ -168,7 +153,6 @@ describe("getSelfHostedOrganizationEntitlementsContext", () => {
const result = await getSelfHostedOrganizationEntitlementsContext("org1");
expect(result.features).toContain("feedback-directories");
expect(result.features).not.toContain("unify-feedback");
expect(result.features).not.toContain("dashboards");
});
@@ -183,21 +167,19 @@ describe("getSelfHostedOrganizationEntitlementsContext", () => {
const result = await getSelfHostedOrganizationEntitlementsContext("org1");
expect(result.features).toContain("dashboards");
expect(result.features).not.toContain("unify-feedback");
expect(result.features).not.toContain("feedback-directories");
});
test("maps all three Hub features when all enabled", async () => {
test("maps both Hub features when all enabled", async () => {
mockGetOrg.mockResolvedValue({ id: "org1" } as any);
mockGetLicense.mockResolvedValue({
status: "active",
active: true,
features: { unifyFeedback: true, feedbackDirectories: true, dashboards: true },
features: { feedbackDirectories: true, dashboards: true },
} as any);
const result = await getSelfHostedOrganizationEntitlementsContext("org1");
expect(result.features).toContain("unify-feedback");
expect(result.features).toContain("feedback-directories");
expect(result.features).toContain("dashboards");
});
@@ -207,7 +189,7 @@ describe("getSelfHostedOrganizationEntitlementsContext", () => {
mockGetLicense.mockResolvedValue({
status: "expired",
active: false,
features: { unifyFeedback: true, feedbackDirectories: true, dashboards: true },
features: { feedbackDirectories: true, dashboards: true },
} as any);
const result = await getSelfHostedOrganizationEntitlementsContext("org1");
@@ -33,9 +33,6 @@ const mapLicenseFeaturesToEntitlements = (
if (features.aiDataAnalysis) {
entitlementKeys.push(CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.AI_DATA_ANALYSIS);
}
if (features.unifyFeedback) {
entitlementKeys.push(CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.UNIFY_FEEDBACK);
}
if (features.feedbackDirectories) {
entitlementKeys.push(CLOUD_STRIPE_FEATURE_LOOKUP_KEYS.FEEDBACK_DIRECTORIES);
}
+6 -6
View File
@@ -12,7 +12,7 @@ const {
mockGetFeedbackRecordTenant,
mockCheckAuthorizationUpdated,
mockUserFindUnique,
mockGetIsUnifyFeedbackEnabled,
mockGetIsFeedbackDirectoriesEnabled,
} = vi.hoisted(() => ({
mockAuthenticateApiKeyFromHeaders: vi.fn(),
mockGetApiKeyFromHeaders: vi.fn(),
@@ -23,7 +23,7 @@ const {
mockGetFeedbackRecordTenant: vi.fn(),
mockCheckAuthorizationUpdated: vi.fn(),
mockUserFindUnique: vi.fn(),
mockGetIsUnifyFeedbackEnabled: vi.fn(),
mockGetIsFeedbackDirectoriesEnabled: vi.fn(),
}));
vi.mock("@/modules/api/lib/api-key-auth", () => ({
@@ -57,7 +57,7 @@ vi.mock("@/modules/ee/feedback-directory/lib/feedback-directory", () => ({
}));
vi.mock("@/modules/ee/license-check/lib/utils", () => ({
getIsUnifyFeedbackEnabled: mockGetIsUnifyFeedbackEnabled,
getIsFeedbackDirectoriesEnabled: mockGetIsFeedbackDirectoriesEnabled,
}));
vi.mock("@/modules/hub/service", () => ({
@@ -118,7 +118,7 @@ describe("authorizeEnvoyRequest", () => {
});
mockCheckAuthorizationUpdated.mockResolvedValue(true);
mockUserFindUnique.mockResolvedValue({ id: "user_1", isActive: true });
mockGetIsUnifyFeedbackEnabled.mockResolvedValue(true);
mockGetIsFeedbackDirectoriesEnabled.mockResolvedValue(true);
});
test("allows create requests with an API key and body tenant_id", async () => {
@@ -457,7 +457,7 @@ describe("authorizeEnvoyRequest", () => {
});
test("returns 403 when unify feedback entitlement is disabled", async () => {
mockGetIsUnifyFeedbackEnabled.mockResolvedValue(false);
mockGetIsFeedbackDirectoriesEnabled.mockResolvedValue(false);
mockGetApiKeyFromHeaders.mockReturnValue("fbk_test");
mockAuthenticateApiKeyFromHeaders.mockResolvedValue({
type: "apiKey",
@@ -476,7 +476,7 @@ describe("authorizeEnvoyRequest", () => {
);
expect(response.status).toBe(403);
expect(mockGetIsUnifyFeedbackEnabled).toHaveBeenCalledWith("org_1");
expect(mockGetIsFeedbackDirectoriesEnabled).toHaveBeenCalledWith("org_1");
});
test("returns 403 for archived directories", async () => {
@@ -10,7 +10,7 @@ import { verifyFeedbackRecordsGatewayToken } from "@/lib/jwt";
import { checkAuthorizationUpdated } from "@/lib/utils/action-client/action-client-middleware";
import { getBearerTokenFromHeaders } from "@/modules/api/lib/api-key-auth";
import { getFeedbackDirectoryAuthContext } from "@/modules/ee/feedback-directory/lib/feedback-directory";
import { getIsUnifyFeedbackEnabled } from "@/modules/ee/license-check/lib/utils";
import { getIsFeedbackDirectoriesEnabled } from "@/modules/ee/license-check/lib/utils";
import {
TGatewayAuthenticatedPrincipal,
TGatewayRequestAuthorizer,
@@ -264,8 +264,10 @@ const authorizeFeedbackRecordsGatewayRequest = async (
return { allowed: false };
}
const isUnifyFeedbackAllowed = await getIsUnifyFeedbackEnabled(feedbackDirectory.organizationId);
if (!isUnifyFeedbackAllowed) {
const isFeedbackDirectoriesAllowed = await getIsFeedbackDirectoriesEnabled(
feedbackDirectory.organizationId
);
if (!isFeedbackDirectoriesAllowed) {
return { allowed: false };
}
@@ -12,7 +12,7 @@ const {
mockGetFeedbackRecordTenant,
mockCheckAuthorizationUpdated,
mockUserFindUnique,
mockGetIsUnifyFeedbackEnabled,
mockGetIsFeedbackDirectoriesEnabled,
} = vi.hoisted(() => ({
mockAuthenticateApiKeyFromHeaders: vi.fn(),
mockGetApiKeyFromHeaders: vi.fn(),
@@ -23,7 +23,7 @@ const {
mockGetFeedbackRecordTenant: vi.fn(),
mockCheckAuthorizationUpdated: vi.fn(),
mockUserFindUnique: vi.fn(),
mockGetIsUnifyFeedbackEnabled: vi.fn(),
mockGetIsFeedbackDirectoriesEnabled: vi.fn(),
}));
vi.mock("@/modules/api/lib/api-key-auth", () => ({
@@ -57,7 +57,7 @@ vi.mock("@/modules/ee/feedback-directory/lib/feedback-directory", () => ({
}));
vi.mock("@/modules/ee/license-check/lib/utils", () => ({
getIsUnifyFeedbackEnabled: mockGetIsUnifyFeedbackEnabled,
getIsFeedbackDirectoriesEnabled: mockGetIsFeedbackDirectoriesEnabled,
}));
vi.mock("@/modules/hub/service", () => ({
@@ -127,7 +127,7 @@ describe("authorizeTraefikRequest", () => {
});
mockCheckAuthorizationUpdated.mockResolvedValue(true);
mockUserFindUnique.mockResolvedValue({ id: "user_1", isActive: true });
mockGetIsUnifyFeedbackEnabled.mockResolvedValue(true);
mockGetIsFeedbackDirectoriesEnabled.mockResolvedValue(true);
});
test("allows requests using Traefik forwarded method and URI metadata", async () => {