summaryrefslogtreecommitdiffstats
path: root/models/boards.js
diff options
context:
space:
mode:
authorJustin Reynolds <justinr1234@gmail.com>2019-06-26 17:47:27 -0500
committerJustin Reynolds <justinr1234@gmail.com>2019-06-27 09:13:20 -0500
commitc60e80d25baa6a81b28f6090ca848553d20b2bb7 (patch)
tree64bcea66932f4b4635d5df6901f18d5ba6db0a37 /models/boards.js
parentfb728baf0c87bae5fa39d92089b667ff1ed69fa6 (diff)
downloadwekan-c60e80d25baa6a81b28f6090ca848553d20b2bb7.tar.gz
wekan-c60e80d25baa6a81b28f6090ca848553d20b2bb7.tar.bz2
wekan-c60e80d25baa6a81b28f6090ca848553d20b2bb7.zip
Add createdAt and modifiedAt to all collections
Diffstat (limited to 'models/boards.js')
-rw-r--r--models/boards.js953
1 files changed, 528 insertions, 425 deletions
diff --git a/models/boards.js b/models/boards.js
index 396d90fb..2792f80a 100644
--- a/models/boards.js
+++ b/models/boards.js
@@ -3,316 +3,347 @@ Boards = new Mongo.Collection('boards');
/**
* This is a Board.
*/
-Boards.attachSchema(new SimpleSchema({
- title: {
- /**
- * The title of the board
- */
- type: String,
- },
- slug: {
- /**
- * The title slugified.
- */
- type: String,
- autoValue() { // eslint-disable-line consistent-return
- // XXX We need to improve slug management. Only the id should be necessary
- // to identify a board in the code.
- // XXX If the board title is updated, the slug should also be updated.
- // In some cases (Chinese and Japanese for instance) the `getSlug` function
- // return an empty string. This is causes bugs in our application so we set
- // a default slug in this case.
- if (this.isInsert && !this.isSet) {
- let slug = 'board';
- const title = this.field('title');
- if (title.isSet) {
- slug = getSlug(title.value) || slug;
+Boards.attachSchema(
+ new SimpleSchema({
+ title: {
+ /**
+ * The title of the board
+ */
+ type: String,
+ },
+ slug: {
+ /**
+ * The title slugified.
+ */
+ type: String,
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ // XXX We need to improve slug management. Only the id should be necessary
+ // to identify a board in the code.
+ // XXX If the board title is updated, the slug should also be updated.
+ // In some cases (Chinese and Japanese for instance) the `getSlug` function
+ // return an empty string. This is causes bugs in our application so we set
+ // a default slug in this case.
+ if (this.isInsert && !this.isSet) {
+ let slug = 'board';
+ const title = this.field('title');
+ if (title.isSet) {
+ slug = getSlug(title.value) || slug;
+ }
+ return slug;
}
- return slug;
- }
+ },
},
- },
- archived: {
- /**
- * Is the board archived?
- */
- type: Boolean,
- autoValue() { // eslint-disable-line consistent-return
- if (this.isInsert && !this.isSet) {
- return false;
- }
+ archived: {
+ /**
+ * Is the board archived?
+ */
+ type: Boolean,
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert && !this.isSet) {
+ return false;
+ }
+ },
},
- },
- createdAt: {
- /**
- * Creation time of the board
- */
- type: Date,
- autoValue() { // eslint-disable-line consistent-return
- if (this.isInsert) {
- return new Date();
- } else {
- this.unset();
- }
+ createdAt: {
+ /**
+ * Creation time of the board
+ */
+ type: Date,
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
- },
- // XXX Inconsistent field naming
- modifiedAt: {
- /**
- * Last modification time of the board
- */
- type: Date,
- optional: true,
- autoValue() { // eslint-disable-line consistent-return
- if (this.isUpdate) {
- return new Date();
- } else {
- this.unset();
- }
+ // XXX Inconsistent field naming
+ modifiedAt: {
+ /**
+ * Last modification time of the board
+ */
+ type: Date,
+ optional: true,
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert || this.isUpsert || this.isUpdate) {
+ return new Date();
+ } else {
+ this.unset();
+ }
+ },
},
- },
- // De-normalized number of users that have starred this board
- stars: {
- /**
- * How many stars the board has
- */
- type: Number,
- autoValue() { // eslint-disable-line consistent-return
- if (this.isInsert) {
- return 0;
- }
+ // De-normalized number of users that have starred this board
+ stars: {
+ /**
+ * How many stars the board has
+ */
+ type: Number,
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert) {
+ return 0;
+ }
+ },
},
- },
- // De-normalized label system
- 'labels': {
- /**
- * List of labels attached to a board
- */
- type: [Object],
- autoValue() { // eslint-disable-line consistent-return
- if (this.isInsert && !this.isSet) {
- const colors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
- const defaultLabelsColors = _.clone(colors).splice(0, 6);
- return defaultLabelsColors.map((color) => ({
- color,
- _id: Random.id(6),
- name: '',
- }));
- }
+ // De-normalized label system
+ labels: {
+ /**
+ * List of labels attached to a board
+ */
+ type: [Object],
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert && !this.isSet) {
+ const colors = Boards.simpleSchema()._schema['labels.$.color']
+ .allowedValues;
+ const defaultLabelsColors = _.clone(colors).splice(0, 6);
+ return defaultLabelsColors.map((color) => ({
+ color,
+ _id: Random.id(6),
+ name: '',
+ }));
+ }
+ },
},
- },
- 'labels.$._id': {
- /**
- * Unique id of a label
- */
- // We don't specify that this field must be unique in the board because that
- // will cause performance penalties and is not necessary since this field is
- // always set on the server.
- // XXX Actually if we create a new label, the `_id` is set on the client
- // without being overwritten by the server, could it be a problem?
- type: String,
- },
- 'labels.$.name': {
- /**
- * Name of a label
- */
- type: String,
- optional: true,
- },
- 'labels.$.color': {
- /**
- * color of a label.
- *
- * Can be amongst `green`, `yellow`, `orange`, `red`, `purple`,
- * `blue`, `sky`, `lime`, `pink`, `black`,
- * `silver`, `peachpuff`, `crimson`, `plum`, `darkgreen`,
- * `slateblue`, `magenta`, `gold`, `navy`, `gray`,
- * `saddlebrown`, `paleturquoise`, `mistyrose`, `indigo`
- */
- type: String,
- allowedValues: [
- 'green', 'yellow', 'orange', 'red', 'purple',
- 'blue', 'sky', 'lime', 'pink', 'black',
- 'silver', 'peachpuff', 'crimson', 'plum', 'darkgreen',
- 'slateblue', 'magenta', 'gold', 'navy', 'gray',
- 'saddlebrown', 'paleturquoise', 'mistyrose', 'indigo',
- ],
- },
- // XXX We might want to maintain more informations under the member sub-
- // documents like de-normalized meta-data (the date the member joined the
- // board, the number of contributions, etc.).
- 'members': {
- /**
- * List of members of a board
- */
- type: [Object],
- autoValue() { // eslint-disable-line consistent-return
- if (this.isInsert && !this.isSet) {
- return [{
- userId: this.userId,
- isAdmin: true,
- isActive: true,
- isNoComments: false,
- isCommentOnly: false,
- }];
- }
+ 'labels.$._id': {
+ /**
+ * Unique id of a label
+ */
+ // We don't specify that this field must be unique in the board because that
+ // will cause performance penalties and is not necessary since this field is
+ // always set on the server.
+ // XXX Actually if we create a new label, the `_id` is set on the client
+ // without being overwritten by the server, could it be a problem?
+ type: String,
},
- },
- 'members.$.userId': {
- /**
- * The uniq ID of the member
- */
- type: String,
- },
- 'members.$.isAdmin': {
- /**
- * Is the member an admin of the board?
- */
- type: Boolean,
- },
- 'members.$.isActive': {
- /**
- * Is the member active?
- */
- type: Boolean,
- },
- 'members.$.isNoComments': {
- /**
- * Is the member not allowed to make comments
- */
- type: Boolean,
- optional: true,
- },
- 'members.$.isCommentOnly': {
- /**
- * Is the member only allowed to comment on the board
- */
- type: Boolean,
- optional: true,
- },
- permission: {
- /**
- * visibility of the board
- */
- type: String,
- allowedValues: ['public', 'private'],
- },
- color: {
- /**
- * The color of the board.
- */
- type: String,
- allowedValues: [
- 'belize',
- 'nephritis',
- 'pomegranate',
- 'pumpkin',
- 'wisteria',
- 'midnight',
- ],
- autoValue() { // eslint-disable-line consistent-return
- if (this.isInsert && !this.isSet) {
- return Boards.simpleSchema()._schema.color.allowedValues[0];
- }
+ 'labels.$.name': {
+ /**
+ * Name of a label
+ */
+ type: String,
+ optional: true,
},
- },
- description: {
- /**
- * The description of the board
- */
- type: String,
- optional: true,
- },
- subtasksDefaultBoardId: {
- /**
- * The default board ID assigned to subtasks.
- */
- type: String,
- optional: true,
- defaultValue: null,
- },
- subtasksDefaultListId: {
- /**
- * The default List ID assigned to subtasks.
- */
- type: String,
- optional: true,
- defaultValue: null,
- },
- allowsSubtasks: {
- /**
- * Does the board allows subtasks?
- */
- type: Boolean,
- defaultValue: true,
- },
- presentParentTask: {
- /**
- * Controls how to present the parent task:
- *
- * - `prefix-with-full-path`: add a prefix with the full path
- * - `prefix-with-parent`: add a prefisx with the parent name
- * - `subtext-with-full-path`: add a subtext with the full path
- * - `subtext-with-parent`: add a subtext with the parent name
- * - `no-parent`: does not show the parent at all
- */
- type: String,
- allowedValues: [
- 'prefix-with-full-path',
- 'prefix-with-parent',
- 'subtext-with-full-path',
- 'subtext-with-parent',
- 'no-parent',
- ],
- optional: true,
- defaultValue: 'no-parent',
- },
- startAt: {
- /**
- * Starting date of the board.
- */
- type: Date,
- optional: true,
- },
- dueAt: {
- /**
- * Due date of the board.
- */
- type: Date,
- optional: true,
- },
- endAt: {
- /**
- * End date of the board.
- */
- type: Date,
- optional: true,
- },
- spentTime: {
- /**
- * Time spent in the board.
- */
- type: Number,
- decimal: true,
- optional: true,
- },
- isOvertime: {
- /**
- * Is the board overtimed?
- */
- type: Boolean,
- defaultValue: false,
- optional: true,
- },
- type: {
- /**
- * The type of board
- */
- type: String,
- defaultValue: 'board',
- },
-}));
-
+ 'labels.$.color': {
+ /**
+ * color of a label.
+ *
+ * Can be amongst `green`, `yellow`, `orange`, `red`, `purple`,
+ * `blue`, `sky`, `lime`, `pink`, `black`,
+ * `silver`, `peachpuff`, `crimson`, `plum`, `darkgreen`,
+ * `slateblue`, `magenta`, `gold`, `navy`, `gray`,
+ * `saddlebrown`, `paleturquoise`, `mistyrose`, `indigo`
+ */
+ type: String,
+ allowedValues: [
+ 'green',
+ 'yellow',
+ 'orange',
+ 'red',
+ 'purple',
+ 'blue',
+ 'sky',
+ 'lime',
+ 'pink',
+ 'black',
+ 'silver',
+ 'peachpuff',
+ 'crimson',
+ 'plum',
+ 'darkgreen',
+ 'slateblue',
+ 'magenta',
+ 'gold',
+ 'navy',
+ 'gray',
+ 'saddlebrown',
+ 'paleturquoise',
+ 'mistyrose',
+ 'indigo',
+ ],
+ },
+ // XXX We might want to maintain more informations under the member sub-
+ // documents like de-normalized meta-data (the date the member joined the
+ // board, the number of contributions, etc.).
+ members: {
+ /**
+ * List of members of a board
+ */
+ type: [Object],
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert && !this.isSet) {
+ return [
+ {
+ userId: this.userId,
+ isAdmin: true,
+ isActive: true,
+ isNoComments: false,
+ isCommentOnly: false,
+ },
+ ];
+ }
+ },
+ },
+ 'members.$.userId': {
+ /**
+ * The uniq ID of the member
+ */
+ type: String,
+ },
+ 'members.$.isAdmin': {
+ /**
+ * Is the member an admin of the board?
+ */
+ type: Boolean,
+ },
+ 'members.$.isActive': {
+ /**
+ * Is the member active?
+ */
+ type: Boolean,
+ },
+ 'members.$.isNoComments': {
+ /**
+ * Is the member not allowed to make comments
+ */
+ type: Boolean,
+ optional: true,
+ },
+ 'members.$.isCommentOnly': {
+ /**
+ * Is the member only allowed to comment on the board
+ */
+ type: Boolean,
+ optional: true,
+ },
+ permission: {
+ /**
+ * visibility of the board
+ */
+ type: String,
+ allowedValues: ['public', 'private'],
+ },
+ color: {
+ /**
+ * The color of the board.
+ */
+ type: String,
+ allowedValues: [
+ 'belize',
+ 'nephritis',
+ 'pomegranate',
+ 'pumpkin',
+ 'wisteria',
+ 'midnight',
+ ],
+ // eslint-disable-next-line consistent-return
+ autoValue() {
+ if (this.isInsert && !this.isSet) {
+ return Boards.simpleSchema()._schema.color.allowedValues[0];
+ }
+ },
+ },
+ description: {
+ /**
+ * The description of the board
+ */
+ type: String,
+ optional: true,
+ },
+ subtasksDefaultBoardId: {
+ /**
+ * The default board ID assigned to subtasks.
+ */
+ type: String,
+ optional: true,
+ defaultValue: null,
+ },
+ subtasksDefaultListId: {
+ /**
+ * The default List ID assigned to subtasks.
+ */
+ type: String,
+ optional: true,
+ defaultValue: null,
+ },
+ allowsSubtasks: {
+ /**
+ * Does the board allows subtasks?
+ */
+ type: Boolean,
+ defaultValue: true,
+ },
+ presentParentTask: {
+ /**
+ * Controls how to present the parent task:
+ *
+ * - `prefix-with-full-path`: add a prefix with the full path
+ * - `prefix-with-parent`: add a prefisx with the parent name
+ * - `subtext-with-full-path`: add a subtext with the full path
+ * - `subtext-with-parent`: add a subtext with the parent name
+ * - `no-parent`: does not show the parent at all
+ */
+ type: String,
+ allowedValues: [
+ 'prefix-with-full-path',
+ 'prefix-with-parent',
+ 'subtext-with-full-path',
+ 'subtext-with-parent',
+ 'no-parent',
+ ],
+ optional: true,
+ defaultValue: 'no-parent',
+ },
+ startAt: {
+ /**
+ * Starting date of the board.
+ */
+ type: Date,
+ optional: true,
+ },
+ dueAt: {
+ /**
+ * Due date of the board.
+ */
+ type: Date,
+ optional: true,
+ },
+ endAt: {
+ /**
+ * End date of the board.
+ */
+ type: Date,
+ optional: true,
+ },
+ spentTime: {
+ /**
+ * Time spent in the board.
+ */
+ type: Number,
+ decimal: true,
+ optional: true,
+ },
+ isOvertime: {
+ /**
+ * Is the board overtimed?
+ */
+ type: Boolean,
+ defaultValue: false,
+ optional: true,
+ },
+ type: {
+ /**
+ * The type of board
+ */
+ type: String,
+ defaultValue: 'board',
+ },
+ })
+);
Boards.helpers({
copy() {
@@ -350,7 +381,9 @@ Boards.helpers({
*/
isActiveMember(userId) {
if (userId) {
- return this.members.find((member) => (member.userId === userId && member.isActive));
+ return this.members.find(
+ (member) => member.userId === userId && member.isActive
+ );
} else {
return false;
}
@@ -361,11 +394,17 @@ Boards.helpers({
},
cards() {
- return Cards.find({ boardId: this._id, archived: false }, { sort: { title: 1 } });
+ return Cards.find(
+ { boardId: this._id, archived: false },
+ { sort: { title: 1 } }
+ );
},
lists() {
- return Lists.find({ boardId: this._id, archived: false }, { sort: { sort: 1 } });
+ return Lists.find(
+ { boardId: this._id, archived: false },
+ { sort: { sort: 1 } }
+ );
},
nullSortLists() {
@@ -377,18 +416,24 @@ Boards.helpers({
},
swimlanes() {
- return Swimlanes.find({ boardId: this._id, archived: false }, { sort: { sort: 1 } });
+ return Swimlanes.find(
+ { boardId: this._id, archived: false },
+ { sort: { sort: 1 } }
+ );
},
nextSwimlane(swimlane) {
- return Swimlanes.findOne({
- boardId: this._id,
- archived: false,
- sort: { $gte: swimlane.sort },
- _id: { $ne: swimlane._id },
- }, {
- sort: { sort: 1 },
- });
+ return Swimlanes.findOne(
+ {
+ boardId: this._id,
+ archived: false,
+ sort: { $gte: swimlane.sort },
+ _id: { $ne: swimlane._id },
+ },
+ {
+ sort: { sort: 1 },
+ }
+ );
},
nullSortSwimlanes() {
@@ -399,13 +444,21 @@ Boards.helpers({
});
},
- hasOvertimeCards(){
- const card = Cards.findOne({isOvertime: true, boardId: this._id, archived: false} );
+ hasOvertimeCards() {
+ const card = Cards.findOne({
+ isOvertime: true,
+ boardId: this._id,
+ archived: false,
+ });
return card !== undefined;
},
- hasSpentTimeCards(){
- const card = Cards.findOne({spentTime: { $gt: 0 }, boardId: this._id, archived: false} );
+ hasSpentTimeCards() {
+ const card = Cards.findOne({
+ spentTime: { $gt: 0 },
+ boardId: this._id,
+ archived: false,
+ });
return card !== undefined;
},
@@ -429,7 +482,7 @@ Boards.helpers({
return _.findWhere(this.labels, { name, color });
},
- getLabelById(labelId){
+ getLabelById(labelId) {
return _.findWhere(this.labels, { _id: labelId });
},
@@ -446,15 +499,29 @@ Boards.helpers({
},
hasAdmin(memberId) {
- return !!_.findWhere(this.members, { userId: memberId, isActive: true, isAdmin: true });
+ return !!_.findWhere(this.members, {
+ userId: memberId,
+ isActive: true,
+ isAdmin: true,
+ });
},
hasNoComments(memberId) {
- return !!_.findWhere(this.members, { userId: memberId, isActive: true, isAdmin: false, isNoComments: true });
+ return !!_.findWhere(this.members, {
+ userId: memberId,
+ isActive: true,
+ isAdmin: false,
+ isNoComments: true,
+ });
},
hasCommentOnly(memberId) {
- return !!_.findWhere(this.members, { userId: memberId, isActive: true, isAdmin: false, isCommentOnly: true });
+ return !!_.findWhere(this.members, {
+ userId: memberId,
+ isActive: true,
+ isAdmin: false,
+ isCommentOnly: true,
+ });
},
absoluteUrl() {
@@ -466,7 +533,10 @@ Boards.helpers({
},
customFields() {
- return CustomFields.find({ boardIds: {$in: [this._id]} }, { sort: { name: 1 } });
+ return CustomFields.find(
+ { boardIds: { $in: [this._id] } },
+ { sort: { name: 1 } }
+ );
},
// XXX currently mutations return no value so we have an issue when using addLabel in import
@@ -489,10 +559,7 @@ Boards.helpers({
if (term) {
const regex = new RegExp(term, 'i');
- query.$or = [
- { title: regex },
- { description: regex },
- ];
+ query.$or = [{ title: regex }, { description: regex }];
}
return Cards.find(query, projection);
@@ -506,17 +573,14 @@ Boards.helpers({
query.type = 'template-swimlane';
query.archived = false;
} else {
- query.type = {$nin: ['template-swimlane']};
+ query.type = { $nin: ['template-swimlane'] };
}
const projection = { limit: 10, sort: { createdAt: -1 } };
if (term) {
const regex = new RegExp(term, 'i');
- query.$or = [
- { title: regex },
- { description: regex },
- ];
+ query.$or = [{ title: regex }, { description: regex }];
}
return Swimlanes.find(query, projection);
@@ -530,17 +594,14 @@ Boards.helpers({
query.type = 'template-list';
query.archived = false;
} else {
- query.type = {$nin: ['template-list']};
+ query.type = { $nin: ['template-list'] };
}
const projection = { limit: 10, sort: { createdAt: -1 } };
if (term) {
const regex = new RegExp(term, 'i');
- query.$or = [
- { title: regex },
- { description: regex },
- ];
+ query.$or = [{ title: regex }, { description: regex }];
}
return Lists.find(query, projection);
@@ -557,17 +618,14 @@ Boards.helpers({
query.type = 'template-card';
query.archived = false;
} else {
- query.type = {$nin: ['template-card']};
+ query.type = { $nin: ['template-card'] };
}
const projection = { limit: 10, sort: { createdAt: -1 } };
if (term) {
const regex = new RegExp(term, 'i');
- query.$or = [
- { title: regex },
- { description: regex },
- ];
+ query.$or = [{ title: regex }, { description: regex }];
}
return Cards.find(query, projection);
@@ -575,22 +633,29 @@ Boards.helpers({
// A board alwasy has another board where it deposits subtasks of thasks
// that belong to itself.
getDefaultSubtasksBoardId() {
- if ((this.subtasksDefaultBoardId === null) || (this.subtasksDefaultBoardId === undefined)) {
+ if (
+ this.subtasksDefaultBoardId === null ||
+ this.subtasksDefaultBoardId === undefined
+ ) {
this.subtasksDefaultBoardId = Boards.insert({
title: `^${this.title}^`,
permission: this.permission,
members: this.members,
color: this.color,
- description: TAPi18n.__('default-subtasks-board', {board: this.title}),
+ description: TAPi18n.__('default-subtasks-board', {
+ board: this.title,
+ }),
});
Swimlanes.insert({
title: TAPi18n.__('default'),
boardId: this.subtasksDefaultBoardId,
});
- Boards.update(this._id, {$set: {
- subtasksDefaultBoardId: this.subtasksDefaultBoardId,
- }});
+ Boards.update(this._id, {
+ $set: {
+ subtasksDefaultBoardId: this.subtasksDefaultBoardId,
+ },
+ });
}
return this.subtasksDefaultBoardId;
},
@@ -600,7 +665,10 @@ Boards.helpers({
},
getDefaultSubtasksListId() {
- if ((this.subtasksDefaultListId === null) || (this.subtasksDefaultListId === undefined)) {
+ if (
+ this.subtasksDefaultListId === null ||
+ this.subtasksDefaultListId === undefined
+ ) {
this.subtasksDefaultListId = Lists.insert({
title: TAPi18n.__('queue'),
boardId: this._id,
@@ -615,13 +683,13 @@ Boards.helpers({
},
getDefaultSwimline() {
- let result = Swimlanes.findOne({boardId: this._id});
+ let result = Swimlanes.findOne({ boardId: this._id });
if (result === undefined) {
Swimlanes.insert({
title: TAPi18n.__('default'),
boardId: this._id,
});
- result = Swimlanes.findOne({boardId: this._id});
+ result = Swimlanes.findOne({ boardId: this._id });
}
return result;
},
@@ -633,19 +701,24 @@ Boards.helpers({
{
startAt: {
$lte: start,
- }, endAt: {
+ },
+ endAt: {
$gte: start,
},
- }, {
+ },
+ {
startAt: {
$lte: end,
- }, endAt: {
+ },
+ endAt: {
$gte: end,
},
- }, {
+ },
+ {
startAt: {
$gte: start,
- }, endAt: {
+ },
+ endAt: {
$lte: end,
},
},
@@ -662,7 +735,6 @@ Boards.helpers({
},
});
-
Boards.mutations({
archive() {
return { $set: { archived: true } };
@@ -753,7 +825,8 @@ Boards.mutations({
const memberIndex = this.memberIndex(memberId);
// we do not allow the only one admin to be removed
- const allowRemove = (!this.members[memberIndex].isAdmin) || (this.activeAdmins().length > 1);
+ const allowRemove =
+ !this.members[memberIndex].isAdmin || this.activeAdmins().length > 1;
if (!allowRemove) {
return {
$set: {
@@ -770,7 +843,13 @@ Boards.mutations({
};
},
- setMemberPermission(memberId, isAdmin, isNoComments, isCommentOnly, currentUserId = Meteor.userId()) {
+ setMemberPermission(
+ memberId,
+ isAdmin,
+ isNoComments,
+ isCommentOnly,
+ currentUserId = Meteor.userId()
+ ) {
const memberIndex = this.memberIndex(memberId);
// do not allow change permission of self
if (memberId === currentUserId) {
@@ -804,12 +883,13 @@ Boards.mutations({
});
function boardRemover(userId, doc) {
- [Cards, Lists, Swimlanes, Integrations, Rules, Activities].forEach((element) => {
- element.remove({ boardId: doc._id });
- });
+ [Cards, Lists, Swimlanes, Integrations, Rules, Activities].forEach(
+ (element) => {
+ element.remove({ boardId: doc._id });
+ }
+ );
}
-
if (Meteor.isServer) {
Boards.allow({
insert: Meteor.userId,
@@ -830,25 +910,25 @@ if (Meteor.isServer) {
// We can't remove a member if it is the last administrator
Boards.deny({
update(userId, doc, fieldNames, modifier) {
- if (!_.contains(fieldNames, 'members'))
- return false;
+ if (!_.contains(fieldNames, 'members')) return false;
// We only care in case of a $pull operation, ie remove a member
- if (!_.isObject(modifier.$pull && modifier.$pull.members))
- return false;
+ if (!_.isObject(modifier.$pull && modifier.$pull.members)) return false;
// If there is more than one admin, it's ok to remove anyone
- const nbAdmins = _.where(doc.members, { isActive: true, isAdmin: true }).length;
- if (nbAdmins > 1)
- return false;
+ const nbAdmins = _.where(doc.members, { isActive: true, isAdmin: true })
+ .length;
+ if (nbAdmins > 1) return false;
// If all the previous conditions were verified, we can't remove
// a user if it's an admin
const removedMemberId = modifier.$pull.members.userId;
- return Boolean(_.findWhere(doc.members, {
- userId: removedMemberId,
- isAdmin: true,
- }));
+ return Boolean(
+ _.findWhere(doc.members, {
+ userId: removedMemberId,
+ isAdmin: true,
+ })
+ );
},
fetch: ['members'],
});
@@ -882,16 +962,19 @@ if (Meteor.isServer) {
} else throw new Meteor.Error('error-board-doesNotExist');
},
});
-
}
if (Meteor.isServer) {
// Let MongoDB ensure that a member is not included twice in the same board
Meteor.startup(() => {
- Boards._collection._ensureIndex({
- _id: 1,
- 'members.userId': 1,
- }, { unique: true });
+ Boards._collection._ensureIndex({ modifiedAt: -1 });
+ Boards._collection._ensureIndex(
+ {
+ _id: 1,
+ 'members.userId': 1,
+ },
+ { unique: true }
+ );
Boards._collection._ensureIndex({ 'members.userId': 1 });
});
@@ -909,10 +992,12 @@ if (Meteor.isServer) {
// If the user remove one label from a board, we cant to remove reference of
// this label in any card of this board.
Boards.after.update((userId, doc, fieldNames, modifier) => {
- if (!_.contains(fieldNames, 'labels') ||
+ if (
+ !_.contains(fieldNames, 'labels') ||
!modifier.$pull ||
!modifier.$pull.labels ||
- !modifier.$pull.labels._id) {
+ !modifier.$pull.labels._id
+ ) {
return;
}
@@ -935,12 +1020,21 @@ if (Meteor.isServer) {
}
const parts = set.split('.');
- if (parts.length === 3 && parts[0] === 'members' && parts[2] === 'isActive') {
+ if (
+ parts.length === 3 &&
+ parts[0] === 'members' &&
+ parts[2] === 'isActive'
+ ) {
callback(doc.members[parts[1]].userId);
}
});
};
+ Boards.before.update((userId, doc, fieldNames, modifier, options) => {
+ modifier.$set = modifier.$set || {};
+ modifier.$set.modifiedAt = Date.now();
+ });
+
// Remove a member from all objects of the board before leaving the board
Boards.before.update((userId, doc, fieldNames, modifier) => {
if (!_.contains(fieldNames, 'members')) {
@@ -976,14 +1070,11 @@ if (Meteor.isServer) {
// Remove board from users starred list
if (!board.isPublic()) {
- Users.update(
- memberId,
- {
- $pull: {
- 'profile.starredBoards': boardId,
- },
- }
- );
+ Users.update(memberId, {
+ $pull: {
+ 'profile.starredBoards': boardId,
+ },
+ });
}
});
}
@@ -1044,29 +1135,34 @@ if (Meteor.isServer) {
* @return_type [{_id: string,
title: string}]
*/
- JsonRoutes.add('GET', '/api/users/:userId/boards', function (req, res) {
+ JsonRoutes.add('GET', '/api/users/:userId/boards', function(req, res) {
try {
Authentication.checkLoggedIn(req.userId);
const paramUserId = req.params.userId;
// A normal user should be able to see their own boards,
// admins can access boards of any user
- Authentication.checkAdminOrCondition(req.userId, req.userId === paramUserId);
+ Authentication.checkAdminOrCondition(
+ req.userId,
+ req.userId === paramUserId
+ );
- const data = Boards.find({
- archived: false,
- 'members.userId': paramUserId,
- }, {
- sort: ['title'],
- }).map(function(board) {
+ const data = Boards.find(
+ {
+ archived: false,
+ 'members.userId': paramUserId,
+ },
+ {
+ sort: ['title'],
+ }
+ ).map(function(board) {
return {
_id: board._id,
title: board.title,
};
});
- JsonRoutes.sendResult(res, {code: 200, data});
- }
- catch (error) {
+ JsonRoutes.sendResult(res, { code: 200, data });
+ } catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
data: error,
@@ -1081,20 +1177,19 @@ if (Meteor.isServer) {
* @return_type [{_id: string,
title: string}]
*/
- JsonRoutes.add('GET', '/api/boards', function (req, res) {
+ JsonRoutes.add('GET', '/api/boards', function(req, res) {
try {
Authentication.checkUserId(req.userId);
JsonRoutes.sendResult(res, {
code: 200,
- data: Boards.find({ permission: 'public' }).map(function (doc) {
+ data: Boards.find({ permission: 'public' }).map(function(doc) {
return {
_id: doc._id,
title: doc.title,
};
}),
});
- }
- catch (error) {
+ } catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
data: error,
@@ -1109,7 +1204,7 @@ if (Meteor.isServer) {
* @param {string} boardId the ID of the board to retrieve the data
* @return_type Boards
*/
- JsonRoutes.add('GET', '/api/boards/:boardId', function (req, res) {
+ JsonRoutes.add('GET', '/api/boards/:boardId', function(req, res) {
try {
const id = req.params.boardId;
Authentication.checkBoardAccess(req.userId, id);
@@ -1118,8 +1213,7 @@ if (Meteor.isServer) {
code: 200,
data: Boards.findOne({ _id: id }),
});
- }
- catch (error) {
+ } catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
data: error,
@@ -1152,7 +1246,7 @@ if (Meteor.isServer) {
* @return_type {_id: string,
defaultSwimlaneId: string}
*/
- JsonRoutes.add('POST', '/api/boards', function (req, res) {
+ JsonRoutes.add('POST', '/api/boards', function(req, res) {
try {
Authentication.checkUserId(req.userId);
const id = Boards.insert({
@@ -1180,8 +1274,7 @@ if (Meteor.isServer) {
defaultSwimlaneId: swimlaneId,
},
});
- }
- catch (error) {
+ } catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
data: error,
@@ -1195,19 +1288,18 @@ if (Meteor.isServer) {
*
* @param {string} boardId the ID of the board
*/
- JsonRoutes.add('DELETE', '/api/boards/:boardId', function (req, res) {
+ JsonRoutes.add('DELETE', '/api/boards/:boardId', function(req, res) {
try {
Authentication.checkUserId(req.userId);
const id = req.params.boardId;
Boards.remove({ _id: id });
JsonRoutes.sendResult(res, {
code: 200,
- data:{
+ data: {
_id: id,
},
});
- }
- catch (error) {
+ } catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
data: error,
@@ -1228,7 +1320,7 @@ if (Meteor.isServer) {
*
* @return_type string
*/
- JsonRoutes.add('PUT', '/api/boards/:boardId/labels', function (req, res) {
+ JsonRoutes.add('PUT', '/api/boards/:boardId/labels', function(req, res) {
Authentication.checkUserId(req.userId);
const id = req.params.boardId;
try {
@@ -1238,7 +1330,10 @@ if (Meteor.isServer) {
const name = req.body.label.name;
const labelId = Random.id(6);
if (!board.getLabel(name, color)) {
- Boards.direct.update({ _id: id }, { $push: { labels: { _id: labelId, name, color } } });
+ Boards.direct.update(
+ { _id: id },
+ { $push: { labels: { _id: labelId, name, color } } }
+ );
JsonRoutes.sendResult(res, {
code: 200,
data: labelId,
@@ -1249,8 +1344,7 @@ if (Meteor.isServer) {
});
}
}
- }
- catch (error) {
+ } catch (error) {
JsonRoutes.sendResult(res, {
data: error,
});
@@ -1268,29 +1362,36 @@ if (Meteor.isServer) {
* @param {boolean} isNoComments NoComments capability
* @param {boolean} isCommentOnly CommentsOnly capability
*/
- JsonRoutes.add('POST', '/api/boards/:boardId/members/:memberId', function (req, res) {
+ JsonRoutes.add('POST', '/api/boards/:boardId/members/:memberId', function(
+ req,
+ res
+ ) {
try {
const boardId = req.params.boardId;
const memberId = req.params.memberId;
- const {isAdmin, isNoComments, isCommentOnly} = req.body;
+ const { isAdmin, isNoComments, isCommentOnly } = req.body;
Authentication.checkBoardAccess(req.userId, boardId);
const board = Boards.findOne({ _id: boardId });
- function isTrue(data){
+ function isTrue(data) {
try {
return data.toLowerCase() === 'true';
- }
- catch (error) {
+ } catch (error) {
return data;
}
}
- const query = board.setMemberPermission(memberId, isTrue(isAdmin), isTrue(isNoComments), isTrue(isCommentOnly), req.userId);
+ const query = board.setMemberPermission(
+ memberId,
+ isTrue(isAdmin),
+ isTrue(isNoComments),
+ isTrue(isCommentOnly),
+ req.userId
+ );
JsonRoutes.sendResult(res, {
code: 200,
data: query,
});
- }
- catch (error) {
+ } catch (error) {
JsonRoutes.sendResult(res, {
code: 200,
data: error,
@@ -1298,3 +1399,5 @@ if (Meteor.isServer) {
}
});
}
+
+export default Boards;