dingtalk-robot 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5610c1eb754261c791d47dea3e5d27f3f42b51e7865ea250b49a9acf52d919b2
4
- data.tar.gz: ab3d436f7ea8acc7ddb1aec8521547845da90c89713671e30222f6b109d15f82
3
+ metadata.gz: 97b1c273fef2a375e19ecd2381ddc54d2fa63e24e75e009950c7f7d90344abb6
4
+ data.tar.gz: 37727da06b77aa56244ed350b6b521afee42e7a446c16caa1bff822de72d6dc7
5
5
  SHA512:
6
- metadata.gz: 80806218ea40567fa48584dd7c5af3b45ba750d00f4bf2d6f47ea2bb185b8c0580c4a58a1ef791c5697a9b444925b8d97bb27123a4f7feb0f5e66959d6dc951d
7
- data.tar.gz: b05e185d0d1eefd1588548013bbeafdc44e6c613573c6f028f3bce94cb7718d96f2b8fa7ea23cd5d27e4ed9752a5257b0fd12c842cb2e240be302ebba7b426d5
6
+ metadata.gz: d668b0fa121bf6d758657668f4c99d0fa9604b3161a3a25c04667710d0290d906e91916c3d87f260f1ba276fb9b505608ea3f4e41ccabfdbef4f5dc1d8d242a7
7
+ data.tar.gz: c132ab63e4a0eddf88f459c24c4cb3e76a25261f6bdd25b2651aad5d84aa22d9ac84851328ce8bd760580acacc4e8b0fb024a3bfbfbad9681f971a56482135e7
data/.gitignore CHANGED
@@ -6,3 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /.byebug_history
10
+ /.DS_Store
11
+ /Gemfile.lock
12
+ /.ruby-version
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.5
2
+ TargetRubyVersion: 2.3
3
3
  Metrics/LineLength:
4
4
  Max: 120
5
5
  Metrics/MethodLength:
data/Gemfile CHANGED
@@ -7,7 +7,6 @@ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
7
7
  # Specify your gem's dependencies in active_notifier.gemspec
8
8
  gemspec
9
9
 
10
- gem 'bundler', '~> 1.16'
11
10
  gem 'byebug'
12
11
  gem 'codecov', '>= 0.1.10', require: false
13
12
  gem 'rake', '~> 10.0'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # Dingtalk::Robot
1
+ # Dingtalk Robot
2
2
 
3
- A simple wrapper for [DingTalk Group Robot](https://open-doc.dingtalk.com/microapp/serverapi2/qf2nxq).
3
+ A simple wrapper for [Dingtalk Group Robot](https://open-doc.dingtalk.com/microapp/serverapi2/qf2nxq).
4
4
 
5
5
  [![Gem Version](https://badge.fury.io/rb/dingtalk-robot.svg)](https://rubygems.org/gems/dingtalk-robot)
6
6
  [![Build Status](https://travis-ci.org/pinewong/dingtalk-robot.svg)](https://travis-ci.org/pinewong/dingtalk-robot)
@@ -29,7 +29,20 @@ $ gem install dingtalk-robot
29
29
 
30
30
  ## Usage
31
31
 
32
- TODO: Write usage instructions here
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
 
@@ -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 DingTalk Group Robot.'
14
- spec.description = 'A simple wrapper for DingTalk Group Robot.'
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
@@ -1,11 +1,78 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dingtalk/robot/version'
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
- module Robot
9
- # Your code goes here...
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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dingtalk
4
- module Robot
5
- VERSION = '0.1.0'
4
+ class Robot
5
+ VERSION = '0.2.0'
6
6
  end
7
7
  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.1.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-16 00:00:00.000000000 Z
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 DingTalk Group Robot.
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: '0'
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 DingTalk Group Robot.
86
+ summary: A simple wrapper for Dingtalk Group Robot.
71
87
  test_files: []
@@ -1 +0,0 @@
1
- 2.5.1
@@ -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