gandi_v5 0.1.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +14 -4
  4. data/.travis.yml +16 -1
  5. data/CHANGELOG.md +80 -2
  6. data/FUNDING.yml +10 -0
  7. data/Guardfile +5 -6
  8. data/LICENSE.md +2 -6
  9. data/README.md +17 -23
  10. data/gandi_v5.gemspec +4 -3
  11. data/lib/gandi_v5.rb +54 -15
  12. data/lib/gandi_v5/billing.rb +2 -4
  13. data/lib/gandi_v5/billing/info.rb +0 -2
  14. data/lib/gandi_v5/data.rb +1 -2
  15. data/lib/gandi_v5/data/converter.rb +0 -4
  16. data/lib/gandi_v5/data/converter/integer.rb +26 -0
  17. data/lib/gandi_v5/domain.rb +201 -101
  18. data/lib/gandi_v5/domain/auto_renew.rb +4 -4
  19. data/lib/gandi_v5/domain/availability.rb +46 -0
  20. data/lib/gandi_v5/domain/availability/product.rb +49 -0
  21. data/lib/gandi_v5/domain/availability/product/period.rb +24 -0
  22. data/lib/gandi_v5/domain/availability/product/price.rb +36 -0
  23. data/lib/gandi_v5/domain/availability/tax.rb +20 -0
  24. data/lib/gandi_v5/domain/live_dns.rb +42 -0
  25. data/lib/gandi_v5/domain/renewal_information.rb +0 -3
  26. data/lib/gandi_v5/domain/sharing_space.rb +10 -2
  27. data/lib/gandi_v5/domain/tld.rb +57 -0
  28. data/lib/gandi_v5/email.rb +0 -4
  29. data/lib/gandi_v5/email/forward.rb +108 -0
  30. data/lib/gandi_v5/email/mailbox.rb +85 -24
  31. data/lib/gandi_v5/email/mailbox/responder.rb +43 -2
  32. data/lib/gandi_v5/email/offer.rb +2 -2
  33. data/lib/gandi_v5/email/slot.rb +52 -18
  34. data/lib/gandi_v5/error.rb +0 -2
  35. data/lib/gandi_v5/error/gandi_error.rb +2 -2
  36. data/lib/gandi_v5/live_dns.rb +20 -4
  37. data/lib/gandi_v5/live_dns/domain.rb +21 -150
  38. data/lib/gandi_v5/live_dns/has_zone_records.rb +153 -0
  39. data/lib/gandi_v5/live_dns/record_set.rb +1 -1
  40. data/lib/gandi_v5/live_dns/zone.rb +24 -165
  41. data/lib/gandi_v5/live_dns/zone/snapshot.rb +27 -8
  42. data/lib/gandi_v5/organization.rb +39 -6
  43. data/lib/gandi_v5/organization/customer.rb +90 -0
  44. data/lib/gandi_v5/version.rb +1 -1
  45. data/spec/.rubocop.yml +9 -2
  46. data/spec/features/domain_spec.rb +2 -2
  47. data/spec/features/livedns_zone_spec.rb +12 -13
  48. data/spec/fixtures/bodies/GandiV5_Billing/{info.yaml → info.yml} +0 -0
  49. data/spec/fixtures/bodies/GandiV5_Domain/{get.yaml → fetch.yml} +8 -0
  50. data/spec/fixtures/bodies/GandiV5_Domain/{fetch_contacts.yaml → fetch_contacts.yml} +0 -0
  51. data/spec/fixtures/bodies/GandiV5_Domain/fetch_glue_records.yml +7 -0
  52. data/spec/fixtures/bodies/GandiV5_Domain/fetch_livedns.yml +6 -0
  53. data/spec/fixtures/bodies/GandiV5_Domain/fetch_name_servers.yml +2 -0
  54. data/spec/fixtures/bodies/GandiV5_Domain/{renewal_info.yaml → fetch_renewal_info.yml} +0 -3
  55. data/spec/fixtures/bodies/GandiV5_Domain/{restore_info.yaml → fetch_restore_info.yml} +0 -0
  56. data/spec/fixtures/bodies/GandiV5_Domain/{list.yaml → list.yml} +1 -0
  57. data/spec/fixtures/bodies/{GandiV5_Domain/availability.yaml → GandiV5_Domain_Availability/fetch.yml} +0 -0
  58. data/spec/fixtures/bodies/{GandiV5_Domain/tld.yaml → GandiV5_Domain_TLD/fetch.yml} +0 -0
  59. data/spec/fixtures/bodies/{GandiV5_Domain/tlds.yaml → GandiV5_Domain_TLD/list.yml} +0 -0
  60. data/spec/fixtures/bodies/GandiV5_Email_Forward/list.yml +6 -0
  61. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/{get.yaml → fetch.yml} +0 -0
  62. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/{list.yaml → list.yml} +0 -0
  63. data/spec/fixtures/bodies/GandiV5_Email_Slot/{get.yaml → fetch.yml} +0 -0
  64. data/spec/fixtures/bodies/GandiV5_Email_Slot/{list.yaml → list.yml} +0 -0
  65. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/{get.yaml → fetch.yml} +0 -0
  66. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/{list.yaml → list.yml} +0 -0
  67. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/{get.yaml → fetch.yml} +0 -0
  68. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/{list.yaml → list.yml} +0 -0
  69. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/{get.yaml → fetch.yml} +0 -0
  70. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yml +3 -0
  71. data/spec/fixtures/bodies/GandiV5_Organization/{get.yaml → fetch.yml} +0 -0
  72. data/spec/fixtures/bodies/GandiV5_Organization/list.yml +7 -0
  73. data/spec/fixtures/bodies/GandiV5_Organization_Customer/list.yml +8 -0
  74. data/spec/fixtures/vcr/Domain_features/List_domains.yml +2 -1
  75. data/spec/spec_helper.rb +2 -2
  76. data/spec/units/gandi_v5/billing_spec.rb +4 -4
  77. data/spec/units/gandi_v5/data/converter/integer_spec.rb +16 -0
  78. data/spec/units/gandi_v5/domain/auto_renew_spec.rb +5 -5
  79. data/spec/units/gandi_v5/domain/availability/product/period_spec.rb +4 -0
  80. data/spec/units/gandi_v5/domain/availability/product/price_spec.rb +4 -0
  81. data/spec/units/gandi_v5/domain/availability/product_spec.rb +4 -0
  82. data/spec/units/gandi_v5/domain/availability/tax_spec.rb +4 -0
  83. data/spec/units/gandi_v5/domain/availability_spec.rb +43 -0
  84. data/spec/units/gandi_v5/domain/live_dns_spec.rb +45 -0
  85. data/spec/units/gandi_v5/domain/tld_spec.rb +29 -0
  86. data/spec/units/gandi_v5/domain_spec.rb +359 -91
  87. data/spec/units/gandi_v5/email/forward_spec.rb +121 -0
  88. data/spec/units/gandi_v5/email/mailbox/responder_spec.rb +52 -0
  89. data/spec/units/gandi_v5/email/mailbox_spec.rb +174 -33
  90. data/spec/units/gandi_v5/email/offer_spec.rb +1 -1
  91. data/spec/units/gandi_v5/email/slot_spec.rb +113 -17
  92. data/spec/units/gandi_v5/live_dns/domain_spec.rb +73 -43
  93. data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +32 -3
  94. data/spec/units/gandi_v5/live_dns/zone_spec.rb +70 -52
  95. data/spec/units/gandi_v5/live_dns_spec.rb +24 -0
  96. data/spec/units/gandi_v5/organization/customer_spec.rb +81 -0
  97. data/spec/units/gandi_v5/organization_spec.rb +52 -1
  98. data/spec/units/gandi_v5_spec.rb +56 -19
  99. metadata +71 -29
  100. data/TODO.md +0 -29
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'billing/info'
4
-
5
3
  class GandiV5
6
4
  # Gandi Billing API.
7
5
  # @see https://api.gandi.net/docs/billing
@@ -11,9 +9,9 @@ class GandiV5
11
9
  # @param url [sharing_id] the Sharing ID of the organisation to get info for
12
10
  # defaults to the user the api key belomgs to.
13
11
  # @return [GandiV5::Billing::Info]
14
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
12
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
15
13
  def self.info(sharing_id = nil)
16
- data = GandiV5.get url(sharing_id)
14
+ _response, data = GandiV5.get url(sharing_id)
17
15
  GandiV5::Billing::Info.from_gandi data
18
16
  end
19
17
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'info/prepaid'
4
-
5
3
  class GandiV5
6
4
  class Billing
7
5
  # Account's information.
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'data/converter'
4
-
5
3
  class GandiV5
6
4
  # Addin providing a DSL to manage declaring attributes and how to map
7
5
  # and convert to/from Gandi's fields.
@@ -181,6 +179,7 @@ class GandiV5
181
179
  define_method "#{name}=" do |value|
182
180
  instance_variable_set("@#{name}", value)
183
181
  end
182
+
184
183
  private "#{name}="
185
184
  end
186
185
 
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'converter/array_of'
4
- require_relative 'converter/symbol'
5
- require_relative 'converter/time'
6
-
7
3
  class GandiV5
8
4
  module Data
9
5
  # Namespace for converters to/from Gandi's format.
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ module Data
5
+ class Converter
6
+ # Methods for converting strings to/from integerss.
7
+ class Integer
8
+ # @param value [Integer]
9
+ # @return [String]
10
+ def self.to_gandi(value)
11
+ return nil if value.nil?
12
+
13
+ value.to_s
14
+ end
15
+
16
+ # @param [String]
17
+ # @return value [Integer]
18
+ def self.from_gandi(value)
19
+ return nil if value.nil?
20
+
21
+ value.to_i
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,29 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: Add method renewal_price(currency: 'GBP', period: 1, sharing_id: self.sharing_id)
4
-
5
- # TODO: Glue Record Management
6
- # * get-v5-domain-domains-domain-hosts
7
- # * post-v5-domain-domains-domain-hosts
8
- # TODO: Glue Record Information
9
- # * get-v5-domain-domains-domain-hosts-name
10
- # * put-v5-domain-domains-domain-hosts-name
11
- # * delete-v5-domain-domains-domain-hosts-name
12
- # TODO: LiveDNS Management
13
- # * get-v5-domain-domains-domain-livedns
14
- # * post-v5-domain-domains-domain-livedns
15
- # TODO: Nameservers Management
16
- # * get-v5-domain-domains-domain-nameservers
17
- # * put-v5-domain-domains-domain-nameservers
18
-
19
- require_relative 'domain/auto_renew'
20
- require_relative 'domain/contact'
21
- require_relative 'domain/contract'
22
- require_relative 'domain/dates'
23
- require_relative 'domain/renewal_information'
24
- require_relative 'domain/restore_information'
25
- require_relative 'domain/sharing_space'
26
-
27
3
  class GandiV5
28
4
  # Gandi Domain Management API.
29
5
  # @see https://api.gandi.net/docs/domains
@@ -175,7 +151,7 @@ class GandiV5
175
151
  # Contacts for the domain.
176
152
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-contacts
177
153
  # @return [Hash{:owner, :admin, :bill, :tech => GandiV5::Domain::Contact}]
178
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
154
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
179
155
  def contacts
180
156
  @contacts ||= fetch_contacts
181
157
  end
@@ -183,9 +159,9 @@ class GandiV5
183
159
  # Requery Gandi for the domain's contacts.
184
160
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-contacts
185
161
  # @return [Hash{:owner, :admin, :bill, :tech => GandiV5::Domain::Contact}]
186
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
162
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
187
163
  def fetch_contacts
188
- data = GandiV5.get url('contacts')
164
+ _response, data = GandiV5.get url('contacts')
189
165
  self.contacts = data.transform_keys(&:to_sym)
190
166
  CONTACTS_CONVERTER.call contacts
191
167
  end
@@ -199,7 +175,7 @@ class GandiV5
199
175
  # @param tech [GandiV5::Domain::Contact, #to_gandi, #to_h]
200
176
  # details for the new technical contact.
201
177
  # @return [Hash{:owner, :admin, :bill, :tech => GandiV5::Domain::Contact}]
202
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
178
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
203
179
  def update_contacts(admin: nil, bill: nil, tech: nil)
204
180
  body = {
205
181
  admin: admin.respond_to?(:to_gandi) ? admin.to_gandi : admin,
@@ -214,7 +190,7 @@ class GandiV5
214
190
  # Renewal information for the domain.
215
191
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-renew
216
192
  # @return [GandiV5::Domain::RenewalInformation]
217
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
193
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
218
194
  def renewal_information
219
195
  @renewal_information ||= fetch_renewal_information
220
196
  end
@@ -222,9 +198,9 @@ class GandiV5
222
198
  # Requery Gandi for the domain's renewal information.
223
199
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-renew
224
200
  # @return [GandiV5::Domain::RenewalInformation]
225
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
201
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
226
202
  def fetch_renewal_information
227
- data = GandiV5.get url('renew')
203
+ _response, data = GandiV5.get url('renew')
228
204
  data = data['renew'].merge('contracts' => data['contracts'])
229
205
  @renewal_information = GandiV5::Domain::RenewalInformation.from_gandi data
230
206
  end
@@ -234,31 +210,32 @@ class GandiV5
234
210
  # @see https://api.gandi.net/docs/domains#post-v5-domain-domains-domain-renew
235
211
  # @param duration [Integer, #to_s] how long to renew for (in years).
236
212
  # @return [String] confirmation message from Gandi.
237
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
238
- def renew_for(duration = 1)
213
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
214
+ def renew_for(duration = 1, sharing_id: nil, dry_run: false)
239
215
  body = { duration: duration }.to_json
240
- data = GandiV5.post url('renew'), body
241
- data['message']
216
+ url_ = url('renew')
217
+ url_ = sharing_id ? "#{url_}?sharing_id=#{sharing_id}" : url_
218
+
219
+ _response, data = GandiV5.post(url_, body, 'Dry-Run': dry_run ? 1 : 0)
220
+ dry_run ? data : data['message']
242
221
  end
243
222
 
244
- # TODO: Test when I have a restorable domain
245
223
  # Restoration information for the domain.
246
224
  # @see https://docs.gandi.net/en/domain_names/renew/restore.html
247
225
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-restore
248
226
  # @return [GandiV5::Domain::RestoreInformation]
249
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
227
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
250
228
  def restore_information
251
229
  @restore_information ||= fetch_restore_information
252
230
  end
253
231
 
254
- # TODO: Test when I have a restorable domain
255
232
  # Requery Gandi for the domain's restore information.
256
233
  # @see https://docs.gandi.net/en/domain_names/renew/restore.html
257
234
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-restore
258
235
  # @return [GandiV5::Domain::RestoreInformation]
259
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
236
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
260
237
  def fetch_restore_information
261
- data = GandiV5.get url('restore')
238
+ _response, data = GandiV5.get url('restore')
262
239
  @restore_information = GandiV5::Domain::RestoreInformation.from_gandi data
263
240
  rescue RestClient::NotFound
264
241
  @restore_information = GandiV5::Domain::RestoreInformation.from_gandi restorable: false
@@ -269,25 +246,190 @@ class GandiV5
269
246
  # @see https://docs.gandi.net/en/domain_names/renew/restore.html
270
247
  # @see https://api.gandi.net/docs/domains#post-v5-domain-domains-domain-restore
271
248
  # @return [String] The confirmation message from Gandi.
272
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
249
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
273
250
  def restore
274
- data = GandiV5.post url('restore'), '{}'
251
+ _response, data = GandiV5.post url('restore'), '{}'
275
252
  data['message']
276
253
  end
277
254
 
278
255
  # Requery Gandi fo this domain's information.
279
256
  # @return [GandiV5::Domain]
280
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
257
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
281
258
  def refresh
282
- data = GandiV5.get url
259
+ _response, data = GandiV5.get url
283
260
  from_gandi data
284
261
  auto_renew.domain = self
285
262
  end
286
263
 
264
+ # Get the price for renewing this domain.
265
+ # @param currency [String] the currency to get the price in (e.g. GBP)
266
+ # @param period [Integer] the number of year(s) renewal to get the price for
267
+ # @return [GandiV5::Domain::Availability::Product::Price]
268
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error
269
+ def renewal_price(currency: 'GBP', period: 1)
270
+ arguments = { processes: [:renew], currency: currency, period: period }
271
+ GandiV5::Domain::Availability.fetch(fqdn, **arguments)
272
+ .products.first
273
+ .prices.first
274
+ end
275
+
276
+ # LiveDNS information for the domain.
277
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-livedns
278
+ # @return [GandiV5::Domain::LiveDNS]
279
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
280
+ def livedns
281
+ @livedns ||= fetch_livedns
282
+ end
283
+
284
+ # Requery Gandi for the domain's LiveDNS information.
285
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-livedns
286
+ # @return [GandiV5::Domain::LiveDNS]
287
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
288
+ def fetch_livedns
289
+ _response, data = GandiV5.get url('livedns')
290
+ @livedns = GandiV5::Domain::LiveDNS.from_gandi data
291
+ @name_server = @livedns.current
292
+ @name_servers = @livedns.name_servers
293
+ @livedns
294
+ end
295
+
296
+ # Enable LiveDNS for the domain.
297
+ # If you want to disable LiveDNS, change the nameservers.
298
+ # Please note that if the domain is on the classic Gandi DNS,
299
+ # this will also perform a copy of all existing records immediately afterwards.
300
+ # @see https://api.gandi.net/docs/domains#post-v5-domain-domains-domain-livedns
301
+ # @return [String] confirmation message from Gandi.
302
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
303
+ def enable_livedns
304
+ _response, data = GandiV5.post url('livedns')
305
+ data['message']
306
+ end
307
+
308
+ # Name servers for the domain.
309
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-nameservers
310
+ # @return [Array<String>]
311
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
312
+ def name_servers
313
+ @name_servers ||= fetch_name_servers
314
+ end
315
+
316
+ # Requery Gandi for the domain's name servers.
317
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-nameservers
318
+ # @return [Array<String>]
319
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
320
+ def fetch_name_servers
321
+ _response, data = GandiV5.get url('nameservers')
322
+ @name_servers = data
323
+ end
324
+
325
+ # Update name servers in Gandi.
326
+ # @see https://api.gandi.net/docs/domains#put-v5-domain-domains-domain-nameservers
327
+ # @param nameservers [Array<String>] the name servers to use.
328
+ # @return [String] confirmation message from Gandi.
329
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
330
+ def update_name_servers(nameservers)
331
+ _response, data = GandiV5.put url('nameservers'), { 'nameservers' => nameservers }.to_json
332
+ @name_servers = nameservers
333
+ data['message']
334
+ end
335
+
336
+ # Glue records for the domain.
337
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-hosts
338
+ # @return [Hash<String => Array<String>>] name to list of IPs
339
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
340
+ def glue_records
341
+ @glue_records ||= fetch_glue_records
342
+ end
343
+
344
+ # Requery Gandi for the domain's glue records.
345
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-hosts
346
+ # @return [Hash<String => Array<String>>] name to list of IPs
347
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
348
+ def fetch_glue_records
349
+ _response, data = GandiV5.get url('hosts')
350
+ @glue_records = data.map { |record| record.values_at('name', 'ips') }.to_h
351
+ end
352
+
353
+ # Add a new glue record to the domain in Gandi.
354
+ # @see https://api.gandi.net/docs/domains#post-v5-domain-domains-domain-hosts
355
+ # @param name [String] the DNS name (excluding FQDN) for the glue record to add (e.g. 'ns1').
356
+ # @param ips [Array<String>] the IPs for the name.
357
+ # @return [String] confirmation message from Gandi.
358
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
359
+ def add_glue_record(name, *ips)
360
+ _response, data = GandiV5.post url('hosts'), { 'name' => name, 'ips' => ips }.to_json
361
+ @glue_records ||= {}
362
+ @glue_records[name] = ips
363
+ data['message']
364
+ end
365
+
366
+ # Get a specific glue record for the domain.
367
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-hosts
368
+ # @param name [String] the DNS name (excluding FQDN) for the glue record to add (e.g. 'ns1').
369
+ # @return [Hash<String => Array<String>>] name to list of IPs
370
+ # @return [nil] name was not found
371
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
372
+ def glue_record(name)
373
+ records = @glue_records.key?(name) ? @glue_records : fetch_glue_records
374
+ records.key?(name) ? records.select { |k, _v| k == name } : nil
375
+ end
376
+
377
+ # Update a specific glue record for the domain.
378
+ # @see https://api.gandi.net/docs/domains#put-v5-domain-domains-domain-hosts-name
379
+ # @param name [String] the DNS name (excluding FQDN) for the glue record to update (e.g. 'ns1').
380
+ # @param ips [Array<String>] the IPs for the name.
381
+ # @return [String] confirmation message from Gandi.
382
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
383
+ def update_glue_record(name, *ips)
384
+ _response, data = GandiV5.put url('hosts', name), { 'ips' => ips }.to_json
385
+ @glue_records ||= {}
386
+ @glue_records[name] = ips
387
+ data['message']
388
+ end
389
+
390
+ # Delete a specific glue record for the domain.
391
+ # @see https://api.gandi.net/docs/domains#delete-v5-domain-domains-domain-hosts-name
392
+ # @param name [String] the DNS name (excluding FQDN) for the glue record to update (e.g. 'ns1').
393
+ # @return [String] confirmation message from Gandi.
394
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
395
+ def delete_glue_record(name)
396
+ _response, data = GandiV5.delete url('hosts', name)
397
+ @glue_records ||= {}
398
+ @glue_records.delete(name)
399
+ data['message']
400
+ end
401
+
402
+ # @see GandiV5::Email::Mailbox.list
403
+ def mailboxes(**params)
404
+ GandiV5::Email::Mailbox.list(**params, fqdn: fqdn)
405
+ end
406
+
407
+ # @see GandiV5::Email::Slot.list
408
+ def mailbox_slots(**params)
409
+ GandiV5::Email::Slot.list(**params, fqdn: fqdn)
410
+ end
411
+
412
+ # @see GandiV5::Email::Forward.list
413
+ def email_forwards(**params)
414
+ GandiV5::Email::Forward.list(**params, fqdn: fqdn)
415
+ end
416
+
287
417
  # Create (register) a new domain.
288
418
  # Warning! This is not a free operation. Please ensure your prepaid account has enough credit.
289
419
  # @see https://api.gandi.net/docs/domains#post-v5-domain-domains
290
420
  # @param fqdn [String, #to_s] the fully qualified domain name to create.
421
+ # @param dry_run [Boolean]
422
+ # whether the details should be checked instead of actually creating the domain.
423
+ # @param sharing_id [String] either:
424
+ # * nil (default) - nothing special happens
425
+ # * an organization ID - pay using another organization
426
+ # (you need to have billing permissions on the organization
427
+ # and use the same organization name for the domain name's owner).
428
+ # The invoice will be edited using this organization's information.
429
+ # * a reseller ID - buy a domain for a customer using a reseller account
430
+ # (you need to have billing permissions on the reseller organization
431
+ # and have your customer's information for the owner).
432
+ # The invoice will be edited using the reseller organization's information.
291
433
  # @param owner [GandiV5::Domain::Contact, #to_gandi, #to_h] (required)
292
434
  # the owner of the new domain.
293
435
  # @param admin [GandiV5::Domain::Contact, #to_gandi, #to_h] (optional, defaults to owner)
@@ -312,34 +454,34 @@ class GandiV5
312
454
  # @param nameservers [Array<String>, #to_gandi, #to_json] (optional)
313
455
  # List of nameservers. Gandi's LiveDNS nameservers are used if omitted..
314
456
  # @param price [Numeric, #to_gandi, #to_json] (optional) unknown - not documented at Gandi.
315
- # @param reselle_id [String, #to_gandi, #to_json] (optional) unknown - not documented at Gandi.
457
+ # @param resellee_id [String, #to_gandi, #to_json] (optional) unknown - not documented at Gandi.
316
458
  # @param smd [String, #to_gandi, #to_json] (optional)
317
459
  # Contents of a Signed Mark Data file (used for newgtld sunrises, tld_period must be sunrise).
318
460
  # @param tld_period ["sunrise", "landrush", "eap1", "eap2", "eap3", "eap4", "eap5", "eap6",
319
461
  # "eap7", "eap8", "eap9", "golive", #to_gandi, #to_json] (optional)
320
462
  # @see https://docs.gandi.net/en/domain_names/register/new_gtld.html
321
- # @param dry_run [Boolean] whether the details should be checked
322
- # instead of actually creating the domain.
323
- # @return [Hash] if actually creating, you get what Gandi returns.
324
- # @return [Hash] if doing a dry run, you get what Gandi returns.
325
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
326
- # TODO: Return created domain unless dry_run
327
- def self.create(fqdn, dry_run: false, **params)
463
+ # @return [GandiV5::Domain] the created domain
464
+ # @return [Hash] if doing a dry run, you get what Gandi returns
465
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error
466
+ def self.create(fqdn, dry_run: false, sharing_id: nil, **params)
328
467
  fail ArgumentError, 'missing keyword: owner' unless params.key?(:owner)
329
468
 
330
469
  body = params.merge(fqdn: fqdn)
331
470
  .transform_values { |val| val.respond_to?(:to_gandi) ? val.to_gandi : val }
332
471
  .to_json
333
- GandiV5.post url, body, 'Dry-Run': dry_run ? 1 : 0
472
+ url_ = sharing_id ? "#{url}?sharing_id=#{sharing_id}" : url
473
+
474
+ response, data = GandiV5.post(url_, body, 'Dry-Run': dry_run ? 1 : 0)
475
+ dry_run ? data : fetch(response.headers[:location].split('/').last)
334
476
  end
335
477
 
336
478
  # Get information on a domain.
337
479
  # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain
338
480
  # @param fqdn [String, #to_s] the fully qualified domain name to fetch.
339
481
  # @return [GandiV5::Domain]
340
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
482
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
341
483
  def self.fetch(fqdn)
342
- data = GandiV5.get url(fqdn)
484
+ _response, data = GandiV5.get url(fqdn)
343
485
  domain = from_gandi data
344
486
  domain.auto_renew.domain = fqdn
345
487
  domain
@@ -357,13 +499,13 @@ class GandiV5
357
499
  # @param sort_by [String, #to_s] (optional default "fqdn") how to sort the list.
358
500
  # @param tld [String, #to_s] (optional) used to filter by just the top level domain.
359
501
  # @return [Array<GandiV5::Domain>]
360
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
502
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
361
503
  def self.list(page: (1..), per_page: 100, **params)
362
504
  page = [page.to_i] unless page.respond_to?(:each)
363
505
 
364
506
  domains = []
365
507
  page.each do |page_number|
366
- data = GandiV5.get url, params: params.merge(page: page_number, per_page: per_page)
508
+ _resp, data = GandiV5.get url, params: params.merge(page: page_number, per_page: per_page)
367
509
  break if data.empty?
368
510
 
369
511
  domains += data.map { |domain| from_gandi domain }
@@ -372,54 +514,12 @@ class GandiV5
372
514
  domains
373
515
  end
374
516
 
375
- # Check domain availability and pricing.
376
- # @see https://api.gandi.net/docs/domains#get-v5-domain-check
377
- # @param fqdn [String, #to_s] the fully qualified domain name to check.
378
- # @param country [String, #to_s] (optional) ISO country code for which taxes are to be applied.
379
- # @param currency [String, #to_s] (optional) request price for a specific ISO currency code.
380
- # @param duration_unit [String, #to_s] (optional) define the unit for max_duration.
381
- # @param extension [String, #to_s] (optional) query a specific extension for product options.
382
- # @param grid [String, #to_s] (optional) request price for a specific rate.
383
- # @param lang [String, #to_s] (optional) language code.
384
- # @param max_duration [Integer, #to_s] (optional)
385
- # set a limit on the duration range for returned prices.
386
- # @param period [String, #to_s] (optional) specific registration period to query.
387
- # @param _ [Array<:create, :renew, :transfer etc.>] (optional default [:create])
388
- # list of at least 1 process for which pricing is to be made.
389
- # @param sharing_id [String, #to_s] (optional) organization for which the pricing is to be made.
390
- # @return [Hash]
391
- # TODO: Return an Availabillity object ???
392
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
393
- def self.availability(fqdn, **options)
394
- GandiV5.get "#{BASE}domain/check", params: { name: fqdn }.merge(options)
395
- end
396
-
397
- # List of available TLDs.
398
- # @see https://api.gandi.net/docs/domains#get-v5-domain-tlds
399
- # @return Array<String>
400
- # TODO: Maybe return an array of TLD objects ???
401
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
402
- def self.tlds
403
- GandiV5.get("#{BASE}domain/tlds")
404
- .map { |hash| hash['name'] }
405
- end
406
-
407
- # Get TLD information.
408
- # @see https://api.gandi.net/docs/domains#get-v5-domain-tlds-name
409
- # @param name [String, #to_s] the top level domain to get information for.
410
- # @return [Hash]
411
- # TODO: Return a TLD object ???
412
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
413
- def self.tld(name)
414
- GandiV5.get("#{BASE}domain/tlds/#{CGI.escape name}").transform_keys(&:to_sym)
415
- end
416
-
417
517
  private
418
518
 
419
- def url(extra = nil)
519
+ def url(*extra)
420
520
  "#{BASE}domain/domains/" +
421
521
  CGI.escape(fqdn) +
422
- (extra ? "/#{extra}" : '')
522
+ (extra.empty? ? '' : "/#{extra.join('/')}")
423
523
  end
424
524
 
425
525
  def self.url(fqdn = nil)