line-bot-api 0.1.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.
@@ -0,0 +1,11 @@
1
+ require 'line/bot/client'
2
+ require 'line/bot/api/errors'
3
+ require 'line/bot/event_type'
4
+ require 'line/bot/message'
5
+ require 'line/bot/operation'
6
+ require 'line/bot/receive/message'
7
+ require 'line/bot/receive/operation'
8
+ require 'line/bot/receive/request'
9
+ require 'line/bot/response/user/profile'
10
+ require 'line/bot/request'
11
+ require 'line/bot/api/version'
@@ -0,0 +1,7 @@
1
+ module Line
2
+ module Bot
3
+ module API
4
+ class InvalidCredentialsError < StandardError; end
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Line
2
+ module Bot
3
+ module API
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,102 @@
1
+ require 'line/bot/message'
2
+
3
+ module Line
4
+ module Bot
5
+ module Builder
6
+ class MultipleMessage
7
+
8
+ def initialize client
9
+ @messages ||= []
10
+ @client = client
11
+ end
12
+
13
+ def add_text(attrs = {})
14
+ tap {
15
+ message = Message::Text.new(
16
+ text: attrs[:text],
17
+ )
18
+ push_message(message)
19
+ }
20
+ end
21
+
22
+ def add_image(attrs = {})
23
+ tap {
24
+ message = Message::Image.new(
25
+ image_url: attrs[:image_url],
26
+ preview_url: attrs[:preview_url],
27
+ )
28
+ push_message(message)
29
+ }
30
+ end
31
+
32
+ def add_video(attrs = {})
33
+ tap {
34
+ message = Message::Video.new(
35
+ video_url: attrs[:video_url],
36
+ preview_url: attrs[:preview_url],
37
+ )
38
+ push_message(message)
39
+ }
40
+ end
41
+
42
+ def add_audio(attrs = {})
43
+ tap {
44
+ message = Message::Audio.new(
45
+ audio_url: attrs[:audio_url],
46
+ duration: attrs[:duration],
47
+ )
48
+ push_message(message)
49
+ }
50
+ end
51
+
52
+ def add_location(attrs = {})
53
+ tap {
54
+ message = Message::Location.new(
55
+ title: attrs[:title],
56
+ latitude: attrs[:latitude],
57
+ longitude: attrs[:longitude],
58
+ )
59
+ push_message(message)
60
+ }
61
+ end
62
+
63
+ def add_sticker(attrs = {})
64
+ tap {
65
+ message = Message::Sticker.new(
66
+ stkpkgid: attrs[:stkpkgid],
67
+ stkid: attrs[:stkid],
68
+ stkver: attrs[:stkver],
69
+ )
70
+ push_message(message)
71
+ }
72
+ end
73
+
74
+ def push_message(message)
75
+ raise ArgumentError, "Invalid arguments" unless message.valid?
76
+ @messages << message.content
77
+ end
78
+
79
+ def send(attrs = {})
80
+ to_mid = attrs.instance_of?(Hash) ? attrs[:to_mid] : attrs
81
+ @client.send_message(to_mid, self)
82
+ end
83
+
84
+ def event_type
85
+ 140177271400161403
86
+ end
87
+
88
+ def content
89
+ {
90
+ messageNotified: 0,
91
+ messages: @messages
92
+ }
93
+ end
94
+
95
+ def valid?
96
+ @messages.size > 0
97
+ end
98
+
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,138 @@
1
+ require 'line/bot/message'
2
+ require 'json'
3
+
4
+ module Line
5
+ module Bot
6
+ module Builder
7
+ class RichMessage
8
+
9
+ def initialize client
10
+ @actions ||= {}
11
+ @listeners ||= []
12
+ @client = client
13
+ end
14
+
15
+ def set_action(attrs = {})
16
+ tap {
17
+ attrs.each { |key, value|
18
+ raise ArgumentError, 'Invalid arguments, :text, :link_url keys.' unless validate_action_attributes(value)
19
+
20
+ @actions[key.to_s] ||= {}
21
+ @actions[key.to_s] = {
22
+ type: 'web',
23
+ text: value[:text].to_s,
24
+ params: {
25
+ linkUri: value[:link_url].to_s
26
+ },
27
+ }
28
+ }
29
+ }
30
+ end
31
+
32
+ def validate_action_attributes(attrs = {})
33
+ attrs[:text] && attrs[:link_url]
34
+ end
35
+
36
+ def add_listener(attrs = {})
37
+ tap {
38
+ raise ArgumentError, 'Invalid arguments, :x [Fixnum], :y [Fixnum], :width [Fixnum], :height [Fixnum] keys.' unless validate_listener_attributes(attrs)
39
+
40
+ listener = {
41
+ type: 'touch', # Fixed "touch".
42
+ params: [attrs[:x], attrs[:y], attrs[:width], attrs[:height]],
43
+ action: attrs[:action],
44
+ }
45
+ @listeners << listener
46
+ }
47
+ end
48
+
49
+ def validate_listener_attributes(attrs = {})
50
+ attrs[:action].instance_of?(String) &&
51
+ attrs[:x].instance_of?(Fixnum) &&
52
+ attrs[:y].instance_of?(Fixnum) &&
53
+ attrs[:width].instance_of?(Fixnum) &&
54
+ attrs[:height].instance_of?(Fixnum)
55
+ end
56
+
57
+ # send rich message to line server and to users
58
+ #
59
+ # @param attrs [Hash]
60
+ # @param attrs [:to_mid] [String or Array] line user's mids
61
+ # @param attrs [:image_url] [String] image file's url
62
+ # @param attrs [:alt_text] [String] alt text for image file's url
63
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :image_url, :preview_url keys.
64
+ #
65
+ # @return [Net::HTTPResponse] response for a request to line server
66
+ def send(attrs = {})
67
+ @image_url = attrs[:image_url]
68
+ @alt_text = attrs[:alt_text]
69
+
70
+ @client.send_message(attrs[:to_mid], self)
71
+ end
72
+
73
+ def height
74
+ height = 0
75
+ @listeners.each { |listener|
76
+ h = listener[:params][1] + listener[:params][3] # params.y + params.height
77
+ height = h if height < h
78
+ }
79
+
80
+ height > 2080 ? 2080 : height
81
+ end
82
+
83
+ def event_type
84
+ 138311608800106203
85
+ end
86
+
87
+ def content
88
+ {
89
+ contentType: Line::Bot::Message::ContentType::RICH_MESSAGE,
90
+ toType: 1,
91
+ contentMetadata: {
92
+ DOWNLOAD_URL: @image_url,
93
+ SPEC_REV: "1", # Fixed "1".
94
+ ALT_TEXT: @alt_text,
95
+ MARKUP_JSON: markup_json,
96
+ },
97
+ }
98
+ end
99
+
100
+ def valid?
101
+ @image_url && @alt_text
102
+ end
103
+
104
+ def markup_json
105
+ {
106
+ canvas: {
107
+ height: height,
108
+ width: 1040, # Integer fixed value: 1040
109
+ initialScene: 'scene1',
110
+ },
111
+ images: {
112
+ image1: {
113
+ x: 0,
114
+ y: 0,
115
+ width: 1040, # Integer fixed value: 1040
116
+ height: height
117
+ },
118
+ },
119
+ actions: @actions,
120
+ scenes: {
121
+ scene1: {
122
+ draws: {
123
+ image: 'image1', # Use the image ID "image1".
124
+ x: 0,
125
+ y: 0,
126
+ width: 1040, # Integer fixed value: 1040
127
+ height: height
128
+ },
129
+ listeners: @listeners
130
+ }
131
+ }
132
+ }.to_json
133
+ end
134
+
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,249 @@
1
+ require 'line/bot/message'
2
+ require 'line/bot/request'
3
+ require 'line/bot/builder/rich_message'
4
+ require 'line/bot/builder/multiple_message'
5
+ require 'line/bot/api/errors'
6
+ require 'base64'
7
+ require 'net/http'
8
+
9
+ module Line
10
+ module Bot
11
+ class Client
12
+ attr_accessor :channel_id, :channel_secret, :channel_mid
13
+
14
+ # Initializes a new Bot Client
15
+ #
16
+ # @param options [Hash]
17
+ # @return [LINE::Bot::Client]
18
+ def initialize
19
+ yield(self) if block_given?
20
+ end
21
+
22
+ # @return [Hash]
23
+ def credentials
24
+ {
25
+ 'X-Line-ChannelID' => channel_id,
26
+ 'X-Line-ChannelSecret' => channel_secret,
27
+ 'X-Line-Trusted-User-With-ACL' => channel_mid,
28
+ }
29
+ end
30
+
31
+ def credentials?
32
+ credentials.values.all?
33
+ end
34
+
35
+ # Sends text to users
36
+ #
37
+ # @param attrs [Hash]
38
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
39
+ # @param attrs [:text] [String]
40
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :text keys.
41
+ #
42
+ # @return [Net::HTTPResponse]
43
+ def send_text(attrs = {})
44
+ message = Message::Text.new(
45
+ text: attrs[:text],
46
+ )
47
+ send_message(attrs[:to_mid], message)
48
+ end
49
+
50
+ # Sends image to users
51
+ #
52
+ # @param attrs [Hash]
53
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
54
+ # @param attrs [:image_url] [String] Image file's url
55
+ # @param attrs [:preview_url] [String] Preview image file's url
56
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :image_url, :preview_url keys.
57
+ #
58
+ # @return [Net::HTTPResponse]
59
+ def send_image(attrs = {})
60
+ message = Message::Image.new(
61
+ image_url: attrs[:image_url],
62
+ preview_url: attrs[:preview_url],
63
+ )
64
+ send_message(attrs[:to_mid], message)
65
+ end
66
+
67
+ # Sends video to users
68
+ #
69
+ # @param attrs [Hash]
70
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
71
+ # @param attrs [:video_url] [String] Video file's url
72
+ # @param attrs [:preview_url] [String] Preview image file's url
73
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :video_url, :preview_url keys.
74
+ #
75
+ # @return [Net::HTTPResponse]
76
+ def send_video(attrs = {})
77
+ message = Message::Video.new(
78
+ video_url: attrs[:video_url],
79
+ preview_url: attrs[:preview_url],
80
+ )
81
+ send_message(attrs[:to_mid], message)
82
+ end
83
+
84
+ # Sends audio to users
85
+ #
86
+ # @param attrs [Hash]
87
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
88
+ # @param attrs [:audio_url] [String] Audio file's url
89
+ # @param attrs [:duration] [String or Integer] Voice message's length, milliseconds
90
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :audio_url, :duration keys.
91
+ #
92
+ # @return [Net::HTTPResponse]
93
+ def send_audio(attrs = {})
94
+ message = Message::Audio.new(
95
+ audio_url: attrs[:audio_url],
96
+ duration: attrs[:duration],
97
+ )
98
+ send_message(attrs[:to_mid], message)
99
+ end
100
+
101
+ # Sends location to users
102
+ #
103
+ # @param attrs [Hash]
104
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
105
+ # @param attrs [:title] [String] Location's title
106
+ # @param attrs [:address] [String] Location's address
107
+ # @param attrs [:latitude] [Float] Location's latitude
108
+ # @param attrs [:longitude] [Float] Location's longitude
109
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :title, :latitude, :longitude keys.
110
+ #
111
+ # @return [Net::HTTPResponse]
112
+ def send_location(attrs = {})
113
+ message = Message::Location.new(
114
+ title: attrs[:title],
115
+ address: attrs[:address],
116
+ latitude: attrs[:latitude],
117
+ longitude: attrs[:longitude],
118
+ )
119
+ send_message(attrs[:to_mid], message)
120
+ end
121
+
122
+ # Sends sticker to users
123
+ #
124
+ # @param attrs [Hash]
125
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
126
+ # @param attrs [:stkpkgid] [String or Integer] Sticker's package identifier
127
+ # @param attrs [:stkid] [String or Integer] Sticker's identifier
128
+ # @param attrs [:stkver] [String or Integer] Sticker's version number
129
+ # @raise [ArgumentError] Error raised when supplied argument are missing :to_mid, :stkpkgid, :stkid, :stkver keys.
130
+ #
131
+ # @return [Net::HTTPResponse]
132
+ def send_sticker(attrs = {})
133
+ message = Message::Sticker.new(
134
+ stkpkgid: attrs[:stkpkgid],
135
+ stkid: attrs[:stkid],
136
+ stkver: attrs[:stkver],
137
+ )
138
+ send_message(attrs[:to_mid], message)
139
+ end
140
+
141
+ # Sends message to line server and to users
142
+ #
143
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
144
+ # @param message [Line::Bot::Message]
145
+ # @raise [ArgumentError] Error raised when supplied argument are missing message.
146
+ #
147
+ # @return [Net::HTTPResponse]
148
+ def send_message(to_mid, message)
149
+ raise Line::Bot::API::InvalidCredentialsError, 'Invalidates credentials' unless credentials?
150
+
151
+ request = Request.new do |config|
152
+ config.endpoint_path = '/v1/events'
153
+ config.credentials = credentials
154
+ config.to_mid = to_mid
155
+ config.message = message
156
+ end
157
+
158
+ request.post
159
+ end
160
+
161
+ # Gets message content
162
+ #
163
+ # @param identifer [String] Message's identifier
164
+ #
165
+ # @raise [ArgumentError] Error raised when supplied argument are missing message.
166
+ #
167
+ # @return [Net::HTTPResponse]
168
+ def get_message_content(identifer)
169
+ endpoint_path = "/v1/bot/message/#{identifer}/content"
170
+ get(endpoint_path)
171
+ end
172
+
173
+ # Gets preview of message content
174
+ #
175
+ # @param identifer [String] Message's identifier
176
+ #
177
+ # @raise [ArgumentError] Error raised when supplied argument are missing message.
178
+ #
179
+ # @return [Net::HTTPResponse]
180
+ def get_message_content_preview(identifer)
181
+ endpoint_path = "/v1/bot/message/#{identifer}/content/preview"
182
+ get(endpoint_path)
183
+ end
184
+
185
+ # Gets user profile
186
+ #
187
+ # @param attrs [:to_mid] [String or Array] User's indentifiers
188
+ #
189
+ # @raise [ArgumentError] Error raised when supplied argument are missing message.
190
+ # @raise [HTTPError]
191
+ #
192
+ # @return [Line::Bot::Response::User::Profile]
193
+ def get_user_profile(mids)
194
+ mids = mids.instance_of?(String) ? [mids] : mids
195
+ endpoint_path = "/v1/profiles?mids=#{mids.join(',')}"
196
+
197
+ response = get(endpoint_path)
198
+
199
+ Line::Bot::Response::User::Profile.new(response) if !response.value
200
+ end
201
+
202
+ # Fetches data
203
+ #
204
+ # @param endpoint_path [String]
205
+ #
206
+ # @return [Net::HTTPResponse]
207
+ def get(endpoint_path)
208
+ raise Line::Bot::API::InvalidCredentialsError, 'Invalidates credentials' unless credentials?
209
+
210
+ request = Request.new do |config|
211
+ config.endpoint_path = endpoint_path
212
+ config.credentials = credentials
213
+ end
214
+
215
+ request.get
216
+ end
217
+
218
+ # Creates rich message to line server and to users
219
+ #
220
+ # @return [Line::Bot::Builder::RichMessage]
221
+ def rich_message
222
+ Line::Bot::Builder::RichMessage.new(self)
223
+ end
224
+
225
+ # Creates multiple message to line server and to users
226
+ #
227
+ # @return [Line::Bot::Builder::MultipleMessage]
228
+ def multiple_message
229
+ Line::Bot::Builder::MultipleMessage.new(self)
230
+ end
231
+
232
+ # Validates signature
233
+ #
234
+ # @param content [String] Request's body
235
+ # @param channel_signature [String] Request'header 'X-LINE-ChannelSignature' # HTTP_X_LINE_CHANNELSIGNATURE
236
+ #
237
+ # @return [Boolean]
238
+ def validate_signature(content = "", channel_signature)
239
+ return false unless !channel_signature.nil? && credentials?
240
+
241
+ hash = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, channel_secret, content)
242
+ signature = Base64.strict_encode64(hash)
243
+
244
+ channel_signature == signature
245
+ end
246
+ end
247
+
248
+ end
249
+ end