chatty_crow 1.2.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.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG +0 -0
  3. data/Gemfile +3 -0
  4. data/Guardfile +5 -0
  5. data/INSTALL +0 -0
  6. data/LICENSE +201 -0
  7. data/README.textile +183 -0
  8. data/Rakefile +14 -0
  9. data/chatty_crow.gemspec +37 -0
  10. data/lib/chatty-crow.rb +1 -0
  11. data/lib/chatty_crow.rb +119 -0
  12. data/lib/chatty_crow/action_mailer_extension.rb +31 -0
  13. data/lib/chatty_crow/config.rb +64 -0
  14. data/lib/chatty_crow/contacts_request.rb +79 -0
  15. data/lib/chatty_crow/error.rb +26 -0
  16. data/lib/chatty_crow/error/channel_not_found.rb +6 -0
  17. data/lib/chatty_crow/error/invalid_attributes.rb +21 -0
  18. data/lib/chatty_crow/error/invalid_return.rb +7 -0
  19. data/lib/chatty_crow/error/unauthorized_request.rb +6 -0
  20. data/lib/chatty_crow/notification_request.rb +54 -0
  21. data/lib/chatty_crow/railtie.rb +10 -0
  22. data/lib/chatty_crow/request.rb +53 -0
  23. data/lib/chatty_crow/request/android.rb +23 -0
  24. data/lib/chatty_crow/request/ios.rb +16 -0
  25. data/lib/chatty_crow/request/jabber.rb +17 -0
  26. data/lib/chatty_crow/request/mail.rb +264 -0
  27. data/lib/chatty_crow/request/skype.rb +17 -0
  28. data/lib/chatty_crow/request/sms.rb +17 -0
  29. data/lib/chatty_crow/response.rb +34 -0
  30. data/lib/chatty_crow/response/contacts_add.rb +43 -0
  31. data/lib/chatty_crow/response/contacts_remove.rb +35 -0
  32. data/lib/chatty_crow/response/notification.rb +19 -0
  33. data/lib/chatty_crow/version.rb +4 -0
  34. data/lib/chattycrow.rb +1 -0
  35. data/test/android_test.rb +57 -0
  36. data/test/attachment_test.rb +13 -0
  37. data/test/base_parser_test.rb +125 -0
  38. data/test/configuration_test.rb +37 -0
  39. data/test/contacts_test.rb +90 -0
  40. data/test/factories/stewie.jpeg +0 -0
  41. data/test/helper.rb +63 -0
  42. data/test/mail_test.rb +62 -0
  43. data/test/response_test.rb +33 -0
  44. metadata +251 -0
@@ -0,0 +1,23 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # Android push notification request
4
+ class Android < BaseRequest
5
+ # Initialize android request
6
+ # @param args [Array] Options
7
+ def initialize(*args)
8
+ super(*args)
9
+
10
+ # Get payload
11
+ @payload = @options.delete(:payload)
12
+
13
+ # Raise error when payload is empty!
14
+ fail ::ArgumentError, 'Payload is empty!' if @payload.nil? || !@payload.is_a?(Hash)
15
+
16
+ # Android require data field and the field must be hash!
17
+ if !@payload[:data].is_a?(Hash) || @payload[:data].nil? || @payload[:data].keys.empty?
18
+ fail ::ArgumentError, 'Data in payload is required and it needs to be hash!'
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # Ios push notification request
4
+ class Ios < BaseRequest
5
+ def initialize(*args)
6
+ super(*args)
7
+
8
+ # Get payload
9
+ @payload = @options.delete(:payload)
10
+
11
+ # Raise error when payload is empty!
12
+ fail ::ArgumentError, 'Payload is empty!' unless @payload
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # Jabber request
4
+ class Jabber < 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_jabber 'Hello'
10
+ @options[:body] = @arguments_flatten if @arguments_flatten
11
+
12
+ # Set payload
13
+ @payload = @options
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,264 @@
1
+ require 'base64'
2
+ require 'mime/types'
3
+
4
+ module ChattyCrow
5
+ module Request
6
+ # Support class for Attachments!
7
+ class Attachment
8
+ # Attachment data!
9
+ # * File = FD
10
+ # * Name = File Name
11
+ # * Mime = Mime/type
12
+ attr_accessor :file, :filename, :mime_type, :inline
13
+
14
+ # Initializer - set variables
15
+ def initialize(options = {})
16
+ @file = options.delete(:file)
17
+ @filename = options.delete(:filename)
18
+ @mime_type = options.delete(:mime_type)
19
+ @inline = options.delete(:inline)
20
+ end
21
+
22
+ # To json
23
+ # @return [Hash] JSon hash for API
24
+ def to_json
25
+ {
26
+ name: @filename,
27
+ mime_type: @mime_type,
28
+ base64data: file_base64,
29
+ inline: @inline ? true : false
30
+ }
31
+ end
32
+
33
+ private
34
+
35
+ # File base 64 decide what file descriptor means
36
+ # and return BASE 64
37
+ def file_base64
38
+ f = @file
39
+
40
+ # ActionDispatch::Http::UploadedFile (get tempfile)
41
+ if defined?(::ActionDispatch) && f.instance_of?(::ActionDispatch::Http::UploadedFile)
42
+ f = f.tempfile
43
+ end
44
+
45
+ case f.class.name
46
+ when 'String' # File is String = Base 64 already!
47
+ f
48
+ when 'Tempfile', 'File'
49
+ # Seek to start
50
+ f.seek(0)
51
+
52
+ # Read
53
+ Base64.encode64(f.read)
54
+ else
55
+ # Try to convert to base 64!
56
+ if f.respond_to?(:to_s)
57
+ Base64.encode64(f.to_s)
58
+ else
59
+ Base64.encode64(f)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ # Mail request
66
+ class Mail < BaseRequest
67
+ # Mail data
68
+ #
69
+ # * Mail subject
70
+ # * Text mail body
71
+ # * Html mail body
72
+ # * Attachments
73
+ attr_accessor :subject, :text_body, :html_body, :attachments
74
+
75
+ # Action Mailer mail!
76
+ attr_accessor :am_mail, :am_klass
77
+
78
+ # Create mail from options
79
+ # @param args [Array] Options
80
+ def initialize(*args)
81
+ # Super parse arguments
82
+ super(*args)
83
+
84
+ # Parse email or email from Rails
85
+ if action_mailer?
86
+ @am_klass = @arguments[0]
87
+ @am_mail = @arguments[1]
88
+ else
89
+ # Delete required parts
90
+ @subject = @options.delete(:subject)
91
+ @text_body = @options.delete(:text_body)
92
+ @html_body = @options.delete(:html_body)
93
+ end
94
+ end
95
+
96
+ # Validate if arguments are from Rails::ActionMailer
97
+ def action_mailer?
98
+ defined?(::Rails) && @arguments && @arguments.count == 2 && @arguments[1].instance_of?(::Mail::Message)
99
+ end
100
+
101
+ # Method missing (Rails Action Mailer extension)
102
+ # Forward methods to Mail::Message from ActionMailer
103
+ def method_missing(method_name, *args)
104
+ if @am_mail && @am_mail.respond_to?(method_name)
105
+ @am_mail.send(method_name, *args)
106
+ else
107
+ super
108
+ end
109
+ end
110
+
111
+ # Add attachments
112
+ def add_file(options = {})
113
+ # Get file
114
+ file = options.delete(:file)
115
+
116
+ # Raise argument error when argument file missing!
117
+ fail ::ArgumentError, 'File is required' unless file
118
+
119
+ # Other options
120
+ filename = options.delete(:filename)
121
+ mime_type = options.delete(:mime_type)
122
+
123
+ # When file is String! options are required
124
+ if file.is_a?(String) && (filename.to_s.empty? || mime_type.to_s.empty?)
125
+ fail ::ArgumentError, 'Filename and Mime Type options are required if file is base64data string'
126
+ end
127
+
128
+ # Create file instance
129
+ attachment = Attachment.new(file: file, filename: filename, mime_type: mime_type)
130
+
131
+ # Rails File
132
+ if defined?(::ActionDispatch) && file.instance_of?(::ActionDispatch::Http::UploadedFile)
133
+ attachment.filename = filename || file.original_filename
134
+ attachment.mime_type = mime_type || file.content_type
135
+ end
136
+
137
+ # Guess filename & mime-types! (only Tempfile or File)
138
+ unless attachment.filename
139
+ attachment.filename = File.basename(file.path)
140
+ end
141
+
142
+ unless attachment.mime_type
143
+ mime = MIME::Types.type_for(file.path).first
144
+ attachment.mime_type = mime.simplified if mime
145
+ end
146
+
147
+ # Raise arguments error when there is not filename or mime type
148
+ fail ::ArgumentError, 'Mime type is required' unless attachment.mime_type
149
+ fail ::ArgumentError, 'Filename is required' unless attachment.filename
150
+
151
+ # Add to attachments
152
+ attachments << attachment
153
+
154
+ # Return attachment
155
+ attachment
156
+ end
157
+
158
+ # Return attachments - always array!
159
+ def attachments
160
+ @attachments ||= []
161
+ end
162
+
163
+ # Override deliver method from Mail::Message
164
+ # @return [ChattyCrow::Response] Response
165
+ def deliver
166
+ if invalid?
167
+ false
168
+ else
169
+ NotificationRequest.execute(self, false)
170
+ end
171
+ end
172
+
173
+ # Raise errors if error
174
+ def deliver!
175
+ if invalid?
176
+ fail ::ArgumentError, 'Body is required!'
177
+ else
178
+ NotificationRequest.execute(self)
179
+ end
180
+ end
181
+
182
+ # Payload method
183
+ def payload
184
+ # Set data from Action mailer
185
+ set_data_from_am if @am_mail
186
+
187
+ # Prepare payload!
188
+ {
189
+ subject: @subject,
190
+ html_body: Base64.encode64(@html_body || ''),
191
+ text_body: Base64.encode64(@text_body || ''),
192
+ attachments: attachments.map(&:to_json)
193
+ }
194
+ end
195
+
196
+ private
197
+
198
+ def invalid?
199
+ # Set data from Action mailer
200
+ set_data_from_am if @am_mail
201
+
202
+ # Text body
203
+ @text_body.to_s.empty? && @html_body.to_s.empty?
204
+ end
205
+
206
+ # Set all data from Mail::Message
207
+ def set_data_from_am
208
+ # Contacts
209
+ @contacts = ChattyCrow.wrap(@am_mail.to)
210
+
211
+ # Channel?
212
+ @channel = @am_klass.cc_channel
213
+
214
+ # Subject
215
+ @subject = @am_mail.subject
216
+
217
+ # Body parts!
218
+ @am_mail.body.parts.each do |part|
219
+ content_type = part.content_type
220
+
221
+ if content_type.include?('text/html')
222
+ @html_body = part.body.raw_source
223
+ end
224
+
225
+ if content_type.include?('text/plain')
226
+ @text_body = part.body.raw_source
227
+ end
228
+ end
229
+
230
+ # Attachments!
231
+ @am_mail.attachments.each do |attachment|
232
+ # Create file!
233
+ file = ChattyCrow::Request::Attachment.new
234
+
235
+ # Inline attachment?
236
+ file.inline = attachment.inline?
237
+
238
+ # Set file data
239
+ file.file = Base64.encode64(attachment.body.raw_source)
240
+
241
+ # Rails save mime types and names into headers
242
+ header = attachment.header.fields.first
243
+
244
+ # Get mime_type!
245
+ if header
246
+ file.mime_type = "#{header.main_type}/#{header.sub_type}"
247
+ else
248
+ file.mime_type = 'text/plain'
249
+ end
250
+
251
+ # Get filename
252
+ if header
253
+ file.filename = header.filename
254
+ else
255
+ file.filename = 'unknown_file'
256
+ end
257
+
258
+ # Return attachment
259
+ attachments << file
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
@@ -0,0 +1,17 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # Skype request
4
+ class Skype < 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_skype 'Hello'
10
+ @options[:body] = @arguments_flatten if @arguments_flatten
11
+
12
+ # Set payload
13
+ @payload = @options
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module ChattyCrow
2
+ module Request
3
+ # SMS request
4
+ class Sms < 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_jabber 'Hello'
10
+ @options[:body] = @arguments_flatten if @arguments_flatten
11
+
12
+ # Set payload
13
+ @payload = @options
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,34 @@
1
+ # Parent of all ChattyCrow errors
2
+ module ChattyCrow
3
+ module Response
4
+ # Parent of all responses
5
+ class Base
6
+ # Parse response from RestClient
7
+ attr_accessor :code, :body, :status, :msg
8
+
9
+ def initialize(response)
10
+ @code = response.code
11
+ @body = JSON.parse(response.body)
12
+ @status = @body.delete('status')
13
+ @msg = @body.delete('msg')
14
+ end
15
+
16
+ def ok?
17
+ @status.to_s.downcase == 'ok'
18
+ end
19
+
20
+ def partial_error?
21
+ @status.to_s.downcase == 'perror'
22
+ end
23
+
24
+ def error?
25
+ @status.to_s.downcase == 'error'
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ Dir[File.dirname(__FILE__) + '/response/*.rb'].sort.each do |path|
32
+ filename = File.basename(path)
33
+ require "chatty_crow/response/#{filename}"
34
+ end
@@ -0,0 +1,43 @@
1
+ module ChattyCrow
2
+ module Response
3
+ # Contacts add request
4
+ class ContactsAdd < Base
5
+ # Statistics
6
+ attr_accessor :success_count, :exists_count, :failed_count
7
+
8
+ # Contact lists
9
+ attr_accessor :exists, :failed
10
+
11
+ # Initialize contact add response
12
+ # @param response [RestClient::Response] Response from server
13
+ def initialize(response)
14
+ super response
15
+
16
+ # Parse response
17
+ stats = @body.delete('stats')
18
+ contacts = @body.delete('contacts')
19
+
20
+ # Set statistics
21
+ if stats
22
+ @success_count = stats.delete('success')
23
+ @exists_count = stats.delete('exists')
24
+ @failed_count = stats.delete('failed')
25
+ end
26
+
27
+ # Set contacts
28
+ if contacts
29
+ @exists = contacts.delete('exists')
30
+ @failed = contacts.delete('failed')
31
+ end
32
+ end
33
+
34
+ def exists
35
+ @exists || []
36
+ end
37
+
38
+ def failed
39
+ @failed || []
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ module ChattyCrow
2
+ module Response
3
+ # Contact remove response
4
+ class ContactsRemove < Base
5
+ # Statistics
6
+ attr_accessor :success_count, :failed_count
7
+
8
+ # Failed contacts
9
+ attr_accessor :failed
10
+
11
+ # Initialize contact add response
12
+ # @param response [RestClient::Response] Response from server
13
+ def initialize(response)
14
+ super response
15
+
16
+ # Parse response
17
+ stats = @body.delete('stats')
18
+ contacts = @body.delete('contacts')
19
+
20
+ # Set statistics
21
+ if stats
22
+ @success_count = stats.delete('success')
23
+ @failed_count = stats.delete('failed')
24
+ end
25
+
26
+ # Set contacts
27
+ @failed = contacts.delete('failed') if contacts
28
+ end
29
+
30
+ def failed
31
+ @failed || []
32
+ end
33
+ end
34
+ end
35
+ end