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.
- checksums.yaml +7 -0
- data/CHANGELOG +0 -0
- data/Gemfile +3 -0
- data/Guardfile +5 -0
- data/INSTALL +0 -0
- data/LICENSE +201 -0
- data/README.textile +183 -0
- data/Rakefile +14 -0
- data/chatty_crow.gemspec +37 -0
- data/lib/chatty-crow.rb +1 -0
- data/lib/chatty_crow.rb +119 -0
- data/lib/chatty_crow/action_mailer_extension.rb +31 -0
- data/lib/chatty_crow/config.rb +64 -0
- data/lib/chatty_crow/contacts_request.rb +79 -0
- data/lib/chatty_crow/error.rb +26 -0
- data/lib/chatty_crow/error/channel_not_found.rb +6 -0
- data/lib/chatty_crow/error/invalid_attributes.rb +21 -0
- data/lib/chatty_crow/error/invalid_return.rb +7 -0
- data/lib/chatty_crow/error/unauthorized_request.rb +6 -0
- data/lib/chatty_crow/notification_request.rb +54 -0
- data/lib/chatty_crow/railtie.rb +10 -0
- data/lib/chatty_crow/request.rb +53 -0
- data/lib/chatty_crow/request/android.rb +23 -0
- data/lib/chatty_crow/request/ios.rb +16 -0
- data/lib/chatty_crow/request/jabber.rb +17 -0
- data/lib/chatty_crow/request/mail.rb +264 -0
- data/lib/chatty_crow/request/skype.rb +17 -0
- data/lib/chatty_crow/request/sms.rb +17 -0
- data/lib/chatty_crow/response.rb +34 -0
- data/lib/chatty_crow/response/contacts_add.rb +43 -0
- data/lib/chatty_crow/response/contacts_remove.rb +35 -0
- data/lib/chatty_crow/response/notification.rb +19 -0
- data/lib/chatty_crow/version.rb +4 -0
- data/lib/chattycrow.rb +1 -0
- data/test/android_test.rb +57 -0
- data/test/attachment_test.rb +13 -0
- data/test/base_parser_test.rb +125 -0
- data/test/configuration_test.rb +37 -0
- data/test/contacts_test.rb +90 -0
- data/test/factories/stewie.jpeg +0 -0
- data/test/helper.rb +63 -0
- data/test/mail_test.rb +62 -0
- data/test/response_test.rb +33 -0
- 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
|