summaryrefslogtreecommitdiffstats
path: root/models/lists.js
diff options
context:
space:
mode:
Diffstat (limited to 'models/lists.js')
-rw-r--r--models/lists.js187
1 files changed, 184 insertions, 3 deletions
diff --git a/models/lists.js b/models/lists.js
index 6f6996cb..1a0910c2 100644
--- a/models/lists.js
+++ b/models/lists.js
@@ -1,10 +1,19 @@
Lists = new Mongo.Collection('lists');
+/**
+ * A list (column) in the Wekan board.
+ */
Lists.attachSchema(new SimpleSchema({
title: {
+ /**
+ * the title of the list
+ */
type: String,
},
archived: {
+ /**
+ * is the list archived
+ */
type: Boolean,
autoValue() { // eslint-disable-line consistent-return
if (this.isInsert && !this.isSet) {
@@ -13,9 +22,22 @@ Lists.attachSchema(new SimpleSchema({
},
},
boardId: {
+ /**
+ * the board associated to this list
+ */
type: String,
},
+ swimlaneId: {
+ /**
+ * the swimlane associated to this list. Used for templates
+ */
+ type: String,
+ defaultValue: '',
+ },
createdAt: {
+ /**
+ * creation date
+ */
type: Date,
autoValue() { // eslint-disable-line consistent-return
if (this.isInsert) {
@@ -26,12 +48,18 @@ Lists.attachSchema(new SimpleSchema({
},
},
sort: {
+ /**
+ * is the list sorted
+ */
type: Number,
decimal: true,
// XXX We should probably provide a default
optional: true,
},
updatedAt: {
+ /**
+ * last update of the list
+ */
type: Date,
optional: true,
autoValue() { // eslint-disable-line consistent-return
@@ -43,38 +71,102 @@ Lists.attachSchema(new SimpleSchema({
},
},
wipLimit: {
+ /**
+ * WIP object, see below
+ */
type: Object,
optional: true,
},
'wipLimit.value': {
+ /**
+ * value of the WIP
+ */
type: Number,
decimal: false,
defaultValue: 1,
},
'wipLimit.enabled': {
+ /**
+ * is the WIP enabled
+ */
type: Boolean,
defaultValue: false,
},
'wipLimit.soft': {
+ /**
+ * is the WIP a soft or hard requirement
+ */
type: Boolean,
defaultValue: false,
},
+ color: {
+ /**
+ * the color of the list
+ */
+ type: String,
+ optional: true,
+ // silver is the default, so it is left out
+ allowedValues: [
+ 'white', 'green', 'yellow', 'orange', 'red', 'purple',
+ 'blue', 'sky', 'lime', 'pink', 'black',
+ 'peachpuff', 'crimson', 'plum', 'darkgreen',
+ 'slateblue', 'magenta', 'gold', 'navy', 'gray',
+ 'saddlebrown', 'paleturquoise', 'mistyrose', 'indigo',
+ ],
+ },
+ type: {
+ /**
+ * The type of list
+ */
+ type: String,
+ defaultValue: 'list',
+ },
}));
Lists.allow({
insert(userId, doc) {
- return allowIsBoardMemberNonComment(userId, Boards.findOne(doc.boardId));
+ return allowIsBoardMemberCommentOnly(userId, Boards.findOne(doc.boardId));
},
update(userId, doc) {
- return allowIsBoardMemberNonComment(userId, Boards.findOne(doc.boardId));
+ return allowIsBoardMemberCommentOnly(userId, Boards.findOne(doc.boardId));
},
remove(userId, doc) {
- return allowIsBoardMemberNonComment(userId, Boards.findOne(doc.boardId));
+ return allowIsBoardMemberCommentOnly(userId, Boards.findOne(doc.boardId));
},
fetch: ['boardId'],
});
Lists.helpers({
+ copy(boardId, swimlaneId) {
+ const oldId = this._id;
+ const oldSwimlaneId = this.swimlaneId || null;
+ this.boardId = boardId;
+ this.swimlaneId = swimlaneId;
+
+ let _id = null;
+ existingListWithSameName = Lists.findOne({
+ boardId,
+ title: this.title,
+ archived: false,
+ });
+ if (existingListWithSameName) {
+ _id = existingListWithSameName._id;
+ } else {
+ delete this._id;
+ delete this.swimlaneId;
+ _id = Lists.insert(this);
+ }
+
+ // Copy all cards in list
+ Cards.find({
+ swimlaneId: oldSwimlaneId,
+ listId: oldId,
+ archived: false,
+ }).forEach((card) => {
+ card.copy(boardId, swimlaneId, _id);
+ });
+ },
+
cards(swimlaneId) {
const selector = {
listId: this._id,
@@ -86,6 +178,17 @@ Lists.helpers({
{ sort: ['sort'] });
},
+ cardsUnfiltered(swimlaneId) {
+ const selector = {
+ listId: this._id,
+ archived: false,
+ };
+ if (swimlaneId)
+ selector.swimlaneId = swimlaneId;
+ return Cards.find(selector,
+ { sort: ['sort'] });
+ },
+
allCards() {
return Cards.find({ listId: this._id });
},
@@ -104,6 +207,20 @@ Lists.helpers({
return list.wipLimit[option] ? list.wipLimit[option] : 0; // Necessary check to avoid exceptions for the case where the doc doesn't have the wipLimit field yet set
}
},
+
+ colorClass() {
+ if (this.color)
+ return this.color;
+ return '';
+ },
+
+ isTemplateList() {
+ return this.type === 'template-list';
+ },
+
+ remove() {
+ Lists.remove({ _id: this._id});
+ },
});
Lists.mutations({
@@ -112,10 +229,20 @@ Lists.mutations({
},
archive() {
+ if (this.isTemplateList()) {
+ this.cards().forEach((card) => {
+ return card.archive();
+ });
+ }
return { $set: { archived: true } };
},
restore() {
+ if (this.isTemplateList()) {
+ this.allCards().forEach((card) => {
+ return card.restore();
+ });
+ }
return { $set: { archived: false } };
},
@@ -130,6 +257,17 @@ Lists.mutations({
setWipLimit(limit) {
return { $set: { 'wipLimit.value': limit } };
},
+
+ setColor(newColor) {
+ if (newColor === 'silver') {
+ newColor = null;
+ }
+ return {
+ $set: {
+ color: newColor,
+ },
+ };
+ },
});
Meteor.methods({
@@ -176,6 +314,12 @@ if (Meteor.isServer) {
});
Lists.before.remove((userId, doc) => {
+ const cards = Cards.find({ listId: doc._id });
+ if (cards) {
+ cards.forEach((card) => {
+ Cards.remove(card._id);
+ });
+ }
Activities.insert({
userId,
type: 'list',
@@ -201,6 +345,14 @@ if (Meteor.isServer) {
//LISTS REST API
if (Meteor.isServer) {
+ /**
+ * @operation get_all_lists
+ * @summary Get the list of Lists attached to a board
+ *
+ * @param {string} boardId the board ID
+ * @return_type [{_id: string,
+ * title: string}]
+ */
JsonRoutes.add('GET', '/api/boards/:boardId/lists', function (req, res) {
try {
const paramBoardId = req.params.boardId;
@@ -224,6 +376,14 @@ if (Meteor.isServer) {
}
});
+ /**
+ * @operation get_list
+ * @summary Get a List attached to a board
+ *
+ * @param {string} boardId the board ID
+ * @param {string} listId the List ID
+ * @return_type Lists
+ */
JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId', function (req, res) {
try {
const paramBoardId = req.params.boardId;
@@ -242,13 +402,23 @@ if (Meteor.isServer) {
}
});
+ /**
+ * @operation new_list
+ * @summary Add a List to a board
+ *
+ * @param {string} boardId the board ID
+ * @param {string} title the title of the List
+ * @return_type {_id: string}
+ */
JsonRoutes.add('POST', '/api/boards/:boardId/lists', function (req, res) {
try {
Authentication.checkUserId( req.userId);
const paramBoardId = req.params.boardId;
+ const board = Boards.findOne(paramBoardId);
const id = Lists.insert({
title: req.body.title,
boardId: paramBoardId,
+ sort: board.lists().count(),
});
JsonRoutes.sendResult(res, {
code: 200,
@@ -265,6 +435,17 @@ if (Meteor.isServer) {
}
});
+ /**
+ * @operation delete_list
+ * @summary Delete a List
+ *
+ * @description This **deletes** a list from a board.
+ * The list is not put in the recycle bin.
+ *
+ * @param {string} boardId the board ID
+ * @param {string} listId the ID of the list to remove
+ * @return_type {_id: string}
+ */
JsonRoutes.add('DELETE', '/api/boards/:boardId/lists/:listId', function (req, res) {
try {
Authentication.checkUserId( req.userId);