mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 19:44:52 +00:00
Merge pull request #1804 from Infisical/feat/add-support-for-secret-folder-rename-overview
Feature: add support for secret folder rename in the overview page
This commit is contained in:
@@ -8,9 +8,16 @@ import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services
|
||||
import { TSecretSnapshotServiceFactory } from "@app/ee/services/secret-snapshot/secret-snapshot-service";
|
||||
import { BadRequestError } from "@app/lib/errors";
|
||||
|
||||
import { TProjectDALFactory } from "../project/project-dal";
|
||||
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
|
||||
import { TSecretFolderDALFactory } from "./secret-folder-dal";
|
||||
import { TCreateFolderDTO, TDeleteFolderDTO, TGetFolderDTO, TUpdateFolderDTO } from "./secret-folder-types";
|
||||
import {
|
||||
TCreateFolderDTO,
|
||||
TDeleteFolderDTO,
|
||||
TGetFolderDTO,
|
||||
TUpdateFolderDTO,
|
||||
TUpdateManyFoldersDTO
|
||||
} from "./secret-folder-types";
|
||||
import { TSecretFolderVersionDALFactory } from "./secret-folder-version-dal";
|
||||
|
||||
type TSecretFolderServiceFactoryDep = {
|
||||
@@ -19,6 +26,7 @@ type TSecretFolderServiceFactoryDep = {
|
||||
folderDAL: TSecretFolderDALFactory;
|
||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "findOne">;
|
||||
folderVersionDAL: TSecretFolderVersionDALFactory;
|
||||
projectDAL: Pick<TProjectDALFactory, "findProjectBySlug">;
|
||||
};
|
||||
|
||||
export type TSecretFolderServiceFactory = ReturnType<typeof secretFolderServiceFactory>;
|
||||
@@ -28,7 +36,8 @@ export const secretFolderServiceFactory = ({
|
||||
snapshotService,
|
||||
permissionService,
|
||||
projectEnvDAL,
|
||||
folderVersionDAL
|
||||
folderVersionDAL,
|
||||
projectDAL
|
||||
}: TSecretFolderServiceFactoryDep) => {
|
||||
const createFolder = async ({
|
||||
projectId,
|
||||
@@ -116,6 +125,105 @@ export const secretFolderServiceFactory = ({
|
||||
return folder;
|
||||
};
|
||||
|
||||
const updateManyFolders = async ({
|
||||
actor,
|
||||
actorId,
|
||||
projectSlug,
|
||||
actorAuthMethod,
|
||||
actorOrgId,
|
||||
folders
|
||||
}: TUpdateManyFoldersDTO) => {
|
||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||
if (!project) {
|
||||
throw new BadRequestError({ message: "Project not found" });
|
||||
}
|
||||
|
||||
const { permission } = await permissionService.getProjectPermission(
|
||||
actor,
|
||||
actorId,
|
||||
project.id,
|
||||
actorAuthMethod,
|
||||
actorOrgId
|
||||
);
|
||||
|
||||
folders.forEach(({ environment, path: secretPath }) => {
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
ProjectPermissionActions.Edit,
|
||||
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
|
||||
);
|
||||
});
|
||||
|
||||
const result = await folderDAL.transaction(async (tx) =>
|
||||
Promise.all(
|
||||
folders.map(async (newFolder) => {
|
||||
const { environment, path: secretPath, id, name } = newFolder;
|
||||
|
||||
const parentFolder = await folderDAL.findBySecretPath(project.id, environment, secretPath);
|
||||
if (!parentFolder) {
|
||||
throw new BadRequestError({ message: "Secret path not found", name: "Batch update folder" });
|
||||
}
|
||||
|
||||
const env = await projectEnvDAL.findOne({ projectId: project.id, slug: environment });
|
||||
if (!env) {
|
||||
throw new BadRequestError({ message: "Environment not found", name: "Batch update folder" });
|
||||
}
|
||||
const folder = await folderDAL
|
||||
.findOne({ envId: env.id, id, parentId: parentFolder.id })
|
||||
// now folder api accepts id based change
|
||||
// this is for cli backward compatiability and when cli removes this, we will remove this logic
|
||||
.catch(() => folderDAL.findOne({ envId: env.id, name: id, parentId: parentFolder.id }));
|
||||
|
||||
if (!folder) {
|
||||
throw new BadRequestError({ message: "Folder not found" });
|
||||
}
|
||||
if (name !== folder.name) {
|
||||
// ensure that new folder name is unique
|
||||
const folderToCheck = await folderDAL.findOne({
|
||||
name,
|
||||
envId: env.id,
|
||||
parentId: parentFolder.id
|
||||
});
|
||||
|
||||
if (folderToCheck) {
|
||||
throw new BadRequestError({
|
||||
message: "Folder with specified name already exists",
|
||||
name: "Batch update folder"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const [doc] = await folderDAL.update(
|
||||
{ envId: env.id, id: folder.id, parentId: parentFolder.id },
|
||||
{ name },
|
||||
tx
|
||||
);
|
||||
await folderVersionDAL.create(
|
||||
{
|
||||
name: doc.name,
|
||||
envId: doc.envId,
|
||||
version: doc.version,
|
||||
folderId: doc.id
|
||||
},
|
||||
tx
|
||||
);
|
||||
if (!doc) {
|
||||
throw new BadRequestError({ message: "Folder not found", name: "Batch update folder" });
|
||||
}
|
||||
|
||||
return { oldFolder: folder, newFolder: doc };
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
await Promise.all(result.map(async (res) => snapshotService.performSnapshot(res.newFolder.parentId as string)));
|
||||
|
||||
return {
|
||||
projectId: project.id,
|
||||
newFolders: result.map((res) => res.newFolder),
|
||||
oldFolders: result.map((res) => res.oldFolder)
|
||||
};
|
||||
};
|
||||
|
||||
const updateFolder = async ({
|
||||
projectId,
|
||||
actor,
|
||||
@@ -151,6 +259,21 @@ export const secretFolderServiceFactory = ({
|
||||
.catch(() => folderDAL.findOne({ envId: env.id, name: id, parentId: parentFolder.id }));
|
||||
|
||||
if (!folder) throw new BadRequestError({ message: "Folder not found" });
|
||||
if (name !== folder.name) {
|
||||
// ensure that new folder name is unique
|
||||
const folderToCheck = await folderDAL.findOne({
|
||||
name,
|
||||
envId: env.id,
|
||||
parentId: parentFolder.id
|
||||
});
|
||||
|
||||
if (folderToCheck) {
|
||||
throw new BadRequestError({
|
||||
message: "Folder with specified name already exists",
|
||||
name: "Update folder"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const newFolder = await folderDAL.transaction(async (tx) => {
|
||||
const [doc] = await folderDAL.update({ envId: env.id, id: folder.id, parentId: parentFolder.id }, { name }, tx);
|
||||
@@ -239,6 +362,7 @@ export const secretFolderServiceFactory = ({
|
||||
return {
|
||||
createFolder,
|
||||
updateFolder,
|
||||
updateManyFolders,
|
||||
deleteFolder,
|
||||
getFolders
|
||||
};
|
||||
|
||||
@@ -13,6 +13,16 @@ export type TUpdateFolderDTO = {
|
||||
name: string;
|
||||
} & TProjectPermission;
|
||||
|
||||
export type TUpdateManyFoldersDTO = {
|
||||
projectSlug: string;
|
||||
folders: {
|
||||
environment: string;
|
||||
path: string;
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
} & Omit<TProjectPermission, "projectId">;
|
||||
|
||||
export type TDeleteFolderDTO = {
|
||||
environment: string;
|
||||
path: string;
|
||||
|
||||
Reference in New Issue
Block a user