gandi_v5 0.9.1 → 0.10.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.md +10 -6
  4. data/lib/gandi_v5.rb +2 -0
  5. data/lib/gandi_v5/domain.rb +39 -1
  6. data/lib/gandi_v5/domain/transfer_in.rb +2 -0
  7. data/lib/gandi_v5/domain/web_forwarding.rb +182 -0
  8. data/lib/gandi_v5/email.rb +2 -0
  9. data/lib/gandi_v5/email/forward.rb +1 -1
  10. data/lib/gandi_v5/email/mailbox.rb +1 -1
  11. data/lib/gandi_v5/live_dns/domain/snapshot.rb +1 -1
  12. data/lib/gandi_v5/live_dns/domain/tsig_key.rb +1 -1
  13. data/lib/gandi_v5/simple_hosting/instance.rb +6 -0
  14. data/lib/gandi_v5/simple_hosting/instance/virtual_host.rb +87 -2
  15. data/lib/gandi_v5/simple_hosting/instance/virtual_host/linked_dns_zone.rb +1 -1
  16. data/lib/gandi_v5/template.rb +271 -0
  17. data/lib/gandi_v5/template/dispatch.rb +109 -0
  18. data/lib/gandi_v5/template/payload.rb +64 -0
  19. data/lib/gandi_v5/template/payload/dns_record.rb +23 -0
  20. data/lib/gandi_v5/template/payload/web_forwarding.rb +82 -0
  21. data/lib/gandi_v5/version.rb +1 -1
  22. data/spec/fixtures/bodies/GandiV5_Domain_WebForwarding/fetch.yml +9 -0
  23. data/spec/fixtures/bodies/GandiV5_Domain_WebForwarding/list.yml +9 -0
  24. data/spec/fixtures/bodies/GandiV5_Template/fetch.yml +41 -0
  25. data/spec/fixtures/bodies/GandiV5_Template/list.yml +20 -0
  26. data/spec/fixtures/bodies/GandiV5_Template_Dispatch/fetch.yml +49 -0
  27. data/spec/spec_helper.rb +8 -7
  28. data/spec/units/gandi_v5/domain/web_forwarding_spec.rb +150 -0
  29. data/spec/units/gandi_v5/domain_spec.rb +50 -0
  30. data/spec/units/gandi_v5/simple_hosting/instance/virtual_host_spec.rb +125 -0
  31. data/spec/units/gandi_v5/simple_hosting/instance_spec.rb +8 -0
  32. data/spec/units/gandi_v5/template/dispatch_spec.rb +70 -0
  33. data/spec/units/gandi_v5/template/payload/web_forwarding_spec.rb +44 -0
  34. data/spec/units/gandi_v5/template_spec.rb +341 -0
  35. data/spec/units/gandi_v5_spec.rb +1 -1
  36. metadata +73 -47
  37. data/spec/units/gandi_v5/billing/info_spec.rb +0 -4
  38. data/spec/units/gandi_v5/domain/availability/product/period_spec.rb +0 -4
  39. data/spec/units/gandi_v5/domain/availability/product/price_spec.rb +0 -4
  40. data/spec/units/gandi_v5/domain/availability/product_spec.rb +0 -4
  41. data/spec/units/gandi_v5/domain/availability/tax_spec.rb +0 -4
  42. data/spec/units/gandi_v5/domain/contract_spec.rb +0 -4
  43. data/spec/units/gandi_v5/domain/dates_spec.rb +0 -4
  44. data/spec/units/gandi_v5/domain/restore_information_spec.rb +0 -4
  45. data/spec/units/gandi_v5/error_spec.rb +0 -4
  46. data/spec/units/gandi_v5/sharing_space_spec.rb +0 -4
  47. data/spec/units/gandi_v5/simple_hosting/instance/database_spec.rb +0 -4
  48. data/spec/units/gandi_v5/simple_hosting/instance/language_spec.rb +0 -4
  49. data/spec/units/gandi_v5/simple_hosting/instance/upgrade_spec.rb +0 -4
@@ -5,7 +5,7 @@ class GandiV5
5
5
  class Instance
6
6
  class VirtualHost
7
7
  # A DNS Zone linked to a virtual host on a simple hosting instance.
8
- # @!attribute [r] allow_zone_alteration
8
+ # @!attribute [r] allow_alteration
9
9
  # @return [Boolean]
10
10
  # @!attribute [r] cname
11
11
  # @return [String]
@@ -0,0 +1,271 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ # Manage configuration templates.
5
+ # @!attribute [r] description
6
+ # @return [String] template purpose's description.
7
+ # @!attribute [r] editable
8
+ # @return [Boolean]
9
+ # @!attribute [r] uuid
10
+ # @return [String]
11
+ # @!attribute [r] name
12
+ # @return [String]
13
+ # @!attribute [r] orgname
14
+ # @return [String]
15
+ # @!attribute [r] sharing_space
16
+ # @return [GandiV5::SharingSpace]
17
+ # @!attribute [r] variables
18
+ # @return [Array<String>, nil]
19
+ # @!attribute [r] payload
20
+ # @return [Array<GandiV5::Template::Payload] the settings which will be applied
21
+ # when this template is used.
22
+ class Template
23
+ include GandiV5::Data
24
+
25
+ members :name, :description, :editable, :variables
26
+ member :uuid, gandi_key: 'id'
27
+ member :organisation_name, gandi_key: 'orgname'
28
+ member :payload, converter: GandiV5::Template::Payload
29
+ member(
30
+ :sharing_space,
31
+ gandi_key: 'sharing_space',
32
+ converter: GandiV5::SharingSpace
33
+ )
34
+
35
+ # Requery Gandi for this template's information.
36
+ # @return [GandiV5::Template]
37
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
38
+ def refresh
39
+ _response, data = GandiV5.get url
40
+ from_gandi data
41
+ self
42
+ end
43
+
44
+ # Delete this template from Gandi.
45
+ # @see https://api.gandi.net/docs/template/#delete-v5-template-templates-id
46
+ # @return [nil]
47
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
48
+ def delete
49
+ GandiV5.delete url
50
+ nil
51
+ end
52
+
53
+ # Applies the template to a domain.
54
+ # @see https://api.gandi.net/v5/template/dispatch/{id}
55
+ # @return [String] The UUID of the dispatch,
56
+ # keep hold of this you'll need it if you want to check the progress.
57
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
58
+ def apply(domain_uuid)
59
+ body = { 'object_type' => 'domain', 'object_id' => domain_uuid }.to_json
60
+ _response, data = GandiV5.post url, body
61
+ data.fetch('dispatch_href').split('/').last
62
+ end
63
+
64
+ # Update the template in Gandi.
65
+ # @see https://api.gandi.net/docs/template/#patch-v5-template-templates-id
66
+ # @param name [String, #to_s] the name to give the created template.
67
+ # @param description [String, #to_s] description of what the template achieves.
68
+ # @param dns_records [Array<Hash>, :default] The DNS records to create (as Gandi's docs)
69
+ # @option dns_records [String] :name The name of the DNS record to create.
70
+ # @option dns_records [String] :type The type of the DNS record to create.
71
+ # @option dns_records [Array<String>] :values The values for the created DNS record.
72
+ # @option dns_records [Integer] :ttl The TTL for the created record (300-2592000)
73
+ # @param mailboxes [Array<String>] The mailboxes to create (as Gandi's docs)
74
+ # @param name_servers [Array<String>, :livedns] The name servers to create (as Gandi's docs)
75
+ # @param web_forwardings [Array<Hash>] The web redirects to create (as Gandi's docs)
76
+ # @option web_forwardings [:cloak, :http301, :http302, :permanent, :temporary, :found] :type
77
+ # @option web_forwardings [String] :target
78
+ # @option web_forwardings [String] :source_host (optional)
79
+ # @option web_forwardings [Boolean] :override (optional, default false)
80
+ # When you create a redirection on a domain, a DNS record is created if it does not exist.
81
+ # When the record already exists and this parameter is set to true it will overwrite the
82
+ # record. Otherwise it will trigger an error.
83
+ # @option web_forwardings [:http, :https, :https_only] :protocol (optional)
84
+ # @return [GandiV5::Template]
85
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error
86
+ # rubocop:disable Metrics/AbcSize
87
+ def update(
88
+ name: nil,
89
+ description: nil,
90
+ dns_records: nil,
91
+ mailboxes: nil,
92
+ name_servers: nil,
93
+ web_forwardings: nil
94
+ )
95
+
96
+ body = Hash.new { |hash, key| hash[key] = {} }
97
+ body['name'] = name if name
98
+ body['description'] = description if description
99
+ body['payload']['dns:records'] = gandify_dns_records(dns_records) if dns_records
100
+ body['payload']['domain:mailboxes'] = gandify_mailboxes(mailboxes) if mailboxes
101
+ body['payload']['domain:nameservers'] = gandify_name_servers(name_servers) if name_servers
102
+ if web_forwardings
103
+ body['payload']['domain:webredirs'] = gandify_web_forwardings(web_forwardings)
104
+ end
105
+
106
+ GandiV5.patch url, body.to_json
107
+ refresh
108
+ end
109
+ # rubocop:enable Metrics/AbcSize
110
+
111
+ # Get information for a template.
112
+ # @see https://api.gandi.net/docs/template/#get-v5-template-templates-id
113
+ # @param uuid [String, #to_s] unique identifier of the template.
114
+ # @return [GandiV5::Template]
115
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
116
+ def self.fetch(uuid)
117
+ _response, data = GandiV5.get url(uuid)
118
+ from_gandi data
119
+ end
120
+
121
+ # List templates.
122
+ # @see https://api.gandi.net/docs/template/#get-v5-template-templates
123
+ # @param page [Integer, #each<Integer>] which page(s) of results to get.
124
+ # If page is not provided keep querying until an empty list is returned.
125
+ # If page responds to .each then iterate until an empty list is returned.
126
+ # @param per_page [Integer, #to_s] (optional default 100) how many results ot get per page.
127
+ # @return [Array<GandiV5::Template>]
128
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
129
+ def self.list(page: (1..), per_page: 100)
130
+ templates = []
131
+ GandiV5.paginated_get(url, page, per_page) do |data|
132
+ templates += data.map { |template| from_gandi template }
133
+ end
134
+ templates
135
+ end
136
+
137
+ # Create a new template.
138
+ # @see https://api.gandi.net/docs/template/#post-v5-template-templates
139
+ # @param name [String, #to_s] the name to give the created template.
140
+ # @param description [String, #to_s] description of what the template achieves.
141
+ # @param sharing_id [String] either:
142
+ # * nil (default) - nothing special happens,
143
+ # the template belongs to the user making the request.
144
+ # * an organization ID - the template will belong to the organization.
145
+ # * a reseller ID - the template will belong to the reseller.
146
+ # @param payload [Hash, #to_h]
147
+ # @option payload [Hash] 'dns:records' The DNS records to create (as Gandi's docs)
148
+ # @option payload [Hash] 'domain:mailboxes' The mailboxes to create (as Gandi's docs)
149
+ # @option payload [Hash] 'domain:nameservers' The name servers to create (as Gandi's docs)
150
+ # @option payload [Hash] 'domain:webredirs' The web redirects to create (as Gandi's docs)
151
+ # @option payload [Array<Hash>, :default] :dns_records
152
+ # Generate dns:records from the passed list or use Gandi's default records.
153
+ # @option dns_records [String] :name The name of the DNS record to create.
154
+ # @option dns_records [String] :type The type of the DNS record to create.
155
+ # @option dns_records [Array<String>] :values The values for the created DNS record.
156
+ # @option dns_records [Integer] :ttl The TTL for the created record (300-2592000)
157
+ # @option payload [Array<String>] :mailboxes
158
+ # Generate domain:mailboxes from the passed list of mail names.
159
+ # @option payload [Array<String>, :livedns] :name_servers
160
+ # Generate domain:nameservers from the passed list of addresses, or set to Gandi's livedns.
161
+ # @option payload [Array<Hash>] :web_forwardings Generate domain:webredirs from the passed list.
162
+ # @option web_forwardings [:cloak, :http301, :http302, :permanent, :temporary, :found] :type
163
+ # @option web_forwardings [String] :target
164
+ # @option web_forwardings [String] :host (optional)
165
+ # @option web_forwardings [Boolean] :override (optional, default false)
166
+ # When you create a redirection on a domain, a DNS record is created if it does not exist.
167
+ # When the record already exists and this parameter is set to true it will overwrite the
168
+ # record. Otherwise it will trigger an error.
169
+ # @option web_forwardings [:http, :https, :https_only] :protocol (optional)
170
+ # @return [GandiV5::Template] the created template
171
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error
172
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
173
+ def self.create(name:, description:, sharing_id: nil, **payload)
174
+ if payload.key? :dns_records
175
+ payload['dns:records'] = gandify_dns_records(payload.delete(:dns_records))
176
+ end
177
+ if payload.key? :mailboxes
178
+ payload['domain:mailboxes'] = gandify_mailboxes(payload.delete(:mailboxes))
179
+ end
180
+ if payload.key? :name_servers
181
+ payload['domain:nameservers'] = gandify_name_servers(payload.delete(:name_servers))
182
+ end
183
+ if payload.key? :web_forwardings
184
+ payload['domain:webredirs'] = gandify_web_forwardings(payload.delete(:web_forwardings))
185
+ end
186
+
187
+ url_ = sharing_id ? "#{url}?sharing_id=#{sharing_id}" : url
188
+ body = { name: name, description: description, payload: payload }.to_json
189
+
190
+ response, _data = GandiV5.post url_, body
191
+ fetch response.headers[:location].split('/').last
192
+ end
193
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
194
+
195
+ private
196
+
197
+ def self.gandify_dns_records(value)
198
+ if value == :default
199
+ { default: true }
200
+ else
201
+ {
202
+ default: false,
203
+ records: value
204
+ }
205
+ end
206
+ end
207
+ private_class_method :gandify_dns_records
208
+
209
+ def gandify_dns_records(value)
210
+ self.class.send :gandify_dns_records, value
211
+ end
212
+
213
+ def self.gandify_mailboxes(value)
214
+ { values: value.map { |name| { login: name } } }
215
+ end
216
+ private_class_method :gandify_mailboxes
217
+
218
+ def gandify_mailboxes(value)
219
+ self.class.send :gandify_mailboxes, value
220
+ end
221
+
222
+ def self.gandify_name_servers(value)
223
+ if value == :livedns
224
+ { service: :livedns }
225
+ else
226
+ {
227
+ service: :custom,
228
+ addresses: value
229
+ }
230
+ end
231
+ end
232
+ private_class_method :gandify_name_servers
233
+
234
+ def gandify_name_servers(value)
235
+ self.class.send :gandify_name_servers, value
236
+ end
237
+
238
+ def self.gandify_web_forwardings(value)
239
+ type_map = {
240
+ 'permanent' => 'http301',
241
+ 'temporary' => 'http302',
242
+ 'found' => 'http302'
243
+ }
244
+
245
+ {
246
+ values: value.map do |redirect|
247
+ type = redirect.fetch(:type).to_s
248
+ new_redirect = { type: type_map.fetch(type, type), url: redirect.fetch(:target) }
249
+ new_redirect[:host] = redirect[:host] if redirect.key?(:host)
250
+ new_redirect[:override] = redirect[:override] if redirect.key?(:override)
251
+ new_redirect[:protocol] = redirect[:protocol].to_s.delete('_') if redirect.key?(:protocol)
252
+ new_redirect
253
+ end
254
+ }
255
+ end
256
+ private_class_method :gandify_web_forwardings
257
+
258
+ def gandify_web_forwardings(value)
259
+ self.class.send :gandify_web_forwardings, value
260
+ end
261
+
262
+ def url
263
+ "#{BASE}template/templates/#{CGI.escape uuid}"
264
+ end
265
+
266
+ def self.url(uuid = nil)
267
+ "#{BASE}template/templates" + (uuid ? "/#{CGI.escape uuid}" : '')
268
+ end
269
+ private_class_method :url
270
+ end
271
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ class Template
5
+ # The current state of a template dispatch.
6
+ # @!attribute [r] uuid
7
+ # @return [String]
8
+ # @!attribute [r] template_uuid
9
+ # @return [String, nil]
10
+ # @!attribute [r] template_name
11
+ # @return [String, nil]
12
+ # @!attribute [r] target_uuid
13
+ # @return [String]
14
+ # @!attribute [r] attempt
15
+ # @return [Integer]
16
+ # @!attribute [r] created_at
17
+ # @return [Time]
18
+ # @!attribute [r] created_by
19
+ # @return [String] the UUID of the user who applied the template.
20
+ # @!attribute [r] updated_at
21
+ # @return [Time, nil]
22
+ # @!attribute [r] state
23
+ # @return [:pending, :running, :done, :error]
24
+ # @!attribute [r] state_message
25
+ # @return [String, nil]
26
+ # @!attribute [r] task_statuses
27
+ # @return [Array<Hash{Symbol => Synbol}>]
28
+ # maps namespace (e.g. :dns_records) to current status (e.g. :done)
29
+ # @!attribute [r] task_history
30
+ # @return [Array<Hash{:at => Time, :what => Symbol, :status => Symbol, :message => String}>]
31
+ # @!attribute [r] payload
32
+ # @return [Array<GandiV5::Template::Payload] the settings which will be applied
33
+ # when this template is used.
34
+ class Dispatch
35
+ include GandiV5::Data
36
+
37
+ members :attempt, :template_name
38
+ member :uuid, gandi_key: 'id'
39
+ member :template_uuid, gandi_key: 'template_id'
40
+ member :created_at, converter: GandiV5::Data::Converter::Time
41
+ member :created_by, gandi_key: 'sharing_id'
42
+ member :target_uuid, gandi_key: 'target_id'
43
+ member :state_message, gandi_key: 'state_msg'
44
+ member :updated_at, gandi_key: 'task_updated_at', converter: GandiV5::Data::Converter::Time
45
+ member :payload, converter: GandiV5::Template::Payload
46
+
47
+ member(
48
+ :state,
49
+ converter: GandiV5::Data::Converter.new(
50
+ from_gandi: lambda { |value|
51
+ values = { 0 => :pending, 10 => :running, 20 => :done, 30 => :error }
52
+ values.fetch(value)
53
+ }
54
+ )
55
+ )
56
+
57
+ member(
58
+ :task_statuses,
59
+ gandi_key: 'task_status',
60
+ converter: GandiV5::Data::Converter.new(
61
+ from_gandi: lambda { |hash|
62
+ keys = {
63
+ 'dns:records' => :dns_records,
64
+ 'domain:mailboxes' => :mailboxes,
65
+ 'domain:nameservers' => :name_servers,
66
+ 'domain:webredirs' => :web_forwardings
67
+ }
68
+ values = { 0 => :pending, 10 => :running, 20 => :done, 30 => :error }
69
+ hash.transform_keys { |key| keys.fetch(key) }
70
+ .transform_values { |value| values.fetch(value.fetch('status')) }
71
+ }
72
+ )
73
+ )
74
+
75
+ member(
76
+ :task_history,
77
+ converter: GandiV5::Data::Converter.new(
78
+ from_gandi: lambda { |array|
79
+ namespace = {
80
+ 'dns:records' => :dns_records,
81
+ 'domain:mailboxes' => :mailboxes,
82
+ 'domain:nameservers' => :name_servers,
83
+ 'domain:webredirs' => :web_forwardings
84
+ }
85
+ status = { 0 => :pending, 10 => :running, 20 => :done, 30 => :error }
86
+ array.map do |item|
87
+ {
88
+ at: Time.parse(item.fetch('date')),
89
+ what: namespace.fetch(item.fetch('namespace')),
90
+ status: status.fetch(item.fetch('status')),
91
+ message: item.fetch('message')
92
+ }
93
+ end
94
+ }
95
+ )
96
+ )
97
+
98
+ # Get a template dispatch.
99
+ # @see https://api.gandi.net/docs/template/#get-v5-template-dispatch-id
100
+ # @param uuid [String, #to_s] unique identifier of the dispatch.
101
+ # @return [GandiV5::Template::Dispatch]
102
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
103
+ def self.fetch(uuid)
104
+ _response, data = GandiV5.get "#{BASE}template/dispatch/#{CGI.escape uuid}"
105
+ from_gandi data
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class GandiV5
4
+ class Template
5
+ # Payload of a configuration template.
6
+ # @!attribute [r] dns_records
7
+ # @return [Array<GandiV5::Template::Payload::DNSRecord>, :default, nil]
8
+ # the DNS records this template will create.
9
+ # @!attribute [r] mailboxes
10
+ # @return [Array<String>, nil] the mailbox names (upto 2) which will be created.
11
+ # @!attribute [r] name_servers
12
+ # @return [Array<String>, :live_dns, nil] hosts to use as name servers for the domain.
13
+ # @!attribute [r] web_redirects
14
+ # @return [Array<GandiV5::Template::Payload::WebRedirect>, nil]
15
+ # what web redirects will be created.
16
+ class Payload
17
+ include GandiV5::Data
18
+
19
+ member(
20
+ :dns_records,
21
+ gandi_key: 'dns:records',
22
+ converter: GandiV5::Data::Converter.new(
23
+ from_gandi: lambda { |hash|
24
+ if hash['default']
25
+ :default
26
+ else
27
+ hash.fetch('records').map do |item|
28
+ GandiV5::Template::Payload::DNSRecord.from_gandi item
29
+ end
30
+ end
31
+ }
32
+ )
33
+ )
34
+
35
+ member(
36
+ :mailboxes,
37
+ gandi_key: 'domain:mailboxes',
38
+ converter: GandiV5::Data::Converter.new(
39
+ from_gandi: ->(h_a_h) { h_a_h.fetch('values').map { |h| h.fetch('login') } }
40
+ )
41
+ )
42
+
43
+ member(
44
+ :name_servers,
45
+ gandi_key: 'domain:nameservers',
46
+ converter: GandiV5::Data::Converter.new(
47
+ from_gandi: ->(h) { h.fetch('service').eql?('livedns') ? :livedns : h.fetch('addresses') }
48
+ )
49
+ )
50
+
51
+ member(
52
+ :web_forwardings,
53
+ gandi_key: 'domain:webredirs',
54
+ converter: GandiV5::Data::Converter.new(
55
+ from_gandi: lambda { |hash|
56
+ hash.fetch('values').map do |item|
57
+ GandiV5::Template::Payload::WebForwarding.from_gandi item
58
+ end
59
+ }
60
+ )
61
+ )
62
+ end
63
+ end
64
+ end