Class: Driftwood::Slack
- Inherits:
-
Object
- Object
- Driftwood::Slack
- Defined in:
- lib/driftwood/slack.rb
Instance Method Summary collapse
- #all_channels ⇒ Object
- #all_messages(starting_from = 0) ⇒ Object
- #all_users ⇒ Object
- #authorize(auth) ⇒ Object
- #channel_info(team_id, channel_id) ⇒ Object
- #channel_name(team_id, channel_id) ⇒ Object
- #channels(team_id) ⇒ Object
- #create_slack_client(slack_api_secret) ⇒ Object
- #event(request_data) ⇒ Object
-
#initialize(config) ⇒ Slack
constructor
A new instance of Slack.
- #messages(team_id, starting_from = 0) ⇒ Object
- #my_ims ⇒ Object
- #normalize_message(team_id, message) ⇒ Object
- #normalize_messages(team_id, channel_id, messages) ⇒ Object
- #normalize_user(user) ⇒ Object
- #real_name(team_id, user_id) ⇒ Object
- #register_handler(event, &block) ⇒ Object
-
#send_response(team_id, channel, text, unfurl_links = false, attachment = nil, ts = nil) ⇒ Object
Send a response to an Event via the Web API.
- #shell ⇒ Object
- #team(team_id) ⇒ Object
- #team_info(team_id) ⇒ Object
- #team_name(team_id) ⇒ Object
- #teams ⇒ Object
- #to_me?(event_data) ⇒ Boolean
- #user_info(team_id, user_id) ⇒ Object
- #users(team_id) ⇒ Object
Constructor Details
#initialize(config) ⇒ Slack
Returns a new instance of Slack.
4 5 6 7 8 9 10 |
# File 'lib/driftwood/slack.rb', line 4 def initialize(config) @config = config @teams = {} @handlers = {} $logger.info "Started Slack bot" end |
Instance Method Details
#all_channels ⇒ Object
225 226 227 228 229 |
# File 'lib/driftwood/slack.rb', line 225 def all_channels @teams.keys.inject([]) do |channels, team_id| channels.concat(channels(team_id)) end end |
#all_messages(starting_from = 0) ⇒ Object
237 238 239 240 241 |
# File 'lib/driftwood/slack.rb', line 237 def (starting_from = 0) @teams.keys.inject([]) do |, team_id| .concat((team_id, starting_from)) end end |
#all_users ⇒ Object
231 232 233 234 235 |
# File 'lib/driftwood/slack.rb', line 231 def all_users @teams.keys.inject([]) do |users, team_id| users.concat(users(team_id)) end end |
#authorize(auth) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/driftwood/slack.rb', line 12 def (auth) team_id = nil client = Slack::Web::Client.new # OAuth Step 3: Success or failure # is this a cached authentication object? if auth.is_a? Array $logger.info "Using cached authentication for:" auth.each do |row| team_id = row.delete(:team_id) @teams[team_id] = row $logger.info " * #{row[:name] || team_id}" end # we have a token from a single oauth exchange elsif auth.is_a? String begin response = client.oauth_access( { client_id: @config[:client_id], client_secret: @config[:client_secret], redirect_uri: @config[:redirect_uri], code: auth } ) team_id = response['team_id'] $logger.info "Authenticated new integration for team '#{team_id}'." rescue Slack::Web::Api::Error => e # Failure: # D'oh! Let the user know that something went wrong and output the error message returned by the Slack client. $logger.warn "Slack Authentication failed! Reason: #{e.}" raise "Slack Authentication failed! Reason: #{e.}" end # Yay! Auth succeeded! Let's store the tokens @teams[team_id] = { :user_access_token => response['access_token'], :bot_user_id => response['bot']['bot_user_id'], :bot_access_token => response['bot']['bot_access_token'] } else raise "The authentication must either be a cached auth object or a token, not #{auth.class}" end # Create each Team's bot user and authorize the app to access the Team's Events. @teams.each do |team_id, team| begin team[:client] = create_slack_client(team[:bot_access_token]) team[:user] = create_slack_client(team[:user_access_token]) team[:name] = team_name(team_id) $logger.info "Authenticated tokens for team '#{team[:name]}'." $logger.debug JSON.pretty_generate(@teams[team_id]) rescue Slack::Web::Api::Error => e $logger.error "Cached authentication failed for team '#{team[:name] || team_id}'." end end # return the hash structure w/o the client object for caching team(team_id) end |
#channel_info(team_id, channel_id) ⇒ Object
247 248 249 |
# File 'lib/driftwood/slack.rb', line 247 def channel_info(team_id, channel_id) @teams[team_id][:client].channels_info(channel: channel_id)['channel'] end |
#channel_name(team_id, channel_id) ⇒ Object
260 261 262 |
# File 'lib/driftwood/slack.rb', line 260 def channel_name(team_id, channel_id) channel_info(team_id, channel_id)['name'] rescue channel_id end |
#channels(team_id) ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/driftwood/slack.rb', line 175 def channels(team_id) preserve = ['team_id', 'channel_id', 'name', 'created', 'is_private', 'topic', 'purpose', 'num_members'] channels = @teams[team_id][:client].conversations_list(:types => 'public_channel, private_channel') channels = channels['channels'].reject{|i| i['is_archived']} channels.each do |row| row['team_id'] = team_id row['topic'] = row['topic']['value'] row['purpose'] = row['purpose']['value'] row['channel_id'] = row.delete('id') row.select! {|field| preserve.include? field} end end |
#create_slack_client(slack_api_secret) ⇒ Object
84 85 86 87 88 89 90 |
# File 'lib/driftwood/slack.rb', line 84 def create_slack_client(slack_api_secret) Slack.configure do |config| config.token = slack_api_secret fail 'Missing API token' unless config.token end Slack::Web::Client.new end |
#event(request_data) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/driftwood/slack.rb', line 92 def event(request_data) # Check the verification token provided with the request to make sure it matches the verification token in # your app's setting to confirm that the request came from Slack. unless @config[:verification_token] == request_data['token'] $logger.warn "Invalid Slack verification token received: #{request_data['token']}" raise "Invalid Slack verification token received: #{request_data['token']}" end case request_data['type'] # When you enter your Events webhook URL into your app's Event Subscription settings, Slack verifies the # URL's authenticity by sending a challenge token to your endpoint, expecting your app to echo it back. # More info: https://api.slack.com/events/url_verification when 'url_verification' $logger.debug "Authorizing challenge: #{request_data['challenge']}" return request_data['challenge'] when 'event_callback' # Get the Team ID and Event data from the request object team_id = request_data['team_id'] event_data = request_data['event'] event_type = event_data['type'] user_id = event_data['user'] # Don't process events from our bot user unless user_id == @teams[team_id][:bot_user_id] if @handlers.include? event_type begin @handlers[event_type].each do |handler| handler.call(team_id, event_data) end rescue => e $logger.error "Handler for #{event_type} failed: #{e.}" $logger.debug e.backtrace.join("\n") end else $logger.info "Unhandled event:" $logger.debug JSON.pretty_generate(request_data) end end end 'ok' end |
#messages(team_id, starting_from = 0) ⇒ Object
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/driftwood/slack.rb', line 204 def (team_id, starting_from = 0) = [] channels = channels(team_id).map{|c| c['channel_id']} channels.each do |channel_id| oldest = starting_from data = { 'has_more' => true } while data['has_more'] do # note that we need the *user* scope here data = @teams[team_id][:user].channels_history(:channel => channel_id, :count => 1000, :oldest => oldest) oldest = data['messages'].last['ts'] rescue oldest .concat (team_id, channel_id, data['messages']) end end end |
#my_ims ⇒ Object
307 308 309 310 311 |
# File 'lib/driftwood/slack.rb', line 307 def my_ims @teams.map do |team_id, team| team[:client].im_list['ims'].map { |im| im['id'] } end.flatten end |
#normalize_message(team_id, message) ⇒ Object
291 292 293 294 295 296 297 298 |
# File 'lib/driftwood/slack.rb', line 291 def (team_id, ) preserve_fields = [ 'team_id', 'user_id', 'text', 'channel_id','ts' ] ['team_id'] = team_id ['user_id'] = .delete('user') ['channel_id'] = .delete('channel') .select! {|field| preserve_fields.include? field} end |
#normalize_messages(team_id, channel_id, messages) ⇒ Object
300 301 302 303 304 305 |
# File 'lib/driftwood/slack.rb', line 300 def (team_id, channel_id, ) .map do || ['channel'] = channel_id (team_id, ) end end |
#normalize_user(user) ⇒ Object
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/driftwood/slack.rb', line 268 def normalize_user(user) # Why slack? Why? return if user['deleted'] preserve_fields = [ 'team_id', 'user_id', 'name', 'real_name','display_name', 'updated', 'deleted', 'tz', 'tz_offset', 'is_owner', 'is_admin', 'status_text', 'status_emoji', 'image_72', 'image_192', 'title', 'phone', 'skype', 'email', ] user['user_id'] = user.delete('id') user['title'] = user['profile']['title'] user['phone'] = user['profile']['phone'] user['skype'] = user['profile']['skype'] user['email'] = user['profile']['email'] user['display_name'] = user['profile']['display_name'] user['status_text'] = user['profile']['status_text'] user['status_emoji'] = user['profile']['status_emoji'] user['image_72'] = user['profile']['image_72'] user['image_192'] = user['profile']['image_192'] user.select! {|field| preserve_fields.include? field} end |
#real_name(team_id, user_id) ⇒ Object
256 257 258 |
# File 'lib/driftwood/slack.rb', line 256 def real_name(team_id, user_id) user_info(team_id, user_id)['real_name'] rescue user_id end |
#register_handler(event, &block) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/driftwood/slack.rb', line 72 def register_handler(event, &block) raise ArgumentError, "Handler (#{event}): no block passed" unless block_given? raise ArgumentError, "Handler (#{event}): incorrect parameters" unless block.parameters.length == 2 @handlers[event] ||= Array.new @handlers[event] << block $logger.info "Registered slack handler for #{event}" $logger.debug 'Current handlers:' $logger.debug @handlers.inspect end |
#send_response(team_id, channel, text, unfurl_links = false, attachment = nil, ts = nil) ⇒ Object
Send a response to an Event via the Web API.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/driftwood/slack.rb', line 137 def send_response(team_id, channel, text, unfurl_links = false, = nil, ts = nil) # `ts` is optional, depending on whether we're sending the initial # welcome message or updating the existing welcome message tutorial items. # We open a new DM with `chat.postMessage` and update an existing DM with # `chat.update`. if ts @teams[team_id][:client].chat_update( as_user: 'true', channel: channel, ts: ts, text: text, attachments: , unfurl_links: unfurl_links, ) else @teams[team_id][:client].chat_postMessage( as_user: 'true', channel: channel, text: text, attachments: , unfurl_links: unfurl_links, ) end end |
#shell ⇒ Object
318 319 320 321 |
# File 'lib/driftwood/slack.rb', line 318 def shell require 'pry' binding.pry end |
#team(team_id) ⇒ Object
162 163 164 |
# File 'lib/driftwood/slack.rb', line 162 def team(team_id) teams.select {|team| team[:team_id] == team_id }.first end |
#team_info(team_id) ⇒ Object
251 252 253 |
# File 'lib/driftwood/slack.rb', line 251 def team_info(team_id) @teams[team_id][:client].team_info()['team'] end |
#team_name(team_id) ⇒ Object
264 265 266 |
# File 'lib/driftwood/slack.rb', line 264 def team_name(team_id) team_info(team_id)['name'] rescue team_id end |
#teams ⇒ Object
166 167 168 169 170 171 172 173 |
# File 'lib/driftwood/slack.rb', line 166 def teams() # munge into an array of hashes, easier for external tools to use. # ensure that the client object is removed to prevent serialization issues # This weird copy-like thing is to prevent mutation of the original object @teams.map do |team_id, team| {:team_id => team_id}.merge(team.reject { |key,value| [:client, :user].include? key }) end end |
#to_me?(event_data) ⇒ Boolean
313 314 315 316 |
# File 'lib/driftwood/slack.rb', line 313 def to_me?(event_data) return false unless event_data['channel_type'] == 'im' my_ims.include? event_data['channel'] end |
#user_info(team_id, user_id) ⇒ Object
243 244 245 |
# File 'lib/driftwood/slack.rb', line 243 def user_info(team_id, user_id) @teams[team_id][:client].users_info(user: user_id)['user'] end |
#users(team_id) ⇒ Object
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/driftwood/slack.rb', line 188 def users(team_id) users = [] cursor = nil loop do data = @teams[team_id][:client].users_list(limit: 500, cursor: cursor) cursor = data['response_metadata']['next_cursor'] users.concat data['members'] break if (cursor.nil? or cursor.empty?) end users.each do |row| normalize_user(row) end.compact end |