mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Convert pending group addition table into isPending field
This commit is contained in:
8
backend/src/@types/knex.d.ts
vendored
8
backend/src/@types/knex.d.ts
vendored
@@ -86,9 +86,6 @@ import {
|
|||||||
TOrgRoles,
|
TOrgRoles,
|
||||||
TOrgRolesInsert,
|
TOrgRolesInsert,
|
||||||
TOrgRolesUpdate,
|
TOrgRolesUpdate,
|
||||||
TPendingGroupAdditions,
|
|
||||||
TPendingGroupAdditionsInsert,
|
|
||||||
TPendingGroupAdditionsUpdate,
|
|
||||||
TProjectBots,
|
TProjectBots,
|
||||||
TProjectBotsInsert,
|
TProjectBotsInsert,
|
||||||
TProjectBotsUpdate,
|
TProjectBotsUpdate,
|
||||||
@@ -215,11 +212,6 @@ declare module "knex/types/tables" {
|
|||||||
interface Tables {
|
interface Tables {
|
||||||
[TableName.Users]: Knex.CompositeTableType<TUsers, TUsersInsert, TUsersUpdate>;
|
[TableName.Users]: Knex.CompositeTableType<TUsers, TUsersInsert, TUsersUpdate>;
|
||||||
[TableName.Groups]: Knex.CompositeTableType<TGroups, TGroupsInsert, TGroupsUpdate>;
|
[TableName.Groups]: Knex.CompositeTableType<TGroups, TGroupsInsert, TGroupsUpdate>;
|
||||||
[TableName.PendingGroupAddition]: Knex.CompositeTableType<
|
|
||||||
TPendingGroupAdditions,
|
|
||||||
TPendingGroupAdditionsInsert,
|
|
||||||
TPendingGroupAdditionsUpdate
|
|
||||||
>;
|
|
||||||
[TableName.UserGroupMembership]: Knex.CompositeTableType<
|
[TableName.UserGroupMembership]: Knex.CompositeTableType<
|
||||||
TUserGroupMembership,
|
TUserGroupMembership,
|
||||||
TUserGroupMembershipInsert,
|
TUserGroupMembershipInsert,
|
||||||
|
|||||||
@@ -1,25 +1,15 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
import { TableName } from "../schemas";
|
||||||
import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils";
|
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
export async function up(knex: Knex): Promise<void> {
|
||||||
if (!(await knex.schema.hasTable(TableName.PendingGroupAddition))) {
|
await knex.schema.alterTable(TableName.UserGroupMembership, (t) => {
|
||||||
await knex.schema.createTable(TableName.PendingGroupAddition, (t) => {
|
t.boolean("isPending").notNullable().defaultTo(false);
|
||||||
t.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid());
|
});
|
||||||
t.uuid("userId").notNullable();
|
|
||||||
t.foreign("userId").references("id").inTable(TableName.Users).onDelete("CASCADE");
|
|
||||||
t.uuid("groupId").notNullable();
|
|
||||||
t.foreign("groupId").references("id").inTable(TableName.Groups).onDelete("CASCADE");
|
|
||||||
t.unique(["userId", "groupId"]);
|
|
||||||
t.timestamps(true, true, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await createOnUpdateTrigger(knex, TableName.PendingGroupAddition);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
await knex.schema.dropTableIfExists(TableName.PendingGroupAddition);
|
await knex.schema.alterTable(TableName.UserGroupMembership, (t) => {
|
||||||
await dropOnUpdateTrigger(knex, TableName.PendingGroupAddition);
|
t.dropColumn("isPending");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ export * from "./org-bots";
|
|||||||
export * from "./org-memberships";
|
export * from "./org-memberships";
|
||||||
export * from "./org-roles";
|
export * from "./org-roles";
|
||||||
export * from "./organizations";
|
export * from "./organizations";
|
||||||
export * from "./pending-group-additions";
|
|
||||||
export * from "./project-bots";
|
export * from "./project-bots";
|
||||||
export * from "./project-environments";
|
export * from "./project-environments";
|
||||||
export * from "./project-keys";
|
export * from "./project-keys";
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { z } from "zod";
|
|||||||
export enum TableName {
|
export enum TableName {
|
||||||
Users = "users",
|
Users = "users",
|
||||||
Groups = "groups",
|
Groups = "groups",
|
||||||
PendingGroupAddition = "pending_group_additions",
|
|
||||||
GroupProjectMembership = "group_project_memberships",
|
GroupProjectMembership = "group_project_memberships",
|
||||||
GroupProjectMembershipRole = "group_project_membership_roles",
|
GroupProjectMembershipRole = "group_project_membership_roles",
|
||||||
UserGroupMembership = "user_group_membership",
|
UserGroupMembership = "user_group_membership",
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
// Code generated by automation script, DO NOT EDIT.
|
|
||||||
// Automated by pulling database and generating zod schema
|
|
||||||
// To update. Just run npm run generate:schema
|
|
||||||
// Written by akhilmhdh.
|
|
||||||
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
import { TImmutableDBKeys } from "./models";
|
|
||||||
|
|
||||||
export const PendingGroupAdditionsSchema = z.object({
|
|
||||||
id: z.string().uuid(),
|
|
||||||
userId: z.string().uuid(),
|
|
||||||
groupId: z.string().uuid(),
|
|
||||||
createdAt: z.date(),
|
|
||||||
updatedAt: z.date()
|
|
||||||
});
|
|
||||||
|
|
||||||
export type TPendingGroupAdditions = z.infer<typeof PendingGroupAdditionsSchema>;
|
|
||||||
export type TPendingGroupAdditionsInsert = Omit<z.input<typeof PendingGroupAdditionsSchema>, TImmutableDBKeys>;
|
|
||||||
export type TPendingGroupAdditionsUpdate = Partial<Omit<z.input<typeof PendingGroupAdditionsSchema>, TImmutableDBKeys>>;
|
|
||||||
@@ -12,7 +12,8 @@ export const UserGroupMembershipSchema = z.object({
|
|||||||
userId: z.string().uuid(),
|
userId: z.string().uuid(),
|
||||||
groupId: z.string().uuid(),
|
groupId: z.string().uuid(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date()
|
updatedAt: z.date(),
|
||||||
|
isPending: z.boolean().default(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TUserGroupMembership = z.infer<typeof UserGroupMembershipSchema>;
|
export type TUserGroupMembership = z.infer<typeof UserGroupMembershipSchema>;
|
||||||
|
|||||||
@@ -84,36 +84,14 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
db.raw("?", [groupId])
|
db.raw("?", [groupId])
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.leftJoin(TableName.PendingGroupAddition, function () {
|
.select(
|
||||||
this.on(`${TableName.PendingGroupAddition}.userId`, "=", `${TableName.Users}.id`).andOn(
|
|
||||||
`${TableName.PendingGroupAddition}.groupId`,
|
|
||||||
"=",
|
|
||||||
db.raw("?", [groupId])
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.select<
|
|
||||||
{
|
|
||||||
id: string;
|
|
||||||
groupId: string;
|
|
||||||
email: string;
|
|
||||||
username: string;
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
userId: string;
|
|
||||||
isPartOfGroup: boolean;
|
|
||||||
}[]
|
|
||||||
>(
|
|
||||||
db.ref("id").withSchema(TableName.OrgMembership),
|
db.ref("id").withSchema(TableName.OrgMembership),
|
||||||
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
db.ref("groupId").withSchema(TableName.UserGroupMembership),
|
||||||
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),
|
||||||
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.raw('CASE WHEN ?? IS NOT NULL OR ?? IS NOT NULL THEN TRUE ELSE FALSE END AS "isPartOfGroup"', [
|
|
||||||
`${TableName.UserGroupMembership}.groupId`,
|
|
||||||
`${TableName.PendingGroupAddition}.groupId`
|
|
||||||
])
|
|
||||||
)
|
)
|
||||||
.where({ isGhost: false })
|
.where({ isGhost: false })
|
||||||
.offset(offset);
|
.offset(offset);
|
||||||
@@ -128,14 +106,16 @@ export const groupDALFactory = (db: TDbClient) => {
|
|||||||
|
|
||||||
const members = await query;
|
const members = await query;
|
||||||
|
|
||||||
return members.map(({ email, username: memberUsername, firstName, lastName, userId, isPartOfGroup }) => ({
|
return members.map(
|
||||||
id: userId,
|
({ email, username: memberUsername, firstName, lastName, userId, groupId: memberGroupId }) => ({
|
||||||
email,
|
id: userId,
|
||||||
username: memberUsername,
|
email,
|
||||||
firstName,
|
username: memberUsername,
|
||||||
lastName,
|
firstName,
|
||||||
isPartOfGroup
|
lastName,
|
||||||
}));
|
isPartOfGroup: !!memberGroupId
|
||||||
|
})
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find all org members" });
|
throw new DatabaseError({ error, name: "Find all org members" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,24 +5,143 @@ import { decryptAsymmetric, encryptAsymmetric, infisicalSymmetricDecrypt } from
|
|||||||
import { BadRequestError, ScimRequestError } from "@app/lib/errors";
|
import { BadRequestError, ScimRequestError } from "@app/lib/errors";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
TAddUsersToGroup,
|
||||||
TAddUsersToGroupByUserIds,
|
TAddUsersToGroupByUserIds,
|
||||||
TAddUsersToGroupDirectly,
|
|
||||||
TAddUsersToPendingGroupAdditions,
|
|
||||||
TConvertPendingGroupAdditionsToGroupMemberships,
|
TConvertPendingGroupAdditionsToGroupMemberships,
|
||||||
TRemoveUsersFromGroupByUserIds,
|
TRemoveUsersFromGroupByUserIds
|
||||||
TRemoveUsersFromGroupDirectly,
|
|
||||||
TRemoveUsersFromPendingGroupAdditions
|
|
||||||
} from "./group-types";
|
} from "./group-types";
|
||||||
|
|
||||||
/**
|
const addAcceptedUsersToGroup = async ({
|
||||||
* Add users with usernames [usernames] to group [group] directly.
|
userIds,
|
||||||
* - Users must have finished completing their account and have private key(s).
|
|
||||||
* @param {group} group - group to add user(s) to
|
|
||||||
* @param {string[]} usernames - username(s) of user(s) to add to group
|
|
||||||
*/
|
|
||||||
export const addUsersToGroupDirectly = async ({
|
|
||||||
group,
|
group,
|
||||||
usernames,
|
userGroupMembershipDAL,
|
||||||
|
userDAL,
|
||||||
|
groupProjectDAL,
|
||||||
|
projectKeyDAL,
|
||||||
|
projectDAL,
|
||||||
|
projectBotDAL,
|
||||||
|
tx
|
||||||
|
}: TAddUsersToGroup) => {
|
||||||
|
console.log("addAcceptedUsersToGroup args: ", {
|
||||||
|
userIds,
|
||||||
|
group
|
||||||
|
});
|
||||||
|
const users = await userDAL.findUserEncKeyByUserIdsBatch(
|
||||||
|
{
|
||||||
|
userIds
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
await userGroupMembershipDAL.insertMany(
|
||||||
|
users.map((user) => ({
|
||||||
|
userId: user.userId,
|
||||||
|
groupId: group.id,
|
||||||
|
isPending: false
|
||||||
|
})),
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
// check which projects the group is part of
|
||||||
|
const projectIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
(
|
||||||
|
await groupProjectDAL.find(
|
||||||
|
{
|
||||||
|
groupId: group.id
|
||||||
|
},
|
||||||
|
{ tx }
|
||||||
|
)
|
||||||
|
).map((gp) => gp.projectId)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const keys = await projectKeyDAL.find(
|
||||||
|
{
|
||||||
|
$in: {
|
||||||
|
projectId: projectIds,
|
||||||
|
receiverId: users.map((u) => u.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ tx }
|
||||||
|
);
|
||||||
|
|
||||||
|
const userKeysSet = new Set(keys.map((k) => `${k.projectId}-${k.receiverId}`));
|
||||||
|
|
||||||
|
for await (const projectId of projectIds) {
|
||||||
|
const usersToAddProjectKeyFor = users.filter((u) => !userKeysSet.has(`${projectId}-${u.userId}`));
|
||||||
|
|
||||||
|
if (usersToAddProjectKeyFor.length) {
|
||||||
|
// there are users who need to be shared keys
|
||||||
|
// process adding bulk users to projects for each project individually
|
||||||
|
const ghostUser = await projectDAL.findProjectGhostUser(projectId, tx);
|
||||||
|
|
||||||
|
if (!ghostUser) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to find sudo user"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const ghostUserLatestKey = await projectKeyDAL.findLatestProjectKey(ghostUser.id, projectId, tx);
|
||||||
|
|
||||||
|
if (!ghostUserLatestKey) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to find sudo user latest key"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const bot = await projectBotDAL.findOne({ projectId }, tx);
|
||||||
|
|
||||||
|
if (!bot) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Failed to find bot"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const botPrivateKey = infisicalSymmetricDecrypt({
|
||||||
|
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
|
||||||
|
iv: bot.iv,
|
||||||
|
tag: bot.tag,
|
||||||
|
ciphertext: bot.encryptedPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const plaintextProjectKey = decryptAsymmetric({
|
||||||
|
ciphertext: ghostUserLatestKey.encryptedKey,
|
||||||
|
nonce: ghostUserLatestKey.nonce,
|
||||||
|
publicKey: ghostUserLatestKey.sender.publicKey,
|
||||||
|
privateKey: botPrivateKey
|
||||||
|
});
|
||||||
|
|
||||||
|
const projectKeysToAdd = usersToAddProjectKeyFor.map((user) => {
|
||||||
|
const { ciphertext: encryptedKey, nonce } = encryptAsymmetric(
|
||||||
|
plaintextProjectKey,
|
||||||
|
user.publicKey,
|
||||||
|
botPrivateKey
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
encryptedKey,
|
||||||
|
nonce,
|
||||||
|
senderId: ghostUser.id,
|
||||||
|
receiverId: user.userId,
|
||||||
|
projectId
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await projectKeyDAL.insertMany(projectKeysToAdd, tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add users with user ids [userIds] to group [group].
|
||||||
|
* - Users may or may not have finished completing their accounts; this function will
|
||||||
|
* handle both adding users to groups directly and via pending group additions.
|
||||||
|
* @param {group} group - group to add user(s) to
|
||||||
|
* @param {string[]} userIds - id(s) of user(s) to add to group
|
||||||
|
*/
|
||||||
|
export const addUsersToGroupByUserIds = async ({
|
||||||
|
group,
|
||||||
|
userIds,
|
||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
@@ -31,33 +150,27 @@ export const addUsersToGroupDirectly = async ({
|
|||||||
projectDAL,
|
projectDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
tx: outerTx
|
tx: outerTx
|
||||||
}: TAddUsersToGroupDirectly) => {
|
}: TAddUsersToGroupByUserIds) => {
|
||||||
const processAddition = async (tx: Knex) => {
|
const processAddition = async (tx: Knex) => {
|
||||||
const users = await userDAL.findUserEncKeyByUsernameBatch(
|
const foundMembers = await userDAL.find(
|
||||||
{
|
{
|
||||||
usernames
|
$in: {
|
||||||
|
id: userIds
|
||||||
|
}
|
||||||
},
|
},
|
||||||
tx
|
{ tx }
|
||||||
);
|
);
|
||||||
|
|
||||||
const usersUsernamesSet = new Set(users.map((u) => u.username));
|
const foundMembersIdsSet = new Set(foundMembers.map((member) => member.id));
|
||||||
usernames.forEach((username) => {
|
|
||||||
if (!usersUsernamesSet.has(username)) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `Failed to find user with username ${username}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const userIds = users.map((u) => {
|
const isCompleteMatch = userIds.every((userId) => foundMembersIdsSet.has(userId));
|
||||||
if (!u.isAccepted) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `User ${u.username} cannot be added to group because they have not confirmed their account`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.userId;
|
if (!isCompleteMatch) {
|
||||||
});
|
throw new ScimRequestError({
|
||||||
|
detail: "Members not found",
|
||||||
|
status: 404
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// check if user(s) group membership(s) already exists
|
// check if user(s) group membership(s) already exists
|
||||||
const existingUserGroupMemberships = await userGroupMembershipDAL.find(
|
const existingUserGroupMemberships = await userGroupMembershipDAL.find(
|
||||||
@@ -87,194 +200,6 @@ export const addUsersToGroupDirectly = async ({
|
|||||||
{ tx }
|
{ tx }
|
||||||
);
|
);
|
||||||
|
|
||||||
const existingUserOrgMembershipsUsernamesSet = new Set(existingUserOrgMemberships.map((u) => u.username));
|
|
||||||
|
|
||||||
usernames.forEach((username) => {
|
|
||||||
if (!existingUserOrgMembershipsUsernamesSet.has(username))
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `User ${username} is not part of the organization`
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
await userGroupMembershipDAL.insertMany(
|
|
||||||
userIds.map((userId) => ({
|
|
||||||
userId,
|
|
||||||
groupId: group.id
|
|
||||||
})),
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
|
|
||||||
// check which projects the group is part of
|
|
||||||
const projectIds = Array.from(
|
|
||||||
new Set(
|
|
||||||
(
|
|
||||||
await groupProjectDAL.find(
|
|
||||||
{
|
|
||||||
groupId: group.id
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
)
|
|
||||||
).map((gp) => gp.projectId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const keys = await projectKeyDAL.find(
|
|
||||||
{
|
|
||||||
$in: {
|
|
||||||
projectId: projectIds,
|
|
||||||
receiverId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const userKeysSet = new Set(keys.map((k) => `${k.projectId}-${k.receiverId}`));
|
|
||||||
|
|
||||||
for await (const projectId of projectIds) {
|
|
||||||
const usersToAddProjectKeyFor = users.filter((u) => !userKeysSet.has(`${projectId}-${u.userId}`));
|
|
||||||
|
|
||||||
if (usersToAddProjectKeyFor.length) {
|
|
||||||
// there are users who need to be shared keys
|
|
||||||
// process adding bulk users to projects for each project individually
|
|
||||||
const ghostUser = await projectDAL.findProjectGhostUser(projectId, tx);
|
|
||||||
|
|
||||||
if (!ghostUser) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Failed to find sudo user"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const ghostUserLatestKey = await projectKeyDAL.findLatestProjectKey(ghostUser.id, projectId, tx);
|
|
||||||
|
|
||||||
if (!ghostUserLatestKey) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Failed to find sudo user latest key"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const bot = await projectBotDAL.findOne({ projectId }, tx);
|
|
||||||
|
|
||||||
if (!bot) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: "Failed to find bot"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const botPrivateKey = infisicalSymmetricDecrypt({
|
|
||||||
keyEncoding: bot.keyEncoding as SecretKeyEncoding,
|
|
||||||
iv: bot.iv,
|
|
||||||
tag: bot.tag,
|
|
||||||
ciphertext: bot.encryptedPrivateKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const plaintextProjectKey = decryptAsymmetric({
|
|
||||||
ciphertext: ghostUserLatestKey.encryptedKey,
|
|
||||||
nonce: ghostUserLatestKey.nonce,
|
|
||||||
publicKey: ghostUserLatestKey.sender.publicKey,
|
|
||||||
privateKey: botPrivateKey
|
|
||||||
});
|
|
||||||
|
|
||||||
const projectKeysToAdd = usersToAddProjectKeyFor.map((user) => {
|
|
||||||
const { ciphertext: encryptedKey, nonce } = encryptAsymmetric(
|
|
||||||
plaintextProjectKey,
|
|
||||||
user.publicKey,
|
|
||||||
botPrivateKey
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
encryptedKey,
|
|
||||||
nonce,
|
|
||||||
senderId: ghostUser.id,
|
|
||||||
receiverId: user.userId,
|
|
||||||
projectId
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
await projectKeyDAL.insertMany(projectKeysToAdd, tx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (outerTx) {
|
|
||||||
return processAddition(outerTx);
|
|
||||||
}
|
|
||||||
return userDAL.transaction(async (tx) => {
|
|
||||||
return processAddition(tx);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add users with user ids [userIds] to group [group] via pending group additions.
|
|
||||||
* - Users must have not finished completing their accounts (i.e. they don't have private key(s) yet).
|
|
||||||
* @param {group} group - group to add user(s) to
|
|
||||||
* @param {string[]} userIds - id(s) of user(s) to add to group
|
|
||||||
*/
|
|
||||||
export const addUsersToPendingGroupAdditions = async ({
|
|
||||||
group,
|
|
||||||
userIds,
|
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
userDAL,
|
|
||||||
orgDAL,
|
|
||||||
tx: outerTx
|
|
||||||
}: TAddUsersToPendingGroupAdditions) => {
|
|
||||||
const processAddition = async (tx: Knex) => {
|
|
||||||
const users = await userDAL.find(
|
|
||||||
{
|
|
||||||
$in: {
|
|
||||||
id: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const usersUserIdsSet = new Set(users.map((u) => u.id));
|
|
||||||
userIds.forEach((userId) => {
|
|
||||||
if (!usersUserIdsSet.has(userId)) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `Failed to find user with id ${userId}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
users.map((u) => {
|
|
||||||
if (u.isAccepted) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `User ${u.username} cannot be added to a pending group addition because they have confirmed their account`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.id;
|
|
||||||
});
|
|
||||||
|
|
||||||
// check if user(s) pending group addition(s) already exist
|
|
||||||
const existingPendingGroupAdditions = await pendingGroupAdditionDAL.find(
|
|
||||||
{
|
|
||||||
groupId: group.id,
|
|
||||||
$in: {
|
|
||||||
userId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingPendingGroupAdditions.length) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `User(s) are already part of the group ${group.slug}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if all user(s) are part of the organization
|
|
||||||
const existingUserOrgMemberships = await orgDAL.findMembership(
|
|
||||||
{
|
|
||||||
orgId: group.orgId,
|
|
||||||
$in: {
|
|
||||||
userId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingUserOrgMembershipsUserIdsSet = new Set(existingUserOrgMemberships.map((u) => u.userId));
|
const existingUserOrgMembershipsUserIdsSet = new Set(existingUserOrgMemberships.map((u) => u.userId));
|
||||||
|
|
||||||
userIds.forEach((userId) => {
|
userIds.forEach((userId) => {
|
||||||
@@ -284,109 +209,45 @@ export const addUsersToPendingGroupAdditions = async ({
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
await pendingGroupAdditionDAL.insertMany(
|
const membersToAddToGroupNonPending: TUsers[] = [];
|
||||||
users.map((user) => ({
|
|
||||||
userId: user.id,
|
|
||||||
groupId: group.id
|
|
||||||
})),
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (outerTx) {
|
|
||||||
return processAddition(outerTx);
|
|
||||||
}
|
|
||||||
return userDAL.transaction(async (tx) => {
|
|
||||||
return processAddition(tx);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add users with user ids [userIds] to group [group].
|
|
||||||
* - Users may or may not have finished completing their accounts; this function will
|
|
||||||
* handle both adding users to groups directly and via pending group additions.
|
|
||||||
* @param {group} group - group to add user(s) to
|
|
||||||
* @param {string[]} userIds - id(s) of user(s) to add to group
|
|
||||||
*/
|
|
||||||
export const addUsersToGroupByUserIds = async ({
|
|
||||||
group,
|
|
||||||
userIds,
|
|
||||||
userDAL,
|
|
||||||
userGroupMembershipDAL,
|
|
||||||
orgDAL,
|
|
||||||
groupProjectDAL,
|
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
projectKeyDAL,
|
|
||||||
projectDAL,
|
|
||||||
projectBotDAL,
|
|
||||||
tx: outerTx
|
|
||||||
}: TAddUsersToGroupByUserIds) => {
|
|
||||||
const processAddition = async (tx: Knex) => {
|
|
||||||
const foundMembers = await userDAL.find({
|
|
||||||
$in: {
|
|
||||||
id: userIds
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const foundMembersIdsSet = new Set(foundMembers.map((member) => member.id));
|
|
||||||
|
|
||||||
const isCompleteMatch = userIds.every((userId) => foundMembersIdsSet.has(userId));
|
|
||||||
|
|
||||||
if (!isCompleteMatch) {
|
|
||||||
throw new ScimRequestError({
|
|
||||||
detail: "Members not found",
|
|
||||||
status: 404
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const membersToAddToGroupDirectly: TUsers[] = [];
|
|
||||||
const membersToAddToGroupPending: TUsers[] = [];
|
const membersToAddToGroupPending: TUsers[] = [];
|
||||||
|
|
||||||
foundMembers.forEach((member) => {
|
foundMembers.forEach((member) => {
|
||||||
if (member.isAccepted) {
|
if (member.isAccepted) {
|
||||||
// add accepted member to group
|
// add accepted member to group
|
||||||
membersToAddToGroupDirectly.push(member);
|
membersToAddToGroupNonPending.push(member);
|
||||||
} else {
|
} else {
|
||||||
// add incomplete member to pending group addition
|
// add incomplete member to pending group addition
|
||||||
membersToAddToGroupPending.push(member);
|
membersToAddToGroupPending.push(member);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let addedUsers: TUsers[] = [];
|
if (membersToAddToGroupNonPending.length) {
|
||||||
|
await addAcceptedUsersToGroup({
|
||||||
if (membersToAddToGroupDirectly.length) {
|
userIds: membersToAddToGroupNonPending.map((member) => member.id),
|
||||||
addedUsers = addedUsers.concat(
|
group,
|
||||||
await addUsersToGroupDirectly({
|
userDAL,
|
||||||
group,
|
userGroupMembershipDAL,
|
||||||
usernames: membersToAddToGroupDirectly.map((member) => member.username),
|
groupProjectDAL,
|
||||||
userDAL,
|
projectKeyDAL,
|
||||||
userGroupMembershipDAL,
|
projectDAL,
|
||||||
orgDAL,
|
projectBotDAL,
|
||||||
groupProjectDAL,
|
tx
|
||||||
projectKeyDAL,
|
});
|
||||||
projectDAL,
|
|
||||||
projectBotDAL,
|
|
||||||
tx
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (membersToAddToGroupPending.length) {
|
if (membersToAddToGroupPending.length) {
|
||||||
addedUsers = addedUsers.concat(
|
await userGroupMembershipDAL.insertMany(
|
||||||
await addUsersToPendingGroupAdditions({
|
membersToAddToGroupPending.map((member) => ({
|
||||||
group,
|
userId: member.id,
|
||||||
userIds: membersToAddToGroupPending.map((member) => member.id),
|
groupId: group.id,
|
||||||
pendingGroupAdditionDAL,
|
isPending: true
|
||||||
userDAL,
|
})),
|
||||||
orgDAL,
|
tx
|
||||||
tx
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return addedUsers;
|
return membersToAddToGroupNonPending.concat(membersToAddToGroupPending);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (outerTx) {
|
if (outerTx) {
|
||||||
@@ -399,185 +260,7 @@ export const addUsersToGroupByUserIds = async ({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove users with user ids [userIds] from group [group].
|
* Remove users with user ids [userIds] from group [group].
|
||||||
* - Users must be directly added to the group.
|
* - Users may be part of the group (non-pending + pending);
|
||||||
* @param {group} group - group to remove user(s) from
|
|
||||||
* @param {string[]} userIds - id(s) of user(s) to remove from group
|
|
||||||
*/
|
|
||||||
export const removeUsersFromGroupDirectly = async ({
|
|
||||||
group,
|
|
||||||
userIds,
|
|
||||||
userDAL,
|
|
||||||
userGroupMembershipDAL,
|
|
||||||
groupProjectDAL,
|
|
||||||
projectKeyDAL,
|
|
||||||
tx: outerTx
|
|
||||||
}: TRemoveUsersFromGroupDirectly) => {
|
|
||||||
const processRemoval = async (tx: Knex) => {
|
|
||||||
const users = await userDAL.find(
|
|
||||||
{
|
|
||||||
$in: {
|
|
||||||
id: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const usersUserIdsSet = new Set(users.map((u) => u.id));
|
|
||||||
userIds.forEach((userId) => {
|
|
||||||
if (!usersUserIdsSet.has(userId)) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `Failed to find user with id ${userId}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// check if user group membership already exists
|
|
||||||
const existingUserGroupMemberships = await userGroupMembershipDAL.find(
|
|
||||||
{
|
|
||||||
groupId: group.id,
|
|
||||||
$in: {
|
|
||||||
userId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingUserGroupMembershipsUserIdsSet = new Set(existingUserGroupMemberships.map((u) => u.userId));
|
|
||||||
|
|
||||||
userIds.forEach((userId) => {
|
|
||||||
if (!existingUserGroupMembershipsUserIdsSet.has(userId))
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `User(s) are not part of the group ${group.slug}`
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// check which projects the group is part of
|
|
||||||
const projectIds = Array.from(
|
|
||||||
new Set(
|
|
||||||
(
|
|
||||||
await groupProjectDAL.find(
|
|
||||||
{
|
|
||||||
groupId: group.id
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
)
|
|
||||||
).map((gp) => gp.projectId)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: this part can be optimized
|
|
||||||
for await (const userId of userIds) {
|
|
||||||
const t = await userGroupMembershipDAL.filterProjectsByUserMembership(userId, group.id, projectIds, tx);
|
|
||||||
const projectsToDeleteKeyFor = projectIds.filter((p) => !t.has(p));
|
|
||||||
|
|
||||||
if (projectsToDeleteKeyFor.length) {
|
|
||||||
await projectKeyDAL.delete(
|
|
||||||
{
|
|
||||||
receiverId: userId,
|
|
||||||
$in: {
|
|
||||||
projectId: projectsToDeleteKeyFor
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await userGroupMembershipDAL.delete(
|
|
||||||
{
|
|
||||||
groupId: group.id,
|
|
||||||
userId
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (outerTx) {
|
|
||||||
return processRemoval(outerTx);
|
|
||||||
}
|
|
||||||
return userDAL.transaction(async (tx) => {
|
|
||||||
return processRemoval(tx);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove users with user ids [userIds] from group [group] via pending group additions.
|
|
||||||
* - Users must have pending group additions to the group.
|
|
||||||
* @param {group} group - group to remove user(s) from
|
|
||||||
* @param {string[]} userIds - id(s) of user(s) to remove from group
|
|
||||||
*/
|
|
||||||
export const removeUsersFromPendingGroupAdditions = async ({
|
|
||||||
group,
|
|
||||||
userIds,
|
|
||||||
userDAL,
|
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
tx: outerTx
|
|
||||||
}: TRemoveUsersFromPendingGroupAdditions) => {
|
|
||||||
const processRemoval = async (tx: Knex) => {
|
|
||||||
const users = await userDAL.find(
|
|
||||||
{
|
|
||||||
$in: {
|
|
||||||
id: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const usersUserIdsSet = new Set(users.map((u) => u.id));
|
|
||||||
userIds.forEach((userId) => {
|
|
||||||
if (!usersUserIdsSet.has(userId)) {
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `Failed to find user with id ${userId}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// check if user pending group addition already exists
|
|
||||||
const existingPendingGroupAdditions = await pendingGroupAdditionDAL.find(
|
|
||||||
{
|
|
||||||
groupId: group.id,
|
|
||||||
$in: {
|
|
||||||
userId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ tx }
|
|
||||||
);
|
|
||||||
|
|
||||||
const existingPendingGroupAdditionsUserIdsSet = new Set(existingPendingGroupAdditions.map((u) => u.userId));
|
|
||||||
|
|
||||||
userIds.forEach((userId) => {
|
|
||||||
if (!existingPendingGroupAdditionsUserIdsSet.has(userId))
|
|
||||||
throw new BadRequestError({
|
|
||||||
message: `User(s) are not part of the group ${group.slug}`
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
await pendingGroupAdditionDAL.delete(
|
|
||||||
{
|
|
||||||
groupId: group.id,
|
|
||||||
$in: {
|
|
||||||
userId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
|
|
||||||
return users;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (outerTx) {
|
|
||||||
return processRemoval(outerTx);
|
|
||||||
}
|
|
||||||
return userDAL.transaction(async (tx) => {
|
|
||||||
return processRemoval(tx);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove users with user ids [userIds] from group [group].
|
|
||||||
* - Users may be part of the group directly or via pending group additions;
|
|
||||||
* this function will handle both cases.
|
* this function will handle both cases.
|
||||||
* @param {group} group - group to remove user(s) from
|
* @param {group} group - group to remove user(s) from
|
||||||
* @param {string[]} userIds - id(s) of user(s) to remove from group
|
* @param {string[]} userIds - id(s) of user(s) to remove from group
|
||||||
@@ -588,7 +271,6 @@ export const removeUsersFromGroupByUserIds = async ({
|
|||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
tx: outerTx
|
tx: outerTx
|
||||||
}: TRemoveUsersFromGroupByUserIds) => {
|
}: TRemoveUsersFromGroupByUserIds) => {
|
||||||
@@ -610,48 +292,91 @@ export const removeUsersFromGroupByUserIds = async ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const membersToRemoveFromGroupDirectly: TUsers[] = [];
|
// check if user group membership already exists
|
||||||
|
const existingUserGroupMemberships = await userGroupMembershipDAL.find(
|
||||||
|
{
|
||||||
|
groupId: group.id,
|
||||||
|
$in: {
|
||||||
|
userId: userIds
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ tx }
|
||||||
|
);
|
||||||
|
|
||||||
|
const existingUserGroupMembershipsUserIdsSet = new Set(existingUserGroupMemberships.map((u) => u.userId));
|
||||||
|
|
||||||
|
userIds.forEach((userId) => {
|
||||||
|
if (!existingUserGroupMembershipsUserIdsSet.has(userId))
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `User(s) are not part of the group ${group.slug}`
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const membersToRemoveFromGroupNonPending: TUsers[] = [];
|
||||||
const membersToRemoveFromGroupPending: TUsers[] = [];
|
const membersToRemoveFromGroupPending: TUsers[] = [];
|
||||||
|
|
||||||
foundMembers.forEach((member) => {
|
foundMembers.forEach((member) => {
|
||||||
if (member.isAccepted) {
|
if (member.isAccepted) {
|
||||||
// remove accepted member from group
|
// remove accepted member from group
|
||||||
membersToRemoveFromGroupDirectly.push(member);
|
membersToRemoveFromGroupNonPending.push(member);
|
||||||
} else {
|
} else {
|
||||||
// remove incomplete member from pending group addition
|
// remove incomplete member from pending group addition
|
||||||
membersToRemoveFromGroupPending.push(member);
|
membersToRemoveFromGroupPending.push(member);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let removedUsers: TUsers[] = [];
|
if (membersToRemoveFromGroupNonPending.length) {
|
||||||
|
// check which projects the group is part of
|
||||||
if (membersToRemoveFromGroupDirectly.length) {
|
const projectIds = Array.from(
|
||||||
removedUsers = removedUsers.concat(
|
new Set(
|
||||||
await removeUsersFromGroupDirectly({
|
(
|
||||||
group,
|
await groupProjectDAL.find(
|
||||||
userIds: membersToRemoveFromGroupDirectly.map((member) => member.id),
|
{
|
||||||
userDAL,
|
groupId: group.id
|
||||||
userGroupMembershipDAL,
|
},
|
||||||
groupProjectDAL,
|
{ tx }
|
||||||
projectKeyDAL,
|
)
|
||||||
tx
|
).map((gp) => gp.projectId)
|
||||||
})
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO: this part can be optimized
|
||||||
|
for await (const userId of userIds) {
|
||||||
|
const t = await userGroupMembershipDAL.filterProjectsByUserMembership(userId, group.id, projectIds, tx);
|
||||||
|
const projectsToDeleteKeyFor = projectIds.filter((p) => !t.has(p));
|
||||||
|
|
||||||
|
if (projectsToDeleteKeyFor.length) {
|
||||||
|
await projectKeyDAL.delete(
|
||||||
|
{
|
||||||
|
receiverId: userId,
|
||||||
|
$in: {
|
||||||
|
projectId: projectsToDeleteKeyFor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await userGroupMembershipDAL.delete(
|
||||||
|
{
|
||||||
|
groupId: group.id,
|
||||||
|
userId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (membersToRemoveFromGroupPending.length) {
|
if (membersToRemoveFromGroupPending.length) {
|
||||||
removedUsers = removedUsers.concat(
|
await userGroupMembershipDAL.delete({
|
||||||
await removeUsersFromPendingGroupAdditions({
|
groupId: group.id,
|
||||||
group,
|
$in: {
|
||||||
userIds: membersToRemoveFromGroupPending.map((member) => member.id),
|
userId: membersToRemoveFromGroupPending.map((member) => member.id)
|
||||||
pendingGroupAdditionDAL,
|
}
|
||||||
userDAL,
|
});
|
||||||
tx
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return removedUsers;
|
return membersToRemoveFromGroupNonPending.concat(membersToRemoveFromGroupPending);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (outerTx) {
|
if (outerTx) {
|
||||||
@@ -669,9 +394,7 @@ export const removeUsersFromGroupByUserIds = async ({
|
|||||||
export const convertPendingGroupAdditionsToGroupMemberships = async ({
|
export const convertPendingGroupAdditionsToGroupMemberships = async ({
|
||||||
userIds,
|
userIds,
|
||||||
userDAL,
|
userDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
@@ -705,15 +428,14 @@ export const convertPendingGroupAdditionsToGroupMemberships = async ({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const pendingGroupAdditions = await pendingGroupAdditionDAL.deletePendingGroupAdditionsByUserIds(userIds, tx);
|
const pendingGroupAdditions = await userGroupMembershipDAL.deletePendingUserGroupMembershipsByUserIds(userIds, tx);
|
||||||
|
|
||||||
for await (const pendingGroupAddition of pendingGroupAdditions) {
|
for await (const pendingGroupAddition of pendingGroupAdditions) {
|
||||||
await addUsersToGroupDirectly({
|
await addAcceptedUsersToGroup({
|
||||||
|
userIds: [pendingGroupAddition.user.id],
|
||||||
group: pendingGroupAddition.group,
|
group: pendingGroupAddition.group,
|
||||||
usernames: [pendingGroupAddition.user.username],
|
|
||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas";
|
import { OrgMembershipRole, TOrgRoles } from "@app/db/schemas";
|
||||||
import { TPendingGroupAdditionDALFactory } from "@app/ee/services/group/pending-group-addition-dal";
|
|
||||||
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
import { isAtLeastAsPrivileged } from "@app/lib/casl";
|
||||||
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError } from "@app/lib/errors";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
@@ -29,7 +28,7 @@ import {
|
|||||||
import { TUserGroupMembershipDALFactory } from "./user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "./user-group-membership-dal";
|
||||||
|
|
||||||
type TGroupServiceFactoryDep = {
|
type TGroupServiceFactoryDep = {
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "findUserEncKeyByUsernameBatch" | "transaction" | "findOne">;
|
userDAL: Pick<TUserDALFactory, "find" | "findUserEncKeyByUserIdsBatch" | "transaction" | "findOne">;
|
||||||
groupDAL: Pick<TGroupDALFactory, "create" | "findOne" | "update" | "delete" | "findAllGroupMembers">;
|
groupDAL: Pick<TGroupDALFactory, "create" | "findOne" | "update" | "delete" | "findAllGroupMembers">;
|
||||||
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findMembership" | "countAllOrgMembers">;
|
orgDAL: Pick<TOrgDALFactory, "findMembership" | "countAllOrgMembers">;
|
||||||
@@ -40,7 +39,6 @@ type TGroupServiceFactoryDep = {
|
|||||||
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "delete" | "findLatestProjectKey" | "insertMany">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "delete" | "findLatestProjectKey" | "insertMany">;
|
||||||
pendingGroupAdditionDAL: TPendingGroupAdditionDALFactory; // remove?
|
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getOrgPermissionByRole">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getOrgPermissionByRole">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
};
|
};
|
||||||
@@ -56,7 +54,6 @@ export const groupServiceFactory = ({
|
|||||||
projectDAL,
|
projectDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
permissionService,
|
permissionService,
|
||||||
licenseService
|
licenseService
|
||||||
}: TGroupServiceFactoryDep) => {
|
}: TGroupServiceFactoryDep) => {
|
||||||
@@ -279,7 +276,6 @@ export const groupServiceFactory = ({
|
|||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
projectBotDAL
|
projectBotDAL
|
||||||
@@ -333,7 +329,6 @@ export const groupServiceFactory = ({
|
|||||||
userIds: [user.id],
|
userIds: [user.id],
|
||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
projectKeyDAL
|
projectKeyDAL
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { TGroups } from "@app/db/schemas";
|
import { TGroups } from "@app/db/schemas";
|
||||||
import { TPendingGroupAdditionDALFactory } from "@app/ee/services/group/pending-group-addition-dal";
|
|
||||||
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
import { TGenericPermission } from "@app/lib/types";
|
import { TGenericPermission } from "@app/lib/types";
|
||||||
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
import { TGroupProjectDALFactory } from "@app/services/group-project/group-project-dal";
|
||||||
@@ -49,24 +48,22 @@ export type TRemoveUserFromGroupDTO = {
|
|||||||
|
|
||||||
// group fns types
|
// group fns types
|
||||||
|
|
||||||
|
export type TAddUsersToGroup = {
|
||||||
|
userIds: string[];
|
||||||
|
group: TGroups;
|
||||||
|
userDAL: Pick<TUserDALFactory, "findUserEncKeyByUserIdsBatch">;
|
||||||
|
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
|
||||||
|
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
||||||
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
|
||||||
|
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
||||||
|
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||||
|
tx: Knex;
|
||||||
|
};
|
||||||
|
|
||||||
export type TAddUsersToGroupByUserIds = {
|
export type TAddUsersToGroupByUserIds = {
|
||||||
group: TGroups;
|
group: TGroups;
|
||||||
userIds: string[];
|
userIds: string[];
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "findUserEncKeyByUsernameBatch" | "transaction">;
|
userDAL: Pick<TUserDALFactory, "find" | "findUserEncKeyByUserIdsBatch" | "transaction">;
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
|
|
||||||
orgDAL: Pick<TOrgDALFactory, "findMembership">;
|
|
||||||
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
|
||||||
pendingGroupAdditionDAL: Pick<TPendingGroupAdditionDALFactory, "insertMany" | "find">;
|
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
|
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
|
||||||
tx?: Knex;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TAddUsersToGroupDirectly = {
|
|
||||||
group: TGroups;
|
|
||||||
usernames: string[];
|
|
||||||
userDAL: Pick<TUserDALFactory, "findUserEncKeyByUsernameBatch" | "transaction">;
|
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
|
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findMembership">;
|
orgDAL: Pick<TOrgDALFactory, "findMembership">;
|
||||||
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
||||||
@@ -76,50 +73,23 @@ export type TAddUsersToGroupDirectly = {
|
|||||||
tx?: Knex;
|
tx?: Knex;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAddUsersToPendingGroupAdditions = {
|
|
||||||
userIds: string[];
|
|
||||||
group: TGroups;
|
|
||||||
pendingGroupAdditionDAL: Pick<TPendingGroupAdditionDALFactory, "find" | "insertMany">;
|
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "transaction">;
|
|
||||||
orgDAL: Pick<TOrgDALFactory, "findMembership">;
|
|
||||||
tx?: Knex;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TRemoveUsersFromGroupByUserIds = {
|
export type TRemoveUsersFromGroupByUserIds = {
|
||||||
group: TGroups;
|
group: TGroups;
|
||||||
userIds: string[];
|
userIds: string[];
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "transaction">;
|
userDAL: Pick<TUserDALFactory, "find" | "transaction">;
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "filterProjectsByUserMembership" | "delete">;
|
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "filterProjectsByUserMembership" | "delete">;
|
||||||
pendingGroupAdditionDAL: Pick<TPendingGroupAdditionDALFactory, "find" | "delete">;
|
|
||||||
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "delete">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "delete">;
|
||||||
tx?: Knex;
|
tx?: Knex;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TRemoveUsersFromGroupDirectly = {
|
|
||||||
group: TGroups;
|
|
||||||
userIds: string[];
|
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "transaction">;
|
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "filterProjectsByUserMembership" | "delete">;
|
|
||||||
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "delete">;
|
|
||||||
tx?: Knex;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TRemoveUsersFromPendingGroupAdditions = {
|
|
||||||
group: TGroups;
|
|
||||||
userIds: string[];
|
|
||||||
pendingGroupAdditionDAL: Pick<TPendingGroupAdditionDALFactory, "find" | "delete">;
|
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "transaction">;
|
|
||||||
tx?: Knex;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TConvertPendingGroupAdditionsToGroupMemberships = {
|
export type TConvertPendingGroupAdditionsToGroupMemberships = {
|
||||||
userIds: string[];
|
userIds: string[];
|
||||||
pendingGroupAdditionDAL: Pick<TPendingGroupAdditionDALFactory, "deletePendingGroupAdditionsByUserIds">;
|
userDAL: Pick<TUserDALFactory, "findUserEncKeyByUserIdsBatch" | "transaction" | "find" | "findById">;
|
||||||
userDAL: Pick<TUserDALFactory, "findUserEncKeyByUsernameBatch" | "transaction" | "find" | "findById">;
|
userGroupMembershipDAL: Pick<
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
|
TUserGroupMembershipDALFactory,
|
||||||
orgDAL: Pick<TOrgDALFactory, "findMembership">;
|
"find" | "transaction" | "insertMany" | "deletePendingUserGroupMembershipsByUserIds"
|
||||||
|
>;
|
||||||
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
groupProjectDAL: Pick<TGroupProjectDALFactory, "find">;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
import { Knex } from "knex";
|
|
||||||
|
|
||||||
import { TDbClient } from "@app/db";
|
|
||||||
import { TableName } from "@app/db/schemas";
|
|
||||||
import { DatabaseError } from "@app/lib/errors";
|
|
||||||
import { ormify } from "@app/lib/knex";
|
|
||||||
|
|
||||||
export type TPendingGroupAdditionDALFactory = ReturnType<typeof pendingGroupAdditionDALFactory>;
|
|
||||||
|
|
||||||
export const pendingGroupAdditionDALFactory = (db: TDbClient) => {
|
|
||||||
const pendingGroupAdditionOrm = ormify(db, TableName.PendingGroupAddition);
|
|
||||||
|
|
||||||
// special query
|
|
||||||
const deletePendingGroupAdditionsByUserIds = async (userIds: string[], tx?: Knex) => {
|
|
||||||
try {
|
|
||||||
const pendingGroupAdditions = await (tx || db)(TableName.PendingGroupAddition)
|
|
||||||
.whereIn(`${TableName.PendingGroupAddition}.userId`, userIds)
|
|
||||||
.join(TableName.Groups, `${TableName.PendingGroupAddition}.groupId`, `${TableName.Groups}.id`)
|
|
||||||
.join(TableName.Users, `${TableName.PendingGroupAddition}.userId`, `${TableName.Users}.id`);
|
|
||||||
|
|
||||||
await pendingGroupAdditionOrm.delete(
|
|
||||||
{
|
|
||||||
$in: {
|
|
||||||
userId: userIds
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tx
|
|
||||||
);
|
|
||||||
|
|
||||||
return pendingGroupAdditions.map(({ userId, username, groupId, orgId, name, slug, role, roleId }) => ({
|
|
||||||
user: {
|
|
||||||
id: userId,
|
|
||||||
username
|
|
||||||
},
|
|
||||||
group: {
|
|
||||||
id: groupId,
|
|
||||||
orgId,
|
|
||||||
name,
|
|
||||||
slug,
|
|
||||||
role,
|
|
||||||
roleId,
|
|
||||||
createdAt: new Date(),
|
|
||||||
updatedAt: new Date()
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
} catch (error) {
|
|
||||||
throw new DatabaseError({ error, name: "Filter projects by user membership" });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
...pendingGroupAdditionOrm,
|
|
||||||
deletePendingGroupAdditionsByUserIds
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -122,10 +122,49 @@ export const userGroupMembershipDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deletePendingUserGroupMembershipsByUserIds = async (userIds: string[], tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
const members = await (tx || db)(TableName.UserGroupMembership)
|
||||||
|
.whereIn(`${TableName.UserGroupMembership}.userId`, userIds)
|
||||||
|
.where(`${TableName.UserGroupMembership}.isPending`, true)
|
||||||
|
.join(TableName.Groups, `${TableName.UserGroupMembership}.groupId`, `${TableName.Groups}.id`)
|
||||||
|
.join(TableName.Users, `${TableName.UserGroupMembership}.userId`, `${TableName.Users}.id`);
|
||||||
|
|
||||||
|
await userGroupMembershipOrm.delete(
|
||||||
|
{
|
||||||
|
$in: {
|
||||||
|
userId: userIds
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
|
||||||
|
return members.map(({ userId, username, groupId, orgId, name, slug, role, roleId }) => ({
|
||||||
|
user: {
|
||||||
|
id: userId,
|
||||||
|
username
|
||||||
|
},
|
||||||
|
group: {
|
||||||
|
id: groupId,
|
||||||
|
orgId,
|
||||||
|
name,
|
||||||
|
slug,
|
||||||
|
role,
|
||||||
|
roleId,
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date()
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Delete pending user group memberships by user ids" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...userGroupMembershipOrm,
|
...userGroupMembershipOrm,
|
||||||
filterProjectsByUserMembership,
|
filterProjectsByUserMembership,
|
||||||
findUserGroupMembershipsInProject,
|
findUserGroupMembershipsInProject,
|
||||||
findGroupMembersNotInProject
|
findGroupMembersNotInProject,
|
||||||
|
deletePendingUserGroupMembershipsByUserIds
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import jwt from "jsonwebtoken";
|
|||||||
import { OrgMembershipRole, OrgMembershipStatus, TableName, TGroups } from "@app/db/schemas";
|
import { OrgMembershipRole, OrgMembershipStatus, TableName, TGroups } from "@app/db/schemas";
|
||||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
|
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
|
||||||
import { TPendingGroupAdditionDALFactory } from "@app/ee/services/group/pending-group-addition-dal";
|
|
||||||
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
import { TScimDALFactory } from "@app/ee/services/scim/scim-dal";
|
import { TScimDALFactory } from "@app/ee/services/scim/scim-dal";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
@@ -48,7 +47,7 @@ import {
|
|||||||
|
|
||||||
type TScimServiceFactoryDep = {
|
type TScimServiceFactoryDep = {
|
||||||
scimDAL: Pick<TScimDALFactory, "create" | "find" | "findById" | "deleteById">;
|
scimDAL: Pick<TScimDALFactory, "create" | "find" | "findById" | "deleteById">;
|
||||||
userDAL: Pick<TUserDALFactory, "find" | "findOne" | "create" | "transaction" | "findUserEncKeyByUsernameBatch">;
|
userDAL: Pick<TUserDALFactory, "find" | "findOne" | "create" | "transaction" | "findUserEncKeyByUserIdsBatch">;
|
||||||
orgDAL: Pick<
|
orgDAL: Pick<
|
||||||
TOrgDALFactory,
|
TOrgDALFactory,
|
||||||
"createMembership" | "findById" | "findMembership" | "deleteMembershipById" | "transaction"
|
"createMembership" | "findById" | "findMembership" | "deleteMembershipById" | "transaction"
|
||||||
@@ -63,7 +62,6 @@ type TScimServiceFactoryDep = {
|
|||||||
userGroupMembershipDAL: TUserGroupMembershipDALFactory; // TODO: Pick
|
userGroupMembershipDAL: TUserGroupMembershipDALFactory; // TODO: Pick
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany" | "delete">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany" | "delete">;
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||||
pendingGroupAdditionDAL: TPendingGroupAdditionDALFactory; // TODO: Pick
|
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
smtpService: TSmtpService;
|
smtpService: TSmtpService;
|
||||||
@@ -83,7 +81,6 @@ export const scimServiceFactory = ({
|
|||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
permissionService,
|
permissionService,
|
||||||
smtpService
|
smtpService
|
||||||
}: TScimServiceFactoryDep) => {
|
}: TScimServiceFactoryDep) => {
|
||||||
@@ -572,7 +569,6 @@ export const scimServiceFactory = ({
|
|||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
@@ -614,7 +610,6 @@ export const scimServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: update to include pending group additions
|
|
||||||
const users = await groupDAL.findAllGroupMembers({
|
const users = await groupDAL.findAllGroupMembers({
|
||||||
orgId: group.orgId,
|
orgId: group.orgId,
|
||||||
groupId: group.id
|
groupId: group.id
|
||||||
@@ -676,13 +671,15 @@ export const scimServiceFactory = ({
|
|||||||
|
|
||||||
const directMemberUserIds = (
|
const directMemberUserIds = (
|
||||||
await userGroupMembershipDAL.find({
|
await userGroupMembershipDAL.find({
|
||||||
groupId: group.id
|
groupId: group.id,
|
||||||
|
isPending: false
|
||||||
})
|
})
|
||||||
).map((membership) => membership.userId);
|
).map((membership) => membership.userId);
|
||||||
|
|
||||||
const pendingGroupAdditionsUserIds = (
|
const pendingGroupAdditionsUserIds = (
|
||||||
await pendingGroupAdditionDAL.find({
|
await userGroupMembershipDAL.find({
|
||||||
groupId: group.id
|
groupId: group.id,
|
||||||
|
isPending: true
|
||||||
})
|
})
|
||||||
).map((pendingGroupAddition) => pendingGroupAddition.userId);
|
).map((pendingGroupAddition) => pendingGroupAddition.userId);
|
||||||
|
|
||||||
@@ -700,7 +697,6 @@ export const scimServiceFactory = ({
|
|||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
@@ -715,7 +711,6 @@ export const scimServiceFactory = ({
|
|||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
tx
|
tx
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { dynamicSecretLeaseQueueServiceFactory } from "@app/ee/services/dynamic-
|
|||||||
import { dynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
|
import { dynamicSecretLeaseServiceFactory } from "@app/ee/services/dynamic-secret-lease/dynamic-secret-lease-service";
|
||||||
import { groupDALFactory } from "@app/ee/services/group/group-dal";
|
import { groupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { groupServiceFactory } from "@app/ee/services/group/group-service";
|
import { groupServiceFactory } from "@app/ee/services/group/group-service";
|
||||||
import { pendingGroupAdditionDALFactory } from "@app/ee/services/group/pending-group-addition-dal";
|
|
||||||
import { userGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { userGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
import { identityProjectAdditionalPrivilegeDALFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-dal";
|
import { identityProjectAdditionalPrivilegeDALFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-dal";
|
||||||
import { identityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
|
import { identityProjectAdditionalPrivilegeServiceFactory } from "@app/ee/services/identity-project-additional-privilege/identity-project-additional-privilege-service";
|
||||||
@@ -218,7 +217,6 @@ export const registerRoutes = async (
|
|||||||
const groupProjectDAL = groupProjectDALFactory(db);
|
const groupProjectDAL = groupProjectDALFactory(db);
|
||||||
const groupProjectMembershipRoleDAL = groupProjectMembershipRoleDALFactory(db);
|
const groupProjectMembershipRoleDAL = groupProjectMembershipRoleDALFactory(db);
|
||||||
const userGroupMembershipDAL = userGroupMembershipDALFactory(db);
|
const userGroupMembershipDAL = userGroupMembershipDALFactory(db);
|
||||||
const pendingGroupAdditionDAL = pendingGroupAdditionDALFactory(db);
|
|
||||||
const secretScanningDAL = secretScanningDALFactory(db);
|
const secretScanningDAL = secretScanningDALFactory(db);
|
||||||
const licenseDAL = licenseDALFactory(db);
|
const licenseDAL = licenseDALFactory(db);
|
||||||
const dynamicSecretDAL = dynamicSecretDALFactory(db);
|
const dynamicSecretDAL = dynamicSecretDALFactory(db);
|
||||||
@@ -270,7 +268,6 @@ export const registerRoutes = async (
|
|||||||
projectDAL,
|
projectDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
permissionService,
|
permissionService,
|
||||||
licenseService
|
licenseService
|
||||||
});
|
});
|
||||||
@@ -297,7 +294,6 @@ export const registerRoutes = async (
|
|||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectBotDAL,
|
projectBotDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
permissionService,
|
permissionService,
|
||||||
smtpService
|
smtpService
|
||||||
});
|
});
|
||||||
@@ -352,7 +348,6 @@ export const registerRoutes = async (
|
|||||||
smtpService,
|
smtpService,
|
||||||
authDAL,
|
authDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import jwt from "jsonwebtoken";
|
|||||||
|
|
||||||
import { OrgMembershipStatus } from "@app/db/schemas";
|
import { OrgMembershipStatus } from "@app/db/schemas";
|
||||||
import { convertPendingGroupAdditionsToGroupMemberships } from "@app/ee/services/group/group-fns";
|
import { convertPendingGroupAdditionsToGroupMemberships } from "@app/ee/services/group/group-fns";
|
||||||
import { TPendingGroupAdditionDALFactory } from "@app/ee/services/group/pending-group-addition-dal";
|
|
||||||
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
@@ -27,8 +26,10 @@ import { AuthMethod, AuthTokenType } from "./auth-type";
|
|||||||
type TAuthSignupDep = {
|
type TAuthSignupDep = {
|
||||||
authDAL: TAuthDALFactory;
|
authDAL: TAuthDALFactory;
|
||||||
userDAL: TUserDALFactory;
|
userDAL: TUserDALFactory;
|
||||||
pendingGroupAdditionDAL: Pick<TPendingGroupAdditionDALFactory, "deletePendingGroupAdditionsByUserIds">;
|
userGroupMembershipDAL: Pick<
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "find" | "transaction" | "insertMany">;
|
TUserGroupMembershipDALFactory,
|
||||||
|
"find" | "transaction" | "insertMany" | "deletePendingUserGroupMembershipsByUserIds"
|
||||||
|
>;
|
||||||
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
|
projectKeyDAL: Pick<TProjectKeyDALFactory, "find" | "findLatestProjectKey" | "insertMany">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
projectDAL: Pick<TProjectDALFactory, "findProjectGhostUser">;
|
||||||
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
projectBotDAL: Pick<TProjectBotDALFactory, "findOne">;
|
||||||
@@ -44,7 +45,6 @@ export type TAuthSignupFactory = ReturnType<typeof authSignupServiceFactory>;
|
|||||||
export const authSignupServiceFactory = ({
|
export const authSignupServiceFactory = ({
|
||||||
authDAL,
|
authDAL,
|
||||||
userDAL,
|
userDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
@@ -190,9 +190,7 @@ export const authSignupServiceFactory = ({
|
|||||||
await convertPendingGroupAdditionsToGroupMemberships({
|
await convertPendingGroupAdditionsToGroupMemberships({
|
||||||
userIds: [user.id],
|
userIds: [user.id],
|
||||||
userDAL,
|
userDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
@@ -304,9 +302,7 @@ export const authSignupServiceFactory = ({
|
|||||||
await convertPendingGroupAdditionsToGroupMemberships({
|
await convertPendingGroupAdditionsToGroupMemberships({
|
||||||
userIds: [user.id],
|
userIds: [user.id],
|
||||||
userDAL,
|
userDAL,
|
||||||
pendingGroupAdditionDAL,
|
|
||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
orgDAL,
|
|
||||||
groupProjectDAL,
|
groupProjectDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
|
|||||||
@@ -34,16 +34,16 @@ export const userDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findUserEncKeyByUsernameBatch = async ({ usernames }: { usernames: string[] }, tx?: Knex) => {
|
const findUserEncKeyByUserIdsBatch = async ({ userIds }: { userIds: string[] }, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
return await (tx || db)(TableName.Users)
|
return await (tx || db)(TableName.Users)
|
||||||
.where({
|
.where({
|
||||||
isGhost: false
|
isGhost: false
|
||||||
})
|
})
|
||||||
.whereIn("username", usernames)
|
.whereIn(`${TableName.Users}.id`, userIds)
|
||||||
.join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`);
|
.join(TableName.UserEncryptionKey, `${TableName.Users}.id`, `${TableName.UserEncryptionKey}.userId`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new DatabaseError({ error, name: "Find user enc by email batch" });
|
throw new DatabaseError({ error, name: "Find user enc by user ids batch" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ export const userDALFactory = (db: TDbClient) => {
|
|||||||
...userOrm,
|
...userOrm,
|
||||||
findUserByUsername,
|
findUserByUsername,
|
||||||
findUserEncKeyByUsername,
|
findUserEncKeyByUsername,
|
||||||
findUserEncKeyByUsernameBatch, // TODO: if successful, replace findUserEncKeyByUsername with this
|
findUserEncKeyByUserIdsBatch,
|
||||||
findUserEncKeyByUserId,
|
findUserEncKeyByUserId,
|
||||||
updateUserEncryptionByUserId,
|
updateUserEncryptionByUserId,
|
||||||
findUserByProjectMembershipId,
|
findUserByProjectMembershipId,
|
||||||
|
|||||||
Reference in New Issue
Block a user