Integrations = new Mongo.Collection('integrations'); /** * Integration with third-party applications */ Integrations.attachSchema( new SimpleSchema({ enabled: { /** * is the integration enabled? */ type: Boolean, defaultValue: true, }, title: { /** * name of the integration */ type: String, optional: true, }, type: { /** * type of the integratation (Default to 'outgoing-webhooks') */ type: String, defaultValue: 'outgoing-webhooks', }, activities: { /** * activities the integration gets triggered (list) */ type: [String], defaultValue: ['all'], }, url: { // URL validation regex (https://mathiasbynens.be/demo/url-regex) /** * URL validation regex (https://mathiasbynens.be/demo/url-regex) */ type: String, }, token: { /** * token of the integration */ type: String, optional: true, }, boardId: { /** * Board ID of the integration */ type: String, }, createdAt: { /** * Creation date of the integration */ type: Date, denyUpdate: false, // eslint-disable-next-line consistent-return autoValue() { if (this.isInsert) { return new Date(); } else if (this.isUpsert) { return { $setOnInsert: new Date() }; } else { this.unset(); } }, }, modifiedAt: { type: Date, denyUpdate: false, // eslint-disable-next-line consistent-return autoValue() { if (this.isInsert || this.isUpsert || this.isUpdate) { return new Date(); } else { this.unset(); } }, }, userId: { /** * user ID who created the interation */ type: String, }, }), ); Integrations.Const = { GLOBAL_WEBHOOK_ID: '_global', ONEWAY: 'outgoing-webhooks', TWOWAY: 'bidirectional-webhooks', get WEBHOOK_TYPES() { return [this.ONEWAY, this.TWOWAY]; }, }; const permissionHelper = { allow(userId, doc) { const user = Users.findOne(userId); const isAdmin = user && Meteor.user().isAdmin; return isAdmin || allowIsBoardAdmin(userId, Boards.findOne(doc.boardId)); }, }; Integrations.allow({ insert(userId, doc) { return permissionHelper.allow(userId, doc); }, update(userId, doc) { return permissionHelper.allow(userId, doc); }, remove(userId, doc) { return permissionHelper.allow(userId, doc); }, fetch: ['boardId'], }); //INTEGRATIONS REST API if (Meteor.isServer) { Meteor.startup(() => { Integrations._collection._ensureIndex({ modifiedAt: -1 }); Integrations._collection._ensureIndex({ boardId: 1 }); }); /** * @operation get_all_integrations * @summary Get all integrations in board * * @param {string} boardId the board ID * @return_type [Integrations] */ JsonRoutes.add('GET', '/api/boards/:boardId/integrations', function( req, res, ) { try { const paramBoardId = req.params.boardId; Authentication.checkBoardAccess(req.userId, paramBoardId); const data = Integrations.find( { boardId: paramBoardId }, { fields: { token: 0 } }, ).map(function(doc) { return doc; }); JsonRoutes.sendResult(res, { code: 200, data }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }); /** * @operation get_integration * @summary Get a single integration in board * * @param {string} boardId the board ID * @param {string} intId the integration ID * @return_type Integrations */ JsonRoutes.add('GET', '/api/boards/:boardId/integrations/:intId', function( req, res, ) { try { const paramBoardId = req.params.boardId; const paramIntId = req.params.intId; Authentication.checkBoardAccess(req.userId, paramBoardId); JsonRoutes.sendResult(res, { code: 200, data: Integrations.findOne( { _id: paramIntId, boardId: paramBoardId }, { fields: { token: 0 } }, ), }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }); /** * @operation new_integration * @summary Create a new integration * * @param {string} boardId the board ID * @param {string} url the URL of the integration * @return_type {_id: string} */ JsonRoutes.add('POST', '/api/boards/:boardId/integrations', function( req, res, ) { try { const paramBoardId = req.params.boardId; Authentication.checkBoardAccess(req.userId, paramBoardId); const id = Integrations.insert({ userId: req.userId, boardId: paramBoardId, url: req.body.url, }); JsonRoutes.sendResult(res, { code: 200, data: { _id: id, }, }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }); /** * @operation edit_integration * @summary Edit integration data * * @param {string} boardId the board ID * @param {string} intId the integration ID * @param {string} [enabled] is the integration enabled? * @param {string} [title] new name of the integration * @param {string} [url] new URL of the integration * @param {string} [token] new token of the integration * @param {string} [activities] new list of activities of the integration * @return_type {_id: string} */ JsonRoutes.add('PUT', '/api/boards/:boardId/integrations/:intId', function( req, res, ) { try { const paramBoardId = req.params.boardId; const paramIntId = req.params.intId; Authentication.checkBoardAccess(req.userId, paramBoardId); if (req.body.hasOwnProperty('enabled')) { const newEnabled = req.body.enabled; Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $set: { enabled: newEnabled } }, ); } if (req.body.hasOwnProperty('title')) { const newTitle = req.body.title; Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $set: { title: newTitle } }, ); } if (req.body.hasOwnProperty('url')) { const newUrl = req.body.url; Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $set: { url: newUrl } }, ); } if (req.body.hasOwnProperty('token')) { const newToken = req.body.token; Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $set: { token: newToken } }, ); } if (req.body.hasOwnProperty('activities')) { const newActivities = req.body.activities; Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $set: { activities: newActivities } }, ); } JsonRoutes.sendResult(res, { code: 200, data: { _id: paramIntId, }, }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }); /** * @operation delete_integration_activities * @summary Delete subscribed activities * * @param {string} boardId the board ID * @param {string} intId the integration ID * @param {string} newActivities the activities to remove from the integration * @return_type Integrations */ JsonRoutes.add( 'DELETE', '/api/boards/:boardId/integrations/:intId/activities', function(req, res) { try { const paramBoardId = req.params.boardId; const paramIntId = req.params.intId; const newActivities = req.body.activities; Authentication.checkBoardAccess(req.userId, paramBoardId); Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $pullAll: { activities: newActivities } }, ); JsonRoutes.sendResult(res, { code: 200, data: Integrations.findOne( { _id: paramIntId, boardId: paramBoardId }, { fields: { _id: 1, activities: 1 } }, ), }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }, ); /** * @operation new_integration_activities * @summary Add subscribed activities * * @param {string} boardId the board ID * @param {string} intId the integration ID * @param {string} newActivities the activities to add to the integration * @return_type Integrations */ JsonRoutes.add( 'POST', '/api/boards/:boardId/integrations/:intId/activities', function(req, res) { try { const paramBoardId = req.params.boardId; const paramIntId = req.params.intId; const newActivities = req.body.activities; Authentication.checkBoardAccess(req.userId, paramBoardId); Integrations.direct.update( { _id: paramIntId, boardId: paramBoardId }, { $addToSet: { activities: { $each: newActivities } } }, ); JsonRoutes.sendResult(res, { code: 200, data: Integrations.findOne( { _id: paramIntId, boardId: paramBoardId }, { fields: { _id: 1, activities: 1 } }, ), }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }, ); /** * @operation delete_integration * @summary Delete integration * * @param {string} boardId the board ID * @param {string} intId the integration ID * @return_type {_id: string} */ JsonRoutes.add('DELETE', '/api/boards/:boardId/integrations/:intId', function( req, res, ) { try { const paramBoardId = req.params.boardId; const paramIntId = req.params.intId; Authentication.checkBoardAccess(req.userId, paramBoardId); Integrations.direct.remove({ _id: paramIntId, boardId: paramBoardId }); JsonRoutes.sendResult(res, { code: 200, data: { _id: paramIntId, }, }); } catch (error) { JsonRoutes.sendResult(res, { code: 200, data: error, }); } }); } export default Integrations;