feat: fixing ts

This commit is contained in:
=
2025-10-10 00:09:45 +05:30
parent 0ddf98ec15
commit 5a8bad3556
38 changed files with 716 additions and 2437 deletions
+25 -1
View File
@@ -195,12 +195,36 @@ export const groupDALFactory = (db: TDbClient) => {
}
};
const findOne = async (filter: Partial<TGroups>, tx?: Knex): Promise<TGroups | undefined> => {
try {
const doc = await (tx || db.replicaNode())(TableName.Groups)
.join(TableName.Membership, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`)
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
.where((queryBuilder) => {
Object.entries(filter).forEach(([key, value]) => {
void queryBuilder.where(`${TableName.Membership}.${key}`, value);
});
})
.select(
selectAllTableCols(TableName.Groups),
db.ref("role").withSchema(TableName.MembershipRole),
db.ref("customRoleId").as("roleId").withSchema(TableName.MembershipRole)
)
.first();
return doc;
} catch (error) {
throw new DatabaseError({ error, name: "Find one" });
}
};
return {
...groupOrm,
findGroups,
findByOrgId,
findAllGroupPossibleMembers,
findGroupsByProjectId,
findById
findById,
findOne
};
};
+26 -19
View File
@@ -1,6 +1,6 @@
import { Knex } from "knex";
import { ProjectVersion, SecretKeyEncoding, TableName, TUsers } from "@app/db/schemas";
import { AccessScope, ProjectVersion, SecretKeyEncoding, TableName, TUsers } from "@app/db/schemas";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, ForbiddenRequestError, NotFoundError, ScimRequestError } from "@app/lib/errors";
@@ -16,7 +16,7 @@ const addAcceptedUsersToGroup = async ({
group,
userGroupMembershipDAL,
userDAL,
groupProjectDAL,
membershipGroupDAL,
projectKeyDAL,
projectDAL,
projectBotDAL,
@@ -42,13 +42,15 @@ const addAcceptedUsersToGroup = async ({
const projectIds = Array.from(
new Set(
(
await groupProjectDAL.find(
await membershipGroupDAL.find(
{
groupId: group.id
actorGroupId: group.id,
scopeOrgId: group.orgId,
scope: AccessScope.Project
},
{ tx }
)
).map((gp) => gp.projectId)
).map((gp) => gp.scopeProjectId as string)
)
);
@@ -167,11 +169,11 @@ export const addUsersToGroupByUserIds = async ({
userDAL,
userGroupMembershipDAL,
orgDAL,
groupProjectDAL,
projectKeyDAL,
projectDAL,
projectBotDAL,
tx: outerTx
tx: outerTx,
membershipGroupDAL
}: TAddUsersToGroupByUserIds) => {
const processAddition = async (tx: Knex) => {
const foundMembers = await userDAL.find(
@@ -214,15 +216,18 @@ export const addUsersToGroupByUserIds = async ({
// check if all user(s) are part of the organization
const existingUserOrgMemberships = await orgDAL.findMembership(
{
[`${TableName.OrgMembership}.orgId` as "orgId"]: group.orgId,
[`${TableName.Membership}.scopeOrgId` as "scopeOrgId"]: group.orgId,
scope: AccessScope.Organization,
$in: {
[`${TableName.OrgMembership}.userId` as "userId"]: userIds
[`${TableName.Membership}.actorUserId` as "actorUserId"]: userIds
}
},
{ tx }
);
const existingUserOrgMembershipsUserIdsSet = new Set(existingUserOrgMemberships.map((u) => u.userId));
const existingUserOrgMembershipsUserIdsSet = new Set(
existingUserOrgMemberships.map((u) => u.actorUserId as string)
);
userIds.forEach((userId) => {
if (!existingUserOrgMembershipsUserIdsSet.has(userId))
@@ -250,7 +255,7 @@ export const addUsersToGroupByUserIds = async ({
group,
userDAL,
userGroupMembershipDAL,
groupProjectDAL,
membershipGroupDAL,
projectKeyDAL,
projectDAL,
projectBotDAL,
@@ -292,9 +297,9 @@ export const removeUsersFromGroupByUserIds = async ({
userIds,
userDAL,
userGroupMembershipDAL,
groupProjectDAL,
projectKeyDAL,
tx: outerTx
tx: outerTx,
membershipGroupDAL
}: TRemoveUsersFromGroupByUserIds) => {
const processRemoval = async (tx: Knex) => {
const foundMembers = await userDAL.find({
@@ -352,13 +357,15 @@ export const removeUsersFromGroupByUserIds = async ({
const projectIds = Array.from(
new Set(
(
await groupProjectDAL.find(
await membershipGroupDAL.find(
{
groupId: group.id
scope: AccessScope.Project,
actorGroupId: group.id,
scopeOrgId: group.orgId
},
{ tx }
)
).map((gp) => gp.projectId)
).map((gp) => gp.scopeProjectId as string)
)
);
@@ -422,11 +429,11 @@ export const convertPendingGroupAdditionsToGroupMemberships = async ({
userIds,
userDAL,
userGroupMembershipDAL,
groupProjectDAL,
projectKeyDAL,
projectDAL,
projectBotDAL,
tx: outerTx
tx: outerTx,
membershipGroupDAL
}: TConvertPendingGroupAdditionsToGroupMemberships) => {
const processConversion = async (tx: Knex) => {
const users = await userDAL.find(
@@ -463,7 +470,7 @@ export const convertPendingGroupAdditionsToGroupMemberships = async ({
group: pendingGroupAddition.group,
userDAL,
userGroupMembershipDAL,
groupProjectDAL,
membershipGroupDAL,
projectKeyDAL,
projectDAL,
projectBotDAL,
+80 -46
View File
@@ -1,11 +1,12 @@
import { ForbiddenError } from "@casl/ability";
import slugify from "@sindresorhus/slugify";
import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas";
import { AccessScope, OrgMembershipRole, TRoles } from "@app/db/schemas";
import { TOidcConfigDALFactory } from "@app/ee/services/oidc/oidc-config-dal";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
import { TMembershipRoleDALFactory } from "@app/services/membership/membership-role-dal";
import { TMembershipGroupDALFactory } from "@app/services/membership-group/membership-group-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
@@ -35,8 +36,9 @@ type TGroupServiceFactoryDep = {
TGroupDALFactory,
"create" | "findOne" | "update" | "delete" | "findAllGroupPossibleMembers" | "findById" | "transaction"
>;
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
orgDAL: Pick<TOrgDALFactory, "findMembership" | "countAllOrgMembers">;
membershipGroupDAL: Pick<TMembershipGroupDALFactory, "find" | "findOne" | "create">;
membershipRoleDAL: Pick<TMembershipRoleDALFactory, "create" | "delete">;
orgDAL: Pick<TOrgDALFactory, "findMembership" | "countAllOrgMembers" | "findById">;
userGroupMembershipDAL: Pick<
TUserGroupMembershipDALFactory,
"findOne" | "delete" | "filterProjectsByUserMembership" | "transaction" | "insertMany" | "find"
@@ -54,7 +56,6 @@ export type TGroupServiceFactory = ReturnType<typeof groupServiceFactory>;
export const groupServiceFactory = ({
userDAL,
groupDAL,
groupProjectDAL,
orgDAL,
userGroupMembershipDAL,
projectDAL,
@@ -62,12 +63,14 @@ export const groupServiceFactory = ({
projectKeyDAL,
permissionService,
licenseService,
oidcConfigDAL
oidcConfigDAL,
membershipGroupDAL,
membershipRoleDAL
}: TGroupServiceFactoryDep) => {
const createGroup = async ({ name, slug, role, actor, actorId, actorAuthMethod, actorOrgId }: TCreateGroupDTO) => {
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
const { permission, membership } = await permissionService.getOrgPermission(
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
actorOrgId,
@@ -82,25 +85,23 @@ export const groupServiceFactory = ({
message: "Failed to create group due to plan restriction. Upgrade plan to create group."
});
const { permission: rolePermission, role: customRole } = await permissionService.getOrgPermissionByRole(
role,
actorOrgId
);
const isCustomRole = Boolean(customRole);
const [rolePermissionDetails] = await permissionService.getOrgPermissionByRoles([role], actorOrgId);
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
const isCustomRole = Boolean(rolePermissionDetails?.role);
if (role !== OrgMembershipRole.NoAccess) {
const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.GrantPrivileges,
OrgPermissionSubjects.Groups,
permission,
rolePermission
rolePermissionDetails.permission
);
if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({
message: constructPermissionErrorMessage(
"Failed to create group",
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.GrantPrivileges,
OrgPermissionSubjects.Groups
),
@@ -122,7 +123,25 @@ export const groupServiceFactory = ({
slug: slug || slugify(`${name}-${alphaNumericNanoId(4)}`),
orgId: actorOrgId,
role: isCustomRole ? OrgMembershipRole.Custom : role,
roleId: customRole?.id
roleId: rolePermissionDetails?.role?.id
},
tx
);
const membership = await membershipGroupDAL.create(
{
actorGroupId: newGroup.id,
scope: AccessScope.Organization,
scopeOrgId: actorOrgId
},
tx
);
await membershipRoleDAL.create(
{
membershipId: membership.id,
role: isCustomRole ? OrgMembershipRole.Custom : role,
customRoleId: rolePermissionDetails?.role?.id
},
tx
);
@@ -145,7 +164,7 @@ export const groupServiceFactory = ({
}: TUpdateGroupDTO) => {
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
const { permission, membership } = await permissionService.getOrgPermission(
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
actorOrgId,
@@ -166,32 +185,31 @@ export const groupServiceFactory = ({
throw new NotFoundError({ message: `Failed to find group with ID ${id}` });
}
let customRole: TOrgRoles | undefined;
let customRole: TRoles | undefined;
if (role) {
const { permission: rolePermission, role: customOrgRole } = await permissionService.getOrgPermissionByRole(
role,
group.orgId
);
const [rolePermissionDetails] = await permissionService.getOrgPermissionByRoles([role], group.orgId);
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
const isCustomRole = Boolean(rolePermissionDetails?.role);
const isCustomRole = Boolean(customOrgRole);
const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.GrantPrivileges,
OrgPermissionSubjects.Groups,
permission,
rolePermission
rolePermissionDetails.permission
);
if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({
message: constructPermissionErrorMessage(
"Failed to update group",
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.GrantPrivileges,
OrgPermissionSubjects.Groups
),
details: { missingPermissions: permissionBoundary.missingPermissions }
});
if (isCustomRole) customRole = customOrgRole;
if (isCustomRole) customRole = rolePermissionDetails?.role;
}
const updatedGroup = await groupDAL.transaction(async (tx) => {
@@ -211,17 +229,31 @@ export const groupServiceFactory = ({
},
{
name,
slug: slug ? slugify(slug) : undefined,
...(role
? {
role: customRole ? OrgMembershipRole.Custom : role,
roleId: customRole?.id ?? null
}
: {})
slug: slug ? slugify(slug) : undefined
},
tx
);
if (role) {
const membership = await membershipGroupDAL.findOne(
{
scope: AccessScope.Organization,
actorGroupId: updated.id,
scopeOrgId: updated.orgId
},
tx
);
await membershipRoleDAL.delete({ membershipId: membership.id }, tx);
await membershipRoleDAL.create(
{
membershipId: membership.id,
role: customRole ? OrgMembershipRole.Custom : role,
customRoleId: customRole?.id ?? null
},
tx
);
}
return updated;
});
@@ -341,7 +373,7 @@ export const groupServiceFactory = ({
const addUserToGroup = async ({ id, username, actor, actorId, actorAuthMethod, actorOrgId }: TAddUserToGroupDTO) => {
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
const { permission, membership } = await permissionService.getOrgPermission(
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
actorOrgId,
@@ -373,22 +405,23 @@ export const groupServiceFactory = ({
});
}
const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId);
const [rolePermissionDetails] = await permissionService.getOrgPermissionByRoles([group.role], actorOrgId);
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
// check if user has broader or equal to privileges than group
const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.AddMembers,
OrgPermissionSubjects.Groups,
permission,
groupRolePermission
rolePermissionDetails.permission
);
if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({
message: constructPermissionErrorMessage(
"Failed to add user to more privileged group",
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.AddMembers,
OrgPermissionSubjects.Groups
),
@@ -407,7 +440,7 @@ export const groupServiceFactory = ({
userDAL,
userGroupMembershipDAL,
orgDAL,
groupProjectDAL,
membershipGroupDAL,
projectKeyDAL,
projectDAL,
projectBotDAL
@@ -431,7 +464,7 @@ export const groupServiceFactory = ({
}: TRemoveUserFromGroupDTO) => {
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
const { permission, membership } = await permissionService.getOrgPermission(
const { permission } = await permissionService.getOrgPermission(
actor,
actorId,
actorOrgId,
@@ -463,21 +496,22 @@ export const groupServiceFactory = ({
});
}
const { permission: groupRolePermission } = await permissionService.getOrgPermissionByRole(group.role, actorOrgId);
const [rolePermissionDetails] = await permissionService.getOrgPermissionByRoles([group.role], actorOrgId);
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
// check if user has broader or equal to privileges than group
const permissionBoundary = validatePrivilegeChangeOperation(
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.RemoveMembers,
OrgPermissionSubjects.Groups,
permission,
groupRolePermission
rolePermissionDetails.permission
);
if (!permissionBoundary.isValid)
throw new PermissionBoundaryError({
message: constructPermissionErrorMessage(
"Failed to delete user from more privileged group",
membership.shouldUseNewPrivilegeSystem,
shouldUseNewPrivilegeSystem,
OrgPermissionGroupActions.RemoveMembers,
OrgPermissionSubjects.Groups
),
@@ -495,7 +529,7 @@ export const groupServiceFactory = ({
userIds: [user.id],
userDAL,
userGroupMembershipDAL,
groupProjectDAL,
membershipGroupDAL,
projectKeyDAL
});
+5 -5
View File
@@ -3,7 +3,7 @@ import { Knex } from "knex";
import { TGroups } from "@app/db/schemas";
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
import { TGenericPermission } from "@app/lib/types";
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
import { TMembershipGroupDALFactory } from "@app/services/membership-group/membership-group-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TProjectDALFactory } from "@app/services/project/project-dal";
import { TProjectBotDALFactory } from "@app/services/project-bot/project-bot-dal";
@@ -63,7 +63,7 @@ export type TAddUsersToGroup = {
group: TGroups;
userDAL: Pick<TUserDALFactory, "findUserEncKeyByUserIdsBatch">;
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
membershipGroupDAL: Pick<TMembershipGroupDALFactory, "find">;
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser" | "findById">;
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
@@ -76,7 +76,7 @@ export type TAddUsersToGroupByUserIds = {
userDAL: Pick<TUserDALFactory, "find" | "findUserEncKeyByUserIdsBatch" | "transaction">;
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
orgDAL: Pick<TOrgDALFactory, "findMembership">;
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
membershipGroupDAL: Pick<TMembershipGroupDALFactory, "find">;
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser" | "findById">;
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
@@ -88,7 +88,7 @@ export type TRemoveUsersFromGroupByUserIds = {
userIds: string[];
userDAL: Pick<TUserDALFactory, "find" | "transaction">;
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "filterProjectsByUserMembership" | "delete">;
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
membershipGroupDAL: Pick<TMembershipGroupDALFactory, "find">;
projectKeyDAL: Pick<TProjectKeyDALFactory, "delete">;
tx?: Knex;
};
@@ -100,7 +100,7 @@ export type TConvertPendingGroupAdditionsToGroupMemberships = {
TUserGroupMembershipDALFactory,
"find" | "transaction" | "insertMany" | "deletePendingUserGroupMembershipsByUserIds"
>;
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
membershipGroupDAL: Pick<TMembershipGroupDALFactory, "find">;
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser" | "findById">;
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;