chatty_crow 1.2.1 → 1.3.1

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
  SHA1:
3
- metadata.gz: f3d0453caad9e953327867ecef479adf92bf72a4
4
- data.tar.gz: 6a3de41a1532e54d80ea977e03c66e44c3b7ec9f
3
+ metadata.gz: 934f0269b67bacd13a7806530f99771ecd2fb8ba
4
+ data.tar.gz: 7d196a82c2915d95b1c449cba03ae909c672580d
5
5
  SHA512:
6
- metadata.gz: 91cb3bcfac3dee6a1ccc42f046585b1be7b0be84db6845a73cf20d5e54bbbce95a91636072b3869ec305241030f4b7d72ebc568d95fcfcd3690a34f1b9742506
7
- data.tar.gz: cd3406e5a6c162de5d88e3acd5e28b500eb62af93452af3577f14de5468195082d2a31a9b2eda1d66ae9b87e8c42c283376fc3847cdb8f640d1daa443ce1efb0
6
+ metadata.gz: b0437f430fa57e8a0ec001be87591bb5ba25df06237fdb85081afe7868a7da895a24f928b6db3806c07df2d7e4e84663c9e23cbf07ac5e84fb5c3b75fa2a1b0d
7
+ data.tar.gz: 6ee8ed7c1d545790152af84ad81de1fecb04bb46ffaec019e1bcfd254a9ba7d86d8d3855f260f65980652979769e677cc7e7a7b0c2d1463fd22f18890929c638
@@ -102,7 +102,7 @@ h3. IOS Push notification
102
102
 
103
103
  <pre>
104
104
  # Send request
105
- response = ChattyCrow.send_ios(payload: { 'hello' }, channel: 'other_than_default', token: 'other', contacts: [ 'new_ios_id1', 'new_ios_id2' ])
105
+ response = ChattyCrow.send_ios(payload: { 'hello' }, channel: 'other_than_default', token: 'other', contacts: [ 'new_ios_id1', 'new_ios_id2' ], time: { start: DateTime.now.to_i, end: DateTime.now.advance(days: 7) }, location: { latitude: 14.302022, longitude: 43.20923, range: 1000 })
106
106
 
107
107
  # Or simple message
108
108
  response = ChattyCrow.send_ios('Dear users')
@@ -123,6 +123,8 @@ response = ChattyCrow.send_android(payload: { data: { key: 'key1', key2: 'key2'}
123
123
  # response.success = 5
124
124
  # response.failed = 1
125
125
  # response.failed_contacts = [ 'new_ios_id1' ]
126
+ # response.message_id = your created message ID
127
+ # response.message = Response::Message instance
126
128
  </pre>
127
129
 
128
130
  h3. Skype notification
@@ -145,6 +147,26 @@ response = ChattyCrow.send_jabber('Dear users', channel: 'other_than_default', c
145
147
  # response # ChattyCrow::Response::Notification
146
148
  </pre>
147
149
 
150
+ h3. HipChat notifications
151
+
152
+ <pre>
153
+ # Send request
154
+ # Color (red, yellow, purple, random - yellow is default)
155
+ response = ChattyCrow.send_hipchat('Dear users', color: 'red', channel: 'other_than_default', contacts: [ 'new_ios_id1', 'new_ios_id2' ])
156
+
157
+ # Response
158
+ # response # ChattyCrow::Response::Notification
159
+ </pre>
160
+
161
+ h3. Slack notifications
162
+
163
+ <pre>
164
+ # Send request
165
+ response = ChattyCrow.send_hipchat('Dear users', channel: 'other_than_default', contacts: [ 'new_ios_id1', 'new_ios_id2' ])
166
+
167
+ # Response
168
+ # response # ChattyCrow::Response::Notification
169
+ </pre>
148
170
 
149
171
  h3. SMS notification (only Czech Republic yet)
150
172
 
@@ -156,6 +178,16 @@ response = ChattyCrow.send_sms 'Dear Users', contacts: [ '+420111222333', '+4202
156
178
  # response # ChattyCrow::Response::Notification
157
179
  </pre>
158
180
 
181
+ h2. Message detail and state
182
+
183
+ We're providing uniq message id to check what's going on with your message. You obtain message instance from successfull response.
184
+
185
+ <pre>
186
+ message = response.message
187
+ message.refresh_data!
188
+ message.status # OK etc..
189
+ </pre>
190
+
159
191
  h2. Working with contacts via API
160
192
 
161
193
  It's actually very usable, you can automatically add or remove contacts in your application after user was registered.
@@ -181,3 +213,31 @@ h3. Remove contact
181
213
  # response.failed_count = 1
182
214
  # response.failed = [ 'new2failed' ]
183
215
  </pre>
216
+
217
+ h2. Batch notifications
218
+
219
+ Allows sends multiple notifications with serveral restrictions, notifications are immediatelly aborted when:
220
+ * Token and channels not matched
221
+ * One of channel is suspended
222
+ * Times or locations are invalid in any case
223
+
224
+ <pre>
225
+ batch = ChattyCrow.create_batch("different token then default")
226
+
227
+ # Its almost the same as send_android, but channel is required!
228
+ batch.add_jabber 'Dear users', channel: 'channel', contacts: [ 'aa' ]
229
+ batch.execute # add '!' to raise error, when something is wrong
230
+ </pre>
231
+
232
+ h2. Changelog
233
+
234
+ h3. 1.3.0
235
+
236
+ * Add batch notifications (this is required for Redmine Plugin or Capistrano Plugin)
237
+
238
+ h3. 1.2.2
239
+
240
+ * Add messages state API
241
+ * Remove GET contact list methods
242
+ * Add support of change location API
243
+ * Add HipChat, Slack and Telegram
data/Rakefile CHANGED
@@ -12,3 +12,12 @@ end
12
12
 
13
13
  # Default task - test
14
14
  task default: %w(test coveralls:push)
15
+
16
+ # Task console
17
+ task :console do
18
+ require 'irb'
19
+ require 'irb/completion'
20
+ require './lib/chattycrow'
21
+ ARGV.clear
22
+ IRB.start
23
+ end
@@ -14,10 +14,10 @@ Gem::Specification.new do |s|
14
14
  %w(chatty_crow.gemspec CHANGELOG Gemfile Guardfile INSTALL LICENSE Rakefile README.textile)
15
15
  s.test_files = Dir.glob('{test}/**/*')
16
16
 
17
- s.required_ruby_version = '>= 2'
17
+ s.required_ruby_version = '>= 1.9'
18
18
 
19
19
  s.add_runtime_dependency('multi_json', '~> 1.0')
20
- s.add_runtime_dependency('rest_client', '~> 1.7')
20
+ s.add_runtime_dependency('rest-client', '~> 1.7')
21
21
  s.add_runtime_dependency('mime-types', '>= 1')
22
22
 
23
23
  s.add_development_dependency('fakeweb', '~> 1.3')
@@ -2,6 +2,7 @@ require 'rest-client'
2
2
  require 'chatty_crow/config'
3
3
  require 'chatty_crow/error'
4
4
  require 'chatty_crow/response'
5
+ require 'chatty_crow/message'
5
6
  require 'chatty_crow/request'
6
7
  require 'chatty_crow/request/android'
7
8
  require 'chatty_crow/request/ios'
@@ -9,7 +10,14 @@ require 'chatty_crow/request/jabber'
9
10
  require 'chatty_crow/request/mail'
10
11
  require 'chatty_crow/request/skype'
11
12
  require 'chatty_crow/request/sms'
13
+ require 'chatty_crow/request/hipchat'
14
+ require 'chatty_crow/request/slack'
15
+ require 'chatty_crow/response/notification'
16
+ require 'chatty_crow/response/batch'
17
+ require 'chatty_crow/response/contacts_add'
18
+ require 'chatty_crow/response/contacts_remove'
12
19
  require 'chatty_crow/notification_request'
20
+ require 'chatty_crow/batch_notification_request'
13
21
  require 'chatty_crow/contacts_request'
14
22
 
15
23
  # Load Rails Components
@@ -75,6 +83,14 @@ module ChattyCrow
75
83
  NotificationRequest.send(Request::Skype, *args)
76
84
  end
77
85
 
86
+ def self.send_hipchat(*args)
87
+ NotificationRequest.send(Request::HipChat, *args)
88
+ end
89
+
90
+ def self.send_slack(*args)
91
+ NotificationRequest.send(Request::Slack, *args)
92
+ end
93
+
78
94
  def self.send_jabber(*args)
79
95
  NotificationRequest.send(Request::Jabber, *args)
80
96
  end
@@ -95,6 +111,11 @@ module ChattyCrow
95
111
  ContactsRequest.remove(*args)
96
112
  end
97
113
 
114
+ # Create batch request
115
+ def self.create_batch(token = nil)
116
+ BatchNotificationRequest.new(token)
117
+ end
118
+
98
119
  # Helper method for wrapping non-array objects
99
120
  # @param object [Object] Something
100
121
  # @return [Array] Array
@@ -116,4 +137,19 @@ module ChattyCrow
116
137
  {}
117
138
  end
118
139
  end
140
+
141
+ # Symbolize keys
142
+ def self.symbolize_keys!(hash)
143
+ hash.keys.each do |key|
144
+ # Get value
145
+ value = hash.delete(key)
146
+
147
+ # Save as sym
148
+ hash[(key.to_sym rescue key)] = value
149
+
150
+ # Recursive?
151
+ symbolize_keys!(hash[key.to_sym]) if value.is_a?(Hash)
152
+ end
153
+ true
154
+ end
119
155
  end
@@ -0,0 +1,126 @@
1
+ require 'rest_client'
2
+
3
+ module ChattyCrow
4
+ # Batch notification request
5
+ # use for send different kind
6
+ # of notifications
7
+ class BatchNotificationRequest
8
+ # Prepare data
9
+ attr_accessor :requests, :token
10
+
11
+ def initialize(token = nil)
12
+ @token = token
13
+ end
14
+
15
+ def requests
16
+ @requests ||= []
17
+ end
18
+
19
+ # Add requests by type
20
+ def add_mail(*args)
21
+ add_other Request::Mail.new(*args)
22
+ end
23
+
24
+ def add_ios(*args)
25
+ add_other Request::Ios.new(*args)
26
+ end
27
+
28
+ def add_android(*args)
29
+ add_other Request::Android.new(*args)
30
+ end
31
+
32
+ def add_skype(*args)
33
+ add_other Request::Skype.new(*args)
34
+ end
35
+
36
+ def add_hipchat(*args)
37
+ add_other Request::HipChat.new(*args)
38
+ end
39
+
40
+ def add_slack(*args)
41
+ add_other Request::Slack.new(*args)
42
+ end
43
+
44
+ def add_jabber(*args)
45
+ add_other Request::Jabber.new(*args)
46
+ end
47
+
48
+ # Add other with channel name
49
+ def add_other(instance)
50
+ # Throw error when instance has empty channel
51
+ fail ::ArgumentError, 'Channel is required' unless instance.channel
52
+
53
+ # Add
54
+ requests << instance
55
+ end
56
+
57
+ # Send
58
+ def execute
59
+ proceed(false)
60
+ end
61
+
62
+ # Send with errors!
63
+ def execute!
64
+ proceed(true)
65
+ end
66
+
67
+ # :nodoc:
68
+ def self.batch_notification_url
69
+ ChattyCrow.configuration.batch_url
70
+ end
71
+
72
+ # Batch headers
73
+ def batch_headers
74
+ ChattyCrow.batch_headers(@token)
75
+ end
76
+
77
+ private
78
+
79
+ # Method actually sends created request to server
80
+ # [Can be refactored, with request class]
81
+ # @param raise_errors [Boolean] Raise errors if error?
82
+ # @return [Object] Raise an exception or return Response::Notification
83
+ def proceed(raise_errors = true)
84
+ # Empty requests?
85
+ if requests.empty?
86
+ if raise_errors
87
+ fail ::ArgumentError, 'At least one message is required!'
88
+ else
89
+ return false
90
+ end
91
+ end
92
+
93
+ # Headers
94
+ options = { headers: batch_headers, url: self.class.batch_notification_url, method: :post }
95
+
96
+ # Create array!
97
+ options[:payload] = { channels: requests.map { |i| i.to_json(true)[:payload] } }.to_json
98
+
99
+ # Send
100
+ RestClient::Request.execute(options) do |response, request, result, &block|
101
+ begin
102
+ case response.code
103
+ when 200, 201
104
+ Response::Batch.new response, options
105
+ when 301, 302, 307
106
+ response.follow_redirection(request, result, &block)
107
+ when 400
108
+ fail Error::InvalidAttributes, response
109
+ when 401
110
+ fail Error::UnauthorizedRequest, response
111
+ when 404
112
+ fail Error::ChannelNotFound, response
113
+ else
114
+ fail Error::InvalidReturn, response
115
+ end
116
+ rescue => e
117
+ if raise_errors
118
+ raise e
119
+ else
120
+ false
121
+ end
122
+ end
123
+ end # RestClient
124
+ end # Execute
125
+ end
126
+ end
@@ -24,10 +24,14 @@ module ChattyCrow
24
24
  end
25
25
 
26
26
  def self.default_headers(channel, token)
27
+ batch_headers(token).merge('Channel' => (channel || configuration.default_channel))
28
+ end
29
+
30
+ def self.batch_headers(token)
27
31
  {
28
32
  'Token' => token || configuration.token,
29
- 'Channel' => channel || configuration.default_channel,
30
- 'Accept' => 'application/json'
33
+ 'Accept' => 'application/json',
34
+ 'Content-Type' => 'application/json'
31
35
  }
32
36
  end
33
37
 
@@ -45,10 +49,10 @@ module ChattyCrow
45
49
  attr_accessor :http_read_timeout
46
50
 
47
51
  # Call urls
48
- attr_reader :notification_url, :contacts_url
52
+ attr_reader :notification_url, :contacts_url, :messages_url, :batch_url
49
53
 
50
54
  def initialize
51
- self.host = 'https://chatty-crow.com/api/v1/'
55
+ self.host = 'https://chattycrow.com/api/v1/'
52
56
  @token = nil
53
57
  @default_channel = nil
54
58
  @http_open_timeout = 2
@@ -59,6 +63,8 @@ module ChattyCrow
59
63
  @host = s
60
64
  @notification_url = s + (s[-1] == '/' ? '' : '/') + 'notification'
61
65
  @contacts_url = s + (s[-1] == '/' ? '' : '/') + 'contacts'
66
+ @messages_url = s + (s[-1] == '/' ? '' : '/') + 'message'
67
+ @batch_url = s + (s[-1] == '/' ? '' : '/') + 'batch'
62
68
  end
63
69
  end
64
70
  end
@@ -28,7 +28,7 @@ module ChattyCrow
28
28
  # Method prepare data from add/remove contact
29
29
  # @params klass [Class] Initializable class for response
30
30
  # @params method [String] HTTP method
31
- # @params *ąrgs [Arguments]
31
+ # @params args [Arguments]
32
32
  def self.send_contact_request(klass, method, *args)
33
33
  # Parse options
34
34
  options = ChattyCrow.extract_options!(args)
@@ -55,6 +55,9 @@ module ChattyCrow
55
55
  options[:url] = contacts_url
56
56
  options[:headers] = ChattyCrow.default_headers(options.delete(:channel), options.delete(:token))
57
57
 
58
+ # Convert payload to JSON
59
+ options[:payload] = options[:payload].to_json
60
+
58
61
  # Send request
59
62
  RestClient::Request.execute(options) do |response, request, result, &block|
60
63
  case response.code
@@ -0,0 +1,82 @@
1
+ require 'rest_client'
2
+
3
+ module ChattyCrow
4
+ # Message status
5
+ # It's bind to /api/message_id call
6
+ class Message
7
+ # Attribute
8
+ attr_accessor :channel, :token, :message_id
9
+
10
+ # Actual states
11
+ attr_accessor :success, :waiting, :error, :last_update, :status
12
+
13
+ # Only message_id is required, in case other options
14
+ # are not different from global configuration
15
+ def initialize(opts = {})
16
+ # Set variables
17
+ @channel = opts.delete(:channel)
18
+ @token = opts.delete(:token)
19
+ @message_id = opts.delete(:message_id)
20
+
21
+ # Refresh
22
+ refresh
23
+ end
24
+
25
+ # Refresh
26
+ def refresh!
27
+ refresh_data
28
+ end
29
+
30
+ def refresh
31
+ refresh_data(true)
32
+ end
33
+
34
+ private
35
+
36
+ def data=(response)
37
+ # Parse body
38
+ body = JSON.parse(response.body)
39
+ @status = body.delete('status')
40
+ @success = body['notifications'].delete('success')
41
+ @waiting = body['notifications'].delete('waiting')
42
+ @error = body['notifications'].delete('error')
43
+
44
+ # Set last update
45
+ @last_update = Time.now
46
+ end
47
+
48
+ def call_options
49
+ {
50
+ url: "#{ChattyCrow.configuration.messages_url}/#{@message_id}",
51
+ headers: ChattyCrow.default_headers(@channel, @token),
52
+ method: :get
53
+ }
54
+ end
55
+
56
+ def refresh_data(raise_errors = false)
57
+ # Send request
58
+ RestClient::Request.execute(call_options) do |response, request, result, &block|
59
+ begin
60
+ case response.code
61
+ when 200
62
+ self.data = response
63
+ when 301, 302, 307
64
+ response.follow_redirection(request, result, &block)
65
+ when 401
66
+ fail Error::UnauthorizedRequest, response
67
+ when 404
68
+ fail Error::ChannelNotFound, response
69
+ else
70
+ fail Error::InvalidReturn, response
71
+ end
72
+ rescue => e
73
+ if raise_errors
74
+ raise e
75
+ else
76
+ false
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -23,13 +23,18 @@ module ChattyCrow
23
23
  # @param raise_errors [Boolean] Raise errors if error?
24
24
  # @return [Object] Raise an exception or return Response::Notification
25
25
  def self.execute(instance, raise_errors = true)
26
+ # Get options
26
27
  options = instance.to_json.merge(url: notification_url, method: :post)
27
28
 
29
+ # Set options to JSON string
30
+ options[:payload] = options[:payload].to_json
31
+
32
+ # Send
28
33
  RestClient::Request.execute(options) do |response, request, result, &block|
29
34
  begin
30
35
  case response.code
31
36
  when 200, 201
32
- Response::Notification.new response
37
+ Response::Notification.new response, options
33
38
  when 301, 302, 307
34
39
  response.follow_redirection(request, result, &block)
35
40
  when 400
@@ -3,7 +3,10 @@ module ChattyCrow
3
3
  # Parent of all requests to ChattyCrow API
4
4
  class BaseRequest
5
5
  # Methods
6
- attr_accessor :contacts, :payload, :channel, :token
6
+ attr_accessor :contacts, :payload, :channel, :token, :time, :location
7
+
8
+ # Batch request method
9
+ attr_accessor :channel
7
10
 
8
11
  # Intialize options!
9
12
  attr_accessor :arguments, :options, :arguments_flatten
@@ -19,12 +22,32 @@ module ChattyCrow
19
22
  @options = ChattyCrow.extract_options!(args)
20
23
  @arguments = args
21
24
 
25
+ # Symbolize keys in options for validations
26
+ ChattyCrow.symbolize_keys!(@options)
27
+
22
28
  # Create flatten arguments for (skype/android/sms.. requests)
23
29
  @arguments_flatten = args.join(', ') if args.any?
24
30
 
25
31
  # Recipients
26
32
  @contacts = ChattyCrow.wrap(@options.delete(:contacts)).compact
27
33
 
34
+ # Time and location - validate!
35
+ if @time = @options.delete(:time)
36
+ { start: Fixnum, end: Fixnum }.each do |key, klass|
37
+ unless @time[key].is_a?(klass)
38
+ fail ::ArgumentError, "#{key} must be instance of #{klass}"
39
+ end
40
+ end
41
+ end
42
+
43
+ if @location = @options.delete(:location)
44
+ { latitude: Float, longitude: Float, range: Fixnum }.each do |key, klass|
45
+ unless @location[key].is_a?(klass)
46
+ fail ::ArgumentError, "#{key} must be instance of #{klass}"
47
+ end
48
+ end
49
+ end
50
+
28
51
  # Channel
29
52
  @channel = @options.delete(:channel)
30
53
 
@@ -39,14 +62,20 @@ module ChattyCrow
39
62
 
40
63
  # Get request for send
41
64
  # @return [Hash] Request
42
- def to_json
43
- {
65
+ def to_json(channel = false)
66
+ ret = {
44
67
  payload: {
45
68
  payload: payload,
46
- contacts: @contacts
69
+ contacts: @contacts,
70
+ time: @time,
71
+ location: @location
47
72
  },
48
73
  headers: headers
49
74
  }
75
+
76
+ ret[:payload][:channel] = @channel if channel
77
+
78
+ ret
50
79
  end
51
80
  end
52
81
  end
@@ -0,0 +1,17 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # HipChat request
4
+ class HipChat < BaseRequest
5
+ def initialize(*args)
6
+ super(*args)
7
+
8
+ # If arguments exists set as body into options!
9
+ # Its for just easy ChattyCrow.send_hipchat 'Hello'
10
+ @options[:body] = @arguments_flatten if @arguments_flatten
11
+
12
+ # Set payload
13
+ @payload = @options
14
+ end
15
+ end
16
+ end
17
+ end
@@ -189,7 +189,7 @@ module ChattyCrow
189
189
  subject: @subject,
190
190
  html_body: Base64.encode64(@html_body || ''),
191
191
  text_body: Base64.encode64(@text_body || ''),
192
- attachments: attachments.map(&:to_json)
192
+ files: attachments.map(&:to_json)
193
193
  }
194
194
  end
195
195
 
@@ -0,0 +1,17 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # Slack request
4
+ class Slack < BaseRequest
5
+ def initialize(*args)
6
+ super(*args)
7
+
8
+ # If arguments exists set as body into options!
9
+ # Its for just easy ChattyCrow.send_slack 'Hello'
10
+ @options[:body] = @arguments_flatten if @arguments_flatten
11
+
12
+ # Set payload
13
+ @payload = @options
14
+ end
15
+ end
16
+ end
17
+ end
@@ -7,22 +7,32 @@ module ChattyCrow
7
7
  attr_accessor :code, :body, :status, :msg
8
8
 
9
9
  def initialize(response)
10
- @code = response.code
11
- @body = JSON.parse(response.body)
10
+ if response.is_a?(String)
11
+ @code = response.code
12
+ @body = JSON.parse(response.body)
13
+ else
14
+ @code = -1
15
+ @body = response
16
+ end
17
+
12
18
  @status = @body.delete('status')
13
19
  @msg = @body.delete('msg')
14
20
  end
15
21
 
22
+ def status
23
+ @status.to_s
24
+ end
25
+
16
26
  def ok?
17
- @status.to_s.downcase == 'ok'
27
+ @status.downcase.downcase == 'ok'
18
28
  end
19
29
 
20
30
  def partial_error?
21
- @status.to_s.downcase == 'perror'
31
+ @status.downcase.downcase == 'perror'
22
32
  end
23
33
 
24
34
  def error?
25
- @status.to_s.downcase == 'error'
35
+ @status.downcase.downcase == 'error'
26
36
  end
27
37
  end
28
38
  end
@@ -0,0 +1,66 @@
1
+ module ChattyCrow
2
+ module Response
3
+ # Notification response
4
+ class Batch < Base
5
+ # Channels
6
+ attr_accessor :channels
7
+
8
+ # Actual channel & token
9
+ attr_accessor :token
10
+
11
+ # Initialize notification response
12
+ # @param response [RestClient::Response] Response from server
13
+ # @param options [Hash] Headers
14
+ def initialize(response, options)
15
+ super response
16
+
17
+ # Get Token
18
+ @token = options[:headers]['Token']
19
+
20
+ # Create an hash for channels
21
+ @channels ||= {}
22
+
23
+ # Parse channels!
24
+ @body['channels'].each do |channel|
25
+ @channels[channel['channel']] = BatchNotification.new(channel, @token)
26
+ end
27
+ end
28
+
29
+ def channels
30
+ @channels ||= {}
31
+ end
32
+ end
33
+
34
+ # Batch notification response class
35
+ # Place for refactoring
36
+ class BatchNotification < Base
37
+ # Infos
38
+ attr_accessor :success, :total, :failed_contacts, :message_id
39
+
40
+ # Token & channel
41
+ attr_accessor :token, :channel
42
+
43
+ # Init from response
44
+ def initialize(body, token)
45
+ super(body)
46
+
47
+ # Set token
48
+ @token = token
49
+
50
+ # Parse response
51
+ @channel = @body.delete('channel')
52
+ @success = @body.delete('success')
53
+ @total = @body.delete('total')
54
+ @failed_contacts = @body.delete('contacts')
55
+ @message_id = @body.delete('message_id')
56
+ end
57
+
58
+ # Get instance of message
59
+ # @return Message [ChattyCrow::Message]
60
+ def message
61
+ @message ||= ::ChattyCrow::Message.new(channel: @channel, token: @token, message_id: @message_id)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
@@ -2,17 +2,32 @@ module ChattyCrow
2
2
  module Response
3
3
  # Notification response
4
4
  class Notification < Base
5
- attr_accessor :success, :total, :failed_contacts
5
+ attr_accessor :success, :total, :failed_contacts, :message_id
6
+
7
+ # Actual channel & token
8
+ attr_accessor :token, :channel
6
9
 
7
10
  # Initialize notification response
8
11
  # @param response [RestClient::Response] Response from server
9
- def initialize(response)
12
+ # @param options [Hash] Headers
13
+ def initialize(response, options)
10
14
  super response
11
15
 
12
16
  # Parse response
13
17
  @success = @body.delete('success')
14
18
  @total = @body.delete('total')
15
19
  @failed_contacts = @body.delete('contacts')
20
+ @message_id = @body.delete('message_id')
21
+
22
+ # Parse headers for message
23
+ @channel = options[:headers]['Channel']
24
+ @token = options[:headers]['Token']
25
+ end
26
+
27
+ # Get instance of message
28
+ # @return Message [ChattyCrow::Message]
29
+ def message
30
+ @message ||= ::ChattyCrow::Message.new(channel: @channel, token: @token, message_id: @message_id)
16
31
  end
17
32
  end
18
33
  end
@@ -1,4 +1,4 @@
1
1
  # Version
2
2
  module ChattyCrow
3
- VERSION = '1.2.1'.freeze
3
+ VERSION = '1.3.1'.freeze
4
4
  end
@@ -0,0 +1,20 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ # Unit test for contact methods
4
+ class BaseRequestTest < MiniTest::Should::TestCase
5
+ should 'Raise argument error if location filed has an invalid type' do
6
+ expect { ChattyCrow.send_skype 'Test', location: { latitude: 'invalid string', longitude: 'invalid string', range: 'invalid string' } }.to_raise ArgumentError
7
+ end
8
+
9
+ should 'Raise argument error if some fields in locations missing' do
10
+ expect { ChattyCrow.send_skype 'Test', location: { latitude: 30.2010102, range: 200 } }.to_raise ArgumentError
11
+ end
12
+
13
+ should 'Raise argument error if some fields in time missing' do
14
+ expect { ChattyCrow.send_skype 'Test', time: { start: 4093903 } }.to_raise ArgumentError
15
+ end
16
+
17
+ should 'Raise argument error if some fields in time has an invalid type' do
18
+ expect { ChattyCrow.send_skype 'Test', time: { start: '40.2030', end: 'abcd' } }.to_raise ArgumentError
19
+ end
20
+ end
@@ -0,0 +1,112 @@
1
+ require File.expand_path '../helper', __FILE__
2
+
3
+ # Batch test
4
+ class BatchTest < MiniTest::Should::TestCase
5
+ should 'use default token' do
6
+ batch = ChattyCrow.create_batch
7
+ batch.add_ios payload: 'Dear users', channel: 'test#1'
8
+
9
+ # Mock batch
10
+ body = {
11
+ channels: [
12
+ {
13
+ channel: 'channel#2',
14
+ status: 'PERROR',
15
+ msg: '10 of 15 created',
16
+ success: 10,
17
+ total: 15,
18
+ contacts: %w(test1 test2),
19
+ message_id: 1
20
+ },
21
+ ]
22
+ }
23
+ mock_batch status: %(200 Ok), body: body.to_json
24
+
25
+ # Call
26
+ batch.execute!
27
+
28
+ # Compare last token
29
+ expect(last_headers['token']).to_equal ChattyCrow.configuration.token
30
+ end
31
+
32
+ should 'raise error when try to add service without channel' do
33
+ batch = ChattyCrow.create_batch
34
+ expect { batch.add_ios(payload: 'Dear users') }.to_raise ::ArgumentError
35
+ end
36
+
37
+ should 'return valid notification response' do
38
+ FIRST_CHANNEL = 'channel#1'
39
+
40
+ # Mock notification
41
+ body = {
42
+ channels: [
43
+ {
44
+ channel: FIRST_CHANNEL,
45
+ status: 'OK',
46
+ msg: '15 of 15 created',
47
+ success: 15,
48
+ total: 15,
49
+ contacts: [],
50
+ message_id: 1
51
+ },
52
+ {
53
+ channel: 'channel#2',
54
+ status: 'PERROR',
55
+ msg: '10 of 15 created',
56
+ success: 10,
57
+ total: 15,
58
+ contacts: %w(test1 test2),
59
+ message_id: 1
60
+ },
61
+ ]
62
+ }
63
+ mock_batch status: %(200 Ok), body: body.to_json
64
+
65
+ # Create batch
66
+ batch = ChattyCrow.create_batch
67
+
68
+ # Add some payloads
69
+ batch.add_ios(payload: 'Dear IOS users', channel: FIRST_CHANNEL)
70
+ batch.add_skype(payload: 'Dear SKYPE users', channel: 'channel#2')
71
+
72
+ # Response
73
+ response = batch.execute!
74
+
75
+ # Parse response
76
+ expect(response.channels.count).to_equal 2
77
+
78
+ # Get response for first channel
79
+ channel = response.channels[FIRST_CHANNEL]
80
+ template = body[:channels][0]
81
+ expect(channel).to_be_instance_of ChattyCrow::Response::BatchNotification
82
+ expect(channel.status).to_equal template[:status]
83
+ expect(channel.ok?).to_equal true
84
+ expect(channel.partial_error?).to_equal false
85
+
86
+ # Get message
87
+ message_body = {
88
+ status: :ok,
89
+ notifications: {
90
+ success: 15,
91
+ waiting: 0,
92
+ error: 0
93
+ }
94
+ }
95
+ mock_message(id: template[:message_id], body: message_body.to_json)
96
+ message = channel.message
97
+
98
+ expect(last_headers['token']).to_equal ChattyCrow.configuration.token
99
+ expect(last_headers['channel']).to_equal FIRST_CHANNEL
100
+
101
+ expect(message.channel).to_equal FIRST_CHANNEL
102
+ expect(message.message_id).to_equal template[:message_id]
103
+ expect(message.token).to_equal ChattyCrow.configuration.token
104
+ expect(message.success).to_equal message_body[:notifications][:success]
105
+ expect(message.waiting).to_equal message_body[:notifications][:waiting]
106
+ expect(message.error).to_equal message_body[:notifications][:error]
107
+
108
+ # Clear mocks
109
+ clear_mock_url
110
+ end
111
+ end
112
+
@@ -3,9 +3,10 @@ require File.expand_path '../helper', __FILE__
3
3
  # Test for proper gem configuration
4
4
  class ConfigurationTest < MiniTest::Should::TestCase
5
5
  should 'provide defaults' do
6
- assert_config_default :host, 'https://chatty-crow.com/api/v1/'
7
- assert_config_default :notification_url, 'https://chatty-crow.com/api/v1/notification'
8
- assert_config_default :contacts_url, 'https://chatty-crow.com/api/v1/contacts'
6
+ assert_config_default :host, 'https://chattycrow.com/api/v1/'
7
+ assert_config_default :notification_url, 'https://chattycrow.com/api/v1/notification'
8
+ assert_config_default :contacts_url, 'https://chattycrow.com/api/v1/contacts'
9
+ assert_config_default :batch_url, 'https://chattycrow.com/api/v1/batch'
9
10
  assert_config_default :token, nil
10
11
  assert_config_default :default_channel, nil
11
12
  assert_config_default :http_open_timeout, 2
@@ -19,6 +20,7 @@ class ConfigurationTest < MiniTest::Should::TestCase
19
20
  assert_equal url, config.host
20
21
  assert_equal "#{url}/notification", config.notification_url
21
22
  assert_equal "#{url}/contacts", config.contacts_url
23
+ assert_equal "#{url}/batch", config.batch_url
22
24
  end
23
25
 
24
26
  should 'use correct url with backslash' do
@@ -28,6 +30,7 @@ class ConfigurationTest < MiniTest::Should::TestCase
28
30
  assert_equal url, config.host
29
31
  assert_equal "#{url}notification", config.notification_url
30
32
  assert_equal "#{url}contacts", config.contacts_url
33
+ assert_equal "#{url}batch", config.batch_url
31
34
  end
32
35
 
33
36
  def assert_config_default(option, default_value, config = nil)
@@ -35,6 +35,21 @@ module TestHelpers
35
35
  FakeWeb.register_uri(method, configuration.notification_url, options)
36
36
  end
37
37
 
38
+ # Mock default batch url
39
+ def mock_batch(options)
40
+ method = options.delete(:method) || :post
41
+ options[:status] ||= %w(200 OK)
42
+
43
+ FakeWeb.register_uri(method, configuration.batch_url, options)
44
+ end
45
+
46
+ # Mock messages
47
+ def mock_message(options)
48
+ method = options.delete(:method) || :get
49
+ options[:status] ||= %w(200 OK)
50
+ FakeWeb.register_uri(method, "#{configuration.messages_url}/#{options[:id]}", options)
51
+ end
52
+
38
53
  # Mock default URL for contacts
39
54
  def mock_contacts(options)
40
55
  method = options.delete(:method) || :post
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chatty_crow
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Netbrick s.r.o.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-05 00:00:00.000000000 Z
11
+ date: 2015-01-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rest_client
28
+ name: rest-client
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
@@ -184,6 +184,7 @@ files:
184
184
  - lib/chatty-crow.rb
185
185
  - lib/chatty_crow.rb
186
186
  - lib/chatty_crow/action_mailer_extension.rb
187
+ - lib/chatty_crow/batch_notification_request.rb
187
188
  - lib/chatty_crow/config.rb
188
189
  - lib/chatty_crow/contacts_request.rb
189
190
  - lib/chatty_crow/error.rb
@@ -191,16 +192,20 @@ files:
191
192
  - lib/chatty_crow/error/invalid_attributes.rb
192
193
  - lib/chatty_crow/error/invalid_return.rb
193
194
  - lib/chatty_crow/error/unauthorized_request.rb
195
+ - lib/chatty_crow/message.rb
194
196
  - lib/chatty_crow/notification_request.rb
195
197
  - lib/chatty_crow/railtie.rb
196
198
  - lib/chatty_crow/request.rb
197
199
  - lib/chatty_crow/request/android.rb
200
+ - lib/chatty_crow/request/hipchat.rb
198
201
  - lib/chatty_crow/request/ios.rb
199
202
  - lib/chatty_crow/request/jabber.rb
200
203
  - lib/chatty_crow/request/mail.rb
201
204
  - lib/chatty_crow/request/skype.rb
205
+ - lib/chatty_crow/request/slack.rb
202
206
  - lib/chatty_crow/request/sms.rb
203
207
  - lib/chatty_crow/response.rb
208
+ - lib/chatty_crow/response/batch.rb
204
209
  - lib/chatty_crow/response/contacts_add.rb
205
210
  - lib/chatty_crow/response/contacts_remove.rb
206
211
  - lib/chatty_crow/response/notification.rb
@@ -209,6 +214,8 @@ files:
209
214
  - test/android_test.rb
210
215
  - test/attachment_test.rb
211
216
  - test/base_parser_test.rb
217
+ - test/base_request_test.rb
218
+ - test/batch_test.rb
212
219
  - test/configuration_test.rb
213
220
  - test/contacts_test.rb
214
221
  - test/factories/stewie.jpeg
@@ -227,7 +234,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
227
234
  requirements:
228
235
  - - ">="
229
236
  - !ruby/object:Gem::Version
230
- version: '2'
237
+ version: '1.9'
231
238
  required_rubygems_version: !ruby/object:Gem::Requirement
232
239
  requirements:
233
240
  - - ">="
@@ -235,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
242
  version: '0'
236
243
  requirements: []
237
244
  rubyforge_project:
238
- rubygems_version: 2.4.2
245
+ rubygems_version: 2.4.3
239
246
  signing_key:
240
247
  specification_version: 4
241
248
  summary: Send your messages to more than 6 comunnication channels.
@@ -243,9 +250,12 @@ test_files:
243
250
  - test/android_test.rb
244
251
  - test/attachment_test.rb
245
252
  - test/base_parser_test.rb
253
+ - test/base_request_test.rb
254
+ - test/batch_test.rb
246
255
  - test/configuration_test.rb
247
256
  - test/contacts_test.rb
248
257
  - test/factories/stewie.jpeg
249
258
  - test/helper.rb
250
259
  - test/mail_test.rb
251
260
  - test/response_test.rb
261
+ has_rdoc: