diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/accountSettings.js | 12 | ||||
-rw-r--r-- | models/boards.js | 283 | ||||
-rw-r--r-- | models/cards.js | 16 | ||||
-rw-r--r-- | models/checklists.js | 11 | ||||
-rw-r--r-- | models/export.js | 18 | ||||
-rw-r--r-- | models/settings.js | 8 | ||||
-rw-r--r-- | models/swimlanes.js | 8 | ||||
-rw-r--r-- | models/users.js | 10 | ||||
-rw-r--r-- | models/wekanCreator.js | 2 |
9 files changed, 342 insertions, 26 deletions
diff --git a/models/accountSettings.js b/models/accountSettings.js index f61614b8..a20303f5 100644 --- a/models/accountSettings.js +++ b/models/accountSettings.js @@ -82,4 +82,16 @@ if (Meteor.isServer) { }); } +AccountSettings.helpers({ + allowEmailChange() { + return AccountSettings.findOne('accounts-allowEmailChange').booleanValue; + }, + allowUserNameChange() { + return AccountSettings.findOne('accounts-allowUserNameChange').booleanValue; + }, + allowUserDelete() { + return AccountSettings.findOne('accounts-allowUserDelete').booleanValue; + }, +}); + export default AccountSettings; diff --git a/models/boards.js b/models/boards.js index 85a7558c..8862f301 100644 --- a/models/boards.js +++ b/models/boards.js @@ -185,6 +185,7 @@ Boards.attachSchema( isActive: true, isNoComments: false, isCommentOnly: false, + isWorker: false, }, ]; } @@ -222,6 +223,13 @@ Boards.attachSchema( type: Boolean, optional: true, }, + 'members.$.isWorker': { + /** + * Is the member only allowed to move card, assign himself to card and comment + */ + type: Boolean, + optional: true, + }, permission: { /** * visibility of the board @@ -270,6 +278,7 @@ Boards.attachSchema( optional: true, defaultValue: null, }, + subtasksDefaultListId: { /** * The default List ID assigned to subtasks. @@ -278,6 +287,19 @@ Boards.attachSchema( optional: true, defaultValue: null, }, + + dateSettingsDefaultBoardId: { + type: String, + optional: true, + defaultValue: null, + }, + + dateSettingsDefaultListId: { + type: String, + optional: true, + defaultValue: null, + }, + allowsSubtasks: { /** * Does the board allows subtasks? @@ -285,6 +307,127 @@ Boards.attachSchema( type: Boolean, defaultValue: true, }, + + allowsAttachments: { + /** + * Does the board allows attachments? + */ + type: Boolean, + defaultValue: true, + }, + + allowsChecklists: { + /** + * Does the board allows checklists? + */ + type: Boolean, + defaultValue: true, + }, + + allowsComments: { + /** + * Does the board allows comments? + */ + type: Boolean, + defaultValue: true, + }, + + allowsDescriptionTitle: { + /** + * Does the board allows description title? + */ + type: Boolean, + defaultValue: true, + }, + + allowsDescriptionText: { + /** + * Does the board allows description text? + */ + type: Boolean, + defaultValue: true, + }, + + allowsActivities: { + /** + * Does the board allows comments? + */ + type: Boolean, + defaultValue: true, + }, + + allowsLabels: { + /** + * Does the board allows labels? + */ + type: Boolean, + defaultValue: true, + }, + + allowsAssignee: { + /** + * Does the board allows assignee? + */ + type: Boolean, + defaultValue: true, + }, + + allowsMembers: { + /** + * Does the board allows members? + */ + type: Boolean, + defaultValue: true, + }, + + allowsRequestedBy: { + /** + * Does the board allows requested by? + */ + type: Boolean, + defaultValue: true, + }, + + allowsAssignedBy: { + /** + * Does the board allows requested by? + */ + type: Boolean, + defaultValue: true, + }, + + allowsReceivedDate: { + /** + * Does the board allows received date? + */ + type: Boolean, + defaultValue: true, + }, + + allowsStartDate: { + /** + * Does the board allows start date? + */ + type: Boolean, + defaultValue: true, + }, + + allowsEndDate: { + /** + * Does the board allows end date? + */ + type: Boolean, + defaultValue: true, + }, + + allowsDueDate: { + /** + * Does the board allows due date? + */ + type: Boolean, + defaultValue: true, + }, + presentParentTask: { /** * Controls how to present the parent task: @@ -409,8 +552,12 @@ Boards.helpers({ }, lists() { - const enabled = Meteor.user().hasSortBy(); - return enabled ? this.newestLists() : this.draggableLists(); + //currentUser = Meteor.user(); + //if (currentUser) { + // enabled = Meteor.user().hasSortBy(); + //} + //return enabled ? this.newestLists() : this.draggableLists(); + return this.draggableLists(); }, newestLists() { @@ -534,6 +681,7 @@ Boards.helpers({ isActive: true, isAdmin: false, isNoComments: true, + isWorker: false, }); }, @@ -543,6 +691,17 @@ Boards.helpers({ isActive: true, isAdmin: false, isCommentOnly: true, + isWorker: false, + }); + }, + + hasWorker(memberId) { + return !!_.findWhere(this.members, { + userId: memberId, + isActive: true, + isAdmin: false, + isCommentOnly: false, + isWorker: true, }); }, @@ -686,6 +845,39 @@ Boards.helpers({ return Boards.findOne(this.getDefaultSubtasksBoardId()); }, + //Date Settings option such as received date, start date and so on. + getDefaultDateSettingsBoardId() { + if ( + this.dateSettingsDefaultBoardId === null || + this.dateSettingsDefaultBoardId === undefined + ) { + this.dateSettingsDefaultBoardId = Boards.insert({ + title: `^${this.title}^`, + permission: this.permission, + members: this.members, + color: this.color, + description: TAPi18n.__('default-dates-board', { + board: this.title, + }), + }); + + Swimlanes.insert({ + title: TAPi18n.__('default'), + boardId: this.dateSettingsDefaultBoardId, + }); + Boards.update(this._id, { + $set: { + dateSettingsDefaultBoardId: this.dateSettingsDefaultBoardId, + }, + }); + } + return this.dateSettingsDefaultBoardId; + }, + + getDefaultDateSettingsBoard() { + return Boards.findOne(this.getDefaultDateSettingsBoardId()); + }, + getDefaultSubtasksListId() { if ( this.subtasksDefaultListId === null || @@ -704,6 +896,24 @@ Boards.helpers({ return Lists.findOne(this.getDefaultSubtasksListId()); }, + getDefaultDateSettingsListId() { + if ( + this.dateSettingsDefaultListId === null || + this.dateSettingsDefaultListId === undefined + ) { + this.dateSettingsDefaultListId = Lists.insert({ + title: TAPi18n.__('queue'), + boardId: this._id, + }); + this.setDateSettingsDefaultListId(this.dateSettingsDefaultListId); + } + return this.dateSettingsDefaultListId; + }, + + getDefaultDateSettingsList() { + return Lists.findOne(this.getDefaultDateSettingsListId()); + }, + getDefaultSwimline() { let result = Swimlanes.findOne({ boardId: this._id }); if (result === undefined) { @@ -845,6 +1055,7 @@ Boards.mutations({ isActive: true, isNoComments: false, isCommentOnly: false, + isWorker: false, }, }, }; @@ -877,6 +1088,7 @@ Boards.mutations({ isAdmin, isNoComments, isCommentOnly, + isWorker, currentUserId = Meteor.userId(), ) { const memberIndex = this.memberIndex(memberId); @@ -890,6 +1102,7 @@ Boards.mutations({ [`members.${memberIndex}.isAdmin`]: isAdmin, [`members.${memberIndex}.isNoComments`]: isNoComments, [`members.${memberIndex}.isCommentOnly`]: isCommentOnly, + [`members.${memberIndex}.isWorker`]: isWorker, }, }; }, @@ -898,6 +1111,66 @@ Boards.mutations({ return { $set: { allowsSubtasks } }; }, + setAllowsMembers(allowsMembers) { + return { $set: { allowsMembers } }; + }, + + setAllowsChecklists(allowsChecklists) { + return { $set: { allowsChecklists } }; + }, + + setAllowsAssignee(allowsAssignee) { + return { $set: { allowsAssignee } }; + }, + + setAllowsAssignedBy(allowsAssignedBy) { + return { $set: { allowsAssignedBy } }; + }, + + setAllowsRequestedBy(allowsRequestedBy) { + return { $set: { allowsRequestedBy } }; + }, + + setAllowsAttachments(allowsAttachments) { + return { $set: { allowsAttachments } }; + }, + + setAllowsLabels(allowsLabels) { + return { $set: { allowsLabels } }; + }, + + setAllowsComments(allowsComments) { + return { $set: { allowsComments } }; + }, + + setAllowsDescriptionTitle(allowsDescriptionTitle) { + return { $set: { allowsDescriptionTitle } }; + }, + + setAllowsDescriptionText(allowsDescriptionText) { + return { $set: { allowsDescriptionText } }; + }, + + setAllowsActivities(allowsActivities) { + return { $set: { allowsActivities } }; + }, + + setAllowsReceivedDate(allowsReceivedDate) { + return { $set: { allowsReceivedDate } }; + }, + + setAllowsStartDate(allowsStartDate) { + return { $set: { allowsStartDate } }; + }, + + setAllowsEndDate(allowsEndDate) { + return { $set: { allowsEndDate } }; + }, + + setAllowsDueDate(allowsDueDate) { + return { $set: { allowsDueDate } }; + }, + setSubtasksDefaultBoardId(subtasksDefaultBoardId) { return { $set: { subtasksDefaultBoardId } }; }, @@ -1277,6 +1550,7 @@ if (Meteor.isServer) { * @param {boolean} [isActive] is the board active (default true) * @param {boolean} [isNoComments] disable comments (default false) * @param {boolean} [isCommentOnly] only enable comments (default false) + * @param {boolean} [isWorker] only move cards, assign himself to card and comment (default false) * @param {string} [permission] "private" board <== Set to "public" if you * want public Wekan board * @param {string} [color] the color of the board @@ -1296,6 +1570,7 @@ if (Meteor.isServer) { isActive: req.body.isActive || true, isNoComments: req.body.isNoComments || false, isCommentOnly: req.body.isCommentOnly || false, + isWorker: req.body.isWorker || false, }, ], permission: req.body.permission || 'private', @@ -1399,6 +1674,7 @@ if (Meteor.isServer) { * @param {boolean} isAdmin admin capability * @param {boolean} isNoComments NoComments capability * @param {boolean} isCommentOnly CommentsOnly capability + * @param {boolean} isWorker Worker capability */ JsonRoutes.add('POST', '/api/boards/:boardId/members/:memberId', function( req, @@ -1407,7 +1683,7 @@ if (Meteor.isServer) { try { const boardId = req.params.boardId; const memberId = req.params.memberId; - const { isAdmin, isNoComments, isCommentOnly } = req.body; + const { isAdmin, isNoComments, isCommentOnly, isWorker } = req.body; Authentication.checkBoardAccess(req.userId, boardId); const board = Boards.findOne({ _id: boardId }); function isTrue(data) { @@ -1422,6 +1698,7 @@ if (Meteor.isServer) { isTrue(isAdmin), isTrue(isNoComments), isTrue(isCommentOnly), + isTrue(isWorker), req.userId, ); diff --git a/models/cards.js b/models/cards.js index 86d22c53..fac8922c 100644 --- a/models/cards.js +++ b/models/cards.js @@ -205,7 +205,8 @@ Cards.attachSchema( }, assignees: { /** - * who assignees of the card (user IDs) + * who is assignee of the card (user ID), + * maximum one ID of assignee in array. */ type: [String], optional: true, @@ -1996,15 +1997,22 @@ if (Meteor.isServer) { * @param {string} description the description of the new card * @param {string} swimlaneId the swimlane ID of the new card * @param {string} [members] the member IDs list of the new card - * @param {string} [assignees] the assignee IDs list of the new card + * @param {string} [assignees] the array of maximum one ID of assignee of the new card * @return_type {_id: string} */ JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', function( req, res, ) { - Authentication.checkUserId(req.userId); + // Check user is logged in + Authentication.checkLoggedIn(req.userId); const paramBoardId = req.params.boardId; + // Check user has permission to add card to the board + const board = Boards.findOne({ + _id: paramBoardId, + }); + const addPermission = allowIsBoardMemberCommentOnly(req.userId, board); + Authentication.checkAdminOrCondition(req.userId, addPermission); const paramListId = req.params.listId; const paramParentId = req.params.parentId; const currentCards = Cards.find( @@ -2082,7 +2090,7 @@ if (Meteor.isServer) { * @param {string} [labelIds] the new list of label IDs attached to the card * @param {string} [swimlaneId] the new swimlane ID of the card * @param {string} [members] the new list of member IDs attached to the card - * @param {string} [assignees] the new list of assignee IDs attached to the card + * @param {string} [assignees] the array of maximum one ID of assignee attached to the card * @param {string} [requestedBy] the new requestedBy field of the card * @param {string} [assignedBy] the new assignedBy field of the card * @param {string} [receivedAt] the new receivedAt field of the card diff --git a/models/checklists.js b/models/checklists.js index 3b50cda6..cf73e500 100644 --- a/models/checklists.js +++ b/models/checklists.js @@ -283,8 +283,15 @@ if (Meteor.isServer) { 'POST', '/api/boards/:boardId/cards/:cardId/checklists', function(req, res) { - Authentication.checkUserId(req.userId); - + // Check user is logged in + Authentication.checkLoggedIn(req.userId); + const paramBoardId = req.params.boardId; + // Check user has permission to add checklist to the card + const board = Boards.findOne({ + _id: paramBoardId, + }); + const addPermission = allowIsBoardMemberCommentOnly(req.userId, board); + Authentication.checkAdminOrCondition(req.userId, addPermission); const paramCardId = req.params.cardId; const id = Checklists.insert({ title: req.body.title, diff --git a/models/export.js b/models/export.js index c93a8bda..35e55804 100644 --- a/models/export.js +++ b/models/export.js @@ -24,7 +24,6 @@ if (Meteor.isServer) { JsonRoutes.add('get', '/api/boards/:boardId/export', function(req, res) { const boardId = req.params.boardId; let user = null; - const loginToken = req.query.authToken; if (loginToken) { const hashToken = Accounts._hashLoginToken(loginToken); @@ -35,7 +34,6 @@ if (Meteor.isServer) { Authentication.checkUserId(req.userId); user = Users.findOne({ _id: req.userId, isAdmin: true }); } - const exporter = new Exporter(boardId); if (exporter.canExport(user)) { JsonRoutes.sendResult(res, { @@ -137,8 +135,11 @@ export class Exporter { // [Old] for attachments we only export IDs and absolute url to original doc // [New] Encode attachment to base64 + const getBase64Data = function(doc, callback) { - let buffer = new Buffer(0); + let buffer = Buffer.allocUnsafe(0); + buffer.fill(0); + // callback has the form function (err, res) {} const tmpFile = path.join( os.tmpdir(), @@ -149,14 +150,16 @@ export class Exporter { readStream.on('data', function(chunk) { buffer = Buffer.concat([buffer, chunk]); }); + readStream.on('error', function(err) { - callback(err, null); + callback(null, null); }); readStream.on('end', function() { // done fs.unlink(tmpFile, () => { //ignored }); + callback(null, buffer.toString('base64')); }); readStream.pipe(tmpWriteable); @@ -165,11 +168,14 @@ export class Exporter { result.attachments = Attachments.find({ 'meta.boardId': byBoard.boardId }) .fetch() .map(attachment => { + let filebase64 = null; + filebase64 = getBase64DataSync(attachment); + return { _id: attachment._id, cardId: attachment.cardId, - // url: FlowRouter.url(attachment.url()), - file: getBase64DataSync(attachment), + //url: FlowRouter.url(attachment.url()), + file: filebase64, name: attachment.original.name, type: attachment.original.type, }; diff --git a/models/settings.js b/models/settings.js index 8eb02c5b..63bcd7f3 100644 --- a/models/settings.js +++ b/models/settings.js @@ -33,14 +33,6 @@ Settings.attachSchema( type: String, optional: true, }, - customHTMLafterBodyStart: { - type: String, - optional: true, - }, - customHTMLbeforeBodyEnd: { - type: String, - optional: true, - }, displayAuthenticationMethod: { type: Boolean, optional: true, diff --git a/models/swimlanes.js b/models/swimlanes.js index 831f1eff..aa7016f7 100644 --- a/models/swimlanes.js +++ b/models/swimlanes.js @@ -174,8 +174,12 @@ Swimlanes.helpers({ }, lists() { - const enabled = Meteor.user().hasSortBy(); - return enabled ? this.newestLists() : this.draggableLists(); + //currentUser = Meteor.user(); + //if (currentUser) { + // enabled = Meteor.user().hasSortBy(); + //} + //return enabled ? this.newestLists() : this.draggableLists(); + return this.draggableLists(); }, newestLists() { // sorted lists from newest to the oldest, by its creation date or its cards' last modification date diff --git a/models/users.js b/models/users.js index 83a224ba..7e23835c 100644 --- a/models/users.js +++ b/models/users.js @@ -352,6 +352,16 @@ if (Meteor.isClient) { return board && board.hasCommentOnly(this._id); }, + isNotWorker() { + const board = Boards.findOne(Session.get('currentBoard')); + return board && board.hasMember(this._id) && !board.hasWorker(this._id); + }, + + isWorker() { + const board = Boards.findOne(Session.get('currentBoard')); + return board && board.hasWorker(this._id); + }, + isBoardAdmin() { const board = Boards.findOne(Session.get('currentBoard')); return board && board.hasAdmin(this._id); diff --git a/models/wekanCreator.js b/models/wekanCreator.js index 175c156d..c5591a0b 100644 --- a/models/wekanCreator.js +++ b/models/wekanCreator.js @@ -443,7 +443,7 @@ export class WekanCreator { } else if (att.file) { // FIXME: Change to new file library file.attachData( - new Buffer(att.file, 'base64'), + Buffer.from(att.file, 'base64'), { type: att.type, }, |