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 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 'rubygems-tasks', :git => 'https://github.com/postmodern/rubygems-tasks.git'
11
- end
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>', :subject => 'Hey')
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=>'example2@example.com')
60
+ message.recipients.build(:email=>'')
60
61
  message.post # true
61
- message.recipients.collection.detect{|r| r.errors } # {"phone"=>["is not a number"]}
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 # "forward"
117
- puts at.fields # ["url", "http_method", ...]
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:
@@ -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
- # === Options
11
- # * +:api_root+ - The root URL of the TMS api. Defaults to localhost:3000
12
- # * +:logger+ - An instance of a Logger class (http transport information will be logged here) - defaults to nil
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
- # === Examples
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 = {:api_root => 'http://localhost:3000', :logger => nil})
23
+ def initialize(username, password, options = DEFAULTS)
20
24
  @api_root = options[:api_root]
21
25
  connect!(username, password, options[:logger])
22
26
  discover!
@@ -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
- # # message.rb
38
- # collection_attributes :recipients
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! if attrs.any?
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
- # # email.rb
57
- # collection_attributes :recipients, 'EmailRecipient'
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
- set_attributes_from_hash(self.client.get(href).body)
93
- self
107
+ process_response(client.get(self.href), :get)
94
108
  end
95
109
 
96
110
  def post
97
- response = client.post(self)
111
+ self.errors = nil
112
+ process_response(client.post(self), :post)
113
+ end
98
114
 
99
- case response.status
100
- when 200..299
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
- response = client.put(self)
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
- response = self.client.delete(href)
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
- private
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
- # === Example
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
- # === Example
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
- # ==== Attributes
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
- # * +name+ - The name of the command. This will default to the command_type if not supplied.
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, fields) that can be attached
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
- # ==== Attributes
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 :fields, :name
18
- readonly_attributes :name, :fields
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
- # === Example
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
- collection_attribute :opens, 'EmailRecipientOpens'
25
+ readonly_collection_attribute :opens, 'EmailRecipientOpens'
14
26
 
15
27
  ##
16
28
  # A CollectionResource of EmailRecipientClicks for this EmailRecipient
17
- collection_attribute :clicks, 'EmailRecipientClicks'
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
- # ==== Attributes
6
- #
7
- # * +name+ - The name of the keyword.
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
- # === Examples
12
+ # @example
10
13
  # keyword = client.keywords.build(:name => "HOWDY")
11
14
  # keyword.post
12
- # keyword.name = "DOODY"
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
- # ==== Attributes
6
+ # @attr body [String] The content of the SMS. This field will be truncated to 160 characters.
7
7
  #
8
- # * +body+ - The content of the SMS. This field will be truncated to 160 characters.
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
- # ==== Attributes
7
+ # @attr play_url [String] The url to the sound file to be played back to the call recipients
8
8
  #
9
- # * +play_url+ - The url to the sound file to be played back to the call recipients
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
@@ -1,3 +1,3 @@
1
1
  module TMS #:nodoc:
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
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
 
@@ -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 = [{"fields"=>["dcm_account_codes"], "name"=>"dcm_unsubscribe"},
13
- {"fields"=>["dcm_account_code", "dcm_topic_codes"], "name"=>"dcm_subscribe"},
14
- {"fields"=>["http_method", "username", "password", "url"], "name"=>"forward"}]
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.0
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-02-27 00:00:00.000000000 Z
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: ! 'A reference implementation, written in Ruby, to interact with GovDelivery''s
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: 1.8.25
124
+ rubygems_version: 2.0.3
130
125
  signing_key:
131
- specification_version: 3
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