feat: made v2 project role router use projectid instead of projectslug

This commit is contained in:
=
2024-10-19 21:14:15 +05:30
parent a749e70815
commit 558a809b4c
6 changed files with 112 additions and 120 deletions

View File

@@ -12,6 +12,7 @@ import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { SanitizedRoleSchemaV1 } from "@app/server/routes/sanitizedSchemas";
import { AuthMode } from "@app/services/auth/auth-type";
import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types";
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
server.route({
@@ -61,7 +62,10 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
filter: {
type: ProjectRoleServiceIdentifierType.SLUG,
projectSlug: req.params.projectSlug
},
data: {
...req.body,
permissions: JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions)))
@@ -121,7 +125,6 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
roleId: req.params.roleId,
data: {
...req.body,
@@ -164,7 +167,6 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
roleId: req.params.roleId
});
return { role };
@@ -200,7 +202,10 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug
filter: {
type: ProjectRoleServiceIdentifierType.SLUG,
projectSlug: req.params.projectSlug
}
});
return { roles };
}
@@ -230,7 +235,10 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
filter: {
type: ProjectRoleServiceIdentifierType.SLUG,
projectSlug: req.params.projectSlug
},
roleSlug: req.params.slug
});
return { role };

View File

@@ -2,18 +2,19 @@ import { packRules } from "@casl/ability/extra";
import slugify from "@sindresorhus/slugify";
import { z } from "zod";
import { ProjectMembershipRole, ProjectMembershipsSchema, ProjectRolesSchema } from "@app/db/schemas";
import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { PROJECT_ROLE } from "@app/lib/api-docs";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { SanitizedRoleSchema } from "@app/server/routes/sanitizedSchemas";
import { AuthMode } from "@app/services/auth/auth-type";
import { ProjectRoleServiceIdentifierType } from "@app/services/project-role/project-role-types";
export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
server.route({
method: "POST",
url: "/:projectSlug/roles",
url: "/:projectId/roles",
config: {
rateLimit: writeLimit
},
@@ -25,7 +26,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECT_ROLE.CREATE.projectSlug)
projectId: z.string().trim().describe(PROJECT_ROLE.CREATE.projectId)
}),
body: z.object({
slug: z
@@ -58,7 +59,10 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
filter: {
type: ProjectRoleServiceIdentifierType.ID,
projectId: req.params.projectId
},
data: {
...req.body,
permissions: JSON.stringify(packRules(req.body.permissions))
@@ -82,7 +86,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECT_ROLE.UPDATE.projectSlug),
projectId: z.string().trim().describe(PROJECT_ROLE.UPDATE.projectId),
roleId: z.string().trim().describe(PROJECT_ROLE.UPDATE.roleId)
}),
body: z.object({
@@ -118,7 +122,6 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
roleId: req.params.roleId,
data: {
...req.body,
@@ -131,7 +134,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
server.route({
method: "DELETE",
url: "/:projectSlug/roles/:roleId",
url: "/:projectId/roles/:roleId",
config: {
rateLimit: writeLimit
},
@@ -143,7 +146,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECT_ROLE.DELETE.projectSlug),
projectId: z.string().trim().describe(PROJECT_ROLE.DELETE.projectId),
roleId: z.string().trim().describe(PROJECT_ROLE.DELETE.roleId)
}),
response: {
@@ -159,7 +162,6 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
roleId: req.params.roleId
});
return { role };
@@ -168,7 +170,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:projectSlug/roles",
url: "/:projectId/roles",
config: {
rateLimit: readLimit
},
@@ -180,7 +182,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
}
],
params: z.object({
projectSlug: z.string().trim().describe(PROJECT_ROLE.LIST.projectSlug)
projectId: z.string().trim().describe(PROJECT_ROLE.LIST.projectId)
}),
response: {
200: z.object({
@@ -195,7 +197,10 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug
filter: {
type: ProjectRoleServiceIdentifierType.ID,
projectId: req.params.projectId
}
});
return { roles };
}
@@ -203,13 +208,13 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
server.route({
method: "GET",
url: "/:projectSlug/roles/slug/:roleSlug",
url: "/:projectId/roles/slug/:roleSlug",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectSlug),
projectId: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.projectId),
roleSlug: z.string().trim().describe(PROJECT_ROLE.GET_ROLE_BY_SLUG.roleSlug)
}),
response: {
@@ -225,48 +230,13 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => {
actorId: req.permission.id,
actorOrgId: req.permission.orgId,
actor: req.permission.type,
projectSlug: req.params.projectSlug,
filter: {
type: ProjectRoleServiceIdentifierType.ID,
projectId: req.params.projectId
},
roleSlug: req.params.roleSlug
});
return { role };
}
});
server.route({
method: "GET",
url: "/:projectId/permissions",
config: {
rateLimit: readLimit
},
schema: {
params: z.object({
projectId: z.string().trim()
}),
response: {
200: z.object({
data: z.object({
membership: ProjectMembershipsSchema.extend({
roles: z
.object({
role: z.string()
})
.array()
}),
permissions: z.any().array()
})
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {
const { permissions, membership } = await server.services.projectRole.getUserPermission(
req.permission.id,
req.params.projectId,
req.permission.authMethod,
req.permission.orgId
);
return { data: { permissions, membership } };
}
});
};

View File

@@ -1367,6 +1367,7 @@ export const PKI_COLLECTIONS = {
export const PROJECT_ROLE = {
CREATE: {
projectSlug: "Slug of the project to create the role for.",
projectId: "Id of the project to create the role for.",
slug: "The slug of the role.",
name: "The name of the role.",
description: "The description for the role.",
@@ -1374,6 +1375,7 @@ export const PROJECT_ROLE = {
},
UPDATE: {
projectSlug: "Slug of the project to update the role for.",
projectId: "Id of the project to update the role for.",
roleId: "The ID of the role to update",
slug: "The slug of the role.",
name: "The name of the role.",
@@ -1382,14 +1384,17 @@ export const PROJECT_ROLE = {
},
DELETE: {
projectSlug: "Slug of the project to delete this role for.",
projectId: "Id of the project to delete the role for.",
roleId: "The ID of the role to update"
},
GET_ROLE_BY_SLUG: {
projectSlug: "The slug of the project.",
projectId: "The id of the project.",
roleSlug: "The slug of the role to get details"
},
LIST: {
projectSlug: "The slug of the project to list the roles of."
projectSlug: "The slug of the project to list the roles of.",
projectId: "The id of the project."
}
};

View File

@@ -17,7 +17,14 @@ import { TProjectDALFactory } from "../project/project-dal";
import { TProjectUserMembershipRoleDALFactory } from "../project-membership/project-user-membership-role-dal";
import { TProjectRoleDALFactory } from "./project-role-dal";
import { getPredefinedRoles } from "./project-role-fns";
import { TCreateRoleDTO, TDeleteRoleDTO, TGetRoleBySlugDTO, TListRolesDTO, TUpdateRoleDTO } from "./project-role-types";
import {
ProjectRoleServiceIdentifierType,
TCreateRoleDTO,
TDeleteRoleDTO,
TGetRoleDetailsDTO,
TListRolesDTO,
TUpdateRoleDTO
} from "./project-role-types";
type TProjectRoleServiceFactoryDep = {
projectRoleDAL: TProjectRoleDALFactory;
@@ -41,10 +48,15 @@ export const projectRoleServiceFactory = ({
projectUserMembershipRoleDAL,
projectDAL
}: TProjectRoleServiceFactoryDep) => {
const createRole = async ({ projectSlug, data, actor, actorId, actorAuthMethod, actorOrgId }: TCreateRoleDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
const projectId = project.id;
const createRole = async ({ data, actor, actorId, actorAuthMethod, actorOrgId, filter }: TCreateRoleDTO) => {
let projectId = "";
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
const project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: "Project not found" });
projectId = project.id;
} else {
projectId = filter.projectId;
}
const { permission } = await permissionService.getProjectPermission(
actor,
@@ -69,14 +81,19 @@ export const projectRoleServiceFactory = ({
const getRoleBySlug = async ({
actor,
actorId,
projectSlug,
actorAuthMethod,
actorOrgId,
roleSlug
}: TGetRoleBySlugDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
const projectId = project.id;
roleSlug,
filter
}: TGetRoleDetailsDTO) => {
let projectId = "";
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
const project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: "Project not found" });
projectId = project.id;
} else {
projectId = filter.projectId;
}
const { permission } = await permissionService.getProjectPermission(
actor,
@@ -96,58 +113,41 @@ export const projectRoleServiceFactory = ({
return { ...customRole, permissions: unpackPermissions(customRole.permissions) };
};
const updateRole = async ({
roleId,
projectSlug,
actorOrgId,
actorAuthMethod,
actorId,
actor,
data
}: TUpdateRoleDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
const projectId = project.id;
const updateRole = async ({ roleId, actorOrgId, actorAuthMethod, actorId, actor, data }: TUpdateRoleDTO) => {
const projectRole = await projectRoleDAL.findById(roleId);
if (!projectRole) throw new NotFoundError({ message: "Project role not found", name: "Delete role" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
projectRole.projectId,
actorAuthMethod,
actorOrgId
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Edit, ProjectPermissionSub.Role);
if (data?.slug) {
const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId });
const existingRole = await projectRoleDAL.findOne({ slug: data.slug, projectId: projectRole.projectId });
if (existingRole && existingRole.id !== roleId)
throw new BadRequestError({ name: "Update Role", message: "Project role with the same slug already exists" });
}
const [updatedRole] = await projectRoleDAL.update(
{ id: roleId, projectId },
{
...data,
permissions: data.permissions ? data.permissions : undefined
}
);
if (!updatedRole) {
throw new NotFoundError({
message: `Project role with ID '${roleId}' in project with ID '${projectId}' not found`
});
}
const updatedRole = await projectRoleDAL.updateById(projectRole.id, {
...data,
permissions: data.permissions ? data.permissions : undefined
});
if (!updatedRole) throw new NotFoundError({ message: "Project role not found", name: "Update role" });
return { ...updatedRole, permissions: unpackPermissions(updatedRole.permissions) };
};
const deleteRole = async ({ actor, actorId, actorAuthMethod, actorOrgId, projectSlug, roleId }: TDeleteRoleDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
const projectId = project.id;
const deleteRole = async ({ actor, actorId, actorAuthMethod, actorOrgId, roleId }: TDeleteRoleDTO) => {
const projectRole = await projectRoleDAL.findById(roleId);
if (!projectRole) throw new NotFoundError({ message: "Project role not found", name: "Delete role" });
const { permission } = await permissionService.getProjectPermission(
actor,
actorId,
projectId,
projectRole.projectId,
actorAuthMethod,
actorOrgId
);
@@ -169,21 +169,21 @@ export const projectRoleServiceFactory = ({
});
}
const [deletedRole] = await projectRoleDAL.delete({ id: roleId, projectId });
if (!deletedRole) {
throw new NotFoundError({
message: `Project role with ID '${roleId}' in project with ID '${projectId}' not found`,
name: "DeleteRole"
});
}
const deletedRole = await projectRoleDAL.deleteById(roleId);
if (!deletedRole) throw new NotFoundError({ message: "Project role not found", name: "Delete role" });
return { ...deletedRole, permissions: unpackPermissions(deletedRole.permissions) };
};
const listRoles = async ({ projectSlug, actorOrgId, actorAuthMethod, actorId, actor }: TListRolesDTO) => {
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
const listRoles = async ({ actorOrgId, actorAuthMethod, actorId, actor, filter }: TListRolesDTO) => {
let projectId = "";
if (filter.type === ProjectRoleServiceIdentifierType.SLUG) {
const project = await projectDAL.findProjectBySlug(filter.projectSlug, actorOrgId);
if (!project) throw new BadRequestError({ message: "Project not found" });
projectId = project.id;
} else {
projectId = filter.projectId;
}
const { permission } = await permissionService.getProjectPermission(
actor,

View File

@@ -1,27 +1,36 @@
import { TOrgRolesUpdate, TProjectRolesInsert } from "@app/db/schemas";
import { TProjectPermission } from "@app/lib/types";
export enum ProjectRoleServiceIdentifierType {
ID = "id",
SLUG = "slug"
}
export type TCreateRoleDTO = {
data: Omit<TProjectRolesInsert, "projectId">;
projectSlug: string;
filter:
| { type: ProjectRoleServiceIdentifierType.SLUG; projectSlug: string }
| { type: ProjectRoleServiceIdentifierType.ID; projectId: string };
} & Omit<TProjectPermission, "projectId">;
export type TGetRoleBySlugDTO = {
export type TGetRoleDetailsDTO = {
roleSlug: string;
projectSlug: string;
filter:
| { type: ProjectRoleServiceIdentifierType.SLUG; projectSlug: string }
| { type: ProjectRoleServiceIdentifierType.ID; projectId: string };
} & Omit<TProjectPermission, "projectId">;
export type TUpdateRoleDTO = {
roleId: string;
data: Omit<TOrgRolesUpdate, "orgId">;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TDeleteRoleDTO = {
roleId: string;
projectSlug: string;
} & Omit<TProjectPermission, "projectId">;
export type TListRolesDTO = {
projectSlug: string;
filter:
| { type: ProjectRoleServiceIdentifierType.SLUG; projectSlug: string }
| { type: ProjectRoleServiceIdentifierType.ID; projectId: string };
} & Omit<TProjectPermission, "projectId">;

View File

@@ -136,7 +136,7 @@ const getUserProjectPermissions = async ({ workspaceId }: TGetUserProjectPermiss
permissions: PackRule<RawRuleOf<MongoAbility<OrgPermissionSet>>>[];
membership: Omit<TProjectMembership, "roles"> & { roles: { role: string }[] };
};
}>(`/api/v2/workspace/${workspaceId}/permissions`, {});
}>(`/api/v1/workspace/${workspaceId}/permissions`, {});
return data.data;
};