feat: added subscription plan to secret replication

This commit is contained in:
=
2024-05-31 23:10:03 +05:30
parent 7311cf8f6c
commit 316259f218
7 changed files with 34 additions and 3 deletions
@@ -16,6 +16,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
environmentLimit: null, environmentLimit: null,
environmentsUsed: 0, environmentsUsed: 0,
dynamicSecret: false, dynamicSecret: false,
secretReplication: false,
secretVersioning: true, secretVersioning: true,
pitRecovery: false, pitRecovery: false,
ipAllowlisting: false, ipAllowlisting: false,
@@ -52,6 +52,7 @@ export type TFeatureSet = {
has_used_trial: true; has_used_trial: true;
secretApproval: false; secretApproval: false;
secretRotation: true; secretRotation: true;
secretReplication: false;
}; };
export type TOrgPlansTableDTO = { export type TOrgPlansTableDTO = {
+1
View File
@@ -590,6 +590,7 @@ export const registerRoutes = async (
secretVersionTagDAL secretVersionTagDAL
}); });
const secretImportService = secretImportServiceFactory({ const secretImportService = secretImportServiceFactory({
licenseService,
projectEnvDAL, projectEnvDAL,
folderDAL, folderDAL,
permissionService, permissionService,
@@ -1,6 +1,7 @@
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { TableName } from "@app/db/schemas"; import { TableName } from "@app/db/schemas";
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import { BadRequestError } from "@app/lib/errors"; import { BadRequestError } from "@app/lib/errors";
@@ -30,6 +31,7 @@ type TSecretImportServiceFactoryDep = {
projectEnvDAL: TProjectEnvDALFactory; projectEnvDAL: TProjectEnvDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">; permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "replicateSecrets">; secretQueueService: Pick<TSecretQueueFactory, "syncSecrets" | "replicateSecrets">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
}; };
const ERR_SEC_IMP_NOT_FOUND = new BadRequestError({ message: "Secret import not found" }); const ERR_SEC_IMP_NOT_FOUND = new BadRequestError({ message: "Secret import not found" });
@@ -43,7 +45,8 @@ export const secretImportServiceFactory = ({
folderDAL, folderDAL,
projectDAL, projectDAL,
secretDAL, secretDAL,
secretQueueService secretQueueService,
licenseService
}: TSecretImportServiceFactoryDep) => { }: TSecretImportServiceFactoryDep) => {
const createImport = async ({ const createImport = async ({
environment, environment,
@@ -78,6 +81,14 @@ export const secretImportServiceFactory = ({
secretPath: data.path secretPath: data.path
}) })
); );
if (isReplication) {
const plan = await licenseService.getPlan(actorOrgId);
if (!plan.secretReplication) {
throw new BadRequestError({
message: "Failed to create secret replication due to plan restriction. Upgrade plan to create replication."
});
}
}
await projectDAL.checkProjectUpgradeStatus(projectId); await projectDAL.checkProjectUpgradeStatus(projectId);
@@ -273,6 +284,13 @@ export const secretImportServiceFactory = ({
subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) subject(ProjectPermissionSub.Secrets, { environment, secretPath: path })
); );
const plan = await licenseService.getPlan(actorOrgId);
if (!plan.secretReplication) {
throw new BadRequestError({
message: "Failed to create secret replication due to plan restriction. Upgrade plan to create replication."
});
}
const folder = await folderDAL.findBySecretPath(projectId, environment, path); const folder = await folderDAL.findBySecretPath(projectId, environment, path);
if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Update import" }); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Update import" });
@@ -24,6 +24,7 @@ export type SubscriptionPlan = {
scim: boolean; scim: boolean;
ldap: boolean; ldap: boolean;
groups: boolean; groups: boolean;
secretReplication: boolean;
status: status:
| "incomplete" | "incomplete"
| "incomplete_expired" | "incomplete_expired"
@@ -482,6 +482,7 @@ export const ActionBar = ({
environment={environment} environment={environment}
workspaceId={workspaceId} workspaceId={workspaceId}
secretPath={secretPath} secretPath={secretPath}
onUpgradePlan={() => handlePopUpOpen("upgradePlan")}
isOpen={popUp.addSecretImport.isOpen} isOpen={popUp.addSecretImport.isOpen}
onClose={() => handlePopUpClose("addSecretImport")} onClose={() => handlePopUpClose("addSecretImport")}
onTogglePopUp={(isOpen) => handlePopUpToggle("addSecretImport", isOpen)} onTogglePopUp={(isOpen) => handlePopUpToggle("addSecretImport", isOpen)}
@@ -14,7 +14,7 @@ import {
SelectItem SelectItem
} from "@app/components/v2"; } from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput"; import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { useWorkspace } from "@app/context"; import { useSubscription, useWorkspace } from "@app/context";
import { useCreateSecretImport } from "@app/hooks/api"; import { useCreateSecretImport } from "@app/hooks/api";
const typeSchema = z.object({ const typeSchema = z.object({
@@ -38,6 +38,7 @@ type Props = {
isOpen?: boolean; isOpen?: boolean;
onClose: () => void; onClose: () => void;
onTogglePopUp: (isOpen: boolean) => void; onTogglePopUp: (isOpen: boolean) => void;
onUpgradePlan: () => void;
}; };
export const CreateSecretImportForm = ({ export const CreateSecretImportForm = ({
@@ -46,7 +47,8 @@ export const CreateSecretImportForm = ({
secretPath = "/", secretPath = "/",
isOpen, isOpen,
onClose, onClose,
onTogglePopUp onTogglePopUp,
onUpgradePlan
}: Props) => { }: Props) => {
const { const {
handleSubmit, handleSubmit,
@@ -58,6 +60,7 @@ export const CreateSecretImportForm = ({
const { currentWorkspace } = useWorkspace(); const { currentWorkspace } = useWorkspace();
const environments = currentWorkspace?.environments || []; const environments = currentWorkspace?.environments || [];
const selectedEnvironment = watch("environment"); const selectedEnvironment = watch("environment");
const { subscription } = useSubscription();
const { mutateAsync: createSecretImport } = useCreateSecretImport(); const { mutateAsync: createSecretImport } = useCreateSecretImport();
@@ -67,6 +70,11 @@ export const CreateSecretImportForm = ({
isReplication isReplication
}: TFormSchema) => { }: TFormSchema) => {
try { try {
if (isReplication && !subscription?.secretReplication) {
onUpgradePlan();
return;
}
await createSecretImport({ await createSecretImport({
environment, environment,
projectId: workspaceId, projectId: workspaceId,