From 9137fa4ca5719bb41f6b2766a936f561f72635f2 Mon Sep 17 00:00:00 2001 From: x032205 Date: Mon, 7 Jul 2025 13:31:20 -0400 Subject: [PATCH] Improve + fix invitation reminder logic --- .../20250707162850_last-invited-at-default.ts | 21 +++++++++++++++++++ .../org-membership/org-membership-dal.ts | 19 ++++++++++++++--- backend/src/services/org/org-service.ts | 17 ++++++++++----- 3 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 backend/src/db/migrations/20250707162850_last-invited-at-default.ts diff --git a/backend/src/db/migrations/20250707162850_last-invited-at-default.ts b/backend/src/db/migrations/20250707162850_last-invited-at-default.ts new file mode 100644 index 000000000..bfb7b85d6 --- /dev/null +++ b/backend/src/db/migrations/20250707162850_last-invited-at-default.ts @@ -0,0 +1,21 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasColumn = await knex.schema.hasColumn(TableName.OrgMembership, "lastInvitedAt"); + if (hasColumn) { + await knex.schema.alterTable(TableName.OrgMembership, (t) => { + t.datetime("lastInvitedAt").nullable().defaultTo(knex.fn.now()).alter(); + }); + } +} + +export async function down(knex: Knex): Promise { + const hasColumn = await knex.schema.hasColumn(TableName.OrgMembership, "lastInvitedAt"); + if (hasColumn) { + await knex.schema.alterTable(TableName.OrgMembership, (t) => { + t.datetime("lastInvitedAt").nullable().alter(); + }); + } +} diff --git a/backend/src/services/org-membership/org-membership-dal.ts b/backend/src/services/org-membership/org-membership-dal.ts index 1fbe03f4b..ebf1700d0 100644 --- a/backend/src/services/org-membership/org-membership-dal.ts +++ b/backend/src/services/org-membership/org-membership-dal.ts @@ -122,8 +122,8 @@ export const orgMembershipDALFactory = (db: TDbClient) => { .orWhere((qb) => { // lastInvitedAt is older than 1 week ago AND createdAt is younger than 1 month ago void qb - .where(`${TableName.OrgMembership}.lastInvitedAt`, "<", oneMonthAgo) - .where(`${TableName.OrgMembership}.createdAt`, ">", oneWeekAgo); + .where(`${TableName.OrgMembership}.lastInvitedAt`, "<", oneWeekAgo) + .where(`${TableName.OrgMembership}.createdAt`, ">", oneMonthAgo); }); return memberships; @@ -135,9 +135,22 @@ export const orgMembershipDALFactory = (db: TDbClient) => { } }; + const updateLastInvitedAtByIds = async (membershipIds: string[]) => { + try { + if (membershipIds.length === 0) return; + await db(TableName.OrgMembership).whereIn("id", membershipIds).update({ lastInvitedAt: new Date() }); + } catch (error) { + throw new DatabaseError({ + error, + name: "Update last invited at by ids" + }); + } + }; + return { ...orgMembershipOrm, findOrgMembershipById, - findRecentInvitedMemberships + findRecentInvitedMemberships, + updateLastInvitedAtByIds }; }; diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 195ddae3e..eea37e627 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -109,7 +109,12 @@ type TOrgServiceFactoryDep = { projectKeyDAL: Pick; orgMembershipDAL: Pick< TOrgMembershipDALFactory, - "findOrgMembershipById" | "findOne" | "findById" | "findRecentInvitedMemberships" | "updateById" + | "findOrgMembershipById" + | "findOne" + | "findById" + | "findRecentInvitedMemberships" + | "updateById" + | "updateLastInvitedAtByIds" >; incidentContactDAL: TIncidentContactsDALFactory; samlConfigDAL: Pick; @@ -763,6 +768,10 @@ export const orgServiceFactory = ({ } }); + await orgMembershipDAL.updateById(inviteeOrgMembership.id, { + lastInvitedAt: new Date() + }); + return { signupToken: undefined }; }; @@ -1464,12 +1473,10 @@ export const orgServiceFactory = ({ } }); } - - await orgMembershipDAL.updateById(invitedUser.id, { - lastInvitedAt: new Date() - }); }) ); + + await orgMembershipDAL.updateLastInvitedAtByIds(invitedUsers.map((u) => u.id)); }; return {