Skip to content
Snippets Groups Projects
Commit 3def9ef3 authored by Gabriel Engel's avatar Gabriel Engel Committed by GitHub
Browse files

Merge pull request #4605 from RocketChat/slackbridge-out

Slackbridge out
parents 6b68ab94 50d1e9e3
No related branches found
No related tags found
No related merge requests found
......@@ -17,7 +17,7 @@
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"resolved": "http://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"from": "core-util-is@>=1.0.0 <1.1.0"
},
"css-select": {
......
......@@ -1145,7 +1145,13 @@
"Site_Url_Description": "Example: https://chat.domain.com/",
"Skip": "Skip",
"SlackBridge_error": "SlackBridge got an error while importing your messages at %s: %s",
"SlackBridge_Out_All": "SlackBridge Out All",
"SlackBridge_Out_All_Description": "Send messages from all channels that exist in Slack and the bot has joined",
"SlackBridge_Out_Channels": "SlackBridge Out Channels",
"SlackBridge_Out_Channels_Description": "Choose which channels will send messages back to Slack",
"SlackBridge_finish": "SlackBridge has finished importing the messages at %s. Please reload to view all messages.",
"SlackBridge_Out_Enabled": "SlackBridge Out Enabled",
"SlackBridge_Out_Enabled_Description": "Choose whether SlackBridge should also send your messages back to Slack",
"SlackBridge_start": "@%s has started a SlackBridge import at `#%s`. We'll let you know when it's finished.",
"Slash_Gimme_Description": "Displays ༼ つ ◕_◕ ༽つ before your message",
"Slash_LennyFace_Description": "Displays ( ͡° ͜ʖ ͡°) after your message",
......
......@@ -19,6 +19,9 @@ Meteor.methods({
//Verify the value is what it should be
switch (setting.type) {
case 'roomPick':
check(value, [Object]);
break;
case 'boolean':
check(value, Boolean);
break;
......
......@@ -17,14 +17,55 @@ Meteor.startup(function() {
this.add('SlackBridge_AliasFormat', '', {
type: 'string',
enableQuery: {
_id: 'SlackBridge_Enabled',
value: true
},
i18nLabel: 'Alias_Format',
i18nDescription: 'Alias_Format_Description'
});
this.add('SlackBridge_ExcludeBotnames', '', {
type: 'string',
enableQuery: {
_id: 'SlackBridge_Enabled',
value: true
},
i18nLabel: 'Exclude_Botnames',
i18nDescription: 'Exclude_Botnames_Description'
});
this.add('SlackBridge_Out_Enabled', false, {
type: 'boolean',
enableQuery: {
_id: 'SlackBridge_Enabled',
value: true
}
});
this.add('SlackBridge_Out_All', false, {
type: 'boolean',
enableQuery: [{
_id: 'SlackBridge_Enabled',
value: true
}, {
_id: 'SlackBridge_Out_Enabled',
value: true
}]
});
this.add('SlackBridge_Out_Channels', '', {
type: 'roomPick',
enableQuery: [{
_id: 'SlackBridge_Enabled',
value: true
}, {
_id: 'SlackBridge_Out_Enabled',
value: true
}, {
_id: 'SlackBridge_Out_All',
value: false
}]
});
});
});
......@@ -47,6 +47,16 @@ class SlackBridge {
this.rtm = new RtmClient(this.apiToken);
this.rtm.start();
this.setEvents();
RocketChat.settings.get('SlackBridge_Out_Enabled', (key, value) => {
if (value) {
RocketChat.callbacks.add('afterSaveMessage', this.slackBridgeOut.bind(this), RocketChat.callbacks.priority.LOW, 'SlackBridge_Out');
} else {
RocketChat.callbacks.remove('afterSaveMessage', 'SlackBridge_Out');
}
});
Meteor.startup(() => {
this.populateChannelMap(); // If run outside of Meteor.startup, HTTP is not defined
});
}
}
......@@ -55,6 +65,7 @@ class SlackBridge {
this.connected = false;
this.rtm.disconnect && this.rtm.disconnect();
logger.connection.info('Disconnected');
RocketChat.callbacks.remove('afterSaveMessage', 'SlackBridge_Out');
}
}
......@@ -932,6 +943,57 @@ class SlackBridge {
return callback(new Meteor.Error('error-invalid-room', 'Invalid room'));
}
}
populateChannelMap() {
logger.class.debug('Populating channel map');
let response = HTTP.get('https://slack.com/api/channels.list', { params: { token: this.apiToken } });
if (response && response.data && _.isArray(response.data.channels) && response.data.channels.length > 0) {
for (let channel of response.data.channels) {
let rocketchat_room = RocketChat.models.Rooms.findOneByName(channel.name, { fields: { _id: 1 } });
if (rocketchat_room) {
this.channelMap[rocketchat_room._id] = { id: channel.id, family: channel.id.charAt(0) === 'C' ? 'channels' : 'groups' };
}
}
}
response = HTTP.get('https://slack.com/api/groups.list', { params: { token: this.apiToken } });
if (response && response.data && _.isArray(response.data.groups) && response.data.groups.length > 0) {
for (let group of response.data.groups) {
let rocketchat_room = RocketChat.models.Rooms.findOneByName(group.name, { fields: { _id: 1 } });
if (rocketchat_room) {
this.channelMap[rocketchat_room._id] = { id: group.id, family: group.id.charAt(0) === 'C' ? 'channels' : 'groups' };
}
}
}
}
slackBridgeOut(message) {
// Ignore messages originating from Slack
if (message._id.indexOf('slack-') === 0) {
return message;
}
let outChannels = RocketChat.settings.get('SlackBridge_Out_All') ? _.keys(this.channelMap) : _.pluck(RocketChat.settings.get('SlackBridge_Out_Channels'), '_id') || [];
logger.class.debug('Out Channels: ', outChannels);
if (outChannels.indexOf(message.rid) !== -1) {
logger.class.debug('Message out', message);
this.postMessage(this.channelMap[message.rid], message);
}
return message;
}
postMessage(room, message) {
if (room && room.id) {
let data = {
token: this.apiToken,
text: message.msg,
channel: room.id,
username: message.u && message.u.username,
icon_url: getAvatarUrlFromUsername(message.u && message.u.username),
link_names: 1
};
logger.class.debug('Post Message', data);
HTTP.post('https://slack.com/api/chat.postMessage', { params: data });
}
}
}
RocketChat.SlackBridge = new SlackBridge;
......@@ -1728,6 +1728,12 @@ label.required:after {
padding: 5px;
}
}
.selected-rooms {
.remove-room {
cursor: pointer;
}
}
}
}
.settings-description {
......@@ -1773,6 +1779,7 @@ label.required:after {
}
}
}
}
.page-static {
......
......@@ -5,12 +5,26 @@ Template.admin.onCreated ->
RocketChat.settings.collectionPrivate = RocketChat.settings.cachedCollectionPrivate.collection
RocketChat.settings.cachedCollectionPrivate.init()
this.selectedRooms = new ReactiveVar {}
RocketChat.settings.collectionPrivate.find().observe
added: (data) ->
added: (data) =>
selectedRooms = this.selectedRooms.get()
if data.type is 'roomPick'
selectedRooms[data._id] = data.value
this.selectedRooms.set(selectedRooms)
TempSettings.insert data
changed: (data) ->
changed: (data) =>
selectedRooms = this.selectedRooms.get()
if data.type is 'roomPick'
selectedRooms[data._id] = data.value
this.selectedRooms.set(selectedRooms)
TempSettings.update data._id, data
removed: (data) ->
removed: (data) =>
selectedRooms = this.selectedRooms.get()
if data.type is 'roomPick'
delete selectedRooms[data._id]
this.selectedRooms.set(selectedRooms)
TempSettings.remove data._id
Template.admin.onDestroyed ->
......@@ -200,6 +214,29 @@ Template.admin.helpers
if fileConstraints.extensions?.length > 0
return '.' + fileConstraints.extensions.join(', .')
autocompleteRoom: ->
return {
limit: 10
# inputDelay: 300
rules: [
{
# @TODO maybe change this 'collection' and/or template
collection: 'CachedChannelList'
subscription: 'channelAndPrivateAutocomplete'
field: 'name'
template: Template.roomSearch
noMatchTemplate: Template.roomSearchEmpty
matchAll: true
selector: (match) ->
return { name: match }
sort: 'name'
}
]
}
selectedRooms: ->
console.log(this._id)
return Template.instance().selectedRooms.get()[this._id] or []
Template.admin.events
"change .input-monitor": (e, t) ->
......@@ -341,6 +378,29 @@ Template.admin.events
codeMirrorBox.removeClass('code-mirror-box-fullscreen')
codeMirrorBox.find('.CodeMirror')[0].CodeMirror.refresh()
'autocompleteselect .autocomplete': (event, instance, doc) ->
selectedRooms = instance.selectedRooms.get()
selectedRooms[this.id] = (selectedRooms[this.id] || []).concat doc
instance.selectedRooms.set selectedRooms
value = selectedRooms[this.id]
TempSettings.update {_id: this.id},
$set:
value: value
changed: RocketChat.settings.collectionPrivate.findOne(this.id).value isnt value
event.currentTarget.value = ''
event.currentTarget.focus()
'click .remove-room': (event, instance) ->
docId = this._id
settingId = event.currentTarget.getAttribute('data-setting')
selectedRooms = instance.selectedRooms.get()
selectedRooms[settingId] = _.reject(selectedRooms[settingId] || [], (setting) -> setting._id is docId)
instance.selectedRooms.set selectedRooms
value = selectedRooms[settingId]
TempSettings.update {_id: settingId},
$set:
value: value
changed: RocketChat.settings.collectionPrivate.findOne(settingId).value isnt value
Template.admin.onRendered ->
Tracker.afterFlush ->
......
......@@ -144,6 +144,17 @@
{{/if}}
{{/if}}
{{#if $eq type 'roomPick'}}
<div>
{{> inputAutocomplete settings=autocompleteRoom id=_id name=_id class="search autocomplete" autocomplete="off" disabled=isDisabled.disabled}}
<ul class="selected-rooms">
{{#each selectedRooms}}
<li class="remove-room" data-setting={{../_id}}>{{name}} <i class="icon-cancel"></i></li>
{{/each}}
</ul>
</div>
{{/if}}
{{#if description}}
<div class="settings-description">{{{RocketChatMarkdown description}}}</div>
{{/if}}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment