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 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