From d9c0825d5ff8cf3c6985545640148ce1c0f4262b Mon Sep 17 00:00:00 2001 From: huneau romain Date: Wed, 10 May 2017 15:59:06 +0200 Subject: add rest api for checklist and card comment --- models/cardComments.js | 58 ++++++++++++++++++++++++++++++ models/checklists.js | 96 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 139 insertions(+), 15 deletions(-) diff --git a/models/cardComments.js b/models/cardComments.js index 070c148e..64af4433 100644 --- a/models/cardComments.js +++ b/models/cardComments.js @@ -80,3 +80,61 @@ if (Meteor.isServer) { } }); } + +//CARD COMMENT REST API +if (Meteor.isServer) { + JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/comments', function (req, res, next) { + const paramBoardId = req.params.boardId; + const paramCardId = req.params.cardId; + JsonRoutes.sendResult(res, { + code: 200, + data: CardComments.find({ boardId: paramBoardId, cardId: paramCardId}).map(function (doc) { + return { + _id: doc._id, + comment: doc.text, + authorId: doc.userId, + }; + }), + }); + }); + + JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/comments/:commentId', function (req, res, next) { + const paramBoardId = req.params.boardId; + const paramCommentId = req.params.commentId; + const paramCardId = req.params.cardId; + JsonRoutes.sendResult(res, { + code: 200, + data: CardComments.findOne({ _id: paramCommentId, cardId: paramCardId, boardId: paramBoardId }), + }); + }); + + JsonRoutes.add('POST', '/api/boards/:boardId/cards/:cardId/comments', function (req, res, next) { + const paramBoardId = req.params.boardId; + const paramCardId = req.params.cardId; + const id = CardComments.insert({ + userId: req.body.authorId, + text: req.body.comment, + cardId: paramCardId, + boardId: paramBoardId, + }); + JsonRoutes.sendResult(res, { + code: 200, + data: { + _id: id, + }, + }); + }); + + JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/comments/:commentId', function (req, res, next) { + const paramBoardId = req.params.boardId; + const paramCommentId = req.params.commentId; + const paramCardId = req.params.cardId; + CardComments.remove({ _id: paramCommentId, cardId: paramCardId, boardId: paramBoardId }); + JsonRoutes.sendResult(res, { + code: 200, + data: { + _id: paramCardId, + }, + }); + }); +} diff --git a/models/checklists.js b/models/checklists.js index 3425f230..4bb580c3 100644 --- a/models/checklists.js +++ b/models/checklists.js @@ -28,22 +28,29 @@ Checklists.attachSchema(new SimpleSchema({ createdAt: { type: Date, denyUpdate: false, + autoValue() { // eslint-disable-line consistent-return + if (this.isInsert) { + return new Date(); + } else { + this.unset(); + } + }, }, })); Checklists.helpers({ - itemCount () { + itemCount() { return this.items.length; }, - finishedCount () { + finishedCount() { return this.items.filter((item) => { return item.isFinished; }).length; }, - isFinished () { + isFinished() { return 0 !== this.itemCount() && this.itemCount() === this.finishedCount(); }, - getItem (_id) { + getItem(_id) { return _.findWhere(this.items, { _id }); }, itemIndex(itemId) { @@ -73,17 +80,17 @@ Checklists.before.insert((userId, doc) => { Checklists.mutations({ //for checklist itself - setTitle(title){ - return { $set: { title }}; + setTitle(title) { + return { $set: { title } }; }, //for items in checklist addItem(title) { const itemCount = this.itemCount(); const _id = `${this._id}${itemCount}`; - return { $addToSet: {items: {_id, title, isFinished: false}} }; + return { $addToSet: { items: { _id, title, isFinished: false } } }; }, removeItem(itemId) { - return {$pull: {items: {_id : itemId}}}; + return { $pull: { items: { _id: itemId } } }; }, editItem(itemId, title) { if (this.getItem(itemId)) { @@ -150,13 +157,13 @@ if (Meteor.isServer) { //TODO: so there will be no activity for adding item into checklist, maybe will be implemented in the future. // Checklists.after.update((userId, doc) => { // console.log('update:', doc) - // Activities.insert({ - // userId, - // activityType: 'addChecklist', - // boardId: doc.boardId, - // cardId: doc.cardId, - // checklistId: doc._id, - // }); + // Activities.insert({ + // userId, + // activityType: 'addChecklist', + // boardId: doc.boardId, + // cardId: doc.cardId, + // checklistId: doc._id, + // }); // }); Checklists.before.remove((userId, doc) => { @@ -166,3 +173,62 @@ if (Meteor.isServer) { } }); } + +//CARD COMMENT REST API +if (Meteor.isServer) { + JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists', function (req, res, next) { + const paramCardId = req.params.cardId; + JsonRoutes.sendResult(res, { + code: 200, + data: Checklists.find({ cardId: paramCardId }).map(function (doc) { + return { + _id: doc._id, + title: doc.title, + }; + }), + }); + }); + + JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId', function (req, res, next) { + const paramChecklistId = req.params.checklistId; + const paramCardId = req.params.cardId; + JsonRoutes.sendResult(res, { + code: 200, + data: Checklists.findOne({ _id: paramChecklistId, cardId: paramCardId }), + }); + }); + + JsonRoutes.add('POST', '/api/boards/:boardId/cards/:cardId/checklists', function (req, res, next) { + const paramCardId = req.params.cardId; + + const checklistToSend = {}; + checklistToSend.cardId = paramCardId; + checklistToSend.title = req.body.title; + checklistToSend.items = []; + const id = Checklists.insert(checklistToSend); + const checklist = Checklists.findOne({_id: id}); + req.body.items.forEach(function (item) { + checklist.addItem(item); + }, this); + + + JsonRoutes.sendResult(res, { + code: 200, + data: { + _id: id, + }, + }); + }); + + JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId', function (req, res, next) { + const paramCommentId = req.params.commentId; + const paramCardId = req.params.cardId; + Checklists.remove({ _id: paramCommentId, cardId: paramCardId }); + JsonRoutes.sendResult(res, { + code: 200, + data: { + _id: paramCardId, + }, + }); + }); +} -- cgit v1.2.3-1-g7c22 From 548172949aaaea054f203d5fdc3286c90c5ae8e1 Mon Sep 17 00:00:00 2001 From: huneau romain Date: Wed, 10 May 2017 16:00:08 +0200 Subject: replace console.log by winston logger --- server/logger.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/server/logger.js b/server/logger.js index 376e30aa..70caa292 100644 --- a/server/logger.js +++ b/server/logger.js @@ -3,22 +3,21 @@ Meteor.startup(() => { require('winston-zulip'); const fs = require('fs'); - //remove default logger - Winston.remove(Winston.transports.Console); - - const loggerEnable = process.env.LOGGER_ENABLE || false; - console.log('here1'); - console.log(loggerEnable); if (loggerEnable) { - console.log('here2'); + + Winston.log('info', 'logger is enable'); const loggers = process.env.LOGGERS.split(',') || 'console'; + Winston.log('info', `Loggers selected : ${ process.env.LOGGERS }, if empty default is console`); if (loggers.includes('console')) { Winston.add(Winston.transports.Console, { json: true, timestamp: true, }); + } else { + //remove default logger + Winston.remove(Winston.transports.Console); } if (loggers.includes('file')) { @@ -45,15 +44,23 @@ Meteor.startup(() => { const loggerZulipTo = process.env.LOGGER_ZULIP_TO || 'logs'; const loggerZulipSubject = process.env.LOGGER_ZULIP_SUBJECT || 'wekan'; - Winston.add(Winston.transports.Zulip, { + const zulipConfig = { zulipUsername: loggerZulipUsername, zulipApikey: loggerZulipApikey, zulipRealm: loggerZulipRealm, zulipTo: loggerZulipTo, zulipSubject: loggerZulipSubject, - }); + }; + + Winston.add(Winston.transports.Zulip, zulipConfig); + + Winston.log('info', `zulipconfig ${zulipConfig}`); } + } else { + //remove default logger + Winston.remove(Winston.transports.Console); } + Winston.log('info', 'Logger is completly instanciate'); }); -- cgit v1.2.3-1-g7c22 From b5271e5346cde2563d36c64a300729e27336a86b Mon Sep 17 00:00:00 2001 From: huneau romain Date: Thu, 11 May 2017 12:15:02 +0200 Subject: add token authentication, only admin can use api --- .meteor/packages | 1 + .meteor/versions | 4 ++++ models/boards.js | 4 ++++ models/cardComments.js | 4 ++++ models/cards.js | 4 ++++ models/checklists.js | 4 ++++ models/lists.js | 4 ++++ models/users.js | 4 ++++ server/authentication.js | 21 +++++++++++++++++++++ 9 files changed, 50 insertions(+) create mode 100644 server/authentication.js diff --git a/.meteor/packages b/.meteor/packages index 67678ccb..f5fce1f6 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -77,3 +77,4 @@ simple:json-routes rajit:bootstrap3-datepicker kadira:flow-router shell-server@0.2.3 +simple:rest-accounts-password diff --git a/.meteor/versions b/.meteor/versions index 1a040534..4c1fccf4 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -134,7 +134,11 @@ service-configuration@1.0.11 session@1.1.7 sha@1.0.9 shell-server@0.2.3 +simple:authenticate-user-by-token@1.0.1 simple:json-routes@2.1.0 +simple:rest-accounts-password@1.1.2 +simple:rest-bearer-token-parser@1.0.1 +simple:rest-json-error-handler@1.0.1 softwarerero:accounts-t9n@1.3.9 spacebars@1.0.15 spacebars-compiler@1.1.2 diff --git a/models/boards.js b/models/boards.js index 9cbb5b63..879dde84 100644 --- a/models/boards.js +++ b/models/boards.js @@ -557,6 +557,7 @@ if (Meteor.isServer) { //BOARDS REST API if (Meteor.isServer) { JsonRoutes.add('GET', '/api/boards', function (req, res, next) { + Authentication.checkUserId(req.userId); JsonRoutes.sendResult(res, { code: 200, data: Boards.find({ permission: 'public' }).map(function (doc) { @@ -569,6 +570,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('GET', '/api/boards/:id', function (req, res, next) { + Authentication.checkUserId( req.userId); const id = req.params.id; JsonRoutes.sendResult(res, { code: 200, @@ -577,6 +579,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('POST', '/api/boards', function (req, res, next) { + Authentication.checkUserId( req.userId); const id = Boards.insert({ title: req.body.title, members: [ @@ -599,6 +602,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('DELETE', '/api/boards/:id', function (req, res, next) { + Authentication.checkUserId( req.userId); const id = req.params.id; Boards.remove({ _id: id }); JsonRoutes.sendResult(res, { diff --git a/models/cardComments.js b/models/cardComments.js index 64af4433..e51275a4 100644 --- a/models/cardComments.js +++ b/models/cardComments.js @@ -84,6 +84,7 @@ if (Meteor.isServer) { //CARD COMMENT REST API if (Meteor.isServer) { JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/comments', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramCardId = req.params.cardId; JsonRoutes.sendResult(res, { @@ -99,6 +100,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/comments/:commentId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramCommentId = req.params.commentId; const paramCardId = req.params.cardId; @@ -109,6 +111,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('POST', '/api/boards/:boardId/cards/:cardId/comments', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramCardId = req.params.cardId; const id = CardComments.insert({ @@ -126,6 +129,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/comments/:commentId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramCommentId = req.params.commentId; const paramCardId = req.params.cardId; diff --git a/models/cards.js b/models/cards.js index 2d585825..bbe46b55 100644 --- a/models/cards.js +++ b/models/cards.js @@ -373,6 +373,7 @@ if (Meteor.isServer) { //LISTS REST API if (Meteor.isServer) { JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramListId = req.params.listId; JsonRoutes.sendResult(res, { @@ -388,6 +389,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramListId = req.params.listId; const paramCardId = req.params.cardId; @@ -398,6 +400,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('POST', '/api/boards/:boardId/lists/:listId/cards', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramListId = req.params.listId; const id = Cards.insert({ @@ -418,6 +421,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('DELETE', '/api/boards/:boardId/lists/:listId/cards/:cardId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramListId = req.params.listId; const paramCardId = req.params.cardId; diff --git a/models/checklists.js b/models/checklists.js index 4bb580c3..537aecb0 100644 --- a/models/checklists.js +++ b/models/checklists.js @@ -177,6 +177,7 @@ if (Meteor.isServer) { //CARD COMMENT REST API if (Meteor.isServer) { JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramCardId = req.params.cardId; JsonRoutes.sendResult(res, { code: 200, @@ -190,6 +191,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('GET', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramChecklistId = req.params.checklistId; const paramCardId = req.params.cardId; JsonRoutes.sendResult(res, { @@ -199,6 +201,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('POST', '/api/boards/:boardId/cards/:cardId/checklists', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramCardId = req.params.cardId; const checklistToSend = {}; @@ -221,6 +224,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('DELETE', '/api/boards/:boardId/cards/:cardId/checklists/:checklistId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramCommentId = req.params.commentId; const paramCardId = req.params.cardId; Checklists.remove({ _id: paramCommentId, cardId: paramCardId }); diff --git a/models/lists.js b/models/lists.js index a10e23b6..7dbdc9f2 100644 --- a/models/lists.js +++ b/models/lists.js @@ -132,6 +132,7 @@ if (Meteor.isServer) { //LISTS REST API if (Meteor.isServer) { JsonRoutes.add('GET', '/api/boards/:boardId/lists', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; JsonRoutes.sendResult(res, { code: 200, @@ -145,6 +146,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('GET', '/api/boards/:boardId/lists/:listId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramListId = req.params.listId; JsonRoutes.sendResult(res, { @@ -154,6 +156,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('POST', '/api/boards/:boardId/lists', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const id = Lists.insert({ title: req.body.title, @@ -168,6 +171,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('DELETE', '/api/boards/:boardId/lists/:listId', function (req, res, next) { + Authentication.checkUserId( req.userId); const paramBoardId = req.params.boardId; const paramListId = req.params.listId; Lists.remove({ _id: paramListId, boardId: paramBoardId }); diff --git a/models/users.js b/models/users.js index c1ce146a..aa870dca 100644 --- a/models/users.js +++ b/models/users.js @@ -528,6 +528,7 @@ if (Meteor.isServer) { // USERS REST API if (Meteor.isServer) { JsonRoutes.add('GET', '/api/users', function (req, res, next) { + Authentication.checkUserId( req.userId); JsonRoutes.sendResult(res, { code: 200, data: Meteor.users.find({}).map(function (doc) { @@ -536,6 +537,7 @@ if (Meteor.isServer) { }); }); JsonRoutes.add('GET', '/api/users/:id', function (req, res, next) { + Authentication.checkUserId( req.userId); const id = req.params.id; JsonRoutes.sendResult(res, { code: 200, @@ -543,6 +545,7 @@ if (Meteor.isServer) { }); }); JsonRoutes.add('POST', '/api/users/', function (req, res, next) { + Authentication.checkUserId( req.userId); const id = Accounts.createUser({ username: req.body.username, email: req.body.email, @@ -558,6 +561,7 @@ if (Meteor.isServer) { }); JsonRoutes.add('DELETE', '/api/users/:id', function (req, res, next) { + Authentication.checkUserId( req.userId); const id = req.params.id; Meteor.users.remove({ _id: id }); JsonRoutes.sendResult(res, { diff --git a/server/authentication.js b/server/authentication.js new file mode 100644 index 00000000..816c4d4c --- /dev/null +++ b/server/authentication.js @@ -0,0 +1,21 @@ +Meteor.startup(() => { + Authentication = {}; + + Authentication.checkUserId = function (userId) { + if (userId === undefined) { + const error = new Meteor.Error('Unauthorized', 'Unauthorized'); + error.statusCode = 401; + throw error; + } + const admin = Users.findOne({ _id: userId, isAdmin: true }); + + if (admin === undefined) { + const error = new Meteor.Error('Forbidden', 'Forbidden'); + error.statusCode = 403; + throw error; + } + + }; + +}); + -- cgit v1.2.3-1-g7c22 From c0ddc89f21b6370ea58eee68c5c3696861b3e8f2 Mon Sep 17 00:00:00 2001 From: huneau romain Date: Thu, 11 May 2017 12:30:30 +0200 Subject: add Autentication to global var --- .eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 7aa16f4d..5fa05a38 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -126,6 +126,7 @@ "Settings": true, "InvitationCodes": true, "Winston":true, - "JsonRoutes": true + "JsonRoutes": true, + "Authentication": true } } -- cgit v1.2.3-1-g7c22