integrations.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. Integrations = new Mongo.Collection('integrations');
  2. /**
  3. * Integration with third-party applications
  4. */
  5. Integrations.attachSchema(
  6. new SimpleSchema({
  7. enabled: {
  8. /**
  9. * is the integration enabled?
  10. */
  11. type: Boolean,
  12. defaultValue: true,
  13. },
  14. title: {
  15. /**
  16. * name of the integration
  17. */
  18. type: String,
  19. optional: true,
  20. },
  21. type: {
  22. /**
  23. * type of the integratation (Default to 'outgoing-webhooks')
  24. */
  25. type: String,
  26. defaultValue: 'outgoing-webhooks',
  27. },
  28. activities: {
  29. /**
  30. * activities the integration gets triggered (list)
  31. */
  32. type: [String],
  33. defaultValue: ['all'],
  34. },
  35. url: {
  36. // URL validation regex (https://mathiasbynens.be/demo/url-regex)
  37. /**
  38. * URL validation regex (https://mathiasbynens.be/demo/url-regex)
  39. */
  40. type: String,
  41. },
  42. token: {
  43. /**
  44. * token of the integration
  45. */
  46. type: String,
  47. optional: true,
  48. },
  49. boardId: {
  50. /**
  51. * Board ID of the integration
  52. */
  53. type: String,
  54. },
  55. createdAt: {
  56. /**
  57. * Creation date of the integration
  58. */
  59. type: Date,
  60. denyUpdate: false,
  61. // eslint-disable-next-line consistent-return
  62. autoValue() {
  63. if (this.isInsert) {
  64. return new Date();
  65. } else {
  66. this.unset();
  67. }
  68. },
  69. },
  70. modifiedAt: {
  71. type: Date,
  72. denyUpdate: false,
  73. // eslint-disable-next-line consistent-return
  74. autoValue() {
  75. if (this.isInsert || this.isUpsert || this.isUpdate) {
  76. return new Date();
  77. } else {
  78. this.unset();
  79. }
  80. },
  81. },
  82. userId: {
  83. /**
  84. * user ID who created the interation
  85. */
  86. type: String,
  87. },
  88. })
  89. );
  90. Integrations.before.update((userId, doc, fieldNames, modifier, options) => {
  91. modifier.$set = modifier.$set || {};
  92. modifier.$set.modifiedAt = Date.now();
  93. });
  94. Integrations.allow({
  95. insert(userId, doc) {
  96. return allowIsBoardAdmin(userId, Boards.findOne(doc.boardId));
  97. },
  98. update(userId, doc) {
  99. return allowIsBoardAdmin(userId, Boards.findOne(doc.boardId));
  100. },
  101. remove(userId, doc) {
  102. return allowIsBoardAdmin(userId, Boards.findOne(doc.boardId));
  103. },
  104. fetch: ['boardId'],
  105. });
  106. //INTEGRATIONS REST API
  107. if (Meteor.isServer) {
  108. Meteor.startup(() => {
  109. Integrations._collection._ensureIndex({ modifiedAt: -1 });
  110. Integrations._collection._ensureIndex({ boardId: 1 });
  111. });
  112. /**
  113. * @operation get_all_integrations
  114. * @summary Get all integrations in board
  115. *
  116. * @param {string} boardId the board ID
  117. * @return_type [Integrations]
  118. */
  119. JsonRoutes.add('GET', '/api/boards/:boardId/integrations', function(
  120. req,
  121. res
  122. ) {
  123. try {
  124. const paramBoardId = req.params.boardId;
  125. Authentication.checkBoardAccess(req.userId, paramBoardId);
  126. const data = Integrations.find(
  127. { boardId: paramBoardId },
  128. { fields: { token: 0 } }
  129. ).map(function(doc) {
  130. return doc;
  131. });
  132. JsonRoutes.sendResult(res, { code: 200, data });
  133. } catch (error) {
  134. JsonRoutes.sendResult(res, {
  135. code: 200,
  136. data: error,
  137. });
  138. }
  139. });
  140. /**
  141. * @operation get_integration
  142. * @summary Get a single integration in board
  143. *
  144. * @param {string} boardId the board ID
  145. * @param {string} intId the integration ID
  146. * @return_type Integrations
  147. */
  148. JsonRoutes.add('GET', '/api/boards/:boardId/integrations/:intId', function(
  149. req,
  150. res
  151. ) {
  152. try {
  153. const paramBoardId = req.params.boardId;
  154. const paramIntId = req.params.intId;
  155. Authentication.checkBoardAccess(req.userId, paramBoardId);
  156. JsonRoutes.sendResult(res, {
  157. code: 200,
  158. data: Integrations.findOne(
  159. { _id: paramIntId, boardId: paramBoardId },
  160. { fields: { token: 0 } }
  161. ),
  162. });
  163. } catch (error) {
  164. JsonRoutes.sendResult(res, {
  165. code: 200,
  166. data: error,
  167. });
  168. }
  169. });
  170. /**
  171. * @operation new_integration
  172. * @summary Create a new integration
  173. *
  174. * @param {string} boardId the board ID
  175. * @param {string} url the URL of the integration
  176. * @return_type {_id: string}
  177. */
  178. JsonRoutes.add('POST', '/api/boards/:boardId/integrations', function(
  179. req,
  180. res
  181. ) {
  182. try {
  183. const paramBoardId = req.params.boardId;
  184. Authentication.checkBoardAccess(req.userId, paramBoardId);
  185. const id = Integrations.insert({
  186. userId: req.userId,
  187. boardId: paramBoardId,
  188. url: req.body.url,
  189. });
  190. JsonRoutes.sendResult(res, {
  191. code: 200,
  192. data: {
  193. _id: id,
  194. },
  195. });
  196. } catch (error) {
  197. JsonRoutes.sendResult(res, {
  198. code: 200,
  199. data: error,
  200. });
  201. }
  202. });
  203. /**
  204. * @operation edit_integration
  205. * @summary Edit integration data
  206. *
  207. * @param {string} boardId the board ID
  208. * @param {string} intId the integration ID
  209. * @param {string} [enabled] is the integration enabled?
  210. * @param {string} [title] new name of the integration
  211. * @param {string} [url] new URL of the integration
  212. * @param {string} [token] new token of the integration
  213. * @param {string} [activities] new list of activities of the integration
  214. * @return_type {_id: string}
  215. */
  216. JsonRoutes.add('PUT', '/api/boards/:boardId/integrations/:intId', function(
  217. req,
  218. res
  219. ) {
  220. try {
  221. const paramBoardId = req.params.boardId;
  222. const paramIntId = req.params.intId;
  223. Authentication.checkBoardAccess(req.userId, paramBoardId);
  224. if (req.body.hasOwnProperty('enabled')) {
  225. const newEnabled = req.body.enabled;
  226. Integrations.direct.update(
  227. { _id: paramIntId, boardId: paramBoardId },
  228. { $set: { enabled: newEnabled } }
  229. );
  230. }
  231. if (req.body.hasOwnProperty('title')) {
  232. const newTitle = req.body.title;
  233. Integrations.direct.update(
  234. { _id: paramIntId, boardId: paramBoardId },
  235. { $set: { title: newTitle } }
  236. );
  237. }
  238. if (req.body.hasOwnProperty('url')) {
  239. const newUrl = req.body.url;
  240. Integrations.direct.update(
  241. { _id: paramIntId, boardId: paramBoardId },
  242. { $set: { url: newUrl } }
  243. );
  244. }
  245. if (req.body.hasOwnProperty('token')) {
  246. const newToken = req.body.token;
  247. Integrations.direct.update(
  248. { _id: paramIntId, boardId: paramBoardId },
  249. { $set: { token: newToken } }
  250. );
  251. }
  252. if (req.body.hasOwnProperty('activities')) {
  253. const newActivities = req.body.activities;
  254. Integrations.direct.update(
  255. { _id: paramIntId, boardId: paramBoardId },
  256. { $set: { activities: newActivities } }
  257. );
  258. }
  259. JsonRoutes.sendResult(res, {
  260. code: 200,
  261. data: {
  262. _id: paramIntId,
  263. },
  264. });
  265. } catch (error) {
  266. JsonRoutes.sendResult(res, {
  267. code: 200,
  268. data: error,
  269. });
  270. }
  271. });
  272. /**
  273. * @operation delete_integration_activities
  274. * @summary Delete subscribed activities
  275. *
  276. * @param {string} boardId the board ID
  277. * @param {string} intId the integration ID
  278. * @param {string} newActivities the activities to remove from the integration
  279. * @return_type Integrations
  280. */
  281. JsonRoutes.add(
  282. 'DELETE',
  283. '/api/boards/:boardId/integrations/:intId/activities',
  284. function(req, res) {
  285. try {
  286. const paramBoardId = req.params.boardId;
  287. const paramIntId = req.params.intId;
  288. const newActivities = req.body.activities;
  289. Authentication.checkBoardAccess(req.userId, paramBoardId);
  290. Integrations.direct.update(
  291. { _id: paramIntId, boardId: paramBoardId },
  292. { $pullAll: { activities: newActivities } }
  293. );
  294. JsonRoutes.sendResult(res, {
  295. code: 200,
  296. data: Integrations.findOne(
  297. { _id: paramIntId, boardId: paramBoardId },
  298. { fields: { _id: 1, activities: 1 } }
  299. ),
  300. });
  301. } catch (error) {
  302. JsonRoutes.sendResult(res, {
  303. code: 200,
  304. data: error,
  305. });
  306. }
  307. }
  308. );
  309. /**
  310. * @operation new_integration_activities
  311. * @summary Add subscribed activities
  312. *
  313. * @param {string} boardId the board ID
  314. * @param {string} intId the integration ID
  315. * @param {string} newActivities the activities to add to the integration
  316. * @return_type Integrations
  317. */
  318. JsonRoutes.add(
  319. 'POST',
  320. '/api/boards/:boardId/integrations/:intId/activities',
  321. function(req, res) {
  322. try {
  323. const paramBoardId = req.params.boardId;
  324. const paramIntId = req.params.intId;
  325. const newActivities = req.body.activities;
  326. Authentication.checkBoardAccess(req.userId, paramBoardId);
  327. Integrations.direct.update(
  328. { _id: paramIntId, boardId: paramBoardId },
  329. { $addToSet: { activities: { $each: newActivities } } }
  330. );
  331. JsonRoutes.sendResult(res, {
  332. code: 200,
  333. data: Integrations.findOne(
  334. { _id: paramIntId, boardId: paramBoardId },
  335. { fields: { _id: 1, activities: 1 } }
  336. ),
  337. });
  338. } catch (error) {
  339. JsonRoutes.sendResult(res, {
  340. code: 200,
  341. data: error,
  342. });
  343. }
  344. }
  345. );
  346. /**
  347. * @operation delete_integration
  348. * @summary Delete integration
  349. *
  350. * @param {string} boardId the board ID
  351. * @param {string} intId the integration ID
  352. * @return_type {_id: string}
  353. */
  354. JsonRoutes.add('DELETE', '/api/boards/:boardId/integrations/:intId', function(
  355. req,
  356. res
  357. ) {
  358. try {
  359. const paramBoardId = req.params.boardId;
  360. const paramIntId = req.params.intId;
  361. Authentication.checkBoardAccess(req.userId, paramBoardId);
  362. Integrations.direct.remove({ _id: paramIntId, boardId: paramBoardId });
  363. JsonRoutes.sendResult(res, {
  364. code: 200,
  365. data: {
  366. _id: paramIntId,
  367. },
  368. });
  369. } catch (error) {
  370. JsonRoutes.sendResult(res, {
  371. code: 200,
  372. data: error,
  373. });
  374. }
  375. });
  376. }
  377. export default Integrations;