UNPKG

8.13 kBtext/coffeescriptView Raw
1# Description
2# Relay helper command for Hubot
3#
4# Dependencies:
5# hubot-slack
6#
7# Commands:
8# relay add <local-channel> <remote-channel> <remote-token> - Adds a relay with a remote channel. *NOTE:* Tokens are private and this should be setup via Direct Messaging.
9# relay remove <local-channel> [<remote-channel>]- Removes a relay with a remote channel.
10# relay list - Lists all existing relays.
11#
12# Author:
13# davidkassa
14
15S = require 'string'
16RemoteSlack = require './remote-slack'
17Relay = require './relay'
18
19module.exports = (robot) ->
20
21 BRAIN_KEY = 'hubot-slack-relay.storage'
22 IGNORE_BOTS = process.env.IGNORE_BOTS or true
23 relays = []
24 client = robot.adapter.client
25
26 brainLoaded = () =>
27 #load brain data
28 data = (robot.brain.get BRAIN_KEY) || {}
29
30 relays = for d in data
31 relay = Relay.fromJSON d
32 relay.on 'invalidChannel', invalidChannelError
33 relay
34
35 invalidChannelError = (relay) =>
36 robot.logger.info 'invalidChannelError'
37 remoteBot = relay.remote.client.self.name ? 'the remote bot'
38
39 user = { room: relay.localRoom }
40 robot.adapter.send user, 'Could not deliver message to \'' + relay.remoteRoom + '\' because ' + remoteBot + ' is not in the channel.'
41
42 brainLoaded() #call brainLoaded directly for brains without a load event, such as jobot-brain-file or hubot-scripts/file-brain
43 robot.brain.on 'loaded', brainLoaded
44
45 saveBrain = () =>
46 robot.logger.info 'Save Brain'
47
48 #store array before saving, due to bad mergeData in brain
49 temp = relays
50
51 robot.brain.set BRAIN_KEY, relays
52 robot.brain.save()
53
54 #re-assign relays for deep copy after save
55 relays = temp
56
57
58 robot.respond /relay add\s+(\S+)\s+(\S+)\s+(\S+)/i, (res) =>
59 robot.logger.info 'relay add ' + res.match[1] + ' ' + res.match[2] + ' ' + res.match[3]
60
61 localRoom = S(res.match[1]).chompLeft('#').s
62 remoteRoom = S(res.match[2]).chompLeft('#').s
63 remoteToken = S(res.match[3]).chompLeft('#').s
64
65 #check to make sure it doesn't exist
66 if process.env.HUBOT_SLACK_TOKEN is remoteToken
67 res.send 'This is the local hubot token. Please use the hubot token from the remote server.'
68 return
69
70 for relay in relays
71 if relay.localRoom is localRoom and relay.remoteRoom is remoteRoom and relay.remote.token is remoteToken
72 res.send 'This remote relay already exists.'
73 return
74
75
76 @newResponse = res
77 #TODO: validate local room
78
79 #validate token and remote room by connecting
80 remote = new RemoteSlack(remoteToken)
81 @newRelay = new Relay localRoom, remote, remoteRoom
82
83 remote.on 'remote.connected', newRemoteConnected
84 remote.on 'remote.error', newRemoteError
85
86 remote.login()
87
88 newRemoteConnected = (remote) =>
89 @newRelay.remote.removeListener('remote.connected',newRemoteConnected)
90 @newRelay.remote.removeListener('remote.error',newRemoteError)
91 @newRelay.on 'invalidChannel', invalidChannelError
92
93 channel = @newRelay.remote.client.getChannelGroupOrDMByName @newRelay.remoteRoom
94 remoteBot = @newRelay.remote.client.self.name ? 'the remote bot'
95
96 if channel
97 #save to brain and push onto relay
98 relays.push @newRelay
99 saveBrain()
100
101 if channel.is_member
102 @newResponse.send 'Successfully connected to the remote relay and channel \'' + @newRelay.remoteRoom + '\'.'
103 else
104 @newResponse.send 'Successfully connected to the remote relay but ' + remoteBot + ' needs to be invited to \'' + @newRelay.remoteRoom + '\'.'
105
106 else
107 @newResponse.send 'Could not find the channel \'' + @newRelay.remoteRoom + '\' on the remote relay.'
108
109
110 newRemoteError = (error) =>
111 @newRelay.remote.removeListener('remote.connected',newRemoteConnected)
112 @newRelay.remote.removeListener('remote.error',newRemoteError)
113
114 t = S(@newRelay.remote.token).padLeft(5)
115 @newResponse.send 'Could not connect to remote relay with token \'' + S('*').repeat(t.length - 5) + S(t.substr(t.length - 5)).trim() + '\'.'
116
117 robot.respond /relay remove\s+(\S+)\s*(\S*)\s*(\S*)/i, (res) =>
118 robot.logger.info 'relay remove ' + res.match[1] + ' ' + res.match[2] + ' ' + res.match[3]
119
120 localRoom = S(res.match[1]).chompLeft('#').s
121 remoteRoom = if res.match[2] then S(res.match[2]).chompLeft('#').s
122 remoteToken = if res.match[3] then S(res.match[3]).chompLeft('#').s
123
124 found = false
125 if not remoteRoom
126 relays = for relay in relays
127 #remove if matched
128 if relay.localRoom is localRoom
129 found = true
130 continue
131 relay
132 if found
133 saveBrain()
134 res.send 'Removed all remote relays associated with local channel \'' + localRoom + '\''
135
136 else
137 if remoteToken
138 relays = for relay in relays
139 #remove if matched
140 t = relay.remote.token
141 token = t.substr(t.length - 5)
142 if relay.localRoom is localRoom and relay.remoteRoom is remoteRoom and token is remoteToken
143 found = true
144 continue
145 relay
146 if found
147 saveBrain()
148 res.send 'Removed remote relay - local-channel: ' + localRoom + ' remote-channel: ' + remoteRoom + ' remote-token: ' + remoteToken
149 else
150 matches = []
151 potentialRelays = for relay in relays
152 if relay.localRoom is localRoom and relay.remoteRoom is remoteRoom
153 matches.push relay
154 continue
155 relay
156 #if single, match
157 if matches.length is 1
158 found = true
159 relays = potentialRelays
160 saveBrain()
161 res.send 'Removed remote relay - local-channel: ' + localRoom + ' remote-channel: ' + remoteRoom
162 #if multiple, show list
163 else if matches.length > 1
164 found = true
165 res.send '*There are multiple options for this <local-channel> <remote-channel> combination.*\nPlease include the last 5 digits of the remote token and try again.\n`relay remove <local-channel> <remote-channel> <last 5 of remote-token>`'
166 res.send blockList(matches)
167
168 if not found
169 res.send 'Could not find any records matching the criteria.'
170
171 robot.respond /relay list/i, (res) =>
172 robot.logger.info 'relay list'
173 res.send blockList(relays)
174
175
176 blockList = (collection, filter) =>
177 if not collection or collection.length is 0 then return ''
178 filter ?= () -> true
179 list = '```'
180 for item in collection when filter(item)
181 list = list + item.toString() + '\n'
182 list + '```'
183
184 robot.hear /(.+)/i, (res) =>
185
186 if IGNORE_BOTS and client.getUserByID(res.message.user.id).is_bot then return
187
188 for relay in relays
189 if res.message.room isnt relay.localRoom then continue
190 user = { room: relay.remoteRoom }
191 if not relay.remote.send user, '_' + res.message.user.name + ' said:_ ' + res.match[1]
192 invalidChannelError relay
193
194 robot.enter (res) ->
195
196 if IGNORE_BOTS and client.getUserByID(res.message.user.id).is_bot then return
197
198 for relay in relays
199 if res.message.room isnt relay.localRoom then continue
200 user = { room: relay.remoteRoom }
201 if not relay.remote.send user, '_' + res.message.user.name + ' has entered #' + res.message.room + '_'
202 invalidChannelError relay
203
204 robot.leave (res) ->
205
206 if IGNORE_BOTS and client.getUserByID(res.message.user.id).is_bot then return
207
208 for relay in relays
209 if res.message.room isnt relay.localRoom then continue
210 user = { room: relay.remoteRoom }
211 if not relay.remote.send user, '_' + res.message.user.name + ' has left #' + res.message.room + '_'
212 invalidChannelError relay
213
214# robot.catchAll (res) ->
215# robot.logger.info 'catchAll'
216# robot.emit 'slack-attachment',
217# channel: 'other-channel'
218# fallback: res.message
219# content:
220# color: "d96b38",
221# fields: [{
222# title: "Status Change",
223# value: "#test"
224# }]
225