mitake 0.1.2
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/.gitignore +11 -0
- data/.overcommit.yml +34 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +62 -0
- data/LICENSE +21 -0
- data/README.md +101 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/mitake.rb +48 -0
- data/lib/mitake/api.rb +110 -0
- data/lib/mitake/api/base.rb +69 -0
- data/lib/mitake/api/get.rb +33 -0
- data/lib/mitake/api/post.rb +25 -0
- data/lib/mitake/balance.rb +35 -0
- data/lib/mitake/boolean.rb +24 -0
- data/lib/mitake/credential.rb +29 -0
- data/lib/mitake/message.rb +119 -0
- data/lib/mitake/model.rb +38 -0
- data/lib/mitake/model/accessor.rb +72 -0
- data/lib/mitake/model/attributes.rb +30 -0
- data/lib/mitake/parser.rb +60 -0
- data/lib/mitake/recipient.rb +16 -0
- data/lib/mitake/response.rb +21 -0
- data/lib/mitake/status.rb +21 -0
- data/lib/mitake/status_code.rb +9 -0
- data/lib/mitake/version.rb +5 -0
- data/mitake.gemspec +41 -0
- metadata +159 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'net/http'
|
4
|
+
require 'mitake/credential'
|
5
|
+
|
6
|
+
module Mitake
|
7
|
+
module API
|
8
|
+
# @since 0.1.0
|
9
|
+
# @api private
|
10
|
+
class Base
|
11
|
+
# @param path [String] the api endpoint
|
12
|
+
# @param params [Hash] the request body
|
13
|
+
#
|
14
|
+
# @since 0.1.0
|
15
|
+
# @api private
|
16
|
+
def initialize(path, params = {})
|
17
|
+
@path = path
|
18
|
+
@params = params
|
19
|
+
end
|
20
|
+
|
21
|
+
# @since 0.1.0
|
22
|
+
# @api private
|
23
|
+
def request
|
24
|
+
raise NotImplementedError, 'Request not defined!'
|
25
|
+
end
|
26
|
+
|
27
|
+
# Execute HTTP Request
|
28
|
+
#
|
29
|
+
# @return [Net::HTTPResponse] the request result
|
30
|
+
#
|
31
|
+
# @since 0.1.0
|
32
|
+
# @api private
|
33
|
+
def execute
|
34
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: ssl?) do |http|
|
35
|
+
http.request request
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [URI] the request URI
|
40
|
+
#
|
41
|
+
# @since 0.1.0
|
42
|
+
# @api private
|
43
|
+
def uri
|
44
|
+
@uri ||= URI("#{Mitake.credential.server}#{@path}")
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [TrueClass|FalseClass] is the SSL request
|
48
|
+
#
|
49
|
+
# @since 0.1.0
|
50
|
+
# @api private
|
51
|
+
def ssl?
|
52
|
+
@uri.scheme == 'https'
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return the request params
|
56
|
+
#
|
57
|
+
# @return [Hash] the query params
|
58
|
+
#
|
59
|
+
# @since 0.1.0
|
60
|
+
# @api private
|
61
|
+
def params
|
62
|
+
@params.merge(
|
63
|
+
username: Mitake.credential.username,
|
64
|
+
password: Mitake.credential.password
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mitake/api/base'
|
4
|
+
|
5
|
+
module Mitake
|
6
|
+
module API
|
7
|
+
# Create HTTP Get Request
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
# @api private
|
11
|
+
class Get < Base
|
12
|
+
# Create HTTP Get Request
|
13
|
+
#
|
14
|
+
# @since 0.1.0
|
15
|
+
# @api private
|
16
|
+
def request
|
17
|
+
return @request unless @request.nil?
|
18
|
+
|
19
|
+
@request ||= Net::HTTP::Get.new(uri)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @see Mitake::API::Base#uri
|
23
|
+
#
|
24
|
+
# @since 0.1.0
|
25
|
+
# @api private
|
26
|
+
def uri
|
27
|
+
@uri ||=
|
28
|
+
URI("#{Mitake.credential.server}" \
|
29
|
+
"#{@path}?#{URI.encode_www_form(params)}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mitake/api/base'
|
4
|
+
|
5
|
+
module Mitake
|
6
|
+
module API
|
7
|
+
# Create HTTP Get Request
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
# @api private
|
11
|
+
class Post < Base
|
12
|
+
# Create HTTP Post Request
|
13
|
+
#
|
14
|
+
# @since 0.1.0
|
15
|
+
# @api private
|
16
|
+
def request
|
17
|
+
return @request unless @request.nil?
|
18
|
+
|
19
|
+
@request ||= Net::HTTP::Post.new(uri)
|
20
|
+
@request.body = URI.encode_www_form(params)
|
21
|
+
@request
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mitake/api'
|
4
|
+
require 'mitake/model'
|
5
|
+
|
6
|
+
module Mitake
|
7
|
+
# Get the current balance
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
class Balance
|
11
|
+
class << self
|
12
|
+
# Get account point
|
13
|
+
#
|
14
|
+
# @see Mitake::Balance#amount
|
15
|
+
# @return [Integer]
|
16
|
+
#
|
17
|
+
# @since 0.1.0
|
18
|
+
def amount
|
19
|
+
execute&.first&.amount
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
include API
|
24
|
+
include Model
|
25
|
+
|
26
|
+
path '/api/mtk/SmQuery'
|
27
|
+
map 'AccountPoint', 'amount'
|
28
|
+
|
29
|
+
# @!attribute [r] amount
|
30
|
+
# @return [Integer] the amount of account point
|
31
|
+
#
|
32
|
+
# @since 0.1.0
|
33
|
+
attribute :amount, Integer
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mitake
|
4
|
+
# The helper object to define boolean value
|
5
|
+
#
|
6
|
+
# @since 0.1.0
|
7
|
+
# @api private
|
8
|
+
class Boolean
|
9
|
+
TRUE_VALUES = %w[Y 1 yes true].freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
# Parse boolean value
|
13
|
+
#
|
14
|
+
# @since 0.1.0
|
15
|
+
# @api private
|
16
|
+
def parse(value)
|
17
|
+
return true if value == true
|
18
|
+
return true if TRUE_VALUES.include?(value)
|
19
|
+
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mitake
|
4
|
+
# The Mitake SMS Client
|
5
|
+
#
|
6
|
+
# @since 0.1.
|
7
|
+
class Credential
|
8
|
+
# @since 0.1.0
|
9
|
+
# @api private
|
10
|
+
DEFAULT_SERVER = 'https://smsapi.mitake.com.tw'
|
11
|
+
|
12
|
+
# @since 0.1.0
|
13
|
+
attr_reader :username, :password, :server
|
14
|
+
|
15
|
+
# Return Mitake::Client instance
|
16
|
+
#
|
17
|
+
# @param username [String] the username, default is `MITAKE_USERNAME`
|
18
|
+
# @param password [String] the password, default is `MITAKE_PASSWORD`
|
19
|
+
# @param server [String] the API server url
|
20
|
+
# @return [Mitake::Client] the api instance
|
21
|
+
#
|
22
|
+
# @since 0.1.0
|
23
|
+
def initialize(username = nil, password = nil, server = nil)
|
24
|
+
@username = username || ENV['MITAKE_USERNAME']
|
25
|
+
@password = password || ENV['MITAKE_PASSWORD']
|
26
|
+
@server = server || ENV['MITAKE_SERVER'] || DEFAULT_SERVER
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mitake/model'
|
4
|
+
require 'mitake/recipient'
|
5
|
+
require 'mitake/response'
|
6
|
+
require 'mitake/boolean'
|
7
|
+
require 'mitake/status'
|
8
|
+
|
9
|
+
module Mitake
|
10
|
+
# Create Sort Message
|
11
|
+
#
|
12
|
+
# @since 0.1.0
|
13
|
+
class Message
|
14
|
+
include API
|
15
|
+
include Model
|
16
|
+
|
17
|
+
method 'Post'
|
18
|
+
path '/api/mtk/SmSend?CharsetURL=UTF8'
|
19
|
+
map 'msgid', 'id'
|
20
|
+
map 'Duplicate', 'duplicate'
|
21
|
+
map 'statuscode', 'status_code'
|
22
|
+
|
23
|
+
# @!attribute [r] id
|
24
|
+
# @return [String] the message id
|
25
|
+
attribute :id, String, readonly: true
|
26
|
+
|
27
|
+
# @!attribute source_id
|
28
|
+
# @return [String] the customize identity
|
29
|
+
attribute :source_id, String
|
30
|
+
|
31
|
+
# @!attribute receipient
|
32
|
+
# @return [Mitake::Recipient] the message recipient
|
33
|
+
attribute :recipient, Recipient
|
34
|
+
|
35
|
+
# @!attribute body
|
36
|
+
# @return [String] the message body
|
37
|
+
attribute :body, String
|
38
|
+
|
39
|
+
# @!attribute schedule_at
|
40
|
+
# @return [Time|NilClass] the schedule time to send message
|
41
|
+
attribute :schedule_at, Time
|
42
|
+
|
43
|
+
# @!attribute expired_at
|
44
|
+
# @return [Time|NilClass] the valid time for this message
|
45
|
+
attribute :expired_at, Time
|
46
|
+
|
47
|
+
# @!attribute webhook_url
|
48
|
+
# @return [String|NilClass] the response callback url
|
49
|
+
attribute :webhook_url, String
|
50
|
+
|
51
|
+
# @!attribute [r] duplicate
|
52
|
+
# @return [TrueClass|FalseClass] is the message duplicate
|
53
|
+
attribute :duplicate, Boolean, readonly: true
|
54
|
+
|
55
|
+
# @!attribute [r] status_code
|
56
|
+
# @return [Integer] the status code
|
57
|
+
attribute :status_code, Integer, readonly: true
|
58
|
+
|
59
|
+
# Send message
|
60
|
+
#
|
61
|
+
# @since 0.1.0
|
62
|
+
# @api private
|
63
|
+
def delivery
|
64
|
+
return self if sent?
|
65
|
+
|
66
|
+
self.class.execute(params) do |items|
|
67
|
+
attrs = items&.first&.slice(*self.class.attribute_names)
|
68
|
+
assign_attributes(attrs)
|
69
|
+
end
|
70
|
+
|
71
|
+
self
|
72
|
+
end
|
73
|
+
|
74
|
+
# Does message is sent
|
75
|
+
#
|
76
|
+
# @return [TrueClass|FalseClass] is the message sent
|
77
|
+
#
|
78
|
+
# @since 0.1.0
|
79
|
+
def sent?
|
80
|
+
!@id.nil?
|
81
|
+
end
|
82
|
+
|
83
|
+
# Does message is duplicate
|
84
|
+
#
|
85
|
+
# @return [TrueClass|FalseClass] is the message duplicate
|
86
|
+
#
|
87
|
+
# @since 0.1.0
|
88
|
+
def duplicate?
|
89
|
+
@duplicate == true
|
90
|
+
end
|
91
|
+
|
92
|
+
# Readable status code
|
93
|
+
#
|
94
|
+
# @return [String] the status code description
|
95
|
+
#
|
96
|
+
# @since 0.1.0
|
97
|
+
def status
|
98
|
+
Status::CODES[@status_code]
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
# The request params
|
104
|
+
#
|
105
|
+
# @since 0.1.0
|
106
|
+
# @api private
|
107
|
+
def params
|
108
|
+
{
|
109
|
+
clientid: @source_id,
|
110
|
+
smbody: @body,
|
111
|
+
dlvtime: @schedule_at&.strftime('%Y%m%d%H%M%S'),
|
112
|
+
vldtime: @expired_at&.strftime('%Y%m%d%H%M%S'),
|
113
|
+
dstaddr: @recipient.phone_number,
|
114
|
+
destname: @recipient.name,
|
115
|
+
response: @webhook_url
|
116
|
+
}.reject { |_, v| v.nil? }.to_h
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/lib/mitake/model.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'mitake/model/attributes'
|
4
|
+
require 'mitake/model/accessor'
|
5
|
+
|
6
|
+
module Mitake
|
7
|
+
# Provide attributes accessor
|
8
|
+
#
|
9
|
+
# @since 0.1.0
|
10
|
+
# @api private
|
11
|
+
module Model
|
12
|
+
# @since 0.1.0
|
13
|
+
# @api private
|
14
|
+
def self.included(base)
|
15
|
+
base.class_eval do
|
16
|
+
include Attributes
|
17
|
+
extend Accessor
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get attributes as hash
|
22
|
+
#
|
23
|
+
# @return [Hash] the object attributes
|
24
|
+
#
|
25
|
+
# @since 0.1.0
|
26
|
+
def attributes
|
27
|
+
self
|
28
|
+
.class
|
29
|
+
.attribute_names
|
30
|
+
.map { |attr| [attr, send(attr)] }
|
31
|
+
.reject { |_, value| value.nil? }
|
32
|
+
.map do |attr, value|
|
33
|
+
[attr, value.respond_to?(:attributes) ? value.attributes : value]
|
34
|
+
end
|
35
|
+
.to_h
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'time'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
module Mitake
|
7
|
+
module Model
|
8
|
+
# @since 0.1.0
|
9
|
+
# @api private
|
10
|
+
module Accessor
|
11
|
+
# Get attributes
|
12
|
+
#
|
13
|
+
# @return [Hash] the list of attributes and type
|
14
|
+
#
|
15
|
+
# @since 0.1.0
|
16
|
+
def attributes
|
17
|
+
@attributes ||= {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get attribute names
|
21
|
+
#
|
22
|
+
# @return [Array] the list of attribute names
|
23
|
+
#
|
24
|
+
# @since 0.1.0
|
25
|
+
def attribute_names
|
26
|
+
attributes.keys
|
27
|
+
end
|
28
|
+
|
29
|
+
# Define attribute
|
30
|
+
#
|
31
|
+
# @param name [String|Symbol] the attribute name
|
32
|
+
# @param type [Class] the attribute type
|
33
|
+
# @param readonly [TrueClass|FalseClass] is attribute readonly
|
34
|
+
#
|
35
|
+
# @since 0.1.0
|
36
|
+
def attribute(name, type = 'String', readonly: false)
|
37
|
+
@attributes ||= {}
|
38
|
+
@attributes[name.to_s] = type.to_s
|
39
|
+
|
40
|
+
define_method name do
|
41
|
+
instance_variable_get("@#{name}")
|
42
|
+
end
|
43
|
+
return if readonly
|
44
|
+
|
45
|
+
define_method "#{name}=" do |value|
|
46
|
+
instance_variable_set("@#{name}", self.class.cast(value, type.to_s))
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Casting type
|
51
|
+
#
|
52
|
+
# @param value [Object] the source value
|
53
|
+
# @param type [Class] the cast type
|
54
|
+
#
|
55
|
+
# @since 0.1.0
|
56
|
+
# @api private
|
57
|
+
def cast(value, type = 'String')
|
58
|
+
case type.to_s
|
59
|
+
when 'String', 'Integer', 'Float'
|
60
|
+
Kernel.method(type).call(value)
|
61
|
+
when 'Time', 'DateTime', 'Date'
|
62
|
+
Kernel.const_get(type).parse("#{value}+8")
|
63
|
+
else
|
64
|
+
klass = Kernel.const_get(type)
|
65
|
+
return klass.parse(value) if klass.respond_to?(:parse)
|
66
|
+
|
67
|
+
value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|