Skip to content

Commit e6eea3e

Browse files
committed
Handle non-RTM bot registration.
1 parent f023da5 commit e6eea3e

File tree

9 files changed

+165
-28
lines changed

9 files changed

+165
-28
lines changed

.rubocop_todo.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config`
3-
# on 2020-11-14 17:01:04 -0500 using RuboCop version 0.81.0.
3+
# on 2020-11-15 11:38:22 -0500 using RuboCop version 0.81.0.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
@@ -32,14 +32,12 @@ Naming/FileName:
3232
Exclude:
3333
- 'lib/slack-ruby-bot-server.rb'
3434

35-
# Offense count: 3
35+
# Offense count: 1
3636
# Configuration parameters: ForbiddenDelimiters.
3737
# ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
3838
Naming/HeredocDelimiterNaming:
3939
Exclude:
4040
- 'lib/slack-ruby-bot-server/info.rb'
41-
- 'sample_apps/sample_app_activerecord/commands/help.rb'
42-
- 'sample_apps/sample_app_mongoid/commands/help.rb'
4341

4442
# Offense count: 3
4543
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.

README.md

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ Build a complete Slack bot service with Slack button integration, in Ruby.
1111

1212
- [What is this?](#what-is-this)
1313
- [Stable Release](#stable-release)
14-
- [Try Me](#try-me)
15-
- [Run Your Own](#run-your-own)
14+
- [Make Your Own](#make-your-own)
15+
- [Storage](#storage)
1616
- [MongoDB](#mongodb)
1717
- [ActiveRecord](#activerecord)
1818
- [Usage](#usage)
19-
- [OAuth Code Grant](#oauth-code-grant)
2019
- [API](#api)
2120
- [App](#app)
2221
- [Service Manager](#service-manager)
2322
- [Lifecycle Callbacks](#lifecycle-callbacks)
2423
- [Service Timers](#service-timers)
2524
- [Extensions](#extensions)
26-
- [Server Class](#server-class)
2725
- [Service Class](#service-class)
2826
- [HTML Templates](#html-templates)
2927
- [Access Tokens](#access-tokens)
30-
- [Example Bots Using Slack Ruby Bot Server](#example-bots-using-slack-ruby-bot-server)
28+
- [Sample Bots Using Slack Ruby Bot Server](#sample-bots-using-slack-ruby-bot-server)
29+
- [Slack Bots with Granular Permissions](#slack-bots-with-granular-permissions)
30+
- [Legacy Slack Bots](#legacy-slack-bots)
3131
- [Copyright & License](#copyright--license)
3232

3333
### What is this?
@@ -79,26 +79,17 @@ Follow Slack's instructions, note the app client ID and secret, give the bot a d
7979

8080
Within your application, edit your `.env` file and add `SLACK_CLIENT_ID=...` and `SLACK_CLIENT_SECRET=...` in it.
8181

82-
Run `bundle install` and `foreman start` to boot the app. Navigate to [localhost:9292](http://localhost:9292). You should see an "Add to Slack" button. Use it to install the app into your own Slack team.
83-
84-
### OAuth Code Grant
85-
8682
Configure your app's [OAuth scopes](https://api.slack.com/legacy/oauth-scopes) as needed by your application.
8783

8884
```ruby
8985
SlackRubyBotServer.configure do |config|
9086
config.oauth_scope = ['channels:read', 'chat:write:user']
87+
end
9188
```
9289

93-
The "Add to Slack" button uses the standard OAuth code grant flow as described in the [Slack docs](https://api.slack.com/docs/oauth#flow).
94-
95-
The button itself contains a link that looks like this:
90+
The "Add to Slack" button uses the standard OAuth code grant flow as described in the [Slack docs](https://api.slack.com/docs/oauth#flow). Once clicked, the user is taken through the authorization process at Slack's site. Upon successful completion, a callback containing a temporary code is sent to the redirect URL you specified. The endpoint at that URL contains code that persists the bot token each time a Slack client is instantiated for the specific team.
9691

97-
```
98-
https://slack.com/oauth/authorize?scope=<%= SlackRubyBotServer::Config.oauth_scope_s %>&client_id=<%= ENV['SLACK_CLIENT_ID'] %>
99-
```
100-
101-
Once clicked, the user is taken through the authorization process at Slack's site. Upon successful completion, a callback containing a temporary code is sent to the redirect URL you specified. The endpoint at that URL contains code that persists the bot token each time a Slack client is instantiated for the specific team.
92+
Run `bundle install` and `foreman start` to boot the app. Navigate to [localhost:9292](http://localhost:9292). You should see an "Add to Slack" button. Use it to install the app into your own Slack team.
10293

10394
### API
10495

@@ -259,7 +250,7 @@ end
259250

260251
### Access Tokens
261252

262-
By default the implementation of [Team](lib/slack-ruby-bot-server/models/team) stores a `bot_access_token` as `token` (for backwards compatibility), and `activated_user_access_token` as the token with all the requested OAuth scopes.
253+
By default the implementation of [Team](lib/slack-ruby-bot-server/models/team) stores the value of the token with all the requested OAuth scopes in both `token` and `activated_user_access_token` (for backwards compatibility). If a legacy Slack bot integration `bot_access_token` is present, it is stored as `token`, and `activated_user_access_token`is the token that has all the requested OAuth scopes.
263254

264255
### Sample Bots Using Slack Ruby Bot Server
265256

lib/slack-ruby-bot-server/api/endpoints/teams_endpoint.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,14 @@ class TeamsEndpoint < Grape::API
4646
code: params[:code]
4747
)
4848

49-
token = rc['bot']['bot_access_token']
50-
bot_user_id = rc['bot']['bot_user_id']
51-
user_id = rc['user_id']
5249
access_token = rc['access_token']
50+
user_id = rc['user_id']
51+
52+
bot = rc['bot']
53+
54+
token = bot ? bot['bot_access_token'] : access_token
55+
bot_user_id = bot['bot_user_id'] if bot
56+
5357
team = Team.where(token: token).first
5458
team ||= Team.where(team_id: rc['team_id']).first
5559

spec/api/endpoints/teams_endpoint_spec.rb

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,106 @@
4545
end
4646
end
4747

48-
context 'register' do
48+
context 'register a bot' do
49+
before do
50+
oauth_access = {
51+
'access_token' => 'access_token',
52+
'user_id' => 'user_id',
53+
'team_id' => 'team_id',
54+
'team_name' => 'team_name'
55+
}
56+
ENV['SLACK_CLIENT_ID'] = 'client_id'
57+
ENV['SLACK_CLIENT_SECRET'] = 'client_secret'
58+
allow_any_instance_of(Slack::Web::Client).to receive(:oauth_access).with(
59+
hash_including(
60+
code: 'code',
61+
client_id: 'client_id',
62+
client_secret: 'client_secret'
63+
)
64+
).and_return(oauth_access)
65+
end
66+
after do
67+
ENV.delete('SLACK_CLIENT_ID')
68+
ENV.delete('SLACK_CLIENT_SECRET')
69+
end
70+
it 'creates a team' do
71+
expect(SlackRubyBotServer::Service.instance).to receive(:start!)
72+
expect do
73+
team = client.teams._post(code: 'code')
74+
expect(team.team_id).to eq 'team_id'
75+
expect(team.name).to eq 'team_name'
76+
team = Team.find(team.id)
77+
expect(team.token).to eq 'access_token'
78+
expect(team.activated_user_access_token).to eq 'access_token'
79+
expect(team.activated_user_id).to eq 'user_id'
80+
expect(team.bot_user_id).to be nil
81+
end.to change(Team, :count).by(1)
82+
end
83+
84+
it 'includes optional state parameter' do
85+
expect(SlackRubyBotServer::Service.instance).to receive(:create!).with(instance_of(Team), state: 'property')
86+
client.teams._post(code: 'code', state: 'property')
87+
end
88+
89+
it 'reactivates a deactivated team' do
90+
expect(SlackRubyBotServer::Service.instance).to receive(:start!)
91+
existing_team = Fabricate(:team, token: 'access_token', active: false)
92+
expect do
93+
team = client.teams._post(code: 'code')
94+
expect(team.team_id).to eq existing_team.team_id
95+
expect(team.name).to eq existing_team.name
96+
expect(team.active).to be true
97+
team = Team.find(team.id)
98+
expect(team.token).to eq 'access_token'
99+
expect(team.active).to be true
100+
expect(team.activated_user_access_token).to eq 'access_token'
101+
expect(team.activated_user_id).to eq 'user_id'
102+
expect(team.bot_user_id).to be nil
103+
end.to_not change(Team, :count)
104+
end
105+
it 'reactivates a team deactivated on slack' do
106+
expect(SlackRubyBotServer::Service.instance).to receive(:start!)
107+
existing_team = Fabricate(:team, token: 'access_token')
108+
expect do
109+
expect_any_instance_of(Team).to receive(:ping!) { raise Slack::Web::Api::Errors::SlackError, 'invalid_auth' }
110+
team = client.teams._post(code: 'code')
111+
expect(team.team_id).to eq existing_team.team_id
112+
expect(team.name).to eq existing_team.name
113+
expect(team.active).to be true
114+
team = Team.find(team.id)
115+
expect(team.token).to eq 'access_token'
116+
expect(team.active).to be true
117+
expect(team.bot_user_id).to be nil
118+
expect(team.activated_user_id).to eq 'user_id'
119+
end.to_not change(Team, :count)
120+
end
121+
it 'returns a useful error when team already exists' do
122+
expect_any_instance_of(Team).to receive(:ping_if_active!)
123+
existing_team = Fabricate(:team, token: 'access_token')
124+
expect { client.teams._post(code: 'code') }.to raise_error Faraday::ClientError do |e|
125+
json = JSON.parse(e.response[:body])
126+
expect(json['message']).to eq "Team #{existing_team.name} is already registered."
127+
end
128+
end
129+
it 'reactivates a deactivated team with a different code' do
130+
expect(SlackRubyBotServer::Service.instance).to receive(:start!)
131+
existing_team = Fabricate(:team, token: 'old', team_id: 'team_id', active: false)
132+
expect do
133+
team = client.teams._post(code: 'code')
134+
expect(team.team_id).to eq existing_team.team_id
135+
expect(team.name).to eq existing_team.name
136+
expect(team.active).to be true
137+
team = Team.find(team.id)
138+
expect(team.token).to eq 'access_token'
139+
expect(team.active).to be true
140+
expect(team.activated_user_access_token).to eq 'access_token'
141+
expect(team.activated_user_id).to eq 'user_id'
142+
expect(team.bot_user_id).to be nil
143+
end.to_not change(Team, :count)
144+
end
145+
end
146+
147+
context 'register a legacy bot' do
49148
before do
50149
oauth_access = {
51150
'bot' => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
db_config = YAML.safe_load(File.read(File.expand_path('../../../sample_apps/sample_app_activerecord/config/postgresql.yml', __dir__)), [], [], true)[ENV['RACK_ENV']]
1+
db_config = YAML.safe_load(File.read(File.expand_path('config/postgresql.yml', __dir__)), [], [], true)[ENV['RACK_ENV']]
22
ActiveRecord::Tasks::DatabaseTasks.create(db_config)
33
ActiveRecord::Base.establish_connection(db_config)
44
ActiveRecord::Base.logger.level = :info
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
default: &default
2+
adapter: postgresql
3+
pool: 10
4+
timeout: 5000
5+
encoding: unicode
6+
7+
development:
8+
<<: *default
9+
database: slack_ruby_bot_server_development
10+
11+
test:
12+
<<: *default
13+
database: slack_ruby_bot_server_test
14+
15+
production:
16+
<<: *default
17+
url: <%= ENV["DATABASE_URL"] %>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
development:
2+
clients:
3+
default:
4+
database: bot-server_development
5+
hosts:
6+
- 127.0.0.1:27017
7+
options:
8+
raise_not_found_error: false
9+
use_utc: true
10+
11+
test:
12+
clients:
13+
default:
14+
database: bot-server_test
15+
hosts:
16+
- 127.0.0.1:27017
17+
options:
18+
raise_not_found_error: false
19+
use_utc: true
20+
21+
production:
22+
clients:
23+
default:
24+
uri: <%= ENV['MONGO_URL'] || ENV['MONGOHQ_URI'] || ENV['MONGOLAB_URI'] || ENV['MONGODB_URI'] %>
25+
options:
26+
raise_not_found_error: false
27+
use_utc: true
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
Mongo::Logger.logger.level = Logger::INFO
2-
Mongoid.load!(File.expand_path('../../../sample_apps/sample_app_mongoid/config/mongoid.yml', __dir__), ENV['RACK_ENV'])
2+
Mongoid.load!(File.expand_path('config/mongoid.yml', __dir__), ENV['RACK_ENV'])

spec/integration/teams_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
after do
1010
ENV.delete 'SLACK_CLIENT_ID'
1111
ENV.delete 'SLACK_CLIENT_SECRET'
12+
SlackRubyBotServer::Config.oauth_scope = nil
1213
end
1314
context 'oauth' do
1415
before do

0 commit comments

Comments
 (0)