short_message 1.1.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +370 -24
  4. data/Rakefile +2 -3
  5. data/app/controllers/short_message/messages_controller.rb +35 -20
  6. data/app/mailers/short_message/application_mailer.rb +6 -0
  7. data/app/mailers/short_message/mailer.rb +17 -3
  8. data/app/models/short_message/application_record.rb +5 -0
  9. data/app/models/short_message/message.rb +154 -44
  10. data/config/routes.rb +1 -2
  11. data/db/migrate/20130308133457_create_short_message_messages.rb +1 -1
  12. data/db/migrate/20260608090000_add_delivery_metadata_to_short_message_messages.rb +14 -0
  13. data/lib/generators/short_message/templates/config/initializers/short_message.rb +16 -15
  14. data/lib/short_message/config.rb +14 -28
  15. data/lib/short_message/engine.rb +0 -4
  16. data/lib/short_message/version.rb +1 -1
  17. metadata +44 -91
  18. data/test/dummy/README.rdoc +0 -28
  19. data/test/dummy/Rakefile +0 -6
  20. data/test/dummy/app/assets/javascripts/application.js +0 -13
  21. data/test/dummy/app/assets/stylesheets/application.css +0 -15
  22. data/test/dummy/app/controllers/application_controller.rb +0 -5
  23. data/test/dummy/app/helpers/application_helper.rb +0 -2
  24. data/test/dummy/app/views/layouts/application.html.erb +0 -13
  25. data/test/dummy/bin/bundle +0 -3
  26. data/test/dummy/bin/rails +0 -4
  27. data/test/dummy/bin/rake +0 -4
  28. data/test/dummy/bin/setup +0 -29
  29. data/test/dummy/config/application.rb +0 -26
  30. data/test/dummy/config/boot.rb +0 -5
  31. data/test/dummy/config/database.yml +0 -54
  32. data/test/dummy/config/environment.rb +0 -5
  33. data/test/dummy/config/environments/development.rb +0 -41
  34. data/test/dummy/config/environments/production.rb +0 -79
  35. data/test/dummy/config/environments/test.rb +0 -42
  36. data/test/dummy/config/initializers/assets.rb +0 -11
  37. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  38. data/test/dummy/config/initializers/cookies_serializer.rb +0 -3
  39. data/test/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  40. data/test/dummy/config/initializers/inflections.rb +0 -16
  41. data/test/dummy/config/initializers/mime_types.rb +0 -4
  42. data/test/dummy/config/initializers/session_store.rb +0 -3
  43. data/test/dummy/config/initializers/wrap_parameters.rb +0 -14
  44. data/test/dummy/config/locales/en.yml +0 -23
  45. data/test/dummy/config/routes.rb +0 -4
  46. data/test/dummy/config/secrets.yml +0 -22
  47. data/test/dummy/config.ru +0 -4
  48. data/test/dummy/public/404.html +0 -67
  49. data/test/dummy/public/422.html +0 -67
  50. data/test/dummy/public/500.html +0 -66
  51. data/test/dummy/public/favicon.ico +0 -0
  52. data/test/integration/navigation_test.rb +0 -8
  53. data/test/short_message_test.rb +0 -7
  54. data/test/test_helper.rb +0 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f916f657d8160e670f3557e3419605b40dc214151bfb596de9215be72d531d3
4
- data.tar.gz: 24380097ac98b0c0c45dee6503f14c7e0cedaacf8461f439e4b9ef3ba2cec7d6
3
+ metadata.gz: 84df6eda6507a99c19b2389c62b3d1bfd1f7624a87aed826533c6162ced857a3
4
+ data.tar.gz: 18a283ab3dd2cf9a49eb8170c38d51f0a8dafd4b2105d43f088b4a3aeffd7f60
5
5
  SHA512:
6
- metadata.gz: 271e4a3c1fb3714ca093544ef7c381f854432905bd841384948677a6b0255f0f0ad1bbbcb8eaed0a728a60181a5ab9f4d5c5935e2dfd244013eee48c6723f03d
7
- data.tar.gz: a0dad5f6eebdf7161cd4f08b6cde79b9e40e2f4ba9e2eec09eb9ff40fd662d1675c3c7b507c68092ecbb1def34e8efb2eadf05045f5a481dc7adbdd7417ffbb0
6
+ metadata.gz: a0f5a7a88e8480910af30ff20be783fbbf8abc73fa41dee4dd8a29ddb4346040588d7effd776ea3e699f6ee4ba2be82bccd0b8245a5454a35e22d38c13248834
7
+ data.tar.gz: 321c0fc81da7c2d44b727a9481442ab89ff10ecd3f75b92e120fa1894efe626edf95529e97889c16efc28c2cea9a11b95de9a752db3179293148bf8e37773e45
data/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0 - 2026-06-09
4
+
5
+ ### Breaking Changes
6
+ - Removed legacy GTX v1 user/pass delivery mode.
7
+ - Removed legacy configuration keys: gateway_server, gateway_port, send_file_path, account_functions_path, user, password.
8
+ - Delivery now requires api_key and uses GTX REST API v2 endpoint semantics.
9
+ - Removed legacy customization hook based on build_deliver_params_string.
10
+ - Updated runtime requirements to Ruby 3.2+ and Rails 6.1+.
11
+
12
+ ### Added
13
+ - Delivery metadata persistence fields and indexes:
14
+ - provider_http_status
15
+ - provider_status
16
+ - provider_response_body
17
+ - unique index on message_key
18
+ - Optional callback token validation for status endpoint.
19
+ - Tests for delivery success/failure and callback authorization.
20
+
21
+ ### Changed
22
+ - Improved HTTP/TLS safety defaults and timeout configuration.
23
+ - Development/test DB defaults now use sqlite3 in dummy app.
24
+ - Updated Rails compatibility to support Rails 8 (gemspec constraint raised to `< 9.0`).
25
+ - `error_notification` mailer now renders a clean error summary instead of serializing the raw HTTP response object.
26
+ - `payment_required_notification` mailer now references `api_base_url` instead of the removed `gateway_server` config key.
27
+
28
+ ### Removed
29
+ - Dropped all Rails 4/5 compatibility shims: `skip_filter`, `render text:`, and the `deliver_method` version guard.
30
+ - Removed `require_dependency` usage (removed in Rails 7).
31
+ - Removed unused `param_name` metaprogramming from `Configuration`.
32
+ - Raised initial migration version from `[4.2]` to `[6.1]`.
data/README.md CHANGED
@@ -2,74 +2,420 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/short_message.png)](http://badge.fury.io/rb/short_message)
4
4
 
5
+ ShortMessage is a Rails Engine that sends SMS messages via the GTX Messaging REST API v2 and receives delivery status callbacks.
6
+
7
+ **Requires:** Ruby >= 3.2, Rails >= 6.1
8
+
9
+ ---
10
+
11
+ ## Table of Contents
12
+
13
+ - [ShortMessage](#shortmessage)
14
+ - [Table of Contents](#table-of-contents)
15
+ - [Installation](#installation)
16
+ - [Configuration](#configuration)
17
+ - [Configuration reference](#configuration-reference)
18
+ - [Usage](#usage)
19
+ - [Message attributes](#message-attributes)
20
+ - [Delivery Reports](#delivery-reports)
21
+ - [Events](#events)
22
+ - [`short_message.delivered`](#short_messagedelivered)
23
+ - [`short_message.status_updated`](#short_messagestatus_updated)
24
+ - [Email Notifications](#email-notifications)
25
+ - [Customization](#customization)
26
+ - [Status code labels](#status-code-labels)
27
+ - [Extending the request payload](#extending-the-request-payload)
28
+ - [Development](#development)
29
+ - [Testing DLR callbacks locally](#testing-dlr-callbacks-locally)
30
+ - [Building \& Releasing](#building--releasing)
31
+ - [Local Development (using in another project)](#local-development-using-in-another-project)
32
+ - [Upgrade Guide (1.x → 2.0)](#upgrade-guide-1x--20)
33
+ - [License](#license)
34
+
35
+ ---
36
+
5
37
  ## Installation
6
38
 
7
- Add it to your Gemfile:
39
+ Add to your Gemfile:
8
40
 
9
41
  ```ruby
10
42
  gem 'short_message'
11
43
  ```
12
44
 
13
- Run the following command to install it:
45
+ Install dependencies:
14
46
 
15
47
  ```console
16
48
  bundle install
17
49
  ```
18
50
 
19
- Run the generator:
51
+ Run the install generator:
20
52
 
21
53
  ```console
22
54
  rails generate short_message:install
23
55
  ```
24
56
 
25
- And run the migrations:
57
+ Copy and run the migrations:
26
58
 
27
59
  ```console
28
- rake db:migrate
60
+ bundle exec rails railties:install:migrations FROM=short_message
61
+ bundle exec rails db:migrate
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Configuration
67
+
68
+ The generator creates `config/initializers/short_message.rb`. Edit it to suit your setup:
69
+
70
+ ```ruby
71
+ ShortMessage.configure do |config|
72
+ # --- Required ---
73
+ config.api_base_url = "https://rest.gtx-messaging.net"
74
+ config.api_key = ENV.fetch("GTX_API_KEY")
75
+ config.response_format = "json" # "json", "xml", or "plain"
76
+
77
+ # --- SMS defaults ---
78
+ config.default_sms_sender = "MyApp" # sender name or number used when none is set on the message
79
+
80
+ # --- Delivery reports (DLR) ---
81
+ config.dlr_mask = 3 # 1 = delivered, 2 = undelivered, 3 = both
82
+ config.callback_token = ENV["SHORT_MESSAGE_CALLBACK_TOKEN"]
83
+ config.dlr_url = "https://example.com/short_message/messages/status?token=#{config.callback_token}"
84
+
85
+ # --- HTTP timeouts ---
86
+ config.open_timeout = 5 # seconds
87
+ config.read_timeout = 30 # seconds
88
+
89
+ # --- Email notifications (optional) ---
90
+ config.default_mail_sender = "sms@example.com"
91
+ config.admin_notification_email = "admin@example.com" # set nil to disable error emails
92
+ config.reload_notification_email = "billing@example.com" # notified on HTTP 402 from GTX
93
+ end
29
94
  ```
30
95
 
96
+ ### Configuration reference
97
+
98
+ | Key | Required | Default | Description |
99
+ | --------------------------- | -------- | ---------------------------------- | -------------------------------------------------- |
100
+ | `api_base_url` | yes | `"https://rest.gtx-messaging.net"` | GTX API endpoint |
101
+ | `api_key` | yes | — | GTX API authentication key |
102
+ | `response_format` | no | `"json"` | `"json"`, `"xml"`, or `"plain"` |
103
+ | `default_sms_sender` | no | — | Fallback sender when none is set on the message |
104
+ | `dlr_mask` | no | `3` | Delivery report event mask |
105
+ | `dlr_url` | no | — | Callback URL GTX posts status updates to |
106
+ | `callback_token` | no | — | Token validated on incoming status callbacks |
107
+ | `open_timeout` | no | `5` | HTTP connection open timeout (seconds) |
108
+ | `read_timeout` | no | `30` | HTTP read timeout (seconds) |
109
+ | `default_mail_sender` | no | — | From address for notification emails |
110
+ | `admin_notification_email` | no | — | Receives error notifications; set `nil` to disable |
111
+ | `reload_notification_email` | no | — | Receives payment-required (HTTP 402) alerts |
112
+
113
+ ---
114
+
31
115
  ## Usage
32
116
 
33
- Create a message and deliver it:
117
+ Create a `ShortMessage::Message` and call `deliver`:
34
118
 
35
119
  ```ruby
36
- @sms = ShortMessage::Message.new(sender: "0041791234567", recipient: "0041799876543", text: "Hello World!")
37
- @sms.deliver
120
+ sms = ShortMessage::Message.new(
121
+ sender: "+41791234567", # or a name up to 11 chars
122
+ recipient: "+41799876543",
123
+ text: "Hello World!"
124
+ )
125
+
126
+ sms.deliver # => true on success, false on failure
127
+ ```
128
+
129
+ `sender` is optional when `config.default_sms_sender` is configured.
130
+
131
+ Recipient normalization: if `recipient` starts with `00`, the gem automatically converts it to `+` format (for example `0041791234567` -> `+41791234567`). Any other non-E.164 recipient format is rejected before sending.
132
+
133
+ After a successful delivery, `sms.message_key` holds the provider-assigned message ID and `sms.provider_http_status` holds the HTTP status code returned by GTX.
134
+
135
+ ### Message attributes
136
+
137
+ | Attribute | Description |
138
+ | ------------------------ | ----------------------------------------------- |
139
+ | `sender` | SMS sender name or number |
140
+ | `recipient` | SMS recipient phone number in E.164 (`+...`) |
141
+ | `text` | Message body |
142
+ | `message_key` | Unique ID assigned by GTX after delivery |
143
+ | `status_code` | Delivery status code (updated via DLR callback) |
144
+ | `provider_http_status` | HTTP status from GTX at delivery time |
145
+ | `provider_status` | Status string from GTX response |
146
+ | `provider_response_body` | Full raw response payload from GTX |
147
+ | `error_code` | Error code if delivery failed |
148
+ | `error_message` | Error description if delivery failed |
149
+ | `submitted_at` | Timestamp when message was submitted to GTX |
150
+ | `delivered_at` | Timestamp when delivery confirmed |
151
+
152
+ ---
153
+
154
+ ## Delivery Reports
155
+
156
+ ShortMessage mounts a status-update endpoint at `/short_message/messages/status`. Configure GTX to POST (or GET) to this URL with the message ID and status:
157
+
158
+ ```
159
+ POST /short_message/messages/status?id=<message_key>&status=<code>&token=<callback_token>
38
160
  ```
39
161
 
40
- ## Delivery Report
162
+ | Parameter | Description |
163
+ | --------- | -------------------------------------------- |
164
+ | `id` | The `message_key` of the message to update |
165
+ | `status` | Numeric status code from GTX |
166
+ | `token` | Required when `config.callback_token` is set |
167
+
168
+ **Response codes**
169
+
170
+ | HTTP | Meaning |
171
+ | ---- | ---------------------------------- |
172
+ | 200 | Status updated successfully |
173
+ | 400 | Missing `id` or `status` parameter |
174
+ | 401 | Invalid or missing callback token |
175
+ | 404 | Message not found |
176
+
177
+ When `config.callback_token` is set, every incoming callback must include `token=<value>` or it will be rejected with a 401.
178
+
179
+ ---
41
180
 
42
- ShortMessage listens for status updates on `/short_message/messages/status`. Provide `:id` and `:status` by either `POST` or `GET`.
181
+ ## Events
182
+
183
+ ShortMessage fires `ActiveSupport::Notifications` events so you can react to delivery and status changes without monkey-patching.
184
+
185
+ ### `short_message.delivered`
186
+
187
+ Fired after a message is successfully sent to GTX.
188
+
189
+ ```ruby
190
+ ActiveSupport::Notifications.subscribe('short_message.delivered') do |name, start, finish, id, payload|
191
+ Rails.logger.info "SMS #{payload[:key]} delivered"
192
+ end
193
+ ```
194
+
195
+ Payload keys: `key` (the `message_key` assigned by GTX).
196
+
197
+ ### `short_message.status_updated`
198
+
199
+ Fired when a delivery report callback is received.
200
+
201
+ ```ruby
202
+ ActiveSupport::Notifications.subscribe('short_message.status_updated') do |name, start, finish, id, payload|
203
+ Activity.create(
204
+ message: "Message #{payload[:key]} status → #{payload[:status]}"
205
+ )
206
+ end
207
+ ```
208
+
209
+ Payload keys: `key` (message ID), `status` (new status code).
210
+
211
+ ---
212
+
213
+ ## Email Notifications
214
+
215
+ When `admin_notification_email` is configured, ShortMessage sends an email on delivery failure or unexpected exceptions. Set it to `nil` to disable.
216
+
217
+ When `reload_notification_email` is configured, ShortMessage sends an email when GTX returns HTTP 402 (payment required / credit exhausted).
218
+
219
+ ---
43
220
 
44
221
  ## Customization
45
222
 
46
- ### Status Codes
223
+ ### Status code labels
47
224
 
48
- If you need to customize the status response codes simply edit the internationalization files in config/locales
225
+ Status code descriptions are stored in locale files under `config/locales/`. Add or override keys there to customise the text returned by `message.status_text`.
49
226
 
50
- ### Params
227
+ ```yaml
228
+ # config/locales/short_message.en.yml
229
+ en:
230
+ short_message:
231
+ status:
232
+ code_1: "Delivered to handset"
233
+ code_2: "Delivery failed"
234
+ code_4: "Queued on SMSC"
235
+ code_8: "Delivered to SMSC"
236
+ code_16: "Not delivered to SMSC"
237
+ ```
51
238
 
52
- To override the params string add the code below into `config/initializers/short_message.rb`:
239
+ ```ruby
240
+ sms.status_text # => "Delivered to handset"
241
+ ```
242
+
243
+ ### Extending the request payload
244
+
245
+ Override `build_deliver_params_hash` in an initializer to add or change parameters sent to GTX:
53
246
 
54
247
  ```ruby
55
248
  ShortMessage::Message.module_eval do
56
249
  private
57
- def build_deliver_params_string
58
- # your code here
59
- end
60
250
 
61
- def build_recharge_params_string amount
62
- # your code here
251
+ def build_deliver_params_hash
252
+ super.merge("coding" => 2) # e.g. enable UCS-2 encoding
63
253
  end
64
254
  end
65
255
  ```
66
256
 
67
- ### Events
257
+ ---
68
258
 
69
- ShortMessage sends event notifications on message delivery `short_message.delivered` and on status update `short_message.status_updated`. Add following code to an initializer to listen:
259
+ ## Development
260
+
261
+ Clone the repo and install dependencies:
262
+
263
+ ```console
264
+ git clone https://github.com/asaurer/short_message.git
265
+ cd short_message
266
+ bundle install
267
+ ```
268
+
269
+ Run the test suite (migrations run automatically):
270
+
271
+ ```console
272
+ bundle exec rake test
273
+ ```
274
+
275
+ ### Testing DLR callbacks locally
276
+
277
+ GTX needs a publicly reachable HTTPS URL to deliver status callbacks. Use [ngrok](https://ngrok.com) to expose your local server:
278
+
279
+ ```console
280
+ ngrok http 3000
281
+ ```
282
+
283
+ Then configure the tunnel URL in your initializer:
70
284
 
71
285
  ```ruby
72
- ActiveSupport::Notifications.subscribe('short_message.status_updated') do |name, start, finish, id, payload|
73
- Activity.create(successful: true, message: "Message #{payload[:options][:key]} has now status #{payload[:options][:status]}.")
74
- end
286
+ config.callback_token = "dev-secret"
287
+ config.dlr_url = "https://abc123.ngrok.io/short_message/messages/status?token=dev-secret"
288
+ ```
289
+
290
+ Restart your Rails server after changing the initializer. Once a message is delivered, GTX will POST the status update to the ngrok URL which forwards it to your local app.
291
+
292
+ You can also simulate a callback manually without ngrok:
293
+
294
+ ```console
295
+ curl -X POST "http://localhost:3000/short_message/messages/status" \
296
+ -d "id=YOUR_MESSAGE_KEY&status=1&token=dev-secret"
297
+ ```
298
+
299
+ Replace `YOUR_MESSAGE_KEY` with the value of `sms.message_key` after calling `sms.deliver`.
300
+
301
+ ---
302
+
303
+ ## Building & Releasing
304
+
305
+ Build the gem locally:
306
+
307
+ ```console
308
+ gem build short_message.gemspec
309
+ ```
310
+
311
+ This creates `short_message-<version>.gem` in the project root.
312
+
313
+ Install the built gem locally to verify it works:
314
+
315
+ ```console
316
+ gem install short_message-<version>.gem
317
+ ```
318
+
319
+ Push to RubyGems:
320
+
321
+ ```console
322
+ gem push short_message-<version>.gem
323
+ ```
324
+
325
+ You need a [RubyGems account](https://rubygems.org) with push access to the `short_message` gem. Credentials are stored in `~/.gem/credentials`.
326
+
327
+ **Release checklist:**
328
+
329
+ 1. Update `lib/short_message/version.rb` with the new version number
330
+ 2. Update `CHANGELOG.md` with the release notes
331
+ 3. Commit the version bump and changelog
332
+ 4. Build and push the gem
333
+ 5. Tag the release: `git tag v<version> && git push origin v<version>`
334
+
335
+ ---
336
+
337
+ ## Local Development (using in another project)
338
+
339
+ When you want to work on `short_message` and test changes inside a host Rails app simultaneously, point the host app's Gemfile at your local checkout instead of RubyGems:
340
+
341
+ ```ruby
342
+ # host-app/Gemfile
343
+ gem 'short_message', path: '/path/to/short_message'
344
+ ```
345
+
346
+ Then in the host app:
347
+
348
+ ```console
349
+ bundle install
350
+ ```
351
+
352
+ Bundler symlinks the gem from the local path, so every change you make in the `short_message` directory is picked up immediately on the next request (or `reload!` in the console) without re-running `bundle install`.
353
+
354
+ If the gem has pending migrations that need to land in the host app's database:
355
+
356
+ ```console
357
+ bundle exec rails railties:install:migrations FROM=short_message
358
+ bundle exec rails db:migrate
359
+ ```
360
+
361
+ To re-generate the initializer or locales after making changes to the generator templates:
362
+
363
+ ```console
364
+ bundle exec rails generate short_message:install
75
365
  ```
366
+
367
+ When you are done and want to switch back to the published gem, restore the Gemfile entry:
368
+
369
+ ```ruby
370
+ gem 'short_message', '~> 2.0'
371
+ ```
372
+
373
+ ---
374
+
375
+ ## Upgrade Guide (1.x → 2.0)
376
+
377
+ 1. Replace old GTX config keys with `api_base_url`, `api_key`, and `response_format`.
378
+ 2. Remove any initializer override of `build_deliver_params_string` (renamed to `build_deliver_params_hash`).
379
+ 3. Install and run the new migration:
380
+
381
+ ```console
382
+ bundle exec rails railties:install:migrations FROM=short_message
383
+ bundle exec rails db:migrate
384
+ ```
385
+
386
+ If the `short_message_messages` table already
387
+ exists you will see `Mysql2::Error: Table 'short_message_messages' already exists`.
388
+ This happens because `railties:install:migrations` re-copies the original
389
+ create migration under a new timestamp. Mark it as already applied, then migrate:
390
+
391
+ ```bash
392
+ bundle exec rails runner \
393
+ "ActiveRecord::Base.connection.execute(
394
+ \"INSERT IGNORE INTO schema_migrations (version) \" \
395
+ \"VALUES ('$(ls db/migrate/*create_short_message_messages.short_message.rb \
396
+ | grep -oP '[0-9]+(?=_)')' )\")"
397
+ bundle exec rails db:migrate
398
+ ```
399
+
400
+ SQLite users: replace `INSERT IGNORE` with `INSERT OR IGNORE`.
401
+
402
+ 4. Optionally refresh the initializer and locales:
403
+
404
+ ```console
405
+ bundle exec rails generate short_message:install
406
+ ```
407
+
408
+ 5. Configure delivery reports — set `config.dlr_url` to your callback endpoint and `config.callback_token` for request validation:
409
+
410
+ ```ruby
411
+ config.callback_token = ENV["SHORT_MESSAGE_CALLBACK_TOKEN"]
412
+ config.dlr_url = "https://your-app.example/short_message/messages/status?token=#{config.callback_token}"
413
+ ```
414
+
415
+ In the GTX portal, ensure delivery report callbacks are enabled for your API key and that your app's callback URL is publicly reachable over HTTPS.
416
+
417
+ ---
418
+
419
+ ## License
420
+
421
+ MIT — see [MIT-LICENSE](MIT-LICENSE).
data/Rakefile CHANGED
@@ -18,9 +18,6 @@ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
18
  load 'rails/tasks/engine.rake'
19
19
 
20
20
 
21
- load 'rails/tasks/statistics.rake'
22
-
23
-
24
21
 
25
22
  Bundler::GemHelper.install_tasks
26
23
 
@@ -33,5 +30,7 @@ Rake::TestTask.new(:test) do |t|
33
30
  t.verbose = false
34
31
  end
35
32
 
33
+ Rake::Task[:test].enhance(["app:db:migrate"])
34
+
36
35
 
37
36
  task default: :test
@@ -1,29 +1,44 @@
1
- require_dependency "short_message/application_controller"
2
-
3
1
  module ShortMessage
4
2
  class MessagesController < ApplicationController
3
+ skip_before_action :verify_authenticity_token, only: :status
4
+
5
5
  def status
6
- unless params[:id].blank? or params[:status].blank?
7
- if message = ShortMessage::Message.where(message_key: params[:id]).first
8
- message.status_code = params[:status]
9
- message.save!
10
-
11
- ActiveSupport::Notifications.instrument('short_message.status_updated', options: { key: params[:id], status: params[:status] })
12
- message = "Message #{params[:id]} has now status #{params[:status]}"
13
- else
14
- message = "Message #{params[:id]} not found!"
15
- status = 404
16
- end
17
- else
18
- message = "Message ID or status not provided!"
19
- status = 400
6
+ if callback_token_invalid?
7
+ return render plain: "Unauthorized", status: :unauthorized
20
8
  end
21
9
 
22
- if Rails.version[0].to_i > 4
23
- render plain: message, status: status
24
- else
25
- render text: message, status: status
10
+ message_id = params[:id] || params[:"message-id"]
11
+ dlr_mask = params[:"dlr-mask"]
12
+ error_code = params[:"error-code"]
13
+
14
+ return render plain: "OK", status: :ok if message_id.blank?
15
+
16
+ record = ShortMessage::Message.find_by(message_key: message_id)
17
+ return render plain: "OK", status: :ok unless record
18
+
19
+ update_params = {}
20
+ update_params[:status_code] = dlr_mask.to_i if dlr_mask.present?
21
+
22
+ # Only store error fields if error-code is not "0000" (success)
23
+ if error_code.present? && error_code != "0000"
24
+ update_params[:error_code] = error_code
25
+ update_params[:error_message] = params[:"error-message"] if params[:"error-message"].present?
26
26
  end
27
+
28
+ update_params[:submitted_at] = params[:"submit-date"] if params[:"submit-date"].present?
29
+ update_params[:delivered_at] = params[:"done-date"] if params[:"done-date"].present?
30
+
31
+ record.update(update_params)
32
+ render plain: "OK", status: :ok
33
+ end
34
+
35
+ private
36
+
37
+ def callback_token_invalid?
38
+ expected_token = ShortMessage.config.callback_token.to_s
39
+ return false if expected_token.empty?
40
+
41
+ params[:token].to_s != expected_token
27
42
  end
28
43
  end
29
44
  end
@@ -0,0 +1,6 @@
1
+ module ShortMessage
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: -> { ShortMessage.config.default_mail_sender }
4
+ layout false
5
+ end
6
+ end
@@ -1,11 +1,25 @@
1
1
  module ShortMessage
2
2
  class Mailer < ApplicationMailer
3
- def error_notification message, response
4
- mail to: ShortMessage.config.admin_notification_email, subject: "Error delivering SMS to #{message.recipient}", body: "SMS from #{message.sender} to #{message.recipient} could not be sent!\r\n\r\nResponse: #{response.to_yaml}"
3
+ def error_notification(message, response_or_error)
4
+ details = if response_or_error.respond_to?(:code)
5
+ "HTTP #{response_or_error.code}: #{response_or_error.body.to_s.truncate(500)}"
6
+ else
7
+ "#{response_or_error.class}: #{response_or_error.message}"
8
+ end
9
+
10
+ mail(
11
+ to: ShortMessage.config.admin_notification_email,
12
+ subject: "Error delivering SMS to #{message.recipient}",
13
+ body: "SMS from #{message.sender} to #{message.recipient} could not be sent!\r\n\r\nResponse: #{details}"
14
+ )
5
15
  end
6
16
 
7
17
  def payment_required_notification
8
- mail to: ShortMessage.config.reload_notification_email, subject: "SMS Gateway requires payment", body: "Your SMS Gateway API #{ShortMessage.config.gateway_server} requires payment!"
18
+ mail(
19
+ to: ShortMessage.config.reload_notification_email,
20
+ subject: "SMS Gateway requires payment",
21
+ body: "Your SMS Gateway API (#{ShortMessage.config.api_base_url}) requires payment!"
22
+ )
9
23
  end
10
24
  end
11
25
  end
@@ -0,0 +1,5 @@
1
+ module ShortMessage
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end