chatty_crow 1.2.1 → 1.3.1

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