diff --git a/backend/src/services/secret-reminder-recipients/secret-reminder-recipients-dal.ts b/backend/src/services/secret-reminder-recipients/secret-reminder-recipients-dal.ts index 5e8f388f9..ec4a3f807 100644 --- a/backend/src/services/secret-reminder-recipients/secret-reminder-recipients-dal.ts +++ b/backend/src/services/secret-reminder-recipients/secret-reminder-recipients-dal.ts @@ -1,3 +1,5 @@ +import { Knex } from "knex"; + import { TDbClient } from "@app/db"; import { TableName } from "@app/db/schemas"; import { ormify, selectAllTableCols } from "@app/lib/knex"; @@ -7,9 +9,8 @@ export type TSecretReminderRecipientsDALFactory = ReturnType { const secretReminderRecipientsOrm = ormify(db, TableName.SecretReminderRecipients); - const findUsersBySecretId = async (secretId: string) => { - const res = await db - .replicaNode()(TableName.SecretReminderRecipients) + const findUsersBySecretId = async (secretId: string, tx?: Knex) => { + const res = await (tx || db.replicaNode())(TableName.SecretReminderRecipients) .where({ secretId }) .leftJoin(TableName.Users, `${TableName.SecretReminderRecipients}.userId`, `${TableName.Users}.id`) .leftJoin(TableName.Project, `${TableName.SecretReminderRecipients}.projectId`, `${TableName.Project}.id`) diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts index 56e9e91f5..4f813b3d7 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-fns.ts @@ -346,7 +346,7 @@ export const fnSecretBulkDelete = async ({ deletedSecrets .filter(({ reminderRepeatDays }) => Boolean(reminderRepeatDays)) .map(({ id, reminderRepeatDays }) => - secretQueueService.removeSecretReminder({ secretId: id, repeatDays: reminderRepeatDays as number }) + secretQueueService.removeSecretReminder({ secretId: id, repeatDays: reminderRepeatDays as number }, tx) ) ); diff --git a/backend/src/services/secret-v2-bridge/secret-v2-bridge-types.ts b/backend/src/services/secret-v2-bridge/secret-v2-bridge-types.ts index d3e4464fb..f4a27d4c5 100644 --- a/backend/src/services/secret-v2-bridge/secret-v2-bridge-types.ts +++ b/backend/src/services/secret-v2-bridge/secret-v2-bridge-types.ts @@ -221,7 +221,7 @@ export type TFnSecretBulkDelete = { tx?: Knex; secretDAL: Pick; secretQueueService: { - removeSecretReminder: (data: TRemoveSecretReminderDTO) => Promise; + removeSecretReminder: (data: TRemoveSecretReminderDTO, tx?: Knex) => Promise; }; }; diff --git a/backend/src/services/secret/secret-fns.ts b/backend/src/services/secret/secret-fns.ts index c295be7e7..ddc9edc07 100644 --- a/backend/src/services/secret/secret-fns.ts +++ b/backend/src/services/secret/secret-fns.ts @@ -737,7 +737,7 @@ export const fnSecretBulkDelete = async ({ deletedSecrets .filter(({ secretReminderRepeatDays }) => Boolean(secretReminderRepeatDays)) .map(({ id, secretReminderRepeatDays }) => - secretQueueService.removeSecretReminder({ secretId: id, repeatDays: secretReminderRepeatDays as number }) + secretQueueService.removeSecretReminder({ secretId: id, repeatDays: secretReminderRepeatDays as number }, tx) ) ); diff --git a/backend/src/services/secret/secret-queue.ts b/backend/src/services/secret/secret-queue.ts index a768a4fe5..de9b6f990 100644 --- a/backend/src/services/secret/secret-queue.ts +++ b/backend/src/services/secret/secret-queue.ts @@ -1,6 +1,7 @@ /* eslint-disable no-await-in-loop */ import opentelemetry from "@opentelemetry/api"; import { AxiosError } from "axios"; +import { Knex } from "knex"; import { ProjectMembershipRole, @@ -185,8 +186,10 @@ export const secretQueueFactory = ({ unit: "1" }); - const removeSecretReminder = async (dto: TRemoveSecretReminderDTO) => { - await secretReminderRecipientsDAL.delete({ secretId: dto.secretId }); + const removeSecretReminder = async ({ deleteRecipients = true, ...dto }: TRemoveSecretReminderDTO, tx?: Knex) => { + if (deleteRecipients) { + await secretReminderRecipientsDAL.delete({ secretId: dto.secretId }, tx); + } const appCfg = getConfig(); await queueService.stopRepeatableJob( @@ -233,7 +236,12 @@ export const secretQueueFactory = ({ .replace(":", "-"); }; - const addSecretReminder = async ({ oldSecret, newSecret, projectId, recipients }: TCreateSecretReminderDTO) => { + const addSecretReminder = async ({ + oldSecret, + newSecret, + projectId, + deleteRecipients = true + }: TCreateSecretReminderDTO) => { try { const appCfg = getConfig(); @@ -255,28 +263,11 @@ export const secretQueueFactory = ({ if (oldSecret.secretReminderRepeatDays) { await removeSecretReminder({ repeatDays: oldSecret.secretReminderRepeatDays, - secretId: oldSecret.id + secretId: oldSecret.id, + deleteRecipients }); } - const existingRecipients = await secretReminderRecipientsDAL.findUsersBySecretId(newSecret.id); - - if (recipients?.length) { - await secretReminderRecipientsDAL.transaction(async (tx) => { - await secretReminderRecipientsDAL.delete({ secretId: newSecret.id }, tx); - await secretReminderRecipientsDAL.insertMany( - recipients.map((r) => ({ - secretId: newSecret.id, - userId: r, - projectId - })), - tx - ); - }); - } else if (existingRecipients) { - await secretReminderRecipientsDAL.delete({ secretId: newSecret.id }); - } - await queueService.queue( QueueName.SecretReminder, QueueJobs.SecretReminder, @@ -315,33 +306,52 @@ export const secretQueueFactory = ({ const recipientsUpdated = secretReminderRecipients?.some( (newId) => !oldSecret.secretReminderRecipients?.find((oldId) => newId === oldId) - ) || - (secretReminderRecipients?.length !== oldSecret.secretReminderRecipients?.length && - secretReminderRepeatDays !== null); + ) || secretReminderRecipients?.length !== oldSecret.secretReminderRecipients?.length; - if (newSecret.type !== SecretType.Personal && secretReminderRepeatDays !== undefined) { - if ( - (secretReminderRepeatDays && oldSecret.secretReminderRepeatDays !== secretReminderRepeatDays) || - (secretReminderNote && oldSecret.secretReminderNote !== secretReminderNote) || - recipientsUpdated - ) { - await addSecretReminder({ - oldSecret, - newSecret, - projectId, - recipients: newSecret.secretReminderRecipients - }); - } else if ( - secretReminderRepeatDays === null && - secretReminderNote === null && - oldSecret.secretReminderRepeatDays - ) { - await removeSecretReminder({ - secretId: oldSecret.id, - repeatDays: oldSecret.secretReminderRepeatDays - }); + await secretReminderRecipientsDAL.transaction(async (tx) => { + if (newSecret.type !== SecretType.Personal && secretReminderRepeatDays !== undefined) { + if ( + (secretReminderRepeatDays && oldSecret.secretReminderRepeatDays !== secretReminderRepeatDays) || + (secretReminderNote && oldSecret.secretReminderNote !== secretReminderNote) + ) { + await addSecretReminder({ + oldSecret, + newSecret, + projectId, + deleteRecipients: false + }); + } else if ( + secretReminderRepeatDays === null && + secretReminderNote === null && + oldSecret.secretReminderRepeatDays + ) { + await removeSecretReminder({ + secretId: oldSecret.id, + repeatDays: oldSecret.secretReminderRepeatDays + }); + } } - } + + if (recipientsUpdated) { + // if no recipients, delete all existing recipients + if (!secretReminderRecipients?.length) { + const existingRecipients = await secretReminderRecipientsDAL.findUsersBySecretId(newSecret.id, tx); + if (existingRecipients) { + await secretReminderRecipientsDAL.delete({ secretId: newSecret.id }, tx); + } + } else { + await secretReminderRecipientsDAL.delete({ secretId: newSecret.id }, tx); + await secretReminderRecipientsDAL.insertMany( + secretReminderRecipients.map((r) => ({ + secretId: newSecret.id, + userId: r, + projectId + })), + tx + ); + } + } + }); }; const createManySecretsRawFn = createManySecretsRawFnFactory({ projectDAL, diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index d69d587d2..46ed7ef83 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -546,10 +546,13 @@ export const secretServiceFactory = ({ for await (const secret of secrets) { if (secret.secretReminderRepeatDays !== null && secret.secretReminderRepeatDays !== undefined) { - await secretQueueService.removeSecretReminder({ - repeatDays: secret.secretReminderRepeatDays, - secretId: secret.id - }); + await secretQueueService.removeSecretReminder( + { + repeatDays: secret.secretReminderRepeatDays, + secretId: secret.id + }, + tx + ); } } @@ -1074,10 +1077,13 @@ export const secretServiceFactory = ({ for await (const secret of secrets) { if (secret.secretReminderRepeatDays !== null && secret.secretReminderRepeatDays !== undefined) { - await secretQueueService.removeSecretReminder({ - repeatDays: secret.secretReminderRepeatDays, - secretId: secret.id - }); + await secretQueueService.removeSecretReminder( + { + repeatDays: secret.secretReminderRepeatDays, + secretId: secret.id + }, + tx + ); } } const secretValueHidden = !hasSecretReadValueOrDescribePermission( diff --git a/backend/src/services/secret/secret-types.ts b/backend/src/services/secret/secret-types.ts index 82df6023f..30e3dfafa 100644 --- a/backend/src/services/secret/secret-types.ts +++ b/backend/src/services/secret/secret-types.ts @@ -379,7 +379,7 @@ export type TFnSecretBulkDelete = { tx?: Knex; secretDAL: Pick; secretQueueService: { - removeSecretReminder: (data: TRemoveSecretReminderDTO) => Promise; + removeSecretReminder: (data: TRemoveSecretReminderDTO, tx?: Knex) => Promise; }; }; @@ -410,12 +410,14 @@ export type TCreateSecretReminderDTO = { oldSecret: TPartialSecret; newSecret: TPartialSecret; projectId: string; - recipients?: string[] | null; + + deleteRecipients?: boolean; }; export type TRemoveSecretReminderDTO = { secretId: string; repeatDays: number; + deleteRecipients?: boolean; }; export type TBackFillSecretReferencesDTO = TProjectPermission; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/CreateReminderForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/CreateReminderForm.tsx index 5f95d7149..dba934301 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/CreateReminderForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/SecretListView/CreateReminderForm.tsx @@ -87,6 +87,15 @@ export const CreateReminderForm = ({ } }, [members, isOpen, recipients]); + useEffect(() => { + if (repeatDays) { + setValue("days", repeatDays); + } + if (note) { + setValue("note", note); + } + }, [repeatDays, note]); + return (