feat(server): added identity privilege route changes with project slug

This commit is contained in:
Akhil Mohan
2024-03-28 19:55:12 +05:30
parent 51716336c2
commit c8cbcaf10c
8 changed files with 264 additions and 214 deletions
@@ -1,12 +1,13 @@
import { packRules } from "@casl/ability/extra";
import { MongoAbility, RawRuleOf } from "@casl/ability";
import { PackRule, packRules, unpackRules } from "@casl/ability/extra";
import slugify from "@sindresorhus/slugify";
import ms from "ms";
import { z } from "zod";
import { IdentityProjectAdditionalPrivilegeSchema } from "@app/db/schemas";
import { IdentityProjectAdditionalPrivilegeTemporaryMode } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-types";
import { ProjectPermissionSet } from "@app/ee/services/permission/project-permission";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { zpStr } from "@app/lib/zod";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { AuthMode } from "@app/services/auth/auth-type";
@@ -18,37 +19,37 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
body: z.union([
z.object({
identityId: z.string().min(1),
projectId: z.string().min(1),
// disallow empty string
slug: zpStr(
z
.string()
.max(60)
.trim()
.optional()
.default(`privilege-${slugify(alphaNumericNanoId(12))}`)
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
})
),
projectSlug: z.string().min(1),
slug: z
.string()
.min(1)
.max(60)
.trim()
.optional()
.default(`privilege-${slugify(alphaNumericNanoId(12))}`)
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
}),
permissions: z.any().array(),
isPackedPermission: z.boolean().optional().default(true),
isPackedPermission: z.boolean().optional().default(false),
isTemporary: z.literal(false).default(false)
}),
z.object({
identityId: z.string(),
projectId: z.string(),
projectSlug: z.string().min(1),
slug: z
.string()
.min(1)
.max(60)
.trim()
.optional()
.default(`privilege-${slugify(alphaNumericNanoId(12))}`)
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
}),
permissions: z.any().array(),
isTemporary: z.literal(true),
isPackedPermission: z.boolean().optional().default(true),
isPackedPermission: z.boolean().optional().default(false),
temporaryMode: z.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode),
temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"),
temporaryAccessStartTime: z.string().datetime()
@@ -77,30 +78,33 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
});
server.route({
url: "/:privilegeId",
url: "/",
method: "PATCH",
schema: {
params: z.object({
privilegeId: z.string()
body: z.object({
// disallow empty string
slug: z.string().min(1),
identityId: z.string().min(1),
projectSlug: z.string().min(1),
data: z
.object({
slug: z
.string()
.min(1)
.max(60)
.trim()
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
}),
isPackedPermission: z.boolean().optional().default(false),
permissions: z.any().array(),
isTemporary: z.boolean(),
temporaryMode: z.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode),
temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"),
temporaryAccessStartTime: z.string().datetime()
})
.partial()
}),
body: z
.object({
// disallow empty string
slug: z
.string()
.max(60)
.trim()
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
}),
permissions: z.any().array(),
isPackedPermission: z.boolean().optional().default(true),
isTemporary: z.boolean(),
temporaryMode: z.nativeEnum(IdentityProjectAdditionalPrivilegeTemporaryMode),
temporaryRange: z.string().refine((val) => ms(val) > 0, "Temporary range must be a positive number"),
temporaryAccessStartTime: z.string().datetime()
})
.partial(),
response: {
200: z.object({
privilege: IdentityProjectAdditionalPrivilegeSchema
@@ -109,27 +113,32 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const privilege = await server.services.identityProjectAdditionalPrivilege.updateById({
const { isPackedPermission, ...data } = req.body.data;
const privilege = await server.services.identityProjectAdditionalPrivilege.updateBySlug({
actorId: req.permission.id,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod,
...req.body,
permissions: req.body.permissions
? JSON.stringify(req.body.isPackedPermission ? req.body.permissions : packRules(req.body.permissions))
: undefined,
privilegeId: req.params.privilegeId
data: {
...data,
permissions: data?.permissions
? JSON.stringify(isPackedPermission ? data?.permissions : packRules(data.permissions))
: undefined
}
});
return { privilege };
}
});
server.route({
url: "/:privilegeId",
url: "/",
method: "DELETE",
schema: {
params: z.object({
privilegeId: z.string()
body: z.object({
slug: z.string().min(1),
identityId: z.string().min(1),
projectSlug: z.string().min(1)
}),
response: {
200: z.object({
@@ -139,23 +148,27 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const privilege = await server.services.identityProjectAdditionalPrivilege.deleteById({
const privilege = await server.services.identityProjectAdditionalPrivilege.deleteBySlug({
actorId: req.permission.id,
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
privilegeId: req.params.privilegeId
...req.body
});
return { privilege };
}
});
server.route({
url: "/:privilegeId",
url: "/:slug",
method: "GET",
schema: {
params: z.object({
privilegeId: z.string()
slug: z.string()
}),
querystring: z.object({
identityId: z.string().min(1),
projectSlug: z.string().min(1)
}),
response: {
200: z.object({
@@ -165,24 +178,29 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
},
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const privilege = await server.services.identityProjectAdditionalPrivilege.getPrivilegeDetailsById({
const privilege = await server.services.identityProjectAdditionalPrivilege.getPrivilegeDetailsBySlug({
actorId: req.permission.id,
actorAuthMethod: req.permission.authMethod,
actor: req.permission.type,
actorOrgId: req.permission.orgId,
privilegeId: req.params.privilegeId
slug: req.params.slug,
...req.query
});
return { privilege };
}
});
server.route({
url: "/permissions",
method: "POST",
url: "/",
method: "GET",
schema: {
body: z.object({
identityId: z.string(),
projectId: z.string()
querystring: z.object({
identityId: z.string().min(1),
projectSlug: z.string().min(1),
unpacked: z
.enum(["false", "true"])
.transform((el) => el === "true")
.default("true")
}),
response: {
200: z.object({
@@ -197,9 +215,16 @@ export const registerIdentityProjectAdditionalPrivilegeRouter = async (server: F
actor: req.permission.type,
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
projectId: req.body.projectId,
identityId: req.body.identityId
...req.query
});
if (req.query.unpacked) {
return {
privileges: privileges.map(({ permissions, ...el }) => ({
...el,
permissions: unpackRules(permissions as PackRule<RawRuleOf<MongoAbility<ProjectPermissionSet>>>[])
}))
};
}
return { privileges };
}
});