mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-03 21:26:04 +00:00
feat: switched up all dal except policy ones
This commit is contained in:
@@ -36,7 +36,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.uuid("scopeNamespaceId");
|
t.uuid("scopeNamespaceId");
|
||||||
t.foreign("scopeNamespaceId").references("id").inTable(TableName.Namespace).onDelete("CASCADE");
|
t.foreign("scopeNamespaceId").references("id").inTable(TableName.Namespace).onDelete("CASCADE");
|
||||||
|
|
||||||
t.boolean("isActive");
|
t.boolean("isActive").defaultTo(true).notNullable();
|
||||||
t.string("status").defaultTo("invited");
|
t.string("status").defaultTo("invited");
|
||||||
t.string("inviteEmail");
|
t.string("inviteEmail");
|
||||||
t.datetime("lastInvitedAt");
|
t.datetime("lastInvitedAt");
|
||||||
|
|||||||
@@ -261,7 +261,16 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
memberships: OrgMembershipsSchema.array(),
|
memberships: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
roles: z
|
||||||
|
.object({
|
||||||
|
role: z.string()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
.array(),
|
||||||
permissions: z.any().array()
|
permissions: z.any().array()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -274,7 +283,16 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
req.permission.authMethod,
|
req.permission.authMethod,
|
||||||
req.permission.orgId
|
req.permission.orgId
|
||||||
);
|
);
|
||||||
return { permissions, memberships };
|
return {
|
||||||
|
permissions,
|
||||||
|
memberships: memberships.map((el) => ({
|
||||||
|
...el,
|
||||||
|
role: el.roles[0].customRoleSlug || el.roles[0].role,
|
||||||
|
orgId: el.scopeOrgId,
|
||||||
|
status: el.status || "",
|
||||||
|
isActive: el.isActive || true
|
||||||
|
}))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { ProjectMembershipRole, ProjectRolesSchema, AccessScope } from "@app/db/schemas";
|
import { AccessScope, ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns";
|
||||||
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
|
|||||||
@@ -238,17 +238,17 @@ export interface TAccessApprovalRequestDALFactory extends Omit<TOrmify<TableName
|
|||||||
export const accessApprovalRequestDALFactory = (db: TDbClient): TAccessApprovalRequestDALFactory => {
|
export const accessApprovalRequestDALFactory = (db: TDbClient): TAccessApprovalRequestDALFactory => {
|
||||||
const accessApprovalRequestOrm = ormify(db, TableName.AccessApprovalRequest);
|
const accessApprovalRequestOrm = ormify(db, TableName.AccessApprovalRequest);
|
||||||
|
|
||||||
|
// TODO(simp): check this from begginging
|
||||||
const findRequestsWithPrivilegeByPolicyIds: TAccessApprovalRequestDALFactory["findRequestsWithPrivilegeByPolicyIds"] =
|
const findRequestsWithPrivilegeByPolicyIds: TAccessApprovalRequestDALFactory["findRequestsWithPrivilegeByPolicyIds"] =
|
||||||
async (policyIds) => {
|
async (policyIds) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.AccessApprovalRequest)
|
.replicaNode()(TableName.AccessApprovalRequest)
|
||||||
.whereIn(`${TableName.AccessApprovalRequest}.policyId`, policyIds)
|
.whereIn(`${TableName.AccessApprovalRequest}.policyId`, policyIds)
|
||||||
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.ProjectUserAdditionalPrivilege,
|
TableName.AdditionalPrivilege,
|
||||||
`${TableName.AccessApprovalRequest}.privilegeId`,
|
`${TableName.AccessApprovalRequest}.privilegeId`,
|
||||||
`${TableName.ProjectUserAdditionalPrivilege}.id`
|
`${TableName.AdditionalPrivilege}.id`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.AccessApprovalPolicy,
|
TableName.AccessApprovalPolicy,
|
||||||
@@ -276,7 +276,6 @@ export const accessApprovalRequestDALFactory = (db: TDbClient): TAccessApprovalR
|
|||||||
`${TableName.UserGroupMembership}.groupId`
|
`${TableName.UserGroupMembership}.groupId`
|
||||||
)
|
)
|
||||||
.leftJoin(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.leftJoin(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.AccessApprovalPolicyBypasser,
|
TableName.AccessApprovalPolicyBypasser,
|
||||||
`${TableName.AccessApprovalPolicy}.id`,
|
`${TableName.AccessApprovalPolicy}.id`,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TGroups } from "@app/db/schemas";
|
import { AccessScope, TableName, TGroups } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { buildFindFilter, ormify, selectAllTableCols, TFindFilter, TFindOpt } from "@app/lib/knex";
|
import { buildFindFilter, ormify, selectAllTableCols, TFindFilter, TFindOpt } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -81,9 +81,11 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
}) => {
|
}) => {
|
||||||
try {
|
try {
|
||||||
const query = db
|
const query = db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.leftJoin(TableName.UserGroupMembership, (bd) => {
|
.leftJoin(TableName.UserGroupMembership, (bd) => {
|
||||||
bd.on(`${TableName.UserGroupMembership}.userId`, "=", `${TableName.Users}.id`).andOn(
|
bd.on(`${TableName.UserGroupMembership}.userId`, "=", `${TableName.Users}.id`).andOn(
|
||||||
`${TableName.UserGroupMembership}.groupId`,
|
`${TableName.UserGroupMembership}.groupId`,
|
||||||
@@ -92,7 +94,7 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.OrgMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
||||||
db.ref("createdAt").withSchema(TableName.UserGroupMembership).as("joinedGroupAt"),
|
db.ref("createdAt").withSchema(TableName.UserGroupMembership).as("joinedGroupAt"),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
@@ -160,8 +162,10 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
const findGroupsByProjectId = async (projectId: string, tx?: Knex) => {
|
const findGroupsByProjectId = async (projectId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await (tx || db.replicaNode())(TableName.Groups)
|
const docs = await (tx || db.replicaNode())(TableName.Groups)
|
||||||
.join(TableName.GroupProjectMembership, `${TableName.Groups}.id`, `${TableName.GroupProjectMembership}.groupId`)
|
.join(TableName.Membership, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`)
|
||||||
.where(`${TableName.GroupProjectMembership}.projectId`, projectId)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorGroupId`)
|
||||||
.select(selectAllTableCols(TableName.Groups));
|
.select(selectAllTableCols(TableName.Groups));
|
||||||
return docs;
|
return docs;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -172,11 +176,16 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
const findById = async (id: string, tx?: Knex) => {
|
const findById = async (id: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const doc = await (tx || db.replicaNode())(TableName.Groups)
|
const doc = await (tx || db.replicaNode())(TableName.Groups)
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.Groups}.roleId`, `${TableName.OrgRoles}.id`)
|
.join(TableName.Membership, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.where(`${TableName.Groups}.id`, id)
|
.where(`${TableName.Groups}.id`, id)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.Groups),
|
selectAllTableCols(TableName.Groups),
|
||||||
db.ref("slug").as("customRoleSlug").withSchema(TableName.OrgRoles)
|
db.ref("slug").as("customRoleSlug").withSchema(TableName.Role),
|
||||||
|
db.ref("customRoleId").as("roleId").withSchema(TableName.MembershipRole),
|
||||||
|
db.ref("role").withSchema(TableName.MembershipRole)
|
||||||
)
|
)
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TUserEncryptionKeys } from "@app/db/schemas";
|
import { AccessScope, TableName, TUserEncryptionKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify } from "@app/lib/knex";
|
import { ormify } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -18,21 +18,19 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
|
|||||||
*/
|
*/
|
||||||
const filterProjectsByUserMembership = async (userId: string, groupId: string, projectIds: string[], tx?: Knex) => {
|
const filterProjectsByUserMembership = async (userId: string, groupId: string, projectIds: string[], tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const userProjectMemberships: string[] = await (tx || db.replicaNode())(TableName.ProjectMembership)
|
const userProjectMemberships: string[] = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.ProjectMembership}.userId`, userId)
|
.where(`${TableName.Membership}.actorUserId`, userId)
|
||||||
.whereIn(`${TableName.ProjectMembership}.projectId`, projectIds)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.pluck(`${TableName.ProjectMembership}.projectId`);
|
.whereIn(`${TableName.Membership}.scopeProjectId`, projectIds)
|
||||||
|
.pluck(`${TableName.Membership}.scopeProjectId`);
|
||||||
|
|
||||||
const userGroupMemberships: string[] = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
const userGroupMemberships: string[] = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
||||||
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
||||||
.whereNot(`${TableName.UserGroupMembership}.groupId`, groupId)
|
.whereNot(`${TableName.UserGroupMembership}.groupId`, groupId)
|
||||||
.join(
|
.join(TableName.Membership, `${TableName.UserGroupMembership}.groupId`, `${TableName.Membership}.actorGroupId`)
|
||||||
TableName.GroupProjectMembership,
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
`${TableName.UserGroupMembership}.groupId`,
|
.whereIn(`${TableName.Membership}.scopeProjectId`, projectIds)
|
||||||
`${TableName.GroupProjectMembership}.groupId`
|
.pluck(`${TableName.Membership}.scopeProjectId`);
|
||||||
)
|
|
||||||
.whereIn(`${TableName.GroupProjectMembership}.projectId`, projectIds)
|
|
||||||
.pluck(`${TableName.GroupProjectMembership}.projectId`);
|
|
||||||
|
|
||||||
return new Set(userProjectMemberships.concat(userGroupMemberships));
|
return new Set(userProjectMemberships.concat(userGroupMemberships));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -44,13 +42,10 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const findUserGroupMembershipsInProject = async (usernames: string[], projectId: string, tx?: Knex) => {
|
const findUserGroupMembershipsInProject = async (usernames: string[], projectId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const usernameDocs: string[] = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
const usernameDocs: string[] = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
||||||
.join(
|
.join(TableName.Membership, `${TableName.UserGroupMembership}.groupId`, `${TableName.Membership}.actorGroupId`)
|
||||||
TableName.GroupProjectMembership,
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
`${TableName.UserGroupMembership}.groupId`,
|
|
||||||
`${TableName.GroupProjectMembership}.groupId`
|
|
||||||
)
|
|
||||||
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.GroupProjectMembership}.projectId`, projectId)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
.whereIn(`${TableName.Users}.username`, usernames)
|
.whereIn(`${TableName.Users}.username`, usernames)
|
||||||
.pluck(`${TableName.Users}.id`);
|
.pluck(`${TableName.Users}.id`);
|
||||||
|
|
||||||
@@ -73,24 +68,25 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
// get list of groups in the project with id [projectId]
|
// get list of groups in the project with id [projectId]
|
||||||
// that that are not the group with id [groupId]
|
// that that are not the group with id [groupId]
|
||||||
const groups: string[] = await (tx || db.replicaNode())(TableName.GroupProjectMembership)
|
const groups: string[] = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.GroupProjectMembership}.projectId`, projectId)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
.whereNot(`${TableName.GroupProjectMembership}.groupId`, groupId)
|
.whereNot(`${TableName.Membership}.actorGroupId`, groupId)
|
||||||
.pluck(`${TableName.GroupProjectMembership}.groupId`);
|
.pluck(`${TableName.Membership}.groupId`);
|
||||||
|
|
||||||
// main query
|
// main query
|
||||||
const members = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
const members = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
||||||
.where(`${TableName.UserGroupMembership}.groupId`, groupId)
|
.where(`${TableName.UserGroupMembership}.groupId`, groupId)
|
||||||
.where(`${TableName.UserGroupMembership}.isPending`, false)
|
.where(`${TableName.UserGroupMembership}.isPending`, false)
|
||||||
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
.leftJoin(TableName.ProjectMembership, (bd) => {
|
.leftJoin(TableName.Membership, (bd) => {
|
||||||
bd.on(`${TableName.Users}.id`, "=", `${TableName.ProjectMembership}.userId`).andOn(
|
bd.on(`${TableName.Users}.id`, "=", `${TableName.Membership}.actorUserId`).andOn(
|
||||||
`${TableName.ProjectMembership}.projectId`,
|
`${TableName.Membership}.scopeProjectId`,
|
||||||
"=",
|
"=",
|
||||||
db.raw("?", [projectId])
|
db.raw("?", [projectId])
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.whereNull(`${TableName.ProjectMembership}.userId`)
|
.whereNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.leftJoin<TUserEncryptionKeys>(
|
.leftJoin<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
@@ -166,15 +162,17 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.UserGroupMembership)
|
.replicaNode()(TableName.UserGroupMembership)
|
||||||
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
||||||
.join(TableName.OrgMembership, `${TableName.UserGroupMembership}.userId`, `${TableName.OrgMembership}.userId`)
|
.join(TableName.Membership, `${TableName.UserGroupMembership}.userId`, `${TableName.Membership}.actorUserId`)
|
||||||
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.where(`${TableName.Groups}.orgId`, orgId)
|
.where(`${TableName.Groups}.orgId`, orgId)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.UserGroupMembership),
|
db.ref("id").withSchema(TableName.UserGroupMembership),
|
||||||
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
||||||
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
||||||
db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"),
|
db.ref("id").withSchema(TableName.Membership).as("orgMembershipId"),
|
||||||
db.ref("firstName").withSchema(TableName.Users).as("firstName"),
|
db.ref("firstName").withSchema(TableName.Users).as("firstName"),
|
||||||
db.ref("lastName").withSchema(TableName.Users).as("lastName"),
|
db.ref("lastName").withSchema(TableName.Users).as("lastName"),
|
||||||
db.ref("slug").withSchema(TableName.Groups).as("groupSlug")
|
db.ref("slug").withSchema(TableName.Groups).as("groupSlug")
|
||||||
@@ -191,15 +189,17 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.UserGroupMembership)
|
.replicaNode()(TableName.UserGroupMembership)
|
||||||
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
||||||
.join(TableName.OrgMembership, `${TableName.UserGroupMembership}.userId`, `${TableName.OrgMembership}.userId`)
|
.join(TableName.Membership, `${TableName.UserGroupMembership}.userId`, `${TableName.Membership}.actorGroupId`)
|
||||||
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.Groups}.id`, groupId)
|
.where(`${TableName.Groups}.id`, groupId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.where(`${TableName.Groups}.orgId`, orgId)
|
.where(`${TableName.Groups}.orgId`, orgId)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.UserGroupMembership),
|
db.ref("id").withSchema(TableName.UserGroupMembership),
|
||||||
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
||||||
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
db.ref("name").withSchema(TableName.Groups).as("groupName"),
|
||||||
db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"),
|
db.ref("id").withSchema(TableName.Membership).as("orgMembershipId"),
|
||||||
db.ref("firstName").withSchema(TableName.Users).as("firstName"),
|
db.ref("firstName").withSchema(TableName.Users).as("firstName"),
|
||||||
db.ref("lastName").withSchema(TableName.Users).as("lastName")
|
db.ref("lastName").withSchema(TableName.Users).as("lastName")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { OrgMembershipStatus, TableName } from "@app/db/schemas";
|
import { AccessScope, OrgMembershipStatus, TableName } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
|
|
||||||
export type TLicenseDALFactory = ReturnType<typeof licenseDALFactory>;
|
export type TLicenseDALFactory = ReturnType<typeof licenseDALFactory>;
|
||||||
@@ -9,14 +9,14 @@ export type TLicenseDALFactory = ReturnType<typeof licenseDALFactory>;
|
|||||||
export const licenseDALFactory = (db: TDbClient) => {
|
export const licenseDALFactory = (db: TDbClient) => {
|
||||||
const countOfOrgMembers = async (orgId: string | null, tx?: Knex) => {
|
const countOfOrgMembers = async (orgId: string | null, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const doc = await (tx || db.replicaNode())(TableName.OrgMembership)
|
const doc = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where({ status: OrgMembershipStatus.Accepted })
|
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
||||||
.andWhere((bd) => {
|
.andWhere((bd) => {
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
void bd.where({ orgId });
|
void bd.where(`${TableName.Membership}.scopeOrgId`, orgId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.Users}.isGhost`, false)
|
.where(`${TableName.Users}.isGhost`, false)
|
||||||
.count();
|
.count();
|
||||||
return Number(doc?.[0]?.count ?? 0);
|
return Number(doc?.[0]?.count ?? 0);
|
||||||
@@ -28,24 +28,27 @@ export const licenseDALFactory = (db: TDbClient) => {
|
|||||||
const countOrgUsersAndIdentities = async (orgId: string | null, tx?: Knex) => {
|
const countOrgUsersAndIdentities = async (orgId: string | null, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
// count org users
|
// count org users
|
||||||
const userDoc = await (tx || db.replicaNode())(TableName.OrgMembership)
|
const userDoc = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where({ status: OrgMembershipStatus.Accepted })
|
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.andWhere((bd) => {
|
.andWhere((bd) => {
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
void bd.where({ orgId });
|
void bd.where(`${TableName.Membership}.scopeOrgId`, orgId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.Membership}.userId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.Users}.isGhost`, false)
|
.where(`${TableName.Users}.isGhost`, false)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
const userCount = Number(userDoc?.[0].count);
|
const userCount = Number(userDoc?.[0].count);
|
||||||
|
|
||||||
// count org identities
|
// count org identities
|
||||||
const identityDoc = await (tx || db.replicaNode())(TableName.IdentityOrgMembership)
|
const identityDoc = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
|
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.where((bd) => {
|
.where((bd) => {
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
void bd.where({ orgId });
|
void bd.where(`${TableName.Membership}.scopeOrgId`, orgId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
|
|||||||
-10
@@ -1,10 +0,0 @@
|
|||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { ormify, TOrmify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TProjectUserAdditionalPrivilegeDALFactory = TOrmify<TableName.ProjectUserAdditionalPrivilege>;
|
|
||||||
|
|
||||||
export const projectUserAdditionalPrivilegeDALFactory = (db: TDbClient): TProjectUserAdditionalPrivilegeDALFactory => {
|
|
||||||
const orm = ormify(db, TableName.ProjectUserAdditionalPrivilege);
|
|
||||||
return orm;
|
|
||||||
};
|
|
||||||
@@ -252,7 +252,6 @@ import { offlineUsageReportServiceFactory } from "@app/services/offline-usage-re
|
|||||||
import { incidentContactDALFactory } from "@app/services/org/incident-contacts-dal";
|
import { incidentContactDALFactory } from "@app/services/org/incident-contacts-dal";
|
||||||
import { orgBotDALFactory } from "@app/services/org/org-bot-dal";
|
import { orgBotDALFactory } from "@app/services/org/org-bot-dal";
|
||||||
import { orgDALFactory } from "@app/services/org/org-dal";
|
import { orgDALFactory } from "@app/services/org/org-dal";
|
||||||
import { orgRoleDALFactory } from "@app/services/org/org-role-dal";
|
|
||||||
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
import { orgRoleServiceFactory } from "@app/services/org/org-role-service";
|
||||||
import { orgServiceFactory } from "@app/services/org/org-service";
|
import { orgServiceFactory } from "@app/services/org/org-service";
|
||||||
import { orgAdminServiceFactory } from "@app/services/org-admin/org-admin-service";
|
import { orgAdminServiceFactory } from "@app/services/org-admin/org-admin-service";
|
||||||
@@ -394,7 +393,6 @@ export const registerRoutes = async (
|
|||||||
const orgMembershipDAL = orgMembershipDALFactory(db);
|
const orgMembershipDAL = orgMembershipDALFactory(db);
|
||||||
const orgBotDAL = orgBotDALFactory(db);
|
const orgBotDAL = orgBotDALFactory(db);
|
||||||
const incidentContactDAL = incidentContactDALFactory(db);
|
const incidentContactDAL = incidentContactDALFactory(db);
|
||||||
const orgRoleDAL = orgRoleDALFactory(db);
|
|
||||||
const rateLimitDAL = rateLimitDALFactory(db);
|
const rateLimitDAL = rateLimitDALFactory(db);
|
||||||
const apiKeyDAL = apiKeyDALFactory(db);
|
const apiKeyDAL = apiKeyDALFactory(db);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
OrgMembershipsSchema,
|
OrgMembershipsSchema,
|
||||||
ProjectMembershipsSchema,
|
ProjectMembershipsSchema,
|
||||||
ProjectUserMembershipRolesSchema,
|
ProjectUserMembershipRolesSchema,
|
||||||
@@ -66,14 +67,23 @@ export const registerDeprecatedProjectMembershipRouter = async (server: FastifyZ
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const memberships = await server.services.projectMembership.getProjectMemberships({
|
const { data: memberships } = await server.services.membershipUser.listMemberships({
|
||||||
actorId: req.permission.id,
|
permission: req.permission,
|
||||||
actor: req.permission.type,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
projectId: req.params.workspaceId
|
projectId: req.params.workspaceId
|
||||||
|
},
|
||||||
|
data: {}
|
||||||
});
|
});
|
||||||
return { memberships };
|
|
||||||
|
return {
|
||||||
|
memberships: memberships.map((el) => ({
|
||||||
|
...el,
|
||||||
|
userId: el.actorUserId as string,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
}))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -124,15 +134,30 @@ export const registerDeprecatedProjectMembershipRouter = async (server: FastifyZ
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const membership = await server.services.projectMembership.getProjectMembershipById({
|
const { userId } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.params.membershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
projectId: req.params.workspaceId,
|
const membership = await server.services.membershipUser.getMembershipByUserId({
|
||||||
id: req.params.membershipId
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.params.workspaceId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
userId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { membership };
|
|
||||||
|
return {
|
||||||
|
membership: {
|
||||||
|
...membership,
|
||||||
|
userId,
|
||||||
|
projectId: req.params.workspacId
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -241,8 +266,8 @@ export const registerDeprecatedProjectMembershipRouter = async (server: FastifyZ
|
|||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.ADD_BATCH_PROJECT_MEMBER,
|
type: EventType.ADD_BATCH_PROJECT_MEMBER,
|
||||||
metadata: data.map(({ userId }) => ({
|
metadata: data.map(({ actorUserId }) => ({
|
||||||
userId: userId || "",
|
userId: actorUserId || "",
|
||||||
email: ""
|
email: ""
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
@@ -300,30 +325,28 @@ export const registerDeprecatedProjectMembershipRouter = async (server: FastifyZ
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
onRequest: verifyAuth([AuthMode.JWT, AuthMode.API_KEY, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.projectMembership.updateProjectMembership({
|
const { userId } = await server.services.convertor.userMembershipIdToUserId(
|
||||||
actorId: req.permission.id,
|
req.params.membershipId,
|
||||||
actor: req.permission.type,
|
AccessScope.Project,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
req.permission.orgId
|
||||||
actorOrgId: req.permission.orgId,
|
);
|
||||||
projectId: req.params.workspaceId,
|
|
||||||
membershipId: req.params.membershipId,
|
const { membership } = await server.services.membershipUser.updateMembership({
|
||||||
roles: req.body.roles
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
projectId: req.params.projectId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
roles: req.body.roles
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// await server.services.auditLog.createAuditLog({
|
return { roles: membership.roles.map((el) => ({ ...el, projectMembershipId: req.params.membershipId })) };
|
||||||
// ...req.auditLogInfo,
|
|
||||||
// projectId: req.params.workspaceId,
|
|
||||||
// event: {
|
|
||||||
// type: EventType.UPDATE_USER_WORKSPACE_ROLE,
|
|
||||||
// metadata: {
|
|
||||||
// userId: membership.userId,
|
|
||||||
// newRole: req.body.role,
|
|
||||||
// oldRole: membership.role,
|
|
||||||
// email: ""
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
return { roles };
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
IdentitiesSchema,
|
IdentitiesSchema,
|
||||||
IdentityProjectMembershipsSchema,
|
IdentityProjectMembershipsSchema,
|
||||||
ProjectMembershipRole,
|
ProjectMembershipRole,
|
||||||
ProjectUserMembershipRolesSchema
|
ProjectUserMembershipRolesSchema,
|
||||||
|
TemporaryPermissionMode
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { ApiDocsTags, ORGANIZATIONS, PROJECT_IDENTITIES } from "@app/lib/api-docs";
|
import { ApiDocsTags, ORGANIZATIONS, PROJECT_IDENTITIES } from "@app/lib/api-docs";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
@@ -14,7 +16,6 @@ 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 { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
import { ProjectIdentityOrderBy } from "@app/services/identity-project/identity-project-types";
|
import { ProjectIdentityOrderBy } from "@app/services/identity-project/identity-project-types";
|
||||||
import { ProjectUserMembershipTemporaryMode } from "@app/services/project-membership/project-membership-types";
|
|
||||||
|
|
||||||
import { SanitizedProjectSchema } from "../sanitizedSchemas";
|
import { SanitizedProjectSchema } from "../sanitizedSchemas";
|
||||||
|
|
||||||
@@ -56,7 +57,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
|||||||
role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(ProjectUserMembershipTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -82,16 +83,22 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
|||||||
const { role, roles } = req.body;
|
const { role, roles } = req.body;
|
||||||
if (!role && !roles) throw new BadRequestError({ message: "You must provide either role or roles field" });
|
if (!role && !roles) throw new BadRequestError({ message: "You must provide either role or roles field" });
|
||||||
|
|
||||||
const identityMembership = await server.services.identityProject.createProjectIdentity({
|
const { membership } = await server.services.membershipIdentity.createMembership({
|
||||||
actor: req.permission.type,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
identityId: req.params.identityId,
|
projectId: req.params.projectId
|
||||||
projectId: req.params.projectId,
|
},
|
||||||
roles: roles || [{ role }]
|
data: {
|
||||||
|
identityId: req.params.identityId,
|
||||||
|
roles: roles || [{ role, isTemporary: false }]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { identityMembership };
|
|
||||||
|
return {
|
||||||
|
identityMembership: { ...membership, identityId: req.params.identityId, projectId: req.params.projectId }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -130,7 +137,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
|||||||
role: z.string().describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.role),
|
role: z.string().describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.isTemporary),
|
isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.isTemporary),
|
||||||
temporaryMode: z
|
temporaryMode: z
|
||||||
.nativeEnum(ProjectUserMembershipTemporaryMode)
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
.describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.temporaryMode),
|
.describe(PROJECT_IDENTITIES.UPDATE_IDENTITY_MEMBERSHIP.roles.temporaryMode),
|
||||||
temporaryRange: z
|
temporaryRange: z
|
||||||
.string()
|
.string()
|
||||||
@@ -153,16 +160,24 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const roles = await server.services.identityProject.updateProjectIdentity({
|
const { membership } = await server.services.membershipIdentity.updateMembership({
|
||||||
actor: req.permission.type,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
identityId: req.params.identityId,
|
projectId: req.params.projectId
|
||||||
projectId: req.params.projectId,
|
},
|
||||||
roles: req.body.roles
|
selector: {
|
||||||
|
identityId: req.params.identityId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
roles: req.body.roles
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { roles };
|
|
||||||
|
return {
|
||||||
|
roles: membership.roles.map((el) => ({ ...el, projectMembershipId: membership.id }))
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -193,15 +208,21 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const identityMembership = await server.services.identityProject.deleteProjectIdentity({
|
const { membership } = await server.services.membershipIdentity.deleteMembership({
|
||||||
actor: req.permission.type,
|
permission: req.permission,
|
||||||
actorId: req.permission.id,
|
scopeData: {
|
||||||
actorAuthMethod: req.permission.authMethod,
|
scope: AccessScope.Project,
|
||||||
actorOrgId: req.permission.orgId,
|
orgId: req.permission.orgId,
|
||||||
identityId: req.params.identityId,
|
projectId: req.params.projectId
|
||||||
projectId: req.params.projectId
|
},
|
||||||
|
selector: {
|
||||||
|
identityId: req.params.identityId
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return { identityMembership };
|
|
||||||
|
return {
|
||||||
|
identityMembership: { ...membership, identityId: req.params.identityId, projectId: req.params.projectId }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -362,6 +383,7 @@ export const registerIdentityProjectRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO(simp): look into how to handle projects
|
||||||
server.route({
|
server.route({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: "/identity-memberships/:identityMembershipId",
|
url: "/identity-memberships/:identityMembershipId",
|
||||||
|
|||||||
@@ -1,53 +1,45 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TUserEncryptionKeys } from "@app/db/schemas";
|
import { AccessScope, TableName, TMemberships, TUserEncryptionKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, sqlNestRelationships } from "@app/lib/knex";
|
import { sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TGroupProjectDALFactory = ReturnType<typeof groupProjectDALFactory>;
|
export type TGroupProjectDALFactory = ReturnType<typeof groupProjectDALFactory>;
|
||||||
|
|
||||||
export const groupProjectDALFactory = (db: TDbClient) => {
|
export const groupProjectDALFactory = (db: TDbClient) => {
|
||||||
const groupProjectOrm = ormify(db, TableName.GroupProjectMembership);
|
|
||||||
|
|
||||||
const findByProjectId = async (projectId: string, filter?: { groupId?: string }, tx?: Knex) => {
|
const findByProjectId = async (projectId: string, filter?: { groupId?: string }, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await (tx || db.replicaNode())(TableName.GroupProjectMembership)
|
const docs = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.GroupProjectMembership}.projectId`, projectId)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorGroupId`)
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
if (filter?.groupId) {
|
if (filter?.groupId) {
|
||||||
void qb.where(`${TableName.Groups}.id`, "=", filter.groupId);
|
void qb.where(`${TableName.Groups}.id`, "=", filter.groupId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(TableName.Groups, `${TableName.GroupProjectMembership}.groupId`, `${TableName.Groups}.id`)
|
.join(TableName.Groups, `${TableName.Membership}.actorGroupId`, `${TableName.Groups}.id`)
|
||||||
.join(
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
TableName.GroupProjectMembershipRole,
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
`${TableName.GroupProjectMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.GroupProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.GroupProjectMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("createdAt").withSchema(TableName.GroupProjectMembership),
|
db.ref("createdAt").withSchema(TableName.Membership),
|
||||||
db.ref("updatedAt").withSchema(TableName.GroupProjectMembership),
|
db.ref("updatedAt").withSchema(TableName.Membership),
|
||||||
db.ref("id").as("groupId").withSchema(TableName.Groups),
|
db.ref("id").as("groupId").withSchema(TableName.Groups),
|
||||||
db.ref("name").as("groupName").withSchema(TableName.Groups),
|
db.ref("name").as("groupName").withSchema(TableName.Groups),
|
||||||
db.ref("slug").as("groupSlug").withSchema(TableName.Groups),
|
db.ref("slug").as("groupSlug").withSchema(TableName.Groups),
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("role").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.GroupProjectMembershipRole)
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole)
|
||||||
);
|
);
|
||||||
|
|
||||||
const members = sqlNestRelationships({
|
const members = sqlNestRelationships({
|
||||||
@@ -104,8 +96,8 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const docs = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
const docs = await (tx || db.replicaNode())(TableName.UserGroupMembership)
|
||||||
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
||||||
.join(TableName.Groups, function () {
|
.join(TableName.Groups, (qb) => {
|
||||||
this.on(`${TableName.UserGroupMembership}.groupId`, "=", `${TableName.Groups}.id`).andOn(
|
qb.on(`${TableName.UserGroupMembership}.groupId`, "=", `${TableName.Groups}.id`).andOn(
|
||||||
`${TableName.Groups}.orgId`,
|
`${TableName.Groups}.orgId`,
|
||||||
"=",
|
"=",
|
||||||
db.raw("?", [orgId])
|
db.raw("?", [orgId])
|
||||||
@@ -131,32 +123,26 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
const docs = await db(TableName.UserGroupMembership)
|
const docs = await db(TableName.UserGroupMembership)
|
||||||
// Join the GroupProjectMembership table with the Groups table to get the group name and slug.
|
// Join the GroupProjectMembership table with the Groups table to get the group name and slug.
|
||||||
.join(
|
.join(
|
||||||
TableName.GroupProjectMembership,
|
TableName.Membership,
|
||||||
`${TableName.UserGroupMembership}.groupId`,
|
`${TableName.UserGroupMembership}.groupId`,
|
||||||
`${TableName.GroupProjectMembership}.groupId` // this gives us access to the project id in the group membership
|
`${TableName.Membership}.actorGroupId` // this gives us access to the project id in the group membership
|
||||||
)
|
)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
.join(TableName.Project, `${TableName.GroupProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.where(`${TableName.GroupProjectMembership}.projectId`, projectId)
|
|
||||||
|
|
||||||
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`)
|
||||||
.join<TUserEncryptionKeys>(
|
.join<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.join(
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
TableName.GroupProjectMembershipRole,
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
`${TableName.GroupProjectMembershipRole}.projectMembershipId`,
|
.join<TMemberships>(db(TableName.Membership).as("orgMembership"), (qb) => {
|
||||||
`${TableName.GroupProjectMembership}.id`
|
qb.on(`${TableName.Users}.id`, `orgMembership.userId`)
|
||||||
)
|
.andOn(`orgMembership.scope`, db.raw("?", [AccessScope.Organization]))
|
||||||
.leftJoin(
|
.andOn(`orgMembership.scopeOrgId`, `${TableName.Project}.orgId`);
|
||||||
TableName.ProjectRoles,
|
})
|
||||||
`${TableName.GroupProjectMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.join(TableName.OrgMembership, `${TableName.Users}.id`, `${TableName.OrgMembership}.userId`)
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.UserGroupMembership),
|
db.ref("id").withSchema(TableName.UserGroupMembership),
|
||||||
db.ref("createdAt").withSchema(TableName.UserGroupMembership),
|
db.ref("createdAt").withSchema(TableName.UserGroupMembership),
|
||||||
@@ -167,18 +153,18 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
db.ref("lastName").withSchema(TableName.Users),
|
db.ref("lastName").withSchema(TableName.Users),
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
db.ref("id").withSchema(TableName.Users).as("userId"),
|
||||||
db.ref("role").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.GroupProjectMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.GroupProjectMembershipRole),
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").as("projectName").withSchema(TableName.Project),
|
db.ref("name").as("projectName").withSchema(TableName.Project),
|
||||||
db.ref("isActive").withSchema(TableName.OrgMembership)
|
db.ref("isActive").withSchema("orgMembership")
|
||||||
)
|
)
|
||||||
.where({ isGhost: false });
|
.where({ isGhost: false });
|
||||||
|
|
||||||
@@ -242,5 +228,5 @@ export const groupProjectDALFactory = (db: TDbClient) => {
|
|||||||
return members;
|
return members;
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...groupProjectOrm, findByProjectId, findByUserId, findAllProjectGroupMembers };
|
return { findByProjectId, findByUserId, findAllProjectGroupMembers };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TGroupProjectMembershipRoleDALFactory = ReturnType<typeof groupProjectMembershipRoleDALFactory>;
|
|
||||||
|
|
||||||
export const groupProjectMembershipRoleDALFactory = (db: TDbClient) => {
|
|
||||||
const orm = ormify(db, TableName.GroupProjectMembershipRole);
|
|
||||||
return orm;
|
|
||||||
};
|
|
||||||
@@ -2,6 +2,7 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
TableName,
|
TableName,
|
||||||
TIdentities,
|
TIdentities,
|
||||||
TIdentityAlicloudAuths,
|
TIdentityAlicloudAuths,
|
||||||
@@ -15,7 +16,7 @@ import {
|
|||||||
TIdentityUniversalAuths
|
TIdentityUniversalAuths
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
import { OrderByDirection } from "@app/lib/types";
|
import { OrderByDirection } from "@app/lib/types";
|
||||||
import { ProjectIdentityOrderBy, TListProjectIdentityDTO } from "@app/services/identity-project/identity-project-types";
|
import { ProjectIdentityOrderBy, TListProjectIdentityDTO } from "@app/services/identity-project/identity-project-types";
|
||||||
|
|
||||||
@@ -24,96 +25,82 @@ import { buildAuthMethods } from "../identity/identity-fns";
|
|||||||
export type TIdentityProjectDALFactory = ReturnType<typeof identityProjectDALFactory>;
|
export type TIdentityProjectDALFactory = ReturnType<typeof identityProjectDALFactory>;
|
||||||
|
|
||||||
export const identityProjectDALFactory = (db: TDbClient) => {
|
export const identityProjectDALFactory = (db: TDbClient) => {
|
||||||
const identityProjectOrm = ormify(db, TableName.IdentityProjectMembership);
|
|
||||||
|
|
||||||
const findByIdentityId = async (identityId: string, tx?: Knex) => {
|
const findByIdentityId = async (identityId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await (tx || db.replicaNode())(TableName.IdentityProjectMembership)
|
const docs = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.IdentityProjectMembership}.identityId`, identityId)
|
.where(`${TableName.Membership}.actorIdentityId`, identityId)
|
||||||
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.join(TableName.Identity, `${TableName.IdentityProjectMembership}.identityId`, `${TableName.Identity}.id`)
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.join(
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
TableName.IdentityProjectMembershipRole,
|
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
`${TableName.IdentityProjectMembershipRole}.projectMembershipId`,
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
`${TableName.IdentityProjectMembership}.id`
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.IdentityProjectMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.IdentityProjectAdditionalPrivilege,
|
|
||||||
`${TableName.IdentityProjectMembership}.id`,
|
|
||||||
`${TableName.IdentityProjectAdditionalPrivilege}.projectMembershipId`
|
|
||||||
)
|
|
||||||
|
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityUniversalAuth,
|
TableName.IdentityUniversalAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityUniversalAuth}.identityId`
|
`${TableName.IdentityUniversalAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityGcpAuth,
|
TableName.IdentityGcpAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityGcpAuth}.identityId`
|
`${TableName.IdentityGcpAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityAliCloudAuth,
|
TableName.IdentityAliCloudAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAliCloudAuth}.identityId`
|
`${TableName.IdentityAliCloudAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityAwsAuth,
|
TableName.IdentityAwsAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAwsAuth}.identityId`
|
`${TableName.IdentityAwsAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityKubernetesAuth,
|
TableName.IdentityKubernetesAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityKubernetesAuth}.identityId`
|
`${TableName.IdentityKubernetesAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityOciAuth,
|
TableName.IdentityOciAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityOciAuth}.identityId`
|
`${TableName.IdentityOciAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityOidcAuth,
|
TableName.IdentityOidcAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityOidcAuth}.identityId`
|
`${TableName.IdentityOidcAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityAzureAuth,
|
TableName.IdentityAzureAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAzureAuth}.identityId`
|
`${TableName.IdentityAzureAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityTokenAuth,
|
TableName.IdentityTokenAuth,
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityTokenAuth}.identityId`
|
`${TableName.IdentityTokenAuth}.identityId`
|
||||||
)
|
)
|
||||||
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("createdAt").withSchema(TableName.IdentityProjectMembership),
|
db.ref("createdAt").withSchema(TableName.Membership),
|
||||||
db.ref("updatedAt").withSchema(TableName.IdentityProjectMembership),
|
db.ref("updatedAt").withSchema(TableName.Membership),
|
||||||
|
|
||||||
db.ref("id").as("identityId").withSchema(TableName.Identity),
|
db.ref("id").as("identityId").withSchema(TableName.Identity),
|
||||||
db.ref("name").as("identityName").withSchema(TableName.Identity),
|
db.ref("name").as("identityName").withSchema(TableName.Identity),
|
||||||
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("role").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("projectId").withSchema(TableName.IdentityProjectMembership),
|
db.ref("scopeProjectId").withSchema(TableName.Membership).as("projectId"),
|
||||||
db.ref("name").as("projectName").withSchema(TableName.Project),
|
db.ref("name").as("projectName").withSchema(TableName.Project),
|
||||||
db.ref("type").as("projectType").withSchema(TableName.Project),
|
db.ref("type").as("projectType").withSchema(TableName.Project),
|
||||||
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
||||||
@@ -165,7 +152,7 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
project: {
|
project: {
|
||||||
id: projectId,
|
id: projectId as string,
|
||||||
name: projectName,
|
name: projectName,
|
||||||
type: projectType
|
type: projectType
|
||||||
}
|
}
|
||||||
@@ -223,12 +210,10 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
void qb.whereILike(`${TableName.Identity}.name`, `%${filter.search}%`);
|
void qb.whereILike(`${TableName.Identity}.name`, `%${filter.search}%`);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(
|
.join(TableName.Membership, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
TableName.IdentityProjectMembership,
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
`${TableName.IdentityProjectMembership}.identityId`,
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
`${TableName.Identity}.id`
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
)
|
|
||||||
.where(`${TableName.IdentityProjectMembership}.projectId`, projectId)
|
|
||||||
.orderBy(
|
.orderBy(
|
||||||
`${TableName.Identity}.${filter.orderBy ?? ProjectIdentityOrderBy.Name}`,
|
`${TableName.Identity}.${filter.orderBy ?? ProjectIdentityOrderBy.Name}`,
|
||||||
filter.orderDirection ?? OrderByDirection.ASC
|
filter.orderDirection ?? OrderByDirection.ASC
|
||||||
@@ -240,33 +225,20 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
void fetchIdentitySubquery.offset(filter.offset ?? 0).limit(filter.limit);
|
void fetchIdentitySubquery.offset(filter.offset ?? 0).limit(filter.limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
const query = (tx || db.replicaNode())(TableName.IdentityProjectMembership)
|
const query = (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.IdentityProjectMembership}.projectId`, projectId)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
.join<TIdentities, TIdentities>(fetchIdentitySubquery, (bd) => {
|
.join<TIdentities, TIdentities>(fetchIdentitySubquery, (bd) => {
|
||||||
bd.on(`${TableName.IdentityProjectMembership}.identityId`, `${TableName.Identity}.id`);
|
bd.on(`${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`);
|
||||||
})
|
})
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
if (filter.identityId) {
|
if (filter.identityId) {
|
||||||
void qb.where(`${TableName.IdentityProjectMembership}.identityId`, filter.identityId);
|
void qb.where(`${TableName.Membership}.actorIdentityId`, filter.identityId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
TableName.IdentityProjectMembershipRole,
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
`${TableName.IdentityProjectMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.IdentityProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.IdentityProjectMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.IdentityProjectAdditionalPrivilege,
|
|
||||||
`${TableName.IdentityProjectMembership}.id`,
|
|
||||||
`${TableName.IdentityProjectAdditionalPrivilege}.projectMembershipId`
|
|
||||||
)
|
|
||||||
|
|
||||||
.leftJoin<TIdentityUniversalAuths>(
|
.leftJoin<TIdentityUniversalAuths>(
|
||||||
TableName.IdentityUniversalAuth,
|
TableName.IdentityUniversalAuth,
|
||||||
`${TableName.Identity}.id`,
|
`${TableName.Identity}.id`,
|
||||||
@@ -314,23 +286,23 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("createdAt").withSchema(TableName.IdentityProjectMembership),
|
db.ref("createdAt").withSchema(TableName.Membership),
|
||||||
db.ref("updatedAt").withSchema(TableName.IdentityProjectMembership),
|
db.ref("updatedAt").withSchema(TableName.Membership),
|
||||||
db.ref("authMethod").as("identityAuthMethod").withSchema(TableName.Identity),
|
db.ref("authMethod").as("identityAuthMethod").withSchema(TableName.Identity),
|
||||||
db.ref("id").as("identityId").withSchema(TableName.Identity),
|
db.ref("id").as("identityId").withSchema(TableName.Identity),
|
||||||
db.ref("name").as("identityName").withSchema(TableName.Identity),
|
db.ref("name").as("identityName").withSchema(TableName.Identity),
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("role").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.IdentityProjectMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.IdentityProjectMembershipRole),
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").as("projectName").withSchema(TableName.Project),
|
db.ref("name").as("projectName").withSchema(TableName.Project),
|
||||||
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
||||||
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
|
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
|
||||||
@@ -450,10 +422,11 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const identities = await (tx || db.replicaNode())(TableName.IdentityProjectMembership)
|
const identities = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.IdentityProjectMembership}.projectId`, projectId)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.join(TableName.Identity, `${TableName.IdentityProjectMembership}.identityId`, `${TableName.Identity}.id`)
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
|
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
if (filter.identityId) {
|
if (filter.identityId) {
|
||||||
void qb.where("identityId", filter.identityId);
|
void qb.where("identityId", filter.identityId);
|
||||||
@@ -472,7 +445,6 @@ export const identityProjectDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...identityProjectOrm,
|
|
||||||
findByIdentityId,
|
findByIdentityId,
|
||||||
findByProjectId,
|
findByProjectId,
|
||||||
getCountByProjectId
|
getCountByProjectId
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TIdentityProjectMembershipRoleDALFactory = ReturnType<typeof identityProjectMembershipRoleDALFactory>;
|
|
||||||
|
|
||||||
export const identityProjectMembershipRoleDALFactory = (db: TDbClient) => {
|
|
||||||
const orm = ormify(db, TableName.IdentityProjectMembershipRole);
|
|
||||||
return orm;
|
|
||||||
};
|
|
||||||
@@ -2,6 +2,7 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
TableName,
|
TableName,
|
||||||
TIdentityAlicloudAuths,
|
TIdentityAlicloudAuths,
|
||||||
TIdentityAwsAuths,
|
TIdentityAwsAuths,
|
||||||
@@ -11,15 +12,15 @@ import {
|
|||||||
TIdentityKubernetesAuths,
|
TIdentityKubernetesAuths,
|
||||||
TIdentityOciAuths,
|
TIdentityOciAuths,
|
||||||
TIdentityOidcAuths,
|
TIdentityOidcAuths,
|
||||||
TIdentityOrgMemberships,
|
|
||||||
TIdentityTlsCertAuths,
|
TIdentityTlsCertAuths,
|
||||||
TIdentityTokenAuths,
|
TIdentityTokenAuths,
|
||||||
TIdentityUniversalAuths,
|
TIdentityUniversalAuths,
|
||||||
TOrgRoles
|
TMembershipRoles,
|
||||||
|
TMemberships
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { TIdentityLdapAuths } from "@app/db/schemas/identity-ldap-auths";
|
import { TIdentityLdapAuths } from "@app/db/schemas/identity-ldap-auths";
|
||||||
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
import { buildKnexFilterForSearchResource } from "@app/lib/search-resource/db";
|
import { buildKnexFilterForSearchResource } from "@app/lib/search-resource/db";
|
||||||
import { OrderByDirection } from "@app/lib/types";
|
import { OrderByDirection } from "@app/lib/types";
|
||||||
import {
|
import {
|
||||||
@@ -33,80 +34,80 @@ import { buildAuthMethods } from "./identity-fns";
|
|||||||
export type TIdentityOrgDALFactory = ReturnType<typeof identityOrgDALFactory>;
|
export type TIdentityOrgDALFactory = ReturnType<typeof identityOrgDALFactory>;
|
||||||
|
|
||||||
export const identityOrgDALFactory = (db: TDbClient) => {
|
export const identityOrgDALFactory = (db: TDbClient) => {
|
||||||
const identityOrgOrm = ormify(db, TableName.IdentityOrgMembership);
|
const findOne = async (filter: Partial<TMemberships>, tx?: Knex) => {
|
||||||
|
|
||||||
const findOne = async (filter: Partial<TIdentityOrgMemberships>, tx?: Knex) => {
|
|
||||||
try {
|
try {
|
||||||
const [data] = await (tx || db.replicaNode())(TableName.IdentityOrgMembership)
|
const [data] = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.where((queryBuilder) => {
|
.where((queryBuilder) => {
|
||||||
Object.entries(filter).forEach(([key, value]) => {
|
Object.entries(filter).forEach(([key, value]) => {
|
||||||
void queryBuilder.where(`${TableName.IdentityOrgMembership}.${key}`, value);
|
void queryBuilder.where(`${TableName.Membership}.${key}`, value);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`)
|
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
|
|
||||||
.leftJoin<TIdentityUniversalAuths>(
|
.leftJoin<TIdentityUniversalAuths>(
|
||||||
TableName.IdentityUniversalAuth,
|
TableName.IdentityUniversalAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityUniversalAuth}.identityId`
|
`${TableName.IdentityUniversalAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityGcpAuths>(
|
.leftJoin<TIdentityGcpAuths>(
|
||||||
TableName.IdentityGcpAuth,
|
TableName.IdentityGcpAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityGcpAuth}.identityId`
|
`${TableName.IdentityGcpAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityAlicloudAuths>(
|
.leftJoin<TIdentityAlicloudAuths>(
|
||||||
TableName.IdentityAliCloudAuth,
|
TableName.IdentityAliCloudAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAliCloudAuth}.identityId`
|
`${TableName.IdentityAliCloudAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityAwsAuths>(
|
.leftJoin<TIdentityAwsAuths>(
|
||||||
TableName.IdentityAwsAuth,
|
TableName.IdentityAwsAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAwsAuth}.identityId`
|
`${TableName.IdentityAwsAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityKubernetesAuths>(
|
.leftJoin<TIdentityKubernetesAuths>(
|
||||||
TableName.IdentityKubernetesAuth,
|
TableName.IdentityKubernetesAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityKubernetesAuth}.identityId`
|
`${TableName.IdentityKubernetesAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityOciAuths>(
|
.leftJoin<TIdentityOciAuths>(
|
||||||
TableName.IdentityOciAuth,
|
TableName.IdentityOciAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityOciAuth}.identityId`
|
`${TableName.IdentityOciAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityOidcAuths>(
|
.leftJoin<TIdentityOidcAuths>(
|
||||||
TableName.IdentityOidcAuth,
|
TableName.IdentityOidcAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityOidcAuth}.identityId`
|
`${TableName.IdentityOidcAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityAzureAuths>(
|
.leftJoin<TIdentityAzureAuths>(
|
||||||
TableName.IdentityAzureAuth,
|
TableName.IdentityAzureAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAzureAuth}.identityId`
|
`${TableName.IdentityAzureAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityTokenAuths>(
|
.leftJoin<TIdentityTokenAuths>(
|
||||||
TableName.IdentityTokenAuth,
|
TableName.IdentityTokenAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityTokenAuth}.identityId`
|
`${TableName.IdentityTokenAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityJwtAuths>(
|
.leftJoin<TIdentityJwtAuths>(
|
||||||
TableName.IdentityJwtAuth,
|
TableName.IdentityJwtAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityJwtAuth}.identityId`
|
`${TableName.IdentityJwtAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityLdapAuths>(
|
.leftJoin<TIdentityLdapAuths>(
|
||||||
TableName.IdentityLdapAuth,
|
TableName.IdentityLdapAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityLdapAuth}.identityId`
|
`${TableName.IdentityLdapAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin<TIdentityTlsCertAuths>(
|
.leftJoin<TIdentityTlsCertAuths>(
|
||||||
TableName.IdentityTlsCertAuth,
|
TableName.IdentityTlsCertAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityTlsCertAuth}.identityId`
|
`${TableName.IdentityTlsCertAuth}.identityId`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.IdentityOrgMembership),
|
selectAllTableCols(TableName.Membership),
|
||||||
|
|
||||||
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
||||||
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
|
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
|
||||||
@@ -129,7 +130,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
return {
|
return {
|
||||||
...data,
|
...data,
|
||||||
identity: {
|
identity: {
|
||||||
id: data.identityId,
|
id: data.actorIdentityId as string,
|
||||||
name,
|
name,
|
||||||
hasDeleteProtection,
|
hasDeleteProtection,
|
||||||
authMethods: buildAuthMethods(data)
|
authMethods: buildAuthMethods(data)
|
||||||
@@ -149,20 +150,18 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
orderDirection = OrderByDirection.ASC,
|
orderDirection = OrderByDirection.ASC,
|
||||||
search,
|
search,
|
||||||
...filter
|
...filter
|
||||||
}: Partial<TIdentityOrgMemberships> &
|
}: Partial<TMemberships> &
|
||||||
Pick<TListOrgIdentitiesByOrgIdDTO, "offset" | "limit" | "orderBy" | "orderDirection" | "search">,
|
Pick<TListOrgIdentitiesByOrgIdDTO, "offset" | "limit" | "orderBy" | "orderDirection" | "search">,
|
||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const paginatedIdentity = (tx || db.replicaNode())(TableName.Identity)
|
const paginatedIdentity = (tx || db.replicaNode())(TableName.Identity)
|
||||||
.join(
|
.join(TableName.Membership, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
TableName.IdentityOrgMembership,
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
`${TableName.Identity}.id`
|
|
||||||
)
|
|
||||||
.orderBy(`${TableName.Identity}.${orderBy}`, orderDirection)
|
.orderBy(`${TableName.Identity}.${orderBy}`, orderDirection)
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.IdentityOrgMembership),
|
selectAllTableCols(TableName.Membership),
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
||||||
db.ref("hasDeleteProtection").withSchema(TableName.Identity)
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity)
|
||||||
)
|
)
|
||||||
@@ -181,14 +180,17 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
type TSubquery = Awaited<typeof paginatedIdentity>;
|
type TSubquery = Awaited<typeof paginatedIdentity>;
|
||||||
const query = (tx || db.replicaNode())
|
const query = (tx || db.replicaNode())
|
||||||
.from<TSubquery[number], TSubquery>(paginatedIdentity)
|
.from<TSubquery[number], TSubquery>(paginatedIdentity)
|
||||||
.leftJoin<TOrgRoles>(TableName.OrgRoles, `paginatedIdentity.roleId`, `${TableName.OrgRoles}.id`)
|
.join<TMembershipRoles>(
|
||||||
|
TableName.MembershipRole,
|
||||||
|
`${TableName.MembershipRole}.membershipId`,
|
||||||
|
"paginatedIdentity.id"
|
||||||
|
)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
||||||
void queryBuilder
|
void queryBuilder
|
||||||
.on(`paginatedIdentity.identityId`, `${TableName.IdentityMetadata}.identityId`)
|
.on(`paginatedIdentity.actorIdentityId`, `${TableName.IdentityMetadata}.identityId`)
|
||||||
.andOn(`paginatedIdentity.orgId`, `${TableName.IdentityMetadata}.orgId`);
|
.andOn(`paginatedIdentity.scopeOrgId`, `${TableName.IdentityMetadata}.orgId`);
|
||||||
})
|
})
|
||||||
|
|
||||||
.leftJoin<TIdentityUniversalAuths>(
|
.leftJoin<TIdentityUniversalAuths>(
|
||||||
TableName.IdentityUniversalAuth,
|
TableName.IdentityUniversalAuth,
|
||||||
"paginatedIdentity.identityId",
|
"paginatedIdentity.identityId",
|
||||||
@@ -251,14 +253,14 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema("paginatedIdentity"),
|
db.ref("id").withSchema("paginatedIdentity"),
|
||||||
db.ref("role").withSchema("paginatedIdentity"),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("roleId").withSchema("paginatedIdentity"),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
db.ref("orgId").withSchema("paginatedIdentity"),
|
db.ref("scopeOrgId").withSchema("paginatedIdentity").as("orgId"),
|
||||||
db.ref("lastLoginAuthMethod").withSchema("paginatedIdentity"),
|
db.ref("lastLoginAuthMethod").withSchema("paginatedIdentity"),
|
||||||
db.ref("lastLoginTime").withSchema("paginatedIdentity"),
|
db.ref("lastLoginTime").withSchema("paginatedIdentity"),
|
||||||
db.ref("createdAt").withSchema("paginatedIdentity"),
|
db.ref("createdAt").withSchema("paginatedIdentity"),
|
||||||
db.ref("updatedAt").withSchema("paginatedIdentity"),
|
db.ref("updatedAt").withSchema("paginatedIdentity"),
|
||||||
db.ref("identityId").withSchema("paginatedIdentity").as("identityId"),
|
db.ref("actorIdentityId").withSchema("paginatedIdentity").as("identityId"),
|
||||||
db.ref("identityName").withSchema("paginatedIdentity"),
|
db.ref("identityName").withSchema("paginatedIdentity"),
|
||||||
db.ref("hasDeleteProtection").withSchema("paginatedIdentity"),
|
db.ref("hasDeleteProtection").withSchema("paginatedIdentity"),
|
||||||
|
|
||||||
@@ -276,12 +278,11 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("id").as("tlsCertId").withSchema(TableName.IdentityTlsCertAuth)
|
db.ref("id").as("tlsCertId").withSchema(TableName.IdentityTlsCertAuth)
|
||||||
)
|
)
|
||||||
// cr stands for custom role
|
// cr stands for custom role
|
||||||
.select(db.ref("id").as("crId").withSchema(TableName.OrgRoles))
|
.select(db.ref("id").as("crId").withSchema(TableName.Role))
|
||||||
.select(db.ref("name").as("crName").withSchema(TableName.OrgRoles))
|
.select(db.ref("name").as("crName").withSchema(TableName.Role))
|
||||||
.select(db.ref("slug").as("crSlug").withSchema(TableName.OrgRoles))
|
.select(db.ref("slug").as("crSlug").withSchema(TableName.Role))
|
||||||
.select(db.ref("description").as("crDescription").withSchema(TableName.OrgRoles))
|
.select(db.ref("description").as("crDescription").withSchema(TableName.Role))
|
||||||
.select(db.ref("permissions").as("crPermission").withSchema(TableName.OrgRoles))
|
.select(db.ref("permissions").as("crPermission").withSchema(TableName.Role))
|
||||||
.select(db.ref("permissions").as("crPermission").withSchema(TableName.OrgRoles))
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
|
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
|
||||||
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
||||||
@@ -327,7 +328,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
}) => ({
|
}) => ({
|
||||||
role,
|
role,
|
||||||
roleId,
|
roleId,
|
||||||
identityId,
|
identityId: identityId as string,
|
||||||
id,
|
id,
|
||||||
orgId,
|
orgId,
|
||||||
createdAt,
|
createdAt,
|
||||||
@@ -344,7 +345,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
identity: {
|
identity: {
|
||||||
id: identityId,
|
id: identityId as string,
|
||||||
name: identityName,
|
name: identityName,
|
||||||
hasDeleteProtection,
|
hasDeleteProtection,
|
||||||
authMethods: buildAuthMethods({
|
authMethods: buildAuthMethods({
|
||||||
@@ -394,20 +395,23 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const searchQuery = (tx || db.replicaNode())(TableName.IdentityOrgMembership)
|
const searchQuery = (tx || db.replicaNode())(TableName.Membership)
|
||||||
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.IdentityOrgMembership}.identityId`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
|
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.Membership}.actorIdentityId`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.orderBy(
|
.orderBy(
|
||||||
orderBy === OrgIdentityOrderBy.Role
|
orderBy === OrgIdentityOrderBy.Role
|
||||||
? `${TableName.IdentityOrgMembership}.${orderBy}`
|
? `${TableName.Membership}.${orderBy}`
|
||||||
: `${TableName.Identity}.${orderBy}`,
|
: `${TableName.Identity}.${orderBy}`,
|
||||||
orderDirection
|
orderDirection
|
||||||
)
|
)
|
||||||
.select(`${TableName.IdentityOrgMembership}.id`)
|
.select(`${TableName.Membership}.id`)
|
||||||
.select<{ id: string; total_count: string }>(
|
.select<{ id: string; total_count: string }>(
|
||||||
db.raw(
|
db.raw(
|
||||||
`count(${TableName.IdentityOrgMembership}."identityId") OVER(PARTITION BY ${TableName.IdentityOrgMembership}."orgId") as total_count`
|
`count(${TableName.Membership}."actorIdentityId") OVER(PARTITION BY ${TableName.Membership}."scopeOrgId") as total_count`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.as("searchedIdentities");
|
.as("searchedIdentities");
|
||||||
@@ -416,7 +420,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
buildKnexFilterForSearchResource(searchQuery, searchFilter, (attr) => {
|
buildKnexFilterForSearchResource(searchQuery, searchFilter, (attr) => {
|
||||||
switch (attr) {
|
switch (attr) {
|
||||||
case "role":
|
case "role":
|
||||||
return [`${TableName.OrgRoles}.slug`, `${TableName.IdentityOrgMembership}.role`];
|
return [`${TableName.Role}.slug`, `${TableName.MembershipRole}.role`];
|
||||||
case "name":
|
case "name":
|
||||||
return `${TableName.Identity}.name`;
|
return `${TableName.Identity}.name`;
|
||||||
default:
|
default:
|
||||||
@@ -430,82 +434,85 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TSubquery = Awaited<typeof searchQuery>;
|
type TSubquery = Awaited<typeof searchQuery>;
|
||||||
const query = (tx || db.replicaNode())(TableName.IdentityOrgMembership)
|
const query = (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.IdentityOrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
.join<TSubquery>(searchQuery, `${TableName.IdentityOrgMembership}.id`, "searchedIdentities.id")
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.IdentityOrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
.join<TSubquery>(searchQuery, `${TableName.Membership}.id`, "searchedIdentities.id")
|
||||||
|
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
||||||
void queryBuilder
|
void queryBuilder
|
||||||
.on(`${TableName.IdentityOrgMembership}.identityId`, `${TableName.IdentityMetadata}.identityId`)
|
.on(`${TableName.Membership}.actorIdentityId`, `${TableName.IdentityMetadata}.identityId`)
|
||||||
.andOn(`${TableName.IdentityOrgMembership}.orgId`, `${TableName.IdentityMetadata}.orgId`);
|
.andOn(`${TableName.Membership}.scopeOrgId`, `${TableName.IdentityMetadata}.orgId`);
|
||||||
})
|
})
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityUniversalAuth,
|
TableName.IdentityUniversalAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityUniversalAuth}.identityId`
|
`${TableName.IdentityUniversalAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityGcpAuth,
|
TableName.IdentityGcpAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityGcpAuth}.identityId`
|
`${TableName.IdentityGcpAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityAliCloudAuth,
|
TableName.IdentityAliCloudAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAliCloudAuth}.identityId`
|
`${TableName.IdentityAliCloudAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityAwsAuth,
|
TableName.IdentityAwsAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAwsAuth}.identityId`
|
`${TableName.IdentityAwsAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityKubernetesAuth,
|
TableName.IdentityKubernetesAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityKubernetesAuth}.identityId`
|
`${TableName.IdentityKubernetesAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityOciAuth,
|
TableName.IdentityOciAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityOciAuth}.identityId`
|
`${TableName.IdentityOciAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityOidcAuth,
|
TableName.IdentityOidcAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityOidcAuth}.identityId`
|
`${TableName.IdentityOidcAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityAzureAuth,
|
TableName.IdentityAzureAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityAzureAuth}.identityId`
|
`${TableName.IdentityAzureAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityTokenAuth,
|
TableName.IdentityTokenAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityTokenAuth}.identityId`
|
`${TableName.IdentityTokenAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityJwtAuth,
|
TableName.IdentityJwtAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityJwtAuth}.identityId`
|
`${TableName.IdentityJwtAuth}.identityId`
|
||||||
)
|
)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
TableName.IdentityLdapAuth,
|
TableName.IdentityLdapAuth,
|
||||||
`${TableName.IdentityOrgMembership}.identityId`,
|
`${TableName.Membership}.actorIdentityId`,
|
||||||
`${TableName.IdentityLdapAuth}.identityId`
|
`${TableName.IdentityLdapAuth}.identityId`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.IdentityOrgMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("total_count").withSchema("searchedIdentities"),
|
db.ref("total_count").withSchema("searchedIdentities"),
|
||||||
db.ref("role").withSchema(TableName.IdentityOrgMembership),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("roleId").withSchema(TableName.IdentityOrgMembership),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
db.ref("orgId").withSchema(TableName.IdentityOrgMembership),
|
db.ref("scopeOrgId").withSchema(TableName.Membership).as("orgId"),
|
||||||
db.ref("createdAt").withSchema(TableName.IdentityOrgMembership),
|
db.ref("createdAt").withSchema(TableName.Membership),
|
||||||
db.ref("updatedAt").withSchema(TableName.IdentityOrgMembership),
|
db.ref("updatedAt").withSchema(TableName.Membership),
|
||||||
db.ref("lastLoginAuthMethod").withSchema(TableName.IdentityOrgMembership),
|
db.ref("lastLoginAuthMethod").withSchema(TableName.Membership),
|
||||||
db.ref("lastLoginTime").withSchema(TableName.IdentityOrgMembership),
|
db.ref("lastLoginTime").withSchema(TableName.Membership),
|
||||||
db.ref("identityId").withSchema(TableName.IdentityOrgMembership).as("identityId"),
|
db.ref("actorIdentityId").withSchema(TableName.Membership).as("identityId"),
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
||||||
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
||||||
|
|
||||||
@@ -522,12 +529,11 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("id").as("ldapId").withSchema(TableName.IdentityLdapAuth)
|
db.ref("id").as("ldapId").withSchema(TableName.IdentityLdapAuth)
|
||||||
)
|
)
|
||||||
// cr stands for custom role
|
// cr stands for custom role
|
||||||
.select(db.ref("id").as("crId").withSchema(TableName.OrgRoles))
|
.select(db.ref("id").as("crId").withSchema(TableName.Role))
|
||||||
.select(db.ref("name").as("crName").withSchema(TableName.OrgRoles))
|
.select(db.ref("name").as("crName").withSchema(TableName.Role))
|
||||||
.select(db.ref("slug").as("crSlug").withSchema(TableName.OrgRoles))
|
.select(db.ref("slug").as("crSlug").withSchema(TableName.Role))
|
||||||
.select(db.ref("description").as("crDescription").withSchema(TableName.OrgRoles))
|
.select(db.ref("description").as("crDescription").withSchema(TableName.Role))
|
||||||
.select(db.ref("permissions").as("crPermission").withSchema(TableName.OrgRoles))
|
.select(db.ref("permissions").as("crPermission").withSchema(TableName.Role))
|
||||||
.select(db.ref("permissions").as("crPermission").withSchema(TableName.OrgRoles))
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
|
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
|
||||||
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
|
||||||
@@ -545,13 +551,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
ELSE ??.role
|
ELSE ??.role
|
||||||
END ?
|
END ?
|
||||||
`,
|
`,
|
||||||
[
|
[TableName.MembershipRole, "custom", TableName.Role, TableName.MembershipRole, db.raw(orderDirection)]
|
||||||
TableName.IdentityOrgMembership,
|
|
||||||
"custom",
|
|
||||||
TableName.OrgRoles,
|
|
||||||
TableName.IdentityOrgMembership,
|
|
||||||
db.raw(orderDirection)
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,7 +590,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
}) => ({
|
}) => ({
|
||||||
role,
|
role,
|
||||||
roleId,
|
roleId,
|
||||||
identityId,
|
identityId: identityId as string,
|
||||||
id,
|
id,
|
||||||
total_count: total_count as string,
|
total_count: total_count as string,
|
||||||
orgId,
|
orgId,
|
||||||
@@ -646,13 +646,15 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const countAllOrgIdentities = async (
|
const countAllOrgIdentities = async (
|
||||||
{ search, ...filter }: Partial<TIdentityOrgMemberships> & Pick<TListOrgIdentitiesByOrgIdDTO, "search">,
|
{ search, ...filter }: Partial<TMemberships> & Pick<TListOrgIdentitiesByOrgIdDTO, "search">,
|
||||||
tx?: Knex
|
tx?: Knex
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const query = (tx || db.replicaNode())(TableName.IdentityOrgMembership)
|
const query = (tx || db.replicaNode())(TableName.Membership)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.where(filter)
|
.where(filter)
|
||||||
.join(TableName.Identity, `${TableName.IdentityOrgMembership}.identityId`, `${TableName.Identity}.id`)
|
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
if (search?.length) {
|
if (search?.length) {
|
||||||
@@ -667,5 +669,5 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...identityOrgOrm, find, findOne, countAllOrgIdentities, searchIdentities };
|
return { find, findOne, countAllOrgIdentities, searchIdentities };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -239,8 +239,8 @@ export const membershipIdentityServiceFactory = ({
|
|||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
await membershipRoleDAL.insertMany(roleDocs, tx);
|
const insertedRoleDocs = await membershipRoleDAL.insertMany(roleDocs, tx);
|
||||||
return doc;
|
return { ...doc, roles: insertedRoleDocs };
|
||||||
});
|
});
|
||||||
|
|
||||||
return { membership: membershipDoc };
|
return { membership: membershipDoc };
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TUserEncryptionKeys } from "@app/db/schemas";
|
import { AccessScope, TableName, TUserEncryptionKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, sqlNestRelationships } from "@app/lib/knex";
|
import { sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TOrgMembershipDALFactory = ReturnType<typeof orgMembershipDALFactory>;
|
export type TOrgMembershipDALFactory = ReturnType<typeof orgMembershipDALFactory>;
|
||||||
|
|
||||||
export const orgMembershipDALFactory = (db: TDbClient) => {
|
export const orgMembershipDALFactory = (db: TDbClient) => {
|
||||||
const orgMembershipOrm = ormify(db, TableName.OrgMembership);
|
|
||||||
|
|
||||||
const findOrgMembershipById = async (membershipId: string) => {
|
const findOrgMembershipById = async (membershipId: string) => {
|
||||||
try {
|
try {
|
||||||
const member = await db
|
const member = await db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.id`, membershipId)
|
.where(`${TableName.Membership}.id`, membershipId)
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
.leftJoin<TUserEncryptionKeys>(
|
.leftJoin<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
@@ -21,19 +22,19 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
||||||
void queryBuilder
|
void queryBuilder
|
||||||
.on(`${TableName.OrgMembership}.userId`, `${TableName.IdentityMetadata}.userId`)
|
.on(`${TableName.Membership}.actorUserId`, `${TableName.IdentityMetadata}.userId`)
|
||||||
.andOn(`${TableName.OrgMembership}.orgId`, `${TableName.IdentityMetadata}.orgId`);
|
.andOn(`${TableName.Membership}.scopeOrgId`, `${TableName.IdentityMetadata}.orgId`);
|
||||||
})
|
})
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.OrgMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("inviteEmail").withSchema(TableName.OrgMembership),
|
db.ref("inviteEmail").withSchema(TableName.Membership),
|
||||||
db.ref("orgId").withSchema(TableName.OrgMembership),
|
db.ref("scopeOrgId").withSchema(TableName.Membership).as("orgId"),
|
||||||
db.ref("role").withSchema(TableName.OrgMembership),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("roleId").withSchema(TableName.OrgMembership),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
db.ref("status").withSchema(TableName.OrgMembership),
|
db.ref("status").withSchema(TableName.Membership),
|
||||||
db.ref("isActive").withSchema(TableName.OrgMembership),
|
db.ref("isActive").withSchema(TableName.Membership),
|
||||||
db.ref("lastLoginAuthMethod").withSchema(TableName.OrgMembership),
|
db.ref("lastLoginAuthMethod").withSchema(TableName.Membership),
|
||||||
db.ref("lastLoginTime").withSchema(TableName.OrgMembership),
|
db.ref("lastLoginTime").withSchema(TableName.Membership),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
@@ -117,18 +118,20 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const twelveMonthsAgo = new Date(now.getTime() - 360 * 24 * 60 * 60 * 1000);
|
const twelveMonthsAgo = new Date(now.getTime() - 360 * 24 * 60 * 60 * 1000);
|
||||||
|
|
||||||
const memberships = await db
|
const memberships = await db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.where("status", "invited")
|
.where("status", "invited")
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
// lastInvitedAt is null AND createdAt is between 1 week and 12 months ago
|
// lastInvitedAt is null AND createdAt is between 1 week and 12 months ago
|
||||||
void qb
|
void qb
|
||||||
.whereNull(`${TableName.OrgMembership}.lastInvitedAt`)
|
.whereNull(`${TableName.Membership}.lastInvitedAt`)
|
||||||
.whereBetween(`${TableName.OrgMembership}.createdAt`, [twelveMonthsAgo, oneWeekAgo]);
|
.whereBetween(`${TableName.Membership}.createdAt`, [twelveMonthsAgo, oneWeekAgo]);
|
||||||
// lastInvitedAt is older than 1 week ago AND createdAt is younger than 1 month ago
|
// lastInvitedAt is older than 1 week ago AND createdAt is younger than 1 month ago
|
||||||
void qb.orWhere((qbInner) => {
|
void qb.orWhere((qbInner) => {
|
||||||
void qbInner
|
void qbInner
|
||||||
.where(`${TableName.OrgMembership}.lastInvitedAt`, "<", oneWeekAgo)
|
.where(`${TableName.Membership}.lastInvitedAt`, "<", oneWeekAgo)
|
||||||
.where(`${TableName.OrgMembership}.createdAt`, ">", oneMonthAgo);
|
.where(`${TableName.Membership}.createdAt`, ">", oneMonthAgo);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -144,7 +147,11 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const updateLastInvitedAtByIds = async (membershipIds: string[]) => {
|
const updateLastInvitedAtByIds = async (membershipIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
if (membershipIds.length === 0) return;
|
if (membershipIds.length === 0) return;
|
||||||
await db(TableName.OrgMembership).whereIn("id", membershipIds).update({ lastInvitedAt: new Date() });
|
await db(TableName.Membership)
|
||||||
|
.whereIn("id", membershipIds)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.update({ lastInvitedAt: new Date() });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({
|
throw new DatabaseError({
|
||||||
error,
|
error,
|
||||||
@@ -156,9 +163,12 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const findOrgMembershipsWithUsersByOrgId = async (orgId: string) => {
|
const findOrgMembershipsWithUsersByOrgId = async (orgId: string) => {
|
||||||
try {
|
try {
|
||||||
const members = await db
|
const members = await db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
.leftJoin<TUserEncryptionKeys>(
|
.leftJoin<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
@@ -166,17 +176,17 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
.leftJoin(TableName.IdentityMetadata, (queryBuilder) => {
|
||||||
void queryBuilder
|
void queryBuilder
|
||||||
.on(`${TableName.OrgMembership}.userId`, `${TableName.IdentityMetadata}.userId`)
|
.on(`${TableName.Membership}.actorUserId`, `${TableName.IdentityMetadata}.userId`)
|
||||||
.andOn(`${TableName.OrgMembership}.orgId`, `${TableName.IdentityMetadata}.orgId`);
|
.andOn(`${TableName.Membership}.scopeOrgId`, `${TableName.IdentityMetadata}.orgId`);
|
||||||
})
|
})
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.OrgMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("inviteEmail").withSchema(TableName.OrgMembership),
|
db.ref("inviteEmail").withSchema(TableName.Membership),
|
||||||
db.ref("orgId").withSchema(TableName.OrgMembership),
|
db.ref("scopeOrgId").withSchema(TableName.Membership).as("orgId"),
|
||||||
db.ref("role").withSchema(TableName.OrgMembership),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("roleId").withSchema(TableName.OrgMembership),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("customRoleId"),
|
||||||
db.ref("status").withSchema(TableName.OrgMembership),
|
db.ref("status").withSchema(TableName.Membership),
|
||||||
db.ref("isActive").withSchema(TableName.OrgMembership),
|
db.ref("isActive").withSchema(TableName.Membership),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
@@ -207,7 +217,6 @@ export const orgMembershipDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...orgMembershipOrm,
|
|
||||||
findOrgMembershipById,
|
findOrgMembershipById,
|
||||||
findRecentInvitedMemberships,
|
findRecentInvitedMemberships,
|
||||||
updateLastInvitedAtByIds,
|
updateLastInvitedAtByIds,
|
||||||
|
|||||||
+114
-127
@@ -2,14 +2,15 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
OrganizationsSchema,
|
OrganizationsSchema,
|
||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
TableName,
|
TableName,
|
||||||
|
TMemberships,
|
||||||
|
TMembershipsInsert,
|
||||||
|
TMembershipsUpdate,
|
||||||
TOrganizations,
|
TOrganizations,
|
||||||
TOrganizationsInsert,
|
TOrganizationsInsert,
|
||||||
TOrgMemberships,
|
|
||||||
TOrgMembershipsInsert,
|
|
||||||
TOrgMembershipsUpdate,
|
|
||||||
TUserEncryptionKeys
|
TUserEncryptionKeys
|
||||||
} from "@app/db/schemas";
|
} from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
@@ -64,9 +65,12 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
.replicaNode()(TableName.Organization)
|
.replicaNode()(TableName.Organization)
|
||||||
.whereIn(`${TableName.Organization}.id`, orgIdSubquery)
|
.whereIn(`${TableName.Organization}.id`, orgIdSubquery)
|
||||||
.leftJoin(TableName.Project, `${TableName.Organization}.id`, `${TableName.Project}.orgId`)
|
.leftJoin(TableName.Project, `${TableName.Organization}.id`, `${TableName.Project}.orgId`)
|
||||||
.leftJoin(TableName.OrgMembership, `${TableName.Organization}.id`, `${TableName.OrgMembership}.orgId`)
|
.leftJoin(TableName.Membership, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.leftJoin(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
.leftJoin(TableName.OrgRoles, `${TableName.OrgMembership}.roleId`, `${TableName.OrgRoles}.id`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.leftJoin(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
|
.leftJoin(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
void qb.where(`${TableName.Users}.isGhost`, false).orWhereNull(`${TableName.Users}.id`);
|
void qb.where(`${TableName.Users}.isGhost`, false).orWhereNull(`${TableName.Users}.id`);
|
||||||
});
|
});
|
||||||
@@ -84,11 +88,11 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
.select(db.ref("firstName").withSchema(TableName.Users).as("firstName"))
|
.select(db.ref("firstName").withSchema(TableName.Users).as("firstName"))
|
||||||
.select(db.ref("lastName").withSchema(TableName.Users).as("lastName"))
|
.select(db.ref("lastName").withSchema(TableName.Users).as("lastName"))
|
||||||
.select(db.ref("id").withSchema(TableName.Users).as("userId"))
|
.select(db.ref("id").withSchema(TableName.Users).as("userId"))
|
||||||
.select(db.ref("id").withSchema(TableName.OrgMembership).as("orgMembershipId"))
|
.select(db.ref("id").withSchema(TableName.Membership).as("orgMembershipId"))
|
||||||
.select(db.ref("role").withSchema(TableName.OrgMembership).as("orgMembershipRole"))
|
.select(db.ref("status").withSchema(TableName.Membership).as("orgMembershipStatus"))
|
||||||
.select(db.ref("roleId").withSchema(TableName.OrgMembership).as("orgMembershipRoleId"))
|
.select(db.ref("role").withSchema(TableName.MembershipRole).as("orgMembershipRole"))
|
||||||
.select(db.ref("status").withSchema(TableName.OrgMembership).as("orgMembershipStatus"))
|
.select(db.ref("customRoleId").withSchema(TableName.MembershipRole).as("orgMembershipRoleId"))
|
||||||
.select(db.ref("name").withSchema(TableName.OrgRoles).as("orgMembershipRoleName")),
|
.select(db.ref("name").withSchema(TableName.Role).as("orgMembershipRoleName")),
|
||||||
buildBaseQuery(countQuery).countDistinct(`${TableName.Organization}.id`, { as: "count" }).first()
|
buildBaseQuery(countQuery).countDistinct(`${TableName.Organization}.id`, { as: "count" }).first()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -229,9 +233,12 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
): Promise<(TOrganizations & { orgAuthMethod: string; userRole: string; userStatus: string })[]> => {
|
): Promise<(TOrganizations & { orgAuthMethod: string; userRole: string; userStatus: string })[]> => {
|
||||||
try {
|
try {
|
||||||
const org = (await db
|
const org = (await db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where({ userId })
|
.where(`${TableName.Membership}.actorUserId`, userId)
|
||||||
.join(TableName.Organization, `${TableName.OrgMembership}.orgId`, `${TableName.Organization}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
|
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
|
||||||
.leftJoin(TableName.SamlConfig, (qb) => {
|
.leftJoin(TableName.SamlConfig, (qb) => {
|
||||||
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
||||||
`${TableName.SamlConfig}.isActive`,
|
`${TableName.SamlConfig}.isActive`,
|
||||||
@@ -247,8 +254,8 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
.select(selectAllTableCols(TableName.Organization))
|
.select(selectAllTableCols(TableName.Organization))
|
||||||
.select(db.ref("role").withSchema(TableName.OrgMembership).as("userRole"))
|
.select(db.ref("role").withSchema(TableName.MembershipRole).as("userRole"))
|
||||||
.select(db.ref("status").withSchema(TableName.OrgMembership).as("userStatus"))
|
.select(db.ref("status").withSchema(TableName.Membership).as("userStatus"))
|
||||||
.select(
|
.select(
|
||||||
db.raw(`
|
db.raw(`
|
||||||
CASE
|
CASE
|
||||||
@@ -283,24 +290,28 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
const findAllOrgMembers = async (orgId: string) => {
|
const findAllOrgMembers = async (orgId: string) => {
|
||||||
try {
|
try {
|
||||||
const members = await db
|
const members = await db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.leftJoin<TUserEncryptionKeys>(
|
.leftJoin<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.OrgMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("inviteEmail").withSchema(TableName.OrgMembership),
|
db.ref("inviteEmail").withSchema(TableName.Membership),
|
||||||
db.ref("orgId").withSchema(TableName.OrgMembership),
|
db.ref("actorOrgId").withSchema(TableName.Membership).as("orgId"),
|
||||||
db.ref("role").withSchema(TableName.OrgMembership),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("roleId").withSchema(TableName.OrgMembership),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
db.ref("status").withSchema(TableName.OrgMembership),
|
db.ref("status").withSchema(TableName.Membership),
|
||||||
db.ref("isActive").withSchema(TableName.OrgMembership),
|
db.ref("isActive").withSchema(TableName.Membership),
|
||||||
db.ref("lastLoginAuthMethod").withSchema(TableName.OrgMembership),
|
db.ref("lastLoginAuthMethod").withSchema(TableName.Membership),
|
||||||
db.ref("lastLoginTime").withSchema(TableName.OrgMembership),
|
db.ref("lastLoginTime").withSchema(TableName.Membership),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
db.ref("isEmailVerified").withSchema(TableName.Users),
|
db.ref("isEmailVerified").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
@@ -332,11 +343,13 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const count = await db
|
const count = await db
|
||||||
.replicaNode()(TableName.OrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.orgId`, orgId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.count("*")
|
.count("*")
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.where({ isGhost: false, [`${TableName.OrgMembership}.isActive` as "isActive"]: true })
|
.where({ isGhost: false, [`${TableName.Membership}.isActive` as "isActive"]: true })
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
return parseInt((count as unknown as CountResult).count || "0", 10);
|
return parseInt((count as unknown as CountResult).count || "0", 10);
|
||||||
@@ -348,21 +361,25 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
const findOrgMembersByUsername = async (orgId: string, usernames: string[], tx?: Knex) => {
|
const findOrgMembersByUsername = async (orgId: string, usernames: string[], tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const conn = tx || db.replicaNode();
|
const conn = tx || db.replicaNode();
|
||||||
const members = await conn(TableName.OrgMembership)
|
const members = await conn(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
.leftJoin<TUserEncryptionKeys>(
|
.leftJoin<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
conn.ref("id").withSchema(TableName.OrgMembership),
|
conn.ref("id").withSchema(TableName.Membership),
|
||||||
conn.ref("inviteEmail").withSchema(TableName.OrgMembership),
|
conn.ref("inviteEmail").withSchema(TableName.Membership),
|
||||||
conn.ref("orgId").withSchema(TableName.OrgMembership),
|
conn.ref("orgId").withSchema(TableName.Membership),
|
||||||
conn.ref("role").withSchema(TableName.OrgMembership),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
conn.ref("roleId").withSchema(TableName.OrgMembership),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
conn.ref("status").withSchema(TableName.OrgMembership),
|
conn.ref("status").withSchema(TableName.Membership),
|
||||||
conn.ref("username").withSchema(TableName.Users),
|
conn.ref("username").withSchema(TableName.Users),
|
||||||
conn.ref("email").withSchema(TableName.Users),
|
conn.ref("email").withSchema(TableName.Users),
|
||||||
conn.ref("firstName").withSchema(TableName.Users),
|
conn.ref("firstName").withSchema(TableName.Users),
|
||||||
@@ -384,22 +401,25 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
const findOrgMembersByRole = async (orgId: string, role: OrgMembershipRole, tx?: Knex) => {
|
const findOrgMembersByRole = async (orgId: string, role: OrgMembershipRole, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const conn = tx || db.replicaNode();
|
const conn = tx || db.replicaNode();
|
||||||
const members = await conn(TableName.OrgMembership)
|
const members = await conn(TableName.Membership)
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.where(`${TableName.OrgMembership}.role`, role)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
|
.where(`${TableName.MembershipRole}.role`, role)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.leftJoin<TUserEncryptionKeys>(
|
.leftJoin<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
conn.ref("id").withSchema(TableName.OrgMembership),
|
conn.ref("id").withSchema(TableName.Membership),
|
||||||
conn.ref("inviteEmail").withSchema(TableName.OrgMembership),
|
conn.ref("inviteEmail").withSchema(TableName.Membership),
|
||||||
conn.ref("orgId").withSchema(TableName.OrgMembership),
|
conn.ref("orgId").withSchema(TableName.Membership),
|
||||||
conn.ref("role").withSchema(TableName.OrgMembership),
|
conn.ref("role").withSchema(TableName.MembershipRole),
|
||||||
conn.ref("roleId").withSchema(TableName.OrgMembership),
|
conn.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
conn.ref("status").withSchema(TableName.OrgMembership),
|
conn.ref("status").withSchema(TableName.Membership),
|
||||||
conn.ref("username").withSchema(TableName.Users),
|
conn.ref("username").withSchema(TableName.Users),
|
||||||
conn.ref("email").withSchema(TableName.Users),
|
conn.ref("email").withSchema(TableName.Users),
|
||||||
conn.ref("firstName").withSchema(TableName.Users),
|
conn.ref("firstName").withSchema(TableName.Users),
|
||||||
@@ -418,47 +438,6 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findOrgGhostUser = async (orgId: string) => {
|
|
||||||
try {
|
|
||||||
const member = await db
|
|
||||||
.replicaNode()(TableName.OrgMembership)
|
|
||||||
.where({ orgId })
|
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
|
||||||
.leftJoin(TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id`)
|
|
||||||
.select(
|
|
||||||
db.ref("id").withSchema(TableName.OrgMembership),
|
|
||||||
db.ref("orgId").withSchema(TableName.OrgMembership),
|
|
||||||
db.ref("role").withSchema(TableName.OrgMembership),
|
|
||||||
db.ref("roleId").withSchema(TableName.OrgMembership),
|
|
||||||
db.ref("status").withSchema(TableName.OrgMembership),
|
|
||||||
db.ref("email").withSchema(TableName.Users),
|
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
|
||||||
db.ref("publicKey").withSchema(TableName.UserEncryptionKey)
|
|
||||||
)
|
|
||||||
.where({ isGhost: true })
|
|
||||||
.first();
|
|
||||||
return member;
|
|
||||||
} catch (error) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const ghostUserExists = async (orgId: string) => {
|
|
||||||
try {
|
|
||||||
const member = await db
|
|
||||||
.replicaNode()(TableName.OrgMembership)
|
|
||||||
.where({ orgId })
|
|
||||||
.join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
|
||||||
.leftJoin(TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id`)
|
|
||||||
.select(db.ref("id").withSchema(TableName.Users).as("userId"))
|
|
||||||
.where({ isGhost: true })
|
|
||||||
.first();
|
|
||||||
return Boolean(member);
|
|
||||||
} catch (error) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const create = async (dto: TOrganizationsInsert, tx?: Knex) => {
|
const create = async (dto: TOrganizationsInsert, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const [organization] = await (tx || db)(TableName.Organization).insert(dto).returning("*");
|
const [organization] = await (tx || db)(TableName.Organization).insert(dto).returning("*");
|
||||||
@@ -491,38 +470,37 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
// MEMBERSHIP OPERATIONS
|
// MEMBERSHIP OPERATIONS
|
||||||
// --------------------
|
// --------------------
|
||||||
// const orgMembershipOrm = ormify(db, TableName.OrgMembership);
|
|
||||||
|
|
||||||
const createMembership = async (data: TOrgMembershipsInsert, tx?: Knex) => {
|
const createMembership = async (data: TMembershipsInsert, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const [membership] = await (tx || db)(TableName.OrgMembership).insert(data).returning("*");
|
const [membership] = await (tx || db)(TableName.Membership).insert(data).returning("*");
|
||||||
return membership;
|
return membership;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Create org membership" });
|
throw new DatabaseError({ error, name: "Create org membership" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const bulkCreateMemberships = async (data: TOrgMembershipsInsert[], tx?: Knex) => {
|
const bulkCreateMemberships = async (data: TMembershipsInsert[], tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const memberships = await (tx || db)(TableName.OrgMembership).insert(data).returning("*");
|
const memberships = await (tx || db)(TableName.Membership).insert(data).returning("*");
|
||||||
return memberships;
|
return memberships;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Create org memberships" });
|
throw new DatabaseError({ error, name: "Create org memberships" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMembershipById = async (id: string, data: TOrgMembershipsUpdate, tx?: Knex) => {
|
const updateMembershipById = async (id: string, data: TMembershipsUpdate, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const [membership] = await (tx || db)(TableName.OrgMembership).where({ id }).update(data).returning("*");
|
const [membership] = await (tx || db)(TableName.Membership).where({ id }).update(data).returning("*");
|
||||||
return membership;
|
return membership;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Update org membership" });
|
throw new DatabaseError({ error, name: "Update org membership" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateMembership = async (filter: Partial<TOrgMemberships>, data: TOrgMembershipsUpdate, tx?: Knex) => {
|
const updateMembership = async (filter: Partial<TMemberships>, data: TMembershipsUpdate, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const membership = await (tx || db)(TableName.OrgMembership).where(filter).update(data).returning("*");
|
const membership = await (tx || db)(TableName.Membership).where(filter).update(data).returning("*");
|
||||||
return membership;
|
return membership;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Update org memberships" });
|
throw new DatabaseError({ error, name: "Update org memberships" });
|
||||||
@@ -531,7 +509,10 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const deleteMembershipById = async (id: string, orgId: string, tx?: Knex) => {
|
const deleteMembershipById = async (id: string, orgId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const [membership] = await (tx || db)(TableName.OrgMembership).where({ id, orgId }).delete().returning("*");
|
const [membership] = await (tx || db)(TableName.Membership)
|
||||||
|
.where({ id, scopeOrgId: orgId, scope: AccessScope.Organization })
|
||||||
|
.delete()
|
||||||
|
.returning("*");
|
||||||
return membership;
|
return membership;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Delete org membership" });
|
throw new DatabaseError({ error, name: "Delete org membership" });
|
||||||
@@ -540,9 +521,10 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const deleteMembershipsById = async (ids: string[], orgId: string, tx?: Knex) => {
|
const deleteMembershipsById = async (ids: string[], orgId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const memberships = await (tx || db)(TableName.OrgMembership)
|
const memberships = await (tx || db)(TableName.Membership)
|
||||||
.where({
|
.where({
|
||||||
orgId
|
scopeOrgId: orgId,
|
||||||
|
scope: AccessScope.Organization
|
||||||
})
|
})
|
||||||
.whereIn("id", ids)
|
.whereIn("id", ids)
|
||||||
.delete()
|
.delete()
|
||||||
@@ -554,22 +536,23 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const findMembership = async (
|
const findMembership = async (
|
||||||
filter: TFindFilter<TOrgMemberships>,
|
filter: TFindFilter<TMemberships>,
|
||||||
{ offset, limit, sort, tx }: TFindOpt<TOrgMemberships> = {}
|
{ offset, limit, sort, tx }: TFindOpt<TMemberships> = {}
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const query = (tx || db.replicaNode())(TableName.OrgMembership)
|
const query = (tx || db.replicaNode())(TableName.Membership)
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
.where(buildFindFilter(filter))
|
.where(buildFindFilter(filter))
|
||||||
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.OrgMembership}.userId`)
|
.where("scope", AccessScope.Organization)
|
||||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.OrgMembership}.orgId`)
|
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.leftJoin(TableName.UserAliases, function joinUserAlias() {
|
.leftJoin(TableName.UserAliases, function joinUserAlias() {
|
||||||
this.on(`${TableName.UserAliases}.userId`, "=", `${TableName.OrgMembership}.userId`)
|
this.on(`${TableName.UserAliases}.userId`, "=", `${TableName.Membership}.actorUserId`)
|
||||||
.andOn(`${TableName.UserAliases}.orgId`, "=", `${TableName.OrgMembership}.orgId`)
|
.andOn(`${TableName.UserAliases}.orgId`, "=", `${TableName.Membership}.scopeOrgId`)
|
||||||
.andOn(`${TableName.UserAliases}.aliasType`, "=", (tx || db).raw("?", ["saml"]));
|
.andOn(`${TableName.UserAliases}.aliasType`, "=", (tx || db).raw("?", ["saml"]));
|
||||||
})
|
})
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.OrgMembership),
|
selectAllTableCols(TableName.Membership),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
db.ref("isEmailVerified").withSchema(TableName.Users),
|
db.ref("isEmailVerified").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
@@ -595,18 +578,20 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
const findMembershipWithScimFilter = async (
|
const findMembershipWithScimFilter = async (
|
||||||
orgId: string,
|
orgId: string,
|
||||||
scimFilter: string | undefined,
|
scimFilter: string | undefined,
|
||||||
{ offset, limit, sort, tx }: TFindOpt<TOrgMemberships> = {}
|
{ offset, limit, sort, tx }: TFindOpt<TMemberships> = {}
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const query = (tx || db.replicaNode())(TableName.OrgMembership)
|
const query = (tx || db.replicaNode())(TableName.Membership)
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
.where(`${TableName.OrgMembership}.orgId`, orgId)
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
if (scimFilter) {
|
if (scimFilter) {
|
||||||
void generateKnexQueryFromScim(qb, scimFilter, (attrPath) => {
|
void generateKnexQueryFromScim(qb, scimFilter, (attrPath) => {
|
||||||
switch (attrPath) {
|
switch (attrPath) {
|
||||||
case "active":
|
case "active":
|
||||||
return `${TableName.OrgMembership}.isActive`;
|
return `${TableName.Membership}.isActive`;
|
||||||
case "userName":
|
case "userName":
|
||||||
return `${TableName.UserAliases}.externalId`;
|
return `${TableName.UserAliases}.externalId`;
|
||||||
case "name.givenName":
|
case "name.givenName":
|
||||||
@@ -621,15 +606,15 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.OrgMembership}.userId`)
|
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.Membership}.actorUserId`)
|
||||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.OrgMembership}.orgId`)
|
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.leftJoin(TableName.UserAliases, function joinUserAlias() {
|
.leftJoin(TableName.UserAliases, function joinUserAlias() {
|
||||||
this.on(`${TableName.UserAliases}.userId`, "=", `${TableName.OrgMembership}.userId`)
|
this.on(`${TableName.UserAliases}.userId`, "=", `${TableName.Membership}.actorUserId`)
|
||||||
.andOn(`${TableName.UserAliases}.orgId`, "=", `${TableName.OrgMembership}.orgId`)
|
.andOn(`${TableName.UserAliases}.orgId`, "=", `${TableName.Membership}.scopeOrgId`)
|
||||||
.andOn(`${TableName.UserAliases}.aliasType`, "=", (tx || db).raw("?", ["saml"]));
|
.andOn(`${TableName.UserAliases}.aliasType`, "=", (tx || db).raw("?", ["saml"]));
|
||||||
})
|
})
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.OrgMembership),
|
selectAllTableCols(TableName.Membership),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
db.ref("isEmailVerified").withSchema(TableName.Users),
|
db.ref("isEmailVerified").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
@@ -653,18 +638,22 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(simp): resolve this role field later
|
||||||
const findIdentityOrganization = async (
|
const findIdentityOrganization = async (
|
||||||
identityId: string
|
identityId: string
|
||||||
): Promise<{ id: string; name: string; slug: string; role: string }> => {
|
): Promise<{ id: string; name: string; slug: string; role: string }> => {
|
||||||
try {
|
try {
|
||||||
const org = await db
|
const org = await db
|
||||||
.replicaNode()(TableName.IdentityOrgMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where({ identityId })
|
.where({ actorIdentityId: identityId })
|
||||||
.join(TableName.Organization, `${TableName.IdentityOrgMembership}.orgId`, `${TableName.Organization}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
|
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
|
||||||
.select(db.ref("id").withSchema(TableName.Organization).as("id"))
|
.select(db.ref("id").withSchema(TableName.Organization).as("id"))
|
||||||
.select(db.ref("name").withSchema(TableName.Organization).as("name"))
|
.select(db.ref("name").withSchema(TableName.Organization).as("name"))
|
||||||
.select(db.ref("slug").withSchema(TableName.Organization).as("slug"))
|
.select(db.ref("slug").withSchema(TableName.Organization).as("slug"))
|
||||||
.select(db.ref("role").withSchema(TableName.IdentityOrgMembership).as("role"));
|
.select(db.ref("role").withSchema(TableName.MembershipRole).as("role"));
|
||||||
|
|
||||||
return org?.[0];
|
return org?.[0];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -681,10 +670,8 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
findOrgBySlug,
|
findOrgBySlug,
|
||||||
findAllOrgsByUserId,
|
findAllOrgsByUserId,
|
||||||
findOrganizationsByFilter,
|
findOrganizationsByFilter,
|
||||||
ghostUserExists,
|
|
||||||
findOrgMembersByUsername,
|
findOrgMembersByUsername,
|
||||||
findOrgMembersByRole,
|
findOrgMembersByRole,
|
||||||
findOrgGhostUser,
|
|
||||||
create,
|
create,
|
||||||
updateById,
|
updateById,
|
||||||
deleteById,
|
deleteById,
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TOrgRoleDALFactory = ReturnType<typeof orgRoleDALFactory>;
|
|
||||||
|
|
||||||
export const orgRoleDALFactory = (db: TDbClient) => ormify(db, TableName.OrgRoles);
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import { OrgMembershipRole } from "@app/db/schemas";
|
import { OrgMembershipRole } from "@app/db/schemas";
|
||||||
import { TFeatureSet } from "@app/ee/services/license/license-types";
|
import { TFeatureSet } from "@app/ee/services/license/license-types";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { TOrgRoleDALFactory } from "@app/services/org/org-role-dal";
|
|
||||||
|
import { TRoleDALFactory } from "../role/role-dal";
|
||||||
|
|
||||||
const RESERVED_ORG_ROLE_SLUGS = Object.values(OrgMembershipRole).filter((role) => role !== "custom");
|
const RESERVED_ORG_ROLE_SLUGS = Object.values(OrgMembershipRole).filter((role) => role !== "custom");
|
||||||
|
|
||||||
@@ -10,13 +11,13 @@ export const isCustomOrgRole = (roleSlug: string) => !RESERVED_ORG_ROLE_SLUGS.fi
|
|||||||
// this is only for updating an org
|
// this is only for updating an org
|
||||||
export const getDefaultOrgMembershipRoleForUpdateOrg = async ({
|
export const getDefaultOrgMembershipRoleForUpdateOrg = async ({
|
||||||
membershipRoleSlug,
|
membershipRoleSlug,
|
||||||
orgRoleDAL,
|
roleDAL,
|
||||||
plan,
|
plan,
|
||||||
orgId
|
orgId
|
||||||
}: {
|
}: {
|
||||||
orgId: string;
|
orgId: string;
|
||||||
membershipRoleSlug: string;
|
membershipRoleSlug: string;
|
||||||
orgRoleDAL: TOrgRoleDALFactory;
|
roleDAL: TRoleDALFactory;
|
||||||
plan: TFeatureSet;
|
plan: TFeatureSet;
|
||||||
}) => {
|
}) => {
|
||||||
if (isCustomOrgRole(membershipRoleSlug)) {
|
if (isCustomOrgRole(membershipRoleSlug)) {
|
||||||
@@ -26,7 +27,7 @@ export const getDefaultOrgMembershipRoleForUpdateOrg = async ({
|
|||||||
"Failed to set custom default role due to plan RBAC restriction. Upgrade plan to set custom default org membership role."
|
"Failed to set custom default role due to plan RBAC restriction. Upgrade plan to set custom default org membership role."
|
||||||
});
|
});
|
||||||
|
|
||||||
const customRole = await orgRoleDAL.findOne({ slug: membershipRoleSlug, orgId });
|
const customRole = await roleDAL.findOne({ slug: membershipRoleSlug, orgId });
|
||||||
if (!customRole) {
|
if (!customRole) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
name: "UpdateOrg",
|
name: "UpdateOrg",
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
|||||||
import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal";
|
import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal";
|
||||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
|
|
||||||
import { ActorAuthMethod } from "../auth/auth-type";
|
import { ActorAuthMethod, ActorType } from "../auth/auth-type";
|
||||||
import { TOrgRoleDALFactory } from "./org-role-dal";
|
import { TOrgRoleDALFactory } from "./org-role-dal";
|
||||||
|
|
||||||
type TOrgRoleServiceFactoryDep = {
|
type TOrgRoleServiceFactoryDep = {
|
||||||
@@ -224,13 +224,14 @@ export const orgRoleServiceFactory = ({
|
|||||||
actorAuthMethod: ActorAuthMethod,
|
actorAuthMethod: ActorAuthMethod,
|
||||||
actorOrgId: string | undefined
|
actorOrgId: string | undefined
|
||||||
) => {
|
) => {
|
||||||
const { permission, membership } = await permissionService.getUserOrgPermission(
|
const { permission, memberships } = await permissionService.getOrgPermission(
|
||||||
|
ActorType.USER,
|
||||||
userId,
|
userId,
|
||||||
orgId,
|
orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
);
|
||||||
return { permissions: packRules(permission.rules), membership };
|
return { permissions: packRules(permission.rules), memberships };
|
||||||
};
|
};
|
||||||
|
|
||||||
return { createRole, getRole, updateRole, deleteRole, listRoles, getUserPermission };
|
return { createRole, getRole, updateRole, deleteRole, listRoles, getUserPermission };
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ import { TIncidentContactsDALFactory } from "./incident-contacts-dal";
|
|||||||
import { TOrgBotDALFactory } from "./org-bot-dal";
|
import { TOrgBotDALFactory } from "./org-bot-dal";
|
||||||
import { TOrgDALFactory } from "./org-dal";
|
import { TOrgDALFactory } from "./org-dal";
|
||||||
import { deleteOrgMembershipFn, deleteOrgMembershipsFn } from "./org-fns";
|
import { deleteOrgMembershipFn, deleteOrgMembershipsFn } from "./org-fns";
|
||||||
import { TOrgRoleDALFactory } from "./org-role-dal";
|
|
||||||
import {
|
import {
|
||||||
TDeleteOrgMembershipDTO,
|
TDeleteOrgMembershipDTO,
|
||||||
TDeleteOrgMembershipsDTO,
|
TDeleteOrgMembershipsDTO,
|
||||||
@@ -92,6 +91,7 @@ import {
|
|||||||
TUpgradePrivilegeSystemDTO,
|
TUpgradePrivilegeSystemDTO,
|
||||||
TVerifyUserToOrgDTO
|
TVerifyUserToOrgDTO
|
||||||
} from "./org-types";
|
} from "./org-types";
|
||||||
|
import { TRoleDALFactory } from "../role/role-dal";
|
||||||
|
|
||||||
type TOrgServiceFactoryDep = {
|
type TOrgServiceFactoryDep = {
|
||||||
userAliasDAL: Pick<TUserAliasDALFactory, "delete">;
|
userAliasDAL: Pick<TUserAliasDALFactory, "delete">;
|
||||||
@@ -100,7 +100,7 @@ type TOrgServiceFactoryDep = {
|
|||||||
folderDAL: Pick<TSecretFolderDALFactory, "findByProjectId">;
|
folderDAL: Pick<TSecretFolderDALFactory, "findByProjectId">;
|
||||||
orgDAL: TOrgDALFactory;
|
orgDAL: TOrgDALFactory;
|
||||||
orgBotDAL: TOrgBotDALFactory;
|
orgBotDAL: TOrgBotDALFactory;
|
||||||
orgRoleDAL: TOrgRoleDALFactory;
|
roleDAL: TRoleDALFactory;
|
||||||
userDAL: TUserDALFactory;
|
userDAL: TUserDALFactory;
|
||||||
groupDAL: TGroupDALFactory;
|
groupDAL: TGroupDALFactory;
|
||||||
projectDAL: TProjectDALFactory;
|
projectDAL: TProjectDALFactory;
|
||||||
@@ -154,7 +154,7 @@ export const orgServiceFactory = ({
|
|||||||
folderDAL,
|
folderDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
groupDAL,
|
groupDAL,
|
||||||
orgRoleDAL,
|
roleDAL,
|
||||||
incidentContactDAL,
|
incidentContactDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
smtpService,
|
smtpService,
|
||||||
@@ -185,7 +185,7 @@ export const orgServiceFactory = ({
|
|||||||
actorAuthMethod: ActorAuthMethod,
|
actorAuthMethod: ActorAuthMethod,
|
||||||
actorOrgId: string | undefined
|
actorOrgId: string | undefined
|
||||||
) => {
|
) => {
|
||||||
await permissionService.getUserOrgPermission(userId, orgId, actorAuthMethod, actorOrgId);
|
await permissionService.getOrgPermission(ActorType.USER, userId, orgId, actorAuthMethod, actorOrgId);
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
const org = await orgDAL.findOrgById(orgId);
|
||||||
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
||||||
@@ -221,7 +221,13 @@ export const orgServiceFactory = ({
|
|||||||
actorAuthMethod: ActorAuthMethod,
|
actorAuthMethod: ActorAuthMethod,
|
||||||
actorOrgId: string | undefined
|
actorOrgId: string | undefined
|
||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
ActorType.USER,
|
||||||
|
userId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
||||||
|
|
||||||
const members = await orgDAL.findAllOrgMembers(orgId);
|
const members = await orgDAL.findAllOrgMembers(orgId);
|
||||||
@@ -323,9 +329,15 @@ export const orgServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
orgId
|
orgId
|
||||||
}: TUpgradePrivilegeSystemDTO) => {
|
}: TUpgradePrivilegeSystemDTO) => {
|
||||||
const { membership } = await permissionService.getUserOrgPermission(actorId, orgId, actorAuthMethod, actorOrgId);
|
const { hasRole } = await permissionService.getOrgPermission(
|
||||||
|
ActorType.USER,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
|
||||||
if (membership.role !== OrgMembershipRole.Admin) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({
|
throw new ForbiddenRequestError({
|
||||||
message: "Insufficient privileges - only the organization admin can upgrade the privilege system."
|
message: "Insufficient privileges - only the organization admin can upgrade the privilege system."
|
||||||
});
|
});
|
||||||
@@ -531,7 +543,7 @@ export const orgServiceFactory = ({
|
|||||||
defaultMembershipRole = await getDefaultOrgMembershipRoleForUpdateOrg({
|
defaultMembershipRole = await getDefaultOrgMembershipRoleForUpdateOrg({
|
||||||
membershipRoleSlug: defaultMembershipRoleSlug,
|
membershipRoleSlug: defaultMembershipRoleSlug,
|
||||||
orgId,
|
orgId,
|
||||||
orgRoleDAL,
|
roleDAL,
|
||||||
plan
|
plan
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -659,8 +671,14 @@ export const orgServiceFactory = ({
|
|||||||
actorAuthMethod: ActorAuthMethod;
|
actorAuthMethod: ActorAuthMethod;
|
||||||
actorOrgId: string | undefined;
|
actorOrgId: string | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
const { membership } = await permissionService.getUserOrgPermission(userId, orgId, actorAuthMethod, actorOrgId);
|
const { hasRole } = await permissionService.getOrgPermission(
|
||||||
if ((membership.role as OrgMembershipRole) !== OrgMembershipRole.Admin) {
|
ActorType.USER,
|
||||||
|
userId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({
|
throw new ForbiddenRequestError({
|
||||||
name: "DeleteOrganizationById",
|
name: "DeleteOrganizationById",
|
||||||
message: "Insufficient privileges"
|
message: "Insufficient privileges"
|
||||||
@@ -739,7 +757,13 @@ export const orgServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
metadata
|
metadata
|
||||||
}: TUpdateOrgMembershipDTO) => {
|
}: TUpdateOrgMembershipDTO) => {
|
||||||
const { permission } = await permissionService.getUserOrgPermission(userId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
|
ActorType.USER,
|
||||||
|
userId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
);
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member);
|
||||||
|
|
||||||
const foundMembership = await orgMembershipDAL.findById(membershipId);
|
const foundMembership = await orgMembershipDAL.findById(membershipId);
|
||||||
@@ -754,7 +778,7 @@ export const orgServiceFactory = ({
|
|||||||
let userRole = role;
|
let userRole = role;
|
||||||
let userRoleId: string | null = null;
|
let userRoleId: string | null = null;
|
||||||
if (role && isCustomRole) {
|
if (role && isCustomRole) {
|
||||||
const customRole = await orgRoleDAL.findOne({ slug: role, orgId });
|
const customRole = await roleDAL.findOne({ slug: role, orgId });
|
||||||
if (!customRole) throw new BadRequestError({ name: "UpdateMembership", message: "Organization role not found" });
|
if (!customRole) throw new BadRequestError({ name: "UpdateMembership", message: "Organization role not found" });
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -768,16 +792,16 @@ export const orgServiceFactory = ({
|
|||||||
}
|
}
|
||||||
const membership = await orgDAL.transaction(async (tx) => {
|
const membership = await orgDAL.transaction(async (tx) => {
|
||||||
const [updatedOrgMembership] = await orgDAL.updateMembership(
|
const [updatedOrgMembership] = await orgDAL.updateMembership(
|
||||||
{ id: membershipId, orgId },
|
{ id: membershipId, scopeOrgId: orgId },
|
||||||
{ role: userRole, roleId: userRoleId, isActive }
|
{ role: userRole, roleId: userRoleId, isActive }
|
||||||
);
|
);
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
await identityMetadataDAL.delete({ userId: updatedOrgMembership.userId, orgId }, tx);
|
await identityMetadataDAL.delete({ userId: updatedOrgMembership.actorUserId, orgId }, tx);
|
||||||
if (metadata.length) {
|
if (metadata.length) {
|
||||||
await identityMetadataDAL.insertMany(
|
await identityMetadataDAL.insertMany(
|
||||||
metadata.map(({ key, value }) => ({
|
metadata.map(({ key, value }) => ({
|
||||||
userId: updatedOrgMembership.userId,
|
userId: updatedOrgMembership.actorUserId as string,
|
||||||
orgId,
|
orgId,
|
||||||
key,
|
key,
|
||||||
value
|
value
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TProjectBots, TUserEncryptionKeys } from "@app/db/schemas";
|
import { AccessScope, TableName, TProjectBots, TUserEncryptionKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -44,12 +44,13 @@ export const projectBotDALFactory = (db: TDbClient) => {
|
|||||||
const findProjectUserWorkspaceKey = async (projectId: string) => {
|
const findProjectUserWorkspaceKey = async (projectId: string) => {
|
||||||
try {
|
try {
|
||||||
const doc = await db
|
const doc = await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where(`${TableName.ProjectMembership}.projectId` as "projectId", projectId)
|
.where(`${TableName.Membership}.scopeProjectId` as "projectId", projectId)
|
||||||
.where(`${TableName.ProjectKeys}.projectId` as "projectId", projectId)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.where(`${TableName.Users}.isGhost` as "isGhost", false)
|
.where(`${TableName.Users}.isGhost` as "isGhost", false)
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.join(TableName.ProjectKeys, `${TableName.ProjectMembership}.userId`, `${TableName.ProjectKeys}.receiverId`)
|
.join(TableName.ProjectKeys, `${TableName.Membership}.actorUserId`, `${TableName.ProjectKeys}.receiverId`)
|
||||||
|
.where(`${TableName.ProjectKeys}.projectId` as "projectId", projectId)
|
||||||
.join<TUserEncryptionKeys>(
|
.join<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TProjectKeys } from "@app/db/schemas";
|
import { AccessScope, TableName, TProjectKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||||
|
|
||||||
@@ -34,9 +34,10 @@ export const projectKeyDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const findAllProjectUserPubKeys = async (projectId: string, tx?: Knex) => {
|
const findAllProjectUserPubKeys = async (projectId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const pubKeys = await (tx || db.replicaNode())(TableName.ProjectMembership)
|
const pubKeys = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where({ projectId })
|
.where(`${TableName.Membership}.scopeProjectId` as "projectId", projectId)
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`)
|
.join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`)
|
||||||
.select("userId", "publicKey");
|
.select("userId", "publicKey");
|
||||||
return pubKeys;
|
return pubKeys;
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName, TUserEncryptionKeys } from "@app/db/schemas";
|
import { AccessScope, TableName, TMemberships, TUserEncryptionKeys } from "@app/db/schemas";
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
import { DatabaseError } from "@app/lib/errors";
|
||||||
import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TProjectMembershipDALFactory = ReturnType<typeof projectMembershipDALFactory>;
|
export type TProjectMembershipDALFactory = ReturnType<typeof projectMembershipDALFactory>;
|
||||||
|
|
||||||
export const projectMembershipDALFactory = (db: TDbClient) => {
|
export const projectMembershipDALFactory = (db: TDbClient) => {
|
||||||
const projectMemberOrm = ormify(db, TableName.ProjectMembership);
|
|
||||||
|
|
||||||
// special query
|
// special query
|
||||||
const findAllProjectMembers = async (
|
const findAllProjectMembers = async (
|
||||||
projectId: string,
|
projectId: string,
|
||||||
@@ -17,18 +15,17 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where({ [`${TableName.ProjectMembership}.projectId` as "projectId"]: projectId })
|
.where({ [`${TableName.Membership}.scopeProjectId` as "scopeProjectId"]: projectId })
|
||||||
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where({ [`${TableName.Membership}.scope` as "scope"]: AccessScope.Project })
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.join(TableName.OrgMembership, (qb) => {
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
qb.on(`${TableName.Users}.id`, "=", `${TableName.OrgMembership}.userId`).andOn(
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
`${TableName.OrgMembership}.orgId`,
|
.join<TMemberships>(db(TableName.Membership).as("orgMembership"), (qb) => {
|
||||||
"=",
|
qb.on(`${TableName.Users}.id`, "=", `orgMembership.actorUserId`)
|
||||||
`${TableName.Project}.orgId`
|
.andOn(`orgMembership.scopeOrgId`, "=", `${TableName.Project}.orgId`)
|
||||||
);
|
.andOn("orgMembership.scope", AccessScope.Organization);
|
||||||
})
|
})
|
||||||
|
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
if (filter.usernames) {
|
if (filter.usernames) {
|
||||||
void qb.whereIn("username", filter.usernames);
|
void qb.whereIn("username", filter.usernames);
|
||||||
@@ -37,28 +34,24 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
void qb.where("username", filter.username);
|
void qb.where("username", filter.username);
|
||||||
}
|
}
|
||||||
if (filter.id) {
|
if (filter.id) {
|
||||||
void qb.where(`${TableName.ProjectMembership}.id`, filter.id);
|
void qb.where(`${TableName.Membership}.id`, filter.id);
|
||||||
}
|
}
|
||||||
if (filter.roles && filter.roles.length > 0) {
|
if (filter.roles && filter.roles.length > 0) {
|
||||||
void qb.whereExists((subQuery) => {
|
void qb.whereExists((subQuery) => {
|
||||||
void subQuery
|
void subQuery
|
||||||
.select("role")
|
.select("role")
|
||||||
.from(TableName.ProjectUserMembershipRole)
|
.from(TableName.MembershipRole)
|
||||||
.leftJoin(
|
.leftJoin(TableName.Role, `${TableName.Role}.id`, `${TableName.MembershipRole}.customRoleId`)
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.ProjectRoles}.id`,
|
|
||||||
`${TableName.ProjectUserMembershipRole}.customRoleId`
|
|
||||||
)
|
|
||||||
.whereRaw("??.?? = ??.??", [
|
.whereRaw("??.?? = ??.??", [
|
||||||
TableName.ProjectUserMembershipRole,
|
TableName.MembershipRole,
|
||||||
"projectMembershipId",
|
"projectMembershipId",
|
||||||
TableName.ProjectMembership,
|
TableName.Membership,
|
||||||
"id"
|
"id"
|
||||||
])
|
])
|
||||||
.where((subQb) => {
|
.where((subQb) => {
|
||||||
void subQb
|
void subQb
|
||||||
.whereIn(`${TableName.ProjectUserMembershipRole}.role`, filter.roles as string[])
|
.whereIn(`${TableName.MembershipRole}.role`, filter.roles as string[])
|
||||||
.orWhereIn(`${TableName.ProjectRoles}.slug`, filter.roles as string[]);
|
.orWhereIn(`${TableName.Role}.slug`, filter.roles as string[]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -68,19 +61,11 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.join(
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
TableName.ProjectUserMembershipRole,
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
`${TableName.ProjectUserMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.ProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.ProjectUserMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.ProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("createdAt").withSchema(TableName.ProjectMembership),
|
db.ref("createdAt").withSchema(TableName.Membership),
|
||||||
db.ref("isGhost").withSchema(TableName.Users),
|
db.ref("isGhost").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
@@ -88,18 +73,18 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
db.ref("lastName").withSchema(TableName.Users),
|
db.ref("lastName").withSchema(TableName.Users),
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
db.ref("id").withSchema(TableName.Users).as("userId"),
|
||||||
db.ref("role").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.ProjectUserMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").as("projectName").withSchema(TableName.Project),
|
db.ref("name").as("projectName").withSchema(TableName.Project),
|
||||||
db.ref("isActive").withSchema(TableName.OrgMembership)
|
db.ref("isActive").withSchema("orgMembership")
|
||||||
)
|
)
|
||||||
.where({ isGhost: false })
|
.where({ isGhost: false })
|
||||||
.orderBy(`${TableName.Users}.username` as "username");
|
.orderBy(`${TableName.Users}.username` as "username");
|
||||||
@@ -184,9 +169,11 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const findProjectGhostUser = async (projectId: string, tx?: Knex) => {
|
const findProjectGhostUser = async (projectId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const ghostUser = await (tx || db.replicaNode())(TableName.ProjectMembership)
|
const ghostUser = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where({ projectId })
|
.where({ [`${TableName.Membership}.scopeProjectId` as "scopeProjectId"]: projectId })
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.where({ [`${TableName.Membership}.scope` as "scope"]: AccessScope.Project })
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.select(selectAllTableCols(TableName.Users))
|
.select(selectAllTableCols(TableName.Users))
|
||||||
.where({ isGhost: true })
|
.where({ isGhost: true })
|
||||||
.first();
|
.first();
|
||||||
@@ -200,21 +187,24 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const findMembershipsByUsername = async (projectId: string, usernames: string[]) => {
|
const findMembershipsByUsername = async (projectId: string, usernames: string[]) => {
|
||||||
try {
|
try {
|
||||||
const members = await db
|
const members = await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where({ projectId })
|
.where({ [`${TableName.Membership}.scopeProjectId` as "scopeProjectId"]: projectId })
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.where({ [`${TableName.Membership}.scope` as "scope"]: AccessScope.Project })
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.join<TUserEncryptionKeys>(
|
.join<TUserEncryptionKeys>(
|
||||||
TableName.UserEncryptionKey,
|
TableName.UserEncryptionKey,
|
||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.ProjectMembership),
|
selectAllTableCols(TableName.Membership),
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
db.ref("id").withSchema(TableName.Users).as("userId"),
|
||||||
db.ref("username").withSchema(TableName.Users)
|
db.ref("username").withSchema(TableName.Users)
|
||||||
)
|
)
|
||||||
.whereIn("username", usernames)
|
.whereIn("username", usernames)
|
||||||
.where({ isGhost: false });
|
.where({ isGhost: false });
|
||||||
|
|
||||||
return members.map(({ userId, username, ...data }) => ({
|
return members.map(({ userId, username, ...data }) => ({
|
||||||
...data,
|
...data,
|
||||||
user: { id: userId, username }
|
user: { id: userId, username }
|
||||||
@@ -227,9 +217,11 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const findProjectMembershipsByUserId = async (orgId: string, userId: string) => {
|
const findProjectMembershipsByUserId = async (orgId: string, userId: string) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where({ [`${TableName.Membership}.scope` as "scope"]: AccessScope.Project })
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.Users}.id`, userId)
|
.where(`${TableName.Users}.id`, userId)
|
||||||
.where(`${TableName.Project}.orgId`, orgId)
|
.where(`${TableName.Project}.orgId`, orgId)
|
||||||
.join<TUserEncryptionKeys>(
|
.join<TUserEncryptionKeys>(
|
||||||
@@ -237,18 +229,10 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.join(
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
TableName.ProjectUserMembershipRole,
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
`${TableName.ProjectUserMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.ProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.ProjectUserMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.ProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("isGhost").withSchema(TableName.Users),
|
db.ref("isGhost").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
@@ -256,16 +240,16 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
db.ref("lastName").withSchema(TableName.Users),
|
db.ref("lastName").withSchema(TableName.Users),
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
db.ref("id").withSchema(TableName.Users).as("userId"),
|
||||||
db.ref("role").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.ProjectUserMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").as("projectName").withSchema(TableName.Project),
|
db.ref("name").as("projectName").withSchema(TableName.Project),
|
||||||
db.ref("id").as("projectId").withSchema(TableName.Project),
|
db.ref("id").as("projectId").withSchema(TableName.Project),
|
||||||
db.ref("type").as("projectType").withSchema(TableName.Project)
|
db.ref("type").as("projectType").withSchema(TableName.Project)
|
||||||
@@ -336,9 +320,11 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
const findProjectMembershipsByUserIds = async (orgId: string, userIds: string[]) => {
|
const findProjectMembershipsByUserIds = async (orgId: string, userIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
const docs = await db
|
const docs = await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where({ [`${TableName.Membership}.scope` as "scope"]: AccessScope.Project })
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.whereIn(`${TableName.Users}.id`, userIds)
|
.whereIn(`${TableName.Users}.id`, userIds)
|
||||||
.where(`${TableName.Project}.orgId`, orgId)
|
.where(`${TableName.Project}.orgId`, orgId)
|
||||||
.join<TUserEncryptionKeys>(
|
.join<TUserEncryptionKeys>(
|
||||||
@@ -346,18 +332,10 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
`${TableName.UserEncryptionKey}.userId`,
|
`${TableName.UserEncryptionKey}.userId`,
|
||||||
`${TableName.Users}.id`
|
`${TableName.Users}.id`
|
||||||
)
|
)
|
||||||
.join(
|
.join(TableName.MembershipRole, `${TableName.MembershipRole}.membershipId`, `${TableName.Membership}.id`)
|
||||||
TableName.ProjectUserMembershipRole,
|
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
|
||||||
`${TableName.ProjectUserMembershipRole}.projectMembershipId`,
|
|
||||||
`${TableName.ProjectMembership}.id`
|
|
||||||
)
|
|
||||||
.leftJoin(
|
|
||||||
TableName.ProjectRoles,
|
|
||||||
`${TableName.ProjectUserMembershipRole}.customRoleId`,
|
|
||||||
`${TableName.ProjectRoles}.id`
|
|
||||||
)
|
|
||||||
.select(
|
.select(
|
||||||
db.ref("id").withSchema(TableName.ProjectMembership),
|
db.ref("id").withSchema(TableName.Membership),
|
||||||
db.ref("isGhost").withSchema(TableName.Users),
|
db.ref("isGhost").withSchema(TableName.Users),
|
||||||
db.ref("username").withSchema(TableName.Users),
|
db.ref("username").withSchema(TableName.Users),
|
||||||
db.ref("email").withSchema(TableName.Users),
|
db.ref("email").withSchema(TableName.Users),
|
||||||
@@ -365,16 +343,16 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("firstName").withSchema(TableName.Users),
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
db.ref("lastName").withSchema(TableName.Users),
|
db.ref("lastName").withSchema(TableName.Users),
|
||||||
db.ref("id").withSchema(TableName.Users).as("userId"),
|
db.ref("id").withSchema(TableName.Users).as("userId"),
|
||||||
db.ref("role").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("role").withSchema(TableName.MembershipRole),
|
||||||
db.ref("id").withSchema(TableName.ProjectUserMembershipRole).as("membershipRoleId"),
|
db.ref("id").withSchema(TableName.MembershipRole).as("membershipRoleId"),
|
||||||
db.ref("customRoleId").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").withSchema(TableName.ProjectRoles).as("customRoleName"),
|
db.ref("name").withSchema(TableName.Role).as("customRoleName"),
|
||||||
db.ref("slug").withSchema(TableName.ProjectRoles).as("customRoleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("customRoleSlug"),
|
||||||
db.ref("temporaryMode").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryMode").withSchema(TableName.MembershipRole),
|
||||||
db.ref("isTemporary").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("isTemporary").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryRange").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryRange").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessStartTime").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryAccessStartTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("temporaryAccessEndTime").withSchema(TableName.ProjectUserMembershipRole),
|
db.ref("temporaryAccessEndTime").withSchema(TableName.MembershipRole),
|
||||||
db.ref("name").as("projectName").withSchema(TableName.Project),
|
db.ref("name").as("projectName").withSchema(TableName.Project),
|
||||||
db.ref("id").as("projectId").withSchema(TableName.Project),
|
db.ref("id").as("projectId").withSchema(TableName.Project),
|
||||||
db.ref("type").as("projectType").withSchema(TableName.Project)
|
db.ref("type").as("projectType").withSchema(TableName.Project)
|
||||||
@@ -444,7 +422,6 @@ export const projectMembershipDALFactory = (db: TDbClient) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...projectMemberOrm,
|
|
||||||
findAllProjectMembers,
|
findAllProjectMembers,
|
||||||
findProjectGhostUser,
|
findProjectGhostUser,
|
||||||
findMembershipsByUsername,
|
findMembershipsByUsername,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* eslint-disable no-await-in-loop */
|
/* eslint-disable no-await-in-loop */
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType, ProjectMembershipRole, ProjectVersion, TableName } from "@app/db/schemas";
|
import { AccessScope, ActionProjectType, ProjectMembershipRole, ProjectVersion, TableName } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import {
|
import {
|
||||||
constructPermissionErrorMessage,
|
constructPermissionErrorMessage,
|
||||||
@@ -41,21 +41,25 @@ import {
|
|||||||
TUpdateProjectMembershipDTO
|
TUpdateProjectMembershipDTO
|
||||||
} from "./project-membership-types";
|
} from "./project-membership-types";
|
||||||
import { TProjectUserMembershipRoleDALFactory } from "./project-user-membership-role-dal";
|
import { TProjectUserMembershipRoleDALFactory } from "./project-user-membership-role-dal";
|
||||||
|
import { TRoleDALFactory } from "../role/role-dal";
|
||||||
|
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
|
||||||
|
import { TMembershipDALFactory } from "../membership/membership-dal";
|
||||||
|
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
|
||||||
|
|
||||||
type TProjectMembershipServiceFactoryDep = {
|
type TProjectMembershipServiceFactoryDep = {
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRoles"| "invalidateProjectPermissionCache">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getProjectPermissionByRoles"| "invalidateProjectPermissionCache">;
|
||||||
smtpService: TSmtpService;
|
smtpService: TSmtpService;
|
||||||
projectBotDAL: TProjectBotDALFactory;
|
|
||||||
projectMembershipDAL: TProjectMembershipDALFactory;
|
projectMembershipDAL: TProjectMembershipDALFactory;
|
||||||
projectUserMembershipRoleDAL: Pick<TProjectUserMembershipRoleDALFactory, "insertMany" | "find" | "delete">;
|
membershipDAL: TMembershipDALFactory;
|
||||||
|
membershipRoleDAL: Pick<TMembershipRoleDALFactory, "insertMany" | "find" | "delete">;
|
||||||
userDAL: Pick<TUserDALFactory, "findById" | "findOne" | "findUserByProjectMembershipId" | "find">;
|
userDAL: Pick<TUserDALFactory, "findById" | "findOne" | "findUserByProjectMembershipId" | "find">;
|
||||||
userGroupMembershipDAL: TUserGroupMembershipDALFactory;
|
userGroupMembershipDAL: TUserGroupMembershipDALFactory;
|
||||||
projectRoleDAL: Pick<TProjectRoleDALFactory, "find" | "findOne">;
|
roleDAL: Pick<TRoleDALFactory, "find" | "findOne">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findMembership" | "findOrgMembersByUsername">;
|
orgDAL: Pick<TOrgDALFactory, "findMembership" | "findOrgMembersByUsername" | "findById">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findById" | "findProjectGhostUser" | "transaction" | "findProjectById">;
|
projectDAL: Pick<TProjectDALFactory, "findById" | "findProjectGhostUser" | "transaction" | "findProjectById">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "findLatestProjectKey" | "delete" | "insertMany">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "findLatestProjectKey" | "delete" | "insertMany">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
projectUserAdditionalPrivilegeDAL: Pick<TProjectUserAdditionalPrivilegeDALFactory, "delete">;
|
additionalPrivilegeDAL: Pick<TAdditionalPrivilegeDALFactory, "delete">;
|
||||||
secretReminderRecipientsDAL: Pick<TSecretReminderRecipientsDALFactory, "delete">;
|
secretReminderRecipientsDAL: Pick<TSecretReminderRecipientsDALFactory, "delete">;
|
||||||
groupProjectDAL: TGroupProjectDALFactory;
|
groupProjectDAL: TGroupProjectDALFactory;
|
||||||
notificationService: Pick<TNotificationServiceFactory, "createUserNotifications">;
|
notificationService: Pick<TNotificationServiceFactory, "createUserNotifications">;
|
||||||
@@ -68,9 +72,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
projectMembershipDAL,
|
projectMembershipDAL,
|
||||||
projectUserMembershipRoleDAL,
|
projectUserMembershipRoleDAL,
|
||||||
smtpService,
|
smtpService,
|
||||||
projectRoleDAL,
|
|
||||||
orgDAL,
|
orgDAL,
|
||||||
projectUserAdditionalPrivilegeDAL,
|
|
||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
@@ -78,7 +80,11 @@ export const projectMembershipServiceFactory = ({
|
|||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
secretReminderRecipientsDAL,
|
secretReminderRecipientsDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
notificationService
|
notificationService,
|
||||||
|
roleDAL,
|
||||||
|
membershipRoleDAL,
|
||||||
|
additionalPrivilegeDAL,
|
||||||
|
membershipDAL
|
||||||
}: TProjectMembershipServiceFactoryDep) => {
|
}: TProjectMembershipServiceFactoryDep) => {
|
||||||
const getProjectMemberships = async ({
|
const getProjectMemberships = async ({
|
||||||
actorId,
|
actorId,
|
||||||
@@ -170,6 +176,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
return membership;
|
return membership;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(simp): cross-check akhil
|
||||||
const addUsersToProject = async ({
|
const addUsersToProject = async ({
|
||||||
projectId,
|
projectId,
|
||||||
actorId,
|
actorId,
|
||||||
@@ -191,17 +198,20 @@ export const projectMembershipServiceFactory = ({
|
|||||||
actionProjectType: ActionProjectType.Any
|
actionProjectType: ActionProjectType.Any
|
||||||
});
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Create, ProjectPermissionSub.Member);
|
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionMemberActions.Create, ProjectPermissionSub.Member);
|
||||||
const orgMembers = await orgDAL.findMembership({
|
const orgMembers = await membershipDAL.find({
|
||||||
[`${TableName.OrgMembership}.orgId` as "orgId"]: project.orgId,
|
[`${TableName.Membership}.scopeOrgId` as "scopeOrgId"]: project.orgId,
|
||||||
|
scope: AccessScope.Organization,
|
||||||
$in: {
|
$in: {
|
||||||
[`${TableName.OrgMembership}.id` as "id"]: members.map(({ orgMembershipId }) => orgMembershipId)
|
[`${TableName.Membership}.id` as "id"]: members.map(({ orgMembershipId }) => orgMembershipId)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (orgMembers.length !== members.length) throw new BadRequestError({ message: "Some users are not part of org" });
|
if (orgMembers.length !== members.length) throw new BadRequestError({ message: "Some users are not part of org" });
|
||||||
|
|
||||||
const existingMembers = await projectMembershipDAL.find({
|
const existingMembers = await membershipDAL.find({
|
||||||
projectId,
|
[`${TableName.Membership}.scopeProjectId` as "scopeProjectId"]: projectId,
|
||||||
$in: { userId: orgMembers.map(({ userId }) => userId).filter(Boolean) }
|
scope: AccessScope.Project,
|
||||||
|
$in: { actorUserId: orgMembers.map(({ actorUserId }) => actorUserId).filter(Boolean) }
|
||||||
});
|
});
|
||||||
if (existingMembers.length) throw new BadRequestError({ message: "Some users are already part of project" });
|
if (existingMembers.length) throw new BadRequestError({ message: "Some users are already part of project" });
|
||||||
|
|
||||||
@@ -212,7 +222,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
await projectMembershipDAL.transaction(async (tx) => {
|
await membershipDAL.transaction(async (tx) => {
|
||||||
const projectMemberships = await projectMembershipDAL.insertMany(
|
const projectMemberships = await projectMembershipDAL.insertMany(
|
||||||
orgMembers.map(({ userId }) => ({
|
orgMembers.map(({ userId }) => ({
|
||||||
projectId,
|
projectId,
|
||||||
@@ -275,7 +285,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
membershipId,
|
membershipId,
|
||||||
roles
|
roles
|
||||||
}: TUpdateProjectMembershipDTO) => {
|
}: TUpdateProjectMembershipDTO) => {
|
||||||
const { permission, membership } = await permissionService.getProjectPermission({
|
const { permission, memberships } = await permissionService.getProjectPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
projectId,
|
projectId,
|
||||||
@@ -290,14 +300,14 @@ export const projectMembershipServiceFactory = ({
|
|||||||
throw new ForbiddenRequestError({ message: "Forbidden member update" });
|
throw new ForbiddenRequestError({ message: "Forbidden member update" });
|
||||||
}
|
}
|
||||||
|
|
||||||
for await (const { role: requestedRoleChange } of roles) {
|
const providedRolePermissionDetails = await permissionService.getProjectPermissionByRoles(
|
||||||
const { permission: rolePermission } = await permissionService.getProjectPermissionByRole(
|
roles.map((el) => el.role).filter((el) => el !== ProjectMembershipRole.NoAccess),
|
||||||
requestedRoleChange,
|
projectId
|
||||||
projectId
|
);
|
||||||
);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
|
||||||
|
for await (const { permission: rolePermission } of providedRolePermissionDetails) {
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
membership.shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
ProjectPermissionMemberActions.GrantPrivileges,
|
ProjectPermissionMemberActions.GrantPrivileges,
|
||||||
ProjectPermissionSub.Member,
|
ProjectPermissionSub.Member,
|
||||||
permission,
|
permission,
|
||||||
@@ -306,8 +316,8 @@ export const projectMembershipServiceFactory = ({
|
|||||||
if (!permissionBoundary.isValid)
|
if (!permissionBoundary.isValid)
|
||||||
throw new PermissionBoundaryError({
|
throw new PermissionBoundaryError({
|
||||||
message: constructPermissionErrorMessage(
|
message: constructPermissionErrorMessage(
|
||||||
`Failed to change role ${requestedRoleChange}`,
|
"Failed to assign to role",
|
||||||
membership.shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
ProjectPermissionMemberActions.GrantPrivileges,
|
ProjectPermissionMemberActions.GrantPrivileges,
|
||||||
ProjectPermissionSub.Member
|
ProjectPermissionSub.Member
|
||||||
),
|
),
|
||||||
@@ -322,7 +332,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
// we don't want to include custom in this check;
|
// we don't want to include custom in this check;
|
||||||
// this unintentionally enables setting slug to custom which is reserved
|
// this unintentionally enables setting slug to custom which is reserved
|
||||||
.filter((r) => r !== ProjectMembershipRole.Custom)
|
.filter((r) => r !== ProjectMembershipRole.Custom)
|
||||||
.includes(role as ProjectMembershipRole)
|
.includes(role as ProjectMembershipRole.Member)
|
||||||
);
|
);
|
||||||
const hasCustomRole = Boolean(customInputRoles.length);
|
const hasCustomRole = Boolean(customInputRoles.length);
|
||||||
if (hasCustomRole) {
|
if (hasCustomRole) {
|
||||||
@@ -334,7 +344,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const customRoles = hasCustomRole
|
const customRoles = hasCustomRole
|
||||||
? await projectRoleDAL.find({
|
? await roleDAL.find({
|
||||||
projectId,
|
projectId,
|
||||||
$in: { slug: customInputRoles.map(({ role }) => role) }
|
$in: { slug: customInputRoles.map(({ role }) => role) }
|
||||||
})
|
})
|
||||||
@@ -368,7 +378,7 @@ export const projectMembershipServiceFactory = ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatedRoles = await projectMembershipDAL.transaction(async (tx) => {
|
const updatedRoles = await membershipDAL.transaction(async (tx) => {
|
||||||
await projectUserMembershipRoleDAL.delete({ projectMembershipId: membershipId }, tx);
|
await projectUserMembershipRoleDAL.delete({ projectMembershipId: membershipId }, tx);
|
||||||
return projectUserMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
return projectUserMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TProjectRoleDALFactory = ReturnType<typeof projectRoleDALFactory>;
|
|
||||||
|
|
||||||
export const projectRoleDALFactory = (db: TDbClient) => ormify(db, TableName.ProjectRoles);
|
|
||||||
@@ -2,6 +2,7 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
ProjectsSchema,
|
ProjectsSchema,
|
||||||
ProjectType,
|
ProjectType,
|
||||||
ProjectUpgradeStatus,
|
ProjectUpgradeStatus,
|
||||||
@@ -24,10 +25,13 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const findIdentityProjects = async (identityId: string, orgId: string, projectType?: ProjectType) => {
|
const findIdentityProjects = async (identityId: string, orgId: string, projectType?: ProjectType) => {
|
||||||
try {
|
try {
|
||||||
const workspaces = await db(TableName.IdentityProjectMembership)
|
const workspaces = await db
|
||||||
.where({ identityId })
|
.replicaNode()(TableName.Membership)
|
||||||
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.where(`${TableName.Membership}.actorIdentityId`, identityId)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
.where(`${TableName.Project}.orgId`, orgId)
|
.where(`${TableName.Project}.orgId`, orgId)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
.andWhere((qb) => {
|
.andWhere((qb) => {
|
||||||
if (projectType) {
|
if (projectType) {
|
||||||
void qb.where(`${TableName.Project}.type`, projectType);
|
void qb.where(`${TableName.Project}.type`, projectType);
|
||||||
@@ -74,11 +78,23 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const findUserProjects = async (userId: string, orgId: string, projectType?: ProjectType) => {
|
const findUserProjects = async (userId: string, orgId: string, projectType?: ProjectType) => {
|
||||||
try {
|
try {
|
||||||
const workspaces = await db
|
const userGroupSubquery = db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Groups)
|
||||||
.where({ userId })
|
.leftJoin(TableName.UserGroupMembership, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
||||||
.join(TableName.Project, `${TableName.ProjectMembership}.projectId`, `${TableName.Project}.id`)
|
.where(`${TableName.Groups}.orgId`, orgId)
|
||||||
|
.where(`${TableName.UserGroupMembership}.userId`, userId)
|
||||||
|
.select(db.ref("id").withSchema(TableName.Groups));
|
||||||
|
|
||||||
|
const projects = await db
|
||||||
|
.replicaNode()(TableName.Membership)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
.where(`${TableName.Project}.orgId`, orgId)
|
.where(`${TableName.Project}.orgId`, orgId)
|
||||||
|
.andWhere((qb) => {
|
||||||
|
void qb
|
||||||
|
.where(`${TableName.Membership}.actorUserId`, userId)
|
||||||
|
.orWhereIn(`${TableName.Membership}.actorGroupId`, userGroupSubquery);
|
||||||
|
})
|
||||||
.andWhere((qb) => {
|
.andWhere((qb) => {
|
||||||
if (projectType) {
|
if (projectType) {
|
||||||
void qb.where(`${TableName.Project}.type`, projectType);
|
void qb.where(`${TableName.Project}.type`, projectType);
|
||||||
@@ -97,36 +113,8 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
{ column: `${TableName.Environment}.position`, order: "asc" }
|
{ column: `${TableName.Environment}.position`, order: "asc" }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const groups = db(TableName.UserGroupMembership).where({ userId }).select("groupId");
|
const formattedProjects = sqlNestRelationships({
|
||||||
|
data: projects,
|
||||||
const groupWorkspaces = await db(TableName.GroupProjectMembership)
|
|
||||||
.whereIn("groupId", groups)
|
|
||||||
.join(TableName.Project, `${TableName.GroupProjectMembership}.projectId`, `${TableName.Project}.id`)
|
|
||||||
.where(`${TableName.Project}.orgId`, orgId)
|
|
||||||
.andWhere((qb) => {
|
|
||||||
if (projectType) {
|
|
||||||
void qb.where(`${TableName.Project}.type`, projectType);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.whereNotIn(
|
|
||||||
`${TableName.Project}.id`,
|
|
||||||
workspaces.map(({ id }) => id)
|
|
||||||
)
|
|
||||||
.leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
|
|
||||||
.select(
|
|
||||||
selectAllTableCols(TableName.Project),
|
|
||||||
db.ref("id").withSchema(TableName.Project).as("_id"),
|
|
||||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
|
||||||
)
|
|
||||||
.orderBy([
|
|
||||||
{ column: `${TableName.Project}.name`, order: "asc" },
|
|
||||||
{ column: `${TableName.Environment}.position`, order: "asc" }
|
|
||||||
]);
|
|
||||||
|
|
||||||
const nestedWorkspaces = sqlNestRelationships({
|
|
||||||
data: workspaces.concat(groupWorkspaces),
|
|
||||||
key: "id",
|
key: "id",
|
||||||
parentMapper: ({ _id, ...el }) => ({ _id, ...ProjectsSchema.parse(el) }),
|
parentMapper: ({ _id, ...el }) => ({ _id, ...ProjectsSchema.parse(el) }),
|
||||||
childrenMapper: [
|
childrenMapper: [
|
||||||
@@ -142,7 +130,7 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
return nestedWorkspaces.map((workspace) => ({
|
return formattedProjects.map((workspace) => ({
|
||||||
...workspace,
|
...workspace,
|
||||||
organization: workspace.orgId
|
organization: workspace.orgId
|
||||||
}));
|
}));
|
||||||
@@ -153,9 +141,10 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const findProjectGhostUser = async (projectId: string, tx?: Knex) => {
|
const findProjectGhostUser = async (projectId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const ghostUser = await (tx || db.replicaNode())(TableName.ProjectMembership)
|
const ghostUser = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where({ projectId })
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scopeProjectId`, projectId)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.select(selectAllTableCols(TableName.Users))
|
.select(selectAllTableCols(TableName.Users))
|
||||||
.where({ isGhost: true })
|
.where({ isGhost: true })
|
||||||
.first();
|
.first();
|
||||||
@@ -177,54 +166,6 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findAllProjectsByIdentity = async (identityId: string, projectType?: ProjectType) => {
|
|
||||||
try {
|
|
||||||
const workspaces = await db
|
|
||||||
.replicaNode()(TableName.IdentityProjectMembership)
|
|
||||||
.where({ identityId })
|
|
||||||
.join(TableName.Project, `${TableName.IdentityProjectMembership}.projectId`, `${TableName.Project}.id`)
|
|
||||||
.andWhere((qb) => {
|
|
||||||
if (projectType) {
|
|
||||||
void qb.where(`${TableName.Project}.type`, projectType);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.leftJoin(TableName.Environment, `${TableName.Environment}.projectId`, `${TableName.Project}.id`)
|
|
||||||
.select(
|
|
||||||
selectAllTableCols(TableName.Project),
|
|
||||||
db.ref("id").withSchema(TableName.Project).as("_id"),
|
|
||||||
db.ref("id").withSchema(TableName.Environment).as("envId"),
|
|
||||||
db.ref("slug").withSchema(TableName.Environment).as("envSlug"),
|
|
||||||
db.ref("name").withSchema(TableName.Environment).as("envName")
|
|
||||||
)
|
|
||||||
.orderBy("createdAt", "asc", "last");
|
|
||||||
|
|
||||||
const nestedWorkspaces = sqlNestRelationships({
|
|
||||||
data: workspaces,
|
|
||||||
key: "id",
|
|
||||||
parentMapper: ({ _id, ...el }) => ({ _id, ...ProjectsSchema.parse(el) }),
|
|
||||||
childrenMapper: [
|
|
||||||
{
|
|
||||||
key: "envId",
|
|
||||||
label: "environments" as const,
|
|
||||||
mapper: ({ envId: id, envSlug: slug, envName: name }) => ({
|
|
||||||
id,
|
|
||||||
slug,
|
|
||||||
name
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// We need to add the organization field, as it's required for one of our API endpoint responses.
|
|
||||||
return nestedWorkspaces.map((workspace) => ({
|
|
||||||
...workspace,
|
|
||||||
organization: workspace.orgId
|
|
||||||
}));
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "Find all projects by identity" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const findProjectById = async (id: string) => {
|
const findProjectById = async (id: string) => {
|
||||||
try {
|
try {
|
||||||
const workspaces = await db
|
const workspaces = await db
|
||||||
@@ -402,18 +343,27 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
projectIds?: string[];
|
projectIds?: string[];
|
||||||
}) => {
|
}) => {
|
||||||
const { limit = 20, offset = 0, sortBy = SearchProjectSortBy.NAME, sortDir = SortDirection.ASC } = dto;
|
const { limit = 20, offset = 0, sortBy = SearchProjectSortBy.NAME, sortDir = SortDirection.ASC } = dto;
|
||||||
|
const groupMembershipSubquery = db(TableName.Groups)
|
||||||
|
.leftJoin(TableName.UserGroupMembership, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
||||||
|
.where(`${TableName.Groups}.orgId`, dto.orgId)
|
||||||
|
.where(`${TableName.UserGroupMembership}.userId`, dto.actorId)
|
||||||
|
.select(db.ref("id").withSchema(TableName.Groups));
|
||||||
|
const userMembershipSubquery = db(TableName.Membership)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.where((qb) => {
|
||||||
|
if (dto.actor === ActorType.IDENTITY) {
|
||||||
|
} else {
|
||||||
|
void qb
|
||||||
|
.where(`${TableName.Membership}.actorUserId`, dto.actorId)
|
||||||
|
.orWhereIn(`${TableName.Membership}.actorGroupId`, groupMembershipSubquery);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.select("scopeProjectId");
|
||||||
|
|
||||||
const userMembershipSubquery = db(TableName.ProjectMembership).where({ userId: dto.actorId }).select("projectId");
|
const identityMembershipSubQuery = db(TableName.Membership).where({ identityId: dto.actorId }).select("projectId");
|
||||||
const groups = db(TableName.UserGroupMembership).where({ userId: dto.actorId }).select("groupId");
|
|
||||||
const groupMembershipSubquery = db(TableName.GroupProjectMembership).whereIn("groupId", groups).select("projectId");
|
|
||||||
|
|
||||||
const identityMembershipSubQuery = db(TableName.IdentityProjectMembership)
|
|
||||||
.where({ identityId: dto.actorId })
|
|
||||||
.select("projectId");
|
|
||||||
|
|
||||||
// Get the SQL strings for the subqueries
|
// Get the SQL strings for the subqueries
|
||||||
const userMembershipSql = userMembershipSubquery.toQuery();
|
const userMembershipSql = userMembershipSubquery.toQuery();
|
||||||
const groupMembershipSql = groupMembershipSubquery.toQuery();
|
|
||||||
const identityMembershipSql = identityMembershipSubQuery.toQuery();
|
const identityMembershipSql = identityMembershipSubQuery.toQuery();
|
||||||
|
|
||||||
const query = db
|
const query = db
|
||||||
@@ -431,7 +381,7 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
ELSE FALSE
|
ELSE FALSE
|
||||||
END as "isMember"
|
END as "isMember"
|
||||||
`,
|
`,
|
||||||
[db.raw(userMembershipSql), db.raw(groupMembershipSql)]
|
[db.raw(userMembershipSql)]
|
||||||
)
|
)
|
||||||
: db.raw(
|
: db.raw(
|
||||||
`
|
`
|
||||||
@@ -495,7 +445,6 @@ export const projectDALFactory = (db: TDbClient) => {
|
|||||||
findUserProjects,
|
findUserProjects,
|
||||||
findIdentityProjects,
|
findIdentityProjects,
|
||||||
setProjectUpgradeStatus,
|
setProjectUpgradeStatus,
|
||||||
findAllProjectsByIdentity,
|
|
||||||
findProjectGhostUser,
|
findProjectGhostUser,
|
||||||
findProjectById,
|
findProjectById,
|
||||||
findProjectByFilter,
|
findProjectByFilter,
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ export const newNamespaceRoleFactory = (_dto: TNamespaceRoleScopeFactoryDep): TR
|
|||||||
throw new BadRequestError({ message: "Invalid scope provided for the factory" });
|
throw new BadRequestError({ message: "Invalid scope provided for the factory" });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isCustomRole: TRoleScopeFactory["isCustomRole"] = () => false;
|
||||||
|
|
||||||
|
const getPredefinedRoles: TRoleScopeFactory["getPredefinedRoles"] = async () => [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
onCreateRoleGuard,
|
onCreateRoleGuard,
|
||||||
onUpdateRoleGuard,
|
onUpdateRoleGuard,
|
||||||
@@ -36,6 +40,8 @@ export const newNamespaceRoleFactory = (_dto: TNamespaceRoleScopeFactoryDep): TR
|
|||||||
onListRoleGuard,
|
onListRoleGuard,
|
||||||
onGetRoleByIdGuard,
|
onGetRoleByIdGuard,
|
||||||
onGetRoleBySlugGuard,
|
onGetRoleBySlugGuard,
|
||||||
getScopeField
|
getScopeField,
|
||||||
|
isCustomRole,
|
||||||
|
getPredefinedRoles
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,18 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope } from "@app/db/schemas";
|
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 { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { TRoleScopeFactory } from "../role-types";
|
import { TRoleScopeFactory } from "../role-types";
|
||||||
|
import { isCustomOrgRole } from "@app/services/org/org-role-fns";
|
||||||
|
|
||||||
type TOrgRoleScopeFactoryDep = {
|
type TOrgRoleScopeFactoryDep = {
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
@@ -19,6 +26,8 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep
|
|||||||
throw new BadRequestError({ message: "Invalid scope provided for the factory" });
|
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 onCreateRoleGuard: TRoleScopeFactory["onCreateRoleGuard"] = async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission(
|
||||||
dto.permission.type,
|
dto.permission.type,
|
||||||
@@ -85,6 +94,42 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep
|
|||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
|
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 {
|
return {
|
||||||
onCreateRoleGuard,
|
onCreateRoleGuard,
|
||||||
onUpdateRoleGuard,
|
onUpdateRoleGuard,
|
||||||
@@ -92,6 +137,8 @@ export const newOrgRoleFactory = ({ permissionService }: TOrgRoleScopeFactoryDep
|
|||||||
onListRoleGuard,
|
onListRoleGuard,
|
||||||
onGetRoleByIdGuard,
|
onGetRoleByIdGuard,
|
||||||
onGetRoleBySlugGuard,
|
onGetRoleBySlugGuard,
|
||||||
getScopeField
|
getScopeField,
|
||||||
|
getPredefinedRoles,
|
||||||
|
isCustomRole
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,17 +1,35 @@
|
|||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import { ForbiddenError } from "@casl/ability";
|
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 { 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 { BadRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { TRoleScopeFactory } from "../role-types";
|
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 = {
|
type TProjectRoleScopeFactoryDep = {
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
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) => {
|
const getScopeField: TRoleScopeFactory["getScopeField"] = (dto) => {
|
||||||
if (dto.scope === AccessScope.Project) {
|
if (dto.scope === AccessScope.Project) {
|
||||||
return { key: "projectId" as const, value: dto.projectId };
|
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" });
|
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 onCreateRoleGuard: TRoleScopeFactory["onCreateRoleGuard"] = async (dto) => {
|
||||||
const scope = getScopeField(dto.scopeData);
|
const scope = getScopeField(dto.scopeData);
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
@@ -97,6 +117,78 @@ export const newProjectRoleFactory = ({ permissionService }: TProjectRoleScopeFa
|
|||||||
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Role);
|
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 {
|
return {
|
||||||
onCreateRoleGuard,
|
onCreateRoleGuard,
|
||||||
onUpdateRoleGuard,
|
onUpdateRoleGuard,
|
||||||
@@ -104,6 +196,8 @@ export const newProjectRoleFactory = ({ permissionService }: TProjectRoleScopeFa
|
|||||||
onListRoleGuard,
|
onListRoleGuard,
|
||||||
onGetRoleByIdGuard,
|
onGetRoleByIdGuard,
|
||||||
onGetRoleBySlugGuard,
|
onGetRoleBySlugGuard,
|
||||||
getScopeField
|
getScopeField,
|
||||||
|
getPredefinedRoles,
|
||||||
|
isCustomRole
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,20 +16,23 @@ import {
|
|||||||
TListRoleDTO,
|
TListRoleDTO,
|
||||||
TUpdateRoleDTO
|
TUpdateRoleDTO
|
||||||
} from "./role-types";
|
} from "./role-types";
|
||||||
|
import { TProjectDALFactory } from "../project/project-dal";
|
||||||
|
|
||||||
type TRoleServiceFactoryDep = {
|
type TRoleServiceFactoryDep = {
|
||||||
roleDAL: TRoleDALFactory;
|
roleDAL: TRoleDALFactory;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission" | "getOrgPermission">;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TRoleServiceFactory = ReturnType<typeof roleServiceFactory>;
|
export type TRoleServiceFactory = ReturnType<typeof roleServiceFactory>;
|
||||||
|
|
||||||
export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceFactoryDep) => {
|
export const roleServiceFactory = ({ roleDAL, permissionService, projectDAL }: TRoleServiceFactoryDep) => {
|
||||||
const orgRoleFactory = newOrgRoleFactory({
|
const orgRoleFactory = newOrgRoleFactory({
|
||||||
permissionService
|
permissionService
|
||||||
});
|
});
|
||||||
const projectRoleFactory = newProjectRoleFactory({
|
const projectRoleFactory = newProjectRoleFactory({
|
||||||
permissionService
|
permissionService,
|
||||||
|
projectDAL
|
||||||
});
|
});
|
||||||
const namespaceRoleFactory = newNamespaceRoleFactory({
|
const namespaceRoleFactory = newNamespaceRoleFactory({
|
||||||
permissionService
|
permissionService
|
||||||
@@ -130,6 +133,7 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
|||||||
await factory.onListRoleGuard(dto);
|
await factory.onListRoleGuard(dto);
|
||||||
|
|
||||||
const scope = factory.getScopeField(scopeData);
|
const scope = factory.getScopeField(scopeData);
|
||||||
|
const predefinedRoles = await factory.getPredefinedRoles(scopeData);
|
||||||
const roles = await roleDAL.find(
|
const roles = await roleDAL.find(
|
||||||
{
|
{
|
||||||
[scope.key]: scope.value
|
[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"]] }
|
{ 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) => {
|
const getRoleById = async (dto: TGetRoleByIdDTO) => {
|
||||||
@@ -163,6 +169,14 @@ export const roleServiceFactory = ({ roleDAL, permissionService }: TRoleServiceF
|
|||||||
await factory.onGetRoleBySlugGuard(dto);
|
await factory.onGetRoleBySlugGuard(dto);
|
||||||
|
|
||||||
const scope = factory.getScopeField(scopeData);
|
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({
|
const role = await roleDAL.findOne({
|
||||||
slug: selector.slug,
|
slug: selector.slug,
|
||||||
[scope.key]: scope.value
|
[scope.key]: scope.value
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import { AccessScopeData } from "@app/db/schemas";
|
import { AccessScopeData, TRoles } from "@app/db/schemas";
|
||||||
import { OrgServiceActor } from "@app/lib/types";
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
|
import { MongoAbility, RawRuleOf } from "@casl/ability";
|
||||||
|
|
||||||
export interface TRoleScopeFactory {
|
export interface TRoleScopeFactory {
|
||||||
onCreateRoleGuard: (arg: TCreateRoleDTO) => Promise<void>;
|
onCreateRoleGuard: (arg: TCreateRoleDTO) => Promise<void>;
|
||||||
onUpdateRoleGuard: (arg: TUpdateRoleDTO) => Promise<void>;
|
onUpdateRoleGuard: (arg: TUpdateRoleDTO) => Promise<void>;
|
||||||
onDeleteRoleGuard: (arg: TDeleteRoleDTO) => Promise<void>;
|
onDeleteRoleGuard: (arg: TDeleteRoleDTO) => Promise<void>;
|
||||||
onListRoleGuard: (arg: TListRoleDTO) => Promise<void>;
|
onListRoleGuard: (arg: TListRoleDTO) => Promise<void>;
|
||||||
|
getPredefinedRoles: (arg: AccessScopeData) => Promise<(TRoles & { permissions: RawRuleOf<MongoAbility>[] })[]>;
|
||||||
onGetRoleByIdGuard: (arg: TGetRoleByIdDTO) => Promise<void>;
|
onGetRoleByIdGuard: (arg: TGetRoleByIdDTO) => Promise<void>;
|
||||||
onGetRoleBySlugGuard: (arg: TGetRoleBySlugDTO) => Promise<void>;
|
onGetRoleBySlugGuard: (arg: TGetRoleBySlugDTO) => Promise<void>;
|
||||||
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
|
getScopeField: (scope: AccessScopeData) => { key: "orgId" | "namespaceId" | "projectId"; value: string };
|
||||||
|
isCustomRole: (role: string) => boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TCreateRoleDTO = {
|
export type TCreateRoleDTO = {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { TableName } from "@app/db/schemas";
|
import { AccessScope, TableName } from "@app/db/schemas";
|
||||||
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
import { ormify, selectAllTableCols } from "@app/lib/knex";
|
||||||
|
|
||||||
export type TSecretReminderRecipientsDALFactory = ReturnType<typeof secretReminderRecipientsDALFactory>;
|
export type TSecretReminderRecipientsDALFactory = ReturnType<typeof secretReminderRecipientsDALFactory>;
|
||||||
@@ -14,13 +14,13 @@ export const secretReminderRecipientsDALFactory = (db: TDbClient) => {
|
|||||||
.where({ secretId })
|
.where({ secretId })
|
||||||
.leftJoin(TableName.Users, `${TableName.SecretReminderRecipients}.userId`, `${TableName.Users}.id`)
|
.leftJoin(TableName.Users, `${TableName.SecretReminderRecipients}.userId`, `${TableName.Users}.id`)
|
||||||
.leftJoin(TableName.Project, `${TableName.SecretReminderRecipients}.projectId`, `${TableName.Project}.id`)
|
.leftJoin(TableName.Project, `${TableName.SecretReminderRecipients}.projectId`, `${TableName.Project}.id`)
|
||||||
.leftJoin(TableName.OrgMembership, (bd) => {
|
.leftJoin(TableName.Membership, (bd) => {
|
||||||
void bd
|
void bd
|
||||||
.on(`${TableName.OrgMembership}.userId`, "=", `${TableName.SecretReminderRecipients}.userId`)
|
.on(`${TableName.Membership}.actorUserId`, "=", `${TableName.SecretReminderRecipients}.userId`)
|
||||||
.andOn(`${TableName.OrgMembership}.orgId`, "=", `${TableName.Project}.orgId`);
|
.andOn(`${TableName.Membership}.scopeOrgId`, "=", `${TableName.Project}.orgId`)
|
||||||
|
.andOn(`${TableName.Membership}.scope`, db.raw("?", [AccessScope.Organization]));
|
||||||
})
|
})
|
||||||
|
.where(`${TableName.Membership}.isActive`, true)
|
||||||
.where(`${TableName.OrgMembership}.isActive`, true)
|
|
||||||
.select(selectAllTableCols(TableName.SecretReminderRecipients))
|
.select(selectAllTableCols(TableName.SecretReminderRecipients))
|
||||||
.select(
|
.select(
|
||||||
db.ref("email").withSchema(TableName.Users).as("email"),
|
db.ref("email").withSchema(TableName.Users).as("email"),
|
||||||
|
|||||||
@@ -2,7 +2,13 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import { SecretVersionsV2Schema, TableName, TSecretVersionsV2, TSecretVersionsV2Update } from "@app/db/schemas";
|
import {
|
||||||
|
AccessScope,
|
||||||
|
SecretVersionsV2Schema,
|
||||||
|
TableName,
|
||||||
|
TSecretVersionsV2,
|
||||||
|
TSecretVersionsV2Update
|
||||||
|
} from "@app/db/schemas";
|
||||||
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
import { BadRequestError, DatabaseError } from "@app/lib/errors";
|
||||||
import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindOpt } from "@app/lib/knex";
|
import { buildFindFilter, ormify, selectAllTableCols, sqlNestRelationships, TFindOpt } from "@app/lib/knex";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
@@ -191,11 +197,11 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => {
|
|||||||
const { offset, limit, sort = [["createdAt", "desc"]] } = findOpt;
|
const { offset, limit, sort = [["createdAt", "desc"]] } = findOpt;
|
||||||
const query = (tx || db.replicaNode())(TableName.SecretVersionV2)
|
const query = (tx || db.replicaNode())(TableName.SecretVersionV2)
|
||||||
.leftJoin(TableName.Users, `${TableName.Users}.id`, `${TableName.SecretVersionV2}.userActorId`)
|
.leftJoin(TableName.Users, `${TableName.Users}.id`, `${TableName.SecretVersionV2}.userActorId`)
|
||||||
.leftJoin(
|
.leftJoin(TableName.Membership, (qb) => {
|
||||||
TableName.ProjectMembership,
|
void qb
|
||||||
`${TableName.ProjectMembership}.userId`,
|
.on(`${TableName.Membership}.actorUserId`, `${TableName.SecretVersionV2}.userActorId`)
|
||||||
`${TableName.SecretVersionV2}.userActorId`
|
.andOn(`${TableName.Membership}.scope`, db.raw("?", [AccessScope.Project]));
|
||||||
)
|
})
|
||||||
.leftJoin(TableName.Identity, `${TableName.Identity}.id`, `${TableName.SecretVersionV2}.identityActorId`)
|
.leftJoin(TableName.Identity, `${TableName.Identity}.id`, `${TableName.SecretVersionV2}.identityActorId`)
|
||||||
.leftJoin(TableName.SecretV2, `${TableName.SecretVersionV2}.secretId`, `${TableName.SecretV2}.id`)
|
.leftJoin(TableName.SecretV2, `${TableName.SecretVersionV2}.secretId`, `${TableName.SecretV2}.id`)
|
||||||
.leftJoin(
|
.leftJoin(
|
||||||
@@ -210,19 +216,19 @@ export const secretVersionV2BridgeDALFactory = (db: TDbClient) => {
|
|||||||
)
|
)
|
||||||
.where((qb) => {
|
.where((qb) => {
|
||||||
void qb.where(`${TableName.SecretVersionV2}.secretId`, secretId);
|
void qb.where(`${TableName.SecretVersionV2}.secretId`, secretId);
|
||||||
void qb.where(`${TableName.ProjectMembership}.projectId`, projectId);
|
void qb.where(`${TableName.Membership}.scopeProjectId`, projectId);
|
||||||
if (secretVersions?.length) void qb.whereIn(`${TableName.SecretVersionV2}.version`, secretVersions);
|
if (secretVersions?.length) void qb.whereIn(`${TableName.SecretVersionV2}.version`, secretVersions);
|
||||||
})
|
})
|
||||||
.orWhere((qb) => {
|
.orWhere((qb) => {
|
||||||
void qb.where(`${TableName.SecretVersionV2}.secretId`, secretId);
|
void qb.where(`${TableName.SecretVersionV2}.secretId`, secretId);
|
||||||
void qb.whereNull(`${TableName.ProjectMembership}.projectId`);
|
void qb.whereNull(`${TableName.Membership}.actorProjectId`);
|
||||||
if (secretVersions?.length) void qb.whereIn(`${TableName.SecretVersionV2}.version`, secretVersions);
|
if (secretVersions?.length) void qb.whereIn(`${TableName.SecretVersionV2}.version`, secretVersions);
|
||||||
})
|
})
|
||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.SecretVersionV2),
|
selectAllTableCols(TableName.SecretVersionV2),
|
||||||
db.ref("username").withSchema(TableName.Users).as("userActorName"),
|
db.ref("username").withSchema(TableName.Users).as("userActorName"),
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityActorName"),
|
db.ref("name").withSchema(TableName.Identity).as("identityActorName"),
|
||||||
db.ref("id").withSchema(TableName.ProjectMembership).as("membershipId"),
|
db.ref("id").withSchema(TableName.Membership).as("membershipId"),
|
||||||
db.ref("id").withSchema(TableName.SecretTag).as("tagId"),
|
db.ref("id").withSchema(TableName.SecretTag).as("tagId"),
|
||||||
db.ref("color").withSchema(TableName.SecretTag).as("tagColor"),
|
db.ref("color").withSchema(TableName.SecretTag).as("tagColor"),
|
||||||
db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug")
|
db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug")
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Knex } from "knex";
|
|||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
import { TDbClient } from "@app/db";
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
TableName,
|
TableName,
|
||||||
TUserActionsInsert,
|
TUserActionsInsert,
|
||||||
TUserActionsUpdate,
|
TUserActionsUpdate,
|
||||||
@@ -127,9 +128,13 @@ export const userDALFactory = (db: TDbClient) => {
|
|||||||
const findUserByProjectMembershipId = async (projectMembershipId: string) => {
|
const findUserByProjectMembershipId = async (projectMembershipId: string) => {
|
||||||
try {
|
try {
|
||||||
return await db
|
return await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where({ [`${TableName.ProjectMembership}.id` as "id"]: projectMembershipId })
|
.where({
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
[`${TableName.Membership}.id` as "id"]: projectMembershipId,
|
||||||
|
[`${TableName.Membership}.scope` as "scope"]: AccessScope.Project
|
||||||
|
})
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.first();
|
.first();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find user by project membership id" });
|
throw new DatabaseError({ error, name: "Find user by project membership id" });
|
||||||
@@ -139,9 +144,11 @@ export const userDALFactory = (db: TDbClient) => {
|
|||||||
const findUsersByProjectMembershipIds = async (projectMembershipIds: string[]) => {
|
const findUsersByProjectMembershipIds = async (projectMembershipIds: string[]) => {
|
||||||
try {
|
try {
|
||||||
return await db
|
return await db
|
||||||
.replicaNode()(TableName.ProjectMembership)
|
.replicaNode()(TableName.Membership)
|
||||||
.whereIn(`${TableName.ProjectMembership}.id`, projectMembershipIds)
|
.whereIn(`${TableName.Membership}.id`, projectMembershipIds)
|
||||||
.join(TableName.Users, `${TableName.ProjectMembership}.userId`, `${TableName.Users}.id`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.select("*");
|
.select("*");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find users by project membership ids" });
|
throw new DatabaseError({ error, name: "Find users by project membership ids" });
|
||||||
@@ -191,8 +198,10 @@ export const userDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const doc = await db(TableName.Users)
|
const doc = await db(TableName.Users)
|
||||||
.where({ email })
|
.where({ email })
|
||||||
.leftJoin(TableName.OrgMembership, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`)
|
.leftJoin(TableName.Membership, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.leftJoin(TableName.Organization, `${TableName.Organization}.id`, `${TableName.OrgMembership}.orgId`)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.leftJoin(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.select(selectAllTableCols(TableName.Users))
|
.select(selectAllTableCols(TableName.Users))
|
||||||
.select(
|
.select(
|
||||||
db.ref("name").withSchema(TableName.Organization).as("orgName"),
|
db.ref("name").withSchema(TableName.Organization).as("orgName"),
|
||||||
|
|||||||
Reference in New Issue
Block a user