outgoing.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. const postCatchError = Meteor.wrapAsync((url, options, resolve) => {
  2. HTTP.post(url, options, (err, res) => {
  3. if (err) {
  4. resolve(null, err.response);
  5. } else {
  6. resolve(null, res);
  7. }
  8. });
  9. });
  10. const Lock = {
  11. _lock: {},
  12. has(id) {
  13. return !!this._lock[id];
  14. },
  15. set(id) {
  16. this._lock[id] = 1;
  17. },
  18. unset(id) {
  19. delete this._lock[id];
  20. },
  21. };
  22. const webhooksAtbts = (process.env.WEBHOOKS_ATTRIBUTES &&
  23. process.env.WEBHOOKS_ATTRIBUTES.split(',')) || [
  24. 'cardId',
  25. 'listId',
  26. 'oldListId',
  27. 'boardId',
  28. 'comment',
  29. 'user',
  30. 'card',
  31. 'commentId',
  32. 'swimlaneId',
  33. ];
  34. const responseFunc = 'reactOnHookResponse';
  35. Meteor.methods({
  36. [responseFunc](data) {
  37. check(data, Object);
  38. const paramCommentId = data.commentId;
  39. const paramCardId = data.cardId;
  40. const paramBoardId = data.boardId;
  41. const newComment = data.comment;
  42. if (paramCardId && paramBoardId && newComment) {
  43. // only process data with the cardid, boardid and comment text, TODO can expand other functions here to react on returned data
  44. const comment = CardComments.findOne({
  45. _id: paramCommentId,
  46. cardId: paramCardId,
  47. boardId: paramBoardId,
  48. });
  49. if (comment) {
  50. CardComments.update(comment._id, {
  51. $set: {
  52. text: newComment,
  53. },
  54. });
  55. } else {
  56. const userId = data.userId;
  57. if (userId) {
  58. CardComments.insert({
  59. text: newComment,
  60. userId,
  61. cardId,
  62. boardId,
  63. });
  64. }
  65. }
  66. }
  67. },
  68. outgoingWebhooks(integration, description, params) {
  69. check(integration, Object);
  70. check(description, String);
  71. check(params, Object);
  72. this.unblock();
  73. // label activity did not work yet, see wekan/models/activities.js
  74. const quoteParams = _.clone(params);
  75. const clonedParams = _.clone(params);
  76. [
  77. 'card',
  78. 'list',
  79. 'oldList',
  80. 'board',
  81. 'oldBoard',
  82. 'comment',
  83. 'checklist',
  84. 'swimlane',
  85. 'oldSwimlane',
  86. 'label',
  87. 'attachment',
  88. ].forEach(key => {
  89. if (quoteParams[key]) quoteParams[key] = `"${params[key]}"`;
  90. });
  91. const userId = params.userId ? params.userId : integrations[0].userId;
  92. const user = Users.findOne(userId);
  93. const text = `${params.user} ${TAPi18n.__(
  94. description,
  95. quoteParams,
  96. user.getLanguage(),
  97. )}\n${params.url}`;
  98. if (text.length === 0) return;
  99. const value = {
  100. text: `${text}`,
  101. };
  102. webhooksAtbts.forEach(key => {
  103. if (params[key]) value[key] = params[key];
  104. });
  105. value.description = description;
  106. //integrations.forEach(integration => {
  107. const is2way = integration.type === Integrations.Const.TWOWAY;
  108. const token = integration.token || '';
  109. const headers = {
  110. 'Content-Type': 'application/json',
  111. };
  112. if (token) headers['X-Wekan-Token'] = token;
  113. const options = {
  114. headers,
  115. data: is2way ? clonedParams : value,
  116. };
  117. const url = integration.url;
  118. const response = postCatchError(url, options);
  119. if (response && response.statusCode && response.statusCode === 200) {
  120. if (is2way) {
  121. const cid = params.commentId;
  122. const tooSoon = Lock.has(cid); // if an activity happens to fast, notification shouldn't fire with the same id
  123. if (!tooSoon) {
  124. let clearNotification = () => {};
  125. if (cid) {
  126. Lock.set(cid);
  127. const clearNotificationFlagTimeout = 1000;
  128. clearNotification = () => Lock.unset(cid);
  129. Meteor.setTimeout(clearNotification, clearNotificationFlagTimeout);
  130. }
  131. const data = response.data; // only an JSON encoded response will be actioned
  132. if (data) {
  133. Meteor.call(responseFunc, data, () => {
  134. clearNotification();
  135. });
  136. }
  137. }
  138. }
  139. return response; // eslint-disable-line consistent-return
  140. } else {
  141. throw new Meteor.Error('error-invalid-webhook-response');
  142. }
  143. //});
  144. },
  145. });