mitake 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|