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,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