gandi_v5 0.8.0 → 0.9.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -9
  3. data/README.md +54 -10
  4. data/lib/gandi_v5.rb +112 -66
  5. data/lib/gandi_v5/billing/info/prepaid.rb +1 -0
  6. data/lib/gandi_v5/data.rb +1 -0
  7. data/lib/gandi_v5/data/converter.rb +3 -2
  8. data/lib/gandi_v5/data/converter/array_of.rb +3 -2
  9. data/lib/gandi_v5/data/converter/integer.rb +3 -2
  10. data/lib/gandi_v5/data/converter/symbol.rb +3 -2
  11. data/lib/gandi_v5/data/converter/time.rb +3 -2
  12. data/lib/gandi_v5/domain.rb +9 -6
  13. data/lib/gandi_v5/domain/availability/product/period.rb +1 -1
  14. data/lib/gandi_v5/domain/contact.rb +5 -5
  15. data/lib/gandi_v5/domain/tld.rb +2 -2
  16. data/lib/gandi_v5/domain/transfer_in.rb +170 -0
  17. data/lib/gandi_v5/domain/transfer_in/availability.rb +51 -0
  18. data/lib/gandi_v5/email.rb +1 -0
  19. data/lib/gandi_v5/email/mailbox.rb +1 -1
  20. data/lib/gandi_v5/error/gandi_error.rb +1 -0
  21. data/lib/gandi_v5/live_dns.rb +2 -0
  22. data/lib/gandi_v5/live_dns/domain.rb +28 -1
  23. data/lib/gandi_v5/live_dns/domain/dnssec_key.rb +16 -11
  24. data/lib/gandi_v5/live_dns/domain/snapshot.rb +4 -0
  25. data/lib/gandi_v5/live_dns/domain/tsig_key.rb +7 -4
  26. data/lib/gandi_v5/simple_hosting.rb +1 -0
  27. data/lib/gandi_v5/simple_hosting/instance.rb +3 -0
  28. data/lib/gandi_v5/simple_hosting/instance/application.rb +1 -0
  29. data/lib/gandi_v5/simple_hosting/instance/database.rb +1 -0
  30. data/lib/gandi_v5/simple_hosting/instance/language.rb +1 -1
  31. data/lib/gandi_v5/simple_hosting/instance/upgrade.rb +1 -0
  32. data/lib/gandi_v5/simple_hosting/instance/virtual_host.rb +2 -2
  33. data/lib/gandi_v5/simple_hosting/instance/virtual_host/linked_dns_zone.rb +1 -0
  34. data/lib/gandi_v5/version.rb +1 -1
  35. data/spec/features/list_domain_renewals_spec.rb +16 -0
  36. data/spec/features/list_email_addresses_spec.rb +39 -0
  37. data/spec/fixtures/bodies/GandiV5_Domain_TransferIn/fetch.yml +21 -0
  38. data/spec/fixtures/bodies/GandiV5_Domain_TransferIn_Availability/fetch.yml +10 -0
  39. data/spec/fixtures/vcr/Examples/List_domain_renewals.yml +54 -0
  40. data/spec/fixtures/vcr/Examples/List_email_addresses.yml +103 -0
  41. data/spec/units/gandi_v5/domain/transfer_in/availability_spec.rb +49 -0
  42. data/spec/units/gandi_v5/domain/transfer_in_spec.rb +143 -0
  43. metadata +127 -20
  44. data/.gitignore +0 -26
  45. data/.rspec +0 -3
  46. data/.rubocop.yml +0 -74
  47. data/.travis.yml +0 -38
  48. data/FUNDING.yml +0 -10
  49. data/Gemfile +0 -6
  50. data/Guardfile +0 -39
  51. data/Rakefile +0 -3
  52. data/bin/console +0 -13
  53. data/gandi_v5.gemspec +0 -42
@@ -4,6 +4,7 @@ class GandiV5
4
4
  class SimpleHosting
5
5
  class Instance
6
6
  class VirtualHost
7
+ # A DNS Zone linked to a virtual host on a simple hosting instance.
7
8
  # @!attribute [r] allow_zone_alteration
8
9
  # @return [Boolean]
9
10
  # @!attribute [r] cname
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GandiV5
4
- VERSION = '0.8.0'
4
+ VERSION = '0.9.0'
5
5
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Examples', :vcr do
4
+ it 'List domain renewals' do
5
+ expect(STDOUT).to receive(:puts).with("2021-03-12\t£8.87\texample.com")
6
+
7
+ # For each domain (sorted by assending renewal date) print <date>\t<cost>\t<fqdn>
8
+ GandiV5::Domain.list.each do |domain|
9
+ puts [
10
+ domain.dates.registry_ends_at.to_date,
11
+ "£#{domain.renewal_price.price_after_taxes}",
12
+ domain.fqdn
13
+ ].join("\t")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe 'Examples', :vcr do
4
+ it 'List email addresses' do
5
+ expect(STDOUT).to receive(:puts).with("alias@example.com\talias for user@example.com").ordered
6
+ expect(STDOUT).to receive(:puts).with("forward@example.com\tforwards to user@example.com").ordered
7
+ expect(STDOUT).to receive(:puts).with("user@example.com\tstandard mailbox (0% of 3GB used)").ordered
8
+
9
+ # For each domain:
10
+ # 1. Create an empty hash to store address => description
11
+ # 2. Get the mailboxes and add them to the hash
12
+ # 3. Get the forwards and add them to the hash
13
+ # 4. Sort the hash by email address
14
+ # 5. Print the list
15
+ GandiV5::Domain.list.each do |domain|
16
+ emails = {}
17
+
18
+ mailboxes = GandiV5::Email::Mailbox.list(domain.fqdn)
19
+ mailboxes.each do |mailbox|
20
+ mailbox.refresh
21
+ emails["#{mailbox.login}@#{domain.fqdn}"] = "#{mailbox.type} mailbox " \
22
+ "(#{mailbox.quota_usage.to_i}% " \
23
+ "of #{(mailbox.quota / 1024**3).round}GB used)"
24
+ mailbox.aliases.each do |alias_name|
25
+ emails["#{alias_name}@#{domain.fqdn}"] = "alias for #{mailbox.login}@#{domain.fqdn}"
26
+ end
27
+ end
28
+
29
+ forwards = GandiV5::Email::Forward.list(domain.fqdn)
30
+ forwards.each do |forward|
31
+ emails["#{forward.source}@#{domain.fqdn}"] = "forwards to #{forward.destinations.join(', ')}"
32
+ end
33
+
34
+ emails.sort.each do |address, text|
35
+ puts "#{address}\t#{text}"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ ---
2
+ created_at: '2011-02-21T10:39:00Z'
3
+ owner_contact: owner contact
4
+ params:
5
+ domain: example.com
6
+ duration: 1
7
+ reseller: reseller-uuid
8
+ tld: com
9
+ version: 0
10
+ step: step text
11
+ step_nb: 2
12
+ updated_at: '2011-02-22T10:39:00Z'
13
+ errortype: error-type
14
+ errortype_label: error label
15
+ foa:
16
+ - answer: ans
17
+ email: user@example.com
18
+ inner_step: inner-step
19
+ regac_at: '2011-02-23T10:39:00Z'
20
+ start_at: '2011-02-24T10:39:00Z'
21
+ transfer_procedure: transfer-procedure
@@ -0,0 +1,10 @@
1
+ ---
2
+ available: true
3
+ fqdn: example.com
4
+ fqdn_ulabel: EXAMPLE.COM
5
+ corporate: false
6
+ internal: false
7
+ durations: [1, 2, 3]
8
+ minimum_duration: 1
9
+ maximum_duration: 3
10
+ msg: This is a message
@@ -0,0 +1,54 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.gandi.net/v5/domain/domains?page=1&per_page=100
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Authorization:
13
+ - Apikey abdce12345
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Content-Type:
20
+ - application/json; charset=utf-8
21
+ Content-Length:
22
+ - '461'
23
+ body:
24
+ encoding: UTF-8
25
+ string: '[{"status":[],"dates":{"created_at":"2011-02-21T10:39:00Z","registry_created_at":"2003-03-12T12:02:11Z","registry_ends_at":"2021-03-12T12:02:11Z","updated_at":"2020-03-25T17:06:34Z"},"tags":[],"fqdn":"example.com","id":"domain-uuid","autorenew":false,"tld":"com","owner":"Mr. Example","orga_owner":"Example Org","domain_owner":"Owner","nameserver":{"current":"livedns"},"href":"https://api.gandi.net/v5/domain/domains/example.com","fqdn_unicode":"example.com"}]'
26
+ recorded_at: Mon, 17 Aug 2020 16:02:51 GMT
27
+
28
+ - request:
29
+ method: get
30
+ uri: https://api.gandi.net/v5/domain/check?currency=GBP&name=example.com&period=1&processes%5B%5D=renew
31
+ body:
32
+ encoding: US-ASCII
33
+ string: ''
34
+ headers:
35
+ Accept:
36
+ - application/json
37
+ Authorization:
38
+ - Apikey abcde12345
39
+ response:
40
+ status:
41
+ code: 200
42
+ message: OK
43
+ headers:
44
+ Content-Type:
45
+ - application/json; charset=utf-8
46
+ Content-Length:
47
+ - '353'
48
+ body:
49
+ encoding: UTF-8
50
+ string: '{"currency":"GBP","products":[{"name":"example.com","taxes":[{"rate":20,"name":"vat","type":"service"}],"process":"renew","prices":[{"min_duration":1,"discount":false,"price_after_taxes":8.87,"max_duration":9,"price_before_taxes":7.39,"duration_unit":"y"}],"status":"unavailable"}],"grid":"A","taxes":[{"rate":20,"name":"vat","type":"service"}]}'
51
+ http_version:
52
+ recorded_at: Mon, 17 Aug 2020 16:53:54 GMT
53
+
54
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,103 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://api.gandi.net/v5/domain/domains?page=1&per_page=100
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Authorization:
13
+ - Apikey abdce12345
14
+ response:
15
+ status:
16
+ code: 200
17
+ message: OK
18
+ headers:
19
+ Content-Type:
20
+ - application/json; charset=utf-8
21
+ Content-Length:
22
+ - '461'
23
+ body:
24
+ encoding: UTF-8
25
+ string: '[{"status":[],"dates":{"created_at":"2011-02-21T10:39:00Z","registry_created_at":"2003-03-12T12:02:11Z","registry_ends_at":"2021-03-12T12:02:11Z","updated_at":"2020-03-25T17:06:34Z"},"tags":[],"fqdn":"example.com","id":"domain-uuid","autorenew":false,"tld":"com","owner":"Mr. Example","orga_owner":"Example Org","domain_owner":"Owner","nameserver":{"current":"livedns"},"href":"https://api.gandi.net/v5/domain/domains/example.com","fqdn_unicode":"example.com"}]'
26
+ recorded_at: Mon, 17 Aug 2020 16:02:51 GMT
27
+
28
+ - request:
29
+ method: get
30
+ uri: https://api.gandi.net/v5/email/mailboxes/example.com?page=1&per_page=100
31
+ body:
32
+ encoding: US-ASCII
33
+ string: ''
34
+ headers:
35
+ Accept:
36
+ - application/json
37
+ Authorization:
38
+ - Apikey abdce12345
39
+ response:
40
+ status:
41
+ code: 200
42
+ message: OK
43
+ headers:
44
+ Content-Type:
45
+ - application/json; charset=utf-8
46
+ Content-Length:
47
+ - '284'
48
+ body:
49
+ encoding: UTF-8
50
+ string: '[{"responder":{"message":"","enabled":false},"mailbox_type":"standard","login":"user","quota_used":3597,"domain":"example.com","aliases":["alias"],"address":"user@example.com","href":"https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid","id":"mailbox-uuid"}]'
51
+ recorded_at: Mon, 17 Aug 2020 16:02:51 GMT
52
+
53
+ - request:
54
+ method: get
55
+ uri: https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid
56
+ body:
57
+ encoding: US-ASCII
58
+ string: ''
59
+ headers:
60
+ Accept:
61
+ - application/json
62
+ Authorization:
63
+ - Apikey abdce12345
64
+ response:
65
+ status:
66
+ code: 200
67
+ message: OK
68
+ headers:
69
+ Content-Type:
70
+ - application/json; charset=utf-8
71
+ Content-Length:
72
+ - '270'
73
+ body:
74
+ encoding: UTF-8
75
+ string: '{"responder":{"message":"","enabled":false},"mailbox_type":"standard","login":"user","quota_used":3597,"domain":"example.com","aliases":["alias"],"address":"user@example.com","href":"https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid","id":"mailbox-uuid"}'
76
+ recorded_at: Mon, 17 Aug 2020 16:17:50 GMT
77
+
78
+ - request:
79
+ method: get
80
+ uri: https://api.gandi.net/v5/email/forwards/example.com?page=1&per_page=100
81
+ body:
82
+ encoding: US-ASCII
83
+ string: ''
84
+ headers:
85
+ Accept:
86
+ - application/json
87
+ Authorization:
88
+ - Apikey abdce12345
89
+ response:
90
+ status:
91
+ code: 200
92
+ message: OK
93
+ headers:
94
+ Content-Type:
95
+ - application/json; charset=utf-8
96
+ Content-Length:
97
+ - '127'
98
+ body:
99
+ encoding: UTF-8
100
+ string: '[{"destinations":["user@example.com"],"source":"forward","href":"https://api.gandi.net/v5/email/forwards/example.com/forward"}]'
101
+ recorded_at: Mon, 17 Aug 2020 16:02:52 GMT
102
+
103
+ recorded_with: VCR 4.0.0
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe GandiV5::Domain::TransferIn::Availability do
4
+ describe '.fetch' do
5
+ let(:body_fixture) do
6
+ File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain_TransferIn_Availability', 'fetch.yml'))
7
+ end
8
+
9
+ describe 'Without auth_code' do
10
+ subject { described_class.fetch 'example.com' }
11
+
12
+ before(:each) do
13
+ url = 'https://api.gandi.net/v5/domain/transferin/example.com/available'
14
+ expect(GandiV5).to receive(:post).with(url, {})
15
+ .and_return([nil, YAML.load_file(body_fixture)])
16
+ end
17
+
18
+ its('available') { should be true }
19
+ its('fqdn') { should eq 'example.com' }
20
+ its('fqdn_unicode') { should eq 'EXAMPLE.COM' }
21
+ its('corporate') { should be false }
22
+ its('internal') { should be false }
23
+ its('durations') { should eq [1, 2, 3] }
24
+ its('minimum_duration') { should eq 1 }
25
+ its('maximum_duration') { should eq 3 }
26
+ its('message') { should eq 'This is a message' }
27
+ end
28
+
29
+ describe 'With auth_code' do
30
+ subject { described_class.fetch 'example.com', 'auth-code' }
31
+
32
+ before(:each) do
33
+ url = 'https://api.gandi.net/v5/domain/transferin/example.com/available'
34
+ expect(GandiV5).to receive(:post).with(url, { 'authinfo' => 'auth-code' })
35
+ .and_return([nil, YAML.load_file(body_fixture)])
36
+ end
37
+
38
+ its('available') { should be true }
39
+ its('fqdn') { should eq 'example.com' }
40
+ its('fqdn_unicode') { should eq 'EXAMPLE.COM' }
41
+ its('corporate') { should be false }
42
+ its('internal') { should be false }
43
+ its('durations') { should eq [1, 2, 3] }
44
+ its('minimum_duration') { should eq 1 }
45
+ its('maximum_duration') { should eq 3 }
46
+ its('message') { should eq 'This is a message' }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe GandiV5::Domain::TransferIn do
4
+ subject { described_class.new fqdn: 'example.com' }
5
+
6
+ describe '.fetch' do
7
+ subject { described_class.fetch 'example.com' }
8
+
9
+ before :each do
10
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain_TransferIn', 'fetch.yml'))
11
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/transferin/example.com')
12
+ .and_return([nil, YAML.load_file(body_fixture)])
13
+ end
14
+
15
+ its('fqdn') { should eq 'example.com' }
16
+ its('created_at') { should eq Time.new(2011, 2, 21, 10, 39, 0, 0) }
17
+ its('owner_contact') { should eq 'owner contact' }
18
+ its('duration') { should eq 1 }
19
+ its('reseller_uuid') { should eq 'reseller-uuid' }
20
+ its('version') { should eq 0 }
21
+ its('step') { should eq 'step text' }
22
+ its('step_number') { should eq 2 }
23
+ its('updated_at') { should eq Time.new(2011, 2, 22, 10, 39, 0, 0) }
24
+ its('errortype') { should eq 'error-type' }
25
+ its('errortype_label') { should eq 'error label' }
26
+ its('inner_step') { should eq 'inner-step' }
27
+ its('regac_at') { should eq Time.new(2011, 2, 23, 10, 39, 0, 0) }
28
+ its('start_at') { should eq Time.new(2011, 2, 24, 10, 39, 0, 0) }
29
+ its('transfer_procedure') { should eq 'transfer-procedure' }
30
+ its('foa_status') { should eq({ 'user@example.com' => 'ans' }) }
31
+ end
32
+
33
+ describe '.create' do
34
+ let(:url) { 'https://api.gandi.net/v5/domain/transferin' }
35
+
36
+ describe 'Sets dry-run header' do
37
+ let(:body) { '{"owner":{},"fqdn":"example.com"}' }
38
+
39
+ it 'False by default' do
40
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0).and_return([nil, { 'message' => 'confirmation' }])
41
+ described_class.create 'example.com', owner: {}
42
+ end
43
+
44
+ it 'True' do
45
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1).and_return([nil, nil])
46
+ described_class.create 'example.com', owner: {}, dry_run: true
47
+ end
48
+
49
+ it 'False' do
50
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0).and_return([nil, { 'message' => 'confirmation' }])
51
+ described_class.create 'example.com', owner: {}, dry_run: false
52
+ end
53
+
54
+ it 'Dry run was successful' do
55
+ returns = { 'status' => 'success' }
56
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1)
57
+ .and_return([nil, returns])
58
+ expect(described_class.create('example.com', owner: {}, dry_run: true)).to be returns
59
+ end
60
+
61
+ it 'Dry run has errors' do
62
+ returns = {
63
+ 'status' => 'error',
64
+ 'errors' => [{ 'description' => 'd', 'location' => 'l', 'name' => 'n' }]
65
+ }
66
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1)
67
+ .and_return([nil, returns])
68
+ expect(described_class.create('example.com', owner: {}, dry_run: true)).to be returns
69
+ end
70
+ end
71
+
72
+ describe 'Sets sharing_id' do
73
+ it 'Absent by default' do
74
+ expect(GandiV5).to receive(:post).with(url, any_args).and_return([nil, { 'message' => 'confirmation' }])
75
+ described_class.create('example.com', owner: {})
76
+ end
77
+
78
+ it 'Paying as another organization' do
79
+ expect(GandiV5).to receive(:post).with("#{url}?sharing_id=organization_id", any_args)
80
+ .and_return([nil, { 'message' => 'confirmation' }])
81
+ described_class.create('example.com', sharing_id: 'organization_id', owner: {})
82
+ end
83
+
84
+ it 'Buy as a reseller' do
85
+ expect(GandiV5).to receive(:post).with("#{url}?sharing_id=reseller_id", any_args)
86
+ .and_return([nil, { 'message' => 'confirmation' }])
87
+ described_class.create('example.com', sharing_id: 'reseller_id', owner: {})
88
+ end
89
+ end
90
+
91
+ it 'Success' do
92
+ body = '{"owner":{},"fqdn":"example.com"}'
93
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
94
+ .and_return([nil, { 'message' => 'confirmation' }])
95
+ expect(described_class.create('example.com', owner: {})).to eq 'confirmation'
96
+ end
97
+
98
+ it 'Errors on missing owner' do
99
+ expect { described_class.create 'example.com' }.to raise_error ArgumentError, 'missing keyword: owner'
100
+ end
101
+
102
+ it 'Given contact as hash' do
103
+ body = '{"owner":{"email":"owner@example.com"},"fqdn":"example.com"}'
104
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
105
+ .and_return([nil, { 'message' => 'confirmation' }])
106
+ described_class.create 'example.com', owner: { email: 'owner@example.com' }
107
+ end
108
+
109
+ it 'Given contact as GandiV5::Domain::Contact' do
110
+ body = '{"owner":{"email":"owner@example.com"},"fqdn":"example.com"}'
111
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
112
+ .and_return([nil, { 'message' => 'confirmation' }])
113
+ owner = double GandiV5::Domain::Contact, to_gandi: { 'email' => 'owner@example.com' }
114
+ described_class.create 'example.com', owner: owner
115
+ end
116
+ end
117
+
118
+ it '.relaunch' do
119
+ expect(GandiV5).to receive(:put).with('https://api.gandi.net/v5/domain/transferin/example.com')
120
+ .and_return([nil, { 'message' => 'confirmation' }])
121
+ expect(described_class.relaunch('example.com')).to eq 'confirmation'
122
+ end
123
+
124
+ it '.resend_foa_emails' do
125
+ url = 'https://api.gandi.net/v5/domain/transferin/example.com/foa'
126
+ body = '{"email":"user@example.com"}'
127
+ expect(GandiV5).to receive(:post).with(url, body)
128
+ .and_return([nil, { 'message' => 'confirmation' }])
129
+ expect(described_class.resend_foa_emails('example.com', 'user@example.com')).to eq 'confirmation'
130
+ end
131
+
132
+ it '#relaunch' do
133
+ returned = double String
134
+ expect(described_class).to receive(:relaunch).with('example.com').and_return(returned)
135
+ expect(subject.relaunch).to be returned
136
+ end
137
+
138
+ it '#resend_foa_emails' do
139
+ returned = double String
140
+ expect(described_class).to receive(:resend_foa_emails).with('example.com', 'user@example.com').and_return(returned)
141
+ expect(subject.resend_foa_emails('user@example.com')).to be returned
142
+ end
143
+ end