gandi_v5 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +20 -0
  5. data/.travis.yml +23 -0
  6. data/CHANGELOG.md +3 -0
  7. data/Gemfile +6 -0
  8. data/Guardfile +40 -0
  9. data/LICENSE.md +32 -0
  10. data/README.md +94 -0
  11. data/Rakefile +3 -0
  12. data/TODO.md +29 -0
  13. data/bin/console +13 -0
  14. data/gandi_v5.gemspec +41 -0
  15. data/lib/gandi_v5/billing/info/prepaid.rb +33 -0
  16. data/lib/gandi_v5/billing/info.rb +26 -0
  17. data/lib/gandi_v5/billing.rb +28 -0
  18. data/lib/gandi_v5/data/converter/array_of.rb +35 -0
  19. data/lib/gandi_v5/data/converter/symbol.rb +26 -0
  20. data/lib/gandi_v5/data/converter/time.rb +28 -0
  21. data/lib/gandi_v5/data/converter.rb +41 -0
  22. data/lib/gandi_v5/data.rb +244 -0
  23. data/lib/gandi_v5/domain/auto_renew.rb +64 -0
  24. data/lib/gandi_v5/domain/contact.rb +102 -0
  25. data/lib/gandi_v5/domain/contract.rb +22 -0
  26. data/lib/gandi_v5/domain/dates.rb +44 -0
  27. data/lib/gandi_v5/domain/renewal_information.rb +41 -0
  28. data/lib/gandi_v5/domain/restore_information.rb +18 -0
  29. data/lib/gandi_v5/domain/sharing_space.rb +21 -0
  30. data/lib/gandi_v5/domain.rb +431 -0
  31. data/lib/gandi_v5/email/mailbox/responder.rb +36 -0
  32. data/lib/gandi_v5/email/mailbox.rb +236 -0
  33. data/lib/gandi_v5/email/offer.rb +27 -0
  34. data/lib/gandi_v5/email/slot.rb +134 -0
  35. data/lib/gandi_v5/email.rb +11 -0
  36. data/lib/gandi_v5/error/gandi_error.rb +21 -0
  37. data/lib/gandi_v5/error.rb +9 -0
  38. data/lib/gandi_v5/live_dns/domain.rb +211 -0
  39. data/lib/gandi_v5/live_dns/record_set.rb +79 -0
  40. data/lib/gandi_v5/live_dns/zone/snapshot.rb +62 -0
  41. data/lib/gandi_v5/live_dns/zone.rb +301 -0
  42. data/lib/gandi_v5/live_dns.rb +30 -0
  43. data/lib/gandi_v5/organization.rb +66 -0
  44. data/lib/gandi_v5/version.rb +5 -0
  45. data/lib/gandi_v5.rb +178 -0
  46. data/spec/.rubocop.yml +4 -0
  47. data/spec/features/domain_spec.rb +45 -0
  48. data/spec/features/livedns_domain_spec.rb +8 -0
  49. data/spec/features/livedns_zone_spec.rb +45 -0
  50. data/spec/features/mailbox_spec.rb +18 -0
  51. data/spec/fixtures/bodies/GandiV5_Billing/info.yaml +10 -0
  52. data/spec/fixtures/bodies/GandiV5_Domain/availability.yaml +15 -0
  53. data/spec/fixtures/bodies/GandiV5_Domain/fetch_contacts.yaml +8 -0
  54. data/spec/fixtures/bodies/GandiV5_Domain/get.yaml +37 -0
  55. data/spec/fixtures/bodies/GandiV5_Domain/list.yaml +20 -0
  56. data/spec/fixtures/bodies/GandiV5_Domain/renewal_info.yaml +12 -0
  57. data/spec/fixtures/bodies/GandiV5_Domain/restore_info.yaml +5 -0
  58. data/spec/fixtures/bodies/GandiV5_Domain/tld.yaml +10 -0
  59. data/spec/fixtures/bodies/GandiV5_Domain/tlds.yaml +7 -0
  60. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/get.yaml +16 -0
  61. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/list.yaml +8 -0
  62. data/spec/fixtures/bodies/GandiV5_Email_Slot/get.yaml +10 -0
  63. data/spec/fixtures/bodies/GandiV5_Email_Slot/list.yaml +8 -0
  64. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/get.yaml +4 -0
  65. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list.yaml +2 -0
  66. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/get.yaml +11 -0
  67. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yaml +11 -0
  68. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/get.yaml +9 -0
  69. data/spec/fixtures/bodies/GandiV5_Organization/get.yaml +17 -0
  70. data/spec/fixtures/vcr/Domain_features/List_domains.yml +54 -0
  71. data/spec/fixtures/vcr/Domain_features/Renew_domain.yml +133 -0
  72. data/spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml +32 -0
  73. data/spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml +42 -0
  74. data/spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml +72 -0
  75. data/spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml +28 -0
  76. data/spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml +39 -0
  77. data/spec/spec_helper.rb +60 -0
  78. data/spec/test.env +1 -0
  79. data/spec/units/gandi_v5/billing/info/prepaid_spec.rb +20 -0
  80. data/spec/units/gandi_v5/billing/info_spec.rb +4 -0
  81. data/spec/units/gandi_v5/billing_spec.rb +41 -0
  82. data/spec/units/gandi_v5/data/converter/array_of_spec.rb +18 -0
  83. data/spec/units/gandi_v5/data/converter/symbol_spec.rb +16 -0
  84. data/spec/units/gandi_v5/data/converter/time_spec.rb +16 -0
  85. data/spec/units/gandi_v5/data/converter_spec.rb +31 -0
  86. data/spec/units/gandi_v5/data_spec.rb +340 -0
  87. data/spec/units/gandi_v5/domain/auto_renew_spec.rb +70 -0
  88. data/spec/units/gandi_v5/domain/contact_spec.rb +36 -0
  89. data/spec/units/gandi_v5/domain/contract_spec.rb +4 -0
  90. data/spec/units/gandi_v5/domain/dates_spec.rb +4 -0
  91. data/spec/units/gandi_v5/domain/renewal_information_spec.rb +81 -0
  92. data/spec/units/gandi_v5/domain/restore_information_spec.rb +4 -0
  93. data/spec/units/gandi_v5/domain/sharing_space_spec.rb +4 -0
  94. data/spec/units/gandi_v5/domain_spec.rb +451 -0
  95. data/spec/units/gandi_v5/email/mailbox/responder_spec.rb +131 -0
  96. data/spec/units/gandi_v5/email/mailbox_spec.rb +384 -0
  97. data/spec/units/gandi_v5/email/offer_spec.rb +17 -0
  98. data/spec/units/gandi_v5/email/slot_spec.rb +102 -0
  99. data/spec/units/gandi_v5/error/gandi_error_spec.rb +30 -0
  100. data/spec/units/gandi_v5/error_spec.rb +4 -0
  101. data/spec/units/gandi_v5/live_dns/domain_spec.rb +247 -0
  102. data/spec/units/gandi_v5/live_dns/record_set_spec.rb +74 -0
  103. data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +37 -0
  104. data/spec/units/gandi_v5/live_dns/zone_spec.rb +329 -0
  105. data/spec/units/gandi_v5/live_dns_spec.rb +17 -0
  106. data/spec/units/gandi_v5/organization_spec.rb +30 -0
  107. data/spec/units/gandi_v5_spec.rb +204 -0
  108. metadata +406 -0
@@ -0,0 +1,431 @@
1
+ # frozen_string_literal: true
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
+ class GandiV5
28
+ # Gandi Domain Management API.
29
+ # @see https://api.gandi.net/docs/domains
30
+ # @!attribute [r] fqdn
31
+ # @return [String] fully qualified domain name, written in its native alphabet (IDN).
32
+ # @!attribute [r] fqdn_unicode
33
+ # @return [String] fully qualified domain name, written in unicode.
34
+ # @see https://docs.gandi.net/en/domain_names/register/idn.html
35
+ # @!attribute [r] name_servers
36
+ # @return [Array<String>]
37
+ # @!attribute [r] services
38
+ # @return [Array<Symbol>] list of Gandi services attached to this domain.
39
+ # gandidns, redirection, gandimail, packmail, dnssec, blog, hosting,
40
+ # paas, site, certificate, gandilivedns, mailboxv2
41
+ # @!attribute [r] sharing_space
42
+ # @return [GandiV5::Domain::SharingSpace]
43
+ # @!attribute [r] status
44
+ # @return [String] one of: "clientHold", "clientUpdateProhibited", "clientTransferProhibited",
45
+ # "clientDeleteProhibited", "clientRenewProhibited", "serverHold", "pendingTransfer",
46
+ # "serverTransferProhibited"
47
+ # @see https://docs.gandi.net/en/domain_names/faq/domain_statuses.html
48
+ # @!attribute [r] tld
49
+ # @return [String]
50
+ # @!attribute [r] dates
51
+ # @return [GandiV5::Domain::Dates]
52
+ # @!attribute [r] can_tld_lock
53
+ # @return [Boolean]
54
+ # @!attribute [r] contacts
55
+ # @return [Hash<:owner, :admin, :bill, :tech => GandiV5::Domain::Contact>]
56
+ # @!attribute [r] auto_renew
57
+ # @return [GandiV5::Domain::AutoRenew]
58
+ # @!attribute [r] auth_info
59
+ # @return [nil, String]
60
+ # @!attribute [r] uuid
61
+ # @return [nil, String]
62
+ # @!attribute [r] sharing_uuid
63
+ # @return [nil, String]
64
+ # @!attribute [r] tags
65
+ # @return [nil, Array<String>] list of tags that have been assigned to the domain.
66
+ # @!attribute [r] trustee_roles
67
+ # @return [nil, Array<Symbol>] one of: admin, tech.
68
+ # @!attribute [r] owner
69
+ # @return [String]
70
+ # @!attribute [r] organisation_owner
71
+ # @return [_String
72
+ # @!attribute [r] domain_owner
73
+ # @return [String]
74
+ # @!attribute [r] name_server
75
+ # @return [Symbol]
76
+ class Domain
77
+ include GandiV5::Data
78
+
79
+ SERVICES = {
80
+ gandidns: 'GandiDNS',
81
+ gandilivedns: 'LiveDNS',
82
+ dnssec: 'DNSSEC',
83
+ certificate: 'SSL Certificate',
84
+ paas: 'PAAS',
85
+ redirection: 'Redirection',
86
+ gandimail: 'GandiMail',
87
+ packmail: 'PackMail',
88
+ blog: 'Blog',
89
+ hosting: 'Hosting',
90
+ site: 'Site',
91
+ mailboxv2: 'MailboxV2'
92
+ }.freeze
93
+
94
+ STATUSES = {
95
+ clientHold: 'clientHold',
96
+ clientUpdateProhibited: 'clientUpdateProhibited',
97
+ clientTransferProhibited: 'clientTransferProhibited',
98
+ clientDeleteProhibited: 'clientDeleteProhibited',
99
+ clientRenewProhibited: 'clientRenewProhibited',
100
+ serverHold: 'serverHold',
101
+ pendingTransfer: 'pendingTransfer',
102
+ serverTransferProhibited: 'serverTransferProhibited'
103
+ }.freeze
104
+
105
+ CONTACTS_CONVERTER = lambda { |hash|
106
+ break {} if hash.nil?
107
+
108
+ hash = hash.transform_keys(&:to_sym)
109
+ .transform_values { |value| GandiV5::Domain::Contact.from_gandi value }
110
+
111
+ hash.define_singleton_method(:owner) { send :'[]', :owner }
112
+ hash.define_singleton_method(:admin) { send :'[]', :admin }
113
+ hash.define_singleton_method(:bill) { send :'[]', :bill }
114
+ hash.define_singleton_method(:tech) { send :'[]', :tech }
115
+
116
+ hash
117
+ }
118
+ private_constant :CONTACTS_CONVERTER
119
+
120
+ members :fqdn, :fqdn_unicode, :tld, :can_tld_lock, :tags, :owner, :domain_owner
121
+ member :sharing_uuid, gandi_key: 'sharing_id'
122
+ member :name_servers, gandi_key: 'nameservers'
123
+ member :auth_info, gandi_key: 'authinfo'
124
+ member :organisation_owner, gandi_key: 'orga_owner'
125
+ member :uuid, gandi_key: 'id'
126
+
127
+ member(
128
+ :dates,
129
+ converter: GandiV5::Domain::Dates
130
+ )
131
+ member(
132
+ :sharing_space,
133
+ gandi_key: 'sharing_space',
134
+ converter: GandiV5::Domain::SharingSpace
135
+ )
136
+
137
+ member(
138
+ :auto_renew,
139
+ gandi_key: 'autorenew',
140
+ converter: GandiV5::Data::Converter.new(from_gandi: lambda { |hash|
141
+ break nil if hash.nil?
142
+ break nil if hash.eql?(true)
143
+ break GandiV5::Domain::AutoRenew.from_gandi('enabled' => false) if hash.eql?(false)
144
+
145
+ GandiV5::Domain::AutoRenew.from_gandi hash
146
+ })
147
+ )
148
+
149
+ member(
150
+ :contacts,
151
+ converter: GandiV5::Data::Converter.new(from_gandi: CONTACTS_CONVERTER)
152
+ )
153
+
154
+ member(
155
+ :name_server,
156
+ gandi_key: 'nameserver',
157
+ converter: GandiV5::Data::Converter.new(from_gandi: ->(hash) { hash&.[]('current')&.to_sym })
158
+ )
159
+ member :services, converter: GandiV5::Data::Converter::Symbol, array: true
160
+ member :status, converter: GandiV5::Data::Converter::Symbol, array: true
161
+ member :trustee_roles, converter: GandiV5::Data::Converter::Symbol, array: true
162
+
163
+ alias domain_uuid uuid
164
+
165
+ # rubocop:disable Style/AsciiComments
166
+ # Returns the string representation of the domain.
167
+ # @return [String] e.g. "example.com", "😀.com (xn--e28h.uk.com)"
168
+ # rubocop:enable Style/AsciiComments
169
+ def to_s
170
+ string = fqdn_unicode
171
+ string += " (#{fqdn})" unless fqdn == fqdn_unicode
172
+ string
173
+ end
174
+
175
+ # Contacts for the domain.
176
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-contacts
177
+ # @return [Hash{:owner, :admin, :bill, :tech => GandiV5::Domain::Contact}]
178
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
179
+ def contacts
180
+ @contacts ||= fetch_contacts
181
+ end
182
+
183
+ # Requery Gandi for the domain's contacts.
184
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-contacts
185
+ # @return [Hash{:owner, :admin, :bill, :tech => GandiV5::Domain::Contact}]
186
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
187
+ def fetch_contacts
188
+ data = GandiV5.get url('contacts')
189
+ self.contacts = data.transform_keys(&:to_sym)
190
+ CONTACTS_CONVERTER.call contacts
191
+ end
192
+
193
+ # Update some of the domain's contacts.
194
+ # @see https://api.gandi.net/docs/domains#patch-v5-domain-domains-domain-contacts
195
+ # @param admin [GandiV5::Domain::Contact, #to_gandi, #to_h]
196
+ # details for the new administrative contact.
197
+ # @param bill [GandiV5::Domain::Contact, #to_gandi, #to_h]
198
+ # details for the new billing contact.
199
+ # @param tech [GandiV5::Domain::Contact, #to_gandi, #to_h]
200
+ # details for the new technical contact.
201
+ # @return [Hash{:owner, :admin, :bill, :tech => GandiV5::Domain::Contact}]
202
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
203
+ def update_contacts(admin: nil, bill: nil, tech: nil)
204
+ body = {
205
+ admin: admin.respond_to?(:to_gandi) ? admin.to_gandi : admin,
206
+ bill: bill.respond_to?(:to_gandi) ? bill.to_gandi : bill,
207
+ tech: tech.respond_to?(:to_gandi) ? tech.to_gandi : tech
208
+ }.reject { |_k, v| v.nil? }.to_json
209
+
210
+ GandiV5.patch url('contacts'), body
211
+ fetch_contacts
212
+ end
213
+
214
+ # Renewal information for the domain.
215
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-renew
216
+ # @return [GandiV5::Domain::RenewalInformation]
217
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
218
+ def renewal_information
219
+ @renewal_information ||= fetch_renewal_information
220
+ end
221
+
222
+ # Requery Gandi for the domain's renewal information.
223
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-renew
224
+ # @return [GandiV5::Domain::RenewalInformation]
225
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
226
+ def fetch_renewal_information
227
+ data = GandiV5.get url('renew')
228
+ data = data['renew'].merge('contracts' => data['contracts'])
229
+ @renewal_information = GandiV5::Domain::RenewalInformation.from_gandi data
230
+ end
231
+
232
+ # Renew domain.
233
+ # Warning! This is not a free operation. Please ensure your prepaid account has enough credit.
234
+ # @see https://api.gandi.net/docs/domains#post-v5-domain-domains-domain-renew
235
+ # @param duration [Integer, #to_s] how long to renew for (in years).
236
+ # @return [String] confirmation message from Gandi.
237
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
238
+ def renew_for(duration = 1)
239
+ body = { duration: duration }.to_json
240
+ data = GandiV5.post url('renew'), body
241
+ data['message']
242
+ end
243
+
244
+ # TODO: Test when I have a restorable domain
245
+ # Restoration information for the domain.
246
+ # @see https://docs.gandi.net/en/domain_names/renew/restore.html
247
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-restore
248
+ # @return [GandiV5::Domain::RestoreInformation]
249
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
250
+ def restore_information
251
+ @restore_information ||= fetch_restore_information
252
+ end
253
+
254
+ # TODO: Test when I have a restorable domain
255
+ # Requery Gandi for the domain's restore information.
256
+ # @see https://docs.gandi.net/en/domain_names/renew/restore.html
257
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain-restore
258
+ # @return [GandiV5::Domain::RestoreInformation]
259
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
260
+ def fetch_restore_information
261
+ data = GandiV5.get url('restore')
262
+ @restore_information = GandiV5::Domain::RestoreInformation.from_gandi data
263
+ rescue RestClient::NotFound
264
+ @restore_information = GandiV5::Domain::RestoreInformation.from_gandi restorable: false
265
+ end
266
+
267
+ # Restore an expired domain.
268
+ # Warning! This is not a free operation. Please ensure your prepaid account has enough credit.
269
+ # @see https://docs.gandi.net/en/domain_names/renew/restore.html
270
+ # @see https://api.gandi.net/docs/domains#post-v5-domain-domains-domain-restore
271
+ # @return [String] The confirmation message from Gandi.
272
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
273
+ def restore
274
+ data = GandiV5.post url('restore'), '{}'
275
+ data['message']
276
+ end
277
+
278
+ # Requery Gandi fo this domain's information.
279
+ # @return [GandiV5::Domain]
280
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
281
+ def refresh
282
+ data = GandiV5.get url
283
+ from_gandi data
284
+ auto_renew.domain = self
285
+ end
286
+
287
+ # Create (register) a new domain.
288
+ # Warning! This is not a free operation. Please ensure your prepaid account has enough credit.
289
+ # @see https://api.gandi.net/docs/domains#post-v5-domain-domains
290
+ # @param fqdn [String, #to_s] the fully qualified domain name to create.
291
+ # @param owner [GandiV5::Domain::Contact, #to_gandi, #to_h] (required)
292
+ # the owner of the new domain.
293
+ # @param admin [GandiV5::Domain::Contact, #to_gandi, #to_h] (optional, defaults to owner)
294
+ # the administrative contact for the new domain.
295
+ # @param bill [GandiV5::Domain::Contact, #to_gandi, #to_h] (optional, defaults to owner)
296
+ # the billing contact for the new domain.
297
+ # @param tech [GandiV5::Domain::Contact, #to_gandi, #to_h] (optional, defaults to owner)
298
+ # the technical contact for the new domain.
299
+ # @param claims [String] (optional) unknown - not documented at Gandi.
300
+ # @param currency ["EUR", "USD", "GBP", "TWD", "CNY"] (optional)
301
+ # the currency you wish to be charged in.
302
+ # @param duration [Integer] (optional, default 1, minimum 1 maximum 10)
303
+ # how many years to register for.
304
+ # @param enforce_premium [Boolean] (optional)
305
+ # must be set to true if the domain is a premium domain.
306
+ # @param extra_parameters [Hash, #to_gandi, #to_json] (optional)
307
+ # unknown - not documented at Gandi.
308
+ # @param lang [String] (optional)
309
+ # ISO-639-2 language code of the domain, required for some IDN domains.
310
+ # @param nameserver_ips [Hash<String => Array<String>>, #to_gandi, #to_json] (optional)
311
+ # For glue records only - dictionnary associating a nameserver to a list of IP addresses.
312
+ # @param nameservers [Array<String>, #to_gandi, #to_json] (optional)
313
+ # List of nameservers. Gandi's LiveDNS nameservers are used if omitted..
314
+ # @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.
316
+ # @param smd [String, #to_gandi, #to_json] (optional)
317
+ # Contents of a Signed Mark Data file (used for newgtld sunrises, tld_period must be sunrise).
318
+ # @param tld_period ["sunrise", "landrush", "eap1", "eap2", "eap3", "eap4", "eap5", "eap6",
319
+ # "eap7", "eap8", "eap9", "golive", #to_gandi, #to_json] (optional)
320
+ # @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)
328
+ fail ArgumentError, 'missing keyword: owner' unless params.key?(:owner)
329
+
330
+ body = params.merge(fqdn: fqdn)
331
+ .transform_values { |val| val.respond_to?(:to_gandi) ? val.to_gandi : val }
332
+ .to_json
333
+ GandiV5.post url, body, 'Dry-Run': dry_run ? 1 : 0
334
+ end
335
+
336
+ # Get information on a domain.
337
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains-domain
338
+ # @param fqdn [String, #to_s] the fully qualified domain name to fetch.
339
+ # @return [GandiV5::Domain]
340
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
341
+ def self.fetch(fqdn)
342
+ data = GandiV5.get url(fqdn)
343
+ domain = from_gandi data
344
+ domain.auto_renew.domain = fqdn
345
+ domain
346
+ end
347
+
348
+ # List domains.
349
+ # @see https://api.gandi.net/docs/domains#get-v5-domain-domains
350
+ # @param page [#each<Integer, #to_s>] the page(s) of results to retrieve.
351
+ # If page is not provided keep querying until an empty list is returned.
352
+ # If page responds to .each then iterate until an empty list is returned.
353
+ # @param per_page [Integer, #to_s] (optional default 100) how many results ot get per page.
354
+ # @param fqdn [String, #to_s] (optional)
355
+ # filters the list by domain name, with optional patterns.
356
+ # e.g. "example.net", "example.*", "*ample.com"
357
+ # @param sort_by [String, #to_s] (optional default "fqdn") how to sort the list.
358
+ # @param tld [String, #to_s] (optional) used to filter by just the top level domain.
359
+ # @return [Array<GandiV5::Domain>]
360
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
361
+ def self.list(page: (1..), per_page: 100, **params)
362
+ page = [page.to_i] unless page.respond_to?(:each)
363
+
364
+ domains = []
365
+ page.each do |page_number|
366
+ data = GandiV5.get url, params: params.merge(page: page_number, per_page: per_page)
367
+ break if data.empty?
368
+
369
+ domains += data.map { |domain| from_gandi domain }
370
+ break if data.count < per_page
371
+ end
372
+ domains
373
+ end
374
+
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
+ private
418
+
419
+ def url(extra = nil)
420
+ "#{BASE}domain/domains/" +
421
+ CGI.escape(fqdn) +
422
+ (extra ? "/#{extra}" : '')
423
+ end
424
+
425
+ def self.url(fqdn = nil)
426
+ "#{BASE}domain/domains" +
427
+ (fqdn ? "/#{CGI.escape fqdn}" : '')
428
+ end
429
+ private_class_method :url
430
+ end
431
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: Allow enable/disable from here too ???
4
+
5
+ class GandiV5
6
+ class Email
7
+ class Mailbox
8
+ # Status of a mailbox's auto responder.
9
+ # @see https://api.gandi.net/docs/email#get-v5-email-mailboxes-domain-mailbox_id
10
+ # @!attribute [r] enabled
11
+ # @return [Boolean]
12
+ # @!attribute [r] starts_at
13
+ # @return [nil, Time]
14
+ # @!attribute [r] ends_at
15
+ # @return [nil, Time]
16
+ # @!attribute [r] message
17
+ # @return [nil, String]
18
+ class Responder
19
+ include GandiV5::Data
20
+
21
+ members :enabled, :message
22
+ member :starts_at, converter: GandiV5::Data::Converter::Time
23
+ member :ends_at, converter: GandiV5::Data::Converter::Time
24
+
25
+ # Check if this responder is currently active.
26
+ # @return [Boolean] whether the responder is enabled,
27
+ # started in the past and ends in the future.
28
+ def active?
29
+ enabled &&
30
+ (starts_at.nil? || starts_at < Time.now) &&
31
+ (ends_at.nil? || ends_at > Time.now)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end