|
|
|
|
@ -1,10 +1,19 @@ |
|
|
|
|
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
|
|
|
|
|
@ -24,6 +33,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
archived: { |
|
|
|
|
/** |
|
|
|
|
* Is the board archived? |
|
|
|
|
*/ |
|
|
|
|
type: Boolean, |
|
|
|
|
autoValue() { // eslint-disable-line consistent-return
|
|
|
|
|
if (this.isInsert && !this.isSet) { |
|
|
|
|
@ -32,6 +44,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
createdAt: { |
|
|
|
|
/** |
|
|
|
|
* Creation time of the board |
|
|
|
|
*/ |
|
|
|
|
type: Date, |
|
|
|
|
autoValue() { // eslint-disable-line consistent-return
|
|
|
|
|
if (this.isInsert) { |
|
|
|
|
@ -43,6 +58,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
// XXX Inconsistent field naming
|
|
|
|
|
modifiedAt: { |
|
|
|
|
/** |
|
|
|
|
* Last modification time of the board |
|
|
|
|
*/ |
|
|
|
|
type: Date, |
|
|
|
|
optional: true, |
|
|
|
|
autoValue() { // eslint-disable-line consistent-return
|
|
|
|
|
@ -55,6 +73,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
// 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) { |
|
|
|
|
@ -64,6 +85,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
// 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) { |
|
|
|
|
@ -78,6 +102,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
'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.
|
|
|
|
|
@ -86,10 +113,22 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
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', |
|
|
|
|
@ -103,6 +142,9 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
// 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) { |
|
|
|
|
@ -117,27 +159,48 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
'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', |
|
|
|
|
@ -154,24 +217,45 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
}, |
|
|
|
|
}, |
|
|
|
|
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', |
|
|
|
|
@ -184,23 +268,38 @@ Boards.attachSchema(new SimpleSchema({ |
|
|
|
|
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, |
|
|
|
|
@ -774,6 +873,14 @@ if (Meteor.isServer) { |
|
|
|
|
|
|
|
|
|
//BOARDS REST API
|
|
|
|
|
if (Meteor.isServer) { |
|
|
|
|
/** |
|
|
|
|
* @operation get_boards_from_user |
|
|
|
|
* @summary Get all boards attached to a user |
|
|
|
|
* |
|
|
|
|
* @param {string} userId the ID of the user to retrieve the data |
|
|
|
|
* @return_type [{_id: string, |
|
|
|
|
title: string}] |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('GET', '/api/users/:userId/boards', function (req, res) { |
|
|
|
|
try { |
|
|
|
|
Authentication.checkLoggedIn(req.userId); |
|
|
|
|
@ -804,6 +911,13 @@ if (Meteor.isServer) { |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @operation get_public_boards |
|
|
|
|
* @summary Get all public boards |
|
|
|
|
* |
|
|
|
|
* @return_type [{_id: string, |
|
|
|
|
title: string}] |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('GET', '/api/boards', function (req, res) { |
|
|
|
|
try { |
|
|
|
|
Authentication.checkUserId(req.userId); |
|
|
|
|
@ -825,6 +939,13 @@ if (Meteor.isServer) { |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @operation get_board |
|
|
|
|
* @summary Get the board with that particular ID |
|
|
|
|
* |
|
|
|
|
* @param {string} boardId the ID of the board to retrieve the data |
|
|
|
|
* @return_type Boards |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('GET', '/api/boards/:boardId', function (req, res) { |
|
|
|
|
try { |
|
|
|
|
const id = req.params.boardId; |
|
|
|
|
@ -843,6 +964,31 @@ if (Meteor.isServer) { |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @operation new_board |
|
|
|
|
* @summary Create a board |
|
|
|
|
* |
|
|
|
|
* @description This allows to create a board. |
|
|
|
|
* |
|
|
|
|
* The color has to be chosen between `belize`, `nephritis`, `pomegranate`, |
|
|
|
|
* `pumpkin`, `wisteria`, `midnight`: |
|
|
|
|
* |
|
|
|
|
* <img src="https://wekan.github.io/board-colors.png" width="40%" alt="Wekan logo" /> |
|
|
|
|
* |
|
|
|
|
* @param {string} title the new title of the board |
|
|
|
|
* @param {string} owner "ABCDE12345" <= User ID in Wekan. |
|
|
|
|
* (Not username or email) |
|
|
|
|
* @param {boolean} [isAdmin] is the owner an admin of the board (default true) |
|
|
|
|
* @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 {string} [permission] "private" board <== Set to "public" if you |
|
|
|
|
* want public Wekan board |
|
|
|
|
* @param {string} [color] the color of the board |
|
|
|
|
* |
|
|
|
|
* @return_type {_id: string, |
|
|
|
|
defaultSwimlaneId: string} |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('POST', '/api/boards', function (req, res) { |
|
|
|
|
try { |
|
|
|
|
Authentication.checkUserId(req.userId); |
|
|
|
|
@ -880,6 +1026,12 @@ if (Meteor.isServer) { |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @operation delete_board |
|
|
|
|
* @summary Delete a board |
|
|
|
|
* |
|
|
|
|
* @param {string} boardId the ID of the board |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('DELETE', '/api/boards/:boardId', function (req, res) { |
|
|
|
|
try { |
|
|
|
|
Authentication.checkUserId(req.userId); |
|
|
|
|
@ -900,6 +1052,19 @@ if (Meteor.isServer) { |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @operation add_board_label |
|
|
|
|
* @summary Add a label to a board |
|
|
|
|
* |
|
|
|
|
* @description If the board doesn't have the name/color label, this function |
|
|
|
|
* adds the label to the board. |
|
|
|
|
* |
|
|
|
|
* @param {string} boardId the board |
|
|
|
|
* @param {string} color the color of the new label |
|
|
|
|
* @param {string} name the name of the new label |
|
|
|
|
* |
|
|
|
|
* @return_type string |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('PUT', '/api/boards/:boardId/labels', function (req, res) { |
|
|
|
|
Authentication.checkUserId(req.userId); |
|
|
|
|
const id = req.params.boardId; |
|
|
|
|
@ -929,6 +1094,17 @@ if (Meteor.isServer) { |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* @operation set_board_member_permission |
|
|
|
|
* @tag Users |
|
|
|
|
* @summary Change the permission of a member of a board |
|
|
|
|
* |
|
|
|
|
* @param {string} boardId the ID of the board that we are changing |
|
|
|
|
* @param {string} memberId the ID of the user to change permissions |
|
|
|
|
* @param {boolean} isAdmin admin capability |
|
|
|
|
* @param {boolean} isNoComments NoComments capability |
|
|
|
|
* @param {boolean} isCommentOnly CommentsOnly capability |
|
|
|
|
*/ |
|
|
|
|
JsonRoutes.add('POST', '/api/boards/:boardId/members/:memberId', function (req, res) { |
|
|
|
|
try { |
|
|
|
|
const boardId = req.params.boardId; |
|
|
|
|
|