1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-19 05:09:43 +02:00

feat: Add ability to mention users in comments (#1162)

This commit is contained in:
Roman Zavarnitsyn 2025-05-30 22:01:29 +02:00 committed by GitHub
parent eb2a3a2875
commit c0b0436851
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 357 additions and 42 deletions

View file

@ -6,10 +6,18 @@
const escapeMarkdown = require('escape-markdown');
const escapeHtml = require('escape-html');
const { formatTextWithMentions } = require('../../../utils/formatters');
const extractMentionedUserIds = (text) => {
const mentionRegex = /@\[.*?\]\((.*?)\)/g;
const matches = [...text.matchAll(mentionRegex)];
return matches.map((match) => match[1]);
};
const buildAndSendNotifications = async (services, board, card, comment, actorUser, t) => {
const markdownCardLink = `[${escapeMarkdown(card.name)}](${sails.config.custom.baseUrl}/cards/${card.id})`;
const htmlCardLink = `<a href="${sails.config.custom.baseUrl}/cards/${card.id}}">${escapeHtml(card.name)}</a>`;
const commentText = _.truncate(comment.text);
const commentText = _.truncate(formatTextWithMentions(comment.text));
await sails.helpers.utils.sendNotifications(services, t('New Comment'), {
text: `${t(
@ -91,6 +99,19 @@ module.exports = {
user: values.user,
});
let mentionedUserIds = extractMentionedUserIds(values.text);
if (mentionedUserIds.length > 0) {
const boardMemberUserIds = await sails.helpers.boards.getMemberUserIds(inputs.board.id);
mentionedUserIds = _.difference(
_.intersection(mentionedUserIds, boardMemberUserIds),
comment.userId,
);
}
const mentionedUserIdsSet = new Set(mentionedUserIds);
const cardSubscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds(
comment.cardId,
comment.userId,
@ -101,7 +122,11 @@ module.exports = {
comment.userId,
);
const notifiableUserIds = _.union(cardSubscriptionUserIds, boardSubscriptionUserIds);
const notifiableUserIds = _.union(
mentionedUserIds,
cardSubscriptionUserIds,
boardSubscriptionUserIds,
);
await Promise.all(
notifiableUserIds.map((userId) =>
@ -109,7 +134,9 @@ module.exports = {
values: {
userId,
comment,
type: Notification.Types.COMMENT_CARD,
type: mentionedUserIdsSet.has(userId)
? Notification.Types.MENTION_IN_COMMENT
: Notification.Types.COMMENT_CARD,
data: {
card: _.pick(values.card, ['name']),
text: comment.text,

View file

@ -6,6 +6,8 @@
const escapeMarkdown = require('escape-markdown');
const escapeHtml = require('escape-html');
const { formatTextWithMentions } = require('../../../utils/formatters');
const buildTitle = (notification, t) => {
switch (notification.type) {
case Notification.Types.MOVE_CARD:
@ -14,6 +16,8 @@ const buildTitle = (notification, t) => {
return t('New Comment');
case Notification.Types.ADD_MEMBER_TO_CARD:
return t('You Were Added to Card');
case Notification.Types.MENTION_IN_COMMENT:
return t('You Were Mentioned in Comment');
default:
return null;
}
@ -56,7 +60,7 @@ const buildBodyByFormat = (board, card, notification, actorUser, t) => {
};
}
case Notification.Types.COMMENT_CARD: {
const commentText = _.truncate(notification.data.text);
const commentText = _.truncate(formatTextWithMentions(notification.data.text));
return {
text: `${t(
@ -95,6 +99,30 @@ const buildBodyByFormat = (board, card, notification, actorUser, t) => {
escapeHtml(board.name),
),
};
case Notification.Types.MENTION_IN_COMMENT: {
const commentText = _.truncate(formatTextWithMentions(notification.data.text));
return {
text: `${t(
'%s mentioned you in %s on %s',
actorUser.name,
card.name,
board.name,
)}:\n${commentText}`,
markdown: `${t(
'%s mentioned you in %s on %s',
escapeMarkdown(actorUser.name),
markdownCardLink,
escapeMarkdown(board.name),
)}:\n\n*${escapeMarkdown(commentText)}*`,
html: `${t(
'%s mentioned you in %s on %s',
escapeHtml(actorUser.name),
htmlCardLink,
escapeHtml(board.name),
)}:\n\n<i>${escapeHtml(commentText)}</i>`,
};
}
default:
return null;
}
@ -147,6 +175,15 @@ const buildAndSendEmail = async (board, card, notification, actorUser, notifiabl
boardLink,
)}</p>`;
break;
case Notification.Types.MENTION_IN_COMMENT:
html = `<p>${t(
'%s mentioned you in %s on %s',
escapeHtml(actorUser.name),
cardLink,
boardLink,
)}</p><p>${escapeHtml(notification.data.text)}</p>`;
break;
default:
return;
@ -186,9 +223,11 @@ module.exports = {
values.userId = values.user.id;
}
const isCommentCard = values.type === Notification.Types.COMMENT_CARD;
const isCommentRelated =
values.type === Notification.Types.COMMENT_CARD ||
values.type === Notification.Types.MENTION_IN_COMMENT;
if (isCommentCard) {
if (isCommentRelated) {
values.commentId = values.comment.id;
} else {
values.actionId = values.action.id;
@ -217,7 +256,7 @@ module.exports = {
boards: [inputs.board],
lists: [inputs.list],
cards: [values.card],
...(isCommentCard
...(isCommentRelated
? {
comments: [values.comment],
}

View file

@ -14,6 +14,7 @@ const Types = {
MOVE_CARD: 'moveCard',
COMMENT_CARD: 'commentCard',
ADD_MEMBER_TO_CARD: 'addMemberToCard',
MENTION_IN_COMMENT: 'mentionInComment',
};
module.exports = {