Fix New Board Permissions: NormalAssignedOnly, CommentAssignedOnly, ReadOnly, ReadAssignedOnly. Part 1.

Thanks to nazim-oss and xet7 !

Related #6060
This commit is contained in:
Lauri Ojansivu 2026-01-14 23:43:11 +02:00
parent 2f59e42024
commit eabb6a239d
25 changed files with 562 additions and 291 deletions

View file

@ -20,6 +20,17 @@ allowIsBoardMemberNoComments = function(userId, board) {
return board && board.hasMember(userId) && !board.hasNoComments(userId);
};
// Check if user has write access to board (can create/edit cards and lists)
allowIsBoardMemberWithWriteAccess = function(userId, board) {
return board && board.members && board.members.some(e => e.userId === userId && e.isActive && !e.isNoComments && !e.isCommentOnly && !e.isWorker && !e.isReadOnly && !e.isReadAssignedOnly);
};
// Check if user has write access via a card's board
allowIsBoardMemberWithWriteAccessByCard = function(userId, card) {
const board = card && card.board && card.board();
return allowIsBoardMemberWithWriteAccess(userId, board);
};
allowIsBoardMemberByCard = function(userId, card) {
const board = card.board();
return board && board.hasMember(userId);

View file

@ -21,6 +21,28 @@ Meteor.publish('activities', function(kind, id, limit, showActivities) {
return this.ready();
}
// Check user permissions - only BoardAdmin can view activities
if (this.userId) {
const user = ReactiveCache.getUser(this.userId);
const board = ReactiveCache.getBoard(id);
if (user && board) {
// Find user membership in board
const membership = board.members.find(m => m.userId === this.userId);
// Only BoardAdmin can view activities
if (!membership || !membership.isAdmin) {
return this.ready();
}
} else {
// If board or user not found, deny
return this.ready();
}
} else {
// If not logged in, deny
return this.ready();
}
// Get linkedBoard
let linkedElmtId = [id];
if (kind == 'board') {

View file

@ -296,14 +296,23 @@ Meteor.publishRelations('board', function(boardId, isArchived) {
const linkedBoardCards = this.join(Cards);
linkedBoardCards.selector = _ids => ({ boardId: _ids });
// Build card selector based on user's permissions
const cardSelector = {
boardId: { $in: [boardId, board.subtasksDefaultBoardId] },
archived: isArchived,
};
// Check if current user has assigned-only permissions
if (thisUserId && board.members) {
const member = _.findWhere(board.members, { userId: thisUserId, isActive: true });
if (member && (member.isNormalAssignedOnly || member.isCommentAssignedOnly || member.isReadAssignedOnly)) {
// User with assigned-only permissions should only see cards assigned to them
cardSelector.assignees = { $in: [thisUserId] };
}
}
this.cursor(
ReactiveCache.getCards({
boardId: { $in: [boardId, board.subtasksDefaultBoardId] },
archived: isArchived,
},
{},
true,
),
ReactiveCache.getCards(cardSelector, {}, true),
function(cardId, card) {
if (card.type === 'cardType-linkedCard') {
const impCardId = card.linkedId;

View file

@ -75,6 +75,24 @@ import Team from "../../models/team";
Meteor.publish('card', cardId => {
check(cardId, String);
const userId = Meteor.userId();
const card = ReactiveCache.getCard({ _id: cardId });
// If user has assigned-only permissions, check if they're assigned to this card
if (userId && card && card.boardId) {
const board = ReactiveCache.getBoard({ _id: card.boardId });
if (board && board.members) {
const member = _.findWhere(board.members, { userId: userId, isActive: true });
if (member && (member.isNormalAssignedOnly || member.isCommentAssignedOnly || member.isReadAssignedOnly)) {
// User with assigned-only permissions can only view cards assigned to them
if (!card.assignees || !card.assignees.includes(userId)) {
return []; // Don't publish if user is not assigned
}
}
}
}
const ret = ReactiveCache.getCards(
{ _id: cardId },
{},
@ -88,6 +106,24 @@ Meteor.publish('card', cardId => {
*/
Meteor.publishRelations('popupCardData', function(cardId) {
check(cardId, String);
const userId = this.userId;
const card = ReactiveCache.getCard({ _id: cardId });
// If user has assigned-only permissions, check if they're assigned to this card
if (userId && card && card.boardId) {
const board = ReactiveCache.getBoard({ _id: card.boardId });
if (board && board.members) {
const member = _.findWhere(board.members, { userId: userId, isActive: true });
if (member && (member.isNormalAssignedOnly || member.isCommentAssignedOnly || member.isReadAssignedOnly)) {
// User with assigned-only permissions can only view cards assigned to them
if (!card.assignees || !card.assignees.includes(userId)) {
return this.ready(); // Don't publish if user is not assigned
}
}
}
}
this.cursor(
ReactiveCache.getCards(
{ _id: cardId },