summaryrefslogtreecommitdiffstats
path: root/models/cards.js
diff options
context:
space:
mode:
Diffstat (limited to 'models/cards.js')
-rw-r--r--models/cards.js132
1 files changed, 100 insertions, 32 deletions
diff --git a/models/cards.js b/models/cards.js
index 17abf430..8b917ee3 100644
--- a/models/cards.js
+++ b/models/cards.js
@@ -18,9 +18,12 @@ Cards.attachSchema(new SimpleSchema({
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.
+ swimlaneId: {
+ 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,
},
@@ -71,6 +74,10 @@ Cards.attachSchema(new SimpleSchema({
type: [String],
optional: true,
},
+ receivedAt: {
+ type: Date,
+ optional: true,
+ },
startAt: {
type: Date,
optional: true,
@@ -79,8 +86,22 @@ Cards.attachSchema(new SimpleSchema({
type: Date,
optional: true,
},
- // XXX Should probably be called `authorId`. Is it even needed since we have
- // the `members` field?
+ endAt: {
+ type: Date,
+ optional: true,
+ },
+ spentTime: {
+ type: Number,
+ decimal: true,
+ optional: true,
+ },
+ isOvertime: {
+ type: Boolean,
+ defaultValue: false,
+ optional: true,
+ },
+ // XXX Should probably be called `authorId`. Is it even needed since we have
+ // the `members` field?
userId: {
type: String,
autoValue() { // eslint-disable-line consistent-return
@@ -151,13 +172,13 @@ Cards.helpers({
cover() {
const cover = Attachments.findOne(this.coverId);
- // if we return a cover before it is fully stored, we will get errors when we try to display it
- // todo XXX we could return a default "upload pending" image in the meantime?
+ // if we return a cover before it is fully stored, we will get errors when we try to display it
+ // todo XXX we could return a default "upload pending" image in the meantime?
return cover && cover.url() && cover;
},
checklists() {
- return Checklists.find({cardId: this._id}, {sort: {createdAt: 1}});
+ return Checklists.find({cardId: this._id}, {sort: { sort: 1 } });
},
checklistItemCount() {
@@ -219,6 +240,14 @@ Cards.helpers({
cardId: this._id,
});
},
+
+ canBeRestored() {
+ const list = Lists.findOne({_id: this.listId});
+ if(!list.getWipLimit('soft') && list.getWipLimit('enabled') && list.getWipLimit('value') === list.cards().count()){
+ return false;
+ }
+ return true;
+ },
});
Cards.mutations({
@@ -238,11 +267,15 @@ Cards.mutations({
return {$set: {description}};
},
- move(listId, sortIndex) {
- const mutatedFields = {listId};
- if (sortIndex) {
- mutatedFields.sort = sortIndex;
- }
+ move(swimlaneId, listId, sortIndex) {
+ const list = Lists.findOne(listId);
+ const mutatedFields = {
+ swimlaneId,
+ listId,
+ boardId: list.boardId,
+ sort: sortIndex,
+ };
+
return {$set: mutatedFields};
},
@@ -312,6 +345,14 @@ Cards.mutations({
return {$unset: {coverId: ''}};
},
+ setReceived(receivedAt) {
+ return {$set: {receivedAt}};
+ },
+
+ unsetReceived() {
+ return {$unset: {receivedAt: ''}};
+ },
+
setStart(startAt) {
return {$set: {startAt}};
},
@@ -327,6 +368,26 @@ Cards.mutations({
unsetDue() {
return {$unset: {dueAt: ''}};
},
+
+ setEnd(endAt) {
+ return {$set: {endAt}};
+ },
+
+ unsetEnd() {
+ return {$unset: {endAt: ''}};
+ },
+
+ setOvertime(isOvertime) {
+ return {$set: {isOvertime}};
+ },
+
+ setSpentTime(spentTime) {
+ return {$set: {spentTime}};
+ },
+
+ unsetSpentTime() {
+ return {$unset: {spentTime: '', isOvertime: false}};
+ },
});
@@ -371,7 +432,7 @@ function cardMembers(userId, doc, fieldNames, modifier) {
if (!_.contains(fieldNames, 'members'))
return;
let memberId;
- // Say hello to the new member
+ // Say hello to the new member
if (modifier.$addToSet && modifier.$addToSet.members) {
memberId = modifier.$addToSet.members;
if (!_.contains(doc.members, memberId)) {
@@ -385,10 +446,10 @@ function cardMembers(userId, doc, fieldNames, modifier) {
}
}
- // Say goodbye to the former member
+ // Say goodbye to the former member
if (modifier.$pull && modifier.$pull.members) {
memberId = modifier.$pull.members;
- // Check that the former member is member of the card
+ // Check that the former member is member of the card
if (_.contains(doc.members, memberId)) {
Activities.insert({
userId,
@@ -428,8 +489,8 @@ function cardRemover(userId, doc) {
if (Meteor.isServer) {
- // Cards are often fetched within a board, so we create an index to make these
- // queries more efficient.
+ // Cards are often fetched within a board, so we create an index to make these
+ // queries more efficient.
Meteor.startup(() => {
Cards._collection._ensureIndex({boardId: 1, createdAt: -1});
});
@@ -438,31 +499,31 @@ if (Meteor.isServer) {
cardCreation(userId, doc);
});
- // New activity for card (un)archivage
+ // New activity for card (un)archivage
Cards.after.update((userId, doc, fieldNames) => {
cardState(userId, doc, fieldNames);
});
- //New activity for card moves
+ //New activity for card moves
Cards.after.update(function (userId, doc, fieldNames) {
const oldListId = this.previous.listId;
cardMove(userId, doc, fieldNames, oldListId);
});
- // Add a new activity if we add or remove a member to the card
+ // Add a new activity if we add or remove a member to the card
Cards.before.update((userId, doc, fieldNames, modifier) => {
cardMembers(userId, doc, fieldNames, modifier);
});
- // Remove all activities associated with a card if we remove the card
- // Remove also card_comments / checklists / attachments
+ // Remove all activities associated with a card if we remove the card
+ // Remove also card_comments / checklists / attachments
Cards.after.remove((userId, doc) => {
cardRemover(userId, doc);
});
}
//LISTS REST API
if (Meteor.isServer) {
- JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards', function (req, res, next) {
+ JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards', function (req, res) {
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
Authentication.checkBoardAccess(req.userId, paramBoardId);
@@ -478,7 +539,7 @@ if (Meteor.isServer) {
});
});
- JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res, next) {
+ JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res) {
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
const paramCardId = req.params.cardId;
@@ -489,11 +550,12 @@ if (Meteor.isServer) {
});
});
- JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', function (req, res, next) {
+ JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', function (req, res) {
Authentication.checkUserId(req.userId);
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;
const check = Users.findOne({_id: req.body.authorId});
+ const members = req.body.members || [req.body.authorId];
if (typeof check !== 'undefined') {
const id = Cards.direct.insert({
title: req.body.title,
@@ -501,8 +563,9 @@ if (Meteor.isServer) {
listId: paramListId,
description: req.body.description,
userId: req.body.authorId,
+ swimlaneId: req.body.swimlaneId,
sort: 0,
- members: [req.body.authorId],
+ members,
});
JsonRoutes.sendResult(res, {
code: 200,
@@ -521,7 +584,7 @@ if (Meteor.isServer) {
}
});
- JsonRoutes.add('PUT', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res, next) {
+ JsonRoutes.add('PUT', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res) {
Authentication.checkUserId(req.userId);
const paramBoardId = req.params.boardId;
const paramCardId = req.params.cardId;
@@ -530,12 +593,12 @@ if (Meteor.isServer) {
if (req.body.hasOwnProperty('title')) {
const newTitle = req.body.title;
Cards.direct.update({_id: paramCardId, listId: paramListId, boardId: paramBoardId, archived: false},
- {$set: {title: newTitle}});
+ {$set: {title: newTitle}});
}
if (req.body.hasOwnProperty('listId')) {
const newParamListId = req.body.listId;
Cards.direct.update({_id: paramCardId, listId: paramListId, boardId: paramBoardId, archived: false},
- {$set: {listId: newParamListId}});
+ {$set: {listId: newParamListId}});
const card = Cards.findOne({_id: paramCardId} );
cardMove(req.body.authorId, card, {fieldName: 'listId'}, paramListId);
@@ -544,7 +607,12 @@ if (Meteor.isServer) {
if (req.body.hasOwnProperty('description')) {
const newDescription = req.body.description;
Cards.direct.update({_id: paramCardId, listId: paramListId, boardId: paramBoardId, archived: false},
- {$set: {description: newDescription}});
+ {$set: {description: newDescription}});
+ }
+ if (req.body.hasOwnProperty('labelIds')) {
+ const newlabelIds = req.body.labelIds;
+ Cards.direct.update({_id: paramCardId, listId: paramListId, boardId: paramBoardId, archived: false},
+ {$set: {labelIds: newlabelIds}});
}
JsonRoutes.sendResult(res, {
code: 200,
@@ -555,7 +623,7 @@ if (Meteor.isServer) {
});
- JsonRoutes.add('DELETE', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res, next) {
+ JsonRoutes.add('DELETE', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res) {
Authentication.checkUserId(req.userId);
const paramBoardId = req.params.boardId;
const paramListId = req.params.listId;