123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 |
- import { ReactiveCache } from '/imports/reactiveCache';
- import { TAPi18n } from '/imports/i18n';
- if (Meteor.isServer) {
- const postCatchError = Meteor.wrapAsync((url, options, resolve) => {
- HTTP.post(url, options, (err, res) => {
- if (err) {
- resolve(null, err.response);
- } else {
- resolve(null, res);
- }
- });
- });
- const Lock = {
- _lock: {},
- _timer: {},
- echoDelay: 500, // echo should be happening much faster
- normalDelay: 1e3, // normally user typed comment will be much slower
- ECHO: 2,
- NORMAL: 1,
- NULL: 0,
- has(id, value) {
- const existing = this._lock[id];
- let ret = this.NULL;
- if (existing) {
- ret = existing === value ? this.ECHO : this.NORMAL;
- }
- return ret;
- },
- clear(id, delay) {
- const previous = this._timer[id];
- if (previous) {
- Meteor.clearTimeout(previous);
- }
- this._timer[id] = Meteor.setTimeout(() => this.unset(id), delay);
- },
- set(id, value) {
- const state = this.has(id, value);
- let delay = this.normalDelay;
- if (state === this.ECHO) {
- delay = this.echoDelay;
- }
- if (!value) {
- // user commented, we set a lock
- value = 1;
- }
- this._lock[id] = value;
- this.clear(id, delay); // always auto reset the locker after delay
- },
- unset(id) {
- delete this._lock[id];
- },
- };
- const webhooksAtbts = (process.env.WEBHOOKS_ATTRIBUTES &&
- process.env.WEBHOOKS_ATTRIBUTES.split(',')) || [
- 'cardId',
- 'listId',
- 'oldListId',
- 'boardId',
- 'comment',
- 'user',
- 'card',
- 'commentId',
- 'swimlaneId',
- 'customField',
- 'customFieldValue',
- 'attachmentId',
- ];
- const responseFunc = data => {
- const paramCommentId = data.commentId;
- const paramCardId = data.cardId;
- const paramBoardId = data.boardId;
- const newComment = data.comment;
- if (paramCardId && paramBoardId && newComment) {
- // only process data with the cardid, boardid and comment text, TODO can expand other functions here to react on returned data
- const comment = CardComments.findOne({
- _id: paramCommentId,
- cardId: paramCardId,
- boardId: paramBoardId,
- });
- const board = ReactiveCache.getBoard(paramBoardId);
- const card = Cards.findOne(paramCardId);
- if (board && card) {
- if (comment) {
- Lock.set(comment._id, newComment);
- CardComments.direct.update(comment._id, {
- $set: {
- text: newComment,
- },
- });
- }
- } else {
- const userId = data.userId;
- if (userId) {
- const inserted = CardComments.direct.insert({
- text: newComment,
- userId,
- cardId,
- boardId,
- });
- Lock.set(inserted._id, newComment);
- }
- }
- }
- };
- Meteor.methods({
- outgoingWebhooks(integration, description, params) {
- if (Meteor.user()) {
- check(integration, Object);
- check(description, String);
- check(params, Object);
- this.unblock();
- // label activity did not work yet, see wekan/models/activities.js
- const quoteParams = _.clone(params);
- const clonedParams = _.clone(params);
- [
- 'card',
- 'list',
- 'oldList',
- 'board',
- 'oldBoard',
- 'comment',
- 'checklist',
- 'swimlane',
- 'oldSwimlane',
- 'label',
- 'attachment',
- 'attachmentId',
- ].forEach(key => {
- if (quoteParams[key]) quoteParams[key] = `"${params[key]}"`;
- });
- const userId = params.userId ? params.userId : integrations[0].userId;
- const user = Users.findOne(userId);
- const text = `${params.user} ${TAPi18n.__(
- description,
- quoteParams,
- user.getLanguage(),
- )}\n${params.url}`;
- if (text.length === 0) return;
- const value = {
- text: `${text}`,
- };
- webhooksAtbts.forEach(key => {
- if (params[key]) value[key] = params[key];
- });
- value.description = description;
- //integrations.forEach(integration => {
- const is2way = integration.type === Integrations.Const.TWOWAY;
- const token = integration.token || '';
- const headers = {
- 'Content-Type': 'application/json',
- };
- if (token) headers['X-Wekan-Token'] = token;
- const options = {
- headers,
- data: is2way ? { description, ...clonedParams } : value,
- };
- if (!Integrations.findOne({ url: integration.url })) return;
- const url = integration.url;
- if (is2way) {
- const cid = params.commentId;
- const comment = params.comment;
- const lockState = cid && Lock.has(cid, comment);
- if (cid && lockState !== Lock.NULL) {
- // it's a comment and there is a previous lock
- return;
- } else if (cid) {
- Lock.set(cid, comment); // set a lock here
- }
- }
- const response = postCatchError(url, options);
- if (
- response &&
- response.statusCode &&
- response.statusCode >= 200 &&
- response.statusCode < 300
- ) {
- if (is2way) {
- const data = response.data; // only an JSON encoded response will be actioned
- if (data) {
- try {
- responseFunc(data);
- } catch (e) {
- throw new Meteor.Error('error-process-data');
- }
- }
- }
- return response; // eslint-disable-line consistent-return
- } else {
- throw new Meteor.Error('error-invalid-webhook-response');
- }
- }
- },
- });
- }
|