From 0d3f09d6688c5b46262c8ff438495153eb968882 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Tue, 9 Jan 2024 23:11:39 +0530 Subject: [PATCH] feat(infisical-pg): completed checklist run for dashboard --- backend-pg/src/db/utils.ts | 4 +- .../ee/services/audit-log/audit-log-types.ts | 2 + .../secret-approval-request/sar-secret-dal.ts | 1 + .../secret-approval-request-service.ts | 403 ++++++------------ backend-pg/src/server/routes/index.ts | 21 +- .../src/server/routes/v1/invite-org-router.ts | 1 - .../server/routes/v1/organization-router.ts | 3 +- .../server/routes/v1/project-env-router.ts | 9 +- .../src/server/routes/v3/secret-router.ts | 20 +- .../src/services/identity/identity-service.ts | 8 +- backend-pg/src/services/org/org-dal.ts | 2 +- backend-pg/src/services/org/org-service.ts | 1 + .../services/project-env/project-env-dal.ts | 55 ++- .../project-env/project-env-service.ts | 39 +- .../services/project-env/project-env-types.ts | 1 + backend-pg/src/services/secret/secret-dal.ts | 41 +- .../src/services/secret/secret-service.ts | 37 +- .../src/services/secret/secret-types.ts | 7 + frontend/src/hooks/api/users/mutation.tsx | 2 +- frontend/src/hooks/api/users/types.ts | 2 +- frontend/src/hooks/api/workspace/queries.tsx | 48 +-- frontend/src/hooks/api/workspace/types.ts | 1 + frontend/src/pages/signupinvite.tsx | 2 +- .../OrgMembersSection/OrgMembersTable.tsx | 7 +- .../OrgMembersTable/OrgMembersTable.tsx | 6 +- .../MemberListTab/MemberListTab.tsx | 7 +- .../DeleteProjectSection.tsx | 3 +- .../EnvironmentSection/EnvironmentTable.tsx | 41 +- 28 files changed, 341 insertions(+), 433 deletions(-) diff --git a/backend-pg/src/db/utils.ts b/backend-pg/src/db/utils.ts index f2ee0ca30..f82d52cec 100644 --- a/backend-pg/src/db/utils.ts +++ b/backend-pg/src/db/utils.ts @@ -12,8 +12,8 @@ export const createJunctionTable = ( table.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); table.uuid(`${table1Name}Id`).unsigned().notNullable(); // Foreign key for table1 table.uuid(`${table2Name}Id`).unsigned().notNullable(); // Foreign key for table2 - table.foreign(`${table1Name}Id`).references("id").inTable(table2Name); - table.foreign(`${table2Name}Id`).references("id").inTable(table1Name); + table.foreign(`${table1Name}Id`).references("id").inTable(table1Name); + table.foreign(`${table2Name}Id`).references("id").inTable(table2Name); }); // one time logic diff --git a/backend-pg/src/ee/services/audit-log/audit-log-types.ts b/backend-pg/src/ee/services/audit-log/audit-log-types.ts index 4b2dc2fcf..011dffebe 100644 --- a/backend-pg/src/ee/services/audit-log/audit-log-types.ts +++ b/backend-pg/src/ee/services/audit-log/audit-log-types.ts @@ -413,6 +413,8 @@ interface UpdateEnvironmentEvent { newName: string; oldSlug: string; newSlug: string; + oldPos: number; + newPos: number; }; } diff --git a/backend-pg/src/ee/services/secret-approval-request/sar-secret-dal.ts b/backend-pg/src/ee/services/secret-approval-request/sar-secret-dal.ts index 35dd2b5e0..141472170 100644 --- a/backend-pg/src/ee/services/secret-approval-request/sar-secret-dal.ts +++ b/backend-pg/src/ee/services/secret-approval-request/sar-secret-dal.ts @@ -88,6 +88,7 @@ export const sarSecretDalFactory = (db: TDbClient) => { secret: el.secretId ? { id: el.secretId, + version: orgSecVersion, secretBlindIndex: orgSecBlindIndex, secretKeyIV: orgSecKeyIV, secretKeyTag: orgSecKeyTag, diff --git a/backend-pg/src/ee/services/secret-approval-request/secret-approval-request-service.ts b/backend-pg/src/ee/services/secret-approval-request/secret-approval-request-service.ts index b6627f888..5cc4c323a 100644 --- a/backend-pg/src/ee/services/secret-approval-request/secret-approval-request-service.ts +++ b/backend-pg/src/ee/services/secret-approval-request/secret-approval-request-service.ts @@ -5,20 +5,20 @@ import { SecretEncryptionAlgo, SecretKeyEncoding, SecretType, - TSaRequestSecretsInsert, - TSecrets + TSaRequestSecretsInsert } from "@app/db/schemas"; import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; +import { groupBy, pick } from "@app/lib/fn"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { ActorType } from "@app/services/auth/auth-type"; import { TSecretBlindIndexDalFactory } from "@app/services/secret/secret-blind-index-dal"; -import { TSecretDalFactory } from "@app/services/secret/secret-dal"; -import { generateSecretBlindIndexBySalt } from "@app/services/secret/secret-service"; +import { TSecretServiceFactory } from "@app/services/secret/secret-service"; import { TSecretVersionDalFactory } from "@app/services/secret/secret-version-dal"; import { TSecretFolderDalFactory } from "@app/services/secret-folder/secret-folder-dal"; import { TPermissionServiceFactory } from "../permission/permission-service"; import { ProjectPermissionActions, ProjectPermissionSub } from "../permission/project-permission"; +import { TSecretSnapshotServiceFactory } from "../secret-snapshot/secret-snapshot-service"; import { TSarReviewerDalFactory } from "./sar-reviewer-dal"; import { TSarSecretDalFactory } from "./sar-secret-dal"; import { TSecretApprovalRequestDalFactory } from "./secret-approval-request-dal"; @@ -38,12 +38,20 @@ import { type TSecretApprovalRequestServiceFactoryDep = { permissionService: Pick; secretApprovalRequestDal: TSecretApprovalRequestDalFactory; - secretDal: TSecretDalFactory; sarSecretDal: TSarSecretDalFactory; sarReviewerDal: TSarReviewerDalFactory; - secretVersionDal: Pick; folderDal: Pick; secretBlindIndexDal: Pick; + snapshotService: Pick; + secretVersionDal: Pick; + secretService: Pick< + TSecretServiceFactory, + | "fnSecretBulkInsert" + | "fnSecretBulkUpdate" + | "fnSecretBlindIndexCheck" + | "fnSecretBulkDelete" + | "fnSecretBlindIndexCheckV2" + >; }; export type TSecretApprovalRequestServiceFactory = ReturnType< @@ -53,12 +61,13 @@ export type TSecretApprovalRequestServiceFactory = ReturnType< export const secretApprovalRequestServiceFactory = ({ secretApprovalRequestDal, folderDal, - secretDal, sarReviewerDal, sarSecretDal, - secretVersionDal, secretBlindIndexDal, - permissionService + permissionService, + snapshotService, + secretService, + secretVersionDal }: TSecretApprovalRequestServiceFactoryDep) => { const requestCount = async ({ projectId, actor, actorId }: TApprovalRequestCountDTO) => { const { membership } = await permissionService.getProjectPermission(actor, actorId, projectId); @@ -194,11 +203,11 @@ export const secretApprovalRequestServiceFactory = ({ throw new BadRequestError({ message: "Secret approval request not found" }); if (actor !== ActorType.USER) throw new BadRequestError({ message: "Must be a user" }); - const { policy, folderId } = secretApprovalRequest; + const { policy, folderId, projectId } = secretApprovalRequest; const { membership } = await permissionService.getProjectPermission( ActorType.USER, actorId, - secretApprovalRequest.projectId + projectId ); if ( membership.role !== ProjectMembershipRole.Admin && @@ -225,17 +234,11 @@ export const secretApprovalRequestServiceFactory = ({ const conflicts: Array<{ secretId: string; op: CommitType }> = []; let secretCreationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Create); if (secretCreationCommits.length) { - const conflictedSecrets = await secretDal.findByBlindIndexes( - folderId, - secretCreationCommits.map(({ secretBlindIndex }) => ({ - type: SecretType.Shared, - blindIndex: secretBlindIndex - })) - ); - const conflictGroupByBlindIndex = conflictedSecrets.reduce>( - (prev, curr) => ({ ...prev, [curr.secretBlindIndex || ""]: true }), - {} - ); + const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = + await secretService.fnSecretBlindIndexCheckV2({ + folderId, + inputSecrets: secretCreationCommits.map(({ secretBlindIndex }) => ({ secretBlindIndex })) + }); secretCreationCommits .filter(({ secretBlindIndex }) => conflictGroupByBlindIndex[secretBlindIndex || ""]) .forEach((el) => { @@ -248,22 +251,16 @@ export const secretApprovalRequestServiceFactory = ({ let secretUpdationCommits = secretApprovalSecrets.filter(({ op }) => op === CommitType.Update); if (secretUpdationCommits.length) { - const conflictedByNewBlindIndex = await secretDal.findByBlindIndexes( - folderId, - secretUpdationCommits - .filter( - ({ secretBlindIndex, secret }) => secret && secret.secretBlindIndex !== secretBlindIndex - ) - .map(({ secretBlindIndex }) => ({ - type: SecretType.Shared, - blindIndex: secretBlindIndex - })) - ); - const conflictGroupByBlindIndex = conflictedByNewBlindIndex.reduce>( - (prev, curr) => - curr?.secretBlindIndex ? { ...prev, [curr.secretBlindIndex]: true } : prev, - {} - ); + const { secsGroupedByBlindIndex: conflictGroupByBlindIndex } = + await secretService.fnSecretBlindIndexCheckV2({ + folderId, + inputSecrets: secretUpdationCommits + .filter( + ({ secretBlindIndex, secret }) => + secret && secret.secretBlindIndex !== secretBlindIndex + ) + .map(({ secretBlindIndex }) => ({ secretBlindIndex })) + }); secretUpdationCommits .filter( ({ secretBlindIndex, secretId }) => @@ -284,122 +281,78 @@ export const secretApprovalRequestServiceFactory = ({ ({ op }) => op === CommitType.Delete ); - const mergeStatus = await secretDal.transaction(async (tx) => { + const mergeStatus = await secretApprovalRequestDal.transaction(async (tx) => { const newSecrets = secretCreationCommits.length - ? await secretDal.insertMany( - secretCreationCommits.map( - ({ - secretBlindIndex, - metadata, - secretKeyIV, - secretKeyTag, - secretKeyCiphertext, - secretValueIV, - secretValueTag, - secretValueCiphertext, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretReminderNote, - secretReminderRepeatDays - }) => ({ - secretBlindIndex, - metadata, - secretKeyIV, - secretKeyTag, - secretKeyCiphertext, - secretValueIV, - secretValueTag, - secretValueCiphertext, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretReminderNote, - secretReminderRepeatDays, - version: 1, - folderId, - type: SecretType.Shared, - algorithm: SecretEncryptionAlgo.AES_256_GCM, - keyEncoding: SecretKeyEncoding.UTF8 - }) - ), - tx - ) + ? await secretService.fnSecretBulkInsert({ + tx, + folderId, + inputSecrets: secretCreationCommits.map((el) => ({ + ...pick(el, [ + "secretCommentCiphertext", + "secretCommentTag", + "secretCommentIV", + "secretValueIV", + "secretValueTag", + "secretValueCiphertext", + "secretKeyCiphertext", + "secretKeyTag", + "secretKeyIV", + "metadata", + "skipMultilineEncoding", + "secretReminderNote", + "secretReminderRepeatDays", + "version", + "algorithm", + "keyEncoding", + "secretBlindIndex" + ]), + type: SecretType.Shared + })) + }) : []; const updatedSecrets = secretUpdationCommits.length - ? await secretDal.bulkUpdate( - secretUpdationCommits.map( - ({ - version, - secretId, - secretBlindIndex, - metadata, - secretKeyIV, - secretKeyTag, - secretKeyCiphertext, - secretValueIV, - secretValueTag, - secretValueCiphertext, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretReminderNote, - secretReminderRepeatDays - }) => ({ - folderId, - version: (version || 0) + 1, - id: secretId as string, - type: SecretType.Shared, - secretBlindIndex, - metadata, - secretKeyIV, - secretKeyTag, - secretKeyCiphertext, - secretValueIV, - secretValueTag, - secretValueCiphertext, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretReminderNote, - secretReminderRepeatDays - }) - ), - tx - ) + ? await secretService.fnSecretBulkUpdate({ + folderId, + projectId, + tx, + inputSecrets: secretUpdationCommits.map((el) => ({ + ...pick(el, [ + "secretCommentCiphertext", + "secretCommentTag", + "secretCommentIV", + "secretValueIV", + "secretValueTag", + "secretValueCiphertext", + "secretKeyCiphertext", + "secretKeyTag", + "secretKeyIV", + "metadata", + "skipMultilineEncoding", + "secretReminderNote", + "secretReminderRepeatDays", + "version", + "algorithm", + "keyEncoding", + "secretBlindIndex" + ]), + version: (el.secret?.version || 0) + 1, + id: el.secretId, + type: SecretType.Shared + })) + }) : []; const deletedSecret = secretDeletionCommits.length - ? await secretDal.deleteMany( - secretDeletionCommits.map(({ secretBlindIndex }) => ({ - blindIndex: secretBlindIndex, - type: SecretType.Shared - })), + ? await secretService.fnSecretBulkDelete({ + projectId, folderId, - actorId, - tx - ) - : []; - if (newSecrets.length || updatedSecrets.length) { - await secretVersionDal.insertMany( - newSecrets - .map(({ id, updatedAt, createdAt, ...el }) => ({ - ...el, - secretId: id + tx, + actorId: "", + inputSecrets: secretDeletionCommits.map(({ secretBlindIndex }) => ({ + secretBlindIndex, + type: SecretType.Shared })) - .concat( - updatedSecrets.map(({ id, updatedAt, createdAt, ...el }) => ({ - ...el, - secretId: id - })) - ), - tx - ); - } - + }) + : []; const updatedSecretApproval = await secretApprovalRequestDal.updateById( secretApprovalRequest.id, { @@ -415,6 +368,7 @@ export const secretApprovalRequestServiceFactory = ({ approval: updatedSecretApproval }; }); + await snapshotService.performSnapshot(folderId); return mergeStatus; }; @@ -444,42 +398,27 @@ export const secretApprovalRequestServiceFactory = ({ throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" }); const folderId = folder.id; - const blindIndexDoc = await secretBlindIndexDal.findOne({ projectId }); - if (!blindIndexDoc) + const blindIndexCfg = await secretBlindIndexDal.findOne({ projectId }); + if (!blindIndexCfg) throw new BadRequestError({ message: "Blind index not found", name: "Update secret" }); const commits: Omit[] = []; // for created secret approval change const createdSecrets = data[CommitType.Create]; if (createdSecrets && createdSecrets?.length) { - const secretBlindIndexToKey: Record = {}; // used at audit log point - const secretBlindIndexes = await Promise.all( - createdSecrets.map(({ secretName }) => - generateSecretBlindIndexBySalt(secretName, blindIndexDoc) - ) - ).then((blindIndexes) => - blindIndexes.reduce>((prev, curr, i) => { - // eslint-disable-next-line - prev[createdSecrets[i].secretName] = curr; - secretBlindIndexToKey[curr] = createdSecrets[i].secretName; - return prev; - }, {}) - ); - - const exists = await secretDal.findByBlindIndexes( + const { keyName2BlindIndex } = await secretService.fnSecretBlindIndexCheck({ + inputSecrets: createdSecrets, folderId, - createdSecrets.map(({ secretName }) => ({ - blindIndex: secretBlindIndexes[secretName], - type: SecretType.Shared - })) - ); - if (exists.length) throw new BadRequestError({ message: "Secret already exist" }); + isNew: true, + blindIndexCfg + }); + commits.push( - ...createdSecrets.map((el) => ({ + ...createdSecrets.map(({ secretName, ...el }) => ({ ...el, op: CommitType.Create as const, version: 0, - secretBlindIndex: secretBlindIndexes[el.secretName], + secretBlindIndex: keyName2BlindIndex[secretName], algorithm: SecretEncryptionAlgo.AES_256_GCM, keyEncoding: SecretKeyEncoding.BASE64 })) @@ -491,83 +430,49 @@ export const secretApprovalRequestServiceFactory = ({ // get all blind index // Find all those secrets // if not throw not found - const secretBlindIndexToKey: Record = {}; // used at audit log point - const secretBlindIndexes = await Promise.all( - updatedSecrets.map(({ secretName }) => - generateSecretBlindIndexBySalt(secretName, blindIndexDoc) - ) - ).then((blindIndexes) => - blindIndexes.reduce>((prev, curr, i) => { - // eslint-disable-next-line - prev[updatedSecrets[i].secretName] = curr; - secretBlindIndexToKey[curr] = updatedSecrets[i].secretName; - return prev; - }, {}) - ); - - const secretsToBeUpdated = await secretDal.findByBlindIndexes( - folderId, - updatedSecrets.map(({ secretName }) => ({ - blindIndex: secretBlindIndexes[secretName], - type: SecretType.Shared - })) - ); - if (secretsToBeUpdated.length !== updatedSecrets.length) - throw new BadRequestError({ message: "Secret not found" }); + const { keyName2BlindIndex, secrets: secretsToBeUpdated } = + await secretService.fnSecretBlindIndexCheck({ + inputSecrets: updatedSecrets, + folderId, + isNew: false, + blindIndexCfg + }); // now find any secret that needs to update its name // same process as above const nameUpdatedSecrets = updatedSecrets.filter(({ newSecretName }) => Boolean(newSecretName) ); - const newSecretBlindIndexes = await Promise.all( - nameUpdatedSecrets.map(({ newSecretName }) => - generateSecretBlindIndexBySalt(newSecretName as string, blindIndexDoc) - ) - ).then((blindIndexes) => - blindIndexes.reduce>((prev, curr, i) => { - // eslint-disable-next-line - prev[nameUpdatedSecrets[i].secretName] = curr; - return prev; - }, {}) - ); - const secretsWithNewName = await secretDal.findByBlindIndexes( - folderId, - nameUpdatedSecrets.map(({ newSecretName }) => ({ - blindIndex: newSecretBlindIndexes[newSecretName as string], - type: SecretType.Shared - })) - ); - if (secretsWithNewName.length) - throw new BadRequestError({ message: "Secret with new name already exist" }); + const { keyName2BlindIndex: newKeyName2BlindIndex } = + await secretService.fnSecretBlindIndexCheck({ + inputSecrets: nameUpdatedSecrets, + folderId, + isNew: true, + blindIndexCfg + }); - const secretsGroupedByBlindIndex = secretsToBeUpdated.reduce>( - (prev, curr) => { - // eslint-disable-next-line - if (curr.secretBlindIndex) prev[curr.secretBlindIndex] = curr; - return prev; - }, - {} - ); + const secsGroupedByBlindIndex = groupBy(secretsToBeUpdated, (el) => el.secretBlindIndex); const updatedSecretIds = updatedSecrets.map( - (el) => secretsGroupedByBlindIndex[secretBlindIndexes[el.secretName]].id + (el) => secsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id ); const latestSecretVersions = await secretVersionDal.findLatestVersionMany( folderId, updatedSecretIds ); commits.push( - ...updatedSecrets.map((el) => { - const secretId = secretsGroupedByBlindIndex[secretBlindIndexes[el.secretName]].id; + ...updatedSecrets.map(({ newSecretName, secretName, ...el }) => { + const secretId = secsGroupedByBlindIndex[keyName2BlindIndex[secretName]][0].id; return { ...latestSecretVersions[secretId], + ...el, op: CommitType.Update as const, secret: secretId, secretVersion: latestSecretVersions[secretId].id, - ...el, secretBlindIndex: - newSecretBlindIndexes?.[el.secretName] || secretBlindIndexes[el.secretName], - version: secretsGroupedByBlindIndex[secretBlindIndexes[el.secretName]].version || 1 + newSecretName && newKeyName2BlindIndex[newSecretName] + ? newKeyName2BlindIndex?.[secretName] + : keyName2BlindIndex[secretName], + version: secsGroupedByBlindIndex[keyName2BlindIndex[secretName]][0].version || 1 }; }) ); @@ -578,39 +483,15 @@ export const secretApprovalRequestServiceFactory = ({ // get all blind index // Find all those secrets // if not throw not found - const secretBlindIndexToKey: Record = {}; // used at audit log point - const secretBlindIndexes = await Promise.all( - deletedSecrets.map(({ secretName }) => - generateSecretBlindIndexBySalt(secretName, blindIndexDoc) - ) - ).then((blindIndexes) => - blindIndexes.reduce>((prev, curr, i) => { - // eslint-disable-next-line - prev[deletedSecrets[i].secretName] = curr; - secretBlindIndexToKey[curr] = deletedSecrets[i].secretName; - return prev; - }, {}) - ); - // not find those secrets. if any of them not found throw an not found error - const secretsToBeDeleted = await secretDal.findByBlindIndexes( + const { keyName2BlindIndex, secrets } = await secretService.fnSecretBlindIndexCheck({ + inputSecrets: deletedSecrets, folderId, - deletedSecrets.map(({ secretName }) => ({ - blindIndex: secretBlindIndexes[secretName], - type: SecretType.Shared - })) - ); - if (secretsToBeDeleted.length !== deletedSecrets.length) - throw new BadRequestError({ message: "Secret not found" }); - const secretsGroupedByBlindIndex = secretsToBeDeleted.reduce>( - (prev, curr) => { - // eslint-disable-next-line - if (curr.secretBlindIndex) prev[curr.secretBlindIndex] = curr; - return prev; - }, - {} - ); + isNew: false, + blindIndexCfg + }); + const secretsGroupedByBlindIndex = groupBy(secrets, (i) => i.secretBlindIndex); const deletedSecretIds = deletedSecrets.map( - (el) => secretsGroupedByBlindIndex[secretBlindIndexes[el.secretName]].id + (el) => secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id ); const latestSecretVersions = await secretVersionDal.findLatestVersionMany( folderId, @@ -618,7 +499,7 @@ export const secretApprovalRequestServiceFactory = ({ ); commits.push( ...deletedSecrets.map((el) => { - const secretId = secretsGroupedByBlindIndex[secretBlindIndexes[el.secretName]].id; + const secretId = secretsGroupedByBlindIndex[keyName2BlindIndex[el.secretName]][0].id; return { op: CommitType.Delete as const, ...latestSecretVersions[secretId], diff --git a/backend-pg/src/server/routes/index.ts b/backend-pg/src/server/routes/index.ts index e6bac2856..70f66e5b1 100644 --- a/backend-pg/src/server/routes/index.ts +++ b/backend-pg/src/server/routes/index.ts @@ -173,16 +173,6 @@ export const registerRoutes = async ( userDal, samlConfigDal }); - const sarService = secretApprovalRequestServiceFactory({ - permissionService, - folderDal, - secretDal, - sarSecretDal, - sarReviewerDal, - secretVersionDal, - secretBlindIndexDal, - secretApprovalRequestDal - }); const tokenService = tokenServiceFactory({ tokenDal: authTokenDal }); const userService = userServiceFactory({ userDal }); @@ -282,6 +272,17 @@ export const registerRoutes = async ( }); const projectBotService = projectBotServiceFactory({ permissionService, projectBotDal }); + const sarService = secretApprovalRequestServiceFactory({ + permissionService, + folderDal, + sarSecretDal, + sarReviewerDal, + secretVersionDal, + secretBlindIndexDal, + secretApprovalRequestDal, + secretService, + snapshotService + }); const secretRotationQueue = secretRotationQueueFactory({ secretRotationDal, queue: queueService, diff --git a/backend-pg/src/server/routes/v1/invite-org-router.ts b/backend-pg/src/server/routes/v1/invite-org-router.ts index 66d866ba3..b55c76a1a 100644 --- a/backend-pg/src/server/routes/v1/invite-org-router.ts +++ b/backend-pg/src/server/routes/v1/invite-org-router.ts @@ -52,7 +52,6 @@ export const registerInviteOrgRouter = async (server: FastifyZodProvider) => { }) } }, - onRequest: verifyAuth([AuthMode.JWT]), handler: async (req) => { const { user, token } = await server.services.org.verifyUserToOrg({ orgId: req.body.organizationId, diff --git a/backend-pg/src/server/routes/v1/organization-router.ts b/backend-pg/src/server/routes/v1/organization-router.ts index a75ad17a7..08795d793 100644 --- a/backend-pg/src/server/routes/v1/organization-router.ts +++ b/backend-pg/src/server/routes/v1/organization-router.ts @@ -4,7 +4,6 @@ import { IncidentContactsSchema, OrganizationsSchema, OrgMembershipsSchema, - UserEncryptionKeysSchema, UsersSchema } from "@app/db/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -67,7 +66,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { firstName: true, lastName: true, id: true - }).merge(UserEncryptionKeysSchema.pick({ publicKey: true })) + }).merge(z.object({ publicKey: z.string().nullable() })) }) ) .omit({ createdAt: true, updatedAt: true }) diff --git a/backend-pg/src/server/routes/v1/project-env-router.ts b/backend-pg/src/server/routes/v1/project-env-router.ts index 186c7f389..59c314118 100644 --- a/backend-pg/src/server/routes/v1/project-env-router.ts +++ b/backend-pg/src/server/routes/v1/project-env-router.ts @@ -63,7 +63,8 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { }), body: z.object({ slug: z.string().trim().optional(), - name: z.string().trim().optional() + name: z.string().trim().optional(), + position: z.number().optional() }), response: { 200: z.object({ @@ -91,8 +92,10 @@ export const registerProjectEnvRouter = async (server: FastifyZodProvider) => { metadata: { oldName: old.name, oldSlug: old.slug, - newName: old.name, - newSlug: old.slug + oldPos: old.position, + newName: environment.name, + newSlug: environment.slug, + newPos: environment.position } } }); diff --git a/backend-pg/src/server/routes/v3/secret-router.ts b/backend-pg/src/server/routes/v3/secret-router.ts index 298e4c3a8..03925b338 100644 --- a/backend-pg/src/server/routes/v3/secret-router.ts +++ b/backend-pg/src/server/routes/v3/secret-router.ts @@ -1,6 +1,11 @@ import { z } from "zod"; -import { SecretApprovalRequestsSchema, SecretsSchema, SecretType } from "@app/db/schemas"; +import { + SecretApprovalRequestsSchema, + SecretsSchema, + SecretTagsSchema, + SecretType +} from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { CommitType } from "@app/ee/services/secret-approval-request/secret-approval-request-types"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -22,7 +27,18 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - secrets: SecretsSchema.omit({ secretBlindIndex: true }).array() + secrets: SecretsSchema.omit({ secretBlindIndex: true }) + .merge( + z.object({ + tags: SecretTagsSchema.pick({ + id: true, + slug: true, + name: true, + color: true + }).array() + }) + ) + .array() }) } }, diff --git a/backend-pg/src/services/identity/identity-service.ts b/backend-pg/src/services/identity/identity-service.ts index e13b99faf..ff54ffb78 100644 --- a/backend-pg/src/services/identity/identity-service.ts +++ b/backend-pg/src/services/identity/identity-service.ts @@ -61,7 +61,7 @@ export const identityServiceFactory = ({ }; const updateIdentity = async ({ id, role, name, actor, actorId }: TUpdateIdentityDTO) => { - const identityOrgMembership = await identityOrgMembershipDal.findById(id); + const identityOrgMembership = await identityOrgMembershipDal.findOne({ identityId: id }); if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); @@ -97,7 +97,9 @@ export const identityServiceFactory = ({ } const identity = await identityDal.transaction(async (tx) => { - const newIdentity = await identityDal.updateById(id, { name }, tx); + const newIdentity = name + ? await identityDal.updateById(id, { name }, tx) + : await identityDal.findById(id, tx); if (role) { await identityOrgMembershipDal.update( { identityId: id }, @@ -115,7 +117,7 @@ export const identityServiceFactory = ({ }; const deleteIdentity = async ({ actorId, actor, id }: TDeleteIdentityDTO) => { - const identityOrgMembership = await identityOrgMembershipDal.findById(id); + const identityOrgMembership = await identityOrgMembershipDal.findOne({ identityId: id }); if (!identityOrgMembership) throw new BadRequestError({ message: `Failed to find identity with id ${id}` }); diff --git a/backend-pg/src/services/org/org-dal.ts b/backend-pg/src/services/org/org-dal.ts index 93d69d6e6..eb32fcd5b 100644 --- a/backend-pg/src/services/org/org-dal.ts +++ b/backend-pg/src/services/org/org-dal.ts @@ -46,7 +46,7 @@ export const orgDalFactory = (db: TDbClient) => { const members = await db(TableName.OrgMembership) .where({ orgId }) .join(TableName.Users, `${TableName.OrgMembership}.userId`, `${TableName.Users}.id`) - .join( + .leftJoin( TableName.UserEncryptionKey, `${TableName.UserEncryptionKey}.userId`, `${TableName.Users}.id` diff --git a/backend-pg/src/services/org/org-service.ts b/backend-pg/src/services/org/org-service.ts index 6978ea907..afa9f55a5 100644 --- a/backend-pg/src/services/org/org-service.ts +++ b/backend-pg/src/services/org/org-service.ts @@ -253,6 +253,7 @@ export const orgServiceFactory = ({ await orgDal.createMembership({ inviteEmail: inviteeEmail, orgId, + userId: user.id, role: OrgMembershipRole.Member, status: OrgMembershipStatus.Invited }); diff --git a/backend-pg/src/services/project-env/project-env-dal.ts b/backend-pg/src/services/project-env/project-env-dal.ts index fb4c70307..6433bc2e7 100644 --- a/backend-pg/src/services/project-env/project-env-dal.ts +++ b/backend-pg/src/services/project-env/project-env-dal.ts @@ -26,38 +26,49 @@ export const projectEnvDalFactory = (db: TDbClient) => { const findLastEnvPosition = async (projectId: string, tx?: Knex) => { const lastPos = await (tx || db)(TableName.Environment) .where({ projectId }) - .max("position") + .max({ position: "position" }) .first(); - return lastPos?.position || 1; + return lastPos?.position || 0; }; - const incrementLastPosition = async ( + const updateAllPosition = async ( projectId: string, - startPos: number, - increment = 1, + pos: number, + targetPos: number, tx?: Knex - ) => - (tx || db)(TableName.Environment) - .where("projectId", projectId) - .where("postion", ">=", startPos) - .increment("position", increment); + ) => { + try { + if (targetPos === -1) { + // this means delete + await (tx || db)(TableName.Environment) + .where({ projectId }) + .andWhere("position", ">", pos) + .decrement("position", 1); + return; + } - const decrementLastPosition = async ( - projectId: string, - startPos: number, - decrement = 1, - tx?: Knex - ) => - (tx || db)(TableName.Environment) - .where("projectId", projectId) - .where("postion", ">", startPos) - .decrement("position", decrement); + if (targetPos > pos) { + await (tx || db)(TableName.Environment) + .where({ projectId }) + .where("position", "<=", targetPos) + .andWhere("position", ">", pos) + .decrement("position", 1); + } else { + await (tx || db)(TableName.Environment) + .where({ projectId }) + .where("position", ">=", targetPos) + .andWhere("position", "<", pos) + .increment("position", 1); + } + } catch (error) { + throw new DatabaseError({ error, name: "UpdateEnvPos" }); + } + }; return { ...projectEnvOrm, findBySlugs, findLastEnvPosition, - decrementLastPosition, - incrementLastPosition + updateAllPosition }; }; diff --git a/backend-pg/src/services/project-env/project-env-service.ts b/backend-pg/src/services/project-env/project-env-service.ts index b3097f132..0e64ca48b 100644 --- a/backend-pg/src/services/project-env/project-env-service.ts +++ b/backend-pg/src/services/project-env/project-env-service.ts @@ -8,7 +8,7 @@ import { import { BadRequestError } from "@app/lib/errors"; import { TProjectEnvDalFactory } from "./project-env-dal"; -import { TCreateEnvDTO, TDeleteEnvDTO, TReorderEnvDTO, TUpdateEnvDTO } from "./project-env-types"; +import { TCreateEnvDTO, TDeleteEnvDTO, TUpdateEnvDTO } from "./project-env-types"; type TProjectEnvServiceFactoryDep = { projectEnvDal: TProjectEnvDalFactory; @@ -38,7 +38,7 @@ export const projectEnvServiceFactory = ({ const env = await projectEnvDal.transaction(async (tx) => { const lastPos = await projectEnvDal.findLastEnvPosition(projectId, tx); - const doc = await projectEnvDal.create({ slug, name, projectId, position: lastPos }, tx); + const doc = await projectEnvDal.create({ slug, name, projectId, position: lastPos + 1 }, tx); return doc; }); return env; @@ -50,7 +50,8 @@ export const projectEnvServiceFactory = ({ actor, actorId, name, - id + id, + position }: TUpdateEnvDTO) => { const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); ForbiddenError.from(permission).throwUnlessCan( @@ -71,7 +72,12 @@ export const projectEnvServiceFactory = ({ } } - const env = await projectEnvDal.updateById(oldEnv.id, { name, slug }); + const env = await projectEnvDal.transaction(async (tx) => { + if (position) { + await projectEnvDal.updateAllPosition(projectId, oldEnv.position, position, tx); + } + return projectEnvDal.updateById(oldEnv.id, { name, slug, position }, tx); + }); return { environment: env, old: oldEnv }; }; @@ -90,36 +96,15 @@ export const projectEnvServiceFactory = ({ name: "Re-order env" }); - await projectEnvDal.decrementLastPosition(projectId, doc.position, 1, tx); + await projectEnvDal.updateAllPosition(projectId, doc.position, -1, tx); return doc; }); return env; }; - const reorderEnvironment = async ({ projectId, id, actorId, actor, pos }: TReorderEnvDTO) => { - const { permission } = await permissionService.getProjectPermission(actor, actorId, projectId); - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.Environments - ); - - const [env] = await projectEnvDal.transaction(async (tx) => { - await projectEnvDal.incrementLastPosition(projectId, pos, 1, tx); - return projectEnvDal.update({ id, projectId }, { position: pos }, tx); - }); - if (!env) - throw new BadRequestError({ - message: "Env doesn't exist", - name: "Re-order env" - }); - - return env; - }; - return { createEnvironment, updateEnvironment, - deleteEnvironment, - reorderEnvironment + deleteEnvironment }; }; diff --git a/backend-pg/src/services/project-env/project-env-types.ts b/backend-pg/src/services/project-env/project-env-types.ts index d7265ea04..1cd8c8dd0 100644 --- a/backend-pg/src/services/project-env/project-env-types.ts +++ b/backend-pg/src/services/project-env/project-env-types.ts @@ -9,6 +9,7 @@ export type TUpdateEnvDTO = { id: string; name?: string; slug?: string; + position?: number; } & TProjectPermission; export type TDeleteEnvDTO = { diff --git a/backend-pg/src/services/secret/secret-dal.ts b/backend-pg/src/services/secret/secret-dal.ts index 039133845..51b0bb75f 100644 --- a/backend-pg/src/services/secret/secret-dal.ts +++ b/backend-pg/src/services/secret/secret-dal.ts @@ -1,9 +1,16 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { SecretType, TableName, TSecrets, TSecretsInsert, TSecretsUpdate } from "@app/db/schemas"; +import { + SecretsSchema, + SecretType, + TableName, + TSecrets, + TSecretsInsert, + TSecretsUpdate +} from "@app/db/schemas"; import { BadRequestError, DatabaseError } from "@app/lib/errors"; -import { mergeOneToManyRelation, ormify, selectAllTableCols } from "@app/lib/knex"; +import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex"; export type TSecretDalFactory = ReturnType; @@ -90,19 +97,23 @@ export const secretDalFactory = (db: TDbClient) => { .select(db.ref("color").withSchema(TableName.SecretTag).as("tagColor")) .select(db.ref("slug").withSchema(TableName.SecretTag).as("tagSlug")) .select(db.ref("name").withSchema(TableName.SecretTag).as("tagName")); - const formatedSecs = mergeOneToManyRelation( - secs, - "id", - ({ tagColor, tagId, tagName, tagSlug, ...data }) => data, - ({ tagSlug: slug, tagName: name, tagId: id, tagColor: color }) => ({ - id, - slug, - name, - color - }), - "tags" - ); - return formatedSecs; + return sqlNestRelationships({ + data: secs, + key: "id", + parentMapper: (el) => SecretsSchema.parse(el), + childrenMapper: [ + { + key: "tagId", + label: "tags" as const, + mapper: ({ tagId: id, tagColor: color, tagSlug: slug, tagName: name }) => ({ + id, + color, + slug, + name + }) + } + ] + }); } catch (error) { throw new DatabaseError({ error, name: "get all secret" }); } diff --git a/backend-pg/src/services/secret/secret-service.ts b/backend-pg/src/services/secret/secret-service.ts index 45f119c74..cde6aea52 100644 --- a/backend-pg/src/services/secret/secret-service.ts +++ b/backend-pg/src/services/secret/secret-service.ts @@ -29,6 +29,7 @@ import { TDeleteBulkSecretDTO, TDeleteSecretDTO, TFnSecretBlindIndexCheck, + TFnSecretBlindIndexCheckV2, TFnSecretBulkDelete, TFnSecretBulkInsert, TFnSecretBulkUpdate, @@ -109,8 +110,8 @@ export const secretServiceFactory = ({ const newSecretGroupByBlindIndex = groupBy(newSecrets, (item) => item.secretBlindIndex); const newSecretTags = inputSecrets.flatMap(({ tags: secretTags = [], secretBlindIndex }) => secretTags.map((tag) => ({ - [`${TableName.SecretTag}Id`]: tag, - [`${TableName.Secret}Id`]: newSecretGroupByBlindIndex[secretBlindIndex][0].id + [`${TableName.SecretTag}Id` as const]: tag, + [`${TableName.Secret}Id` as const]: newSecretGroupByBlindIndex[secretBlindIndex][0].id })) ); if (newSecretTags.length) { @@ -147,8 +148,8 @@ export const secretServiceFactory = ({ ); const newSecretTags = secsUpdatedTag.flatMap(({ tags: secretTags = [], id }) => secretTags.map((tag) => ({ - [`${TableName.SecretTag}Id`]: tag, - [`${TableName.Secret}Id`]: id + [`${TableName.SecretTag}Id` as const]: tag, + [`${TableName.Secret}Id` as const]: id })) ); await secretTagDal.saveTagsToSecret(newSecretTags, tx); @@ -229,6 +230,29 @@ export const secretServiceFactory = ({ return { blindIndex2KeyName, keyName2BlindIndex, secrets }; }; + // this is used when secret blind index already exist + // mainly for secret approval + const fnSecretBlindIndexCheckV2 = async ({ + inputSecrets, + folderId, + userId + }: TFnSecretBlindIndexCheckV2) => { + if (inputSecrets.some(({ type }) => type === SecretType.Personal) && !userId) { + throw new BadRequestError({ message: "Missing user id for personal secret" }); + } + const secrets = await secretDal.findByBlindIndexes( + folderId, + inputSecrets.map(({ secretBlindIndex, type }) => ({ + blindIndex: secretBlindIndex, + type: type || SecretType.Shared + })), + userId + ); + const secsGroupedByBlindIndex = groupBy(secrets, (i) => i.secretBlindIndex); + + return { secsGroupedByBlindIndex, secrets }; + }; + const createSecret = async ({ path, actor, @@ -540,7 +564,7 @@ export const secretServiceFactory = ({ fnSecretBulkInsert({ inputSecrets: inputSecrets.map(({ secretName, ...el }) => ({ ...el, - version:0, + version: 0, secretBlindIndex: keyName2BlindIndex[secretName], type: SecretType.Shared, algorithm: SecretEncryptionAlgo.AES_256_GCM, @@ -717,6 +741,7 @@ export const secretServiceFactory = ({ fnSecretBulkDelete, fnSecretBulkUpdate, fnSecretBlindIndexCheck, - fnSecretBulkInsert + fnSecretBulkInsert, + fnSecretBlindIndexCheckV2 }; }; diff --git a/backend-pg/src/services/secret/secret-types.ts b/backend-pg/src/services/secret/secret-types.ts index ac9229725..a6442bb13 100644 --- a/backend-pg/src/services/secret/secret-types.ts +++ b/backend-pg/src/services/secret/secret-types.ts @@ -153,3 +153,10 @@ export type TFnSecretBlindIndexCheck = { inputSecrets: Array<{ secretName: string; type?: SecretType }>; isNew: boolean; }; + +// when blind index is already present +export type TFnSecretBlindIndexCheckV2 = { + folderId: string; + userId?: string; + inputSecrets: Array<{ secretBlindIndex: string; type?: SecretType }>; +}; diff --git a/frontend/src/hooks/api/users/mutation.tsx b/frontend/src/hooks/api/users/mutation.tsx index 4d92202a8..03276c2ef 100644 --- a/frontend/src/hooks/api/users/mutation.tsx +++ b/frontend/src/hooks/api/users/mutation.tsx @@ -35,7 +35,7 @@ export const useAddUserToWs = () => { workspaceEncryptedNonce: inviteeNonce }; }); - const { data } = await apiRequest.post(`/api/v2/workspace/${workspaceId}/memberships`, { + const { data } = await apiRequest.post(`/api/v1/workspace/${workspaceId}/memberships`, { members: newWsMembers }); return data; diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts index 5868d6f5b..47c733885 100644 --- a/frontend/src/hooks/api/users/types.ts +++ b/frontend/src/hooks/api/users/types.ts @@ -49,7 +49,7 @@ export type OrgUser = { role: "owner" | "admin" | "member" | "no-access" | "custom"; status: "invited" | "accepted" | "verified" | "completed"; deniedPermissions: any[]; - customRole: string; + roleId: string; }; export type TWorkspaceUser = OrgUser; diff --git a/frontend/src/hooks/api/workspace/queries.tsx b/frontend/src/hooks/api/workspace/queries.tsx index c18830649..f47a77537 100644 --- a/frontend/src/hooks/api/workspace/queries.tsx +++ b/frontend/src/hooks/api/workspace/queries.tsx @@ -14,7 +14,6 @@ import { DeleteWorkspaceDTO, NameWorkspaceSecretsDTO, RenameWorkspaceDTO, - ReorderEnvironmentsDTO, ToggleAutoCapitalizationDTO, UpdateEnvironmentDTO, Workspace @@ -29,8 +28,9 @@ export const workspaceKeys = { getWorkspaceAuthorization: (workspaceId: string) => [{ workspaceId }, "workspace-authorizations"], getWorkspaceIntegrations: (workspaceId: string) => [{ workspaceId }, "workspace-integrations"], getAllUserWorkspace: ["workspaces"] as const, - getWorkspaceAuditLogs: (workspaceId: string) => [{ workspaceId }] as const, - getWorkspaceUsers: (workspaceId: string) => [{ workspaceId }] as const, + getWorkspaceAuditLogs: (workspaceId: string) => + [{ workspaceId }, "workspace-audit-logs"] as const, + getWorkspaceUsers: (workspaceId: string) => [{ workspaceId }, "workspace-users"] as const, getWorkspaceIdentityMemberships: (workspaceId: string) => [{ workspaceId }, "workspace-identity-memberships"] as const }; @@ -234,38 +234,15 @@ export const useCreateWsEnvironment = () => { }); }; -export const useReorderWsEnvironment = () => { - const queryClient = useQueryClient(); - - return useMutation<{}, {}, ReorderEnvironmentsDTO>({ - mutationFn: ({ - workspaceId, - environmentSlug, - environmentName, - otherEnvironmentSlug, - otherEnvironmentName - }) => { - return apiRequest.patch(`/api/v1/workspace/${workspaceId}/environments`, { - environmentSlug, - environmentName, - otherEnvironmentSlug, - otherEnvironmentName - }); - }, - onSuccess: () => { - queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace); - } - }); -}; - export const useUpdateWsEnvironment = () => { const queryClient = useQueryClient(); return useMutation<{}, {}, UpdateEnvironmentDTO>({ - mutationFn: ({ workspaceId, id, name, slug }) => { + mutationFn: ({ workspaceId, id, name, slug, position }) => { return apiRequest.patch(`/api/v1/workspace/${workspaceId}/environments/${id}`, { name, - slug + slug, + position }); }, onSuccess: () => { @@ -335,7 +312,7 @@ export const useDeleteUserFromWorkspace = () => { }) => { const { data: { deletedMembership } - } = await apiRequest.delete(`/api/v1/${workspaceId}/membership/${membershipId}`); + } = await apiRequest.delete(`/api/v1/workspace/${workspaceId}/memberships/${membershipId}`); return deletedMembership; }, onSuccess: (_, { workspaceId }) => { @@ -358,13 +335,16 @@ export const useUpdateUserWorkspaceRole = () => { }) => { const { data: { membership } - } = await apiRequest.post(`/api/v1/${workspaceId}/membership/${membershipId}`, { - role - }); + } = await apiRequest.patch<{ membership: { projectId: string } }>( + `/api/v1/workspace/${workspaceId}/memberships/${membershipId}`, + { + role + } + ); return membership; }, onSuccess: (res) => { - queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(res.workspace)); + queryClient.invalidateQueries(workspaceKeys.getWorkspaceUsers(res.projectId)); } }); }; diff --git a/frontend/src/hooks/api/workspace/types.ts b/frontend/src/hooks/api/workspace/types.ts index 052c1d491..acec07d45 100644 --- a/frontend/src/hooks/api/workspace/types.ts +++ b/frontend/src/hooks/api/workspace/types.ts @@ -53,6 +53,7 @@ export type UpdateEnvironmentDTO = { id: string; name?: string; slug?: string; + position?: number; }; export type DeleteEnvironmentDTO = { workspaceId: string; id: string }; diff --git a/frontend/src/pages/signupinvite.tsx b/frontend/src/pages/signupinvite.tsx index 6ce4c744f..5eaa48e63 100644 --- a/frontend/src/pages/signupinvite.tsx +++ b/frontend/src/pages/signupinvite.tsx @@ -54,7 +54,7 @@ export default function SignupInvite() { const router = useRouter(); const parsedUrl = queryString.parse(router.asPath.split("?")[1]); const token = parsedUrl.token as string; - const organizationId = parsedUrl.organizationid as string; + const organizationId = parsedUrl.organization_id as string; const email = (parsedUrl.to as string)?.replace(" ", "+").trim(); // Verifies if the information that the users entered (name, workspace) is there, and if the password matched the criteria. diff --git a/frontend/src/views/Org/MembersPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx b/frontend/src/views/Org/MembersPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx index acd4fe735..fc979127e 100644 --- a/frontend/src/views/Org/MembersPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx +++ b/frontend/src/views/Org/MembersPage/components/OrgMembersTab/components/OrgMembersSection/OrgMembersTable.tsx @@ -57,7 +57,6 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLink }: Prop const orgId = currentOrg?.id || ""; const { data: roles, isLoading: isRolesLoading } = useGetOrgRoles(orgId); - console.log(roles); const [searchMemberFilter, setSearchMemberFilter] = useState(""); @@ -172,7 +171,7 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLink }: Prop {isLoading && } {!isLoading && filterdUser?.map( - ({ user: u, inviteEmail, role, customRole, id: orgMembershipId, status }) => { + ({ user: u, inviteEmail, role, roleId, id: orgMembershipId, status }) => { const name = u ? `${u.firstName} ${u.lastName}` : "-"; const email = u?.email || inviteEmail; return ( @@ -188,9 +187,7 @@ export const OrgMembersTable = ({ handlePopUpOpen, setCompleteInviteLink }: Prop <> {status === "accepted" && ( { () => members?.find(({ user: u }) => userId === u?.id)?.role === "owner", [userId, members] ); + console.log(members); const findRoleFromId = useCallback( (roleId: string) => { @@ -290,7 +291,7 @@ export const MemberListTab = () => { {isLoading && } {!isLoading && filterdUsers?.map( - ({ user: u, inviteEmail, id: membershipId, status, customRole, role }) => { + ({ user: u, inviteEmail, id: membershipId, status, roleId, role }) => { const name = u ? `${u.firstName} ${u.lastName}` : "-"; const email = u?.email || inviteEmail; @@ -306,9 +307,7 @@ export const MemberListTab = () => { {(isAllowed) => ( <>