tms_client 0.1.0 → 0.1.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/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
|