diff options
author | Justin Reynolds <justinr1234@gmail.com> | 2019-06-26 17:47:27 -0500 |
---|---|---|
committer | Justin Reynolds <justinr1234@gmail.com> | 2019-06-27 09:13:20 -0500 |
commit | c60e80d25baa6a81b28f6090ca848553d20b2bb7 (patch) | |
tree | 64bcea66932f4b4635d5df6901f18d5ba6db0a37 /models/boards.js | |
parent | fb728baf0c87bae5fa39d92089b667ff1ed69fa6 (diff) | |
download | wekan-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.js | 953 |
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; |