mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 15:30:13 +01:00
_,,ad8888888888bba,_
,ad88888I888888888888888ba,
,88888888I88888888888888888888a,
,d888888888I8888888888888888888888b,
d88888PP"""" ""YY88888888888888888888b,
,d88"'__,,--------,,,,.;ZZZY8888888888888,
,8IIl'" ;;l"ZZZIII8888888888,
,I88l;' ;lZZZZZ888III8888888,
,II88Zl;. ;llZZZZZ888888I888888,
,II888Zl;. .;;;;;lllZZZ888888I8888b
,II8888Z;; `;;;;;''llZZ8888888I8888,
II88888Z;' .;lZZZ8888888I888b
II88888Z; _,aaa, .,aaaaa,__.l;llZZZ88888888I888
II88888IZZZZZZZZZ, .ZZZZZZZZZZZZZZ;llZZ88888888I888,
II88888IZZ<'(@@>Z| |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
,II88888; `""" ;| |ZZ; `""" ;;llZ8888888888I888
II888888l `;; .;llZZ8888888888I888,
,II888888Z; ;;; .;;llZZZ8888888888I888I
III888888Zl; .., `;; ,;;lllZZZ88888888888I888
II88888888Z;;...;(_ _) ,;;;llZZZZ88888888888I888,
II88888888Zl;;;;;' `--'Z;. .,;;;;llZZZZ88888888888I888b
]I888888888Z;;;;' ";llllll;..;;;lllZZZZ88888888888I8888,
II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
`II8888888888888Zl;. ,;;lllZZZZZZZZWMZ88888888888I88888
II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
`II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
`II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
`II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
,II8888888888888888b .;;lllllll;;;.;..88888888I88888888b,
II888888888888888PZI;. .`;;;.;;;..; ...88888888I8888888888,
II888888888888PZ;;';;. ;. .;. .;. .. Y8888888I88888888888b,
,II888888888PZ;;' `8888888I8888888888888b,
II888888888' 888888I8888888888888888
,II888888888 ,888888I8888888888888888
,d88888888888 d888888I8888888888ZZZZZZ
,ad888888888888I 8888888I8888ZZZZZZZZZZZZ
888888888888888' 888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P' Y888ZZZZZZZZZZZZZZZZZZZZ
888888888, " ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888, ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a, _ ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d' ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand 8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
287 lines
6.9 KiB
JavaScript
287 lines
6.9 KiB
JavaScript
Cards = new Mongo.Collection('cards');
|
|
CardComments = new Mongo.Collection('card_comments');
|
|
|
|
// XXX To improve pub/sub performances a card document should include a
|
|
// de-normalized number of comments so we don't have to publish the whole list
|
|
// of comments just to display the number of them in the board view.
|
|
Cards.attachSchema(new SimpleSchema({
|
|
title: {
|
|
type: String
|
|
},
|
|
archived: {
|
|
type: Boolean
|
|
},
|
|
listId: {
|
|
type: String
|
|
},
|
|
// The system could work without this `boardId` information (we could deduce
|
|
// the board identifier from the card), but it would make the system more
|
|
// difficult to manage and less efficient.
|
|
boardId: {
|
|
type: String
|
|
},
|
|
coverId: {
|
|
type: String,
|
|
optional: true
|
|
},
|
|
createdAt: {
|
|
type: Date,
|
|
denyUpdate: true
|
|
},
|
|
dateLastActivity: {
|
|
type: Date
|
|
},
|
|
description: {
|
|
type: String,
|
|
optional: true
|
|
},
|
|
labelIds: {
|
|
type: [String],
|
|
optional: true
|
|
},
|
|
members: {
|
|
type: [String],
|
|
optional: true
|
|
},
|
|
// XXX Should probably be called `authorId`. Is it even needed since we have
|
|
// the `members` field?
|
|
userId: {
|
|
type: String
|
|
},
|
|
sort: {
|
|
type: Number,
|
|
decimal: true
|
|
}
|
|
}));
|
|
|
|
CardComments.attachSchema(new SimpleSchema({
|
|
boardId: {
|
|
type: String
|
|
},
|
|
cardId: {
|
|
type: String
|
|
},
|
|
// XXX Rename in `content`? `text` is a bit vague...
|
|
text: {
|
|
type: String
|
|
},
|
|
// XXX We probably don't need this information here, since we already have it
|
|
// in the associated comment creation activity
|
|
createdAt: {
|
|
type: Date,
|
|
denyUpdate: false
|
|
},
|
|
// XXX Should probably be called `authorId`
|
|
userId: {
|
|
type: String
|
|
}
|
|
}));
|
|
|
|
if (Meteor.isServer) {
|
|
Cards.allow({
|
|
insert: function(userId, doc) {
|
|
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
|
},
|
|
update: function(userId, doc) {
|
|
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
|
},
|
|
remove: function(userId, doc) {
|
|
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
|
},
|
|
fetch: ['boardId']
|
|
});
|
|
|
|
CardComments.allow({
|
|
insert: function(userId, doc) {
|
|
return allowIsBoardMember(userId, Boards.findOne(doc.boardId));
|
|
},
|
|
update: function(userId, doc) {
|
|
return userId === doc.userId;
|
|
},
|
|
remove: function(userId, doc) {
|
|
return userId === doc.userId;
|
|
},
|
|
fetch: ['userId', 'boardId']
|
|
});
|
|
}
|
|
|
|
Cards.helpers({
|
|
list: function() {
|
|
return Lists.findOne(this.listId);
|
|
},
|
|
board: function() {
|
|
return Boards.findOne(this.boardId);
|
|
},
|
|
labels: function() {
|
|
var self = this;
|
|
var boardLabels = self.board().labels;
|
|
var cardLabels = _.filter(boardLabels, function(label) {
|
|
return _.contains(self.labelIds, label._id);
|
|
});
|
|
return cardLabels;
|
|
},
|
|
user: function() {
|
|
return Users.findOne(this.userId);
|
|
},
|
|
activities: function() {
|
|
return Activities.find({ type: 'card', cardId: this._id },
|
|
{ sort: { createdAt: -1 }});
|
|
},
|
|
comments: function() {
|
|
return CardComments.find({ cardId: this._id }, { sort: { createdAt: -1 }});
|
|
},
|
|
attachments: function() {
|
|
return Attachments.find({ cardId: this._id }, { sort: { uploadedAt: -1 }});
|
|
},
|
|
cover: function() {
|
|
return Attachments.findOne(this.coverId);
|
|
},
|
|
absoluteUrl: function() {
|
|
var board = this.board();
|
|
return Router.path('Card', {
|
|
boardId: board._id,
|
|
slug: board.slug,
|
|
cardId: this._id
|
|
});
|
|
},
|
|
rootUrl: function() {
|
|
return Meteor.absoluteUrl(this.absoluteUrl().replace('/', ''));
|
|
}
|
|
});
|
|
|
|
CardComments.helpers({
|
|
user: function() {
|
|
return Users.findOne(this.userId);
|
|
}
|
|
});
|
|
|
|
CardComments.hookOptions.after.update = { fetchPrevious: false };
|
|
Cards.before.insert(function(userId, doc) {
|
|
doc.createdAt = new Date();
|
|
doc.dateLastActivity = new Date();
|
|
|
|
// defaults
|
|
doc.archived = false;
|
|
|
|
// userId native set.
|
|
if (! doc.userId)
|
|
doc.userId = userId;
|
|
});
|
|
|
|
CardComments.before.insert(function(userId, doc) {
|
|
doc.createdAt = new Date();
|
|
doc.userId = userId;
|
|
});
|
|
|
|
if (Meteor.isServer) {
|
|
Cards.after.insert(function(userId, doc) {
|
|
Activities.insert({
|
|
type: 'card',
|
|
activityType: 'createCard',
|
|
boardId: doc.boardId,
|
|
listId: doc.listId,
|
|
cardId: doc._id,
|
|
userId: userId
|
|
});
|
|
});
|
|
|
|
// New activity for card (un)archivage
|
|
Cards.after.update(function(userId, doc, fieldNames) {
|
|
if (_.contains(fieldNames, 'archived')) {
|
|
if (doc.archived) {
|
|
Activities.insert({
|
|
type: 'card',
|
|
activityType: 'archivedCard',
|
|
boardId: doc.boardId,
|
|
listId: doc.listId,
|
|
cardId: doc._id,
|
|
userId: userId
|
|
});
|
|
} else {
|
|
Activities.insert({
|
|
type: 'card',
|
|
activityType: 'restoredCard',
|
|
boardId: doc.boardId,
|
|
listId: doc.listId,
|
|
cardId: doc._id,
|
|
userId: userId
|
|
});
|
|
}
|
|
}
|
|
});
|
|
|
|
// New activity for card moves
|
|
Cards.after.update(function(userId, doc, fieldNames) {
|
|
var oldListId = this.previous.listId;
|
|
if (_.contains(fieldNames, 'listId') && doc.listId !== oldListId) {
|
|
Activities.insert({
|
|
type: 'card',
|
|
activityType: 'moveCard',
|
|
listId: doc.listId,
|
|
oldListId: oldListId,
|
|
boardId: doc.boardId,
|
|
cardId: doc._id,
|
|
userId: userId
|
|
});
|
|
}
|
|
});
|
|
|
|
// Add a new activity if we add or remove a member to the card
|
|
Cards.before.update(function(userId, doc, fieldNames, modifier) {
|
|
if (! _.contains(fieldNames, 'members'))
|
|
return;
|
|
var memberId;
|
|
// Say hello to the new member
|
|
if (modifier.$addToSet && modifier.$addToSet.members) {
|
|
memberId = modifier.$addToSet.members;
|
|
if (! _.contains(doc.members, memberId)) {
|
|
Activities.insert({
|
|
type: 'card',
|
|
activityType: 'joinMember',
|
|
boardId: doc.boardId,
|
|
cardId: doc._id,
|
|
userId: userId,
|
|
memberId: memberId
|
|
});
|
|
}
|
|
}
|
|
|
|
// Say goodbye to the former member
|
|
if (modifier.$pull && modifier.$pull.members) {
|
|
memberId = modifier.$pull.members;
|
|
Activities.insert({
|
|
type: 'card',
|
|
activityType: 'unjoinMember',
|
|
boardId: doc.boardId,
|
|
cardId: doc._id,
|
|
userId: userId,
|
|
memberId: memberId
|
|
});
|
|
}
|
|
});
|
|
|
|
// Remove all activities associated with a card if we remove the card
|
|
Cards.after.remove(function(userId, doc) {
|
|
Activities.remove({
|
|
cardId: doc._id
|
|
});
|
|
});
|
|
|
|
CardComments.after.insert(function(userId, doc) {
|
|
Activities.insert({
|
|
type: 'comment',
|
|
activityType: 'addComment',
|
|
boardId: doc.boardId,
|
|
cardId: doc.cardId,
|
|
commentId: doc._id,
|
|
userId: userId
|
|
});
|
|
});
|
|
|
|
CardComments.after.remove(function(userId, doc) {
|
|
var activity = Activities.findOne({ commentId: doc._id });
|
|
if (activity) {
|
|
Activities.remove(activity._id);
|
|
}
|
|
});
|
|
}
|