feat: update user additional privilege router to new one

This commit is contained in:
=
2024-10-25 00:59:39 +05:30
parent 6f44f3ae21
commit a749e70815
3 changed files with 63 additions and 122 deletions
@@ -3,19 +3,18 @@ import slugify from "@sindresorhus/slugify";
import ms from "ms"; import ms from "ms";
import { z } from "zod"; import { z } from "zod";
import { ProjectUserAdditionalPrivilegeSchema } from "@app/db/schemas"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
import { backfillPermissionV1SchemaToV2Schema } from "@app/ee/services/permission/project-permission";
import { ProjectUserAdditionalPrivilegeTemporaryMode } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types"; import { ProjectUserAdditionalPrivilegeTemporaryMode } from "@app/ee/services/project-user-additional-privilege/project-user-additional-privilege-types";
import { PROJECT_USER_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs"; import { PROJECT_USER_ADDITIONAL_PRIVILEGE } from "@app/lib/api-docs";
import { alphaNumericNanoId } from "@app/lib/nanoid"; import { alphaNumericNanoId } from "@app/lib/nanoid";
import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
import { ProjectSpecificPrivilegePermissionSchema } from "@app/server/routes/sanitizedSchemas"; import { SanitizedUserProjectAdditionalPrivilegeSchema } from "@app/server/routes/santizedSchemas/user-additional-privilege";
import { AuthMode } from "@app/services/auth/auth-type"; import { AuthMode } from "@app/services/auth/auth-type";
export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => { export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodProvider) => {
server.route({ server.route({
url: "/permanent", url: "/",
method: "POST", method: "POST",
config: { config: {
rateLimit: writeLimit rateLimit: writeLimit
@@ -34,80 +33,30 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
}) })
.optional() .optional()
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.slug), .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.slug),
permissions: ProjectSpecificPrivilegePermissionSchema.describe( permissions: ProjectPermissionV2Schema.array().describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.permissions),
PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.permissions type: z.discriminatedUnion("isTemporary", [
) z.object({
}), isTemporary: z.literal(false)
response: { }),
200: z.object({ z.object({
privilege: ProjectUserAdditionalPrivilegeSchema isTemporary: z.literal(true),
}) temporaryMode: z
} .nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
}, .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
onRequest: verifyAuth([AuthMode.JWT]), temporaryRange: z
handler: async (req) => { .string()
const privilege = await server.services.projectUserAdditionalPrivilege.create({ .refine((val) => ms(val) > 0, "Temporary range must be a positive number")
actorId: req.permission.id, .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryRange),
actor: req.permission.type, temporaryAccessStartTime: z
actorOrgId: req.permission.orgId, .string()
actorAuthMethod: req.permission.authMethod, .datetime()
...req.body, .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryAccessStartTime)
slug: req.body.slug ? slugify(req.body.slug) : slugify(alphaNumericNanoId(12)),
isTemporary: false,
permissions: JSON.stringify(
packRules(
backfillPermissionV1SchemaToV2Schema(
req.body.permissions.actions.map((action) => ({
action,
subject: req.body.permissions.subject,
conditions: req.body.permissions.conditions
}))
)
)
)
});
return { privilege };
}
});
server.route({
method: "POST",
url: "/temporary",
config: {
rateLimit: writeLimit
},
schema: {
body: z.object({
projectMembershipId: z.string().min(1).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.projectMembershipId),
slug: z
.string()
.min(1)
.max(60)
.trim()
.refine((v) => v.toLowerCase() === v, "Slug must be lowercase")
.refine((v) => slugify(v) === v, {
message: "Slug must be a valid slug"
}) })
.optional() ])
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.slug),
permissions: ProjectSpecificPrivilegePermissionSchema.describe(
PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.permissions
),
temporaryMode: z
.nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryMode),
temporaryRange: z
.string()
.refine((val) => ms(val) > 0, "Temporary range must be a positive number")
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryRange),
temporaryAccessStartTime: z
.string()
.datetime()
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.CREATE.temporaryAccessStartTime)
}), }),
response: { response: {
200: z.object({ 200: z.object({
privilege: ProjectUserAdditionalPrivilegeSchema privilege: SanitizedUserProjectAdditionalPrivilegeSchema
}) })
} }
}, },
@@ -118,20 +67,10 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
actor: req.permission.type, actor: req.permission.type,
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,
...req.body, projectMembershipId: req.body.projectMembershipId,
slug: req.body.slug ? slugify(req.body.slug) : `privilege-${slugify(alphaNumericNanoId(12))}`, ...req.body.type,
isTemporary: true, slug: req.body.slug || slugify(alphaNumericNanoId(8).toLowerCase()),
permissions: JSON.stringify( permissions: JSON.stringify(packRules(req.body.permissions))
packRules(
backfillPermissionV1SchemaToV2Schema(
req.body.permissions.actions.map((action) => ({
action,
subject: req.body.permissions.subject,
conditions: req.body.permissions.conditions
}))
)
)
)
}); });
return { privilege }; return { privilege };
} }
@@ -158,26 +97,31 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
message: "Slug must be a valid slug" message: "Slug must be a valid slug"
}) })
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.slug), .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.slug),
permissions: ProjectSpecificPrivilegePermissionSchema.describe( permissions: ProjectPermissionV2Schema.array()
PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.permissions .optional()
).optional(), .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.permissions),
isTemporary: z.boolean().describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary), type: z.discriminatedUnion("isTemporary", [
temporaryMode: z z.object({ isTemporary: z.literal(false).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary) }),
.nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode) z.object({
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode), isTemporary: z.literal(true).describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.isTemporary),
temporaryRange: z temporaryMode: z
.string() .nativeEnum(ProjectUserAdditionalPrivilegeTemporaryMode)
.refine((val) => ms(val) > 0, "Temporary range must be a positive number") .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryMode),
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryRange), temporaryRange: z
temporaryAccessStartTime: z .string()
.string() .refine((val) => typeof val === "undefined" || ms(val) > 0, "Temporary range must be a positive number")
.datetime() .describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryRange),
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryAccessStartTime) temporaryAccessStartTime: z
.string()
.datetime()
.describe(PROJECT_USER_ADDITIONAL_PRIVILEGE.UPDATE.temporaryAccessStartTime)
})
])
}) })
.partial(), .partial(),
response: { response: {
200: z.object({ 200: z.object({
privilege: ProjectUserAdditionalPrivilegeSchema privilege: SanitizedUserProjectAdditionalPrivilegeSchema
}) })
} }
}, },
@@ -189,18 +133,11 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
actorOrgId: req.permission.orgId, actorOrgId: req.permission.orgId,
actorAuthMethod: req.permission.authMethod, actorAuthMethod: req.permission.authMethod,
...req.body, ...req.body,
...req.body.type,
permissions: req.body.permissions permissions: req.body.permissions
? JSON.stringify( ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment
packRules( // @ts-ignore-error this is valid ts
backfillPermissionV1SchemaToV2Schema( JSON.stringify(packRules(req.body.permissions))
req.body.permissions.actions.map((action) => ({
action,
subject: req.body.permissions!.subject,
conditions: req.body.permissions!.conditions
}))
)
)
)
: undefined, : undefined,
privilegeId: req.params.privilegeId privilegeId: req.params.privilegeId
}); });
@@ -220,7 +157,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
}), }),
response: { response: {
200: z.object({ 200: z.object({
privilege: ProjectUserAdditionalPrivilegeSchema privilege: SanitizedUserProjectAdditionalPrivilegeSchema
}) })
} }
}, },
@@ -249,7 +186,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
}), }),
response: { response: {
200: z.object({ 200: z.object({
privileges: ProjectUserAdditionalPrivilegeSchema.array() privileges: SanitizedUserProjectAdditionalPrivilegeSchema.omit({ permissions: true }).array()
}) })
} }
}, },
@@ -278,7 +215,7 @@ export const registerUserAdditionalPrivilegeRouter = async (server: FastifyZodPr
}), }),
response: { response: {
200: z.object({ 200: z.object({
privilege: ProjectUserAdditionalPrivilegeSchema privilege: SanitizedUserProjectAdditionalPrivilegeSchema
}) })
} }
}, },
@@ -259,10 +259,7 @@ export const projectUserAdditionalPrivilegeServiceFactory = ({
userId: projectMembership.userId, userId: projectMembership.userId,
projectId: projectMembership.projectId projectId: projectMembership.projectId
}); });
return userPrivileges.map((el) => ({ return userPrivileges;
...el,
permissions: unpackPermissions(el.permissions)
}));
}; };
return { return {
@@ -0,0 +1,7 @@
import { ProjectUserAdditionalPrivilegeSchema } from "@app/db/schemas";
import { UnpackedPermissionSchema } from "./permission";
export const SanitizedUserProjectAdditionalPrivilegeSchema = ProjectUserAdditionalPrivilegeSchema.extend({
permissions: UnpackedPermissionSchema.array()
});