gandi_v5 0.1.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 (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