gandi_v5 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +12 -2
- data/.travis.yml +4 -0
- data/CHANGELOG.md +10 -0
- data/README.md +3 -1
- data/lib/gandi_v5/data.rb +1 -2
- data/lib/gandi_v5/domain.rb +6 -3
- data/lib/gandi_v5/email/mailbox.rb +55 -3
- data/lib/gandi_v5/organization/customer.rb +90 -0
- data/lib/gandi_v5/organization.rb +10 -0
- data/lib/gandi_v5/version.rb +1 -1
- data/lib/gandi_v5.rb +4 -1
- data/spec/.rubocop.yml +8 -1
- data/spec/fixtures/bodies/GandiV5_Organization_Customer/list.yml +8 -0
- data/spec/units/gandi_v5/domain_spec.rb +40 -4
- data/spec/units/gandi_v5/email/mailbox_spec.rb +115 -3
- data/spec/units/gandi_v5/organization/customer_spec.rb +81 -0
- data/spec/units/gandi_v5/organization_spec.rb +14 -0
- data/spec/units/gandi_v5_spec.rb +28 -16
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02621cbb8405cbec872ddcf3d549770535377dc1e6b158e9488f6bddcf65a771
|
4
|
+
data.tar.gz: 73901bcd9e8cb66d5c56c1802915dc849bd66d17d8c013a2895f472ef93f9543
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3caf30dc92addf609acb1e5e7f69841a5f896579f55c839813790200170222ede6df0e2c6448af2b3fa5848de5acb1a1cd50dbd1a19d538afc5c24e2d84e217
|
7
|
+
data.tar.gz: e1efdd6ed8ab463d7379b8040aeff61c62be58485464ed09e00bba3d28a4af9e27ac74f9333a74500f98e094b48832ed00439c01909fd9a1e5fb1a9677a7da76
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -8,13 +8,23 @@ Metrics/AbcSize:
|
|
8
8
|
Max: 20
|
9
9
|
Metrics/ClassLength:
|
10
10
|
Max: 250
|
11
|
-
Metrics/
|
12
|
-
Max:
|
11
|
+
Metrics/CyclomaticComplexity:
|
12
|
+
Max: 8
|
13
13
|
Metrics/MethodLength:
|
14
14
|
Max: 15
|
15
15
|
Metrics/ModuleLength:
|
16
16
|
Max: 200
|
17
|
+
Metrics/ParameterLists:
|
18
|
+
Max: 6
|
17
19
|
Style/DocumentationMethod:
|
18
20
|
Enabled: true
|
21
|
+
Style/HashEachMethods:
|
22
|
+
Enabled: true
|
23
|
+
Style/HashTransformKeys:
|
24
|
+
Enabled: true
|
25
|
+
Style/HashTransformValues:
|
26
|
+
Enabled: true
|
19
27
|
Style/SignalException:
|
20
28
|
Enabled: false
|
29
|
+
Layout/LineLength:
|
30
|
+
Max: 100
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Gandi V5 API Gem Changelog
|
2
2
|
|
3
|
+
## Version 0.4.0
|
4
|
+
|
5
|
+
* Fix exception when delete returns no content-type
|
6
|
+
* Add support for ruby 2.7.0
|
7
|
+
* Add up/downgrading mailbox offer
|
8
|
+
* Add dry run option to creating a mailbox
|
9
|
+
* Add sharing_id & dry run option for renewing domain
|
10
|
+
* Add listing customers under a reseller organization (GandiV5::Organization::Customer.list and GandiV5::Organization#customers)
|
11
|
+
* Add creating customer under a reseller organization (GandiV5::Organization::Customer.create and GandiV5::Organization#create_customer)
|
12
|
+
|
3
13
|
## Version 0.3.0
|
4
14
|
|
5
15
|
* Additions to GandiV5::Domain
|
data/README.md
CHANGED
@@ -8,7 +8,8 @@
|
|
8
8
|
This gem supports the following versions of ruby, it may work on other versions but is not tested against them so don't rely on it.
|
9
9
|
|
10
10
|
* ruby:
|
11
|
-
* 2.6.0 - 2.6.
|
11
|
+
* 2.6.0 - 2.6.6
|
12
|
+
* 2.7.0 - 2.7.1
|
12
13
|
* jruby, once it's reached parity with ruby 2.6.x
|
13
14
|
* truffleruby, once it's reached parity with ruby 2.6.x
|
14
15
|
* rubinius, once it's reached parity with ruby 2.6.x
|
@@ -76,6 +77,7 @@ We follow the [Semantic Versioning](http://semver.org/) concept.
|
|
76
77
|
|
77
78
|
| Gem Version | Gandi API Release Date |
|
78
79
|
| --------------- | ---------------------- |
|
80
|
+
| 0.4.0 | 2019-10-01 |
|
79
81
|
| 0.3.0 | 2019-08-22 |
|
80
82
|
| 0.2.0 | 2019-05-16 |
|
81
83
|
| 0.1.0 | 2019-05-16 |
|
data/lib/gandi_v5/data.rb
CHANGED
@@ -179,9 +179,8 @@ class GandiV5
|
|
179
179
|
define_method "#{name}=" do |value|
|
180
180
|
instance_variable_set("@#{name}", value)
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
private "#{name}="
|
184
|
-
# rubocop:enable Style/AccessModifierDeclarations
|
185
184
|
end
|
186
185
|
|
187
186
|
# @api private
|
data/lib/gandi_v5/domain.rb
CHANGED
@@ -211,10 +211,13 @@ class GandiV5
|
|
211
211
|
# @param duration [Integer, #to_s] how long to renew for (in years).
|
212
212
|
# @return [String] confirmation message from Gandi.
|
213
213
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
214
|
-
def renew_for(duration = 1)
|
214
|
+
def renew_for(duration = 1, sharing_id: nil, dry_run: false)
|
215
215
|
body = { duration: duration }.to_json
|
216
|
-
|
217
|
-
|
216
|
+
url_ = url('renew')
|
217
|
+
url_ = sharing_id ? "#{url_}?sharing_id=#{sharing_id}" : url_
|
218
|
+
|
219
|
+
_response, data = GandiV5.post(url_, body, 'Dry-Run': dry_run ? 1 : 0)
|
220
|
+
dry_run ? data : data['message']
|
218
221
|
end
|
219
222
|
|
220
223
|
# Restoration information for the domain.
|
@@ -105,6 +105,39 @@ class GandiV5
|
|
105
105
|
data['message']
|
106
106
|
end
|
107
107
|
|
108
|
+
# Upgrade a standard mailbox to premium.
|
109
|
+
# If the current slot is a free one, a new premium slot is created and
|
110
|
+
# used for the mailbox. Otherwise, the slot is upgraded to premium.
|
111
|
+
# @see https://api.gandi.net/docs/email#patch-v5-email-mailboxes-domain-mailbox_id-type
|
112
|
+
# @param sharing_id [String, #to_s, nil] (optional)
|
113
|
+
# the organisation ID to bill for the mailbox.
|
114
|
+
# @param dry_run [Boolean] whether the details should be checked instead
|
115
|
+
# of actually upgrading the mailbox.
|
116
|
+
# @return [true] if the mailbox was upgraded
|
117
|
+
# @return [false] if the mailbox was not upgraded (it's already premium)
|
118
|
+
# @return [Hash] if doing a dry run, you get what Gandi returns
|
119
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error
|
120
|
+
def upgrade(sharing_id: nil, dry_run: false)
|
121
|
+
patch_type :premium, sharing_id, dry_run
|
122
|
+
end
|
123
|
+
|
124
|
+
# Downgrade a premium mailbox to standard.
|
125
|
+
# If a free slot is available, the premium slot is destroyed
|
126
|
+
# (and refunded) and the free one is used for the mailbox.
|
127
|
+
# Otherwise, the slot is downgraded to standard.
|
128
|
+
# @see https://api.gandi.net/docs/email#patch-v5-email-mailboxes-domain-mailbox_id-type
|
129
|
+
# @param sharing_id [String, #to_s, nil] (optional)
|
130
|
+
# the organisation ID to bill for the mailbox.
|
131
|
+
# @param dry_run [Boolean] whether the details should be checked instead
|
132
|
+
# of actually downgrading the mailbox.
|
133
|
+
# @return [true] if the mailbox was downgraded
|
134
|
+
# @return [false] if the mailbox was not downgraded (it's already standard)
|
135
|
+
# @return [Hash] if doing a dry run, you get what Gandi returns
|
136
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error
|
137
|
+
def downgrade(sharing_id: nil, dry_run: false)
|
138
|
+
patch_type :standard, sharing_id, dry_run
|
139
|
+
end
|
140
|
+
|
108
141
|
# Create a new mailbox.
|
109
142
|
# Note that before you can create a mailbox, you must have a slot available.
|
110
143
|
# @see https://api.gandi.net/docs/email#post-v5-email-mailboxes-domain
|
@@ -113,10 +146,13 @@ class GandiV5
|
|
113
146
|
# @param password [String, #to_s] the password to use.
|
114
147
|
# @param aliases [Array<String, #to_s>] any alternative email address to be used.
|
115
148
|
# @param type [:standard, :premium] the type of mailbox slot to use.
|
149
|
+
# @param dry_run [Boolean] whether the details should be checked instead
|
150
|
+
# of actually creating the mailbox.
|
116
151
|
# @return [GandiV5::Email::Mailbox] The created mailbox.
|
117
152
|
# @raise [GandiV5::Error] if no slots are available.
|
118
153
|
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
119
|
-
|
154
|
+
# rubocop:disable Metrics/AbcSize
|
155
|
+
def self.create(fqdn, login, password, aliases: [], type: :standard, dry_run: false)
|
120
156
|
fail ArgumentError, "#{type.inspect} is not a valid type" unless TYPES.include?(type)
|
121
157
|
if GandiV5::Email::Slot.list.none? { |slot| slot.mailbox_type == type && slot.inactive? }
|
122
158
|
fail GandiV5::Error, "no available #{type} slots"
|
@@ -131,9 +167,11 @@ class GandiV5
|
|
131
167
|
aliases: aliases.push
|
132
168
|
}.to_json
|
133
169
|
|
134
|
-
response,
|
135
|
-
|
170
|
+
response, data = GandiV5.post(url(fqdn), body, 'Dry-Run': dry_run ? 1 : 0)
|
171
|
+
|
172
|
+
dry_run ? data : fetch(fqdn, response.headers[:location].split('/').last)
|
136
173
|
end
|
174
|
+
# rubocop:enable Metrics/AbcSize
|
137
175
|
|
138
176
|
# Get information for a mailbox.
|
139
177
|
# @see https://api.gandi.net/docs/email#get-v5-email-mailboxes-domain-mailbox_id
|
@@ -240,6 +278,20 @@ class GandiV5
|
|
240
278
|
def crypt_password(password)
|
241
279
|
self.class.send :crypt_password, password
|
242
280
|
end
|
281
|
+
|
282
|
+
def patch_type(new_type, sharing_id, dry_run)
|
283
|
+
fail ArgumentError unless TYPES.include?(new_type)
|
284
|
+
return false if type == new_type
|
285
|
+
|
286
|
+
url_ = "#{url}/type"
|
287
|
+
url_ = sharing_id ? "#{url_}?sharing_id=#{sharing_id}" : url_
|
288
|
+
body = { mailbox_type: new_type }
|
289
|
+
|
290
|
+
_response, data = GandiV5.patch(url_, body.to_json, 'Dry-Run': dry_run ? 1 : 0)
|
291
|
+
|
292
|
+
@type = new_type unless dry_run
|
293
|
+
dry_run ? data : true
|
294
|
+
end
|
243
295
|
end
|
244
296
|
end
|
245
297
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class GandiV5
|
4
|
+
class Organization
|
5
|
+
# A customer of a reseller organization
|
6
|
+
# @!attribute [r] id
|
7
|
+
# @return [String] The main identifier of the customer.
|
8
|
+
# Also known as sharing_id in many routes.
|
9
|
+
# @!attribute [r] email
|
10
|
+
# @return [String] Email of the customer.
|
11
|
+
# @!attribute [r] first_name
|
12
|
+
# @return [String] First name of the customer.
|
13
|
+
# @!attribute [r] last_name
|
14
|
+
# @return [String] Last name of the customer.
|
15
|
+
# @!attribute [r] name
|
16
|
+
# @return [String] Name of the customer.
|
17
|
+
# @!attribute [r] type
|
18
|
+
# @return [:individual, :company, :association, :publicbody]
|
19
|
+
# @!attribute [r] org_name
|
20
|
+
# @return [nil, String] Organization legal name of the customer..
|
21
|
+
class Customer
|
22
|
+
include GandiV5::Data
|
23
|
+
|
24
|
+
members :email, :name
|
25
|
+
member :uuid, gandi_key: 'id'
|
26
|
+
member :first_name, gandi_key: 'firstname'
|
27
|
+
member :last_name, gandi_key: 'lastname'
|
28
|
+
member :org_name, gandi_key: 'orgname'
|
29
|
+
member :type, converter: GandiV5::Data::Converter::Symbol
|
30
|
+
|
31
|
+
# Create a new customer for this organization.
|
32
|
+
# @see https://api.gandi.net/docs/organization/#post-v5-organization-organizations-id-customers
|
33
|
+
# @param org_uuid [String] UUID of the organization to create the customer for.
|
34
|
+
# @param firstname [String, #to_s] (required) Customer's first name.
|
35
|
+
# @param lastname [String, #to_s] (required) Customer's last name.
|
36
|
+
# @param type [String, #to_s] (required) Type of customer
|
37
|
+
# ("individual", "company", "association" or "publicbody").
|
38
|
+
# @param streetaddr [String, #to_s] (required) Customer's street address.
|
39
|
+
# @param city [String, #to_s] (required) Customer's city.
|
40
|
+
# @param country [String, #to_s] (required) Customer's country.
|
41
|
+
# @param email [String, #to_s] (required) Customer's email address.
|
42
|
+
# @param phone [String, #to_s] (required) Customer's phone number.
|
43
|
+
# @param fax [String, #to_s] (optional) Customer's fax number.
|
44
|
+
# @param streetaddr2 [String, #to_s] (optional) Customer's street address (2nd line).
|
45
|
+
# @param state [String, #to_s] (optional) Customer's state/province/region.
|
46
|
+
# @param zip [String, #to_s] (optional) Customer's postal/zip code.
|
47
|
+
# @param reference [String, #to_s] (optional)
|
48
|
+
# Optional text to display on the invoice, such as your own customer reference info.
|
49
|
+
# @param orgname [String, #to_s] (optional) Customer Organization's legal name.
|
50
|
+
# @return [nil]
|
51
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error
|
52
|
+
def self.create(org_uuid, **params)
|
53
|
+
%i[city country email firstname lastname phone streetaddr type].each do |attr|
|
54
|
+
fail ArgumentError, "missing keyword: #{attr}" unless params.key?(attr)
|
55
|
+
end
|
56
|
+
unless %w[individual company association publicbody].include?(params[:type].to_s)
|
57
|
+
fail ArgumentError, "invalid type: #{params[:type].inspect}"
|
58
|
+
end
|
59
|
+
|
60
|
+
_response, _data = GandiV5.post(url(org_uuid), params.to_json)
|
61
|
+
nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# List organisation's customers.
|
65
|
+
# @see https://api.gandi.net/docs/organization/#get-v5-organization-organizations-id-customers
|
66
|
+
# @param org_uuid [String] UUID of the organization to fetch customers for.
|
67
|
+
# @param name [String, #to_s] (optional)
|
68
|
+
# filters the list by name, with optional patterns.
|
69
|
+
# e.g. "alice", "ali*", "*ice"
|
70
|
+
# @param permission [String, #to_s] (optional)
|
71
|
+
# filters the list by the permission the authenticated user has on
|
72
|
+
# that organization and products in it.
|
73
|
+
# @param sort_by [String, #to_s] (optional default "name") how to sort the list.
|
74
|
+
# @return [Array<GandiV5::Organization>]
|
75
|
+
# @raise [GandiV5::Error::GandiError] if Gandi returns an error.
|
76
|
+
def self.list(org_uuid, **params)
|
77
|
+
params['~name'] = params.delete(:name) if params.key?(:name)
|
78
|
+
_resp, data = GandiV5.get url(org_uuid), params: params
|
79
|
+
data.map { |organisation| from_gandi organisation }
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def self.url(org_uuid)
|
85
|
+
"#{BASE}organization/organizations/#{org_uuid}/customers"
|
86
|
+
end
|
87
|
+
private_class_method :url
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -50,6 +50,16 @@ class GandiV5
|
|
50
50
|
|
51
51
|
alias organization_uuid uuid
|
52
52
|
|
53
|
+
# @see GandiV5::Organization::Customer.list
|
54
|
+
def customers(org_uuid, **params)
|
55
|
+
GandiV5::Organization::Customer.list(org_uuid, **params)
|
56
|
+
end
|
57
|
+
|
58
|
+
# @see GandiV5::Organization::Customer.create
|
59
|
+
def create_customer(org_uuid, **params)
|
60
|
+
GandiV5::Organization::Customer.create(org_uuid, **params)
|
61
|
+
end
|
62
|
+
|
53
63
|
# Get information about the current authenticated user.
|
54
64
|
# @see https://api.gandi.net/docs/organization#get-v5-organization-user-info
|
55
65
|
# @return [GandiV5::Organization]
|
data/lib/gandi_v5/version.rb
CHANGED
data/lib/gandi_v5.rb
CHANGED
@@ -93,7 +93,10 @@ class GandiV5
|
|
93
93
|
def delete(url, **headers)
|
94
94
|
prepare_headers headers, url
|
95
95
|
response = RestClient.delete url, **headers
|
96
|
-
[
|
96
|
+
[
|
97
|
+
response,
|
98
|
+
response.headers.key?(:content_type) ? parse_response(response) : nil
|
99
|
+
]
|
97
100
|
rescue RestClient::BadRequest => e
|
98
101
|
handle_bad_request(e)
|
99
102
|
end
|
data/spec/.rubocop.yml
CHANGED
@@ -373,10 +373,46 @@ describe GandiV5::Domain do
|
|
373
373
|
its('durations') { should match_array [1, 2] }
|
374
374
|
end
|
375
375
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
376
|
+
describe '#renew_for' do
|
377
|
+
it 'Defaults to 1 year and current user' do
|
378
|
+
expect(GandiV5).to receive(:post).with(
|
379
|
+
'https://api.gandi.net/v5/domain/domains/example.com/renew',
|
380
|
+
'{"duration":1}',
|
381
|
+
'Dry-Run': 0
|
382
|
+
)
|
383
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
384
|
+
expect(subject.renew_for).to eq 'Confirmation message.'
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'With provided duration' do
|
388
|
+
expect(GandiV5).to receive(:post).with(
|
389
|
+
'https://api.gandi.net/v5/domain/domains/example.com/renew',
|
390
|
+
'{"duration":2}',
|
391
|
+
'Dry-Run': 0
|
392
|
+
)
|
393
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
394
|
+
expect(subject.renew_for(2)).to eq 'Confirmation message.'
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'With provided sharing_id' do
|
398
|
+
expect(GandiV5).to receive(:post).with(
|
399
|
+
'https://api.gandi.net/v5/domain/domains/example.com/renew?sharing_id=def',
|
400
|
+
'{"duration":1}',
|
401
|
+
'Dry-Run': 0
|
402
|
+
)
|
403
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
404
|
+
expect(subject.renew_for(sharing_id: 'def')).to eq 'Confirmation message.'
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'Does a dry run' do
|
408
|
+
expect(GandiV5).to receive(:post).with(
|
409
|
+
'https://api.gandi.net/v5/domain/domains/example.com/renew',
|
410
|
+
'{"duration":1}',
|
411
|
+
'Dry-Run': 1
|
412
|
+
)
|
413
|
+
.and_return([nil, { 'status' => 'success' }])
|
414
|
+
expect(subject.renew_for(dry_run: true)).to eq('status' => 'success')
|
415
|
+
end
|
380
416
|
end
|
381
417
|
|
382
418
|
describe '#renewal_price' do
|
@@ -87,6 +87,108 @@ describe GandiV5::Email::Mailbox do
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
describe '#upgrade' do
|
91
|
+
let(:url) { 'https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid/type' }
|
92
|
+
|
93
|
+
context 'No sharing_id' do
|
94
|
+
it 'Is upgraded' do
|
95
|
+
expect(GandiV5).to receive(:patch).with(url, '{"mailbox_type":"premium"}', 'Dry-Run': 0)
|
96
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
97
|
+
expect(subject.upgrade).to be true
|
98
|
+
expect(subject.type).to be :premium
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'Is already premium' do
|
102
|
+
subject.instance_exec { @type = :premium }
|
103
|
+
expect(GandiV5).to_not receive(:patch)
|
104
|
+
expect(subject.upgrade).to be false
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'With sharing_id' do
|
109
|
+
let(:url) { 'https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid/type?sharing_id=abc' }
|
110
|
+
|
111
|
+
it 'Is upgraded' do
|
112
|
+
expect(GandiV5).to receive(:patch).with(url, '{"mailbox_type":"premium"}', 'Dry-Run': 0)
|
113
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
114
|
+
expect(subject.upgrade(sharing_id: 'abc')).to be true
|
115
|
+
expect(subject.type).to be :premium
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'Is already premium' do
|
119
|
+
subject.instance_exec { @type = :premium }
|
120
|
+
expect(GandiV5).to_not receive(:patch)
|
121
|
+
expect(subject.upgrade(sharing_id: 'abc')).to be false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'Dry run' do
|
126
|
+
it 'Is upgraded' do
|
127
|
+
expect(GandiV5).to receive(:patch).with(url, '{"mailbox_type":"premium"}', 'Dry-Run': 1)
|
128
|
+
.and_return([nil, { 'status' => 'success' }])
|
129
|
+
expect(subject.upgrade(dry_run: true)).to eq('status' => 'success')
|
130
|
+
expect(subject.type).to be :standard
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'Is already premium' do
|
134
|
+
subject.instance_exec { @type = :premium }
|
135
|
+
expect(GandiV5).to_not receive(:patch)
|
136
|
+
expect(subject.upgrade(dry_run: true)).to be false
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#downgrade' do
|
142
|
+
let(:url) { 'https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid/type' }
|
143
|
+
|
144
|
+
context 'No sharing_id' do
|
145
|
+
it 'Is downgraded' do
|
146
|
+
subject.instance_exec { @type = :premium }
|
147
|
+
expect(GandiV5).to receive(:patch).with(url, '{"mailbox_type":"standard"}', 'Dry-Run': 0)
|
148
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
149
|
+
expect(subject.downgrade).to be true
|
150
|
+
expect(subject.type).to be :standard
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'Is already premium' do
|
154
|
+
expect(GandiV5).to_not receive(:patch)
|
155
|
+
expect(subject.downgrade).to be false
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
context 'With sharing_id' do
|
160
|
+
let(:url) { 'https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid/type?sharing_id=abc' }
|
161
|
+
|
162
|
+
it 'Is downgraded' do
|
163
|
+
subject.instance_exec { @type = :premium }
|
164
|
+
expect(GandiV5).to receive(:patch).with(url, '{"mailbox_type":"standard"}', 'Dry-Run': 0)
|
165
|
+
.and_return([nil, { 'message' => 'Confirmation message.' }])
|
166
|
+
expect(subject.downgrade(sharing_id: 'abc')).to be true
|
167
|
+
expect(subject.type).to be :standard
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'Is already premium' do
|
171
|
+
expect(GandiV5).to_not receive(:patch)
|
172
|
+
expect(subject.downgrade(sharing_id: 'abc')).to be false
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'Dry run' do
|
177
|
+
it 'Is downgraded' do
|
178
|
+
subject.instance_exec { @type = :premium }
|
179
|
+
expect(GandiV5).to receive(:patch).with(url, '{"mailbox_type":"standard"}', 'Dry-Run': 1)
|
180
|
+
.and_return([nil, { 'status' => 'success' }])
|
181
|
+
expect(subject.downgrade(dry_run: true)).to eq('status' => 'success')
|
182
|
+
expect(subject.type).to be :premium
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'Is already premium' do
|
186
|
+
expect(GandiV5).to_not receive(:patch)
|
187
|
+
expect(subject.downgrade(dry_run: true)).to be false
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
90
192
|
it '#delete' do
|
91
193
|
url = 'https://api.gandi.net/v5/email/mailboxes/example.com/mailbox-uuid'
|
92
194
|
expect(GandiV5).to receive(:delete).with(url)
|
@@ -204,7 +306,7 @@ describe GandiV5::Email::Mailbox do
|
|
204
306
|
|
205
307
|
it 'No aliases and :standard type' do
|
206
308
|
body = '{"mailbox_type":"standard","login":"login","password":"crypted_password","aliases":[]}'
|
207
|
-
expect(GandiV5).to receive(:post).with(url, body)
|
309
|
+
expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
|
208
310
|
.and_return([created_response, { 'message' => 'Confirmation message.' }])
|
209
311
|
expect(described_class).to receive(:crypt_password).with(good_password).and_return('crypted_password')
|
210
312
|
expect(described_class).to receive(:fetch).with('example.com', 'created-mailbox-uuid').and_return(created_mailbox)
|
@@ -214,7 +316,7 @@ describe GandiV5::Email::Mailbox do
|
|
214
316
|
|
215
317
|
it 'With aliases' do
|
216
318
|
body = '{"mailbox_type":"standard","login":"login","password":"crypted_password","aliases":["alias-1"]}'
|
217
|
-
expect(GandiV5).to receive(:post).with(url, body)
|
319
|
+
expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
|
218
320
|
.and_return([created_response, { 'message' => 'Confirmation message.' }])
|
219
321
|
expect(described_class).to receive(:crypt_password).with(good_password).and_return('crypted_password')
|
220
322
|
expect(described_class).to receive(:fetch).with('example.com', 'created-mailbox-uuid').and_return(created_mailbox)
|
@@ -224,7 +326,7 @@ describe GandiV5::Email::Mailbox do
|
|
224
326
|
|
225
327
|
it 'With different type' do
|
226
328
|
body = '{"mailbox_type":"premium","login":"login","password":"crypted_password","aliases":[]}'
|
227
|
-
expect(GandiV5).to receive(:post).with(url, body)
|
329
|
+
expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
|
228
330
|
.and_return([created_response, { 'message' => 'Confirmation message.' }])
|
229
331
|
expect(described_class).to receive(:crypt_password).with(good_password).and_return('crypted_password')
|
230
332
|
expect(described_class).to receive(:fetch).with('example.com', 'created-mailbox-uuid').and_return(created_mailbox)
|
@@ -254,6 +356,16 @@ describe GandiV5::Email::Mailbox do
|
|
254
356
|
'no available standard slots'
|
255
357
|
)
|
256
358
|
end
|
359
|
+
|
360
|
+
it 'Doing a dry run' do
|
361
|
+
body = '{"mailbox_type":"standard","login":"login","password":"crypted_password","aliases":[]}'
|
362
|
+
expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1)
|
363
|
+
.and_return([nil, { 'status' => 'success' }])
|
364
|
+
expect(described_class).to receive(:crypt_password).with(good_password).and_return('crypted_password')
|
365
|
+
expect(described_class).to_not receive(:fetch)
|
366
|
+
|
367
|
+
expect(described_class.create('example.com', 'login', good_password, dry_run: true)).to eq('status' => 'success')
|
368
|
+
end
|
257
369
|
end
|
258
370
|
|
259
371
|
describe '.fetch' do
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe GandiV5::Organization::Customer do
|
4
|
+
let(:body_fixtures) { File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Organization_Customer')) }
|
5
|
+
|
6
|
+
describe '.create' do
|
7
|
+
let(:url) { 'https://api.gandi.net/v5/organization/organizations/uuid/customers' }
|
8
|
+
let(:attrs) do
|
9
|
+
{
|
10
|
+
city: 'Ci',
|
11
|
+
country: 'Co',
|
12
|
+
email: 'a@e',
|
13
|
+
firstname: 'f',
|
14
|
+
lastname: 'l',
|
15
|
+
phone: '0',
|
16
|
+
streetaddr: 'sa',
|
17
|
+
type: :individual
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'Success' do
|
22
|
+
response = double RestClient::Response, headers: { location: '' }
|
23
|
+
expect(GandiV5).to receive(:post).with(url, attrs.to_json).and_return([response, nil])
|
24
|
+
expect(described_class.create('uuid', **attrs)).to be nil
|
25
|
+
end
|
26
|
+
|
27
|
+
describe 'Checks for required attributes' do
|
28
|
+
%i[city country email firstname lastname phone streetaddr type].each do |attr|
|
29
|
+
it attr do
|
30
|
+
attrs.delete attr
|
31
|
+
expect { described_class.new('org_uuid', **attrs) }.to raise_exception ArgumentError
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'Invalid type' do
|
37
|
+
attrs[:type] = :invalid
|
38
|
+
expect { described_class.new('org_uuid', **attrs) }.to raise_exception ArgumentError
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '.list' do
|
43
|
+
describe 'With default values' do
|
44
|
+
subject { described_class.list('uuid') }
|
45
|
+
|
46
|
+
before :each do
|
47
|
+
url = 'https://api.gandi.net/v5/organization/organizations/uuid/customers'
|
48
|
+
expect(GandiV5).to receive(:get).with(url, params: {})
|
49
|
+
.and_return([nil, YAML.load_file(File.join(body_fixtures, 'list.yml'))])
|
50
|
+
end
|
51
|
+
|
52
|
+
its('count') { should eq 1 }
|
53
|
+
its('first.uuid') { should eq 'customer-uuid' }
|
54
|
+
its('first.name') { should eq 'FirstLast' }
|
55
|
+
its('first.first_name') { should eq 'First' }
|
56
|
+
its('first.last_name') { should eq 'Last' }
|
57
|
+
its('first.email') { should eq 'first.last@example.com' }
|
58
|
+
its('first.type') { should eq :individual }
|
59
|
+
its('first.org_name') { should eq 'Org' }
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'Passes optional query params' do
|
63
|
+
let(:url) { 'https://api.gandi.net/v5/organization/organizations/org_uuid/customers' }
|
64
|
+
|
65
|
+
it 'name' do
|
66
|
+
expect(GandiV5).to receive(:get).with(url, params: { '~name' => '5' })
|
67
|
+
.and_return([nil, []])
|
68
|
+
expect(described_class.list('org_uuid', name: '5')).to eq []
|
69
|
+
end
|
70
|
+
|
71
|
+
%i[permission sort_by].each do |param|
|
72
|
+
it param.to_s do
|
73
|
+
headers = { param => 5 }
|
74
|
+
expect(GandiV5).to receive(:get).with(url, params: headers)
|
75
|
+
.and_return([nil, []])
|
76
|
+
expect(described_class.list('org_uuid', **headers)).to eq []
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -64,4 +64,18 @@ describe GandiV5::Organization do
|
|
64
64
|
its('security_email_validated') { should eq true }
|
65
65
|
its('security_email_validation_deadline') { should eq Time.new(2017, 11, 22, 17, 13, 33) }
|
66
66
|
end
|
67
|
+
|
68
|
+
it '#customers' do
|
69
|
+
subject = described_class.new uuid: 'org_uuid'
|
70
|
+
returns = double Array
|
71
|
+
expect(GandiV5::Organization::Customer).to receive(:list).with('org_uuid', param: :value).and_return(returns)
|
72
|
+
expect(subject.customers('org_uuid', param: :value)).to be returns
|
73
|
+
end
|
74
|
+
|
75
|
+
it '#create_customer' do
|
76
|
+
subject = described_class.new uuid: 'org_uuid'
|
77
|
+
returns = double Object
|
78
|
+
expect(GandiV5::Organization::Customer).to receive(:create).with('org_uuid', param: :value).and_return(returns)
|
79
|
+
expect(subject.create_customer('org_uuid', param: :value)).to be returns
|
80
|
+
end
|
67
81
|
end
|
data/spec/units/gandi_v5_spec.rb
CHANGED
@@ -47,6 +47,10 @@ describe GandiV5 do
|
|
47
47
|
end
|
48
48
|
|
49
49
|
describe 'Uses RestClient' do
|
50
|
+
let(:response) do
|
51
|
+
double RestClient::Response, body: 'Hello world!', headers: { content_type: 'text/plain' }
|
52
|
+
end
|
53
|
+
|
50
54
|
%i[get delete].each do |method|
|
51
55
|
describe ":#{method}" do
|
52
56
|
it 'As JSON' do
|
@@ -58,30 +62,30 @@ describe GandiV5 do
|
|
58
62
|
end
|
59
63
|
|
60
64
|
it 'As text' do
|
61
|
-
response_data = 'Hello world!'
|
62
|
-
response = double RestClient::Response, body: response_data, headers: { content_type: 'text/plain' }
|
63
65
|
expect(described_class).to receive(:prepare_headers)
|
64
66
|
expect(RestClient).to receive(method).with('url', hash_including(accept: 'text/plain')).and_return(response)
|
65
|
-
expect(described_class.send(method, 'url', accept: 'text/plain')).to match_array [response,
|
67
|
+
expect(described_class.send(method, 'url', accept: 'text/plain')).to match_array [response, 'Hello world!']
|
66
68
|
end
|
67
69
|
|
68
70
|
it 'Passes request headers' do
|
69
71
|
expect(described_class).to receive(:prepare_headers)
|
70
72
|
expect(described_class).to receive(:parse_response)
|
71
|
-
expect(RestClient).to receive(method).with(anything, header: 'value')
|
72
|
-
expect(described_class.send(method, 'url', header: 'value')).to match_array [
|
73
|
+
expect(RestClient).to receive(method).with(anything, header: 'value').and_return(response)
|
74
|
+
expect(described_class.send(method, 'url', header: 'value')).to match_array [response, nil]
|
73
75
|
end
|
74
76
|
|
75
77
|
it 'Adds authentication header' do
|
76
78
|
expect(RestClient).to receive(method).with(anything, hash_including(Authorization: 'Apikey abdce12345'))
|
79
|
+
.and_return(response)
|
77
80
|
expect(described_class).to receive(:parse_response)
|
78
|
-
expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [
|
81
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [response, nil]
|
79
82
|
end
|
80
83
|
|
81
84
|
it 'Default accept header' do
|
82
85
|
expect(RestClient).to receive(method).with(any_args, hash_including(accept: 'application/json'))
|
86
|
+
.and_return(response)
|
83
87
|
expect(described_class).to receive(:parse_response)
|
84
|
-
expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [
|
88
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [response, nil]
|
85
89
|
end
|
86
90
|
|
87
91
|
it 'Converts a 406 (bad request) exception' do
|
@@ -92,6 +96,13 @@ describe GandiV5 do
|
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
99
|
+
it ':delete handles no content-type' do
|
100
|
+
response = double RestClient::Response, headers: {}
|
101
|
+
expect(described_class).to receive(:prepare_headers)
|
102
|
+
expect(RestClient).to receive(:delete).with('url', hash_including(accept: 'text/plain')).and_return(response)
|
103
|
+
expect(described_class.delete('url', accept: 'text/plain')).to match_array [response, nil]
|
104
|
+
end
|
105
|
+
|
95
106
|
%i[patch post put].each do |method|
|
96
107
|
describe ":#{method}" do
|
97
108
|
let(:payload) { '{"say":"hello world"}' }
|
@@ -107,26 +118,25 @@ describe GandiV5 do
|
|
107
118
|
end
|
108
119
|
|
109
120
|
it 'As text' do
|
110
|
-
response_data = 'hello world'
|
111
|
-
response = double RestClient::Response, body: response_data, headers: { content_type: 'text/plain' }
|
112
121
|
expect(described_class).to receive(:prepare_headers)
|
113
122
|
expect(RestClient).to receive(method).with('url', payload, hash_including(accept: 'text/plain'))
|
114
123
|
.and_return(response)
|
115
|
-
|
124
|
+
array = [response, 'Hello world!']
|
125
|
+
expect(described_class.send(method, 'url', payload, accept: 'text/plain')).to match_array array
|
116
126
|
end
|
117
127
|
|
118
128
|
it 'Passes payload' do
|
119
129
|
expect(described_class).to receive(:prepare_headers)
|
120
130
|
expect(described_class).to receive(:parse_response)
|
121
|
-
expect(RestClient).to receive(method).with(anything, payload, any_args)
|
122
|
-
expect(described_class.send(method, 'url', payload)).to match_array [
|
131
|
+
expect(RestClient).to receive(method).with(anything, payload, any_args).and_return(response)
|
132
|
+
expect(described_class.send(method, 'url', payload)).to match_array [response, nil]
|
123
133
|
end
|
124
134
|
|
125
135
|
it 'Passes request headers' do
|
126
136
|
expect(described_class).to receive(:prepare_headers)
|
127
137
|
expect(described_class).to receive(:parse_response)
|
128
|
-
expect(RestClient).to receive(method).with(any_args, hash_including(header: 'value'))
|
129
|
-
expect(described_class.send(method, 'url', payload, header: 'value')).to match_array [
|
138
|
+
expect(RestClient).to receive(method).with(any_args, hash_including(header: 'value')).and_return(response)
|
139
|
+
expect(described_class.send(method, 'url', payload, header: 'value')).to match_array [response, nil]
|
130
140
|
end
|
131
141
|
|
132
142
|
it 'Adds content type header' do
|
@@ -137,14 +147,16 @@ describe GandiV5 do
|
|
137
147
|
|
138
148
|
it 'Adds authentication header' do
|
139
149
|
expect(RestClient).to receive(method).with(any_args, hash_including(Authorization: 'Apikey abdce12345'))
|
150
|
+
.and_return(response)
|
140
151
|
expect(described_class).to receive(:parse_response)
|
141
|
-
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [
|
152
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [response, nil]
|
142
153
|
end
|
143
154
|
|
144
155
|
it 'Default accept header' do
|
145
156
|
expect(RestClient).to receive(method).with(any_args, hash_including(accept: 'application/json'))
|
157
|
+
.and_return(response)
|
146
158
|
expect(described_class).to receive(:parse_response)
|
147
|
-
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [
|
159
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [response, nil]
|
148
160
|
end
|
149
161
|
|
150
162
|
it 'Converts a 406 (bad request) exception' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gandi_v5
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Gauld
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dotenv
|
@@ -340,6 +340,7 @@ files:
|
|
340
340
|
- lib/gandi_v5/live_dns/zone.rb
|
341
341
|
- lib/gandi_v5/live_dns/zone/snapshot.rb
|
342
342
|
- lib/gandi_v5/organization.rb
|
343
|
+
- lib/gandi_v5/organization/customer.rb
|
343
344
|
- lib/gandi_v5/version.rb
|
344
345
|
- spec/.rubocop.yml
|
345
346
|
- spec/features/domain_spec.rb
|
@@ -371,6 +372,7 @@ files:
|
|
371
372
|
- spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yml
|
372
373
|
- spec/fixtures/bodies/GandiV5_Organization/fetch.yml
|
373
374
|
- spec/fixtures/bodies/GandiV5_Organization/list.yml
|
375
|
+
- spec/fixtures/bodies/GandiV5_Organization_Customer/list.yml
|
374
376
|
- spec/fixtures/vcr/Domain_features/List_domains.yml
|
375
377
|
- spec/fixtures/vcr/Domain_features/Renew_domain.yml
|
376
378
|
- spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml
|
@@ -415,6 +417,7 @@ files:
|
|
415
417
|
- spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb
|
416
418
|
- spec/units/gandi_v5/live_dns/zone_spec.rb
|
417
419
|
- spec/units/gandi_v5/live_dns_spec.rb
|
420
|
+
- spec/units/gandi_v5/organization/customer_spec.rb
|
418
421
|
- spec/units/gandi_v5/organization_spec.rb
|
419
422
|
- spec/units/gandi_v5_spec.rb
|
420
423
|
homepage: https://github.com/robertgauld/gandi_v5
|
@@ -436,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
436
439
|
- !ruby/object:Gem::Version
|
437
440
|
version: 2.6.14
|
438
441
|
requirements: []
|
439
|
-
rubygems_version: 3.
|
442
|
+
rubygems_version: 3.1.2
|
440
443
|
signing_key:
|
441
444
|
specification_version: 4
|
442
445
|
summary: Make use of Gandi's V5 API.
|