mirror of
https://github.com/plankanban/planka.git
synced 2025-07-19 05:09:43 +02:00
feat: Add notification when user is added to card
This commit is contained in:
parent
f43785c3d0
commit
f6568ce41b
14 changed files with 169 additions and 39 deletions
|
@ -84,6 +84,36 @@ const Item = React.memo(({ id }) => {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case ActivityTypes.ADD_MEMBER_TO_CARD:
|
||||||
|
contentNode =
|
||||||
|
user.id === activity.data.user.id ? (
|
||||||
|
<Trans
|
||||||
|
i18nKey="common.userJoinedThisCard"
|
||||||
|
values={{
|
||||||
|
user: userName,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={styles.author}>{userName}</span>
|
||||||
|
<span className={styles.text}>{' joined this card'}</span>
|
||||||
|
</Trans>
|
||||||
|
) : (
|
||||||
|
<Trans
|
||||||
|
i18nKey="common.userAddedUserToThisCard"
|
||||||
|
values={{
|
||||||
|
actorUser: userName,
|
||||||
|
addedUser: activity.data.user.name,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className={styles.author}>{userName}</span>
|
||||||
|
<span className={styles.text}>
|
||||||
|
{' added '}
|
||||||
|
{activity.data.user.name}
|
||||||
|
{' to this card'}
|
||||||
|
</span>
|
||||||
|
</Trans>
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
contentNode = null;
|
contentNode = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,24 @@ const Item = React.memo(({ id, onClose }) => {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case NotificationTypes.ADD_MEMBER_TO_CARD:
|
||||||
|
contentNode = (
|
||||||
|
<Trans
|
||||||
|
i18nKey="common.userAddedYouToCard"
|
||||||
|
values={{
|
||||||
|
user: creatorUserName,
|
||||||
|
card: cardName,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{creatorUserName}
|
||||||
|
{` added you to `}
|
||||||
|
<Link to={Paths.CARDS.replace(':id', notification.cardId)} onClick={onClose}>
|
||||||
|
{cardName}
|
||||||
|
</Link>
|
||||||
|
</Trans>
|
||||||
|
);
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
contentNode = null;
|
contentNode = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,11 +90,13 @@ export const AttachmentTypes = {
|
||||||
export const ActivityTypes = {
|
export const ActivityTypes = {
|
||||||
CREATE_CARD: 'createCard',
|
CREATE_CARD: 'createCard',
|
||||||
MOVE_CARD: 'moveCard',
|
MOVE_CARD: 'moveCard',
|
||||||
|
ADD_MEMBER_TO_CARD: 'addMemberToCard',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NotificationTypes = {
|
export const NotificationTypes = {
|
||||||
MOVE_CARD: 'moveCard',
|
MOVE_CARD: 'moveCard',
|
||||||
COMMENT_CARD: 'commentCard',
|
COMMENT_CARD: 'commentCard',
|
||||||
|
ADD_MEMBER_TO_CARD: 'addMemberToCard',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NotificationServiceFormats = {
|
export const NotificationServiceFormats = {
|
||||||
|
|
|
@ -287,6 +287,9 @@ export default {
|
||||||
uploadedImages: 'Uploaded images',
|
uploadedImages: 'Uploaded images',
|
||||||
userActions_title: 'User Actions',
|
userActions_title: 'User Actions',
|
||||||
userAddedThisCardToList: '<0>{{user}}</0><1> added this card to {{list}}</1>',
|
userAddedThisCardToList: '<0>{{user}}</0><1> added this card to {{list}}</1>',
|
||||||
|
userAddedUserToThisCard: '<0>{{actorUser}}</0><1> added {{addedUser}} to this card</1>',
|
||||||
|
userAddedYouToCard: '{{user}} added you to <2>{{card}}</2>',
|
||||||
|
userJoinedThisCard: `<0>{{user}}</0><1> joined this card</1>`,
|
||||||
userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}</2>',
|
userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}</2>',
|
||||||
userMovedCardFromListToList: '{{user}} moved <2>{{card}}</2> from {{fromList}} to {{toList}}',
|
userMovedCardFromListToList: '{{user}} moved <2>{{card}}</2> from {{fromList}} to {{toList}}',
|
||||||
userMovedThisCardFromListToList:
|
userMovedThisCardFromListToList:
|
||||||
|
|
|
@ -282,6 +282,9 @@ export default {
|
||||||
uploadedImages: 'Uploaded images',
|
uploadedImages: 'Uploaded images',
|
||||||
userActions_title: 'User Actions',
|
userActions_title: 'User Actions',
|
||||||
userAddedThisCardToList: '<0>{{user}}</0><1> added this card to {{list}}</1>',
|
userAddedThisCardToList: '<0>{{user}}</0><1> added this card to {{list}}</1>',
|
||||||
|
userAddedUserToThisCard: '<0>{{actorUser}}</0><1> added {{addedUser}} to this card</1>',
|
||||||
|
userAddedYouToCard: '{{user}} added you to <2>{{card}}</2>',
|
||||||
|
userJoinedThisCard: `<0>{{user}}</0><1> joined this card</1>`,
|
||||||
userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}</2>',
|
userLeftNewCommentToCard: '{{user}} left a new comment «{{comment}}» to <2>{{card}}</2>',
|
||||||
userMovedCardFromListToList: '{{user}} moved <2>{{card}}</2> from {{fromList}} to {{toList}}',
|
userMovedCardFromListToList: '{{user}} moved <2>{{card}}</2> from {{fromList}} to {{toList}}',
|
||||||
userMovedThisCardFromListToList:
|
userMovedThisCardFromListToList:
|
||||||
|
|
|
@ -67,7 +67,13 @@ module.exports = {
|
||||||
throw Errors.NOT_ENOUGH_RIGHTS;
|
throw Errors.NOT_ENOUGH_RIGHTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isBoardMember = await sails.helpers.users.isBoardMember(inputs.userId, board.id);
|
const user = await User.qm.getOneById(inputs.userId);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw Errors.USER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isBoardMember = await sails.helpers.users.isBoardMember(user.id, board.id);
|
||||||
|
|
||||||
if (!isBoardMember) {
|
if (!isBoardMember) {
|
||||||
throw Errors.USER_NOT_FOUND;
|
throw Errors.USER_NOT_FOUND;
|
||||||
|
@ -80,7 +86,7 @@ module.exports = {
|
||||||
list,
|
list,
|
||||||
values: {
|
values: {
|
||||||
card,
|
card,
|
||||||
userId: inputs.userId,
|
user,
|
||||||
},
|
},
|
||||||
actorUser: currentUser,
|
actorUser: currentUser,
|
||||||
request: this.req,
|
request: this.req,
|
||||||
|
|
|
@ -143,6 +143,26 @@ module.exports = {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (action.type !== Action.Types.CREATE_CARD) {
|
if (action.type !== Action.Types.CREATE_CARD) {
|
||||||
|
if (action.type === Action.Types.ADD_MEMBER_TO_CARD) {
|
||||||
|
if (values.user !== action.data.user.id) {
|
||||||
|
await sails.helpers.notifications.createOne.with({
|
||||||
|
values: {
|
||||||
|
action,
|
||||||
|
type: action.type,
|
||||||
|
data: {
|
||||||
|
...action.data,
|
||||||
|
card: _.pick(values.card, ['name']),
|
||||||
|
},
|
||||||
|
userId: action.data.user.id,
|
||||||
|
creatorUser: values.user,
|
||||||
|
card: values.card,
|
||||||
|
},
|
||||||
|
project: inputs.project,
|
||||||
|
board: inputs.board,
|
||||||
|
list: inputs.list,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const cardSubscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds(
|
const cardSubscriptionUserIds = await sails.helpers.cards.getSubscriptionUserIds(
|
||||||
action.cardId,
|
action.cardId,
|
||||||
action.userId,
|
action.userId,
|
||||||
|
@ -175,7 +195,6 @@ module.exports = {
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
const notificationServices = await NotificationService.qm.getByBoardId(inputs.board.id);
|
const notificationServices = await NotificationService.qm.getByBoardId(inputs.board.id);
|
||||||
|
|
||||||
|
@ -193,6 +212,8 @@ module.exports = {
|
||||||
sails.helpers.utils.makeTranslator(),
|
sails.helpers.utils.makeTranslator(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return action;
|
return action;
|
||||||
},
|
},
|
||||||
|
|
|
@ -37,15 +37,12 @@ module.exports = {
|
||||||
async fn(inputs) {
|
async fn(inputs) {
|
||||||
const { values } = inputs;
|
const { values } = inputs;
|
||||||
|
|
||||||
if (values.user) {
|
|
||||||
values.userId = values.user.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cardMembership;
|
let cardMembership;
|
||||||
try {
|
try {
|
||||||
cardMembership = await CardMembership.qm.createOne({
|
cardMembership = await CardMembership.qm.createOne({
|
||||||
...values,
|
...values,
|
||||||
cardId: values.card.id,
|
cardId: values.card.id,
|
||||||
|
userId: values.user.id,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.code === 'E_UNIQUE') {
|
if (error.code === 'E_UNIQUE') {
|
||||||
|
@ -69,6 +66,7 @@ module.exports = {
|
||||||
buildData: () => ({
|
buildData: () => ({
|
||||||
item: cardMembership,
|
item: cardMembership,
|
||||||
included: {
|
included: {
|
||||||
|
users: [values.user],
|
||||||
projects: [inputs.project],
|
projects: [inputs.project],
|
||||||
boards: [inputs.board],
|
boards: [inputs.board],
|
||||||
lists: [inputs.list],
|
lists: [inputs.list],
|
||||||
|
@ -107,6 +105,20 @@ module.exports = {
|
||||||
// TODO: send webhooks
|
// TODO: send webhooks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await sails.helpers.actions.createOne.with({
|
||||||
|
values: {
|
||||||
|
type: Action.Types.ADD_MEMBER_TO_CARD,
|
||||||
|
data: {
|
||||||
|
user: _.pick(values.user, ['id', 'name']),
|
||||||
|
},
|
||||||
|
user: inputs.actorUser,
|
||||||
|
card: values.card,
|
||||||
|
},
|
||||||
|
project: inputs.project,
|
||||||
|
board: inputs.board,
|
||||||
|
list: inputs.list,
|
||||||
|
});
|
||||||
|
|
||||||
return cardMembership;
|
return cardMembership;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,6 +12,8 @@ const buildTitle = (notification, t) => {
|
||||||
return t('Card Moved');
|
return t('Card Moved');
|
||||||
case Notification.Types.COMMENT_CARD:
|
case Notification.Types.COMMENT_CARD:
|
||||||
return t('New Comment');
|
return t('New Comment');
|
||||||
|
case Notification.Types.ADD_MEMBER_TO_CARD:
|
||||||
|
return t('You Were Added to Card');
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -77,6 +79,22 @@ const buildBodyByFormat = (board, card, notification, actorUser, t) => {
|
||||||
)}:\n\n<i>${escapeHtml(commentText)}</i>`,
|
)}:\n\n<i>${escapeHtml(commentText)}</i>`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
case Notification.Types.ADD_MEMBER_TO_CARD:
|
||||||
|
return {
|
||||||
|
text: t('%s added you to %s on %s', actorUser.name, card.name, board.name),
|
||||||
|
markdown: t(
|
||||||
|
'%s added you to %s on %s',
|
||||||
|
escapeMarkdown(actorUser.name),
|
||||||
|
markdownCardLink,
|
||||||
|
escapeMarkdown(board.name),
|
||||||
|
),
|
||||||
|
html: t(
|
||||||
|
'%s added you to %s on %s',
|
||||||
|
escapeHtml(actorUser.name),
|
||||||
|
htmlCardLink,
|
||||||
|
escapeHtml(board.name),
|
||||||
|
),
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -120,6 +138,15 @@ const buildAndSendEmail = async (board, card, notification, actorUser, notifiabl
|
||||||
boardLink,
|
boardLink,
|
||||||
)}</p><p>${escapeHtml(notification.data.text)}</p>`;
|
)}</p><p>${escapeHtml(notification.data.text)}</p>`;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Notification.Types.ADD_MEMBER_TO_CARD:
|
||||||
|
html = `<p>${t(
|
||||||
|
'%s added you to %s on %s',
|
||||||
|
escapeHtml(actorUser.name),
|
||||||
|
cardLink,
|
||||||
|
boardLink,
|
||||||
|
)}</p>`;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
const Types = {
|
const Types = {
|
||||||
CREATE_CARD: 'createCard',
|
CREATE_CARD: 'createCard',
|
||||||
MOVE_CARD: 'moveCard',
|
MOVE_CARD: 'moveCard',
|
||||||
|
ADD_MEMBER_TO_CARD: 'addMemberToCard',
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
const Types = {
|
const Types = {
|
||||||
MOVE_CARD: 'moveCard',
|
MOVE_CARD: 'moveCard',
|
||||||
COMMENT_CARD: 'commentCard',
|
COMMENT_CARD: 'commentCard',
|
||||||
|
ADD_MEMBER_TO_CARD: 'addMemberToCard',
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
"This is a test text message!": "This is a test text message!",
|
"This is a test text message!": "This is a test text message!",
|
||||||
"This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!",
|
"This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!",
|
||||||
"This is a <i>test</i> <b>html</b> <code>message</code>": "This is a <i>test</i> <b>html</b> <code>message</code>",
|
"This is a <i>test</i> <b>html</b> <code>message</code>": "This is a <i>test</i> <b>html</b> <code>message</code>",
|
||||||
|
"You Were Added to Card": "Your Were Added to Card",
|
||||||
|
"%s added you to %s on %s": "%s added you to %s on %s",
|
||||||
"%s created %s in %s on %s": "%s created %s in %s on %s",
|
"%s created %s in %s on %s": "%s created %s in %s on %s",
|
||||||
"%s left a new comment to %s on %s": "%s left a new comment to %s on %s",
|
"%s left a new comment to %s on %s": "%s left a new comment to %s on %s",
|
||||||
"%s moved %s from %s to %s on %s": "%s moved %s from %s to %s on %s"
|
"%s moved %s from %s to %s on %s": "%s moved %s from %s to %s on %s"
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
"This is a test text message!": "This is a test text message!",
|
"This is a test text message!": "This is a test text message!",
|
||||||
"This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!",
|
"This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!",
|
||||||
"This is a <i>test</i> <b>html</b> <code>message</code>": "This is a <i>test</i> <b>html</b> <code>message</code>",
|
"This is a <i>test</i> <b>html</b> <code>message</code>": "This is a <i>test</i> <b>html</b> <code>message</code>",
|
||||||
|
"You Were Added to Card": "Your Were Added to Card",
|
||||||
|
"%s added you to %s on %s": "%s added you to %s on %s",
|
||||||
"%s created %s in %s on %s": "%s created %s in %s on %s",
|
"%s created %s in %s on %s": "%s created %s in %s on %s",
|
||||||
"%s left a new comment to %s on %s": "%s left a new comment to %s on %s",
|
"%s left a new comment to %s on %s": "%s left a new comment to %s on %s",
|
||||||
"%s moved %s from %s to %s on %s": "%s moved %s from %s to %s on %s"
|
"%s moved %s from %s to %s on %s": "%s moved %s from %s to %s on %s"
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
"This is a test text message!": "Это тестовое сообщение!",
|
"This is a test text message!": "Это тестовое сообщение!",
|
||||||
"This is a *test* **markdown** `message`!": "Это *тестовое* **markdown** `сообщение`!",
|
"This is a *test* **markdown** `message`!": "Это *тестовое* **markdown** `сообщение`!",
|
||||||
"This is a <i>test</i> <b>html</b> <code>message</code>": "Это <i>тестовое</i> <b>html</b> <code>сообщение</code>",
|
"This is a <i>test</i> <b>html</b> <code>message</code>": "Это <i>тестовое</i> <b>html</b> <code>сообщение</code>",
|
||||||
|
"You Were Added to Card": "Вы были добавлены к карточке",
|
||||||
|
"%s added you to %s on %s": "%s добавил(а) вас к %s на %s",
|
||||||
"%s created %s in %s on %s": "%s создал(а) %s в %s на %s",
|
"%s created %s in %s on %s": "%s создал(а) %s в %s на %s",
|
||||||
"%s left a new comment to %s on %s": "%s оставил(а) новый комментарий к %s на %s",
|
"%s left a new comment to %s on %s": "%s оставил(а) новый комментарий к %s на %s",
|
||||||
"%s moved %s from %s to %s on %s": "%s переместил(а) %s из %s в %s на %s"
|
"%s moved %s from %s to %s on %s": "%s переместил(а) %s из %s в %s на %s"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue