gandi_v5 0.9.1 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
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