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,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ class LiveDNS
5
+ # A record set which comes from either a domain or zone.
6
+ # @!attribute [r] type
7
+ # @return [String]
8
+ # @!attribute [r] ttl
9
+ # @return [Integer]
10
+ # @!attribute [r] name
11
+ # @return [String]
12
+ # @!attribute [r] values
13
+ # @return [Array<String>]
14
+ class RecordSet
15
+ include GandiV5::Data
16
+
17
+ member :type, gandi_key: 'rrset_type'
18
+ member :ttl, gandi_key: 'rrset_ttl'
19
+ member :name, gandi_key: 'rrset_name'
20
+ member :values, gandi_key: 'rrset_values'
21
+
22
+ # Generate zone file lines for the record.
23
+ # @return [String]
24
+ def to_s
25
+ values.map do |value|
26
+ "#{name}\t#{ttl}\tIN\t#{type}\t#{value}"
27
+ end.join("\n")
28
+ end
29
+
30
+ GandiV5::LiveDNS::RECORD_TYPES.each do |t|
31
+ # Check the record type.
32
+ # @return [Boolean]
33
+ define_method "#{t.downcase}?" do
34
+ type.eql?(t)
35
+ end
36
+ end
37
+
38
+ # Check the TTL's value in seconds.
39
+ # @param number [Integer] the number of second(s) to check against.
40
+ # @return [Boolean]
41
+ def second?(number = 1)
42
+ ttl == number
43
+ end
44
+ alias seconds? second?
45
+
46
+ # Check the TTL's value in minutes.
47
+ # @param number [Integer] the number of minute(s) to check against.
48
+ # @return [Boolean]
49
+ def minute?(number = 1)
50
+ ttl == number * 60
51
+ end
52
+ alias minutes? minute?
53
+
54
+ # Check the TTL's value in hours.
55
+ # @param number [Integer] the number of hour(s) to check against.
56
+ # @return [Boolean]
57
+ def hour?(number = 1)
58
+ ttl == number * 3_600
59
+ end
60
+ alias hours? hour?
61
+
62
+ # Check the TTL's value in days.
63
+ # @param number [Integer] the number of day(s) to check against.
64
+ # @return [Boolean]
65
+ def day?(number = 1)
66
+ ttl == number * 86_400
67
+ end
68
+ alias days? day?
69
+
70
+ # Check the TTL's value in weeks.
71
+ # @param number [Integer] the number of week(s) to check against.
72
+ # @return [Boolean]
73
+ def week?(number = 1)
74
+ ttl == number * 604_800
75
+ end
76
+ alias weeks? day?
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ class LiveDNS
5
+ class Zone
6
+ # A snapshot (backup) of a zone.
7
+ # @!attribute [r] uuid
8
+ # @return [String]
9
+ # @!attribute [r] zone_uuid
10
+ # @return [String]
11
+ # @!attribute [r] created_at
12
+ # @return [Time]
13
+ # @!attribute [r] records
14
+ # @return [Array<GandiV5::LiveDNS::RecordSet>]
15
+ class Snapshot
16
+ include GandiV5::Data
17
+
18
+ members :uuid, :zone_uuid
19
+ member :created_at, gandi_key: 'date_created', converter: GandiV5::Data::Converter::Time
20
+ member(
21
+ :records,
22
+ gandi_key: 'zone_data',
23
+ converter: GandiV5::LiveDNS::RecordSet,
24
+ array: true
25
+ )
26
+
27
+ alias snapshot_uuid uuid
28
+
29
+ # Delete this snapshot.
30
+ # @return [String] The confirmation message from Gandi.
31
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
32
+ def delete
33
+ data = GandiV5.delete url
34
+ data['message']
35
+ end
36
+
37
+ # Get snapshot from Gandi.
38
+ # @param zone_uuid [String, #to_s] the UUID of the zone the snapshot was made of.
39
+ # @param snapshot_uuid [String, #to_s] the UUID of the snapshot to fetch.
40
+ # @return [GandiV5::LiveDNS::Zone::Snapshot]
41
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
42
+ def self.fetch(zone_uuid, snapshot_uuid)
43
+ data = GandiV5.get url(zone_uuid, snapshot_uuid)
44
+ from_gandi data
45
+ end
46
+
47
+ # TODO: Move listing snapshots to here
48
+
49
+ private
50
+
51
+ def url
52
+ "#{BASE}zones/#{CGI.escape zone_uuid}/snapshots/#{CGI.escape uuid}"
53
+ end
54
+
55
+ def self.url(zone_uuid, snapshot_uuid)
56
+ "#{BASE}zones/#{CGI.escape zone_uuid}/snapshots/#{CGI.escape snapshot_uuid}"
57
+ end
58
+ private_class_method :url
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,301 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'zone/snapshot'
4
+
5
+ class GandiV5
6
+ class LiveDNS
7
+ # A zone within the LiveDNS system.
8
+ # Zones can be used by any number of domains.
9
+ # @!attribute [r] uuid
10
+ # @return [String]
11
+ # @!attribute [r] name
12
+ # @return [String]
13
+ # @!attribute [r] sharing_uuid
14
+ # @return [String]
15
+ # @!attribute [r] soa_retry
16
+ # @return [Integer] retry period, as reported in SOA record.
17
+ # @!attribute [r] soa_minimum
18
+ # @return [Integer] minimum and negative TTL, as reported in SOA record.
19
+ # @!attribute [r] soa_refresh
20
+ # @return [Integer] refresh period, as reported in SOA record.
21
+ # @!attribute [r] soa_expire
22
+ # @return [Integer] expire period, as reported in SOA record.
23
+ # @!attribute [r] soa_serial
24
+ # @return [Integer] serial number, as reported in SOA record.
25
+ # @!attribute [r] soa_email
26
+ # @return [String] admin email address, as reported in SOA record.
27
+ # @!attribute [r] soa_primary_ns
28
+ # @return [String] primary name server, as reported in SOA record.
29
+ class Zone
30
+ include GandiV5::Data
31
+
32
+ members :uuid, :name
33
+ member :sharing_uuid, gandi_key: 'sharing_id'
34
+ member :soa_retry, gandi_key: 'retry'
35
+ member :soa_minimum, gandi_key: 'minimum'
36
+ member :soa_refresh, gandi_key: 'refresh'
37
+ member :soa_expire, gandi_key: 'expire'
38
+ member :soa_serial, gandi_key: 'serial'
39
+ member :soa_email, gandi_key: 'email'
40
+ member :soa_primary_ns, gandi_key: 'primary_ns'
41
+
42
+ alias zone_uuid uuid
43
+
44
+ # Generate SOA record for the zone
45
+ # @return [String]
46
+ def to_s
47
+ "@\tIN\tSOA\t#{soa_primary_ns} #{soa_email} (\n" \
48
+ "\t#{soa_serial}\t;Serial\n" \
49
+ "\t#{soa_refresh}\t\t;Refresh\n" \
50
+ "\t#{soa_retry}\t\t;Retry\n" \
51
+ "\t#{soa_expire}\t\t;Expire\n" \
52
+ "\t#{soa_minimum}\t\t;Minimum & Negative TTL\n" \
53
+ ')'
54
+ end
55
+
56
+ # @overload fetch_records()
57
+ # Fetch all records for this zone.
58
+ # @overload fetch_records(name)
59
+ # Fetch records for a name.
60
+ # @param name [String] the name to fetch records for.
61
+ # @overload fetch_records(name, type)
62
+ # Fetch records of a type for a name.
63
+ # @param name [String] the name to fetch records for.
64
+ # @param type [String] the record type to fetch.
65
+ # @return [Array<GandiV5::LiveDNS::RecordSet>]
66
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
67
+ def fetch_records(name = nil, type = nil)
68
+ GandiV5::LiveDNS.require_valid_record_type type if type
69
+
70
+ url_ = "#{url}/records"
71
+ url_ += "/#{CGI.escape name}" if name
72
+ url_ += "/#{CGI.escape type}" if type
73
+
74
+ data = GandiV5.get url_
75
+ data = [data] unless data.is_a?(Array)
76
+ data.map { |item| GandiV5::LiveDNS::RecordSet.from_gandi item }
77
+ end
78
+
79
+ # @overload fetch_zone_lines()
80
+ # Fetch all records for this zone.
81
+ # @overload fetch_zone_lines(name)
82
+ # Fetch records for a name.
83
+ # @param name [String] the name to fetch records for.
84
+ # @overload fetch_zone_lines(name, type)
85
+ # Fetch records of a type for a name.
86
+ # @param name [String] the name to fetch records for.
87
+ # @param type [String] the record type to fetch.
88
+ # @return [String]
89
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
90
+ def fetch_zone_lines(name = nil, type = nil)
91
+ GandiV5::LiveDNS.require_valid_record_type type if type
92
+
93
+ url_ = "#{url}/records"
94
+ url_ += "/#{CGI.escape name}" if name
95
+ url_ += "/#{CGI.escape type}" if type
96
+
97
+ GandiV5.get url_, accept: 'text/plain'
98
+ end
99
+
100
+ # Add record to this zone.
101
+ # @param name [String]
102
+ # @param type [String]
103
+ # @param ttl [Integer]
104
+ # @param values [Array<String>]
105
+ # @return [String] The confirmation message from Gandi.
106
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
107
+ def add_record(name, type, ttl, *values)
108
+ GandiV5::LiveDNS.require_valid_record_type type
109
+ fail ArgumentError, 'ttl must be positive and non-zero' unless ttl.positive?
110
+ fail ArgumentError, 'there must be at least one value' if values.none?
111
+
112
+ body = {
113
+ rrset_name: name,
114
+ rrset_type: type,
115
+ rrset_ttl: ttl,
116
+ rrset_values: values
117
+ }.to_json
118
+ data = GandiV5.post "#{url}/records", body
119
+ data['message']
120
+ end
121
+
122
+ # @overload delete_records()
123
+ # Delete all records for this zone.
124
+ # @overload delete_records(name)
125
+ # Delete records for a name.
126
+ # @param name [String] the name to delete records for.
127
+ # @overload delete_records(name, type)
128
+ # Delete records of a type for a name.
129
+ # @param name [String] the name to delete records for.
130
+ # @param type [String] the record type to delete.
131
+ # @return [nil]
132
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
133
+ def delete_records(name = nil, type = nil)
134
+ GandiV5::LiveDNS.require_valid_record_type type if type
135
+
136
+ url_ = "#{url}/records"
137
+ url_ += "/#{CGI.escape name}" if name
138
+ url_ += "/#{CGI.escape type}" if type
139
+ GandiV5.delete url_
140
+ end
141
+
142
+ # Replace all records for this zone.
143
+ # @param records
144
+ # [Array<Hash<:name, :type => String, :ttl => Integer, :values => Array<String>>>]
145
+ # the records to add.
146
+ # @param text [String] zone file lines to replace the records with.
147
+ # @return [String] The confirmation message from Gandi.
148
+ # @raise [ArgumentError] if neither/both of records & test are passed.
149
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
150
+ def replace_records(records: nil, text: nil)
151
+ unless [records, text].count(&:nil?).eql?(1)
152
+ fail ArgumentError, 'you must pass ONE of records: or text:'
153
+ end
154
+
155
+ if records
156
+ body = {
157
+ items: records.map { |r| r.transform_keys { |k| "rrset_#{k}" } }
158
+ }.to_json
159
+ data = GandiV5.put "#{url}/records", body
160
+ elsif text
161
+ data = GandiV5.put "#{url}/records", text, 'content-type': 'text/plain'
162
+ end
163
+ data['message']
164
+ end
165
+
166
+ # Replace records for a name in this zone.
167
+ # @param name [String]
168
+ # @param records
169
+ # [Array<Hash<type: String, ttl: Integer, values: Array<String>>>]
170
+ # the records to add.
171
+ # @return [String] The confirmation message from Gandi.
172
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
173
+ def replace_records_for(name, *records)
174
+ body = {
175
+ items: records.map { |r| r.transform_keys { |k| "rrset_#{k}" } }
176
+ }.to_json
177
+ data = GandiV5.put "#{url}/records/#{name}", body
178
+ data['message']
179
+ end
180
+
181
+ GandiV5::LiveDNS::RECORD_TYPES.each do |type|
182
+ # Replace records of a given type for a name in this zone.
183
+ # @return [String] The confirmation message from Gandi.
184
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
185
+ define_method "replace_#{type.downcase}_records_for" do |name, ttl, *values|
186
+ body = {
187
+ rrset_ttl: ttl,
188
+ rrset_values: values
189
+ }.to_json
190
+ data = GandiV5.put "#{url}/records/#{name}/#{type}", body
191
+ data['message']
192
+ end
193
+ end
194
+
195
+ # List the domains that use this zone.
196
+ # @return [Array<String>] The FQDNs.
197
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
198
+ def list_domains
199
+ data = GandiV5.get "#{url}/domains"
200
+ data.map { |item| item['fqdn'] }
201
+ end
202
+
203
+ # Attach domain to this zone.
204
+ # @param fqdn [String, #fqdn, #to_s] the fully qualified domain name
205
+ # that should start using this zone.
206
+ # @return [String] The confirmation message from Gandi.
207
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
208
+ def attach_domain(fqdn)
209
+ fqdn = fqdn.fqdn if fqdn.respond_to?(:fqdn)
210
+ data = GandiV5.patch "#{BASE}domains/#{CGI.escape fqdn}", { zone_uuid: uuid }.to_json
211
+ data['message']
212
+ end
213
+
214
+ # Get snapshot UUIDs for this zone from Gandi.lib/gandi_v5/domain/auto_renew.rb
215
+ # @return [Hash{String => Time}] Mapping UUID to time made.
216
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
217
+ def snapshots
218
+ data = GandiV5.get "#{url}/snapshots"
219
+ Hash[data.map { |snapshot| [snapshot['uuid'], Time.parse(snapshot['date_created'])] }]
220
+ end
221
+
222
+ # Get snapshot from Gandi.
223
+ # @param uuid [String] the UUID of the snapshot to fetch.
224
+ # @return [GandiV5::LiveDNS::Zone::Snapshot]
225
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
226
+ def snapshot(uuid)
227
+ GandiV5::LiveDNS::Zone::Snapshot.fetch self.uuid, uuid
228
+ end
229
+
230
+ # Take a snapshot of this zone.
231
+ # @return [GandiV5::LiveDNS::Zone::Snapshot]
232
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
233
+ def take_snapshot
234
+ data = GandiV5.post "#{url}/snapshots"
235
+ snapshot data['uuid']
236
+ end
237
+
238
+ # Update this zone.
239
+ # @param name [String, #to_s] new name for the zone.
240
+ # @return [String] The confirmation message from Gandi.
241
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
242
+ def update(name:)
243
+ data = GandiV5.patch url, { name: name }.to_json
244
+ self.name = name
245
+ data['message']
246
+ end
247
+
248
+ # Delete this zone from Gandi.
249
+ # @return [nil]
250
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
251
+ def delete
252
+ GandiV5.delete url
253
+ end
254
+
255
+ # Create a new zone.
256
+ # @param name [String] the name for the created zone.
257
+ # @param sharing_id [String] the UUID of the account to ceate the zone under.
258
+ # @return [String] The confirmation message from Gandi.
259
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
260
+ # TODO: Fetch created zone
261
+ def self.create(name, sharing_id: nil)
262
+ params = sharing_id ? { sharing_id: sharing_id } : {}
263
+
264
+ data = GandiV5.post(
265
+ url,
266
+ { name: name }.to_json,
267
+ params: params
268
+ )
269
+ data['message']
270
+ end
271
+
272
+ # List the zones.
273
+ # @return [Array<GandiV5::LiveDNS::Zone>]
274
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
275
+ def self.list
276
+ data = GandiV5.get url
277
+ data.map { |item| from_gandi item }
278
+ end
279
+
280
+ # Get a zone from Gandi.
281
+ # @param uuid [String, #to_s] the UUID of the zone to fetch.
282
+ # @return [GandiV5::LiveDNS::Zone]
283
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
284
+ def self.fetch(uuid)
285
+ data = GandiV5.get url(uuid)
286
+ from_gandi data
287
+ end
288
+
289
+ private
290
+
291
+ def url
292
+ "#{BASE}zones/#{CGI.escape uuid}"
293
+ end
294
+
295
+ def self.url(uuid = nil)
296
+ BASE + (uuid ? "zones/#{CGI.escape(uuid)}" : 'zones')
297
+ end
298
+ private_class_method :url
299
+ end
300
+ end
301
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Namespace for classes which access LiveDNS details.
4
+ class GandiV5
5
+ # Gandi LiveDNS Management API.
6
+ class LiveDNS
7
+ BASE = 'https://dns.api.gandi.net/api/v5/'
8
+
9
+ RECORD_TYPES = %w[
10
+ A AAAA CNAME MX NS TXT ALIAS
11
+ WKS SRV LOC SPF CAA DS SSHFP PTR KEY DNAME TLSA OPENPGPKEY CDS
12
+ ].freeze
13
+
14
+ # Raise an error if passed type is invalid.
15
+ # @param type [String] the record type to check.
16
+ # @return [nil]
17
+ # @raise [ArgumentError]
18
+ # rubocop:disable Style/GuardClause
19
+ def self.require_valid_record_type(type)
20
+ unless RECORD_TYPES.include?(type)
21
+ fail ArgumentError, "type must be one of #{RECORD_TYPES.join(', ')}"
22
+ end
23
+ end
24
+ # rubocop:enable Style/GuardClause
25
+ end
26
+ end
27
+
28
+ require_relative 'live_dns/record_set'
29
+ require_relative 'live_dns/domain'
30
+ require_relative 'live_dns/zone'
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'email/mailbox'
4
+ require_relative 'email/offer'
5
+ require_relative 'email/slot'
6
+
7
+ class GandiV5
8
+ # The Organization API is a read-only API.
9
+ # All organization management must be performed via the web interface.
10
+ # @see https://api.gandi.net/docs/organization
11
+ # @!attribute [r] uuid
12
+ # @return [String] the sharing uuid of the user.
13
+ # @!attribute [r] username
14
+ # @return [String] the username of the user.
15
+ # @!attribute [r] name
16
+ # @return [String] the sharing name of the user.
17
+ # @!attribute [r] first_name
18
+ # @return [nil, String] the first name of the user.
19
+ # @!attribute [r] last_name
20
+ # @return [nil, String] the last name of the user.
21
+ # @!attribute [r] lang
22
+ # @return [String] language used by the user.
23
+ # @!attribute [r] street_address
24
+ # @return [nil, String] the street address of the user.
25
+ # @!attribute [r] city
26
+ # @return [String] the city name of the address.
27
+ # @!attribute [r] zip
28
+ # @return [nil, String] zip code of the address.
29
+ # @!attribute [r] country
30
+ # @return [nil, String] country ISO code of the address.
31
+ # @!attribute [r] email
32
+ # @return [String] the email address of the user.
33
+ # @!attribute [r] phone
34
+ # @return [nil, String] the phone number of the user.
35
+ # @!attribute [r] security_email
36
+ # @return [String] email address used for security processes such as account recovery.
37
+ # @!attribute [r] security_phone
38
+ # @return [nil, String]
39
+ # phone number used for security recovery processes such as totp recovery.
40
+ # @!attribute [r] security_email_validated
41
+ # @return [Boolean] state of the email validation process.
42
+ # @!attribute [r] security_email_validation_deadline
43
+ # @return [Time] deadline for the email address validation process.
44
+ class Organization
45
+ include GandiV5::Data
46
+
47
+ members :username, :name, :lang, :city, :zip, :country, :email, :phone, :security_phone,
48
+ :security_email, :security_email_validated, :security_email_validation_deadline
49
+ member :uuid, gandi_key: 'id'
50
+ member :first_name, gandi_key: 'firstname'
51
+ member :last_name, gandi_key: 'lastname'
52
+ member :street_address, gandi_key: 'streetaddr'
53
+ member :security_email_validation_deadline, converter: GandiV5::Data::Converter::Time
54
+
55
+ alias organization_uuid uuid
56
+
57
+ # Get information about the current authenticated user.
58
+ # @see https://api.gandi.net/docs/organization#get-v5-organization-user-info
59
+ # @return [GandiV5::Organization]
60
+ # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
61
+ def self.fetch
62
+ data = GandiV5.get "#{BASE}organization/user-info"
63
+ from_gandi data
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ VERSION = '0.1.0'
5
+ end