ding_hook 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: f30d5fa527ec11549bb9112cf60e01f6d621928ee393ee7f41b8944fc1e41bc5
4
+ data.tar.gz: 1bffc6cb8cb8b048f4d468ff2097972b3287c4da69f6ab85763c5e051ab23af2
5
+ SHA512:
6
+ metadata.gz: 9bd803e9b5d55e5ed1c1850916d624d01e1a3f183ad479490d742c102144caa1214c1d0844c1a68cc4b7719fcdecafd659aa2861aa6ec69f9c5bc23eddbf668c
7
+ data.tar.gz: d4a421954bc2802bff5bd9476ae551044a06bfe02af2408a52e16c7f3cbc3cfc8d3dfb7d1437ab3772b960a75914c745a7aca791b95c929de1abe11da4c779ac
data/.gitignore ADDED
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .idea/
10
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.3
5
+ before_install: gem install bundler -v 1.16.2
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at lanyuejin1108@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in ding_hook.gemspec
6
+ gemspec
data/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # DingHook
2
+
3
+ 钉钉群机器人中自定义机器人的webhook封装版本,更方便在项目中的使用。[钉钉文档地址](https://open-doc.dingtalk.com/docs/doc.htm?treeId=257&articleId=105735&docType=1)
4
+ ![robot.png](https://i.loli.net/2018/12/02/5c03c363974b1.png)
5
+ ## 安装
6
+
7
+ 如果需要在项目中使用,把下面代码增加到你的Gemfile中:
8
+
9
+ ```ruby
10
+ gem 'ding_hook'
11
+ ```
12
+
13
+ 然后执行下列命令:
14
+
15
+ $ bundle
16
+
17
+ 或者是直接安装对应的gem包使用:
18
+
19
+ $ gem install ding_hook
20
+
21
+ ## 配置
22
+ ### 文件配置
23
+ 1. 在 Rails 项目中使用时,默认会读取`config`目录下的`dinghook.yml`文件
24
+ 2. 非 Rails 项目中,默认读取当前目录中`config`目录下的`dinghook.yml`文件;若不存在,则读取当前用户主目录下的`.ding_hook.yml`文件
25
+
26
+ 配置格式:
27
+ ```yaml
28
+ default: access_token # 默认机器人
29
+ dev: dev_group_access_token # example, 不同分组机器人
30
+ alarm: alarm_group_access_token # example, 不同分组机器人
31
+ ```
32
+
33
+ ### 代码配置
34
+ 当然也可以在代码中去配置对应的`access_token`, 当前配置会覆盖文件中的相同配置项
35
+
36
+ ```ruby
37
+ DingHook.configure do |config|
38
+ config[:default] = 'access_token'
39
+ config[:dev] = 'dev_group_access_token'
40
+ config[:alarm] = 'alarm_group_access_token'
41
+ end
42
+ ```
43
+
44
+ 可以通过下列命令查看已配置的信息:
45
+ ```ruby
46
+ DingHook.config
47
+ ```
48
+
49
+ ## 项目使用
50
+ 在项目中使用时,提供了下列的方法调用:
51
+
52
+ ### 文本类型消息
53
+
54
+ ```ruby
55
+ # 必需的参数
56
+ text = '消息内容' # 文本信息
57
+
58
+ # 可选参数
59
+ options = {
60
+ at_mobiles: [12345678901], # 数组,被@人的手机号码
61
+ is_at_all: false # Boolean, 是否 @所有人
62
+ }
63
+
64
+ accounts = [:default, :dev] # 数组,配置的key值,支持多机器人同时发送
65
+
66
+ # 方法调用
67
+ DingHook.send_text_msg(text, options = {}, accounts = [:default])
68
+ ```
69
+
70
+ 或者是
71
+
72
+ ```ruby
73
+ params = {
74
+ text: '消息内容',
75
+ at_mobiles: [],
76
+ is_at_all: true
77
+ }
78
+
79
+ DingHook.send_msg(params, :text, accounts)
80
+ ```
81
+
82
+ ### link类型消息
83
+
84
+ ```ruby
85
+ # 必需参数
86
+ text = '消息内容。如果太长只会部分展示'
87
+ title = '消息标题'
88
+ msg_url = '点击消息跳转的URL'
89
+
90
+ # 可选参数
91
+ options = {
92
+ pic_url: '图片链接'
93
+ }
94
+
95
+ DingHook.send_link_msg(title, text, msg_url, options = {}, accounts = [:default])
96
+ ```
97
+
98
+ 或者是
99
+
100
+ ```ruby
101
+ params = {
102
+ text: '消息内容。如果太长只会部分展示',
103
+ title: '消息标题',
104
+ message_url: '点击消息跳转的URL',
105
+ pic_url: '图片链接'
106
+ }
107
+
108
+ DingHook.send_msg(params, :link, accounts)
109
+ ```
110
+
111
+ ### markdown类型消息
112
+ ```ruby
113
+ # 必需参数
114
+ title = '首屏会话透出的展示内容'
115
+ text = 'markdown格式的消息'
116
+
117
+ # 可选参数
118
+ options = {
119
+ at_mobiles: [],
120
+ is_at_all: false
121
+ }
122
+
123
+ # 调用方法
124
+ DingHook.send_markdown_msg(title, text, options = {}, accounts = [:default])
125
+ ```
126
+ 或者是
127
+
128
+ ```ruby
129
+ params = {
130
+ text: 'markdown格式的消息',
131
+ title: '首屏会话透出的展示内容',
132
+ at_mobiles: [],
133
+ is_at_all: false
134
+ }
135
+
136
+ DingHook.send_msg(params, :markdown, accounts)
137
+ ```
138
+
139
+ ### 发送单个按钮的action_card
140
+ ````ruby
141
+ # 必需参数
142
+ title = '首屏会话透出的展示内容'
143
+ text = 'markdown格式的消息'
144
+ single_title = '按钮提示'
145
+ single_url = '点击按钮触发的URL'
146
+
147
+ # 可选参数
148
+ options = {
149
+ btn_orientation: '按钮排列方式,0:垂直排列,1:横向排列',
150
+ hide_avator: '0-正常发消息者头像,1-隐藏发消息者头像'
151
+ }
152
+
153
+ # 方法调用
154
+ DingHook.send_single_action_card(title, text, single_title, single_url, options = {}, accounts = [:default])
155
+ ````
156
+
157
+ 或者是
158
+ ```ruby
159
+ params = {
160
+ title: '首屏会话透出的展示内容',
161
+ text: 'markdown格式的消息',
162
+ single_title: '按钮提示',
163
+ single_url: '点击按钮触发的URL',
164
+ btn_orientation: '按钮排列方式,0:垂直排列,1:横向排列',
165
+ hide_avator: '0-正常发消息者头像,1-隐藏发消息者头像'
166
+ }
167
+
168
+ DingHook.send_msg(params, :action_card, accounts)
169
+ ```
170
+
171
+ ### 发送多个按钮的action_card
172
+
173
+ ```ruby
174
+ # 必需参数
175
+ text = 'markdown格式的消息'
176
+ title = '首屏会话透出的展示内容'
177
+ btns = [{
178
+ title: '按钮方案',
179
+ action_url: '点击按钮触发的URL'
180
+ }]
181
+
182
+ # 可选参数
183
+ options = {
184
+ btn_orientation: '按钮排列方式,0:垂直排列,1:横向排列',
185
+ hide_avator: '0-正常发消息者头像,1-隐藏发消息者头像'
186
+ }
187
+
188
+ # 方法调用
189
+ DingHook.send_btns_action_card(title, text, btns, options = {}, accounts = [:default])
190
+ ```
191
+ 或者是
192
+ ```ruby
193
+ params = {
194
+ title: '首屏会话透出的展示内容',
195
+ text: 'markdown格式的消息',
196
+ btns: [{
197
+ title: '按钮方案',
198
+ action_url: '点击按钮触发的URL',
199
+ }],
200
+ btn_orientation: '按钮排列方式,0:垂直排列,1:横向排列',
201
+ hide_avator: '0-正常发消息者头像,1-隐藏发消息者头像'
202
+ }
203
+
204
+ DingHook.send_msg(params, :action_card, accounts)
205
+ ```
206
+
207
+ ### 发送feed_card消息
208
+ ```ruby
209
+ # 必需参数
210
+ links = [
211
+ {
212
+ title: '单条信息文本',
213
+ message_url: '点击单条信息到跳转链接',
214
+ pic_url: '单条信息后面图片的URL'
215
+ }
216
+ ]
217
+
218
+ # 方法调用
219
+ DingHook.send_feed_card(links, accounts = [:default])
220
+ ```
221
+
222
+ 或者是
223
+
224
+ ```ruby
225
+ params = {
226
+ links: [
227
+ {
228
+ title: '单条信息文本',
229
+ message_url: '点击单条信息到跳转链接',
230
+ pic_url: '单条信息后面图片的URL'
231
+ }
232
+ ]
233
+ }
234
+
235
+ DingHook.send_msg(params, accounts)
236
+ ```
237
+ ### 返回格式
238
+ `[true, msg]`
239
+ - true: Boolean 消息发送成功;多账号同时发送时,只有全部成功才会返回true
240
+ - msg: String 错误消息提示
241
+
242
+ ## 命令行使用
243
+ ```shell
244
+ $ bundle exec ding_hook -h
245
+ Usage: ding_hook [options]
246
+
247
+ Specific options:
248
+ -t, --type TYPE the type of msg to send: text, link, markdown, action_card, feed_card
249
+ -a <Account1,Account2...>, the accounts that want to send msg
250
+ --accounts
251
+ -c <Account,Access_token>, the config of accounts
252
+ --config
253
+ --text TEXT the content of msg
254
+ --title TITLE the title of msg
255
+ --mobiles <Phone_no_1,Phone_no_2...>
256
+ the array of mobiles that want to @
257
+ --[no-]all the option is want to @all
258
+ --msg-url the message url of msg
259
+ --pic-url the picture url of msg
260
+ --[no-]btn-vertical Buttons are arranged vertically
261
+ --[no-]show-avator show the avator of sender
262
+ --btns <Title,ActionURL> multi btns for action card
263
+ --single-title Single_title the single btn title for action card
264
+ --single-url Single_url the single btn url for action card
265
+ --links <Title,MessageURL,PicURL>
266
+ the links for feed card
267
+
268
+ Common options:
269
+ -h, --help Show the help message
270
+ -v, --version Show version
271
+
272
+ ```
273
+
274
+ ⚠️:发送对应类型消息时,请参考上面文档,提供所必须的参数,否则消息会发送失败或出现异常错误
275
+
276
+ 例子:
277
+ ```shell
278
+ $ bundle exec ding_hook -c default,access_token -t action_card -a default --text 我爱你 --title ❤ --btns homepage,https://renyijiu.com --btns blog,htts://blog.renyijiu.com --no-btn-vertical --show-avator
279
+
280
+ ```
281
+
282
+ ## 如何贡献
283
+
284
+ 1. Fork it
285
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
286
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
287
+ 4. Push to the branch (`git push origin my-new-feature`)
288
+ 5. Create new Pull Request
289
+
290
+ 欢迎贡献相关代码或是反馈使用时遇到的问题👏,另外请记得为你的代码编写测试。
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ding_hook"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/ding_hook ADDED
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "optparse"
5
+ require "ding_hook"
6
+
7
+ class DingHookOptparser
8
+
9
+ class Parser
10
+ def initialize
11
+ @result = {}
12
+ end
13
+
14
+ def result
15
+ @result
16
+ end
17
+
18
+ def define_options(parser)
19
+ parser.banner = "Usage: ding_hook [options]"
20
+ parser.separator ""
21
+ parser.separator "Specific options:"
22
+
23
+ type_option(parser)
24
+ accounts_option(parser)
25
+ config_option(parser)
26
+ text_option(parser)
27
+ title_option(parser)
28
+ mobiles_option(parser)
29
+ at_all_option(parser)
30
+ message_url_option(parser)
31
+ pic_url_option(parser)
32
+ btn_orientation_option(parser)
33
+ hide_avator_option(parser)
34
+ btns_option(parser)
35
+ single_title_option(parser)
36
+ single_url_option(parser)
37
+ links_option(parser)
38
+
39
+ parser.separator ""
40
+ parser.separator "Common options:"
41
+
42
+ parser.on_tail("-h", "--help", "Show the help message") do
43
+ puts parser
44
+ exit
45
+ end
46
+ # Another typical switch to print the version.
47
+ parser.on_tail("-v", "--version", "Show version") do
48
+ puts DingHook::VERSION
49
+ exit
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def type_option(parser)
56
+ parser.on("-t", "--type TYPE", [:text, :link, :markdown, :action_card, :feed_card], "the type of msg to send: text, link, markdown, action_card, feed_card") do |type|
57
+ @result[:type] = type.to_sym
58
+ end
59
+ end
60
+
61
+ def accounts_option(parser)
62
+ parser.on("-a", "--accounts <Account1,Account2...>", Array, "the accounts that want to send msg") do |accounts|
63
+ @result[:accounts] = accounts.map(&:to_sym)
64
+ end
65
+ end
66
+
67
+ def config_option(parser)
68
+ parser.on("-c", "--config <Account,Access_token>", Array, "the config of accounts") do |config|
69
+ tmp_config = @result[:config] || []
70
+ @result[:config] = tmp_config << config
71
+ end
72
+ end
73
+
74
+ def text_option(parser)
75
+ parser.on("--text TEXT", String, "the content of msg") do |text|
76
+ tmp_params = @result[:params] || {}
77
+ tmp_params[:text] = text
78
+ @result[:params] = tmp_params
79
+ end
80
+ end
81
+
82
+ def title_option(parser)
83
+ parser.on("--title TITLE", String, "the title of msg") do |title|
84
+ tmp_params = @result[:params] || {}
85
+ tmp_params[:title] = title
86
+ @result[:params] = tmp_params
87
+ end
88
+ end
89
+
90
+ def mobiles_option(parser)
91
+ parser.on("--mobiles <Phone_no_1,Phone_no_2...>", Array, "the array of mobiles that want to @") do |mobiles|
92
+ tmp_params = @result[:params] || {}
93
+ tmp_params[:at_mobiles] = mobiles || []
94
+ @result[:params] = tmp_params
95
+ end
96
+ end
97
+
98
+ def at_all_option(parser)
99
+ parser.on("--[no-]all", "the option is want to @all") do |all|
100
+ tmp_params = result[:params] || {}
101
+ tmp_params[:is_at_all] = all
102
+ @result[:params] = tmp_params
103
+ end
104
+ end
105
+
106
+ def message_url_option(parser)
107
+ parser.on("--msg-url", String, "the message url of msg") do |msg_url|
108
+ tmp_params = result[:params] || {}
109
+ tmp_params[:message_url] = msg_url
110
+ @result[:params] = tmp_params
111
+ end
112
+ end
113
+
114
+ def pic_url_option(parser)
115
+ parser.on("--pic-url", String, "the picture url of msg") do |pic_url|
116
+ tmp_params = result[:params] || {}
117
+ tmp_params[:pic_url] = msg_url
118
+ @result[:params] = tmp_params
119
+ end
120
+ end
121
+
122
+ def btn_orientation_option(parser)
123
+ parser.on("--[no-]btn-vertical", "Buttons are arranged vertically") do |btn|
124
+ tmp_params = result[:params] || {}
125
+ tmp_params[:btn_orientation] = btn ? '0' : '1'
126
+ @result[:params] = tmp_params
127
+ end
128
+ end
129
+
130
+ def hide_avator_option(parser)
131
+ parser.on("--[no-]show-avator", "show the avator of sender") do |show_avator|
132
+ tmp_params = result[:params] || {}
133
+ tmp_params[:hide_avator] = show_avator ? '0' : '1'
134
+ @result[:params] = tmp_params
135
+ end
136
+ end
137
+
138
+ def btns_option(parser)
139
+ parser.on("--btns <Title,ActionURL>", Array, "multi btns for action card") do |btn|
140
+ tmp_params = result[:params] || {}
141
+ tmp_btns = tmp_params[:btns] || []
142
+ tmp_params[:btns] = tmp_btns << {title: btn.first, action_url: btn.last}
143
+ @result[:params] = tmp_params
144
+ end
145
+ end
146
+
147
+ def single_title_option(parser)
148
+ parser.on("--single-title Single_title", String, "the single btn title for action card") do |single_title|
149
+ tmp_params = result[:params] || {}
150
+ tmp_params[:single_title] = single_title
151
+ @result[:params] = tmp_params
152
+ end
153
+ end
154
+
155
+ def single_url_option(parser)
156
+ parser.on("--single-url Single_url", String, "the single btn url for action card") do |single_url|
157
+ tmp_params = result[:params] || {}
158
+ tmp_params[:single_url] = single_url
159
+ @result[:params] = tmp_params
160
+ end
161
+ end
162
+
163
+ def links_option(parser)
164
+ parser.on("--links <Title,MessageURL,PicURL>", Array, "the links for feed card") do |link|
165
+ tmp_params = result[:params] || {}
166
+ tmp_links = tmp_params[:links] || []
167
+
168
+ title, msg_url, pic_url = link
169
+ tmp_params[:links] = tmp_links << {title: title, message_url: msg_url, pic_url: pic_url}
170
+ @result[:params] = tmp_params
171
+ end
172
+ end
173
+ end
174
+
175
+ attr_reader :parser, :options
176
+ def parse(args)
177
+ @options = Parser.new
178
+ @args = OptionParser.new do |parser|
179
+ @options.define_options(parser)
180
+ parser.parse!(args)
181
+ end
182
+
183
+ @options.result
184
+ end
185
+ end
186
+
187
+ parser = DingHookOptparser.new
188
+ options = parser.parse(ARGV)
189
+
190
+ DingHook.configure do |config|
191
+ accounts = options[:config] || []
192
+
193
+ accounts.each do |account|
194
+ config[account.first.to_sym] = account.last
195
+ end
196
+ end
197
+
198
+ DingHook.send_msg(options[:params], options[:type], options[:accounts])
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/ding_hook.gemspec ADDED
@@ -0,0 +1,38 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "ding_hook/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ding_hook"
8
+ spec.version = DingHook::VERSION
9
+ spec.authors = ["renyijiu"]
10
+ spec.email = ["lanyuejin1108@gmail.com"]
11
+
12
+ spec.summary = %q{a gem build for dingding webhook}
13
+ spec.description = %q{a gem build for use the dingding webhook convenient and happy}
14
+ spec.homepage = "https://github.com/renyijiu/ding_hook"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata["allowed_push_host"] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against " \
22
+ "public gem pushes."
23
+ end
24
+
25
+ # Specify which files should be added to the gem when it is released.
26
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
27
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
28
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
29
+ end
30
+ spec.bindir = "bin"
31
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_development_dependency "bundler", "~> 1.16"
35
+ spec.add_development_dependency "rake", "~> 10.0"
36
+ spec.add_development_dependency "minitest", "~> 5.0"
37
+ spec.add_development_dependency "mocha", "~> 1.7"
38
+ end
data/lib/ding_hook.rb ADDED
@@ -0,0 +1,95 @@
1
+ require "ding_hook/version"
2
+ require "ding_hook/config"
3
+ require "ding_hook/exception"
4
+ require "ding_hook/valid"
5
+ require "ding_hook/message"
6
+
7
+ module DingHook
8
+
9
+ class << self
10
+ def configure
11
+ config_hash = {}
12
+ yield(config_hash)
13
+
14
+ config = DingHook::Config.instance
15
+ config.configuration(config_hash)
16
+ end
17
+
18
+ def config
19
+ DingHook::Config.instance.configuration
20
+ end
21
+
22
+ def send_msg(params, type = :text, accounts = [:default])
23
+ ding = DingHook::Message.new
24
+
25
+ ding.send_msg(params, accounts, type.to_sym)
26
+ end
27
+
28
+ def send_text_msg(text, options = {}, accounts = [:default])
29
+ params = {
30
+ text: text,
31
+ at_mobiles: options.fetch(:at_mobiles, []),
32
+ is_at_all: options.fetch(:is_at_all, false)
33
+ }
34
+
35
+ DingHook::Message.new.send_msg(params, accounts, :text)
36
+ end
37
+
38
+ def send_link_msg(title, text, msg_url, options = {}, accounts = [:default])
39
+ params = {
40
+ text: text,
41
+ title: title,
42
+ message_url: msg_url,
43
+ pic_url: options.fetch(:pic_url, nil)
44
+ }
45
+
46
+ DingHook::Message.new.send_msg(params, accounts, :link)
47
+ end
48
+
49
+ def send_markdown_msg(title, text, options = {}, accounts = [:default])
50
+ params = {
51
+ text: text,
52
+ title: title,
53
+ at_mobiles: options.fetch(:at_mobiles, []),
54
+ is_at_all: options.fetch(:is_at_all, false)
55
+ }
56
+
57
+ DingHook::Message.new.send_msg(params, accounts, :markdown)
58
+ end
59
+
60
+ def send_single_action_card(title, text, single_title, single_url, options = {}, accounts = [:default])
61
+ params = {
62
+ title: title,
63
+ text: text,
64
+ single_title: single_title,
65
+ single_url: single_url,
66
+ btn_orientation: options.fetch(:btn_orientation, nil),
67
+ hide_avator: options.fetch(:hide_avator, nil)
68
+ }
69
+
70
+ DingHook::Message.new.send_msg(params, accounts, :action_card)
71
+ end
72
+
73
+ def send_btns_action_card(title, text, btns, options = {}, accounts = [:default])
74
+ btns = btns.is_a?(Array) ? btns : [btns]
75
+ params = {
76
+ title: title,
77
+ text: text,
78
+ btns: btns,
79
+ btn_orientation: options.fetch(:btn_orientation, nil),
80
+ hide_avator: options.fetch(:hide_avator, nil)
81
+ }
82
+
83
+ DingHook::Message.new.send_msg(params, accounts, :action_card)
84
+ end
85
+
86
+ def send_feed_card(links, accounts = [:default])
87
+ links = links.is_a?(Array) ? links : [links]
88
+ params = {
89
+ links: links
90
+ }
91
+
92
+ DingHook::Message.new.send_msg(params, accounts, :feed_card)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,41 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+ require 'singleton'
4
+
5
+ module DingHook
6
+ class Config
7
+ include Singleton
8
+
9
+ def configuration(config = {})
10
+ @config ||= yaml_settings.tap do |tmp_config|
11
+ config.each do |key, value|
12
+ tmp_config[key.to_sym] = value if value
13
+ end
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def yaml_settings
20
+ @yaml_settings ||= begin
21
+ if defined?(Rails::VERSION)
22
+ file = Rails.root.join('config', 'dinghook.yml')
23
+
24
+ resolve_config_file(file)
25
+ else
26
+ config_file = File.join(Dir.getwd, 'config', 'dinghook.yml')
27
+ home_config_file = File.join(Dir.home, '.dinghook.yml')
28
+
29
+ return resolve_config_file(config_file) if File.exist?(config_file)
30
+
31
+ resolve_config_file(home_config_file)
32
+ end
33
+ end
34
+ end
35
+
36
+ def resolve_config_file(file)
37
+ File.exist?(file) ? YAML.load(ERB.new(File.read(file)).result) : {}
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,8 @@
1
+ module DingHook
2
+ module Exception
3
+
4
+ class MsgTypeError < StandardError; end
5
+ class AccountError < StandardError; end
6
+
7
+ end
8
+ end
@@ -0,0 +1,123 @@
1
+ require 'uri'
2
+ require 'openssl'
3
+ require 'json'
4
+ require 'net/http'
5
+
6
+ module DingHook
7
+ class Message
8
+ include DingHook::Valid
9
+
10
+ BASE_URL = 'https://oapi.dingtalk.com/robot/send?access_token='.freeze
11
+
12
+ def send_msg(params, accounts, type = :text)
13
+ accounts = accounts.is_a?(Array) ? accounts : [accounts]
14
+ check_msg_type_valid(type)
15
+ check_account_valid(accounts)
16
+
17
+ result = []
18
+ body = send("#{type}_body_params".to_sym, params)
19
+
20
+ accounts.each do |account|
21
+ hook_url = BASE_URL + DingHook.config.fetch(account.to_sym)
22
+
23
+ res = post(hook_url, body)
24
+ res = JSON.parse(res.body.force_encoding('UTF-8'))
25
+ result << [res['errcode'] == 0, res['errmsg']]
26
+ end
27
+
28
+ result.inject([true, '']) {|res, arr| [res.first && arr.first, res.last + arr.last]}
29
+ end
30
+
31
+ private
32
+
33
+ def post(hook_url, body)
34
+ url = URI(hook_url)
35
+
36
+ http = Net::HTTP.new(url.host, url.port)
37
+ http.use_ssl = true
38
+ http.verify_mode = ::OpenSSL::SSL::VERIFY_NONE
39
+
40
+ request = Net::HTTP::Post.new(url)
41
+ request['content-type'] = 'application/json'
42
+ request.body = body
43
+
44
+ http.request(request)
45
+ end
46
+
47
+ def text_body_params(params)
48
+ {
49
+ msgtype: :text,
50
+ text: {
51
+ content: params.fetch(:text, nil)
52
+ },
53
+ at: {
54
+ atMobiles: params.fetch(:at_mobiles, []),
55
+ isAtAll: params.fetch(:is_at_all, false)
56
+ }
57
+ }.to_json
58
+ end
59
+
60
+ def link_body_params(params)
61
+ {
62
+ msgtype: :link,
63
+ link: {
64
+ text: params.fetch(:text, nil),
65
+ title: params.fetch(:title, nil),
66
+ picUrl: params.fetch(:pic_url, nil),
67
+ messageUrl: params.fetch(:message_url, nil)
68
+ }
69
+ }.to_json
70
+ end
71
+
72
+ def markdown_body_params(params)
73
+ {
74
+ msgtype: :markdown,
75
+ markdown: {
76
+ title: params.fetch(:title, nil),
77
+ text: params.fetch(:text, nil)
78
+ },
79
+ at: {
80
+ atMobiles: params.fetch(:at_mobiles, []),
81
+ isAtAll: params.fetch(:is_at_all, false)
82
+ }
83
+ }.to_json
84
+ end
85
+
86
+ def action_card_body_params(params)
87
+ btns = params.fetch(:btns, nil)
88
+
89
+ if btns.nil?
90
+ res = {singleTitle: params.fetch(:single_title, nil), singleURL: params.fetch(:single_url, nil)}
91
+ else
92
+ res = {btns: btns.map{ |btn| {title: btn.fetch(:title, nil), actionURL: btn.fetch(:action_url, nil)} }}
93
+ end
94
+
95
+ {
96
+ msgtype: :actionCard,
97
+ actionCard: {
98
+ title: params.fetch(:title, nil),
99
+ text: params.fetch(:text, nil),
100
+ btnOrientation: params.fetch(:btn_orientation, '0'),
101
+ hideAvator: params.fetch(:hide_avator, '0'),
102
+ }.merge(res)
103
+ }.to_json
104
+ end
105
+
106
+ def feed_card_body_params(params)
107
+ links = params.fetch(:links, [{}]).map do |link|
108
+ {
109
+ title: link.fetch(:title, nil),
110
+ messageURL: link.fetch(:message_url, nil),
111
+ pic_url: link.fetch(:pic_url, nil)
112
+ }
113
+ end
114
+
115
+ {
116
+ msgtype: :feedCard,
117
+ feedCard: {
118
+ links: links
119
+ }
120
+ }.to_json
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,23 @@
1
+ module DingHook
2
+ module Valid
3
+
4
+ VALID_TYPE = [:text, :link, :markdown, :action_card, :feed_card]
5
+
6
+ def check_msg_type_valid(type)
7
+ unless VALID_TYPE.include?(type.to_sym)
8
+ raise DingHook::Exception::MsgTypeError, "无效消息类型,目前支持:#{VALID_TYPE.join(', ')}"
9
+ end
10
+ end
11
+
12
+ def check_account_valid(accounts)
13
+ accounts.each do |account|
14
+ token = DingHook.config.fetch(account.to_sym, nil)
15
+
16
+ if token.nil?
17
+ raise DingHook::Exception::AccountError, "#{account} 对应的access_token未配置"
18
+ end
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ module DingHook
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ding_hook
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - renyijiu
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mocha
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.7'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.7'
69
+ description: a gem build for use the dingding webhook convenient and happy
70
+ email:
71
+ - lanyuejin1108@gmail.com
72
+ executables:
73
+ - console
74
+ - ding_hook
75
+ - setup
76
+ extensions: []
77
+ extra_rdoc_files: []
78
+ files:
79
+ - ".gitignore"
80
+ - ".travis.yml"
81
+ - CODE_OF_CONDUCT.md
82
+ - Gemfile
83
+ - README.md
84
+ - Rakefile
85
+ - bin/console
86
+ - bin/ding_hook
87
+ - bin/setup
88
+ - ding_hook.gemspec
89
+ - lib/ding_hook.rb
90
+ - lib/ding_hook/config.rb
91
+ - lib/ding_hook/exception.rb
92
+ - lib/ding_hook/message.rb
93
+ - lib/ding_hook/valid.rb
94
+ - lib/ding_hook/version.rb
95
+ homepage: https://github.com/renyijiu/ding_hook
96
+ licenses: []
97
+ metadata:
98
+ allowed_push_host: https://rubygems.org
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.7.7
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: a gem build for dingding webhook
119
+ test_files: []