embulk-input-slack-history 0.1.0
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.
- checksums.yaml +7 -0
- data/ChangeLog +16 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +19 -0
- data/README.md +33 -0
- data/Rakefile +4 -0
- data/embulk-input-slack-history.gemspec +21 -0
- data/lib/embulk/input/slack_history.rb +246 -0
- data/slack_history_configsample.yml +7 -0
- metadata +94 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 49031b2f1709e7d4b70fa643310e63f539372b3b
|
|
4
|
+
data.tar.gz: 211c4b5a59e0e9d21f3daa264aba4232aa8c6c3c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 5432efc108632885e6948f3ccaf6e02c0994f207287b677af434a1ce80a61c4a1434c9c0c88af4e20a2ad189f14e06703e888e7c1072d7e6173d273f7fdddb02
|
|
7
|
+
data.tar.gz: ee30df521d35f41ad279ef22d15c51b2cda47786609dc92dc6abc26ed54a3cb72187e5c11e6174072abac928418f0ca71fca65ccdbe04cb29d7e236b0eddefee
|
data/ChangeLog
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
embulk-input-slack-history (0.1.0)
|
|
5
|
+
rest-client (>= 1.7.2)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: http://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
rest-client (1.7.2)
|
|
11
|
+
rake (10.4.2)
|
|
12
|
+
|
|
13
|
+
PLATFORMS
|
|
14
|
+
ruby
|
|
15
|
+
|
|
16
|
+
DEPENDENCIES
|
|
17
|
+
bundler (~> 1.0)
|
|
18
|
+
embulk-input-slack-history!
|
|
19
|
+
rake (>= 0.9.2)
|
data/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# embulk-input-slack-history
|
|
2
|
+
|
|
3
|
+
This [Embulk](https://github.com/embulk/embulk) input plugin for Slack chat history.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## Installation
|
|
7
|
+
|
|
8
|
+
$ java -jar embulk.jar gem install embulk-input-slack-history
|
|
9
|
+
|
|
10
|
+
## Configuration
|
|
11
|
+
|
|
12
|
+
- **token** Slack API token 'Generate from https://api.slack.com/' (string, required)
|
|
13
|
+
- **continuous** last time read continuation (string, default: false)
|
|
14
|
+
- **filepath** continuous information file save path (string, default: /tmp)
|
|
15
|
+
|
|
16
|
+
### Example
|
|
17
|
+
|
|
18
|
+
```yaml
|
|
19
|
+
in:
|
|
20
|
+
type: slack_history
|
|
21
|
+
token: slackapitoken
|
|
22
|
+
continuous: true # optional
|
|
23
|
+
filepath: /tmp # optional
|
|
24
|
+
out:
|
|
25
|
+
type: stdout
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## TODO
|
|
29
|
+
|
|
30
|
+
- attachment file download
|
|
31
|
+
- do not update *.oldest file at preview time
|
|
32
|
+
- error handling and resume
|
|
33
|
+
- multi thread execute Slack API if needed
|
data/Rakefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
|
|
2
|
+
Gem::Specification.new do |gem|
|
|
3
|
+
gem.name = "embulk-input-slack-history"
|
|
4
|
+
gem.version = "0.1.0"
|
|
5
|
+
|
|
6
|
+
gem.summary = %q{Embulk input plugin for Slack chat history}
|
|
7
|
+
gem.description = gem.summary
|
|
8
|
+
gem.authors = ["Akihiro YAGASAKI"]
|
|
9
|
+
gem.email = ["yaggytter@momiage.com"]
|
|
10
|
+
gem.license = "Apache 2.0"
|
|
11
|
+
gem.homepage = "https://github.com/yaggytter/embulk-input-slack-history"
|
|
12
|
+
|
|
13
|
+
gem.files = `git ls-files`.split("\n") + Dir["classpath/*.jar"]
|
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
15
|
+
gem.require_paths = ["lib"]
|
|
16
|
+
gem.has_rdoc = false
|
|
17
|
+
|
|
18
|
+
gem.add_dependency 'rest-client', ['>= 1.7.2']
|
|
19
|
+
gem.add_development_dependency 'bundler', ['~> 1.0']
|
|
20
|
+
gem.add_development_dependency 'rake', ['>= 0.9.2']
|
|
21
|
+
end
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
module Embulk
|
|
2
|
+
module Plugin
|
|
3
|
+
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'rest-client'
|
|
6
|
+
|
|
7
|
+
class SlackApiException < Exception; end
|
|
8
|
+
|
|
9
|
+
class SlackApi
|
|
10
|
+
|
|
11
|
+
def initialize(token)
|
|
12
|
+
@token = token
|
|
13
|
+
@members = {}
|
|
14
|
+
@groups = {}
|
|
15
|
+
@channels = {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def pre()
|
|
19
|
+
|
|
20
|
+
# TODO: need implement error handling
|
|
21
|
+
# HTTP Status Code
|
|
22
|
+
# RestClient Exception
|
|
23
|
+
# result is NOT 'ok'
|
|
24
|
+
|
|
25
|
+
json = RestClient.get('https://slack.com/api/channels.list', {:params => {'token' => @token, 'pretty' => 1}})
|
|
26
|
+
result = JSON.parse(json)
|
|
27
|
+
|
|
28
|
+
if !result['ok'] then
|
|
29
|
+
raise SlackApiException
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
result["channels"].each{|channel|
|
|
33
|
+
@channels[channel["id"]] = channel["name"]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
json = RestClient.get('https://slack.com/api/groups.list', {:params => {'token' => @token, 'pretty' => 1}})
|
|
37
|
+
result = JSON.parse(json)
|
|
38
|
+
|
|
39
|
+
if !result['ok'] then
|
|
40
|
+
raise SlackApiException
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
result["groups"].each{|group|
|
|
44
|
+
@groups[group["id"]] = group["name"]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
json = RestClient.get('https://slack.com/api/users.list', {:params => {'token' => @token, 'pretty' => 1}})
|
|
48
|
+
result = JSON.parse(json)
|
|
49
|
+
|
|
50
|
+
if !result['ok'] then
|
|
51
|
+
raise SlackApiException
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
result["members"].each{|member|
|
|
55
|
+
@members[member["id"]] = member["name"]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return true
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def parse_history(message)
|
|
63
|
+
|
|
64
|
+
res = {}
|
|
65
|
+
|
|
66
|
+
res["ts"] = message["ts"]
|
|
67
|
+
res["username"] = @members[message["user"]]
|
|
68
|
+
res["userid"] = message["user"]
|
|
69
|
+
res["message"] = message["text"]
|
|
70
|
+
|
|
71
|
+
return res
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get_oldest_filepath(filepath, channelid)
|
|
76
|
+
return filepath + "/" + channelid + ".oldest"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def get_continuous_param(continuous, filepath, channelid)
|
|
80
|
+
|
|
81
|
+
if !continuous then
|
|
82
|
+
return ""
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
param = ""
|
|
86
|
+
|
|
87
|
+
fullpath = get_oldest_filepath(filepath, channelid)
|
|
88
|
+
|
|
89
|
+
if !File.exist?(fullpath) then
|
|
90
|
+
return ""
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
line = File.read(fullpath)
|
|
94
|
+
|
|
95
|
+
param = "&oldest=" + line + "&inclusive=0"
|
|
96
|
+
|
|
97
|
+
return param
|
|
98
|
+
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def update_oldest(continuous, filepath, channelid, newest)
|
|
102
|
+
|
|
103
|
+
if !continuous || newest == 0.0 then
|
|
104
|
+
return
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
fullpath = get_oldest_filepath(filepath, channelid)
|
|
108
|
+
File.write(fullpath, newest)
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def get_history_by_channels(continuous, filepath, channels, isprivate)
|
|
113
|
+
|
|
114
|
+
res = []
|
|
115
|
+
i = 0
|
|
116
|
+
|
|
117
|
+
channels.each{|id, name|
|
|
118
|
+
|
|
119
|
+
api = "channels"
|
|
120
|
+
if isprivate == "yes" then
|
|
121
|
+
api = "groups"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
param = get_continuous_param(continuous, filepath, id)
|
|
125
|
+
|
|
126
|
+
json = RestClient.get('https://slack.com/api/' + api + '.history', {:params => {'token' => @token, 'channel' => id, 'pretty' => 1}})
|
|
127
|
+
result = JSON.parse(json)
|
|
128
|
+
|
|
129
|
+
newest = 0.0
|
|
130
|
+
|
|
131
|
+
result["messages"].each{|message|
|
|
132
|
+
|
|
133
|
+
mes = parse_history(message)
|
|
134
|
+
mes["channelid"] = id
|
|
135
|
+
mes["channelname"] = name
|
|
136
|
+
mes["private"] = isprivate
|
|
137
|
+
res[i] = mes
|
|
138
|
+
i += 1
|
|
139
|
+
|
|
140
|
+
ts = message['ts'].to_f
|
|
141
|
+
if newest < ts then
|
|
142
|
+
newest = ts
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
update_oldest(continuous, filepath, id, newest)
|
|
148
|
+
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return res
|
|
152
|
+
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def get_history(continuous, filepath)
|
|
156
|
+
|
|
157
|
+
res = get_history_by_channels(continuous, filepath, @channels, "no")
|
|
158
|
+
res.concat(get_history_by_channels(continuous, filepath, @groups, "yes"))
|
|
159
|
+
|
|
160
|
+
return res
|
|
161
|
+
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
class InputSlackHistory < InputPlugin
|
|
168
|
+
|
|
169
|
+
# input plugin file name must be: embulk/input_<name>.rb
|
|
170
|
+
Plugin.register_input('slack_history', self)
|
|
171
|
+
|
|
172
|
+
def self.transaction(config, &control)
|
|
173
|
+
|
|
174
|
+
@noerror = true
|
|
175
|
+
|
|
176
|
+
threads = 1
|
|
177
|
+
|
|
178
|
+
token = config.param('token', :string)
|
|
179
|
+
continuous = config.param('continuous', :bool, default: false)
|
|
180
|
+
filepath = config.param('filepath', :string, default: '/tmp')
|
|
181
|
+
preview = config.param('preview', :string, default: 'no')
|
|
182
|
+
|
|
183
|
+
task = {
|
|
184
|
+
'token' => token,
|
|
185
|
+
'continuous' => continuous,
|
|
186
|
+
'filepath' => filepath,
|
|
187
|
+
'preview' => preview
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
columns = [
|
|
191
|
+
Column.new(0, 'channelid', :string),
|
|
192
|
+
Column.new(1, 'channelname', :string),
|
|
193
|
+
Column.new(2, 'private', :string),
|
|
194
|
+
Column.new(3, 'datetime', :timestamp),
|
|
195
|
+
Column.new(4, 'username', :string),
|
|
196
|
+
Column.new(5, 'userid', :string),
|
|
197
|
+
Column.new(6, 'message', :string),
|
|
198
|
+
]
|
|
199
|
+
|
|
200
|
+
puts "Slack history input started."
|
|
201
|
+
commit_reports = yield(task, columns, threads)
|
|
202
|
+
puts "Slack history input finished."
|
|
203
|
+
|
|
204
|
+
next_config_diff = {}
|
|
205
|
+
return next_config_diff
|
|
206
|
+
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def initialize(task, schema, index, page_builder)
|
|
211
|
+
super
|
|
212
|
+
@slack = SlackApi.new(task['token'])
|
|
213
|
+
@noerror = @slack.pre()
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def run
|
|
217
|
+
|
|
218
|
+
if !@noerror then
|
|
219
|
+
@page_builder.finish
|
|
220
|
+
return
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
messages = @slack.get_history(@task['continuous'], @task['filepath'])
|
|
224
|
+
|
|
225
|
+
messages.each{|message|
|
|
226
|
+
@page_builder.add([
|
|
227
|
+
message['channelid'],
|
|
228
|
+
message['channelname'],
|
|
229
|
+
message['private'],
|
|
230
|
+
Time.at(message['ts'].to_f),
|
|
231
|
+
message['username'],
|
|
232
|
+
message['userid'],
|
|
233
|
+
message['message']
|
|
234
|
+
])
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
@page_builder.finish
|
|
238
|
+
|
|
239
|
+
commit_report = {}
|
|
240
|
+
return commit_report
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
end
|
|
246
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: embulk-input-slack-history
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Akihiro YAGASAKI
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-02-16 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rest-client
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - '>='
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: 1.7.2
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - '>='
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: 1.7.2
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: bundler
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ~>
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ~>
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rake
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - '>='
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: 0.9.2
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: 0.9.2
|
|
55
|
+
description: Embulk input plugin for Slack chat history
|
|
56
|
+
email:
|
|
57
|
+
- yaggytter@momiage.com
|
|
58
|
+
executables: []
|
|
59
|
+
extensions: []
|
|
60
|
+
extra_rdoc_files: []
|
|
61
|
+
files:
|
|
62
|
+
- ChangeLog
|
|
63
|
+
- Gemfile
|
|
64
|
+
- Gemfile.lock
|
|
65
|
+
- README.md
|
|
66
|
+
- Rakefile
|
|
67
|
+
- embulk-input-slack-history.gemspec
|
|
68
|
+
- lib/embulk/input/slack_history.rb
|
|
69
|
+
- slack_history_configsample.yml
|
|
70
|
+
homepage: https://github.com/yaggytter/embulk-input-slack-history
|
|
71
|
+
licenses:
|
|
72
|
+
- Apache 2.0
|
|
73
|
+
metadata: {}
|
|
74
|
+
post_install_message:
|
|
75
|
+
rdoc_options: []
|
|
76
|
+
require_paths:
|
|
77
|
+
- lib
|
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - '>='
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - '>='
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '0'
|
|
88
|
+
requirements: []
|
|
89
|
+
rubyforge_project:
|
|
90
|
+
rubygems_version: 2.2.2
|
|
91
|
+
signing_key:
|
|
92
|
+
specification_version: 4
|
|
93
|
+
summary: Embulk input plugin for Slack chat history
|
|
94
|
+
test_files: []
|