gandi_v5 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +44 -2
  5. data/Guardfile +5 -6
  6. data/README.md +5 -5
  7. data/doc/GandiV5/Billing/Info/Prepaid.html +817 -0
  8. data/doc/GandiV5/Billing/Info.html +641 -0
  9. data/doc/GandiV5/Billing.html +293 -0
  10. data/doc/GandiV5/Data/ClassMethods.html +223 -0
  11. data/doc/GandiV5/Data/Converter/ArrayOf.html +413 -0
  12. data/doc/GandiV5/Data/Converter/Symbol.html +322 -0
  13. data/doc/GandiV5/Data/Converter/Time.html +330 -0
  14. data/doc/GandiV5/Data/Converter.html +433 -0
  15. data/doc/GandiV5/Data.html +785 -0
  16. data/doc/GandiV5/Domain/AutoRenew.html +1237 -0
  17. data/doc/GandiV5/Domain/Availability/Product/Period.html +220 -0
  18. data/doc/GandiV5/Domain/Availability/Product/Price.html +1031 -0
  19. data/doc/GandiV5/Domain/Availability/Product.html +988 -0
  20. data/doc/GandiV5/Domain/Availability/Tax.html +440 -0
  21. data/doc/GandiV5/Domain/Availability.html +1020 -0
  22. data/doc/GandiV5/Domain/Contact.html +4459 -0
  23. data/doc/GandiV5/Domain/Contract.html +520 -0
  24. data/doc/GandiV5/Domain/Dates.html +1313 -0
  25. data/doc/GandiV5/Domain/RenewalInformation.html +1147 -0
  26. data/doc/GandiV5/Domain/RestoreInformation.html +339 -0
  27. data/doc/GandiV5/Domain/SharingSpace.html +437 -0
  28. data/doc/GandiV5/Domain/TLD.html +1565 -0
  29. data/doc/GandiV5/Domain.html +16847 -0
  30. data/doc/GandiV5/Email/Mailbox/Responder.html +1560 -0
  31. data/doc/GandiV5/Email/Mailbox.html +6307 -0
  32. data/doc/GandiV5/Email/Offer.html +514 -0
  33. data/doc/GandiV5/Email/Slot.html +4244 -0
  34. data/doc/GandiV5/Email.html +144 -0
  35. data/doc/GandiV5/Error/GandiError.html +270 -0
  36. data/doc/GandiV5/Error.html +151 -0
  37. data/doc/GandiV5/LiveDNS/Domain.html +2984 -0
  38. data/doc/GandiV5/LiveDNS/RecordSet.html +1593 -0
  39. data/doc/GandiV5/LiveDNS/Zone/Snapshot.html +1556 -0
  40. data/doc/GandiV5/LiveDNS/Zone.html +8891 -0
  41. data/doc/GandiV5/LiveDNS.html +300 -0
  42. data/doc/GandiV5/Organization.html +2341 -0
  43. data/doc/GandiV5.html +1183 -0
  44. data/doc/_index.html +474 -0
  45. data/doc/class_list.html +51 -0
  46. data/doc/css/common.css +1 -0
  47. data/doc/css/full_list.css +58 -0
  48. data/doc/css/style.css +496 -0
  49. data/doc/file.README.html +175 -0
  50. data/doc/file_list.html +56 -0
  51. data/doc/frames.html +17 -0
  52. data/doc/index.html +175 -0
  53. data/doc/js/app.js +303 -0
  54. data/doc/js/full_list.js +216 -0
  55. data/doc/js/jquery.js +4 -0
  56. data/doc/method_list.html +2427 -0
  57. data/doc/top-level-namespace.html +110 -0
  58. data/gandi_v5.gemspec +1 -1
  59. data/lib/gandi_v5/billing.rb +2 -2
  60. data/lib/gandi_v5/data.rb +2 -0
  61. data/lib/gandi_v5/domain/auto_renew.rb +4 -4
  62. data/lib/gandi_v5/domain/availability/product/period.rb +24 -0
  63. data/lib/gandi_v5/domain/availability/product/price.rb +36 -0
  64. data/lib/gandi_v5/domain/availability/product.rb +52 -0
  65. data/lib/gandi_v5/domain/availability/tax.rb +20 -0
  66. data/lib/gandi_v5/domain/availability.rb +49 -0
  67. data/lib/gandi_v5/domain/tld.rb +57 -0
  68. data/lib/gandi_v5/domain.rb +41 -86
  69. data/lib/gandi_v5/email/mailbox/responder.rb +43 -2
  70. data/lib/gandi_v5/email/mailbox.rb +32 -21
  71. data/lib/gandi_v5/email/offer.rb +2 -2
  72. data/lib/gandi_v5/email/slot.rb +42 -16
  73. data/lib/gandi_v5/error/gandi_error.rb +2 -2
  74. data/lib/gandi_v5/live_dns/domain.rb +59 -45
  75. data/lib/gandi_v5/live_dns/zone/snapshot.rb +27 -8
  76. data/lib/gandi_v5/live_dns/zone.rb +63 -59
  77. data/lib/gandi_v5/live_dns.rb +20 -0
  78. data/lib/gandi_v5/organization.rb +2 -2
  79. data/lib/gandi_v5/version.rb +1 -1
  80. data/lib/gandi_v5.rb +25 -5
  81. data/spec/features/domain_spec.rb +1 -1
  82. data/spec/fixtures/bodies/{GandiV5_Domain/availability.yaml → GandiV5_Domain_Availability/fetch.yaml} +0 -0
  83. data/spec/fixtures/bodies/{GandiV5_Domain/tld.yaml → GandiV5_Domain_TLD/fetch.yaml} +0 -0
  84. data/spec/fixtures/bodies/{GandiV5_Domain/tlds.yaml → GandiV5_Domain_TLD/list.yaml} +0 -0
  85. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/{get.yaml → fetch.yaml} +0 -0
  86. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yaml +3 -0
  87. data/spec/units/gandi_v5/billing_spec.rb +2 -2
  88. data/spec/units/gandi_v5/domain/auto_renew_spec.rb +5 -5
  89. data/spec/units/gandi_v5/domain/availability/product/period_spec.rb +4 -0
  90. data/spec/units/gandi_v5/domain/availability/product/price_spec.rb +4 -0
  91. data/spec/units/gandi_v5/domain/availability/product_spec.rb +4 -0
  92. data/spec/units/gandi_v5/domain/availability/tax_spec.rb +4 -0
  93. data/spec/units/gandi_v5/domain/availability_spec.rb +43 -0
  94. data/spec/units/gandi_v5/domain/tld_spec.rb +29 -0
  95. data/spec/units/gandi_v5/domain_spec.rb +89 -81
  96. data/spec/units/gandi_v5/email/mailbox/responder_spec.rb +52 -0
  97. data/spec/units/gandi_v5/email/mailbox_spec.rb +56 -27
  98. data/spec/units/gandi_v5/email/offer_spec.rb +1 -1
  99. data/spec/units/gandi_v5/email/slot_spec.rb +101 -13
  100. data/spec/units/gandi_v5/live_dns/domain_spec.rb +70 -40
  101. data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +32 -3
  102. data/spec/units/gandi_v5/live_dns/zone_spec.rb +68 -50
  103. data/spec/units/gandi_v5/live_dns_spec.rb +24 -0
  104. data/spec/units/gandi_v5/organization_spec.rb +1 -1
  105. data/spec/units/gandi_v5_spec.rb +37 -12
  106. metadata +72 -9
  107. data/TODO.md +0 -29
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: Allow enable/disable from here too ???
4
-
5
3
  class GandiV5
6
4
  class Email
7
5
  class Mailbox
@@ -15,13 +13,26 @@ class GandiV5
15
13
  # @return [nil, Time]
16
14
  # @!attribute [r] message
17
15
  # @return [nil, String]
16
+ # @!attribute [r] mailbox
17
+ # @return [GandiV5::Email::Mailbox] the mailbox this repsonder belongs to.
18
18
  class Responder
19
19
  include GandiV5::Data
20
20
 
21
+ attr_reader :mailbox
22
+
21
23
  members :enabled, :message
22
24
  member :starts_at, converter: GandiV5::Data::Converter::Time
23
25
  member :ends_at, converter: GandiV5::Data::Converter::Time
24
26
 
27
+ # Create a new GandiV5::Email::Mailbox::Responder
28
+ # @param mailbox [GandiV5::Email::Mailbox] the mailbox this responder belongs to.
29
+ # @param members [Hash<Symbol => Object>]
30
+ # @return [GandiV5::Email::Slot]
31
+ def initialize(mailbox: nil, **members)
32
+ super(**members)
33
+ @mailbox = mailbox
34
+ end
35
+
25
36
  # Check if this responder is currently active.
26
37
  # @return [Boolean] whether the responder is enabled,
27
38
  # started in the past and ends in the future.
@@ -30,6 +41,36 @@ class GandiV5
30
41
  (starts_at.nil? || starts_at < Time.now) &&
31
42
  (ends_at.nil? || ends_at > Time.now)
32
43
  end
44
+
45
+ # Enable the auto responder in Gandi.
46
+ # @param message [String]
47
+ # @param starts_at [Time]
48
+ # @param ends_at [Time]
49
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
50
+ def enable(message:, ends_at:, starts_at: Time.now)
51
+ mailbox.update responder: {
52
+ message: message,
53
+ starts_at: GandiV5::Data::Converter::Time.to_gandi(starts_at),
54
+ ends_at: GandiV5::Data::Converter::Time.to_gandi(ends_at),
55
+ enabled: true
56
+ }
57
+
58
+ self.starts_at = starts_at
59
+ self.ends_at = ends_at
60
+ self.message = message
61
+ self.enabled = true
62
+ end
63
+
64
+ # Disable the auto responder in Gandi.
65
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
66
+ def disable
67
+ mailbox.update responder: { enabled: false }
68
+
69
+ self.starts_at = nil
70
+ self.ends_at = nil
71
+ self.message = nil
72
+ self.enabled = false
73
+ end
33
74
  end
34
75
  end
35
76
  end
@@ -44,33 +44,43 @@ class GandiV5
44
44
 
45
45
  alias mailbox_uuid uuid
46
46
 
47
+ # Create a new GandiV5::Email::Mailbox
48
+ # @param members [Hash<Symbol => Object>]
49
+ # @return [GandiV5::Email::Slot]
50
+ def initialize(**members)
51
+ super(**members)
52
+ responder.instance_exec(self) { |mb| @mailbox = mb } if responder?
53
+ end
54
+
47
55
  # Delete the mailbox and it's contents.
48
56
  # If you delete a mailbox for which you have purchased a slot,
49
57
  # this action frees the slot so it once again becomes available
50
58
  # for use with a new mailbox, or for deletion.
51
59
  # @see https://api.gandi.net/docs/email#delete-v5-email-mailboxes-domain-mailbox_id
52
60
  # @return [String] The confirmation message from Gandi.
53
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
61
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
54
62
  def delete
55
- data = GandiV5.delete url
63
+ _response, data = GandiV5.delete url
56
64
  data['message']
57
65
  end
58
66
 
59
67
  # Purge the contents of the mailbox.
60
68
  # @see https://api.gandi.net/docs/email#delete-v5-email-mailboxes-domain-mailbox_id-contents
61
69
  # @return [String] The confirmation message from Gandi.
62
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
70
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
63
71
  def purge
64
- data = GandiV5.delete "#{url}/contents"
72
+ _response, data = GandiV5.delete "#{url}/contents"
65
73
  data['message']
66
74
  end
67
75
 
68
76
  # Requery Gandi fo this mailbox's information.
69
77
  # @return [GandiV5::Email::Mailbox]
70
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
78
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
71
79
  def refresh
72
- data = GandiV5.get url
80
+ _response, data = GandiV5.get url
73
81
  from_gandi data
82
+ responder.instance_exec(self) { |mb| @mailbox = mb } if responder?
83
+ self
74
84
  end
75
85
 
76
86
  # Update the mailbox's settings.
@@ -81,8 +91,7 @@ class GandiV5
81
91
  # @param responder [Hash, GandiV5::Mailbox::Responder, #to_gandi, #to_h]
82
92
  # auto responder settings.
83
93
  # @return [String] The confirmation message from Gandi.
84
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
85
- # rubocop:disable Metrics/AbcSize
94
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
86
95
  def update(**body)
87
96
  return 'Nothing to update.' if body.empty?
88
97
 
@@ -93,11 +102,10 @@ class GandiV5
93
102
  body[:responder] = responder.respond_to?(:to_gandi) ? responder.to_gandi : responder.to_h
94
103
  end
95
104
 
96
- data = GandiV5.patch url, body.to_json
105
+ _response, data = GandiV5.patch url, body.to_json
97
106
  refresh
98
107
  data['message']
99
108
  end
100
- # rubocop:enable Metrics/AbcSize
101
109
 
102
110
  # Create a new mailbox.
103
111
  # Note that before you can create a mailbox, you must have a slot available.
@@ -107,13 +115,16 @@ class GandiV5
107
115
  # @param password [String, #to_s] the password to use.
108
116
  # @param aliases [Array<String, #to_s>] any alternative email address to be used.
109
117
  # @param type [:standard, :premium] the type of mailbox slot to use.
110
- # @return [String] The confirmation message from Gandi.
111
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
112
- # TODO: Fetch created mailbox
118
+ # @return [GandiV5::Email::Mailbox] The created mailbox.
119
+ # @raise [GandiV5::Error] if no slots are available.
120
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
113
121
  def self.create(fqdn, login, password, aliases: [], type: :standard)
114
- # TODO: Check type is valid
122
+ fail ArgumentError, "#{type.inspect} is not a valid type" unless TYPES.include?(type)
123
+ if GandiV5::Email::Slot.list.none? { |slot| slot.mailbox_type == type && slot.inactive? }
124
+ fail GandiV5::Error, "no available #{type} slots"
125
+ end
126
+
115
127
  check_password password
116
- # TODO: Check if a slot is available
117
128
 
118
129
  body = {
119
130
  mailbox_type: type,
@@ -122,8 +133,8 @@ class GandiV5
122
133
  aliases: aliases.push
123
134
  }.to_json
124
135
 
125
- data = GandiV5.post url(fqdn), body
126
- data['message']
136
+ response, _data = GandiV5.post url(fqdn), body
137
+ fetch fqdn, response.headers[:location].split('/').last
127
138
  end
128
139
 
129
140
  # Get information for a mailbox.
@@ -131,9 +142,9 @@ class GandiV5
131
142
  # @param fqdn [String, #to_s] the fully qualified domain name for the mailbox.
132
143
  # @param uuid [String, #to_s] unique identifier of the mailbox.
133
144
  # @return [GandiV5::Email::Mailbox]
134
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
145
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
135
146
  def self.fetch(fqdn, uuid)
136
- data = GandiV5.get url(fqdn, uuid)
147
+ _response, data = GandiV5.get url(fqdn, uuid)
137
148
  from_gandi data
138
149
  end
139
150
 
@@ -149,7 +160,7 @@ class GandiV5
149
160
  # @param login [String] (optional) filter the list by login (pattern)
150
161
  # e.g. ("alice" "*lice", "alic*").
151
162
  # @return [Array<GandiV5::Email::Mailbox>]
152
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
163
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
153
164
  def self.list(fqdn, page: (1..), **params)
154
165
  page = [page.to_i] unless page.respond_to?(:each)
155
166
 
@@ -158,7 +169,7 @@ class GandiV5
158
169
 
159
170
  mailboxes = []
160
171
  page.each do |page_number|
161
- data = GandiV5.get url(fqdn), params: params.merge(page: page_number)
172
+ _response, data = GandiV5.get url(fqdn), params: params.merge(page: page_number)
162
173
  break if data.empty?
163
174
 
164
175
  mailboxes += data.map { |mailbox| from_gandi mailbox }
@@ -17,9 +17,9 @@ class GandiV5
17
17
  # @see https://api.gandi.net/docs/email#get-v5-email-offers-domain
18
18
  # @param fqdn [String, #to_s] the fully qualified domain name to get the offer for.
19
19
  # @return [GandiV5::Email::Offer]
20
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
20
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
21
21
  def self.fetch(fqdn)
22
- data = GandiV5.get "#{BASE}email/offers/#{CGI.escape fqdn}"
22
+ _response, data = GandiV5.get "#{BASE}email/offers/#{CGI.escape fqdn}"
23
23
  from_gandi data
24
24
  end
25
25
  end
@@ -39,12 +39,12 @@ class GandiV5
39
39
  alias slot_id id
40
40
 
41
41
  # Create a new GandiV5::Email::Slot
42
- # @param string [fqdn] the fully qualified domain this slot belongs to.
42
+ # @param fqdn [String] the fully qualified domain this slot belongs to.
43
43
  # @param members [Hash<Symbol => Object>]
44
44
  # @return [GandiV5::Email::Slot]
45
45
  def initialize(fqdn: nil, **members)
46
46
  super(**members)
47
- @fqdn = fqdn if fqdn
47
+ @fqdn = fqdn
48
48
  end
49
49
 
50
50
  # Delete this slot if it is inactive and refundable.
@@ -53,20 +53,23 @@ class GandiV5
53
53
  # @see GandiV5::Email::Mailbox#delete
54
54
  # @see https://api.gandi.net/docs/email#delete-v5-email-slots-domain-slot_id
55
55
  # @return [String] The confirmation message from Gandi.
56
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
57
- # TODO: check for inactiveness
58
- # TODO: check for refundableness
56
+ # @raise [GandiV5::Error] if slot is active.
57
+ # @raise [GandiV5::Error] if slot is not refundable.
58
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
59
59
  def delete
60
- data = GandiV5.delete url
60
+ fail GandiV5::Error, 'slot can\'t be deleted whilst active' if active?
61
+ fail GandiV5::Error, 'slot can\'t be deleted if it\'s not refundable' unless refundable
62
+
63
+ _response, data = GandiV5.delete url
61
64
  data['message']
62
65
  end
63
66
 
64
67
  # Requery Gandi for this slot's information.
65
68
  # @see https://api.gandi.net/docs/email#get-v5-email-slots-domain-slot_id
66
69
  # @return [GandiV5::Email::Slot]
67
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
70
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
68
71
  def refresh
69
- data = GandiV5.get url
72
+ _response, data = GandiV5.get url
70
73
  from_gandi data
71
74
  end
72
75
 
@@ -77,15 +80,14 @@ class GandiV5
77
80
  # @param fqdn [String, #to_s] the fully qualified domain name to add the slot to.
78
81
  # @param type [:standard, :premium] Tyhe type of slot to add.
79
82
  # @return [String] The confirmation message from Gandi.
80
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
81
- # TODO: Fetch created slot
83
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
82
84
  def self.create(fqdn, type = :standard)
83
85
  body = {
84
86
  mailbox_type: type
85
87
  }.to_json
86
88
 
87
- data = GandiV5.post url(fqdn), body
88
- data['message']
89
+ response, _data = GandiV5.post url(fqdn), body
90
+ fetch fqdn, response.headers[:location].split('/').last
89
91
  end
90
92
 
91
93
  # Get information for a slot.
@@ -93,9 +95,9 @@ class GandiV5
93
95
  # @param fqdn [String, #to_s] the fully qualified domain name the slot is on.
94
96
  # @param id [String, #to_s] the ID of the slot to fetch.
95
97
  # @return [GandiV5::Email::Slot]
96
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
98
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
97
99
  def self.fetch(fqdn, id)
98
- data = GandiV5.get url(fqdn, id)
100
+ _response, data = GandiV5.get url(fqdn, id)
99
101
  slot = from_gandi data
100
102
  slot.instance_eval { @fqdn = fqdn }
101
103
  slot
@@ -105,9 +107,9 @@ class GandiV5
105
107
  # @see https://api.gandi.net/docs/email#
106
108
  # @param fqdn [String, #to_s] the fully qualified domain name to list slots for.
107
109
  # @return [Array<GandiV5::Email::Slot>]
108
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
110
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
109
111
  def self.list(fqdn)
110
- data = GandiV5.get url(fqdn)
112
+ _response, data = GandiV5.get url(fqdn)
111
113
  data.map { |item| from_gandi item }
112
114
  .each { |item| item.instance_eval { @fqdn = fqdn } }
113
115
  end
@@ -118,6 +120,30 @@ class GandiV5
118
120
  status.eql?(:active)
119
121
  end
120
122
 
123
+ # Check if the slot is inactive (not in use)
124
+ # @return [Boolean]
125
+ def inactive?
126
+ status.eql?(:inactive)
127
+ end
128
+
129
+ # Check if the slot's mailbox_type is :free
130
+ # @return [Boolean]
131
+ def free?
132
+ mailbox_type.eql?(:free)
133
+ end
134
+
135
+ # Check if the slot's mailbox_type is :standard
136
+ # @return [Boolean]
137
+ def standard?
138
+ mailbox_type.eql?(:standard)
139
+ end
140
+
141
+ # Check if the slot's mailbox_type is :premium
142
+ # @return [Boolean]
143
+ def premium?
144
+ mailbox_type.eql?(:premium)
145
+ end
146
+
121
147
  private
122
148
 
123
149
  def url
@@ -4,9 +4,9 @@ class GandiV5
4
4
  class Error < RuntimeError
5
5
  # Generic error class for errors returned by Gandi.
6
6
  class GandiError < GandiV5::Error
7
- # Generate a new GandiV5::Error::GandiError::GandiError from the hash returned by Gandi.
7
+ # Generate a new GandiV5::Error::GandiError from the hash returned by Gandi.
8
8
  # @param hash [Hash] the hash returned by Gandi.
9
- # @return [GandiV5::Error::GandiError::GandiError]
9
+ # @return [GandiV5::Error::GandiError]
10
10
  def self.from_hash(hash)
11
11
  hash['errors'] ||= []
12
12
 
@@ -20,9 +20,9 @@ class GandiV5
20
20
 
21
21
  # Refetch the information for this domain from Gandi.
22
22
  # @return [GandiV5::LiveDNS::Domain]
23
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
23
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
24
24
  def refresh
25
- data = GandiV5.get url
25
+ _response, data = GandiV5.get url
26
26
  from_gandi data
27
27
  end
28
28
 
@@ -36,7 +36,7 @@ class GandiV5
36
36
  # @param name [String] the name to fetch records for.
37
37
  # @param type [String] the record type to fetch.
38
38
  # @return [Array<GandiV5::LiveDNS::RecordSet>]
39
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
39
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
40
40
  def fetch_records(name = nil, type = nil)
41
41
  GandiV5::LiveDNS.require_valid_record_type type if type
42
42
 
@@ -44,7 +44,7 @@ class GandiV5
44
44
  url_ += "/#{CGI.escape name}" if name
45
45
  url_ += "/#{CGI.escape type}" if type
46
46
 
47
- data = GandiV5.get url_
47
+ _response, data = GandiV5.get url_
48
48
  data = [data] unless data.is_a?(Array)
49
49
  data.map { |item| GandiV5::LiveDNS::RecordSet.from_gandi item }
50
50
  end
@@ -59,7 +59,7 @@ class GandiV5
59
59
  # @param name [String] the name to fetch records for.
60
60
  # @param type [String] the record type to fetch.
61
61
  # @return [String]
62
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
62
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
63
63
  def fetch_zone_lines(name = nil, type = nil)
64
64
  GandiV5::LiveDNS.require_valid_record_type type if type
65
65
 
@@ -67,7 +67,7 @@ class GandiV5
67
67
  url_ += "/#{CGI.escape name}" if name
68
68
  url_ += "/#{CGI.escape type}" if type
69
69
 
70
- GandiV5.get url_, accept: 'text/plain'
70
+ GandiV5.get(url_, accept: 'text/plain').last
71
71
  end
72
72
 
73
73
  # Add record to this domain.
@@ -76,7 +76,7 @@ class GandiV5
76
76
  # @param ttl [Integer]
77
77
  # @param values [Array<String>]
78
78
  # @return [String] The confirmation message from Gandi.
79
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
79
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
80
80
  def add_record(name, type, ttl, *values)
81
81
  GandiV5::LiveDNS.require_valid_record_type type
82
82
  fail ArgumentError, 'ttl must be positive and non-zero' unless ttl.positive?
@@ -88,7 +88,7 @@ class GandiV5
88
88
  rrset_ttl: ttl,
89
89
  rrset_values: values
90
90
  }.to_json
91
- data = GandiV5.post "#{url}/records", body
91
+ _response, data = GandiV5.post "#{url}/records", body
92
92
  data['message']
93
93
  end
94
94
 
@@ -102,14 +102,14 @@ class GandiV5
102
102
  # @param name [String] the name to delete records for.
103
103
  # @param type [String] the record type to delete.
104
104
  # @return [nil]
105
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
105
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
106
106
  def delete_records(name = nil, type = nil)
107
107
  GandiV5::LiveDNS.require_valid_record_type(type) if type
108
108
 
109
109
  url_ = "#{url}/records"
110
110
  url_ += "/#{CGI.escape name}" if name
111
111
  url_ += "/#{CGI.escape type}" if type
112
- GandiV5.delete url_
112
+ GandiV5.delete(url_).last
113
113
  end
114
114
 
115
115
  # Replace all records for this domain.
@@ -119,7 +119,7 @@ class GandiV5
119
119
  # @param text [String] zone file lines to replace the records with.
120
120
  # @return [String] The confirmation message from Gandi.
121
121
  # @raise [ArgumentError] if neither/both of records & test are passed.
122
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
122
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
123
123
  def replace_records(records: nil, text: nil)
124
124
  unless [records, text].count(&:nil?).eql?(1)
125
125
  fail ArgumentError, 'you must pass ONE of records: or text:'
@@ -129,70 +129,84 @@ class GandiV5
129
129
  body = {
130
130
  items: records.map { |r| r.transform_keys { |k| "rrset_#{k}" } }
131
131
  }.to_json
132
- data = GandiV5.put "#{url}/records", body
132
+ _response, data = GandiV5.put "#{url}/records", body
133
133
  elsif text
134
- data = GandiV5.put "#{url}/records", text, 'content-type': 'text/plain'
134
+ _response, data = GandiV5.put "#{url}/records", text, 'content-type': 'text/plain'
135
135
  end
136
136
  data['message']
137
137
  end
138
138
 
139
- # Replace records for a name in this domain.
140
- # @param name [String]
141
- # @param records
142
- # [Array<Hash<type: String, ttl: Integer, values: Array<String>>>]
143
- # the records to add.
139
+ # @override replace_records_for(name, records)
140
+ # Replace records for a name in this domain.
141
+ # @param name [String]
142
+ # @param records
143
+ # [Array<Hash<type: String, ttl: Integer, values: Array<String>>>]
144
+ # the records to add.
145
+ # @override replace_records_for(name, values, type: nil, ttl: nil)
146
+ # Replace records for a name in this domain.
147
+ # @param name [String]
148
+ # @param type [String] the record type.
149
+ # @param ttl [Integer] the TTL to set for the record.
150
+ # @param values [Array<String>] the values to set for the record.
151
+ # @raise [ArgumentError] if ttl is present and type is absent.
144
152
  # @return [String] The confirmation message from Gandi.
145
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
146
- def replace_records_for(name, *records)
147
- body = {
148
- items: records.map { |r| r.transform_keys { |k| "rrset_#{k}" } }
149
- }.to_json
150
- data = GandiV5.put "#{url}/records/#{name}", body
151
- data['message']
152
- end
153
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
154
+ def replace_records_for(name, records, type: nil, ttl: nil)
155
+ fail ArgumentError, 'missing keyword: type' if ttl && type.nil?
156
+
157
+ if type
158
+ GandiV5::LiveDNS.require_valid_record_type type
159
+ body = { rrset_values: records, rrset_ttl: ttl }
160
+ # body[:rrset_ttl] = ttl if ttl
161
+ _response, data = GandiV5.put "#{url}/records/#{name}/#{type}", body.to_json
153
162
 
154
- GandiV5::LiveDNS::RECORD_TYPES.each do |type|
155
- # Replace records of a given type for a name in this domain.
156
- # TODO: @param name [Type] description.
157
- # TODO: @param ttl [Type] description.
158
- # TODO: documentation for *values
159
- # @return [String] The confirmation message from Gandi.
160
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
161
- define_method "replace_#{type.downcase}_records_for" do |name, ttl, *values|
163
+ else
162
164
  body = {
163
- rrset_ttl: ttl,
164
- rrset_values: values
165
- }.to_json
166
- data = GandiV5.put "#{url}/records/#{name}/#{type}", body
167
- data['message']
165
+ items: records.map { |r| r.transform_keys { |k| "rrset_#{k}" } }
166
+ }
167
+ _response, data = GandiV5.put "#{url}/records/#{name}", body.to_json
168
168
  end
169
+
170
+ data['message']
169
171
  end
170
172
 
171
173
  # Change the zone used by this domain.
172
174
  # @param uuid [String, #uuid, #to_s] the UUID of the zone this domain should now use.
173
175
  # @return [String] The confirmation message from Gandi.
174
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
176
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
175
177
  def change_zone(uuid)
176
178
  uuid = uuid.uuid if uuid.respond_to?(:uuid)
177
- data = GandiV5.patch url, { zone_uuid: uuid }.to_json
179
+ _response, data = GandiV5.patch url, { zone_uuid: uuid }.to_json
178
180
  self.zone_uuid = uuid
179
181
  data['message']
180
182
  end
181
183
 
184
+ # @see GandiV5::LiveDNS::Zone.fetch
185
+ def fetch_zone
186
+ GandiV5::LiveDNS::Zone.fetch zone_uuid
187
+ end
188
+
189
+ # The domain's zone (fetching from Gandi if required).
190
+ # @return [GandiV5::LiveDNS::Zone]
191
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
192
+ def zone
193
+ @zone ||= fetch_zone
194
+ end
195
+
182
196
  # List the domains.
183
197
  # @return [Array<GandiV5::LiveDNS::Domain>]
184
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
198
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
185
199
  def self.list
186
- data = GandiV5.get url
200
+ _response, data = GandiV5.get url
187
201
  data.map { |item| from_gandi item }
188
202
  end
189
203
 
190
204
  # Get a domain.
191
205
  # @param fqdn [String, #to_s] the fully qualified domain name to fetch.
192
206
  # @return [GandiV5::LiveDNS::Domain]
193
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
207
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
194
208
  def self.fetch(fqdn)
195
- data = GandiV5.get url(fqdn)
209
+ _response, data = GandiV5.get url(fqdn)
196
210
  from_gandi data
197
211
  end
198
212
 
@@ -28,32 +28,51 @@ class GandiV5
28
28
 
29
29
  # Delete this snapshot.
30
30
  # @return [String] The confirmation message from Gandi.
31
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
31
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
32
32
  def delete
33
- data = GandiV5.delete url
33
+ _response, data = GandiV5.delete url
34
34
  data['message']
35
35
  end
36
36
 
37
+ # @see GandiV5::LiveDNS::Zone.fetch
38
+ def fetch_zone
39
+ GandiV5::LiveDNS::Zone.fetch zone_uuid
40
+ end
41
+
42
+ # The snapshot's zone (fetching from Gandi if required).
43
+ # @return [GandiV5::LiveDNS::Zone]
44
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
45
+ def zone
46
+ @zone ||= fetch_zone
47
+ end
48
+
49
+ # Get snapshot UUIDs for this zone from Gandi.
50
+ # @return [Hash{String => Time}] Mapping UUID to time made.
51
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
52
+ def self.list(zone_uuid)
53
+ _response, data = GandiV5.get url(zone_uuid)
54
+ Hash[data.map { |snapshot| [snapshot['uuid'], Time.parse(snapshot['date_created'])] }]
55
+ end
56
+
37
57
  # Get snapshot from Gandi.
38
58
  # @param zone_uuid [String, #to_s] the UUID of the zone the snapshot was made of.
39
59
  # @param snapshot_uuid [String, #to_s] the UUID of the snapshot to fetch.
40
60
  # @return [GandiV5::LiveDNS::Zone::Snapshot]
41
- # @raise [GandiV5::Error::GandiError::GandiError] if Gandi returns an error.
61
+ # @raise [GandiV5::Error::GandiError] if Gandi returns an error.
42
62
  def self.fetch(zone_uuid, snapshot_uuid)
43
- data = GandiV5.get url(zone_uuid, snapshot_uuid)
63
+ _response, data = GandiV5.get url(zone_uuid, snapshot_uuid)
44
64
  from_gandi data
45
65
  end
46
66
 
47
- # TODO: Move listing snapshots to here
48
-
49
67
  private
50
68
 
51
69
  def url
52
70
  "#{BASE}zones/#{CGI.escape zone_uuid}/snapshots/#{CGI.escape uuid}"
53
71
  end
54
72
 
55
- def self.url(zone_uuid, snapshot_uuid)
56
- "#{BASE}zones/#{CGI.escape zone_uuid}/snapshots/#{CGI.escape snapshot_uuid}"
73
+ def self.url(zone_uuid, snapshot_uuid = nil)
74
+ "#{BASE}zones/#{CGI.escape zone_uuid}/snapshots" +
75
+ (snapshot_uuid ? "/#{CGI.escape snapshot_uuid}" : '')
57
76
  end
58
77
  private_class_method :url
59
78
  end