slack-wrapper 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cdc038bb2fcc4cda46b1ebb672d67f68324014a5
4
+ data.tar.gz: 5bb831450a48fe3b92ff3ee5187a6b6621fc0ca8
5
+ SHA512:
6
+ metadata.gz: fdbecf535d28e18ed447ea643d0b10a88e9bad4aac85ab0dafd7bf6858268d68b08a7de026bda4287357de94394589380c11c5375d1dba86957d84dd6dafffb4
7
+ data.tar.gz: 6c43eef3cc80b7a9b7fcc6876c2d46f613d81f80afe2f816057ddc3c4e9084f0d9d15a63c1ef2bd130eb3e3d2d723ee86d793bda4b3efaf328a493dadd24bae4
@@ -0,0 +1,18 @@
1
+ require 'net/https'
2
+ require 'net/http/post/multipart'
3
+ require 'json'
4
+ require 'uri'
5
+
6
+ require_relative 'slack-wrapper/errors.rb'
7
+ require_relative 'slack-wrapper/config.rb'
8
+ require_relative 'slack-wrapper/api.rb'
9
+
10
+ module Slack
11
+ extend self
12
+ def id
13
+ Slack::API::Auth.whoami['id']
14
+ end
15
+ def name
16
+ Slack::API::Auth.whoami['name']
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'api/auth.rb'
2
+ require_relative 'api/bots.rb'
3
+ require_relative 'api/channels.rb'
4
+ require_relative 'api/chat.rb'
5
+ require_relative 'api/files.rb'
6
+ require_relative 'api/im.rb'
7
+ require_relative 'api/permissions.rb'
8
+ require_relative 'api/rtm.rb'
9
+ require_relative 'api/users.rb'
10
+
11
+ module Slack
12
+ module API
13
+ extend self
14
+ end
15
+ class << self
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ module Slack
2
+ module API
3
+ module Auth
4
+ extend self
5
+ def is_valid?
6
+ case Slack::Config.token
7
+ when nil
8
+ false
9
+ when String
10
+ uri = URI.parse('https://slack.com/api/auth.test')
11
+ http = Net::HTTP.new(uri.host, uri.port)
12
+ http.use_ssl = true
13
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
14
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}")
15
+ resp = http.request(req)
16
+ false unless resp.code == 200
17
+ JSON.parse(resp.body)['ok']
18
+ else
19
+ false
20
+ end
21
+ end
22
+ def whoami
23
+ uri = URI.parse('https://slack.com/api/auth.test')
24
+ http = Net::HTTP.new(uri.host, uri.port)
25
+ http.use_ssl = true
26
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
27
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}")
28
+ resp = http.request(req)
29
+ false unless resp.code == 200
30
+ data = JSON.parse(resp.body)
31
+ return {"name" => data['user'], 'id' => data['user_id']}
32
+ end
33
+ is_valid?
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,29 @@
1
+ # https://api.slack.com/methods/bots.info
2
+ module Slack
3
+ module API
4
+ module Bots
5
+ extend self
6
+ def info(opts={})
7
+ if Slack::API::Auth
8
+ opts['token'] = Slack::Config.token
9
+ uri = URI.parse('https://slack.com/api/bots.info')
10
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
11
+ res = Net::HTTP::new(uri.host, uri.port)
12
+ res.use_ssl = true
13
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
14
+ resp = res.start do |http|
15
+ http.request(req)
16
+ end
17
+ false unless resp.code == 200
18
+ if JSON.parse(resp.body)['ok']
19
+ JSON.parse(resp.body)['bot']
20
+ else
21
+ Slack::Errors.new(JSON.parse(resp.body))
22
+ end
23
+ else
24
+ Slack::Errors.new({"error" => "not_authed"})
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,277 @@
1
+ # https://api.slack.com/methods/channels.list
2
+ # https://api.slack.com/methods/channels.create
3
+ # https://api.slack.com/methods/channels.archive
4
+ # https://api.slack.com/methods/channels.unarchive
5
+ # https://api.slack.com/methods/channels.info
6
+ # https://api.slack.com/methods/channels.history
7
+ # https://api.slack.com/methods/channels.join
8
+ # https://api.slack.com/methods/channels.leave
9
+ # https://api.slack.com/methods/channels.invite
10
+ # https://api.slack.com/methods/channels.kick
11
+ # https://api.slack.com/methods/channels.rename
12
+ # https://api.slack.com/methods/channels.setPurpose
13
+ # https://api.slack.com/methods/channels.setTopic
14
+ module Slack
15
+ module API
16
+ module Channels
17
+ extend self
18
+ def get_channels(archived=false)
19
+ if Slack::API::Auth
20
+ uri = URI.parse('https://slack.com/api/channels.list')
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+ http.use_ssl = true
23
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
24
+ if archived
25
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&exclude_members=true"
26
+ else
27
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&exclude_archived=true&exclude_members=true"
28
+ end
29
+ req = Net::HTTP::Post.new(url)
30
+ resp = http.request(req)
31
+ false unless resp.code == 200
32
+ if JSON.parse(resp.body)['ok']
33
+ JSON.parse(resp.body)['channels']
34
+ else
35
+ Slack::Errors.new(JSON.parse(resp.body))
36
+ end
37
+ else
38
+ Slack::Errors.new({"error" => "not_authed"})
39
+ end
40
+ end
41
+ def all_channels
42
+ get_channels(true)
43
+ end
44
+ def active_channels
45
+ get_channels()
46
+ end
47
+ def search(term, archived=false, regex=false)
48
+ channels = get_channels(archived)
49
+ if regex
50
+ channels.select{|c| c['name'] =~ /#{term}/}
51
+ else
52
+ channels.select{|c| c['name'] == term}.first
53
+ end
54
+ end
55
+ def create(name, validate=false)
56
+ if Slack::API::Auth
57
+ uri = URI.parse('https://slack.com/api/channels.create')
58
+ http = Net::HTTP.new(uri.host, uri.port)
59
+ http.use_ssl = true
60
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
61
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&name=#{name}&validate=#{validate}")
62
+ resp = http.request(req)
63
+ false unless resp.code == 200
64
+ if JSON.parse(resp.body)['ok']
65
+ JSON.parse(resp.body)['channel']
66
+ else
67
+ Slack::Errors.new(JSON.parse(resp.body))
68
+ end
69
+ else
70
+ Slack::Errors.new({"error" => "not_authed"})
71
+ end
72
+ end
73
+ def archive(id)
74
+ if Slack::API::Auth
75
+ uri = URI.parse('https://slack.com/api/channels.archive')
76
+ http = Net::HTTP.new(uri.host, uri.port)
77
+ http.use_ssl = true
78
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
79
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}")
80
+ resp = http.request(req)
81
+ false unless resp.code == 200
82
+ if JSON.parse(resp.body)['ok']
83
+ true
84
+ else
85
+ Slack::Errors.new(JSON.parse(resp.body))
86
+ end
87
+ else
88
+ Slack::Errors.new({"error" => "not_authed"})
89
+ end
90
+ end
91
+ def unarchive(id)
92
+ if Slack::API::Auth
93
+ uri = URI.parse('https://slack.com/api/channels.unarchive')
94
+ http = Net::HTTP.new(uri.host, uri.port)
95
+ http.use_ssl = true
96
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
97
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}")
98
+ resp = http.request(req)
99
+ false unless resp.code == 200
100
+ if JSON.parse(resp.body)['ok']
101
+ true
102
+ else
103
+ Slack::Errors.new(JSON.parse(resp.body))
104
+ end
105
+ else
106
+ Slack::Errors.new({"error" => "not_authed"})
107
+ end
108
+ end
109
+ def info(id)
110
+ if Slack::API::Auth
111
+ uri = URI.parse('https://slack.com/api/channels.info')
112
+ http = Net::HTTP.new(uri.host, uri.port)
113
+ http.use_ssl = true
114
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
115
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}")
116
+ resp = http.request(req)
117
+ false unless resp.code == 200
118
+ if JSON.parse(resp.body)['ok']
119
+ JSON.parse(resp.body)['channel']
120
+ else
121
+ Slack::Errors.new(JSON.parse(resp.body))
122
+ end
123
+ else
124
+ Slack::Errors.new({"error" => "not_authed"})
125
+ end
126
+ end
127
+ def history(id, count)
128
+ if Slack::API::Auth
129
+ uri = URI.parse('https://slack.com/api/channels.history')
130
+ http = Net::HTTP.new(uri.host, uri.port)
131
+ http.use_ssl = true
132
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
133
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}&count=#{count}")
134
+ resp = http.request(req)
135
+ false unless resp.code == 200
136
+ if JSON.parse(resp.body)['ok']
137
+ JSON.parse(resp.body)['messages']
138
+ else
139
+ Slack::Errors.new(JSON.parse(resp.body))
140
+ end
141
+ else
142
+ Slack::Errors.new({"error" => "not_authed"})
143
+ end
144
+ end
145
+ def join(name)
146
+ if Slack::API::Auth
147
+ uri = URI.parse('https://slack.com/api/channels.join')
148
+ http = Net::HTTP.new(uri.host, uri.port)
149
+ http.use_ssl = true
150
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
151
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&name=#{name}")
152
+ resp = http.request(req)
153
+ false unless resp.code == 200
154
+ if JSON.parse(resp.body)['ok']
155
+ true
156
+ else
157
+ Slack::Errors.new(JSON.parse(resp.body))
158
+ end
159
+ else
160
+ Slack::Errors.new({"error" => "not_authed"})
161
+ end
162
+ end
163
+ def leave(id)
164
+ if Slack::API::Auth
165
+ uri = URI.parse('https://slack.com/api/channels.join')
166
+ http = Net::HTTP.new(uri.host, uri.port)
167
+ http.use_ssl = true
168
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
169
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}")
170
+ resp = http.request(req)
171
+ false unless resp.code == 200
172
+ if JSON.parse(resp.body)['ok']
173
+ true
174
+ else
175
+ Slack::Errors.new(JSON.parse(resp.body))
176
+ end
177
+ else
178
+ Slack::Errors.new({"error" => "not_authed"})
179
+ end
180
+ end
181
+ def invite_user(user, channel)
182
+ if Slack::API::Auth
183
+ uri = URI.parse('https://slack.com/api/channels.invite')
184
+ http = Net::HTTP.new(uri.host, uri.port)
185
+ http.use_ssl = true
186
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
187
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&user=#{user}")
188
+ resp = http.request(req)
189
+ false unless resp.code == 200
190
+ if JSON.parse(resp.body)['ok']
191
+ true
192
+ else
193
+ Slack::Errors.new(JSON.parse(resp.body))
194
+ end
195
+ else
196
+ Slack::Errors.new({"error" => "not_authed"})
197
+ end
198
+ end
199
+ def kick_user(user, channel)
200
+ if Slack::API::Auth
201
+ uri = URI.parse('https://slack.com/api/channels.kick')
202
+ http = Net::HTTP.new(uri.host, uri.port)
203
+ http.use_ssl = true
204
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
205
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&user=#{user}")
206
+ resp = http.request(req)
207
+ false unless resp.code == 200
208
+ if JSON.parse(resp.body)['ok']
209
+ true
210
+ else
211
+ Slack::Errors.new(JSON.parse(resp.body))
212
+ end
213
+ else
214
+ Slack::Errors.new({"error" => "not_authed"})
215
+ end
216
+ end
217
+ def rename(id, name)
218
+ if Slack::API::Auth
219
+ uri = URI.parse('https://slack.com/api/channels.rename')
220
+ http = Net::HTTP.new(uri.host, uri.port)
221
+ http.use_ssl = true
222
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
223
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}&name=#{name}")
224
+ resp = http.request(req)
225
+ false unless resp.code == 200
226
+ if JSON.parse(resp.body)['ok']
227
+ true
228
+ else
229
+ Slack::Errors.new(JSON.parse(resp.body))
230
+ end
231
+ else
232
+ Slack::Errors.new({"error" => "not_authed"})
233
+ end
234
+ end
235
+ def set_purpose(id, text)
236
+ text = URI.escape(text)
237
+ if Slack::API::Auth
238
+ uri = URI.parse('https://slack.com/api/channels.setPurpose')
239
+ http = Net::HTTP.new(uri.host, uri.port)
240
+ http.use_ssl = true
241
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
242
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}&purpose=#{text}")
243
+ resp = http.request(req)
244
+ false unless resp.code == 200
245
+ if JSON.parse(resp.body)['ok']
246
+ true
247
+ else
248
+ Slack::Errors.new(JSON.parse(resp.body))
249
+ end
250
+ else
251
+ Slack::Errors.new({"error" => "not_authed"})
252
+ end
253
+ end
254
+ def set_topic(id, text)
255
+ text = URI.escape(text)
256
+ if Slack::API::Auth
257
+ uri = URI.parse('https://slack.com/api/channels.setTopic')
258
+ http = Net::HTTP.new(uri.host, uri.port)
259
+ http.use_ssl = true
260
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
261
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{id}&topic=#{text}")
262
+ resp = http.request(req)
263
+ false unless resp.code == 200
264
+ if JSON.parse(resp.body)['ok']
265
+ true
266
+ else
267
+ Slack::Errors.new(JSON.parse(resp.body))
268
+ end
269
+ else
270
+ Slack::Errors.new({"error" => "not_authed"})
271
+ end
272
+ end
273
+ end
274
+ class << self
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,136 @@
1
+ # https://api.slack.com/methods/chat.update
2
+ # https://api.slack.com/methods/chat.delete
3
+ # https://api.slack.com/methods/chat.postMessage
4
+ # https://api.slack.com/methods/chat.meMessage
5
+ # https://api.slack.com/methods/chat.postMessage
6
+ module Slack
7
+ module API
8
+ module Chat
9
+ extend self
10
+ def update(text, ts, channel, obj=nil)
11
+ if Slack::API::Auth
12
+ text = URI.escape(text)
13
+ uri = URI.parse('https://slack.com/api/chat.update')
14
+ case obj
15
+ when nil
16
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}&as_user=true&ts=#{ts}"
17
+ when Array
18
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}&as_user=true&attachments=#{URI.escape(obj.to_json)}&ts=#{ts}"
19
+ else
20
+ Slack::Errors.new({'error' => 'invalid_attachment',
21
+ 'detail' => 'Attachment object must be an Array'})
22
+ end
23
+ http = Net::HTTP.new(uri.host, uri.port)
24
+ http.use_ssl = true
25
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
26
+ req = Net::HTTP::Post.new(url)
27
+ resp = http.request(req)
28
+ false unless resp.code == 200
29
+ if JSON.parse(resp.body)['ok']
30
+ true
31
+ else
32
+ Slack::Errors.new(JSON.parse(resp.body))
33
+ end
34
+ else
35
+ Slack::Errors.new({"error" => "not_authed"})
36
+ end
37
+ end
38
+ def delete(ts, channel)
39
+ if Slack::API::Auth
40
+ text = URI.escape(text)
41
+ uri = URI.parse('https://slack.com/api/chat.delete')
42
+ http = Net::HTTP.new(uri.host, uri.port)
43
+ http.use_ssl = true
44
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
45
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&as_user=true&ts=#{ts}")
46
+ resp = http.request(req)
47
+ false unless resp.code == 200
48
+ if JSON.parse(resp.body)['ok']
49
+ true
50
+ else
51
+ Slack::Errors.new(JSON.parse(resp.body))
52
+ end
53
+ else
54
+ Slack::Errors.new({"error" => "not_authed"})
55
+ end
56
+ end
57
+ def post(text, channel, obj=nil)
58
+ if Slack::API::Auth
59
+ text = URI.escape(text)
60
+ uri = URI.parse('https://slack.com/api/chat.postMessage')
61
+ case obj
62
+ when nil
63
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}&as_user=true"
64
+ when Array
65
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}&as_user=true&attachments=#{URI.escape(obj.to_json)}"
66
+ else
67
+ Slack::Errors.new({'error' => 'invalid_attachment',
68
+ 'detail' => 'Attachment object must be an Array'})
69
+ end
70
+ http = Net::HTTP.new(uri.host, uri.port)
71
+ http.use_ssl = true
72
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
73
+ req = Net::HTTP::Post.new(url)
74
+ resp = http.request(req)
75
+ false unless resp.code == 200
76
+ if JSON.parse(resp.body)['ok']
77
+ true
78
+ else
79
+ Slack::Errors.new(JSON.parse(resp.body))
80
+ end
81
+ else
82
+ Slack::Errors.new({"error" => "not_authed"})
83
+ end
84
+ end
85
+ def post_me(text, channel)
86
+ if Slack::API::Auth
87
+ text = URI.escape(text)
88
+ uri = URI.parse('https://slack.com/api/chat.meMessage')
89
+ http = Net::HTTP.new(uri.host, uri.port)
90
+ http.use_ssl = true
91
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
92
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}")
93
+ resp = http.request(req)
94
+ false unless resp.code == 200
95
+ if JSON.parse(resp.body)['ok']
96
+ true
97
+ else
98
+ Slack::Errors.new(JSON.parse(resp.body))
99
+ end
100
+ else
101
+ Slack::Errors.new({"error" => "not_authed"})
102
+ end
103
+ end
104
+ def post_ephemeral(text, channel, user, obj=nil)
105
+ if Slack::API::Auth
106
+ text = URI.escape(text)
107
+ uri = URI.parse('https://slack.com/api/chat.postEphemeral')
108
+ case obj
109
+ when nil
110
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}&as_user=true&user=#{user}"
111
+ when Array
112
+ url = "#{uri.to_s}?token=#{Slack::Config.token}&channel=#{channel}&text=#{text}&as_user=true&user=#{user}&attachments=#{URI.escape(obj.to_json)}"
113
+ else
114
+ Slack::Errors.new({'error' => 'invalid_attachment',
115
+ 'detail' => 'Attachment object must be an Array'})
116
+ end
117
+ http = Net::HTTP.new(uri.host, uri.port)
118
+ http.use_ssl = true
119
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
120
+ req = Net::HTTP::Post.new(url)
121
+ resp = http.request(req)
122
+ false unless resp.code == 200
123
+ if JSON.parse(resp.body)['ok']
124
+ true
125
+ else
126
+ Slack::Errors.new(JSON.parse(resp.body))
127
+ end
128
+ else
129
+ Slack::Errors.new({"error" => "not_authed"})
130
+ end
131
+ end
132
+ end
133
+ class << self
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,185 @@
1
+ # https://api.slack.com/methods/files.list
2
+ # https://api.slack.com/methods/files.delete
3
+ # https://api.slack.com/methods/files.upload
4
+ # https://api.slack.com/methods/files.comments.add
5
+ # https://api.slack.com/methods/files.comments.delete
6
+ # https://api.slack.com/methods/files.comments.edit
7
+ # https://api.slack.com/methods/files.revokePublicURL
8
+ # https://api.slack.com/methods/files.sharedPublicURL
9
+ module Slack
10
+ module API
11
+ module Files
12
+ extend self
13
+ def get_files(type='all')
14
+ if Slack::API::Auth
15
+ type.split(',').each do |t|
16
+ case t
17
+ when 'all', 'spaces', 'snippets', 'images', 'gdocs', 'zips', 'pdfs'
18
+ next
19
+ else
20
+ Slack::Errors.new({'error' => 'invalid file type',
21
+ 'detail' => 'Only all, spaces, snippets, images, gdocs, zips, pdfs supported'})
22
+ end
23
+ end
24
+ uri = URI.parse('https://slack.com/api/files.list')
25
+ http = Net::HTTP.new(uri.host, uri.port)
26
+ http.use_ssl = true
27
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
28
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&types=#{type}")
29
+ resp = http.request(req)
30
+ false unless resp.code == 200
31
+ if JSON.parse(resp.body)['ok']
32
+ JSON.parse(resp.body)['files']
33
+ else
34
+ Slack::Errors.new(JSON.parse(resp.body))
35
+ end
36
+ else
37
+ Slack::Errors.new({"error" => "not_authed"})
38
+ end
39
+ end
40
+ def search(term, regex=false)
41
+ files = get_files
42
+ if regex
43
+ files.select{|f| f['name'] =~ /#{term}/}
44
+ else
45
+ files.select{|f| f['name'] == term}.first
46
+ end
47
+ end
48
+ def delete(id)
49
+ if Slack::API::Auth
50
+ uri = URI.parse('https://slack.com/api/files.delete')
51
+ http = Net::HTTP.new(uri.host, uri.port)
52
+ http.use_ssl = true
53
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
54
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&file=#{id}")
55
+ resp = http.request(req)
56
+ false unless resp.code == 200
57
+ if JSON.parse(resp.body)['ok']
58
+ true
59
+ else
60
+ Slack::Errors.new(JSON.parse(resp.body))
61
+ end
62
+ else
63
+ Slack::Errors.new({"error" => "not_authed"})
64
+ end
65
+ end
66
+ def upload(file, channel, opts={})
67
+ Slack::Errors.new({'error' => 'file_invalid', 'detail' => 'Object is missing or is not a file'}) unless File.file?(file)
68
+ opts['channels'] = channel
69
+ opts['title'] = File.basename(file) unless opts.has_key? :title
70
+ opts['filename'] = File.basename(file) unless opts.has_key? :filename
71
+ opts['filetype'] = 'auto' unless opts.has_key? :filetype
72
+ opts['initial_comment'] = '' unless opts.has_key? :initial_comment
73
+ if Slack::API::Auth
74
+ uri = URI.parse('https://slack.com/api/files.upload')
75
+ opts['token'] = Slack::Config.token
76
+ File.open(file) do |f|
77
+ opts['file'] = UploadIO.new(f, `file --brief --mime-type #{file}`.strip, opts['filename'])
78
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
79
+ res = Net::HTTP::new(uri.host, uri.port)
80
+ res.use_ssl = true
81
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
82
+ resp = res.start do |http|
83
+ http.request(req)
84
+ end
85
+ false unless resp.code == 200
86
+ end
87
+ else
88
+ Slack::Errors.new({"error" => "not_authed"})
89
+ end
90
+ end
91
+ def add_comment(text, file)
92
+ if Slack::API::Auth
93
+ uri = URI.parse('https://slack.com/api/files.comments.add')
94
+ http = Net::HTTP.new(uri.host, uri.port)
95
+ http.use_ssl = true
96
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
97
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&file=#{file}&comment=#{text}")
98
+ resp = http.request(req)
99
+ false unless resp.code == 200
100
+ if JSON.parse(resp.body)['ok']
101
+ JSON.parse(resp.body)['files']
102
+ else
103
+ Slack::Errors.new(JSON.parse(resp.body))
104
+ end
105
+ else
106
+ Slack::Errors.new({"error" => "not_authed"})
107
+ end
108
+ end
109
+ def delete_comment(file, id)
110
+ if Slack::API::Auth
111
+ uri = URI.parse('https://slack.com/api/files.comments.delete')
112
+ http = Net::HTTP.new(uri.host, uri.port)
113
+ http.use_ssl = true
114
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
115
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&file=#{file}&id=#{id}")
116
+ resp = http.request(req)
117
+ false unless resp.code == 200
118
+ if JSON.parse(resp.body)['ok']
119
+ JSON.parse(resp.body)['files']
120
+ else
121
+ Slack::Errors.new(JSON.parse(resp.body))
122
+ end
123
+ else
124
+ Slack::Errors.new({"error" => "not_authed"})
125
+ end
126
+ end
127
+ def edit_comment(text, file, id)
128
+ if Slack::API::Auth
129
+ uri = URI.parse('https://slack.com/api/files.comments.edit')
130
+ http = Net::HTTP.new(uri.host, uri.port)
131
+ http.use_ssl = true
132
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
133
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&comment=#{text}&file=#{file}&id=#{id}")
134
+ resp = http.request(req)
135
+ false unless resp.code == 200
136
+ if JSON.parse(resp.body)['ok']
137
+ JSON.parse(resp.body)['files']
138
+ else
139
+ Slack::Errors.new(JSON.parse(resp.body))
140
+ end
141
+ else
142
+ Slack::Errors.new({"error" => "not_authed"})
143
+ end
144
+ end
145
+ def revoke_URL(file)
146
+ if Slack::API::Auth
147
+ uri = URI.parse('https://slack.com/api/files.sharedPublicURL')
148
+ http = Net::HTTP.new(uri.host, uri.port)
149
+ http.use_ssl = true
150
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
151
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&file=#{file}")
152
+ resp = http.request(req)
153
+ false unless resp.code == 200
154
+ if JSON.parse(resp.body)['ok']
155
+ JSON.parse(resp.body)['file']['url']
156
+ else
157
+ Slack::Errors.new(JSON.parse(resp.body))
158
+ end
159
+ else
160
+ Slack::Errors.new({"error" => "not_authed"})
161
+ end
162
+ end
163
+ def enable_URL(file)
164
+ if Slack::API::Auth
165
+ uri = URI.parse('https://slack.com/api/files.revokePublicURL')
166
+ http = Net::HTTP.new(uri.host, uri.port)
167
+ http.use_ssl = true
168
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
169
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&file=#{file}")
170
+ resp = http.request(req)
171
+ false unless resp.code == 200
172
+ if JSON.parse(resp.body)['ok']
173
+ JSON.parse(resp.body)['files']
174
+ else
175
+ Slack::Errors.new(JSON.parse(resp.body))
176
+ end
177
+ else
178
+ Slack::Errors.new({"error" => "not_authed"})
179
+ end
180
+ end
181
+ end
182
+ class << self
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,105 @@
1
+ # https://api.slack.com/methods/im.open
2
+ # https://api.slack.com/methods/im.close
3
+ # https://api.slack.com/methods/im.history
4
+ # https://api.slack.com/methods/im.list
5
+ module Slack
6
+ module API
7
+ module IM
8
+ extend self
9
+ def open(id, opts={})
10
+ if Slack::API::Auth
11
+ opts['user'] = id
12
+ opts['return_im'] = true
13
+ opts['token'] = Slack::Config.token
14
+ opts['include_locale'] = true
15
+ uri = URI.parse('https://slack.com/api/im.open')
16
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
17
+ res = Net::HTTP::new(uri.host, uri.port)
18
+ res.use_ssl = true
19
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
20
+ resp = res.start do |http|
21
+ http.request(req)
22
+ end
23
+ false unless resp.code == 200
24
+ if JSON.parse(resp.body)['ok']
25
+ JSON.parse(resp.body)['channel']
26
+ else
27
+ Slack::Errors.new(JSON.parse(resp.body))
28
+ end
29
+ else
30
+ Slack::Errors.new({"error" => "not_authed"})
31
+ end
32
+ end
33
+ def close(id, opts={})
34
+ if Slack::API::Auth
35
+ opts['channel'] = id
36
+ opts['token'] = Slack::Config.token
37
+ uri = URI.parse('https://slack.com/api/im.close')
38
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
39
+ res = Net::HTTP::new(uri.host, uri.port)
40
+ res.use_ssl = true
41
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
42
+ resp = res.start do |http|
43
+ http.request(req)
44
+ end
45
+ false unless resp.code == 200
46
+ if JSON.parse(resp.body)['ok']
47
+ true
48
+ else
49
+ Slack::Errors.new(JSON.parse(resp.body))
50
+ end
51
+ else
52
+ Slack::Errors.new({"error" => "not_authed"})
53
+ end
54
+ end
55
+ def history(id, opts={})
56
+ if Slack::API::Auth
57
+ opts['channel'] = id
58
+ opts['token'] = Slack::Config.token
59
+ uri = URI.parse('https://slack.com/api/im.history')
60
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
61
+ res = Net::HTTP::new(uri.host, uri.port)
62
+ res.use_ssl = true
63
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
64
+ resp = res.start do |http|
65
+ http.request(req)
66
+ end
67
+ false unless resp.code == 200
68
+ if JSON.parse(resp.body)['ok']
69
+ JSON.parse(resp.body)['messages']
70
+ else
71
+ Slack::Errors.new(JSON.parse(resp.body))
72
+ end
73
+ else
74
+ Slack::Errors.new({"error" => "not_authed"})
75
+ end
76
+ end
77
+ def list(opts={})
78
+ if Slack::API::Auth
79
+ opts['token'] = Slack::Config.token
80
+ uri = URI.parse('https://slack.com/api/im.list')
81
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
82
+ res = Net::HTTP::new(uri.host, uri.port)
83
+ res.use_ssl = true
84
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
85
+ resp = res.start do |http|
86
+ http.request(req)
87
+ end
88
+ false unless resp.code == 200
89
+ if JSON.parse(resp.body)['ok']
90
+ JSON.parse(resp.body)['ims']
91
+ else
92
+ Slack::Errors.new(JSON.parse(resp.body))
93
+ end
94
+ else
95
+ Slack::Errors.new({"error" => "not_authed"})
96
+ end
97
+ end
98
+ end
99
+ class << self
100
+ def im
101
+ IM
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,57 @@
1
+ # https://api.slack.com/methods/apps.permissions.info
2
+ # https://api.slack.com/methods/apps.permissions.request
3
+ # Slack API still in development for feature, leaving as is for now
4
+ module Slack
5
+ module API
6
+ class Permissions
7
+ def show(opts={})
8
+ if Slack::API::Auth
9
+ opts['token'] = Slack::Config.token
10
+ uri = URI.parse('https://slack.com/api/apps.permissions.info')
11
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
12
+ res = Net::HTTP::new(uri.host, uri.port)
13
+ res.use_ssl = true
14
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ resp = res.start do |http|
16
+ http.request(req)
17
+ end
18
+ false unless resp.code == 200
19
+ if JSON.parse(resp.body)['ok']
20
+ JSON.parse(resp.body)['info']
21
+ else
22
+ Slack::Errors.new(JSON.parse(resp.body))
23
+ end
24
+ else
25
+ Slack::Errors.new({"error" => "not_authed"})
26
+ end
27
+ end
28
+ def request(opts={})
29
+ if Slack::API::Auth
30
+ if opts.key?('scopes') && opts.key?("trigger_id")
31
+ Slack::Errors.new({'error' => 'no_scope', 'detail' => 'You must provide a comma separated scope'}) if opts['scopes'].empty?
32
+ Slack::Errors.new({'error' => 'no_trigger_id', 'detail' => 'You must provide a trigger id'}) if opts['trigger_id'].empty?
33
+ else
34
+ Slack::Errors.new({'error' => 'invalid_parameters', 'detail' => 'You must provide both scopes and trigger_id as options'})
35
+ end
36
+ opts['token'] = Slack::Config.token
37
+ uri = URI.parse('https://slack.com/api/apps.permissions.info')
38
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
39
+ res = Net::HTTP::new(uri.host, uri.port)
40
+ res.use_ssl = true
41
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
42
+ resp = res.start do |http|
43
+ http.request(req)
44
+ end
45
+ false unless resp.code == 200
46
+ if JSON.parse(resp.body)['ok']
47
+ true
48
+ else
49
+ Slack::Errors.new(JSON.parse(resp.body))
50
+ end
51
+ else
52
+ Slack::Errors.new({"error" => "not_authed"})
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,58 @@
1
+ # https://api.slack.com/methods/rtm.connect
2
+ # https://api.slack.com/methods/rtm.start
3
+ module Slack
4
+ module API
5
+ module RTM
6
+ extend self
7
+ def connect(opts={})
8
+ if Slack::API::Auth
9
+ opts['token'] = Slack::Config.token
10
+ uri = URI.parse('https://slack.com/api/rtm.connect')
11
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
12
+ res = Net::HTTP::new(uri.host, uri.port)
13
+ res.use_ssl = true
14
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ resp = res.start do |http|
16
+ http.request(req)
17
+ end
18
+ false unless resp.code == 200
19
+ if JSON.parse(resp.body)['ok']
20
+ JSON.parse(resp.body)['url']
21
+ else
22
+ Slack::Errors.new(JSON.parse(resp.body))
23
+ end
24
+ else
25
+ Slack::Errors.new({"error" => "not_authed"})
26
+ end
27
+ end
28
+ def start(opts={})
29
+ opts['no_unreads'] = true unless opts.key? 'no_unreads'
30
+ opts['simple_latest'] = true unless opts.key? 'simple_latest'
31
+ opts['token'] = Slack::Config.token
32
+ if Slack::API::Auth
33
+ uri = URI.parse('https://slack.com/api/rtm.start')
34
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
35
+ res = Net::HTTP::new(uri.host, uri.port)
36
+ res.use_ssl = true
37
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
38
+ resp = res.start do |http|
39
+ http.request(req)
40
+ end
41
+ false unless resp.code == 200
42
+ if JSON.parse(resp.body)['ok']
43
+ JSON.parse(resp.body)
44
+ else
45
+ Slack::Errors.new(JSON.parse(resp.body))
46
+ end
47
+ else
48
+ Slack::Errors.new({"error" => "not_authed"})
49
+ end
50
+ end
51
+ end
52
+ class << self
53
+ def rtm
54
+ RTM
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,115 @@
1
+ # https://api.slack.com/methods/users.info
2
+ # https://api.slack.com/methods/users.list
3
+ # https://api.slack.com/methods/users.profile.get
4
+ # https://api.slack.com/methods/users.profile.set
5
+ module Slack
6
+ module API
7
+ module Users
8
+ extend self
9
+ def info(id)
10
+ if Slack::API::Auth
11
+ uri = URI.parse('https://slack.com/api/users.info')
12
+ http = Net::HTTP.new(uri.host, uri.port)
13
+ http.use_ssl = true
14
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
15
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&user=#{id}")
16
+ resp = http.request(req)
17
+ false unless resp.code == 200
18
+ if JSON.parse(resp.body)['ok']
19
+ JSON.parse(resp.body)['user']
20
+ else
21
+ Slack::Errors.new(JSON.parse(resp.body))
22
+ end
23
+ else
24
+ Slack::Errors.new({"error" => "not_authed"})
25
+ end
26
+ end
27
+ def get_list()
28
+ if Slack::API::Auth
29
+ uri = URI.parse('https://slack.com/api/users.list')
30
+ http = Net::HTTP.new(uri.host, uri.port)
31
+ http.use_ssl = true
32
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
33
+ req = Net::HTTP::Post.new("#{uri.to_s}?token=#{Slack::Config.token}&presence=false")
34
+ resp = http.request(req)
35
+ false unless resp.code == 200
36
+ if JSON.parse(resp.body)['ok']
37
+ JSON.parse(resp.body)['members']
38
+ else
39
+ Slack::Errors.new(JSON.parse(resp.body))
40
+ end
41
+ else
42
+ Slack::Errors.new({"error" => "not_authed"})
43
+ end
44
+ end
45
+ def search(term, what='username', regex=false)
46
+ users = get_list()
47
+ out = nil
48
+ case what
49
+ when 'email'
50
+ out = users.select{|u| u['profile']['email'] == term} unless regex
51
+ out = users.select{|u| u['profile']['email'] =~ /#{term}/}.first if regex
52
+ when 'username'
53
+ out = users.select{|u| u['name'] == term}.first unless regex
54
+ out = users.select{|u| u['name'] =~ /#{term}/} if regex
55
+ when 'name'
56
+ out = users.select{|u| u['profile']['real_name'] == term}.first unless regex
57
+ out = users.select{|u| u['profile']['real_name'] =~ /#{term}/} if regex
58
+ else
59
+ Slack::Errors.new({"error" => "invalid_search_term",
60
+ "detail" => "You can only search by username, name, or email"})
61
+ end
62
+ out
63
+ end
64
+ def get_profile(id)
65
+ opts = {}
66
+ if Slack::API::Auth
67
+ opts['user'] = id
68
+ opts['token'] = Slack::Config.token
69
+ opts['include_labels'] = true
70
+ uri = URI.parse('https://slack.com/api/users.profile.get')
71
+ opts['token'] = Slack::Config.token
72
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
73
+ res = Net::HTTP::new(uri.host, uri.port)
74
+ res.use_ssl = true
75
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
76
+ resp = res.start do |http|
77
+ http.request(req)
78
+ end
79
+ false unless resp.code == 200
80
+ if JSON.parse(resp.body)['ok']
81
+ JSON.parse(resp.body)['profile']
82
+ else
83
+ Slack::Errors.new(JSON.parse(resp.body))
84
+ end
85
+ else
86
+ Slack::Errors.new({"error" => "not_authed"})
87
+ end
88
+ end
89
+ def set_profile(opts = {})
90
+ if Slack::API::Auth
91
+ opts['token'] = Slack::Config.token
92
+ uri = URI.parse('https://slack.com/api/users.profile.set')
93
+ opts['token'] = Slack::Config.token
94
+ req = Net::HTTP::Post::Multipart.new(uri.path, opts)
95
+ res = Net::HTTP::new(uri.host, uri.port)
96
+ res.use_ssl = true
97
+ res.verify_mode = OpenSSL::SSL::VERIFY_NONE
98
+ resp = res.start do |http|
99
+ http.request(req)
100
+ end
101
+ false unless resp.code == 200
102
+ if JSON.parse(resp.body)['ok']
103
+ JSON.parse(resp.body)['profile']
104
+ else
105
+ Slack::Errors.new(JSON.parse(resp.body))
106
+ end
107
+ else
108
+ Slack::Errors.new({"error" => "not_authed"})
109
+ end
110
+ end
111
+ end
112
+ class << self
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,19 @@
1
+ module Slack
2
+ module Config
3
+ extend self
4
+ attr_accessor :token, :logger
5
+ def reset
6
+ self.token = ENV['SLACK_TOKEN'] ? ENV['SLACK_TOKEN'] : nil
7
+ self.logger = ENV['LOG_LEVEL'] ? ENV['LOG_LEVEL'] : nil
8
+ end
9
+ reset
10
+ end
11
+ class << self
12
+ def configure
13
+ block_given? ? yield(Config) : Config
14
+ end
15
+ def config
16
+ Config
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module Slack
2
+ class Errors
3
+ def initialize(object)
4
+ handle(object)
5
+ end
6
+ def handle(object)
7
+ raise RuntimeError, message(object)
8
+ end
9
+ def message(object)
10
+ case object['error']
11
+ when nil
12
+ error = "Undefined Error"
13
+ when "not_authed"
14
+ object['detail'] = "Invalid Token, check configuration"
15
+ when String
16
+ error = object['error']
17
+ end
18
+ case object['detail']
19
+ when nil
20
+ detail = "Details unknown"
21
+ when String
22
+ detail = object['detail']
23
+ end
24
+ "Error '#{error}' occured. Details: #{detail}"
25
+ end
26
+ end
27
+ end
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slack-wrapper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jason Colyer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.1.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.1.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: multipart-post
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ description: Simple Slack API wrapper for ruby
48
+ email: jcolyer2007@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files: []
52
+ files:
53
+ - lib/slack-wrapper.rb
54
+ - lib/slack-wrapper/api.rb
55
+ - lib/slack-wrapper/api/auth.rb
56
+ - lib/slack-wrapper/api/bots.rb
57
+ - lib/slack-wrapper/api/channels.rb
58
+ - lib/slack-wrapper/api/chat.rb
59
+ - lib/slack-wrapper/api/files.rb
60
+ - lib/slack-wrapper/api/im.rb
61
+ - lib/slack-wrapper/api/permissions.rb
62
+ - lib/slack-wrapper/api/rtm.rb
63
+ - lib/slack-wrapper/api/users.rb
64
+ - lib/slack-wrapper/config.rb
65
+ - lib/slack-wrapper/errors.rb
66
+ homepage: https://rubygems.org/gems/slack-ruby
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 2.5.1
87
+ signing_key:
88
+ specification_version: 4
89
+ summary: TBD
90
+ test_files: []