feat: added root org identity link functionality

This commit is contained in:
=
2025-10-20 18:58:22 +05:30
parent 545ea4e27c
commit b7644c9294
26 changed files with 753 additions and 82 deletions
@@ -291,13 +291,37 @@ export const membershipUserDALFactory = (db: TDbClient) => {
}
};
// const listAvailableUsers = async (scopeData: AccessScopeData) => {
// try {
// const query = await db.replicaNode()(TableName.Membership).where(`${TableName.Membership}.scopeOrgId`);
// } catch (error) {
// throw new DatabaseError({ error, name: "ListAvailableUsers" });
// }
// };
// this right nwo only support sub organization
const listAvailableUsers = async (orgId: string, rootOrgId: string) => {
try {
const usersConnectedToOrg = db
.replicaNode()(TableName.Membership)
.whereNotNull(`${TableName.Membership}.actorUserId`)
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
.where(`${TableName.Membership}.scopeOrgId`, orgId)
.select("actorUserId");
return { ...orm, findUsers, getUserById };
const docs = await db
.replicaNode()(TableName.Membership)
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.Membership}.actorUserId`)
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
.where(`${TableName.Users}.isGhost`, false)
.whereNotNull(`${TableName.Membership}.actorUserId`)
.where(`${TableName.Membership}.scopeOrgId`, rootOrgId)
.whereNot(`${TableName.Membership}.actorUserId`, usersConnectedToOrg)
.select(
db.ref("id").withSchema(TableName.Users),
db.ref("email").withSchema(TableName.Users),
db.ref("username").withSchema(TableName.Users),
db.ref("firstName").withSchema(TableName.Users),
db.ref("lastName").withSchema(TableName.Users)
);
return docs;
} catch (error) {
throw new DatabaseError({ error, name: "ListAvailableUsers" });
}
};
return { ...orm, findUsers, getUserById, listAvailableUsers };
};
@@ -83,7 +83,8 @@ export const membershipUserServiceFactory = ({
orgDAL,
tokenService,
userDAL,
userGroupMembershipDAL
userGroupMembershipDAL,
membershipUserDAL
}),
[AccessScope.Namespace]: newNamespaceMembershipUserFactory({}),
[AccessScope.Project]: newProjectMembershipUserFactory({
@@ -471,11 +472,26 @@ export const membershipUserServiceFactory = ({
return membership;
};
// Should only be used for sub organization as of now
const listAvailableUsers = async (dto: TListMembershipUserDTO) => {
const { scopeData } = dto;
const factory = scopeFactory[scopeData.scope];
await factory.onListMembershipUserGuard(dto);
const organizationDetails = await orgDAL.findById(dto.scopeData.orgId);
if (!organizationDetails.rootOrgId) return { users: [] };
const users = await membershipUserDAL.listAvailableUsers(organizationDetails.id, organizationDetails.rootOrgId);
return { users };
};
return {
createMembership,
updateMembership,
deleteMembership,
listMemberships,
getMembershipByUserId
getMembershipByUserId,
listAvailableUsers
};
};
@@ -93,3 +93,8 @@ export type TGetMembershipUserByUserIdDTO = {
userId: string;
};
};
export type TListAvailableUsersDTO = {
permission: OrgServiceActor;
scopeData: AccessScopeData;
};
@@ -16,6 +16,7 @@ import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TUserDALFactory } from "@app/services/user/user-dal";
import { TMembershipUserScopeFactory } from "../membership-user-types";
import { TMembershipUserDALFactory } from "../membership-user-dal";
type TOrgMembershipUserScopeFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
@@ -25,6 +26,7 @@ type TOrgMembershipUserScopeFactoryDep = {
orgDAL: Pick<TOrgDALFactory, "findById">;
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "delete">;
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
membershipUserDAL: Pick<TMembershipUserDALFactory, "find">;
};
export const newOrgMembershipUserFactory = ({
@@ -33,7 +35,8 @@ export const newOrgMembershipUserFactory = ({
userDAL,
orgDAL,
smtpService,
licenseService
licenseService,
membershipUserDAL
}: TOrgMembershipUserScopeFactoryDep): TMembershipUserScopeFactory => {
const getScopeField: TMembershipUserScopeFactory["getScopeField"] = (dto) => {
if (dto.scope === AccessScope.Organization) {
@@ -51,7 +54,10 @@ export const newOrgMembershipUserFactory = ({
const isCustomRole: TMembershipUserScopeFactory["isCustomRole"] = (role: string) => isCustomOrgRole(role);
const onCreateMembershipUserGuard: TMembershipUserScopeFactory["onCreateMembershipUserGuard"] = async (dto) => {
const onCreateMembershipUserGuard: TMembershipUserScopeFactory["onCreateMembershipUserGuard"] = async (
dto,
newMembers
) => {
const { permission } = await permissionService.getOrgPermission({
actor: dto.permission.type,
actorId: dto.permission.id,
@@ -78,6 +84,19 @@ export const newOrgMembershipUserFactory = ({
message: "Failed to invite user due to org-level auth enforced for organization"
});
}
if (org.rootOrgId) {
const rootOrgMembership = await membershipUserDAL.find({
scope: AccessScope.Organization,
$in: {
actorUserId: newMembers.map((el) => el.id)
},
scopeOrgId: org.rootOrgId
});
if (rootOrgMembership.length !== newMembers.length)
throw new BadRequestError({
message: "User doesn't have membership in root organization"
});
}
};
const onCreateMembershipComplete: TMembershipUserScopeFactory["onCreateMembershipComplete"] = async (