dingtalk-robot 0.1.0 → 0.2.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 +4 -4
- data/.gitignore +4 -0
- data/.rubocop.yml +1 -1
- data/Gemfile +0 -1
- data/README.md +16 -3
- data/dingtalk-robot.gemspec +4 -2
- data/lib/dingtalk/robot.rb +70 -3
- data/lib/dingtalk/robot/configurable.rb +65 -0
- data/lib/dingtalk/robot/errors.rb +26 -0
- data/lib/dingtalk/robot/strategies/markdown_strategy.rb +47 -0
- data/lib/dingtalk/robot/strategies/text_strategy.rb +43 -0
- data/lib/dingtalk/robot/version.rb +2 -2
- metadata +23 -7
- data/.ruby-version +0 -1
- data/Gemfile.lock +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97b1c273fef2a375e19ecd2381ddc54d2fa63e24e75e009950c7f7d90344abb6
|
4
|
+
data.tar.gz: 37727da06b77aa56244ed350b6b521afee42e7a446c16caa1bff822de72d6dc7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d668b0fa121bf6d758657668f4c99d0fa9604b3161a3a25c04667710d0290d906e91916c3d87f260f1ba276fb9b505608ea3f4e41ccabfdbef4f5dc1d8d242a7
|
7
|
+
data.tar.gz: c132ab63e4a0eddf88f459c24c4cb3e76a25261f6bdd25b2651aad5d84aa22d9ac84851328ce8bd760580acacc4e8b0fb024a3bfbfbad9681f971a56482135e7
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Dingtalk
|
1
|
+
# Dingtalk Robot
|
2
2
|
|
3
|
-
A simple wrapper for [
|
3
|
+
A simple wrapper for [Dingtalk Group Robot](https://open-doc.dingtalk.com/microapp/serverapi2/qf2nxq).
|
4
4
|
|
5
5
|
[](https://rubygems.org/gems/dingtalk-robot)
|
6
6
|
[](https://travis-ci.org/pinewong/dingtalk-robot)
|
@@ -29,7 +29,20 @@ $ gem install dingtalk-robot
|
|
29
29
|
|
30
30
|
## Usage
|
31
31
|
|
32
|
-
|
32
|
+
```ruby
|
33
|
+
# Config api token and message template directory
|
34
|
+
Dingtalk::Robot.config.tokens = { order: 'WEBHOOK...' }
|
35
|
+
Dingtalk::Robot.config.template_dir = '.'
|
36
|
+
system %q(echo 'hello, <%= @name %>' > order.text.erb)
|
37
|
+
|
38
|
+
# Notify message
|
39
|
+
robot = Dingtalk::Robot.new(:order) { @name = 'Pine Wong' }
|
40
|
+
robot.notify
|
41
|
+
```
|
42
|
+
|
43
|
+
## Help and Docs
|
44
|
+
|
45
|
+
* [RDoc](https://www.rubydoc.info/github/pinewong/dingtalk-robot)
|
33
46
|
|
34
47
|
## Development
|
35
48
|
|
data/dingtalk-robot.gemspec
CHANGED
@@ -10,8 +10,8 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.authors = ['Pine Wong']
|
11
11
|
spec.email = ['pinewong@163.com']
|
12
12
|
|
13
|
-
spec.summary = 'A simple wrapper for
|
14
|
-
spec.description = 'A simple wrapper for
|
13
|
+
spec.summary = 'A simple wrapper for Dingtalk Group Robot.'
|
14
|
+
spec.description = 'A simple wrapper for Dingtalk Group Robot.'
|
15
15
|
spec.homepage = 'https://github.com/pinewong/dingtalk-robot'
|
16
16
|
|
17
17
|
# Specify which files should be added to the gem when it is released.
|
@@ -23,5 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ['lib']
|
25
25
|
|
26
|
+
spec.required_ruby_version = '>= 2.3'
|
27
|
+
spec.add_dependency 'activesupport', '~> 5.0'
|
26
28
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
27
29
|
end
|
data/lib/dingtalk/robot.rb
CHANGED
@@ -1,11 +1,78 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'net/http'
|
5
|
+
require 'dingtalk/robot/configurable'
|
6
|
+
require 'dingtalk/robot/errors'
|
7
|
+
require 'dingtalk/robot/strategies/text_strategy'
|
8
|
+
require 'dingtalk/robot/strategies/markdown_strategy'
|
4
9
|
|
5
10
|
module Dingtalk
|
6
11
|
# DingTalk Group Robot
|
7
12
|
# @see https://open-doc.dingtalk.com/microapp/serverapi2/qf2nxq
|
8
|
-
|
9
|
-
|
13
|
+
class Robot
|
14
|
+
include Configurable
|
15
|
+
delegate :notify, to: :message_strategy
|
16
|
+
|
17
|
+
# @param channel [#to_sym] Set both api token and message template
|
18
|
+
# @param message_type [#to_sym] (:text) Message type
|
19
|
+
# @example
|
20
|
+
# # Config api token and message template directory
|
21
|
+
# Dingtalk::Robot.config.tokens = { order: 'WEBHOOK...' }
|
22
|
+
# Dingtalk::Robot.config.template_dir = '.'
|
23
|
+
# system %q(echo 'hello, <%= @name %>' > order.text.erb)
|
24
|
+
#
|
25
|
+
# # Notify message
|
26
|
+
# robot = Dingtalk::Robot.new(:order) { @name = 'Pine Wong' }
|
27
|
+
# robot.notify
|
28
|
+
def initialize(channel, message_type = nil, &context_block)
|
29
|
+
@channel = channel.to_sym
|
30
|
+
self.message_type = message_type&.to_sym
|
31
|
+
@context_block = context_block
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_reader :channel, :message_type, :context_block
|
37
|
+
delegate :config, to: :class
|
38
|
+
|
39
|
+
# @param message_type [Symbol, nil]
|
40
|
+
def message_type=(message_type)
|
41
|
+
@message_type = message_type || begin
|
42
|
+
template_paths = Dir["#{config.template_dir}/#{channel}.*.erb"]
|
43
|
+
if template_paths.empty?
|
44
|
+
raise ArgumentError, "Undefined channel template, channel: #{channel}, template_dir: #{config.template_dir}"
|
45
|
+
end
|
46
|
+
types = template_paths.map do |template_path|
|
47
|
+
template_path[%r{#{config.template_dir}/#{channel}.([a-zA-Z]+).erb}, 1].to_sym
|
48
|
+
end
|
49
|
+
types.include?(config.message_type) ? config.message_type : types.first
|
50
|
+
end
|
51
|
+
valid = VALID_MESSAGE_TYPES.include?(@message_type)
|
52
|
+
raise ConfigurationError.new(:message_type, @message_type, VALID_MESSAGE_TYPES) unless valid
|
53
|
+
end
|
54
|
+
|
55
|
+
def message_strategy
|
56
|
+
self.class.const_get("#{message_type.to_s.camelize}Strategy").new(webhook_url, message)
|
57
|
+
end
|
58
|
+
|
59
|
+
def webhook_url
|
60
|
+
token = config.tokens[channel]
|
61
|
+
raise ArgumentError, "Undefined channel token, channel: #{channel}, tokens: #{config.tokens}" unless token
|
62
|
+
"#{WEBHOOK_BASE_URL}#{token}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def message
|
66
|
+
path = "#{config.template_dir}/#{channel}.#{message_type}.erb"
|
67
|
+
ERB.new(File.read(path)).result(context)
|
68
|
+
rescue Errno::ENOENT
|
69
|
+
raise ArgumentError, "Undefined channel template, channel: #{channel}, path: #{path}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def context
|
73
|
+
blank_object = Object.new
|
74
|
+
blank_object.instance_eval(&context_block) if context_block
|
75
|
+
blank_object.instance_eval { binding }
|
76
|
+
end
|
10
77
|
end
|
11
78
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dingtalk
|
4
|
+
class Robot
|
5
|
+
VALID_MESSAGE_TYPES = Dir["#{__dir__}/strategies/*"].map { |path| File.basename(path, '_strategy.rb').to_sym }
|
6
|
+
WEBHOOK_BASE_URL = 'https://oapi.dingtalk.com/robot/send?access_token='
|
7
|
+
|
8
|
+
# @example Config single item
|
9
|
+
# Dingtalk::Robot.tokens = { default: 'TOKENXXXXXXXXXXX' }
|
10
|
+
# @example Config multiple items
|
11
|
+
# Dingtalk::Robot.configure do |config|
|
12
|
+
# config.tokens = { defautl: 'TOKENXXXXXXXXX' }
|
13
|
+
# config.message_type = :markdown
|
14
|
+
# config.template_dir = 'app/views/dingtalk/robot'
|
15
|
+
# end
|
16
|
+
module Configurable
|
17
|
+
def self.included(base)
|
18
|
+
base.extend ClassMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
# @see Configurable
|
22
|
+
module ClassMethods
|
23
|
+
def configure
|
24
|
+
yield config
|
25
|
+
end
|
26
|
+
|
27
|
+
def config
|
28
|
+
@config ||= Configuration.new
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# @see Configurable
|
33
|
+
class Configuration
|
34
|
+
attr_reader :message_type
|
35
|
+
|
36
|
+
def initialize
|
37
|
+
self.message_type = :text
|
38
|
+
end
|
39
|
+
|
40
|
+
def tokens=(tokens)
|
41
|
+
@tokens = tokens.to_h.symbolize_keys!
|
42
|
+
end
|
43
|
+
|
44
|
+
def tokens
|
45
|
+
@tokens.presence || (raise ConfigurationError.new(:tokens, @tokens, Hash))
|
46
|
+
end
|
47
|
+
|
48
|
+
def template_dir=(template_dir)
|
49
|
+
@template_dir = template_dir.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def template_dir
|
53
|
+
@template_dir.presence || (raise ConfigurationError.new(:template_dir, @template_dir, String))
|
54
|
+
end
|
55
|
+
|
56
|
+
def message_type=(message_type)
|
57
|
+
unless VALID_MESSAGE_TYPES.include?(message_type.to_sym)
|
58
|
+
raise ConfigurationError.new(:message_type, message_type, VALID_MESSAGE_TYPES)
|
59
|
+
end
|
60
|
+
@message_type = message_type.to_sym
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dingtalk
|
4
|
+
class Robot
|
5
|
+
# Basic exception
|
6
|
+
class Error < StandardError; end
|
7
|
+
|
8
|
+
# :nodoc:
|
9
|
+
class ConfigurationError < Error
|
10
|
+
attr_reader :key, :value, :valid_values
|
11
|
+
|
12
|
+
def initialize(key, value, valid_values)
|
13
|
+
@key = key
|
14
|
+
@valud = value
|
15
|
+
@valid_values = valid_values
|
16
|
+
valid_values_str = Array(valid_values).join(', ')
|
17
|
+
message = if value.blank?
|
18
|
+
"#{key} not configured or configured with blank value, valid_values: #{valid_values_str}"
|
19
|
+
else
|
20
|
+
"Configure #{key} with value #{value} failed, valid_values: #{valid_values_str}"
|
21
|
+
end
|
22
|
+
super(message)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dingtalk
|
4
|
+
class Robot
|
5
|
+
# Markdown type strategy for sending message
|
6
|
+
class MarkdownStrategy
|
7
|
+
def initialize(webhook_url, message)
|
8
|
+
@webhook_url = webhook_url
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
|
12
|
+
# @option options [String] :title (required)
|
13
|
+
# @option options [Array<String>] :at_mobiles
|
14
|
+
# @option options [Boolean] :is_at_all
|
15
|
+
def notify(**options)
|
16
|
+
title = options[:title].to_s
|
17
|
+
raise ArgumentError, 'title must be present, strategy: markdown' if title.empty?
|
18
|
+
at_mobiles = options[:at_mobiles].to_a
|
19
|
+
is_at_all = options[:is_at_all] ? true : false
|
20
|
+
body = generate_body(title, at_mobiles, is_at_all)
|
21
|
+
headers = {
|
22
|
+
'Content-Type': 'application/json',
|
23
|
+
Accept: 'application/json'
|
24
|
+
}
|
25
|
+
Net::HTTP.post(URI(webhook_url), body.to_json, headers).body
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :webhook_url, :message
|
31
|
+
|
32
|
+
def generate_body(title, at_mobiles, is_at_all)
|
33
|
+
{
|
34
|
+
msgtype: :markdown,
|
35
|
+
markdown: {
|
36
|
+
title: title,
|
37
|
+
text: message
|
38
|
+
},
|
39
|
+
at: {
|
40
|
+
atMobiles: at_mobiles,
|
41
|
+
isAtAll: is_at_all
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dingtalk
|
4
|
+
class Robot
|
5
|
+
# Text type strategy for sending message
|
6
|
+
class TextStrategy
|
7
|
+
def initialize(webhook_url, message)
|
8
|
+
@webhook_url = webhook_url
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
|
12
|
+
# @option options [Array<String>] :at_mobiles
|
13
|
+
# @option options [Boolean] :is_at_all
|
14
|
+
def notify(**options)
|
15
|
+
at_mobiles = options[:at_mobiles].to_a
|
16
|
+
is_at_all = options[:is_at_all] ? true : false
|
17
|
+
body = generate_body(at_mobiles, is_at_all)
|
18
|
+
headers = {
|
19
|
+
'Content-Type': 'application/json',
|
20
|
+
Accept: 'application/json'
|
21
|
+
}
|
22
|
+
Net::HTTP.post(URI(webhook_url), body.to_json, headers).body
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
attr_reader :webhook_url, :message
|
28
|
+
|
29
|
+
def generate_body(at_mobiles, is_at_all)
|
30
|
+
{
|
31
|
+
msgtype: :text,
|
32
|
+
text: {
|
33
|
+
content: message
|
34
|
+
},
|
35
|
+
at: {
|
36
|
+
atMobiles: at_mobiles,
|
37
|
+
isAtAll: is_at_all
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dingtalk-robot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pine Wong
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-09-
|
11
|
+
date: 2018-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '5.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,7 +38,7 @@ dependencies:
|
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: '1.16'
|
27
|
-
description: A simple wrapper for
|
41
|
+
description: A simple wrapper for Dingtalk Group Robot.
|
28
42
|
email:
|
29
43
|
- pinewong@163.com
|
30
44
|
executables: []
|
@@ -33,17 +47,19 @@ extra_rdoc_files: []
|
|
33
47
|
files:
|
34
48
|
- ".gitignore"
|
35
49
|
- ".rubocop.yml"
|
36
|
-
- ".ruby-version"
|
37
50
|
- ".travis.yml"
|
38
51
|
- CODE_OF_CONDUCT.md
|
39
52
|
- Gemfile
|
40
|
-
- Gemfile.lock
|
41
53
|
- README.md
|
42
54
|
- Rakefile
|
43
55
|
- bin/console
|
44
56
|
- bin/setup
|
45
57
|
- dingtalk-robot.gemspec
|
46
58
|
- lib/dingtalk/robot.rb
|
59
|
+
- lib/dingtalk/robot/configurable.rb
|
60
|
+
- lib/dingtalk/robot/errors.rb
|
61
|
+
- lib/dingtalk/robot/strategies/markdown_strategy.rb
|
62
|
+
- lib/dingtalk/robot/strategies/text_strategy.rb
|
47
63
|
- lib/dingtalk/robot/version.rb
|
48
64
|
homepage: https://github.com/pinewong/dingtalk-robot
|
49
65
|
licenses: []
|
@@ -56,7 +72,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
56
72
|
requirements:
|
57
73
|
- - ">="
|
58
74
|
- !ruby/object:Gem::Version
|
59
|
-
version: '
|
75
|
+
version: '2.3'
|
60
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
77
|
requirements:
|
62
78
|
- - ">="
|
@@ -67,5 +83,5 @@ rubyforge_project:
|
|
67
83
|
rubygems_version: 2.7.6
|
68
84
|
signing_key:
|
69
85
|
specification_version: 4
|
70
|
-
summary: A simple wrapper for
|
86
|
+
summary: A simple wrapper for Dingtalk Group Robot.
|
71
87
|
test_files: []
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.5.1
|
data/Gemfile.lock
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
dingtalk-robot (0.1.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
ast (2.4.0)
|
10
|
-
byebug (10.0.2)
|
11
|
-
codecov (0.1.10)
|
12
|
-
json
|
13
|
-
simplecov
|
14
|
-
url
|
15
|
-
diff-lcs (1.3)
|
16
|
-
docile (1.3.1)
|
17
|
-
jaro_winkler (1.5.1)
|
18
|
-
json (2.1.0)
|
19
|
-
parallel (1.12.1)
|
20
|
-
parser (2.5.1.2)
|
21
|
-
ast (~> 2.4.0)
|
22
|
-
powerpack (0.1.2)
|
23
|
-
rainbow (3.0.0)
|
24
|
-
rake (10.5.0)
|
25
|
-
rspec (3.8.0)
|
26
|
-
rspec-core (~> 3.8.0)
|
27
|
-
rspec-expectations (~> 3.8.0)
|
28
|
-
rspec-mocks (~> 3.8.0)
|
29
|
-
rspec-core (3.8.0)
|
30
|
-
rspec-support (~> 3.8.0)
|
31
|
-
rspec-expectations (3.8.1)
|
32
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
-
rspec-support (~> 3.8.0)
|
34
|
-
rspec-mocks (3.8.0)
|
35
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
-
rspec-support (~> 3.8.0)
|
37
|
-
rspec-support (3.8.0)
|
38
|
-
rubocop (0.58.2)
|
39
|
-
jaro_winkler (~> 1.5.1)
|
40
|
-
parallel (~> 1.10)
|
41
|
-
parser (>= 2.5, != 2.5.1.1)
|
42
|
-
powerpack (~> 0.1)
|
43
|
-
rainbow (>= 2.2.2, < 4.0)
|
44
|
-
ruby-progressbar (~> 1.7)
|
45
|
-
unicode-display_width (~> 1.0, >= 1.0.1)
|
46
|
-
ruby-progressbar (1.10.0)
|
47
|
-
simplecov (0.16.1)
|
48
|
-
docile (~> 1.1)
|
49
|
-
json (>= 1.8, < 3)
|
50
|
-
simplecov-html (~> 0.10.0)
|
51
|
-
simplecov-html (0.10.2)
|
52
|
-
unicode-display_width (1.4.0)
|
53
|
-
url (0.3.2)
|
54
|
-
|
55
|
-
PLATFORMS
|
56
|
-
ruby
|
57
|
-
|
58
|
-
DEPENDENCIES
|
59
|
-
bundler (~> 1.16)
|
60
|
-
byebug
|
61
|
-
codecov (>= 0.1.10)
|
62
|
-
dingtalk-robot!
|
63
|
-
rake (~> 10.0)
|
64
|
-
rspec (~> 3.7)
|
65
|
-
rubocop (~> 0.58.1)
|
66
|
-
simplecov
|
67
|
-
|
68
|
-
BUNDLED WITH
|
69
|
-
1.16.2
|