summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam X. Chen <sam.xi.chen@gmail.com>2019-08-17 19:17:57 -0400
committerSam X. Chen <sam.xi.chen@gmail.com>2019-08-17 19:17:57 -0400
commit3f0600fed70512f87dc20fe039695d1681a73d39 (patch)
treecaf01293d663d18797d6834e22e503e2c6d9019a
parentf3147af2f75701b08c5464f8a7a2ab10a3d7d7a5 (diff)
downloadwekan-3f0600fed70512f87dc20fe039695d1681a73d39.tar.gz
wekan-3f0600fed70512f87dc20fe039695d1681a73d39.tar.bz2
wekan-3f0600fed70512f87dc20fe039695d1681a73d39.zip
Add Feature: enable two-way webhooks - stage one
-rw-r--r--client/components/settings/settingBody.jade8
-rw-r--r--client/components/settings/settingBody.js3
-rw-r--r--client/components/sidebar/sidebar.jade36
-rw-r--r--client/components/sidebar/sidebar.js86
-rw-r--r--client/lib/utils.js1
-rw-r--r--i18n/en.i18n.json5
-rw-r--r--models/integrations.js18
-rw-r--r--models/settings.js1
-rw-r--r--server/publications/settings.js6
9 files changed, 115 insertions, 49 deletions
diff --git a/client/components/settings/settingBody.jade b/client/components/settings/settingBody.jade
index 8eb584dc..04b635e8 100644
--- a/client/components/settings/settingBody.jade
+++ b/client/components/settings/settingBody.jade
@@ -18,6 +18,8 @@ template(name="setting")
a.js-setting-menu(data-id="announcement-setting") {{_ 'admin-announcement'}}
li
a.js-setting-menu(data-id="layout-setting") {{_ 'layout'}}
+ li
+ a.js-setting-menu(data-id="webhook-setting") {{_ 'global-webhook'}}
.main-body
if loading.get
+spinner
@@ -31,6 +33,12 @@ template(name="setting")
+announcementSettings
else if layoutSetting.get
+layoutSettings
+ else if webhookSetting.get
+ +webhookSettings
+
+template(name="webhookSettings")
+ span
+ +outgoingWebhooksPopup
template(name="general")
ul#registration-setting.setting-detail
diff --git a/client/components/settings/settingBody.js b/client/components/settings/settingBody.js
index f9b5c08d..4ff5aedd 100644
--- a/client/components/settings/settingBody.js
+++ b/client/components/settings/settingBody.js
@@ -7,11 +7,13 @@ BlazeComponent.extendComponent({
this.accountSetting = new ReactiveVar(false);
this.announcementSetting = new ReactiveVar(false);
this.layoutSetting = new ReactiveVar(false);
+ this.webhookSetting = new ReactiveVar(false);
Meteor.subscribe('setting');
Meteor.subscribe('mailServer');
Meteor.subscribe('accountSettings');
Meteor.subscribe('announcements');
+ Meteor.subscribe('globalwebhooks');
},
setError(error) {
@@ -83,6 +85,7 @@ BlazeComponent.extendComponent({
this.accountSetting.set('account-setting' === targetID);
this.announcementSetting.set('announcement-setting' === targetID);
this.layoutSetting.set('layout-setting' === targetID);
+ this.webhookSetting.set('webhook-setting' === targetID);
}
},
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade
index 2dfe41b3..ccfadc0c 100644
--- a/client/components/sidebar/sidebar.jade
+++ b/client/components/sidebar/sidebar.jade
@@ -135,22 +135,30 @@ template(name="archiveBoardPopup")
template(name="outgoingWebhooksPopup")
each integrations
form.integration-form
- if title
- h4 {{title}}
- else
- h4 {{_ 'no-name'}}
- label
- | URL
- input.js-outgoing-webhooks-url(type="text" name="url" value=url)
- input(type="hidden" value=_id name="id")
+ a.flex
+ span {{_ 'disable-webhook'}}
+ b &nbsp;
+ .materialCheckBox(class="{{#unless enabled}}is-checked{{/unless}}")
+ input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" value=title)
+ input.js-outgoing-webhooks-url(type="text" name="url" value=url autofocus)
+ input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" value=token name="token")
+ select.js-outgoing-webhooks-type(name="type")
+ each _type in types
+ if($eq _type this.type)
+ option(value=_type selected="selected") {{_ _type}}
+ else
+ option(value=_type) {{_ _type}}
+ input(type="hidden" value=this.type name="_type")
+ input(type="hidden" value=_id name="id")
input.primary.wide(type="submit" value="{{_ 'save'}}")
form.integration-form
- h4
- | {{_ 'new-outgoing-webhook'}}
- label
- | URL
- input.js-outgoing-webhooks-url(type="text" name="url" autofocus)
- input.primary.wide(type="submit" value="{{_ 'save'}}")
+ input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" autofocus)
+ input.js-outgoing-webhooks-url(placeholder="{{_ 'URL' }}" type="text" name="url")
+ input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" name="token")
+ select.js-outgoing-webhooks-type(name="type")
+ each _type in types
+ option(value=_type) {{_ _type}}
+ input.primary.wide(type="submit" value="{{_ 'create'}}")
template(name="boardMenuPopup")
ul.pop-over-list
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index f7efb1e8..f1ccfb1e 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -1,6 +1,8 @@
Sidebar = null;
const defaultView = 'home';
+const MCB = '.materialCheckBox';
+const CKCLS = 'is-checked';
const viewTitles = {
filter: 'filter-cards',
@@ -280,44 +282,71 @@ Template.membersWidget.events({
});
BlazeComponent.extendComponent({
+ boardId() {
+ return Session.get('currentBoard') || Integrations.Const.GLOBAL_WEBHOOK_ID;
+ },
integrations() {
- const boardId = Session.get('currentBoard');
+ const boardId = this.boardId();
return Integrations.find({ boardId: `${boardId}` }).fetch();
},
-
- integration(id) {
- const boardId = Session.get('currentBoard');
- return Integrations.findOne({ _id: id, boardId: `${boardId}` });
+ types() {
+ return Integrations.Const.WEBHOOK_TYPES;
+ },
+ integration(cond) {
+ const boardId = this.boardId();
+ const condition = { boardId, ...cond };
+ for (const k in condition) {
+ if (!condition[k]) delete condition[k];
+ }
+ return Integrations.findOne(condition);
+ },
+ onCreated() {
+ this.disabled = new ReactiveVar(false);
},
-
events() {
return [
{
+ 'click a.flex'(evt) {
+ this.disabled.set(!this.disabled.get());
+ $(evt.target).toggleClass(CKCLS, this.disabled.get());
+ },
submit(evt) {
evt.preventDefault();
const url = evt.target.url.value;
- const boardId = Session.get('currentBoard');
+ const boardId = this.boardId();
let id = null;
let integration = null;
+ const title = evt.target.title.value;
+ const token = evt.target.token.value;
+ const type = evt.target.type.value;
+ const enabled = !this.disabled.get();
+ let remove = false;
+ const values = {
+ url,
+ type,
+ token,
+ title,
+ enabled,
+ };
if (evt.target.id) {
id = evt.target.id.value;
- integration = this.integration(id);
- if (url) {
- Integrations.update(integration._id, {
- $set: {
- url: `${url}`,
- },
- });
- } else {
- Integrations.remove(integration._id);
- }
+ integration = this.integration({ _id: id });
+ remove = !url;
+ } else if (url) {
+ integration = this.integration({ url, token });
+ }
+ if (remove) {
+ Integrations.remove(integration._id);
+ } else if (integration && integration._id) {
+ Integrations.update(integration._id, {
+ $set: values,
+ });
} else if (url) {
Integrations.insert({
+ ...values,
userId: Meteor.userId(),
enabled: true,
- type: 'outgoing-webhooks',
- url: `${url}`,
- boardId: `${boardId}`,
+ boardId,
activities: ['all'],
});
}
@@ -474,12 +503,12 @@ BlazeComponent.extendComponent({
evt.preventDefault();
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
- $('.js-field-has-subtasks .materialCheckBox').toggleClass(
- 'is-checked',
+ $(`.js-field-has-subtasks ${MCB}`).toggleClass(
+ CKCLS,
this.currentBoard.allowsSubtasks,
);
$('.js-field-has-subtasks').toggleClass(
- 'is-checked',
+ CKCLS,
this.currentBoard.allowsSubtasks,
);
$('.js-field-deposit-board').prop(
@@ -515,15 +544,12 @@ BlazeComponent.extendComponent({
];
options.forEach(function(element) {
if (element !== value) {
- $(`#${element} .materialCheckBox`).toggleClass(
- 'is-checked',
- false,
- );
- $(`#${element}`).toggleClass('is-checked', false);
+ $(`#${element} ${MCB}`).toggleClass(CKCLS, false);
+ $(`#${element}`).toggleClass(CKCLS, false);
}
});
- $(`#${value} .materialCheckBox`).toggleClass('is-checked', true);
- $(`#${value}`).toggleClass('is-checked', true);
+ $(`#${value} ${MCB}`).toggleClass(CKCLS, true);
+ $(`#${value}`).toggleClass(CKCLS, true);
this.currentBoard.setPresentParentTask(value);
evt.preventDefault();
},
diff --git a/client/lib/utils.js b/client/lib/utils.js
index 81835929..cc3526c0 100644
--- a/client/lib/utils.js
+++ b/client/lib/utils.js
@@ -23,7 +23,6 @@ Utils = {
})
);
},
-
MAX_IMAGE_PIXEL: Meteor.settings.public.MAX_IMAGE_PIXEL,
COMPRESS_RATIO: Meteor.settings.public.IMAGE_COMPRESS_RATIO,
processUploadedAttachment(card, fileObj, callback) {
diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json
index 7065396f..c8acc0de 100644
--- a/i18n/en.i18n.json
+++ b/i18n/en.i18n.json
@@ -508,9 +508,14 @@
"email-smtp-test-text": "You have successfully sent an email",
"error-invitation-code-not-exist": "Invitation code doesn't exist",
"error-notAuthorized": "You are not authorized to view this page.",
+ "webhook-title": "Webhook Name",
+ "webhook-token": "Token (Optional for Authentication)",
"outgoing-webhooks": "Outgoing Webhooks",
+ "bidirectional-webhooks": "Two-Way Webhooks",
"outgoingWebhooksPopup-title": "Outgoing Webhooks",
"boardCardTitlePopup-title": "Card Title Filter",
+ "disable-webhook": "Disable This Webhook",
+ "global-webhook": "Global Webhooks",
"new-outgoing-webhook": "New Outgoing Webhook",
"no-name": "(Unknown)",
"Node_version": "Node version",
diff --git a/models/integrations.js b/models/integrations.js
index 0b2e08c6..0313c959 100644
--- a/models/integrations.js
+++ b/models/integrations.js
@@ -88,16 +88,26 @@ Integrations.attachSchema(
},
}),
);
-
+Integrations.Const = {
+ GLOBAL_WEBHOOK_ID: '_global',
+ WEBHOOK_TYPES: ['outgoing-webhooks', 'bidirectional-webhooks'],
+};
+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 allowIsBoardAdmin(userId, Boards.findOne(doc.boardId));
+ return permissionHelper.allow(userId, doc);
},
update(userId, doc) {
- return allowIsBoardAdmin(userId, Boards.findOne(doc.boardId));
+ return permissionHelper.allow(userId, doc);
},
remove(userId, doc) {
- return allowIsBoardAdmin(userId, Boards.findOne(doc.boardId));
+ return permissionHelper.allow(userId, doc);
},
fetch: ['boardId'],
});
diff --git a/models/settings.js b/models/settings.js
index 4a0359d5..80c2d8e0 100644
--- a/models/settings.js
+++ b/models/settings.js
@@ -147,6 +147,7 @@ if (Meteor.isServer) {
}:${doc.mailServer.port}/`;
}
Accounts.emailTemplates.from = doc.mailServer.from;
+ console.log('Settings saved:', Accounts.emailTemplates);
}
});
diff --git a/server/publications/settings.js b/server/publications/settings.js
index d273fe62..034737e7 100644
--- a/server/publications/settings.js
+++ b/server/publications/settings.js
@@ -1,3 +1,9 @@
+Meteor.publish('globalwebhooks', () => {
+ const boardId = Integrations.Const.GLOBAL_WEBHOOK_ID;
+ return Integrations.find({
+ boardId,
+ });
+});
Meteor.publish('setting', () => {
return Settings.find(
{},