slack-ruby-bot-server 0.9.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.rubocop_todo.yml +44 -7
  4. data/.travis.yml +7 -5
  5. data/CHANGELOG.md +48 -19
  6. data/Gemfile +3 -3
  7. data/LICENSE +1 -1
  8. data/README.md +147 -23
  9. data/UPGRADING.md +42 -2
  10. data/images/create-app.png +0 -0
  11. data/lib/slack-ruby-bot-server.rb +9 -11
  12. data/lib/slack-ruby-bot-server/api.rb +4 -4
  13. data/lib/slack-ruby-bot-server/api/endpoints.rb +3 -3
  14. data/lib/slack-ruby-bot-server/api/endpoints/teams_endpoint.rb +20 -5
  15. data/lib/slack-ruby-bot-server/api/helpers.rb +4 -4
  16. data/lib/slack-ruby-bot-server/api/helpers/cursor_helpers.rb +2 -0
  17. data/lib/slack-ruby-bot-server/api/helpers/sort_helpers.rb +1 -0
  18. data/lib/slack-ruby-bot-server/api/middleware.rb +1 -5
  19. data/lib/slack-ruby-bot-server/api/presenters.rb +5 -5
  20. data/lib/slack-ruby-bot-server/api/presenters/status_presenter.rb +1 -0
  21. data/lib/slack-ruby-bot-server/app.rb +0 -27
  22. data/lib/slack-ruby-bot-server/config.rb +10 -0
  23. data/lib/slack-ruby-bot-server/config/database_adapters/activerecord.rb +6 -2
  24. data/lib/slack-ruby-bot-server/config/database_adapters/mongoid.rb +4 -2
  25. data/lib/slack-ruby-bot-server/models/team/activerecord.rb +8 -5
  26. data/lib/slack-ruby-bot-server/models/team/methods.rb +0 -13
  27. data/lib/slack-ruby-bot-server/models/team/mongoid.rb +11 -4
  28. data/lib/slack-ruby-bot-server/server.rb +1 -0
  29. data/lib/slack-ruby-bot-server/service.rb +51 -9
  30. data/lib/slack-ruby-bot-server/version.rb +1 -1
  31. data/public/index.html.erb +1 -0
  32. data/public/scripts/messages.js +33 -0
  33. data/public/scripts/register.js +3 -32
  34. data/sample_apps/sample_app_activerecord/Gemfile +1 -0
  35. data/sample_apps/sample_app_activerecord/README.md +1 -0
  36. data/sample_apps/sample_app_activerecord/config.ru +8 -1
  37. data/sample_apps/sample_app_activerecord/config/postgresql.yml +1 -1
  38. data/sample_apps/sample_app_activerecord/db/migrate/20170307164946_create_teams_table.rb +0 -1
  39. data/sample_apps/sample_app_activerecord/db/migrate/20190323181453_add_activated_fields.rb +7 -0
  40. data/sample_apps/sample_app_activerecord/db/schema.rb +6 -3
  41. data/sample_apps/sample_app_mongoid/Gemfile +1 -0
  42. data/slack-ruby-bot-server.gemspec +2 -3
  43. metadata +10 -25
  44. data/app.json +0 -9
  45. data/images/new.png +0 -0
  46. data/lib/slack-ruby-bot-server/models.rb +0 -1
@@ -1,9 +1,49 @@
1
1
  Upgrading Slack-Ruby-Bot-Server
2
2
  ===============================
3
3
 
4
+ ### Upgrading to >= 0.11.0
5
+
6
+ #### Removed Legacy Migrations
7
+
8
+ Several legacy migrations have been removed, including the code to automatically create a team from a legacy `SLACK_API_TOKEN`, setting `Team#active`, `name` and `team_id`.
9
+
10
+ See [#101](https://github.com/slack-ruby/slack-ruby-bot-server/pull/101) for more information.
11
+
12
+ #### Unicorn Dependency
13
+
14
+ The dependency on `unicorn` has been removed from gemspec. Use `unicorn` or `puma` or another application server as you see fit by explicitly adding a dependency in your Gemfile.
15
+
16
+ See [#98](https://github.com/slack-ruby/slack-ruby-bot-server/pull/98) for more information.
17
+
18
+ ### Upgrading to >= 0.10.0
19
+
20
+ #### New Team Fields
21
+
22
+ The following fields have been added to `Team`.
23
+
24
+ * `bot_user_id`: the bot `user_id` during installation
25
+ * `activated_user_id`: the installing Slack user `user_id`
26
+ * `activated_user_access_token`: the installing Slack user `access_token`
27
+
28
+ No action is required for Mongoid.
29
+
30
+ If you're using ActiveRecord, create a migration similar to [sample_apps/sample_app_activerecord/db/migrate/20190323181453_add_activated_fields.rb](sample_apps/sample_app_activerecord/db/migrate/20190323181453_add_activated_fields.rb) to add these fields.
31
+
32
+ ```ruby
33
+ class AddActivatedFields < ActiveRecord::Migration[5.0]
34
+ def change
35
+ add_column :teams, :bot_user_id, :string
36
+ add_column :teams, :activated_user_id, :string
37
+ add_column :teams, :activated_user_access_token, :string
38
+ end
39
+ end
40
+ ```
41
+
42
+ See [#96](https://github.com/slack-ruby/slack-ruby-bot-server/pull/96) for more information.
43
+
4
44
  ### Upgrading to >= 0.9.0
5
45
 
6
- ### Removed Ping Worker
46
+ #### Removed Ping Worker
7
47
 
8
48
  The ping worker that was added in 0.7.0 has been removed in favor of a lower level implementation in slack-ruby-client. Remove any references to `ping` options.
9
49
 
@@ -11,7 +51,7 @@ See [slack-ruby-client#226](https://github.com/slack-ruby/slack-ruby-client/pull
11
51
 
12
52
  ### Upgrading to >= 0.8.0
13
53
 
14
- ### Different Asynchronous I/O Library
54
+ #### Different Asynchronous I/O Library
15
55
 
16
56
  The library now uses [async-websocket](https://github.com/socketry/async-websocket) instead of [celluloid-io](https://github.com/celluloid/celluloid-io). If your application is built on Celluloid you may need to make changes and use `Async::Reactor.run` and the likes.
17
57
 
Binary file
@@ -2,15 +2,13 @@ require 'async/websocket'
2
2
 
3
3
  require 'grape-swagger'
4
4
  require 'slack-ruby-bot'
5
- require 'slack-ruby-bot-server/server'
6
- require 'slack-ruby-bot-server/config'
7
5
 
8
- require 'slack-ruby-bot-server/ext'
9
- require 'slack-ruby-bot-server/version'
10
- require 'slack-ruby-bot-server/info'
11
-
12
- require "slack-ruby-bot-server/config/database_adapters/#{SlackRubyBotServer::Config.database_adapter}.rb"
13
-
14
- require 'slack-ruby-bot-server/api'
15
- require 'slack-ruby-bot-server/app'
16
- require 'slack-ruby-bot-server/service'
6
+ require_relative 'slack-ruby-bot-server/service'
7
+ require_relative 'slack-ruby-bot-server/server'
8
+ require_relative 'slack-ruby-bot-server/config'
9
+ require_relative 'slack-ruby-bot-server/ext'
10
+ require_relative 'slack-ruby-bot-server/version'
11
+ require_relative 'slack-ruby-bot-server/info'
12
+ require_relative "slack-ruby-bot-server/config/database_adapters/#{SlackRubyBotServer::Config.database_adapter}.rb"
13
+ require_relative 'slack-ruby-bot-server/api'
14
+ require_relative 'slack-ruby-bot-server/app'
@@ -3,7 +3,7 @@ require 'roar'
3
3
  require 'grape-roar'
4
4
 
5
5
  require_relative 'ext/grape/sort_extension'
6
- require 'slack-ruby-bot-server/api/helpers'
7
- require 'slack-ruby-bot-server/api/presenters'
8
- require 'slack-ruby-bot-server/api/endpoints'
9
- require 'slack-ruby-bot-server/api/middleware'
6
+ require_relative 'api/helpers'
7
+ require_relative 'api/presenters'
8
+ require_relative 'api/endpoints'
9
+ require_relative 'api/middleware'
@@ -1,3 +1,3 @@
1
- require 'slack-ruby-bot-server/api/endpoints/teams_endpoint'
2
- require 'slack-ruby-bot-server/api/endpoints/status_endpoint'
3
- require 'slack-ruby-bot-server/api/endpoints/root_endpoint'
1
+ require_relative 'endpoints/teams_endpoint'
2
+ require_relative 'endpoints/status_endpoint'
3
+ require_relative 'endpoints/root_endpoint'
@@ -33,6 +33,7 @@ module SlackRubyBotServer
33
33
  desc 'Create a team using an OAuth token.'
34
34
  params do
35
35
  requires :code, type: String
36
+ optional :state, type: String
36
37
  end
37
38
  post do
38
39
  client = Slack::Web::Client.new
@@ -46,21 +47,35 @@ module SlackRubyBotServer
46
47
  )
47
48
 
48
49
  token = rc['bot']['bot_access_token']
50
+ bot_user_id = rc['bot']['bot_user_id']
51
+ user_id = rc['user_id']
52
+ access_token = rc['access_token']
49
53
  team = Team.where(token: token).first
50
54
  team ||= Team.where(team_id: rc['team_id']).first
51
- if team && !team.active?
55
+
56
+ if team
57
+ team.update_attributes!(
58
+ activated_user_id: user_id,
59
+ activated_user_access_token: access_token,
60
+ bot_user_id: bot_user_id
61
+ )
62
+ raise "Team #{team.name} is already registered." if team.active?
63
+
52
64
  team.activate!(token)
53
- elsif team
54
- raise "Team #{team.name} is already registered."
55
65
  else
56
66
  team = Team.create!(
57
67
  token: token,
58
68
  team_id: rc['team_id'],
59
- name: rc['team_name']
69
+ name: rc['team_name'],
70
+ activated_user_id: user_id,
71
+ activated_user_access_token: access_token,
72
+ bot_user_id: bot_user_id
60
73
  )
61
74
  end
62
75
 
63
- Service.instance.create!(team)
76
+ options = params.slice(:state)
77
+
78
+ Service.instance.create!(team, options)
64
79
  present team, with: Presenters::TeamPresenter
65
80
  end
66
81
  end
@@ -1,4 +1,4 @@
1
- require 'slack-ruby-bot-server/api/helpers/cursor_helpers'
2
- require 'slack-ruby-bot-server/api/helpers/pagination_parameters'
3
- require 'slack-ruby-bot-server/api/helpers/sort_helpers'
4
- require 'slack-ruby-bot-server/api/helpers/error_helpers'
1
+ require_relative 'helpers/cursor_helpers'
2
+ require_relative 'helpers/pagination_parameters'
3
+ require_relative 'helpers/sort_helpers'
4
+ require_relative 'helpers/error_helpers'
@@ -11,6 +11,7 @@ module SlackRubyBotServer
11
11
  if SlackRubyBotServer::Config.mongoid?
12
12
  def paginate_by_cursor(coll, _options)
13
13
  raise 'Both cursor and offset parameters are present, these are mutually exclusive.' if params.key?(:offset) && params.key?(:cursor)
14
+
14
15
  results = { results: [], next: nil }
15
16
  coll = coll.skip(params[:offset].to_i) if params.key?(:offset)
16
17
  size = (params[:size] || 10).to_i
@@ -26,6 +27,7 @@ module SlackRubyBotServer
26
27
  elsif SlackRubyBotServer::Config.activerecord?
27
28
  def paginate_by_cursor(coll, options)
28
29
  raise 'Both cursor and offset parameters are present, these are mutually exclusive.' if params.key?(:offset) && params.key?(:cursor)
30
+
29
31
  results = { results: [], next: nil }
30
32
  size = (params[:size] || 10).to_i
31
33
  results[:total_count] = coll.count(:all) if params[:total_count]
@@ -7,6 +7,7 @@ module SlackRubyBotServer
7
7
  def sort_order(options = {})
8
8
  params[:sort] = options[:default_sort_order] unless params[:sort]
9
9
  return [] unless params[:sort]
10
+
10
11
  sort_order = params[:sort].to_s
11
12
  unless options[:default_sort_order] == sort_order
12
13
  supported_sort_orders = route_sort
@@ -30,11 +30,7 @@ module SlackRubyBotServer
30
30
  end
31
31
 
32
32
  use Rack::ServerPages do |config|
33
- config.view_path = [
34
- 'views', # relative to Dir.pwd
35
- 'public', # relative to Dir.pwd
36
- File.expand_path(File.join(__dir__, '../../../public')) # built-in fallback
37
- ]
33
+ config.view_path = SlackRubyBotServer::Config.view_paths
38
34
  end
39
35
 
40
36
  run Middleware.new
@@ -2,8 +2,8 @@ require 'roar/representer'
2
2
  require 'roar/json'
3
3
  require 'roar/json/hal'
4
4
 
5
- require 'slack-ruby-bot-server/api/presenters/paginated_presenter'
6
- require 'slack-ruby-bot-server/api/presenters/status_presenter'
7
- require 'slack-ruby-bot-server/api/presenters/team_presenter'
8
- require 'slack-ruby-bot-server/api/presenters/teams_presenter'
9
- require 'slack-ruby-bot-server/api/presenters/root_presenter'
5
+ require_relative 'presenters/paginated_presenter'
6
+ require_relative 'presenters/status_presenter'
7
+ require_relative 'presenters/team_presenter'
8
+ require_relative 'presenters/teams_presenter'
9
+ require_relative 'presenters/root_presenter'
@@ -23,6 +23,7 @@ module SlackRubyBotServer
23
23
  raise 'Unsupported database driver.'
24
24
  end
25
25
  return unless team
26
+
26
27
  team.ping!
27
28
  end
28
29
 
@@ -3,9 +3,6 @@ module SlackRubyBotServer
3
3
  def prepare!
4
4
  check_database!
5
5
  init_database!
6
- mark_teams_active!
7
- migrate_from_single_team!
8
- update_team_name_and_id!
9
6
  purge_inactive_teams!
10
7
  configure_global_aliases!
11
8
  end
@@ -31,30 +28,6 @@ module SlackRubyBotServer
31
28
  SlackRubyBotServer::DatabaseAdapter.init!
32
29
  end
33
30
 
34
- def mark_teams_active!
35
- Team.where(active: nil).update_all(active: true)
36
- end
37
-
38
- def update_team_name_and_id!
39
- Team.active.where(team_id: nil).each do |team|
40
- begin
41
- auth = team.ping![:auth]
42
- team.update_attributes!(team_id: auth['team_id'], name: auth['team'])
43
- rescue StandardError => e
44
- logger.warn "Error pinging team #{team.id}: #{e.message}."
45
- team.set(active: false)
46
- end
47
- end
48
- end
49
-
50
- def migrate_from_single_team!
51
- return unless ENV.key?('SLACK_API_TOKEN')
52
- logger.info 'Migrating from env SLACK_API_TOKEN ...'
53
- team = Team.find_or_create_from_env!
54
- logger.info "Automatically migrated team: #{team}."
55
- logger.warn "You should unset ENV['SLACK_API_TOKEN']."
56
- end
57
-
58
31
  def purge_inactive_teams!
59
32
  Team.purge!
60
33
  end
@@ -3,10 +3,20 @@ module SlackRubyBotServer
3
3
  extend self
4
4
 
5
5
  attr_accessor :server_class
6
+ attr_accessor :service_class
6
7
  attr_accessor :database_adapter
8
+ attr_accessor :view_paths
7
9
 
8
10
  def reset!
9
11
  self.server_class = SlackRubyBotServer::Server
12
+ self.service_class = SlackRubyBotServer::Service
13
+
14
+ self.view_paths = [
15
+ 'views',
16
+ 'public',
17
+ File.expand_path(File.join(__dir__, '../../public'))
18
+ ]
19
+
10
20
  self.database_adapter = if defined?(::Mongoid)
11
21
  :mongoid
12
22
  elsif defined?(::ActiveRecord)
@@ -1,4 +1,4 @@
1
- require 'slack-ruby-bot-server/models/team/activerecord.rb'
1
+ require_relative '../../models/team/activerecord.rb'
2
2
 
3
3
  module SlackRubyBotServer
4
4
  module DatabaseAdapter
@@ -12,11 +12,15 @@ module SlackRubyBotServer
12
12
 
13
13
  def self.init!
14
14
  return if ActiveRecord::Base.connection.tables.include?('teams')
15
+
15
16
  ActiveRecord::Base.connection.create_table :teams do |t|
16
17
  t.string :team_id
17
18
  t.string :name
18
19
  t.string :domain
19
20
  t.string :token
21
+ t.string :bot_user_id
22
+ t.string :activated_user_id
23
+ t.string :activated_user_access_token
20
24
  t.boolean :active, default: true
21
25
  t.timestamps
22
26
  end
@@ -24,4 +28,4 @@ module SlackRubyBotServer
24
28
  end
25
29
  end
26
30
 
27
- ::Boolean = Virtus::Attribute::Boolean
31
+ ::Boolean = Grape::API::Boolean
@@ -1,4 +1,5 @@
1
- require 'slack-ruby-bot-server/models/team/mongoid.rb'
1
+ require_relative '../../models/team/mongoid.rb'
2
+
2
3
  require 'kaminari/grape'
3
4
  require 'mongoid-scroll'
4
5
 
@@ -6,7 +7,8 @@ module SlackRubyBotServer
6
7
  module DatabaseAdapter
7
8
  def self.check!
8
9
  rc = Mongoid.default_client.command(ping: 1)
9
- return if rc && rc.ok?
10
+ return if rc&.ok?
11
+
10
12
  raise rc.documents.first['error'] || 'Unexpected error.'
11
13
  rescue StandardError => e
12
14
  warn "Error connecting to MongoDB: #{e.message}"
@@ -3,11 +3,14 @@ require_relative 'methods'
3
3
  class Team < ActiveRecord::Base
4
4
  include Methods
5
5
 
6
- def self.purge!
7
- # destroy teams inactive for two weeks
8
- Team.where(active: false).where('updated_at <= ?', 2.weeks.ago).each do |team|
9
- puts "Destroying #{team}, inactive since #{team.updated_at}, over two weeks ago."
10
- team.destroy
6
+ def self.purge!(dt = 2.weeks.ago)
7
+ Team.where(active: false).where('updated_at <= ?', dt).each do |team|
8
+ begin
9
+ logger.info "Destroying #{team}, inactive since #{team.updated_at}."
10
+ team.destroy
11
+ rescue StandardError => e
12
+ logger.warn "Error destroying #{team}, #{e.message}."
13
+ end
11
14
  end
12
15
  end
13
16
  end
@@ -38,18 +38,5 @@ module Methods
38
38
  presence: client.users_getPresence(user: auth['user_id'])
39
39
  }
40
40
  end
41
-
42
- def self.find_or_create_from_env!
43
- token = ENV['SLACK_API_TOKEN']
44
- return unless token
45
- team = Team.where(token: token).first
46
- team ||= Team.new(token: token)
47
- info = Slack::Web::Client.new(token: token).team_info
48
- team.team_id = info['team']['id']
49
- team.name = info['team']['name']
50
- team.domain = info['team']['domain']
51
- team.save!
52
- team
53
- end
54
41
  end
55
42
  end
@@ -9,14 +9,21 @@ class Team
9
9
  field :domain, type: String
10
10
  field :token, type: String
11
11
  field :active, type: Boolean, default: true
12
+ field :bot_user_id, type: String
13
+ field :activated_user_id, type: String
14
+ field :activated_user_access_token, type: String
12
15
 
13
16
  include Methods
14
17
 
15
- def self.purge!
18
+ def self.purge!(dt = 2.weeks.ago)
16
19
  # destroy teams inactive for two weeks
17
- Team.where(active: false, :updated_at.lte => 2.weeks.ago).each do |team|
18
- Mongoid.logger.info "Destroying #{team}, inactive since #{team.updated_at}, over two weeks ago."
19
- team.destroy
20
+ Team.where(active: false, :updated_at.lte => dt).each do |team|
21
+ begin
22
+ logger.info "Destroying #{team}, inactive since #{team.updated_at}."
23
+ team.destroy
24
+ rescue StandardError => e
25
+ logger.warn "Error destroying #{team}, #{e.message}."
26
+ end
20
27
  end
21
28
  end
22
29
  end
@@ -8,6 +8,7 @@ module SlackRubyBotServer
8
8
  attrs = attrs.dup
9
9
  @team = attrs.delete(:team)
10
10
  raise 'Missing team' unless @team
11
+
11
12
  attrs[:token] = @team.token
12
13
  super(attrs)
13
14
  open!
@@ -10,21 +10,40 @@ module SlackRubyBotServer
10
10
  end
11
11
 
12
12
  def self.instance
13
- @instance ||= new
13
+ @instance ||= SlackRubyBotServer::Config.service_class.new
14
14
  end
15
15
 
16
16
  def initialize
17
17
  @callbacks = Hash.new { |h, k| h[k] = [] }
18
+ @intervals = Hash.new { |h, k| h[k] = [] }
18
19
  end
19
20
 
20
- def on(type, &block)
21
- @callbacks[type.to_s] << block
21
+ def on(*types, &block)
22
+ Array(types).each do |type|
23
+ @callbacks[type.to_s] << block
24
+ end
25
+ end
26
+
27
+ def every(*intervals, &block)
28
+ Array(intervals).each do |interval|
29
+ case interval
30
+ when :minute
31
+ interval = 60
32
+ when :hour
33
+ interval = 60 * 60
34
+ when :day
35
+ interval = 60 * 60 * 24
36
+ end
37
+ raise "Invalid interval \"#{interval}\"." unless interval.is_a?(Integer) && interval > 0
38
+
39
+ @intervals[interval] << block
40
+ end
22
41
  end
23
42
 
24
- def create!(team)
25
- run_callbacks :creating, team
43
+ def create!(team, options = {})
44
+ run_callbacks :creating, team, nil, options
26
45
  start!(team)
27
- run_callbacks :created, team
46
+ run_callbacks :created, team, nil, options
28
47
  end
29
48
 
30
49
  def start!(team)
@@ -49,7 +68,7 @@ module SlackRubyBotServer
49
68
  def stop!(team)
50
69
  logger.info "Stopping team #{team}."
51
70
  run_callbacks :stopping, team
52
- team.server.stop! if team.server
71
+ team.server&.stop!
53
72
  run_callbacks :stopped, team
54
73
  rescue StandardError => e
55
74
  run_callbacks :error, team, e
@@ -64,6 +83,15 @@ module SlackRubyBotServer
64
83
  start!(team)
65
84
  run_callbacks :booted, team
66
85
  end
86
+ start_intervals!
87
+ end
88
+
89
+ def start_intervals!
90
+ @intervals.each_pair do |period, calls|
91
+ _every period do
92
+ calls.each(&:call)
93
+ end
94
+ end
67
95
  end
68
96
 
69
97
  def deactivate!(team)
@@ -86,6 +114,19 @@ module SlackRubyBotServer
86
114
 
87
115
  private
88
116
 
117
+ def _every(tt, &_block)
118
+ ::Async::Reactor.run do |task|
119
+ loop do
120
+ begin
121
+ task.sleep tt
122
+ yield
123
+ rescue StandardError => e
124
+ logger.error e
125
+ end
126
+ end
127
+ end
128
+ end
129
+
89
130
  def start_server!(team, server, wait = 1)
90
131
  team.server = server
91
132
  server.start_async
@@ -103,11 +144,12 @@ module SlackRubyBotServer
103
144
  end
104
145
  end
105
146
 
106
- def run_callbacks(type, team = nil, error = nil)
147
+ def run_callbacks(type, team = nil, error = nil, options = {})
107
148
  callbacks = @callbacks[type.to_s]
108
149
  return false unless callbacks
150
+
109
151
  callbacks.each do |c|
110
- c.call team, error
152
+ c.call team, error, options
111
153
  end
112
154
  true
113
155
  rescue StandardError => e