tms_client 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +6 -4
- data/README.md +31 -8
- data/lib/tms_client/client.rb +9 -5
- data/lib/tms_client/errors.rb +33 -0
- data/lib/tms_client/instance_resource.rb +54 -54
- data/lib/tms_client/mail/delivery_method.rb +57 -0
- data/lib/tms_client/resource/collections.rb +6 -2
- data/lib/tms_client/resource/command.rb +4 -6
- data/lib/tms_client/resource/command_action.rb +17 -0
- data/lib/tms_client/resource/command_type.rb +7 -7
- data/lib/tms_client/resource/email_message.rb +20 -13
- data/lib/tms_client/resource/email_recipient.rb +16 -4
- data/lib/tms_client/resource/inbound_sms_message.rb +2 -2
- data/lib/tms_client/resource/keyword.rb +12 -8
- data/lib/tms_client/resource/sms_message.rb +2 -4
- data/lib/tms_client/resource/voice_message.rb +2 -4
- data/lib/tms_client/version.rb +1 -1
- data/lib/tms_client.rb +1 -0
- data/spec/command_types_spec.rb +12 -3
- data/spec/instance_resource_spec.rb +2 -0
- data/spec/keyword_spec.rb +8 -4
- data/spec/mail/delivery_method_spec.rb +29 -0
- metadata +18 -22
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b7a0be5e64161ecf0605c965d2bb949ec4b157db
|
4
|
+
data.tar.gz: 6f725c6cb7c2f771dd7cbc07d67f00ad113af1fb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8ede49f2709329392caa5e954071b769f136abe14f6ad32f7f1f8ca617314fe0f07a4025c6e1dc2d6cd7bd4298bc0d8d961381d366e46671d38da898a2b16197
|
7
|
+
data.tar.gz: 4bc8ad9a68092470eea57fd069d6cc6fba3c1b0491f0c28489be27141a3ec25f8f760078e2e53ec76ced4edb35cf4062d72cd03068a323ade5f46b50f9303abb
|
data/Gemfile
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
source "https://rubygems.org"
|
2
2
|
gemspec
|
3
3
|
|
4
|
-
group :development do
|
4
|
+
group :development, :test do
|
5
5
|
gem 'rspec'
|
6
6
|
gem 'rake'
|
7
|
-
gem 'redcarpet'
|
7
|
+
gem 'redcarpet', :platform => :ruby
|
8
8
|
gem 'yard'
|
9
9
|
gem 'guard-rspec'
|
10
|
-
gem '
|
11
|
-
|
10
|
+
gem 'mail'
|
11
|
+
gem 'rubygems-tasks', :git => 'https://github.com/postmodern/rubygems-tasks.git', :platform => :ruby
|
12
|
+
end
|
13
|
+
|
data/README.md
CHANGED
@@ -51,14 +51,15 @@ message.href # "/messages/sms/87"
|
|
51
51
|
message.get # <TMS::SmsMessage href=/messages/sms/87 attributes={...}>
|
52
52
|
```
|
53
53
|
|
54
|
-
### Sending Email
|
54
|
+
### Sending an Email
|
55
55
|
|
56
56
|
```ruby
|
57
|
-
message = client.email_messages.build(:body=>'<p><a href="http://example.com">Visit here</a>',
|
57
|
+
message = client.email_messages.build(:body=>'<p><a href="http://example.com">Visit here</a>',
|
58
|
+
:subject => 'Hey')
|
58
59
|
message.recipients.build(:email=>'example1@example.com')
|
59
|
-
message.recipients.build(:email=>'
|
60
|
+
message.recipients.build(:email=>'')
|
60
61
|
message.post # true
|
61
|
-
message.recipients.collection.detect{|r| r.errors } # {"
|
62
|
+
message.recipients.collection.detect{|r| r.errors } # {"email"=>["can't be blank"]}
|
62
63
|
# save succeeded, but we have one bad recipient
|
63
64
|
message.href # "/messages/email/87"
|
64
65
|
message.get # <TMS::EmailMessage href=/messages/email/88 attributes={...}>
|
@@ -113,8 +114,9 @@ Command Types are the available commands that can be used to respond to an incom
|
|
113
114
|
```ruby
|
114
115
|
command_types = client.command_types.get
|
115
116
|
command_types.collection.each do |at|
|
116
|
-
puts at.name
|
117
|
-
puts at.
|
117
|
+
puts at.name # "forward"
|
118
|
+
puts at.string_fields # ["url", ...]
|
119
|
+
puts at.array_fields # ["foo", ...]
|
118
120
|
end
|
119
121
|
```
|
120
122
|
|
@@ -123,7 +125,7 @@ Keywords are chunks of text that are used to match an incoming SMS message.
|
|
123
125
|
|
124
126
|
```ruby
|
125
127
|
# CRUD
|
126
|
-
keyword = client.keywords.build(:name => "BUSRIDE")
|
128
|
+
keyword = client.keywords.build(:name => "BUSRIDE", :response_text => "Visit example.com/rides for more info")
|
127
129
|
keyword.post # true
|
128
130
|
keyword.name # 'busride'
|
129
131
|
keyword.name = "TRAINRIDE"
|
@@ -134,7 +136,7 @@ keyword.delete # true
|
|
134
136
|
# list
|
135
137
|
keywords = client.keywords.get
|
136
138
|
keywords.collection.each do |k|
|
137
|
-
puts k.name
|
139
|
+
puts k.name, k.response_text
|
138
140
|
end
|
139
141
|
```
|
140
142
|
|
@@ -174,6 +176,27 @@ logger = Logger.new(STDOUT)
|
|
174
176
|
client = TMS::Client.new('username', 'password', :logger => logger)
|
175
177
|
```
|
176
178
|
|
179
|
+
ActionMailer integration
|
180
|
+
------------------------
|
181
|
+
|
182
|
+
You can use TMS from the mail gem or ActionMailer as a delivery method.
|
183
|
+
|
184
|
+
Gemfile
|
185
|
+
```ruby
|
186
|
+
gem 'tms_client', :require=>'tms_client/mail/delivery_method'
|
187
|
+
```
|
188
|
+
|
189
|
+
config/environment.rb
|
190
|
+
```ruby
|
191
|
+
config.action_mailer.delivery_method = :govdelivery_tms
|
192
|
+
config.action_mailer.govdelivery_tms_settings = {
|
193
|
+
:username=>'email@foo.com',
|
194
|
+
:password=>'pass',
|
195
|
+
:api_root=>'https://stage-tms.govdelivery.com'
|
196
|
+
}
|
197
|
+
```
|
198
|
+
|
199
|
+
|
177
200
|
Generating Documentation
|
178
201
|
------------------------
|
179
202
|
This project uses [yard](https://github.com/lsegal/yard) to generate documentation. To generate API documentation yourself, use the following series of commands from the project root:
|
data/lib/tms_client/client.rb
CHANGED
@@ -5,18 +5,22 @@ class TMS::Client
|
|
5
5
|
|
6
6
|
attr_accessor :connection, :href
|
7
7
|
|
8
|
+
DEFAULTS = {:api_root => 'http://localhost:3000', :logger => nil}.freeze
|
9
|
+
|
8
10
|
# Create a new client and issue a request for the available resources for a given account.
|
9
11
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
12
|
+
# @param [String] username The username of your account
|
13
|
+
# @param [String] password The password of your account
|
14
|
+
# @param [Hash] options
|
15
|
+
# @option options [String] :api_root The root URL of the TMS api. Defaults to localhost:3000
|
16
|
+
# @option options [Logger] :logger An instance of a Logger class (http transport information will be logged here) - defaults to nil
|
13
17
|
#
|
14
|
-
#
|
18
|
+
# @example
|
15
19
|
# client = TMS::Client.new("foo@example.com", "onetwothree", {
|
16
20
|
# :api_root => "https://tms.govdelivery.com",
|
17
21
|
# :logger => Logger.new(STDOUT)})
|
18
22
|
#
|
19
|
-
def initialize(username, password, options =
|
23
|
+
def initialize(username, password, options = DEFAULTS)
|
20
24
|
@api_root = options[:api_root]
|
21
25
|
connect!(username, password, options[:logger])
|
22
26
|
discover!
|
data/lib/tms_client/errors.rb
CHANGED
@@ -1,5 +1,38 @@
|
|
1
1
|
module TMS
|
2
2
|
module Errors
|
3
|
+
class ServerError
|
4
|
+
def initialize(response)
|
5
|
+
super("TMS client encountered a server error: #{response.status} \n#{response.body}")
|
6
|
+
end
|
7
|
+
end
|
8
|
+
class NoRelation < StandardError
|
9
|
+
def initialize(rel=nil, obj=nil)
|
10
|
+
message = "no link relation "
|
11
|
+
message << "'#{rel}' " if rel
|
12
|
+
message << 'is available'
|
13
|
+
message << " for #{obj}" if obj
|
14
|
+
super(message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
class InvalidVerb
|
18
|
+
attr_reader :record
|
19
|
+
|
20
|
+
def initialize(record_or_string)
|
21
|
+
if record_or_string.respond_to?(:href)
|
22
|
+
@record = record_or_string
|
23
|
+
super("Couldn't POST #{record.class} to #{record.href}: #{record.errors.join(', ')}")
|
24
|
+
else
|
25
|
+
super(record_or_string)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
class InvalidPost < InvalidVerb
|
31
|
+
end
|
32
|
+
class InvalidPut < InvalidVerb
|
33
|
+
end
|
34
|
+
class InvalidDelete < InvalidVerb
|
35
|
+
end
|
3
36
|
class InvalidGet < StandardError
|
4
37
|
def initialize(message=nil)
|
5
38
|
super(message || "Can't GET a resource after an invalid POST; either create a new object or fix errors")
|
@@ -6,7 +6,7 @@ module TMS::InstanceResource
|
|
6
6
|
end
|
7
7
|
|
8
8
|
module ClassMethods
|
9
|
-
|
9
|
+
##
|
10
10
|
# Writeable attributes are sent on POST/PUT.
|
11
11
|
#
|
12
12
|
def writeable_attributes(*attrs)
|
@@ -18,7 +18,7 @@ module TMS::InstanceResource
|
|
18
18
|
@writeable_attributes
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
##
|
22
22
|
# Readonly attributes don't get POSTed.
|
23
23
|
# (timestamps are included by default)
|
24
24
|
#
|
@@ -31,15 +31,16 @@ module TMS::InstanceResource
|
|
31
31
|
@readonly_attributes
|
32
32
|
end
|
33
33
|
|
34
|
-
|
34
|
+
##
|
35
35
|
# For collections that are represented as attributes (i.e. inline, no href)
|
36
36
|
#
|
37
|
-
#
|
38
|
-
#
|
37
|
+
# @example
|
38
|
+
# collection_attributes :recipients
|
39
|
+
#
|
39
40
|
def collection_attributes(*attrs)
|
40
41
|
@collection_attributes ||= []
|
41
42
|
if attrs.any?
|
42
|
-
@collection_attributes.map!(&:to_sym).concat(attrs).uniq!
|
43
|
+
@collection_attributes.map!(&:to_sym).concat(attrs).uniq!
|
43
44
|
@collection_attributes.each { |a| setup_collection(a) }
|
44
45
|
end
|
45
46
|
@collection_attributes
|
@@ -49,18 +50,32 @@ module TMS::InstanceResource
|
|
49
50
|
@custom_class_names ||= {}
|
50
51
|
end
|
51
52
|
|
52
|
-
|
53
|
+
##
|
53
54
|
# For collections that are represented as attributes (i.e. inline, no href)
|
54
55
|
# and that have a class name other than the one we would infer.
|
55
56
|
#
|
56
|
-
#
|
57
|
-
#
|
57
|
+
# @example
|
58
|
+
# collection_attributes :recipients, 'EmailRecipient'
|
59
|
+
#
|
58
60
|
def collection_attribute(attr, tms_class)
|
59
61
|
@collection_attributes ||= []
|
60
62
|
@collection_attributes.push(attr).uniq!
|
61
63
|
setup_collection(attr, TMS.const_get(tms_class))
|
62
64
|
end
|
63
65
|
|
66
|
+
##
|
67
|
+
# Read-only collection attributes don't get POSTed.
|
68
|
+
# Use this for collections that are represented as attributes, but cannot be modified.
|
69
|
+
#
|
70
|
+
# @example
|
71
|
+
# readonly_collection_attribute :opens
|
72
|
+
#
|
73
|
+
def readonly_collection_attribute(attr, tms_class)
|
74
|
+
@readonly_collection_attributes ||= []
|
75
|
+
@readonly_collection_attributes.push(attr).uniq!
|
76
|
+
setup_collection(attr, TMS.const_get(tms_class))
|
77
|
+
end
|
78
|
+
|
64
79
|
def setup_attributes(attrs, readonly=false)
|
65
80
|
attrs.map(&:to_sym).each do |property|
|
66
81
|
self.send :define_method, :"#{property}=", &lambda { |v| @attributes[property] = v } unless readonly
|
@@ -89,60 +104,24 @@ module TMS::InstanceResource
|
|
89
104
|
|
90
105
|
def get
|
91
106
|
raise TMS::Errors::InvalidGet if self.new_record?
|
92
|
-
|
93
|
-
self
|
107
|
+
process_response(client.get(self.href), :get)
|
94
108
|
end
|
95
109
|
|
96
110
|
def post
|
97
|
-
|
111
|
+
self.errors = nil
|
112
|
+
process_response(client.post(self), :post)
|
113
|
+
end
|
98
114
|
|
99
|
-
|
100
|
-
|
101
|
-
set_attributes_from_hash(response.body)
|
102
|
-
self.new_record=false
|
103
|
-
return true
|
104
|
-
when 401
|
105
|
-
raise Exception.new("401 Not Authorized")
|
106
|
-
when 404
|
107
|
-
raise(Exception.new("Can't POST to #{self.href}"))
|
108
|
-
else
|
109
|
-
if response.body['errors']
|
110
|
-
self.errors = response.body['errors']
|
111
|
-
end
|
112
|
-
end
|
113
|
-
return false
|
115
|
+
def post!
|
116
|
+
self.post or raise TMS::Errors::InvalidPost.new(self)
|
114
117
|
end
|
115
118
|
|
116
119
|
def put
|
117
|
-
|
118
|
-
case response.status
|
119
|
-
when 200
|
120
|
-
self.new_record=false
|
121
|
-
set_attributes_from_hash(response.body)
|
122
|
-
return true
|
123
|
-
when 401
|
124
|
-
raise Exception.new("401 Not Authorized")
|
125
|
-
when 404
|
126
|
-
raise(Exception.new("Can't POST to #{self.href}"))
|
127
|
-
else
|
128
|
-
if response.body['errors']
|
129
|
-
self.errors = response.body['errors']
|
130
|
-
end
|
131
|
-
end
|
132
|
-
return false
|
120
|
+
process_response(client.put(self), :put)
|
133
121
|
end
|
134
122
|
|
135
123
|
def delete
|
136
|
-
|
137
|
-
case response.status
|
138
|
-
when 200
|
139
|
-
return true
|
140
|
-
else
|
141
|
-
if response.body['errors']
|
142
|
-
self.errors = response.body['errors']
|
143
|
-
end
|
144
|
-
end
|
145
|
-
return false
|
124
|
+
process_response(client.delete(self.href), :delete)
|
146
125
|
end
|
147
126
|
|
148
127
|
def to_s
|
@@ -166,7 +145,28 @@ module TMS::InstanceResource
|
|
166
145
|
self.class.custom_class_names[rel.to_sym] || super
|
167
146
|
end
|
168
147
|
|
169
|
-
|
148
|
+
def process_response(response, method)
|
149
|
+
error_class = TMS::Errors.const_get("Invalid#{method.to_s.capitalize}")
|
150
|
+
case response.status
|
151
|
+
when 204
|
152
|
+
return true
|
153
|
+
when 200..299
|
154
|
+
set_attributes_from_hash(response.body) if response.body.is_a?(Hash)
|
155
|
+
self.new_record=false
|
156
|
+
return true
|
157
|
+
when 401
|
158
|
+
raise error_class.new("401 Not Authorized")
|
159
|
+
when 404
|
160
|
+
raise(error_class.new("Can't POST to #{self.href}"))
|
161
|
+
when 500..599
|
162
|
+
raise(TMS::Errors::ServerError.new(response))
|
163
|
+
else # 422?
|
164
|
+
if response.body['errors']
|
165
|
+
self.errors = response.body['errors']
|
166
|
+
end
|
167
|
+
end
|
168
|
+
return false
|
169
|
+
end
|
170
170
|
|
171
171
|
def set_attributes_from_hash(hash)
|
172
172
|
hash.reject { |k, _| k=~/^_/ }.each do |property, value|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'tms_client'
|
2
|
+
require 'mail'
|
3
|
+
require 'mail/check_delivery_params'
|
4
|
+
module TMS
|
5
|
+
module Mail
|
6
|
+
# Use TMS from the mail gem or ActionMailer as a delivery method.
|
7
|
+
#
|
8
|
+
# # Gemfile
|
9
|
+
# gem 'tms_client', :require=>'tms_client/mail/delivery_method'
|
10
|
+
#
|
11
|
+
# # config/environment.rb
|
12
|
+
# config.action_mailer.delivery_method = :govdelivery_tms
|
13
|
+
# config.action_mailer.govdelivery_tms_settings = {
|
14
|
+
# :username=>'email@foo.com',
|
15
|
+
# :password=>'pass',
|
16
|
+
# :api_root=>'https://stage-tms.govdelivery.com'
|
17
|
+
# }
|
18
|
+
class DeliveryMethod
|
19
|
+
include ::Mail::CheckDeliveryParams
|
20
|
+
|
21
|
+
def initialize(values)
|
22
|
+
self.settings = values
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_accessor :settings
|
26
|
+
|
27
|
+
def deliver!(mail)
|
28
|
+
#check_params(mail)
|
29
|
+
raise TMS::Errors::NoRelation.new('email_messages', client) unless client.respond_to?(:email_messages)
|
30
|
+
|
31
|
+
envelope_from = mail.return_path || mail.sender || mail.from_addrs.first
|
32
|
+
|
33
|
+
tms_message = client.email_messages.build(
|
34
|
+
:from_name => mail[:from].display_names.first,
|
35
|
+
:subject => mail.subject,
|
36
|
+
:body => (mail.body || mail.html_part.body || mail.text_part.body).to_s
|
37
|
+
)
|
38
|
+
|
39
|
+
mail.to.each { |recip| tms_message.recipients.build(:email => recip) }
|
40
|
+
tms_message.post!
|
41
|
+
tms_message
|
42
|
+
end
|
43
|
+
|
44
|
+
def client
|
45
|
+
@client ||= TMS::Client.new(settings[:username], settings[:password], settings)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if defined?(ActionMailer)
|
52
|
+
ActionMailer::Base.add_delivery_method :govdelivery_tms, TMS::Mail::DeliveryMethod, {
|
53
|
+
:username => nil,
|
54
|
+
:password => nil,
|
55
|
+
:logger => ActionMailer::Base.logger,
|
56
|
+
:api_root => TMS::Client::DEFAULTS[:api_root]}
|
57
|
+
end
|
@@ -32,7 +32,7 @@ end
|
|
32
32
|
|
33
33
|
# A collection of Keyword objects.
|
34
34
|
#
|
35
|
-
#
|
35
|
+
# @example
|
36
36
|
# keywords = client.keywords.get
|
37
37
|
#
|
38
38
|
class TMS::Keywords
|
@@ -49,7 +49,7 @@ end
|
|
49
49
|
#
|
50
50
|
# This resource is read-only.
|
51
51
|
#
|
52
|
-
#
|
52
|
+
# @example
|
53
53
|
# client.command_types.get
|
54
54
|
# client.command_types.collection.each {|at| ... }
|
55
55
|
class TMS::CommandTypes
|
@@ -59,3 +59,7 @@ end
|
|
59
59
|
class TMS::Commands
|
60
60
|
include TMS::CollectionResource
|
61
61
|
end
|
62
|
+
|
63
|
+
class TMS::CommandActions
|
64
|
+
include TMS::CollectionResource
|
65
|
+
end
|
@@ -2,13 +2,11 @@ module TMS #:nodoc:
|
|
2
2
|
# A command is a combination of behavior and parameters that should be executed
|
3
3
|
# when an incoming SMS message matches the associated Keyword.
|
4
4
|
#
|
5
|
-
#
|
5
|
+
# @attr name [String] The name of the command. This will default to the command_type if not supplied.
|
6
|
+
# @attr command_type [String] The type of this command. A list of valid types can be found by querying the CommandType list.
|
7
|
+
# @attr params [Hash] A Hash of string/string pairs used as configuration for this command.
|
6
8
|
#
|
7
|
-
#
|
8
|
-
# * +command_type+ - The type of this command. A list of valid types can be found by querying the CommandType list.
|
9
|
-
# * +params+ - A Hash of string/string pairs used as configuration for this command.
|
10
|
-
#
|
11
|
-
# === Examples
|
9
|
+
# @example
|
12
10
|
# command = keyword.commands.build(:name => "subscribe to news", :command_type => "dcm_subscribe", :dcm_account_code => "NEWS", :dcm_topic_codes => "NEWS_1, NEWS_2")
|
13
11
|
# command.post
|
14
12
|
# command.dcm_topic_codes += ", NEWS_5"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module TMS #:nodoc:
|
2
|
+
# CommandAction object represent the results of Commands for a particular input (e.g. an incoming SMS message)
|
3
|
+
#
|
4
|
+
# This resource is read-only.
|
5
|
+
#
|
6
|
+
# ==== Attributes
|
7
|
+
#
|
8
|
+
# * +http_response_code+ - e.g. 200, 404, etc.
|
9
|
+
# * +http_content_type+ - text/html, etc.
|
10
|
+
# * +http_body+ - Request body (if it's <500 characters, otherwise it'll be nil)
|
11
|
+
#
|
12
|
+
class CommandAction
|
13
|
+
include InstanceResource
|
14
|
+
|
15
|
+
readonly_attributes :status, :content_type, :response_body, :created_at
|
16
|
+
end
|
17
|
+
end
|
@@ -1,20 +1,20 @@
|
|
1
1
|
module TMS #:nodoc:
|
2
|
-
# CommandType is a pair of values (name,
|
2
|
+
# CommandType is a pair of values (name, string_fields, array_fields) that can be attached
|
3
3
|
# to a Keyword (in a Command object).
|
4
4
|
#
|
5
5
|
# This resource is read-only.
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# * +name+ - The name of the CommandType.
|
10
|
-
# * +fields+ - An Array of strings representing the different fields on this
|
7
|
+
# @attr name [String] The name of the CommandType.
|
8
|
+
# @attr string_fields [Array] An Array of strings representing the different string_fields on this
|
11
9
|
# CommandType. Field values will always be strings.
|
10
|
+
# @attr array_fields [Array] An array of strings representing the different array fields on this
|
11
|
+
# CommandType. Field values will always be arrays of strings.
|
12
12
|
#
|
13
13
|
class CommandType
|
14
14
|
|
15
15
|
include InstanceResource
|
16
16
|
|
17
|
-
# @!parse attr_reader :
|
18
|
-
readonly_attributes :name, :
|
17
|
+
# @!parse attr_reader :string_fields, :array_fields, :name
|
18
|
+
readonly_attributes :name, :string_fields, :array_fields
|
19
19
|
end
|
20
20
|
end
|
@@ -2,37 +2,44 @@ module TMS #:nodoc:
|
|
2
2
|
# An EmailMessage is used to create and send a email to a collection of EmailRecipient
|
3
3
|
# objects. Certain metrics are available after the email is sent, including
|
4
4
|
# the collection of recipients who clicked or opened the email.
|
5
|
-
#
|
6
|
-
#
|
7
|
-
# ==== Attributes
|
8
|
-
#
|
9
|
-
# * +from_name+ - The name of the person or entity sending the email.
|
10
|
-
# * +subject+ - The subject of the email
|
11
|
-
# * +body+ - The body of the email
|
12
5
|
#
|
6
|
+
# @attr from_name [String] The name of the person or entity sending the email.
|
7
|
+
# @attr subject [String] The subject of the email
|
8
|
+
# @attr body [String] The body of the email
|
9
|
+
# @attr open_tracking_enabled [Boolean] Whether to track opens on this message. Optional, defaults to true.
|
10
|
+
# @attr click_tracking_enabled [Boolean] Whether to track clicks on links in this message. Optional, defaults to true.
|
11
|
+
# @attr macros [Hash] A dictionary of key/value pairs to use in the subject and body as default macros.
|
12
|
+
# The message-level macros are used when a recipient has no value for a given macro key.
|
13
13
|
#
|
14
|
-
#
|
15
|
-
# Sending a message
|
14
|
+
# @example Sending a message
|
16
15
|
# email_message = client.email_messages.build(:subject => "Great news!", :body => "You win! <a href='http://example.com/'>click here</a>.")
|
17
16
|
# email_message.recipients.build(:email => "john@example.com")
|
18
17
|
# email_message.recipients.build(:email => "jeff@example.com")
|
19
18
|
# email_message.post
|
20
19
|
# email_message.get
|
21
20
|
#
|
22
|
-
# Viewing recipients that clicked on a link in the email
|
21
|
+
# @example Viewing recipients that clicked on a link in the email
|
23
22
|
# email_message.get
|
24
23
|
# email_message.clicked.get
|
25
24
|
# email_message.clicked.collection # => [<#EmailRecipient>,...]
|
26
25
|
#
|
27
|
-
# Viewing recipients that opened the email
|
26
|
+
# @example Viewing recipients that opened the email
|
28
27
|
# email_message.get
|
29
28
|
# email_message.opened.get
|
30
29
|
# email_message.opened.collection # => [<#EmailRecipient>,...]
|
30
|
+
#
|
31
|
+
# @example Using macros
|
32
|
+
# email_message = client.email_messages.build(:subject => "Hello [[user]]",
|
33
|
+
# :body => "Your name is [[name]]",
|
34
|
+
# :macros => {:user => "Sir or Madam", :name => "unknown"})
|
35
|
+
# email_message.recipients.build(:email => "jeff@example.com", :macros => {:user => "jexample", :name => "Jeff Example"})
|
36
|
+
# email_message.post
|
37
|
+
#
|
31
38
|
class EmailMessage
|
32
39
|
include InstanceResource
|
33
40
|
|
34
|
-
# @!parse attr_accessor :body, :from_name, :subject
|
35
|
-
writeable_attributes :body, :from_name, :subject
|
41
|
+
# @!parse attr_accessor :body, :from_name, :subject, :open_tracking_enabled, :click_tracking_enabled, :macros
|
42
|
+
writeable_attributes :body, :from_name, :subject, :open_tracking_enabled, :click_tracking_enabled, :macros
|
36
43
|
|
37
44
|
# @!parse attr_reader :created_at, :status
|
38
45
|
readonly_attributes :created_at, :status
|
@@ -1,19 +1,31 @@
|
|
1
1
|
module TMS #:nodoc:
|
2
|
+
# An EmailRecipient is used in conjunction with an EmailMessage to send email.
|
3
|
+
#
|
4
|
+
# @attr email [String] The recipient email address
|
5
|
+
# @attr macros [Hash] A dictionary of key/value pairs to resolve in the subject and body as macros. This value can be nil.
|
6
|
+
#
|
7
|
+
# @example Sending a message
|
8
|
+
# email_message = client.email_messages.build(:subject => "Great news!", :body => "You win! <a href='http://example.com/'>click here</a>.")
|
9
|
+
# email_message.recipients.build(:email => "john@example.com")
|
10
|
+
# email_message.recipients.build(:email => "jeff@example.com")
|
11
|
+
# email_message.post
|
12
|
+
# email_message.get
|
13
|
+
#
|
2
14
|
class EmailRecipient
|
3
15
|
include InstanceResource
|
4
16
|
|
5
|
-
# @!parse attr_accessor :email
|
6
|
-
writeable_attributes :email
|
17
|
+
# @!parse attr_accessor :email, :macros
|
18
|
+
writeable_attributes :email, :macros
|
7
19
|
|
8
20
|
# @!parse attr_reader :completed_at
|
9
21
|
readonly_attributes :completed_at
|
10
22
|
|
11
23
|
##
|
12
24
|
# A CollectionResource of EmailRecipientOpens for this EmailRecipient
|
13
|
-
|
25
|
+
readonly_collection_attribute :opens, 'EmailRecipientOpens'
|
14
26
|
|
15
27
|
##
|
16
28
|
# A CollectionResource of EmailRecipientClicks for this EmailRecipient
|
17
|
-
|
29
|
+
readonly_collection_attribute :clicks, 'EmailRecipientClicks'
|
18
30
|
end
|
19
31
|
end
|
@@ -2,7 +2,7 @@ module TMS #:nodoc:
|
|
2
2
|
class InboundSmsMessage
|
3
3
|
include InstanceResource
|
4
4
|
|
5
|
-
# @!parse attr_reader :created_at, :completed_at, :from, :body, :to
|
6
|
-
readonly_attributes :created_at, :completed_at, :from, :body, :to
|
5
|
+
# @!parse attr_reader :created_at, :completed_at, :from, :body, :to, :command_status
|
6
|
+
readonly_attributes :created_at, :completed_at, :from, :body, :to, :command_status, :keyword_response
|
7
7
|
end
|
8
8
|
end
|
@@ -1,22 +1,26 @@
|
|
1
1
|
module TMS #:nodoc:
|
2
2
|
# A Keyword is a word that TMS will detect in an incoming SMS message. Keywords can have Commands, and
|
3
|
-
# when an incoming text message has a keyword, TMS will execute the keyword's Commands.
|
3
|
+
# when an incoming text message has a keyword, TMS will execute the keyword's Commands. Keywords may
|
4
|
+
# also have a response text field. If the response text is not blank, the system will send an SMS reply to the user
|
5
|
+
# immediately with the given text.
|
4
6
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
7
|
+
# @attr name [String] The name of the keyword. The system will scan an incoming SMS for this string (in a case-insensitive manner).
|
8
|
+
# @attr response_text [String] (Optional) The static text with which to reply to an SMS to this keyword.
|
9
|
+
# This value can be blank, in which case the handset user will not receive a response.
|
10
|
+
# Note that all keyword commands will be executed, regardless of the value of response_text.
|
8
11
|
#
|
9
|
-
#
|
12
|
+
# @example
|
10
13
|
# keyword = client.keywords.build(:name => "HOWDY")
|
11
14
|
# keyword.post
|
12
|
-
# keyword.name = "
|
15
|
+
# keyword.name = "INFO"
|
16
|
+
# keyword.response_text = "Please call our support staff at 1-555-555-5555"
|
13
17
|
# keyword.put
|
14
18
|
# keyword.delete
|
15
19
|
class Keyword
|
16
20
|
include InstanceResource
|
17
21
|
|
18
|
-
# @!parse attr_accessor :name
|
19
|
-
writeable_attributes :name
|
22
|
+
# @!parse attr_accessor :name, :response_text
|
23
|
+
writeable_attributes :name, :response_text
|
20
24
|
|
21
25
|
##
|
22
26
|
# A CollectionResource of Command objects
|
@@ -3,11 +3,9 @@ module TMS #:nodoc:
|
|
3
3
|
# objects.
|
4
4
|
#
|
5
5
|
#
|
6
|
-
#
|
6
|
+
# @attr body [String] The content of the SMS. This field will be truncated to 160 characters.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# === Example
|
8
|
+
# @example
|
11
9
|
# sms = client.sms_messages.build(:body => "Hello")
|
12
10
|
# sms.recipients.build(:phone => "+18001002000")
|
13
11
|
# sms.post
|
@@ -4,11 +4,9 @@ module TMS #:nodoc:
|
|
4
4
|
# played to them. Accepted sound formats include +wav+, +mp3+, and +aiff+.
|
5
5
|
#
|
6
6
|
#
|
7
|
-
#
|
7
|
+
# @attr play_url [String] The url to the sound file to be played back to the call recipients
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
# === Example
|
9
|
+
# @example
|
12
10
|
# voice_message = client.voice_messages.build(:play_url => "http://example.com/emergency_weather.mp3")
|
13
11
|
# voice_message.recipients.build(:phone => "+18001002000")
|
14
12
|
# voice_message.post
|
data/lib/tms_client/version.rb
CHANGED
data/lib/tms_client.rb
CHANGED
@@ -28,6 +28,7 @@ require 'tms_client/resource/voice_message'
|
|
28
28
|
require 'tms_client/resource/email_message'
|
29
29
|
require 'tms_client/resource/inbound_sms_message'
|
30
30
|
require 'tms_client/resource/command_type'
|
31
|
+
require 'tms_client/resource/command_action'
|
31
32
|
require 'tms_client/resource/command'
|
32
33
|
require 'tms_client/resource/keyword'
|
33
34
|
|
data/spec/command_types_spec.rb
CHANGED
@@ -9,12 +9,21 @@ describe TMS::CommandTypes do
|
|
9
9
|
@command_types = TMS::CommandTypes.new(client, '/command_types')
|
10
10
|
end
|
11
11
|
it 'should GET ok' do
|
12
|
-
body = [{"
|
13
|
-
|
14
|
-
|
12
|
+
body = [{"name"=>"dcm_unsubscribe",
|
13
|
+
"string_fields"=>[],
|
14
|
+
"array_fields"=>["dcm_account_codes"]},
|
15
|
+
{"name"=>"dcm_subscribe",
|
16
|
+
"string_fields"=>["dcm_account_code"],
|
17
|
+
"array_fields"=>["dcm_topic_codes"]},
|
18
|
+
{"name"=>"forward",
|
19
|
+
"string_fields"=>["http_method", "username", "password", "url"],
|
20
|
+
"array_fields"=>[]}]
|
15
21
|
@command_types.client.should_receive(:get).and_return(double('response', :body => body, :status => 200, :headers => {}))
|
16
22
|
@command_types.get
|
17
23
|
@command_types.collection.length.should == 3
|
24
|
+
ct = @command_types.collection.find{|c| c.name == "dcm_subscribe"}
|
25
|
+
ct.array_fields.should eq(["dcm_topic_codes"])
|
26
|
+
ct.string_fields.should eq(["dcm_account_code"])
|
18
27
|
end
|
19
28
|
end
|
20
29
|
end
|
@@ -3,6 +3,7 @@ class Foo
|
|
3
3
|
include TMS::InstanceResource
|
4
4
|
writeable_attributes :bar
|
5
5
|
collection_attribute :blah, 'EmailMessage'
|
6
|
+
readonly_collection_attribute :shah, 'EmailMessage'
|
6
7
|
end
|
7
8
|
|
8
9
|
describe TMS::InstanceResource do
|
@@ -27,6 +28,7 @@ describe TMS::InstanceResource do
|
|
27
28
|
|
28
29
|
it 'should correctly reflect on collection resources' do
|
29
30
|
@instance_resource.blah.class.should == TMS::EmailMessage
|
31
|
+
@instance_resource.shah.class.should == TMS::EmailMessage
|
30
32
|
end
|
31
33
|
end
|
32
34
|
end
|
data/spec/keyword_spec.rb
CHANGED
@@ -6,22 +6,25 @@ describe TMS::Keyword do
|
|
6
6
|
double('client')
|
7
7
|
end
|
8
8
|
before do
|
9
|
-
@keyword = TMS::Keyword.new(client, nil, {:name => 'LOL'})
|
9
|
+
@keyword = TMS::Keyword.new(client, nil, {:name => 'LOL', :response_text => 'very funny!'})
|
10
10
|
end
|
11
11
|
it 'should initialize with attrs' do
|
12
12
|
@keyword.name.should == 'LOL'
|
13
|
+
@keyword.response_text.should == 'very funny!'
|
13
14
|
end
|
14
15
|
it 'should post successfully' do
|
15
16
|
response = {:name => 'lol'}
|
16
17
|
@keyword.client.should_receive('post').with(@keyword).and_return(double('response', :status => 201, :body => response))
|
17
18
|
@keyword.post
|
18
19
|
@keyword.name.should == 'lol'
|
20
|
+
@keyword.response_text.should == 'very funny!'
|
19
21
|
end
|
20
22
|
it 'should handle errors' do
|
21
23
|
response = {'errors' => {:name => "can't be nil"}}
|
22
24
|
@keyword.client.should_receive('post').with(@keyword).and_return(double('response', :status => 422, :body => response))
|
23
25
|
@keyword.post
|
24
26
|
@keyword.name.should == 'LOL'
|
27
|
+
@keyword.response_text.should == 'very funny!'
|
25
28
|
@keyword.errors.should == {:name => "can't be nil"}
|
26
29
|
end
|
27
30
|
end
|
@@ -35,18 +38,19 @@ describe TMS::Keyword do
|
|
35
38
|
@keyword = TMS::Keyword.new(client, '/keywords/99', {})
|
36
39
|
end
|
37
40
|
it 'should GET cleanly' do
|
38
|
-
response = {:name => 'FOO'}
|
41
|
+
response = {:name => 'FOO', :response_text => 'hello'}
|
39
42
|
@keyword.client.should_receive('get').with(@keyword.href).and_return(double('response', :status => 200, :body => response))
|
40
43
|
@keyword.get
|
41
44
|
@keyword.name.should == 'FOO'
|
45
|
+
@keyword.response_text.should == 'hello'
|
42
46
|
end
|
43
47
|
it 'should PUT cleanly' do
|
44
48
|
@keyword.name = "GOVLIE"
|
45
|
-
response = {:name => 'govlie'}
|
49
|
+
response = {:name => 'govlie', :response_text => nil}
|
46
50
|
@keyword.client.should_receive('put').with(@keyword).and_return(double('response', :status => 200, :body => response))
|
47
51
|
@keyword.put
|
48
52
|
@keyword.name.should == 'govlie'
|
49
|
-
|
53
|
+
@keyword.response_text.should be_nil
|
50
54
|
end
|
51
55
|
it 'should DELETE cleanly' do
|
52
56
|
@keyword.client.should_receive('delete').with(@keyword.href).and_return(double('response', :status => 200, :body => ''))
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mail'
|
3
|
+
require 'tms_client/mail/delivery_method'
|
4
|
+
describe TMS::Mail::DeliveryMethod do
|
5
|
+
subject { TMS::Mail::DeliveryMethod.new({}) }
|
6
|
+
let(:client) { stub('TMS::Client') }
|
7
|
+
let(:email_messages) { double('email_messages') }
|
8
|
+
let(:tms_message) { double('tms_message', :recipients => double(:build => TMS::Recipient.new('href'))) }
|
9
|
+
|
10
|
+
it 'should work with a basic Mail::Message' do
|
11
|
+
mail = Mail.new do
|
12
|
+
subject 'hi'
|
13
|
+
from '"My mom" <my@mom.com>'
|
14
|
+
to '"A Nice Fellow" <tyler@sink.govdelivery.com>'
|
15
|
+
body '<blink>HI</blink>'
|
16
|
+
end
|
17
|
+
client.stub(:email_messages).and_return(email_messages)
|
18
|
+
subject.stub(:client).and_return(client)
|
19
|
+
email_messages.should_receive(:build).with(
|
20
|
+
:from_name => mail[:from].display_names.first,
|
21
|
+
:subject => mail.subject,
|
22
|
+
:body => mail.body.to_s || mail.html_part.body.to_s || mail.text_part.body.to_s
|
23
|
+
).and_return(tms_message)
|
24
|
+
tms_message.should_receive(:post!).and_return(true)
|
25
|
+
|
26
|
+
subject.deliver!(mail)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
metadata
CHANGED
@@ -1,65 +1,58 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tms_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- GovDelivery
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-06-01 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: faraday
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: faraday_middleware
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: activesupport
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
|
-
description:
|
55
|
+
description: 'A reference implementation, written in Ruby, to interact with GovDelivery''s
|
63
56
|
TMS API. The client is compatible with Ruby versions 1.8.7 and 1.9.3. '
|
64
57
|
email:
|
65
58
|
- support@govdelivery.com
|
@@ -79,9 +72,11 @@ files:
|
|
79
72
|
- lib/tms_client/instance_resource.rb
|
80
73
|
- lib/tms_client/link_header.rb
|
81
74
|
- lib/tms_client/logger.rb
|
75
|
+
- lib/tms_client/mail/delivery_method.rb
|
82
76
|
- lib/tms_client/request.rb
|
83
77
|
- lib/tms_client/resource/collections.rb
|
84
78
|
- lib/tms_client/resource/command.rb
|
79
|
+
- lib/tms_client/resource/command_action.rb
|
85
80
|
- lib/tms_client/resource/command_type.rb
|
86
81
|
- lib/tms_client/resource/email_message.rb
|
87
82
|
- lib/tms_client/resource/email_recipient.rb
|
@@ -102,33 +97,33 @@ files:
|
|
102
97
|
- spec/instance_resource_spec.rb
|
103
98
|
- spec/keyword_spec.rb
|
104
99
|
- spec/keywords_spec.rb
|
100
|
+
- spec/mail/delivery_method_spec.rb
|
105
101
|
- spec/message_spec.rb
|
106
102
|
- spec/messages_spec.rb
|
107
103
|
- spec/spec_helper.rb
|
108
104
|
- spec/tms_client_spec.rb
|
109
105
|
homepage: http://govdelivery.com
|
110
106
|
licenses: []
|
107
|
+
metadata: {}
|
111
108
|
post_install_message:
|
112
109
|
rdoc_options: []
|
113
110
|
require_paths:
|
114
111
|
- lib
|
115
112
|
required_ruby_version: !ruby/object:Gem::Requirement
|
116
|
-
none: false
|
117
113
|
requirements:
|
118
|
-
- -
|
114
|
+
- - '>='
|
119
115
|
- !ruby/object:Gem::Version
|
120
116
|
version: '0'
|
121
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
-
none: false
|
123
118
|
requirements:
|
124
|
-
- -
|
119
|
+
- - '>='
|
125
120
|
- !ruby/object:Gem::Version
|
126
121
|
version: '0'
|
127
122
|
requirements: []
|
128
123
|
rubyforge_project:
|
129
|
-
rubygems_version:
|
124
|
+
rubygems_version: 2.0.3
|
130
125
|
signing_key:
|
131
|
-
specification_version:
|
126
|
+
specification_version: 4
|
132
127
|
summary: A ruby client to interact with the GovDelivery TMS REST API.
|
133
128
|
test_files:
|
134
129
|
- spec/client_spec.rb
|
@@ -137,6 +132,7 @@ test_files:
|
|
137
132
|
- spec/instance_resource_spec.rb
|
138
133
|
- spec/keyword_spec.rb
|
139
134
|
- spec/keywords_spec.rb
|
135
|
+
- spec/mail/delivery_method_spec.rb
|
140
136
|
- spec/message_spec.rb
|
141
137
|
- spec/messages_spec.rb
|
142
138
|
- spec/spec_helper.rb
|