feat: update card router to send emails on mention
This commit is contained in:
@@ -10,6 +10,7 @@ import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
|||||||
|
|
||||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||||
import { mergeActivities } from "../utils/activities";
|
import { mergeActivities } from "../utils/activities";
|
||||||
|
import { sendMentionEmails } from "../utils/notifications";
|
||||||
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
|
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
|
||||||
import { generateAttachmentUrl, generateAvatarUrl } from "@kan/shared/utils";
|
import { generateAttachmentUrl, generateAvatarUrl } from "@kan/shared/utils";
|
||||||
|
|
||||||
@@ -153,6 +154,17 @@ export const cardRouter = createTRPCRouter({
|
|||||||
await cardActivityRepo.bulkCreate(ctx.db, cardActivitesInsert);
|
await cardActivityRepo.bulkCreate(ctx.db, cardActivitesInsert);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (input.description) {
|
||||||
|
sendMentionEmails({
|
||||||
|
db: ctx.db,
|
||||||
|
cardPublicId: newCard.publicId,
|
||||||
|
commentHtml: input.description,
|
||||||
|
commenterUserId: userId,
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to send mention emails:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return newCard;
|
return newCard;
|
||||||
}),
|
}),
|
||||||
addComment: protectedProcedure
|
addComment: protectedProcedure
|
||||||
@@ -215,6 +227,16 @@ export const cardRouter = createTRPCRouter({
|
|||||||
createdBy: userId,
|
createdBy: userId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sendMentionEmails({
|
||||||
|
db: ctx.db,
|
||||||
|
cardPublicId: input.cardPublicId,
|
||||||
|
commentHtml: input.comment,
|
||||||
|
commenterUserId: userId,
|
||||||
|
commentId: newComment.id,
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to send mention emails:", error);
|
||||||
|
});
|
||||||
|
|
||||||
return newComment;
|
return newComment;
|
||||||
}),
|
}),
|
||||||
updateComment: protectedProcedure
|
updateComment: protectedProcedure
|
||||||
@@ -295,6 +317,16 @@ export const cardRouter = createTRPCRouter({
|
|||||||
createdBy: userId,
|
createdBy: userId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sendMentionEmails({
|
||||||
|
db: ctx.db,
|
||||||
|
cardPublicId: input.cardPublicId,
|
||||||
|
commentHtml: input.comment,
|
||||||
|
commenterUserId: userId,
|
||||||
|
commentId: updatedComment.id,
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to send mention emails:", error);
|
||||||
|
});
|
||||||
|
|
||||||
return updatedComment;
|
return updatedComment;
|
||||||
}),
|
}),
|
||||||
deleteComment: protectedProcedure
|
deleteComment: protectedProcedure
|
||||||
@@ -924,6 +956,15 @@ export const cardRouter = createTRPCRouter({
|
|||||||
fromDescription: existingCard.description ?? undefined,
|
fromDescription: existingCard.description ?? undefined,
|
||||||
toDescription: input.description,
|
toDescription: input.description,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sendMentionEmails({
|
||||||
|
db: ctx.db,
|
||||||
|
cardPublicId: input.cardPublicId,
|
||||||
|
commentHtml: input.description,
|
||||||
|
commenterUserId: userId,
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error("Failed to send mention emails:", error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ export * from "./subscriptions";
|
|||||||
export * from "./email";
|
export * from "./email";
|
||||||
export * from "./dueDateFilters";
|
export * from "./dueDateFilters";
|
||||||
export * from "./s3";
|
export * from "./s3";
|
||||||
|
export * from "./mentions";
|
||||||
|
|||||||
22
packages/shared/src/utils/mentions.ts
Normal file
22
packages/shared/src/utils/mentions.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* Parses mention data-id attributes from HTML content
|
||||||
|
* Mentions are stored as: <span data-type="mention" data-id="..." data-label="...">@label</span>
|
||||||
|
* @param htmlContent - The HTML content to parse
|
||||||
|
* @returns Array of unique mention public IDs
|
||||||
|
*/
|
||||||
|
export function parseMentionsFromHTML(htmlContent: string): string[] {
|
||||||
|
if (!htmlContent) return [];
|
||||||
|
|
||||||
|
// Match all mention spans with data-id attributes
|
||||||
|
const mentionRegex = /<span[^>]*data-type="mention"[^>]*data-id="([^"]+)"[^>]*>/gi;
|
||||||
|
const matches = Array.from(htmlContent.matchAll(mentionRegex));
|
||||||
|
|
||||||
|
// Extract unique mention IDs
|
||||||
|
const mentionIds = matches
|
||||||
|
.map((match) => match[1])
|
||||||
|
.filter((id): id is string => !!id && id.length >= 12);
|
||||||
|
|
||||||
|
// Return unique IDs
|
||||||
|
return Array.from(new Set(mentionIds));
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user