didww-v3 5.1.0 → 5.3.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/README.md +94 -7
  4. data/examples/README.md +86 -0
  5. data/examples/balance.rb +17 -0
  6. data/examples/capacity_pools.rb +35 -0
  7. data/examples/countries.rb +34 -0
  8. data/examples/did_groups.rb +45 -0
  9. data/examples/did_reservations.rb +55 -0
  10. data/examples/did_trunk_assignment.rb +107 -0
  11. data/examples/dids.rb +62 -0
  12. data/examples/exports.rb +44 -0
  13. data/examples/identities_and_proofs.rb +62 -0
  14. data/examples/orders.rb +60 -0
  15. data/examples/orders_all_item_types.rb +153 -0
  16. data/examples/orders_available_dids.rb +63 -0
  17. data/examples/orders_by_sku.rb +53 -0
  18. data/examples/orders_capacity.rb +44 -0
  19. data/examples/orders_nanpa.rb +44 -0
  20. data/examples/orders_reservation_dids.rb +71 -0
  21. data/examples/regions.rb +45 -0
  22. data/examples/shared_capacity_groups.rb +51 -0
  23. data/examples/voice_in_trunk_groups.rb +51 -0
  24. data/examples/voice_in_trunks.rb +43 -0
  25. data/examples/voice_out_trunks.rb +68 -0
  26. data/lib/didww/base_middleware.rb +12 -6
  27. data/lib/didww/callback/request_validator.rb +5 -12
  28. data/lib/didww/client.rb +40 -115
  29. data/lib/didww/jsonapi_middleware.rb +5 -14
  30. data/lib/didww/resource/address.rb +2 -2
  31. data/lib/didww/resource/address_verification.rb +17 -14
  32. data/lib/didww/resource/concerns/has_status_helpers.rb +17 -0
  33. data/lib/didww/resource/did_group.rb +1 -0
  34. data/lib/didww/resource/encrypted_file.rb +2 -2
  35. data/lib/didww/resource/export.rb +8 -4
  36. data/lib/didww/resource/identity.rb +7 -2
  37. data/lib/didww/resource/order.rb +5 -11
  38. data/lib/didww/resource/permanent_supporting_document.rb +2 -2
  39. data/lib/didww/resource/proof.rb +5 -5
  40. data/lib/didww/resource/region.rb +4 -0
  41. data/lib/didww/resource/requirement.rb +2 -2
  42. data/lib/didww/resource/supporting_document_template.rb +4 -0
  43. data/lib/didww/version.rb +1 -1
  44. metadata +25 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39b910fbb0b5dc4425cf053fd6cacef936c7c46510f8586d33784cccad18a95e
4
- data.tar.gz: 1dae18d3341a93e2a2b4c74d81e224e0402a8c7020bda0053fb685be5186abb2
3
+ metadata.gz: c780bc13f7f052f1733482ee69b37994b6bd8c9926a498857947faf23865c8d2
4
+ data.tar.gz: 22be4b92ea6dd9616dc2e67b77b51b3305876b51b6fed40cba6ce7abb8d015e5
5
5
  SHA512:
6
- metadata.gz: eba0ac2332cf5f0f4c1f65155c0714d9ce35f0a96227024d2b3a21ab650c44587c789035cfb3dd995d797a08573e821eb1301e00732f91cdb3732175c163177c
7
- data.tar.gz: a1ebd2311fa0b1f190d068a210ccfe583b74e3b6ec83c7ad368f2f2eb69d2bdf7d40b8ad5ddb98ab2828b2061ce20a77a67db2406b9c30e5ed4f417d20454259
6
+ metadata.gz: 0c80b1331067374890afec7505eeff625af09f4c36d6e093585483005091c56db11cfd36a4a6ba62547c3e3a300d9b7acc37d78502c8db45f8a91f6cf86c9b83
7
+ data.tar.gz: 549b86aadb2a060b2ed3ae5f84e4d9f0140c012080087ee84b7feb800137957b0726f39c347a1574ea1109e09e8d39b875b2f416389e8633f4cd008f092ca44a
data/CHANGELOG.md CHANGED
@@ -4,6 +4,47 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [5.3.0]
8
+ ### Added
9
+ - `DIDWW::Client.customize_connection` to allow customizing the Faraday connection (e.g. proxy, timeouts, custom middleware).
10
+
11
+ ## [5.2.0]
12
+ ### Changes
13
+ - Extract status predicate methods into `HasStatusHelpers` concern.
14
+ - Merge shared auth header logic into `BaseMiddleware`, `JsonapiMiddleware` inherits and adds `Content-Type`.
15
+ - Replace 29 resource accessor methods with `RESOURCE_CLASSES` hash and `define_method`.
16
+ - Document date and datetime field types in README.
17
+
18
+ ### Fixed
19
+ - Fix date type attributes: use `:time` for ISO 8601 timestamps.
20
+ - Add missing resource fields: `reference`, `permanent`, `iso`, `contact_email`.
21
+ - Add `requirement` relationship to `DidGroup`.
22
+ - Skip `Api-Key` header on `public_keys` endpoint.
23
+ - Add `User-Agent` header to export download.
24
+ - Use timing-safe comparison for callback signature validation.
25
+ - Fix `is_expired` boolean changed to `expires_at` date on `Proof`.
26
+
27
+ ## [5.1.0]
28
+ ### Added
29
+ - `X-DIDWW-API-Version` header sent with requests.
30
+ - Exclusive relationship auto-nullification for DID `voice_in_trunk`/`voice_in_trunk_group`.
31
+ - Export gzip decompression support (`.csv.gz`).
32
+ - `VoiceOutTrunk` CRUD tests and fixtures.
33
+
34
+ ### Changes
35
+ - Rename test fixtures from `sample_N` to self-descriptive names.
36
+
37
+ ## [5.0.0]
38
+ ### Breaking Changes
39
+ - Remove H323 and IAX2 trunk configuration support.
40
+ - Update dependencies and CI for current Ruby/Rails versions.
41
+
42
+ ### Added
43
+ - Add missing relationship declarations and tests for included resources.
44
+
45
+ ### Fixed
46
+ - Fix compatibility with `json_api_client` 1.23.0 and newer Ruby.
47
+
7
48
  ## [4.1.0]
8
49
  ### Breaking Changes
9
50
  - removed DIDWW::Resource::DidGroup::FEATURE_VOICE in favor DIDWW::Resource::DidGroup::FEATURE_VOICE_IN and DIDWW::Resource::DidGroup::FEATURE_VOICE_OUT [#42](https://github.com/didww/didww-v3-ruby/pull/42)
data/README.md CHANGED
@@ -51,17 +51,17 @@ Or install it yourself as:
51
51
  ```ruby
52
52
  require 'didww'
53
53
 
54
- client = DIDWW::Client.configure do |config|
54
+ DIDWW::Client.configure do |config|
55
55
  config.api_key = 'YOUR_API_KEY'
56
56
  config.api_mode = :sandbox
57
57
  end
58
58
 
59
59
  # Check balance
60
- balance = client.balance
60
+ balance = DIDWW::Client.balance
61
61
  puts "Balance: #{balance.total_balance}"
62
62
 
63
63
  # List DID groups with stock keeping units
64
- did_groups = client.did_groups.all(
64
+ did_groups = DIDWW::Client.did_groups.all(
65
65
  include: 'stock_keeping_units',
66
66
  filter: { area_name: 'Acapulco' }
67
67
  )
@@ -69,14 +69,10 @@ did_groups = client.did_groups.all(
69
69
  puts "DID groups: #{did_groups.count}"
70
70
  ```
71
71
 
72
- For more examples visit [examples](examples/).
73
-
74
72
  For details on obtaining your API key please visit https://doc.didww.com/api3/configuration.html
75
73
 
76
74
  ## Examples
77
75
 
78
- - Source code: [examples/](examples/)
79
- - How to run: [examples/README.md](examples/README.md)
80
76
  - Rails integration sample: https://github.com/didww/didww-v3-rails-sample
81
77
 
82
78
  ## Configuration
@@ -104,6 +100,36 @@ end
104
100
  | `:production` | `https://api.didww.com/v3/` |
105
101
  | `:sandbox` | `https://sandbox-api.didww.com/v3/` |
106
102
 
103
+ ### Connection Customization
104
+
105
+ Use `customize_connection` to customize the underlying Faraday connection, for example to configure a proxy or add custom middleware:
106
+
107
+ ```ruby
108
+ # Using a proxy
109
+ DIDWW::Client.configure do |config|
110
+ config.api_key = 'YOUR_API_KEY'
111
+ config.api_mode = :production
112
+ config.customize_connection do |conn|
113
+ # conn is a JsonApiClient::Connection instance
114
+ conn.faraday.proxy = 'http://proxy.example.com:8080'
115
+ end
116
+ end
117
+ ```
118
+
119
+ ```ruby
120
+ # Adding custom middleware and timeouts
121
+ DIDWW::Client.configure do |config|
122
+ config.api_key = 'YOUR_API_KEY'
123
+ config.api_mode = :production
124
+ config.customize_connection do |conn|
125
+ # conn is a JsonApiClient::Connection instance
126
+ conn.use MyCustomMiddleware
127
+ conn.faraday.options.timeout = 30
128
+ conn.faraday.options.open_timeout = 10
129
+ end
130
+ end
131
+ ```
132
+
107
133
  ### API Version
108
134
 
109
135
  The SDK sends `X-DIDWW-API-Version: 2022-05-10` by default. You can override it per block:
@@ -168,6 +194,7 @@ trunk = DIDWW::Client.voice_in_trunks.new(
168
194
  name: 'My SIP Trunk',
169
195
  configuration: {
170
196
  type: 'sip_configurations',
197
+ username: '{DID}',
171
198
  host: 'sip.example.com',
172
199
  port: 5060
173
200
  }
@@ -192,10 +219,70 @@ order = DIDWW::Client.orders.new(
192
219
  order.save
193
220
  ```
194
221
 
222
+ ## Date and Datetime Fields
223
+
224
+ The SDK distinguishes between date-only and datetime fields:
225
+
226
+ - **Datetime fields** — deserialized as `Time`:
227
+ - All `created_at` fields — present on most resources (`EncryptedFile` has no `created_at`)
228
+ - Expiry fields: `Did#expires_at`, `DidReservation#expire_at`, `Proof#expires_at`, `EncryptedFile#expire_at`
229
+ - **Date-only fields** — deserialized as `Date`:
230
+ - `Identity#birth_date`
231
+ - **Date-only fields kept as strings** (`CapacityPool#renew_date`) remain as `String`.
232
+
233
+ ```ruby
234
+ did = DIDWW::Client.dids.find("uuid").first
235
+ puts did.created_at # => 2024-01-15 10:00:00 UTC (Time)
236
+ puts did.expires_at # => nil or 2025-01-15 10:00:00 UTC (Time)
237
+
238
+ identity = DIDWW::Client.identities.find("uuid").first
239
+ puts identity.birth_date # => 1990-05-20 (Date)
240
+ ```
241
+
195
242
  ## Resource Relationships
196
243
 
197
244
  See [docs/resource_relationships.md](docs/resource_relationships.md) for a Mermaid ER diagram showing all `has_one`, `has_many`, and `belongs_to` relationships between resources.
198
245
 
246
+ ## Webhook Signature Validation
247
+
248
+ Validate incoming webhook callbacks from DIDWW using HMAC-SHA1 signature verification.
249
+
250
+ ```ruby
251
+ require 'didww/callback/request_validator'
252
+
253
+ validator = DIDWW::Callback::RequestValidator.new("YOUR_API_KEY")
254
+
255
+ # In your webhook handler:
256
+ valid = validator.validate(
257
+ request_url, # full original URL
258
+ payload_params, # Hash of payload key-value pairs
259
+ signature # value of X-DIDWW-Signature header
260
+ )
261
+ ```
262
+
263
+ The signature header name is available as the constant `DIDWW::Callback::RequestValidator::HEADER`.
264
+
265
+ ### Rails Example
266
+
267
+ ```ruby
268
+ class WebhooksController < ApplicationController
269
+ skip_before_action :verify_authenticity_token
270
+
271
+ def create
272
+ validator = DIDWW::Callback::RequestValidator.new("YOUR_API_KEY")
273
+ signature = request.headers[DIDWW::Callback::RequestValidator::HEADER]
274
+ params_hash = request.POST
275
+
276
+ if validator.validate(request.original_url, params_hash, signature)
277
+ # Process the webhook
278
+ head :ok
279
+ else
280
+ head :forbidden
281
+ end
282
+ end
283
+ end
284
+ ```
285
+
199
286
  ## Development
200
287
 
201
288
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,86 @@
1
+ # Examples
2
+
3
+ All examples read the API key from the `DIDWW_API_KEY` environment variable.
4
+
5
+ ## Prerequisites
6
+
7
+ - Ruby 3.3+
8
+ - Bundler
9
+ - DIDWW API key for sandbox account
10
+
11
+ ## Environment variables
12
+
13
+ - `DIDWW_API_KEY` (required): your DIDWW API key
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ cd examples && bundle install
19
+ ```
20
+
21
+ ## Run an example
22
+
23
+ ```bash
24
+ DIDWW_API_KEY=your_api_key ruby examples/orders_nanpa.rb
25
+ ```
26
+
27
+ ## Available examples
28
+
29
+ ### Core Resources
30
+ | Script | Description |
31
+ |---|---|
32
+ | [`balance.rb`](balance.rb) | Fetches and prints current account balance and credit. |
33
+ | [`countries.rb`](countries.rb) | Lists countries, demonstrates filtering, and fetches one country by ID. |
34
+ | [`regions.rb`](regions.rb) | Lists regions with filters/includes and fetches a specific region. |
35
+ | [`did_groups.rb`](did_groups.rb) | Fetches DID groups with included SKUs and shows group details. |
36
+ | [`dids.rb`](dids.rb) | Updates DID routing/capacity by assigning trunk and capacity pool. |
37
+ | [`exports.rb`](exports.rb) | Lists CDR exports and their details. |
38
+
39
+ ### Voice In (Inbound)
40
+ | Script | Description |
41
+ |---|---|
42
+ | [`voice_in_trunks.rb`](voice_in_trunks.rb) | Lists voice in trunks and their configurations. |
43
+ | [`voice_in_trunk_groups.rb`](voice_in_trunk_groups.rb) | CRUD for trunk groups with trunk relationships. |
44
+
45
+ ### Voice Out (Outbound)
46
+ | Script | Description |
47
+ |---|---|
48
+ | [`voice_out_trunks.rb`](voice_out_trunks.rb) | CRUD for voice out trunks (requires account config). |
49
+
50
+ ### Capacity Management
51
+ | Script | Description |
52
+ |---|---|
53
+ | [`capacity_pools.rb`](capacity_pools.rb) | Lists capacity pools with included shared capacity groups. |
54
+ | [`shared_capacity_groups.rb`](shared_capacity_groups.rb) | Creates a shared capacity group in a capacity pool. |
55
+
56
+ ### Orders - Basic
57
+ | Script | Description |
58
+ |---|---|
59
+ | [`orders.rb`](orders.rb) | Lists orders and creates/cancels a DID order using live SKU lookup. |
60
+ | [`orders_nanpa.rb`](orders_nanpa.rb) | Orders a DID number by NPA/NXX prefix. |
61
+ | [`orders_by_sku.rb`](orders_by_sku.rb) | Creates a DID order by SKU resolved from DID groups. |
62
+ | [`orders_capacity.rb`](orders_capacity.rb) | Purchases capacity by creating a capacity order item. |
63
+
64
+ ### Orders - Advanced
65
+ | Script | Description |
66
+ |---|---|
67
+ | [`orders_available_dids.rb`](orders_available_dids.rb) | Orders an available DID using included DID group SKU. |
68
+ | [`orders_reservation_dids.rb`](orders_reservation_dids.rb) | Reserves a DID and then places an order from that reservation. |
69
+ | [`orders_all_item_types.rb`](orders_all_item_types.rb) | Creates a DID order with all item types: by SKU, available DID, and reservation. |
70
+
71
+ ### DID Management
72
+ | Script | Description |
73
+ |---|---|
74
+ | [`did_reservations.rb`](did_reservations.rb) | Lists DID reservations and available DIDs. |
75
+ | [`did_trunk_assignment.rb`](did_trunk_assignment.rb) | Demonstrates exclusive trunk/trunk group assignment on DIDs. |
76
+
77
+ ### Compliance & Verification
78
+ | Script | Description |
79
+ |---|---|
80
+ | [`identities_and_proofs.rb`](identities_and_proofs.rb) | Creates identities, addresses, and demonstrates proof workflow. |
81
+
82
+ ## Troubleshooting
83
+
84
+ If `DIDWW_API_KEY` is missing, examples fail fast with:
85
+
86
+ `Please set DIDWW_API_KEY`
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ # Fetches and prints current account balance and credit.
3
+ #
4
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/balance.rb
5
+
6
+ require 'bundler/setup'
7
+ require 'didww'
8
+
9
+ DIDWW::Client.configure do |client|
10
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
11
+ client.api_mode = :sandbox
12
+ end
13
+
14
+ balance = DIDWW::Client.balance
15
+ puts "Total Balance: #{balance.total_balance}"
16
+ puts "Balance: #{balance.balance}"
17
+ puts "Credit: #{balance.credit}"
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ # Lists capacity pools with included shared capacity groups.
3
+ #
4
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/capacity_pools.rb
5
+
6
+ require 'bundler/setup'
7
+ require 'didww'
8
+
9
+ DIDWW::Client.configure do |client|
10
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
11
+ client.api_mode = :sandbox
12
+ end
13
+
14
+ # List capacity pools with included shared capacity groups
15
+ puts '=== Capacity Pools ==='
16
+ capacity_pools = DIDWW::Client.capacity_pools
17
+ .includes(:shared_capacity_groups)
18
+ .all
19
+
20
+ puts "Found #{capacity_pools.size} capacity pools"
21
+
22
+ capacity_pools.each do |pool|
23
+ puts "\nCapacity Pool: #{pool.name}"
24
+ puts " Total channels: #{pool.total_channels_count}"
25
+ puts " Assigned channels: #{pool.assigned_channels_count}"
26
+ puts " Monthly price: #{pool.monthly_price}"
27
+ puts " Metered rate: #{pool.metered_rate}"
28
+
29
+ if pool.shared_capacity_groups && !pool.shared_capacity_groups.empty?
30
+ puts ' Shared Capacity Groups:'
31
+ pool.shared_capacity_groups.each do |group|
32
+ puts " - #{group.name} (#{group.shared_channels_count} channels)"
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ # Lists countries, demonstrates filtering, and fetches one country by ID.
3
+ #
4
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/countries.rb
5
+
6
+ require 'bundler/setup'
7
+ require 'didww'
8
+
9
+ DIDWW::Client.configure do |client|
10
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
11
+ client.api_mode = :sandbox
12
+ end
13
+
14
+ # List all countries
15
+ puts '=== All Countries ==='
16
+ countries = DIDWW::Client.countries.all
17
+ countries.first(5).each do |country|
18
+ puts "#{country.name} (+#{country.prefix}) [#{country.iso}]"
19
+ end
20
+
21
+ # Filter countries by name
22
+ puts "\n=== Filtered Countries (United States) ==="
23
+ filtered = DIDWW::Client.countries.where(name: 'United States').all
24
+ puts "Found: #{filtered.size} countries"
25
+ filtered.each do |country|
26
+ puts "#{country.name} (+#{country.prefix})"
27
+ end
28
+
29
+ # Find a specific country
30
+ if !filtered.empty?
31
+ puts "\n=== Specific Country ==="
32
+ country = DIDWW::Client.countries.find(filtered.first.id).first
33
+ puts "Found: #{country.name}"
34
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+ # Fetches DID groups with included SKUs and shows group details.
3
+ #
4
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/did_groups.rb
5
+
6
+ require 'bundler/setup'
7
+ require 'didww'
8
+
9
+ DIDWW::Client.configure do |client|
10
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
11
+ client.api_mode = :sandbox
12
+ end
13
+
14
+ # Fetch DID groups with included stock_keeping_units
15
+ puts '=== DID Groups with SKUs ==='
16
+ did_groups = DIDWW::Client.did_groups
17
+ .includes(:stock_keeping_units)
18
+ .all
19
+
20
+ puts "Found #{did_groups.size} DID groups"
21
+
22
+ did_groups.first(3).each do |did_group|
23
+ puts "\nDID Group: #{did_group.id}"
24
+ puts " Area: #{did_group.area_name}"
25
+ puts " Prefix: #{did_group.prefix}"
26
+ puts " Metered: #{did_group.is_metered}"
27
+ puts " Features: #{did_group.features_human}"
28
+
29
+ if did_group.stock_keeping_units && !did_group.stock_keeping_units.empty?
30
+ puts ' SKUs:'
31
+ did_group.stock_keeping_units.each do |sku|
32
+ puts " - #{sku.id} (monthly: #{sku.monthly_price})"
33
+ end
34
+ end
35
+ end
36
+
37
+ # Find a specific DID group
38
+ if !did_groups.empty?
39
+ puts "\n=== Specific DID Group ==="
40
+ did_group = DIDWW::Client.did_groups
41
+ .includes(:stock_keeping_units)
42
+ .find(did_groups.first.id)
43
+ .first
44
+ puts "Found: #{did_group.area_name} (prefix: #{did_group.prefix})"
45
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ # Lists DID reservations and available DIDs.
3
+ #
4
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/did_reservations.rb
5
+
6
+ require 'bundler/setup'
7
+ require 'didww'
8
+
9
+ DIDWW::Client.configure do |client|
10
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
11
+ client.api_mode = :sandbox
12
+ end
13
+
14
+ # List DID reservations
15
+ puts '=== Existing DID Reservations ==='
16
+ reservations = DIDWW::Client.did_reservations
17
+ .includes(:available_did)
18
+ .all
19
+
20
+ puts "Found #{reservations.size} DID reservations"
21
+ reservations.first(10).each do |reservation|
22
+ did_number = reservation.available_did ? reservation.available_did.number : 'unknown'
23
+ puts "#{reservation.id}"
24
+ puts " DID: #{did_number}"
25
+ puts " Expires: #{reservation.expire_at}"
26
+ puts " Created: #{reservation.created_at}"
27
+ puts ''
28
+ end
29
+
30
+ # List available DIDs
31
+ puts "\n=== Available DIDs ==="
32
+ available_dids = DIDWW::Client.available_dids
33
+ .includes(:did_group)
34
+ .all
35
+
36
+ puts "Found #{available_dids.size} available DIDs"
37
+ available_dids.first(10).each do |available_did|
38
+ puts "#{available_did.number}"
39
+ if available_did.did_group
40
+ puts " Group: #{available_did.did_group.area_name}"
41
+ puts " Prefix: #{available_did.did_group.prefix}"
42
+ end
43
+ puts ''
44
+ end
45
+
46
+ # Find a specific reservation if available
47
+ if !reservations.empty?
48
+ puts "\n=== Specific Reservation Details ==="
49
+ specific_reservation = DIDWW::Client.did_reservations
50
+ .find(reservations.first.id)
51
+ .first
52
+ puts "Reservation: #{specific_reservation.id}"
53
+ puts " Expires at: #{specific_reservation.expire_at}"
54
+ puts " Created at: #{specific_reservation.created_at}"
55
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+ # Demonstrates exclusive trunk/trunk group assignment on DIDs.
3
+ # Assigning a trunk auto-nullifies the trunk group and vice versa.
4
+ #
5
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/did_trunk_assignment.rb
6
+
7
+ require 'bundler/setup'
8
+ require 'didww'
9
+
10
+ DIDWW::Client.configure do |client|
11
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
12
+ client.api_mode = :sandbox
13
+ end
14
+
15
+ # Get a DID to work with
16
+ puts '=== Finding DID ==='
17
+ dids = DIDWW::Client.dids
18
+ .includes(:voice_in_trunk, :voice_in_trunk_group)
19
+ .all
20
+
21
+ if dids.empty?
22
+ puts 'No DIDs found. Please order a DID first.'
23
+ exit 1
24
+ end
25
+
26
+ did = dids.first
27
+ puts "Using DID: #{did.number} (#{did.id})"
28
+
29
+ # Get a trunk
30
+ puts "\n=== Finding Trunk ==="
31
+ trunks = DIDWW::Client.voice_in_trunks.all
32
+
33
+ if trunks.empty?
34
+ puts 'No trunks found. Please create a trunk first.'
35
+ exit 1
36
+ end
37
+
38
+ trunk = trunks.first
39
+ puts "Selected trunk: #{trunk.name} (#{trunk.id})"
40
+
41
+ # Get a trunk group
42
+ puts "\n=== Finding Trunk Group ==="
43
+ trunk_groups = DIDWW::Client.voice_in_trunk_groups.all
44
+
45
+ if trunk_groups.empty?
46
+ puts 'No trunk groups found. Please create a trunk group first.'
47
+ exit 1
48
+ end
49
+
50
+ trunk_group = trunk_groups.first
51
+ puts "Selected trunk group: #{trunk_group.name} (#{trunk_group.id})"
52
+
53
+ def print_did_assignment(client, did_id)
54
+ result = client.dids
55
+ .includes(:voice_in_trunk, :voice_in_trunk_group)
56
+ .find(did_id)
57
+ .first
58
+ trunk = result.voice_in_trunk ? result.voice_in_trunk.id : 'null'
59
+ group = result.voice_in_trunk_group ? result.voice_in_trunk_group.id : 'null'
60
+ puts " trunk = #{trunk}"
61
+ puts " group = #{group}"
62
+ end
63
+
64
+ begin
65
+ # 1. Assign trunk to DID (auto-nullifies trunk group)
66
+ puts "\n=== 1. Assigning trunk to DID ==="
67
+ did.voice_in_trunk = trunk
68
+ if did.save
69
+ print_did_assignment(DIDWW::Client, did.id)
70
+ else
71
+ puts "Error assigning trunk: #{did.errors.full_messages}"
72
+ end
73
+
74
+ # 2. Assign trunk group to DID (auto-nullifies trunk)
75
+ puts "\n=== 2. Assigning trunk group to DID ==="
76
+ did_fresh = DIDWW::Client.dids.find(did.id).first
77
+ did_fresh.voice_in_trunk_group = trunk_group
78
+ if did_fresh.save
79
+ print_did_assignment(DIDWW::Client, did.id)
80
+ else
81
+ puts "Error assigning trunk group: #{did_fresh.errors.full_messages}"
82
+ end
83
+
84
+ # 3. Re-assign trunk (auto-nullifies trunk group again)
85
+ puts "\n=== 3. Re-assigning trunk ==="
86
+ did_fresh = DIDWW::Client.dids.find(did.id).first
87
+ did_fresh.voice_in_trunk = trunk
88
+ if did_fresh.save
89
+ print_did_assignment(DIDWW::Client, did.id)
90
+ else
91
+ puts "Error re-assigning trunk: #{did_fresh.errors.full_messages}"
92
+ end
93
+
94
+ # 4. Update description only (trunk stays assigned)
95
+ puts "\n=== 4. Updating description only (trunk stays) ==="
96
+ did_fresh = DIDWW::Client.dids.find(did.id).first
97
+ did_fresh.description = 'DID with trunk assigned'
98
+ if did_fresh.save
99
+ print_did_assignment(DIDWW::Client, did.id)
100
+ else
101
+ puts "Error updating description: #{did_fresh.errors.full_messages}"
102
+ end
103
+
104
+ puts "\nDemonstration complete!"
105
+ rescue StandardError => e
106
+ puts "Error: #{e.message}"
107
+ end
data/examples/dids.rb ADDED
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+ # Updates DID routing/capacity by assigning trunk and capacity pool.
3
+ #
4
+ # Usage: DIDWW_API_KEY=your_api_key ruby examples/dids.rb
5
+
6
+ require 'bundler/setup'
7
+ require 'didww'
8
+
9
+ DIDWW::Client.configure do |client|
10
+ client.api_key = ENV.fetch('DIDWW_API_KEY') { abort 'Please set DIDWW_API_KEY' }
11
+ client.api_mode = :sandbox
12
+ end
13
+
14
+ # Get the last ordered DID
15
+ puts '=== Finding last ordered DID ==='
16
+ dids = DIDWW::Client.dids
17
+ .all
18
+
19
+ if dids.empty?
20
+ puts 'No DIDs found. Please order a DID first.'
21
+ exit 1
22
+ end
23
+
24
+ did = dids.first
25
+ puts "Selected DID: #{did.id}"
26
+
27
+ # Get last SIP trunk
28
+ puts "\n=== Finding SIP trunk ==="
29
+ trunks = DIDWW::Client.voice_in_trunks
30
+ .where('configuration.type': 'sip_configurations')
31
+ .all
32
+
33
+ if trunks.empty?
34
+ puts 'No SIP trunks found. Please create a SIP trunk first.'
35
+ exit 1
36
+ end
37
+
38
+ trunk = trunks.first
39
+ puts "Selected trunk: #{trunk.name}"
40
+
41
+ # Assign trunk to DID
42
+ puts "\n=== Assigning trunk to DID ==="
43
+ did.voice_in_trunk = trunk
44
+ updated_did = did.save
45
+ puts "Assigned trunk: #{did.voice_in_trunk.name if did.voice_in_trunk}"
46
+
47
+ # Assign capacity pool
48
+ puts "\n=== Assigning capacity pool ==="
49
+ capacity_pools = DIDWW::Client.capacity_pools.all
50
+
51
+ if !capacity_pools.empty?
52
+ pool = capacity_pools.first
53
+ did.capacity_pool = pool
54
+ did.capacity_limit = 5
55
+ did.description = 'Updated by Ruby example'
56
+ did.save
57
+ puts "DID #{did.id}"
58
+ puts " description: #{did.description}"
59
+ puts " capacity_limit: #{did.capacity_limit}"
60
+ else
61
+ puts 'No capacity pools found'
62
+ end