feat: switched up all dal except policy ones

This commit is contained in:
=
2025-10-10 00:09:45 +05:30
parent 4d68d48d89
commit 0ddf98ec15
37 changed files with 1022 additions and 895 deletions
@@ -29,6 +29,10 @@ export const newNamespaceRoleFactory = (_dto: TNamespaceRoleScopeFactoryDep): TR
throw new BadRequestError({ message: "Invalid scope provided for the factory" });
};
const isCustomRole: TRoleScopeFactory["isCustomRole"] = () => false;
const getPredefinedRoles: TRoleScopeFactory["getPredefinedRoles"] = async () => [];
return {
onCreateRoleGuard,
onUpdateRoleGuard,
@@ -36,6 +40,8 @@ export const newNamespaceRoleFactory = (_dto: TNamespaceRoleScopeFactoryDep): TR
onListRoleGuard,
onGetRoleByIdGuard,
onGetRoleBySlugGuard,
getScopeField
getScopeField,
isCustomRole,
getPredefinedRoles
};
};
@@ -1,11 +1,18 @@
import { ForbiddenError } from "@casl/ability";
import { AccessScope } from "@app/db/schemas";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
import {
orgAdminPermissions,
orgMemberPermissions,
orgNoAccessPermissions,
OrgPermissionActions,
OrgPermissionSubjects
} from "@app/ee/services/permission/org-permission";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { BadRequestError } from "@app/lib/errors";
import { TRoleScopeFactory } from "../role-types";
import { isCustomOrgRole } from "@app/services/org/org-role-fns";
type TOrgRoleScopeFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
@@ -19,6 +26,8 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep
throw new BadRequestError({ message: "Invalid scope provided for the factory" });
};
const isCustomRole: TRoleScopeFactory["isCustomRole"] = (role: string) => isCustomOrgRole(role);
const onCreateRoleGuard: TRoleScopeFactory["onCreateRoleGuard"] = async (dto) => {
const { permission } = await permissionService.getOrgPermission(
dto.permission.type,
@@ -85,6 +94,42 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
};
const getPredefinedRoles: TRoleScopeFactory["getPredefinedRoles"] = async (scopeData) => {
const scopeField = getScopeField(scopeData);
return [
{
id: "b11b49a9-09a9-4443-916a-4246f9ff2c69", // dummy userid
name: "Admin",
slug: "admin",
orgId: scopeField.value,
description: "Complete administration access over the organization",
permissions: orgAdminPermissions,
createdAt: new Date(),
updatedAt: new Date()
},
{
id: "b11b49a9-09a9-4443-916a-4246f9ff2c70", // dummy user for zod validation in response
name: "Member",
slug: "member",
orgId: scopeField.value,
description: "Non-administrative role in an organization",
permissions: orgMemberPermissions,
createdAt: new Date(),
updatedAt: new Date()
},
{
id: "b10d49a9-09a9-4443-916a-4246f9ff2c72", // dummy user for zod validation in response
name: "No Access",
slug: "no-access",
orgId: scopeField.value,
description: "No access to any resources in the organization",
permissions: orgNoAccessPermissions,
createdAt: new Date(),
updatedAt: new Date()
}
];
};
return {
onCreateRoleGuard,
onUpdateRoleGuard,
@@ -92,6 +137,8 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep
onListRoleGuard,
onGetRoleByIdGuard,
onGetRoleBySlugGuard,
getScopeField
getScopeField,
getPredefinedRoles,
isCustomRole
};
};
@@ -1,17 +1,35 @@
import { v4 as uuidv4 } from "uuid";
import { ForbiddenError } from "@casl/ability";
import { AccessScope, ActionProjectType } from "@app/db/schemas";
import { AccessScope, ActionProjectType, ProjectMembershipRole, ProjectType } from "@app/db/schemas";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission";
import {
isCustomProjectRole,
ProjectPermissionActions,
ProjectPermissionSub
} from "@app/ee/services/permission/project-permission";
import { BadRequestError } from "@app/lib/errors";
import { TRoleScopeFactory } from "../role-types";
import {
cryptographicOperatorPermissions,
projectAdminPermissions,
projectMemberPermissions,
projectNoAccessPermissions,
projectViewerPermission,
sshHostBootstrapPermissions
} from "@app/ee/services/permission/default-roles";
import { TProjectDALFactory } from "@app/services/project/project-dal";
type TProjectRoleScopeFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
projectDAL: Pick<TProjectDALFactory, "findById">;
};
export const newProjectRoleFactory = ({ permissionService }: TProjectRoleScopeFactoryDep): TRoleScopeFactory => {
export const newProjectRoleFactory = ({
permissionService,
projectDAL
}: TProjectRoleScopeFactoryDep): TRoleScopeFactory => {
const getScopeField: TRoleScopeFactory["getScopeField"] = (dto) => {
if (dto.scope === AccessScope.Project) {
return { key: "projectId" as const, value: dto.projectId };
@@ -19,6 +37,8 @@ export const newProjectRoleFactory = ({ permissionService }: TProjectRoleScopeFa
throw new BadRequestError({ message: "Invalid scope provided for the factory" });
};
const isCustomRole: TRoleScopeFactory["isCustomRole"] = (role: string) => isCustomProjectRole(role);
const onCreateRoleGuard: TRoleScopeFactory["onCreateRoleGuard"] = async (dto) => {
const scope = getScopeField(dto.scopeData);
const { permission } = await permissionService.getProjectPermission({
@@ -97,6 +117,78 @@ export const newProjectRoleFactory = ({ permissionService }: TProjectRoleScopeFa
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
};
const getPredefinedRoles: TRoleScopeFactory["getPredefinedRoles"] = async (scopeData) => {
const scope = getScopeField(scopeData);
const project = await projectDAL.findById(scope.value);
if (!project) throw new BadRequestError({ message: "Project not found" });
const projectId = project.id;
return [
{
id: uuidv4(),
name: "Admin",
slug: ProjectMembershipRole.Admin,
permissions: projectAdminPermissions,
description: "Full administrative access over a project",
createdAt: new Date(),
updatedAt: new Date(),
projectId
},
{
id: uuidv4(),
name: "Developer",
slug: ProjectMembershipRole.Member,
permissions: projectMemberPermissions,
description: "Limited read/write role in a project",
createdAt: new Date(),
updatedAt: new Date(),
projectId
},
{
id: uuidv4(),
name: "SSH Host Bootstrapper",
slug: ProjectMembershipRole.SshHostBootstrapper,
permissions: sshHostBootstrapPermissions,
description: "Create and issue SSH Hosts in a project",
createdAt: new Date(),
updatedAt: new Date(),
projectId,
type: ProjectType.SSH
},
{
id: uuidv4(),
name: "Cryptographic Operator",
slug: ProjectMembershipRole.KmsCryptographicOperator,
permissions: cryptographicOperatorPermissions,
description: "Perform cryptographic operations, such as encryption and signing, in a project",
createdAt: new Date(),
updatedAt: new Date(),
projectId,
type: ProjectType.KMS
},
{
id: uuidv4(),
name: "Viewer",
slug: ProjectMembershipRole.Viewer,
permissions: projectViewerPermission,
description: "Only read role in a project",
createdAt: new Date(),
projectId,
updatedAt: new Date()
},
{
id: uuidv4(),
name: "No Access",
slug: ProjectMembershipRole.NoAccess,
permissions: projectNoAccessPermissions,
description: "No access to any resources in the project",
createdAt: new Date(),
projectId,
updatedAt: new Date()
}
].filter(({ type }) => (type ? type === project.type : true));
};
return {
onCreateRoleGuard,
onUpdateRoleGuard,
@@ -104,6 +196,8 @@ export const newProjectRoleFactory = ({ permissionService }: TProjectRoleScopeFa
onListRoleGuard,
onGetRoleByIdGuard,
onGetRoleBySlugGuard,
getScopeField
getScopeField,
getPredefinedRoles,
isCustomRole
};
};
+17 -3
View File
@@ -16,20 +16,23 @@ import {
TListRoleDTO,
TUpdateRoleDTO
} from "./role-types";
import { TProjectDALFactory } from "../project/project-dal";
type TRoleServiceFactoryDep = {
roleDAL: TRoleDALFactory;
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
projectDAL: Pick<TProjectDALFactory, "findById">;
};
export type TRoleServiceFactory = ReturnType<typeof roleServiceFactory>;
export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceFactoryDep) => {
export const roleServiceFactory = ({ roleDAL, permissionService, projectDAL }: TRoleServiceFactoryDep) => {
const orgRoleFactory = newOrgRoleFactory({
permissionService
});
const projectRoleFactory = newProjectRoleFactory({
permissionService
permissionService,
projectDAL
});
const namespaceRoleFactory = newNamespaceRoleFactory({
permissionService
@@ -130,6 +133,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
await factory.onListRoleGuard(dto);
const scope = factory.getScopeField(scopeData);
const predefinedRoles = await factory.getPredefinedRoles(scopeData);
const roles = await roleDAL.find(
{
[scope.key]: scope.value
@@ -137,7 +141,9 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
{ limit: dto.data.limit, offset: dto.data.offset, sort: [[`${TableName.Role}.slug` as "slug", "asc"]] }
);
return { roles: roles.map((el) => ({ ...el, permissions: unpackPermissions(el.permissions) })) };
return {
roles: [...predefinedRoles, ...roles.map((el) => ({ ...el, permissions: unpackPermissions(el.permissions) }))]
};
};
const getRoleById = async (dto: TGetRoleByIdDTO) => {
@@ -163,6 +169,14 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
await factory.onGetRoleBySlugGuard(dto);
const scope = factory.getScopeField(scopeData);
const isCustomRole = factory.isCustomRole(dto.selector.slug);
if (!isCustomRole) {
const predefinedRole = await factory.getPredefinedRoles(scopeData);
const selectedRole = predefinedRole.find((el) => el.slug === dto.selector.slug);
if (!selectedRole) throw new BadRequestError({ message: `Role with slug ${dto.selector.slug} not found` });
return selectedRole;
}
const role = await roleDAL.findOne({
slug: selector.slug,
[scope.key]: scope.value
+4 -1
View File
@@ -1,14 +1,17 @@
import { AccessScopeData } from "@app/db/schemas";
import { AccessScopeData, TRoles } from "@app/db/schemas";
import { OrgServiceActor } from "@app/lib/types";
import { MongoAbility, RawRuleOf } from "@casl/ability";
export interface TRoleScopeFactory {
onCreateRoleGuard: (arg: TCreateRoleDTO) => Promise<void>;
onUpdateRoleGuard: (arg: TUpdateRoleDTO) => Promise<void>;
onDeleteRoleGuard: (arg: TDeleteRoleDTO) => Promise<void>;
onListRoleGuard: (arg: TListRoleDTO) => Promise<void>;
getPredefinedRoles: (arg: AccessScopeData) => Promise<(TRoles & { permissions: RawRuleOf<MongoAbility>[] })[]>;
onGetRoleByIdGuard: (arg: TGetRoleByIdDTO) => Promise<void>;
onGetRoleBySlugGuard: (arg: TGetRoleBySlugDTO) => Promise<void>;
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
isCustomRole: (role: string) => boolean;
}
export type TCreateRoleDTO = {