Files
wekan/server/lib/syncNotificationAccess.js
Lauri Ojansivu 2df3e9a8b7 Deliver board-level activities durably: a rule's new swimlane and cross-board moves.
Durable delivery identified every activity by a card and a list, so a
rule's createSwimlane activity, which names neither, and a cross-board
move's moveCardBoard activity, which names no list, were written once
but delivered the ordinary way: their notifications and webhooks were
not replayed after a crash. Durable delivery now takes activities
without a list, and without a card. Recipients and webhook senders are
checked against the board, plus the card when one is named. A card or
list the activity does not name is refused. An assigned-only member
never receives a board-level event, since its scope cannot be checked
against their assignments. The rule stage has nothing to run for these
types, because no trigger exists for them, and it refuses a list-less
activity whose type has one.

Thanks to xet7 !
2026-10-03 00:08:13 +03:00

20 lines
1.3 KiB
JavaScript

'use strict';
const { isAssignedOnlyMember } = require('../../models/lib/boardCardScope');
const { boardNotificationRecipients } = require('../../models/lib/boardNotificationRecipients');
// A card or list the activity names must be there and agree with it; a
// board-level activity names neither (2026-10-03). An assigned-only member
// receives only what concerns a card assigned to them - never a board-level
// event, whose scope cannot be checked against their assignments.
function canReceiveStoredNotification({ user, board, card, list, activity }) {
if (typeof user?._id !== 'string' || !user._id || user.loginDisabled || !activity || !board ||
board._id !== activity.boardId) return false;
if (activity.cardId ? (!card || card._id !== activity.cardId || card.boardId !== board._id) : card) return false;
if (activity.listId ? (!list || list._id !== activity.listId || list.boardId !== board._id ||
(card && card.listId !== activity.listId)) : list) return false;
if (isAssignedOnlyMember(board, user._id) &&
(!card || !Array.isArray(card.assignees) || !card.assignees.includes(user._id))) return false;
return boardNotificationRecipients([user._id], board.members, board.watchers,
[...(list?.watchers || []), ...(card?.watchers || [])]).includes(user._id);
}
module.exports = { canReceiveStoredNotification };