Browse Source

Merge branch 'huneau-meteor-1.4-RESTAPI' into devel

Lauri Ojansivu 8 years ago
parent
commit
1c3551201a
11 changed files with 207 additions and 25 deletions
  1. 2 1
      .eslintrc.json
  2. 1 0
      .meteor/packages
  3. 4 0
      .meteor/versions
  4. 4 0
      models/boards.js
  5. 62 0
      models/cardComments.js
  6. 4 0
      models/cards.js
  7. 85 15
      models/checklists.js
  8. 4 0
      models/lists.js
  9. 4 0
      models/users.js
  10. 21 0
      server/authentication.js
  11. 16 9
      server/logger.js

+ 2 - 1
.eslintrc.json

@@ -126,6 +126,7 @@
     "Settings": true,
     "InvitationCodes": true,
     "Winston":true,
-    "JsonRoutes": true
+    "JsonRoutes": true,
+    "Authentication": true
   }
 }

+ 1 - 0
.meteor/packages

@@ -77,3 +77,4 @@ simple:json-routes
 rajit:bootstrap3-datepicker
 kadira:flow-router
 shell-server@0.2.3
+simple:rest-accounts-password

+ 4 - 0
.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

+ 4 - 0
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, {

+ 62 - 0
models/cardComments.js

@@ -80,3 +80,65 @@ 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, {
+      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) {
+    Authentication.checkUserId( req.userId);
+    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) {
+    Authentication.checkUserId( req.userId);
+    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) {
+    Authentication.checkUserId( req.userId);
+    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,
+      },
+    });
+  });
+}

+ 4 - 0
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;

+ 85 - 15
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,66 @@ 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,
+      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) {
+    Authentication.checkUserId( req.userId);
+    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) {
+    Authentication.checkUserId( req.userId);
+    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) {
+    Authentication.checkUserId( req.userId);
+    const paramCommentId = req.params.commentId;
+    const paramCardId = req.params.cardId;
+    Checklists.remove({ _id: paramCommentId, cardId: paramCardId });
+    JsonRoutes.sendResult(res, {
+      code: 200,
+      data: {
+        _id: paramCardId,
+      },
+    });
+  });
+}

+ 4 - 0
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 });

+ 4 - 0
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, {

+ 21 - 0
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;
+    }
+
+  };
+
+});
+

+ 16 - 9
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');
 });