gandirb 1.1.1 → 2.0.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.
- data/CHANGELOG +6 -0
- data/LICENSE +1 -1
- data/README.rdoc +22 -24
- data/Rakefile +8 -9
- data/USAGE.rdoc +131 -0
- data/gandirb.gemspec +7 -9
- data/lib/gandi/connection.rb +65 -0
- data/lib/gandi/connector.rb +7 -0
- data/lib/gandi/contact.rb +175 -0
- data/lib/gandi/domain/contacts.rb +21 -0
- data/lib/gandi/domain/forward.rb +58 -0
- data/lib/gandi/domain/host.rb +63 -0
- data/lib/gandi/domain/mailbox.rb +72 -0
- data/lib/gandi/domain/nameservers.rb +17 -0
- data/lib/gandi/domain/status.rb +19 -0
- data/lib/gandi/domain/tld.rb +17 -0
- data/lib/gandi/domain/transferin.rb +13 -0
- data/lib/gandi/domain.rb +61 -128
- data/lib/gandi/errors.rb +10 -0
- data/lib/gandi/gandi_object_methods.rb +23 -0
- data/lib/gandi/operation.rb +45 -0
- data/lib/gandi/version.rb +1 -1
- data/lib/gandi.rb +57 -6
- data/spec/gandi/connection_spec.rb +39 -0
- data/spec/gandi/contact_spec.rb +173 -0
- data/spec/gandi/domain/forward_spec.rb +103 -0
- data/spec/gandi/domain/host_spec.rb +103 -0
- data/spec/gandi/domain/mailbox_spec.rb +117 -0
- data/spec/gandi/domain/tld_spec.rb +23 -0
- data/spec/gandi/domain_spec.rb +174 -0
- data/spec/gandi/errors_spec.rb +18 -0
- data/spec/gandi/gandi_spec.rb +57 -0
- data/spec/gandi/operation_spec.rb +73 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/support/contact_macros.rb +18 -0
- data/spec/support/domain_macros.rb +103 -0
- data/spec/support/operation_macros.rb +22 -0
- metadata +58 -51
- data/lib/gandi/base.rb +0 -121
- data/lib/gandi/domain_modules/contact.rb +0 -36
- data/lib/gandi/domain_modules/host.rb +0 -29
- data/lib/gandi/domain_modules/mail.rb +0 -80
- data/lib/gandi/domain_modules/name_servers.rb +0 -28
- data/lib/gandi/domain_modules/operations.rb +0 -30
- data/lib/gandi/domain_modules/redirection.rb +0 -25
- data/test/gandi/base_test.rb +0 -188
- data/test/gandi/domain_test.rb +0 -301
- data/test/gandi_test.rb +0 -9
- data/test/test_helper.rb +0 -9
data/CHANGELOG
CHANGED
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,36 +1,34 @@
|
|
1
|
-
=
|
1
|
+
= Gandi - Ruby library for using the Gandi XML-RPC API
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
A Ruby library for using the Gandi XML-RPC API.
|
4
|
+
At the moment support is planned for the Domain, Contact and Operation APIs only, but Hosting and Catalog APIs support may be added in the future.
|
5
|
+
Version 2.0.0 and upwards of this gem supports only the Gandi API version 2.0, use version 1.x of the gem if you need to the 1.0 API.
|
5
6
|
|
6
|
-
==
|
7
|
+
== HOWTO
|
7
8
|
|
8
|
-
See http://
|
9
|
-
Note the
|
9
|
+
See http://rpc.ote.gandi.net/doc/2.0/index.html for the full documentation about the API.
|
10
|
+
Note that the apikey doesn't have to be explicitly provided when calling a method.
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
Quick example:
|
13
|
+
Gandi.apikey = 'my 24-character API key'
|
14
|
+
Gandi.url # => "https://rpc.ote.gandi.net/xmlrpc/"
|
15
|
+
Gandi.url = Gandi::URL #Use the production URL instead of the default Operational Test and Evaluation URL
|
16
|
+
Gandi.call('version.info') #You do not have to provide the apikey for each call
|
17
|
+
contact = Gandi::Contact.new('FLN123-GANDI')
|
18
|
+
contact.country # => "FR"
|
14
19
|
|
15
|
-
|
16
|
-
|
17
|
-
require 'gandi'
|
18
|
-
gandi_session = Gandi::Domain.login 'XXYYY-Gandi', 'mypasswd', Gandi::Domain::TEST_URL #or use Gandi::Domain::URL in production mode
|
19
|
-
gandi_session.account_currency # => "EUR"
|
20
|
-
gandi_session.domain_available ["mycoolwebsite.com"] # => {"mycoolwebsite.com"=>true}
|
21
|
-
gandi_session.domain_available "mycoolwebsite.com" # => true #additional syntax
|
22
|
-
gandi_session.domain_list # => ["mypersonalwebsite.com"]
|
23
|
-
|
24
|
-
Detailed RDoc documentation for each method is available using rake rdoc.
|
20
|
+
You can read more about the library in USAGE.rdoc.
|
21
|
+
Detailed RDoc documentation for each method is available using `rake rdoc`.
|
25
22
|
|
26
23
|
== TODO
|
27
24
|
|
28
25
|
* More tests
|
29
|
-
*
|
30
|
-
*
|
31
|
-
* Refactor
|
26
|
+
* Refactor the Operation object creation from the other classes
|
27
|
+
* Add attributes getters to Domain/Operation/Mailbox/Host classes
|
28
|
+
* Refactor the Contact class to match the other classes behaviour (instances of the class should only match existing records)
|
29
|
+
* Make the Domain/Contact/etc. classes more ActiveModel-like
|
30
|
+
* Better handling of failures and server exceptions, and overall stricter params checking
|
32
31
|
|
33
32
|
== Copyright
|
34
33
|
|
35
|
-
Copyright (c)
|
36
|
-
Some parts inspired by http://github.com/jerome/gandi/tree
|
34
|
+
Copyright (c) 2012 Pickabee. Released under the MIT licence, see LICENSE for details.
|
data/Rakefile
CHANGED
@@ -2,22 +2,21 @@ require 'bundler/setup'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'bundler/gem_tasks'
|
4
4
|
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
test.verbose = false
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new do |t|
|
7
|
+
t.rspec_opts = ['-c', '-f progress', '-r ./spec/spec_helper.rb', '--backtrace']
|
8
|
+
t.pattern = 'spec/**/*_spec.rb'
|
10
9
|
end
|
11
10
|
|
12
|
-
task :default
|
11
|
+
task :default => :spec
|
13
12
|
|
14
13
|
require 'rdoc/task'
|
15
14
|
Rake::RDocTask.new do |rdoc|
|
16
15
|
rdoc.rdoc_dir = 'rdoc'
|
17
16
|
rdoc.title = "Gandirb"
|
18
17
|
rdoc.main = 'README.rdoc'
|
19
|
-
rdoc.rdoc_files.include('README*', 'CHANGELOG', 'LICENSE')
|
18
|
+
rdoc.rdoc_files.include('README*', 'USAGE*', 'CHANGELOG', 'LICENSE')
|
20
19
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
-
rdoc.options <<
|
22
|
-
rdoc.options <<
|
20
|
+
rdoc.options << '--line-numbers'
|
21
|
+
rdoc.options << '--charset=UTF-8'
|
23
22
|
end
|
data/USAGE.rdoc
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
= Setup
|
2
|
+
|
3
|
+
== Installation
|
4
|
+
|
5
|
+
=== Using bundler
|
6
|
+
|
7
|
+
Add the gandi gem requirement to your Gemfile :
|
8
|
+
gem "gandi", "~> 1.0"
|
9
|
+
|
10
|
+
Then install the gem with `bundle`.
|
11
|
+
|
12
|
+
=== Using Rubygems (or any other Ruby package manager)
|
13
|
+
|
14
|
+
Install the gem manually (see your package manager documentation if you are using a Rubygems alternative) :
|
15
|
+
$ gem install gandi
|
16
|
+
|
17
|
+
You will have to require the gandi library manually in your application code :
|
18
|
+
require 'gandi'
|
19
|
+
|
20
|
+
=== Configuration
|
21
|
+
|
22
|
+
Set your API key :
|
23
|
+
Gandi.apikey = 'my 24-character API key'
|
24
|
+
See https://www.gandi.net/admin/apixml/ to activate the API for your account and get your apikey.
|
25
|
+
|
26
|
+
By default, the library will use the OT&E system when calling the API.
|
27
|
+
See http://rpc.ote.gandi.net/doc/2.0/overview.html#ot-e-system to learn more about the OT&E system.
|
28
|
+
You can use the production system by changing the URL :
|
29
|
+
Gandi.url = Gandi::URL
|
30
|
+
|
31
|
+
= Description
|
32
|
+
|
33
|
+
The Gandi library can be used in two ways : either by calling the API directly, or by using Ruby classes and methods that transparently map to the corresponding API calls.
|
34
|
+
|
35
|
+
== API calls
|
36
|
+
|
37
|
+
You can call any API method directly by using Gandi.call :
|
38
|
+
Gandi.call('version.info') # => {"api_version"=>"2.0"}
|
39
|
+
|
40
|
+
The apikey will automatically be provided as the first argument of the called method.
|
41
|
+
|
42
|
+
== Ruby objects
|
43
|
+
|
44
|
+
The Gandi library aims to abstract the API calls by providing classes and methods matching Gandi "objects" :
|
45
|
+
* Gandi::Contact - a Gandi contact (identified by its handle)
|
46
|
+
* Gandi::Domain - a domain name (identified by its fqdn)
|
47
|
+
* Gandi::Domain::Forward - A domain forward (identified by its source email) (TODO)
|
48
|
+
* Gandi::Domain::Host - A domain host (glue record) (identified by its hostname)
|
49
|
+
* Gandi::Domain::Mailbox - a mailbox for a domain name (identified by its login) (TODO)
|
50
|
+
* Gandi::Operation - an operation on the Gandi system (identified by its unique id)
|
51
|
+
|
52
|
+
Be aware that Ruby classes do not specifically map to Gandi API namespaces.
|
53
|
+
For example, Gandi::Domain#nameservers will return an array of nameservers fetched with a previous call to 'domain.info', while Gandi::Domain#nameservers=(nameservers) will call 'domain.nameservers.set'
|
54
|
+
|
55
|
+
Here is a (partial) reference of Gandi namespaces and their matching Ruby classes and methods :
|
56
|
+
* contact
|
57
|
+
* can_associate(contact, domain) => Gandi::Contact.can_associate(contact, domain)
|
58
|
+
* can_associate_domain(handle, domain) => Gandi::Contact#can_associate_domain(domain)
|
59
|
+
* create(contact) => Gandi::Contact.create(contact)
|
60
|
+
* info(handle='') => Gandi::Contact#info, Gandi::Contact.info(handle)
|
61
|
+
* list(opts=nil) => Gandi::Contact.list(opts = {})
|
62
|
+
* update(handle, contact) => Gandi::Contact#update(contact), Gandi::Contact.update(handle, contact)
|
63
|
+
* domain
|
64
|
+
* available(fqdns) => Gandi::Domain.available(fqdns)
|
65
|
+
* count(filters=nil) => Gandi::Domain.count(filters = {})
|
66
|
+
* create(fqdn, params) => Gandi::Domain.create(fqdn, params)
|
67
|
+
* info(fqdn) => Gandi::Domain#info
|
68
|
+
* list(opts=nil) => Gandi::Domain.list(opts = {})
|
69
|
+
* renew(fqdn, params) => Gandi::Domain#renew(params)
|
70
|
+
* domain.contacts
|
71
|
+
* set(fqdn, contacts) => Gandi::Domain#contacts=(contacts)
|
72
|
+
* domain.status
|
73
|
+
* lock(fqdn) => Gandi::Domain#lock
|
74
|
+
* unlock(fqdn) => Gandi::Domain#unlock
|
75
|
+
* domain.host
|
76
|
+
* count(fqdn[, opts=nil])
|
77
|
+
* create(hostname, ips)
|
78
|
+
* delete(hostname)
|
79
|
+
* info(hostname)
|
80
|
+
* list(fqdn[, opts=nil])
|
81
|
+
* update(hostname, ips)
|
82
|
+
* domain.mailbox
|
83
|
+
* count(domain[, opts=nil])
|
84
|
+
* create(domain, login, params)
|
85
|
+
* delete(domain, login)
|
86
|
+
* info(domain, login)
|
87
|
+
* list(domain[, opts=nil])
|
88
|
+
* purge(domain, login)
|
89
|
+
* update(domain, login, params)
|
90
|
+
* domain.mailbox.alias
|
91
|
+
* set(domain, login, aliases)
|
92
|
+
* domain.mailbox.responder
|
93
|
+
* activate(domain, login, params)
|
94
|
+
* deactivate(domain, login[, params=nil])
|
95
|
+
* domain.forward
|
96
|
+
* count(domain[, opts=nil])
|
97
|
+
* create(domain, source, params
|
98
|
+
* delete(domain, source)
|
99
|
+
* list(domain[, opts=nil])
|
100
|
+
* update(domain, source, params)
|
101
|
+
* domain.packmail
|
102
|
+
* domain.tld
|
103
|
+
* list => Gandi::Domain::Tld.list
|
104
|
+
* region => Gandi::Domain::Tld.region
|
105
|
+
* domain.transferin
|
106
|
+
* proceed(fqdn, params) => Gandi::Domain#transferin(params)
|
107
|
+
* domain.nameservers
|
108
|
+
* set(fqdn, nameservers) => Gandi::Domain#nameservers=(nameservers)
|
109
|
+
* operation
|
110
|
+
* cancel(apikey, operation) => Gandi::Operation#cancel
|
111
|
+
* count(apikey[, opts=nil]) => Gandi::Operation.count(opts = {})
|
112
|
+
* info(apikey, operation) => Gandi::Operation#info
|
113
|
+
* list(apikey[, opts=nil]) => Gandi::Operation.list(opts = {})
|
114
|
+
|
115
|
+
For more information on a Ruby class/method see the matching RDoc.
|
116
|
+
|
117
|
+
Note that API calls under the hosting and catalog are not currently implemented.
|
118
|
+
No support is planned for thoses API calls (but pull requests are accepted).
|
119
|
+
|
120
|
+
= Use in testing
|
121
|
+
|
122
|
+
While using the OT&E system is safe as it will not result in any real billing, integration and unit tests for your application should be repeatable and isolated.
|
123
|
+
You can use mocking (and/or stubbing) to avoid calling the XML-RPC methods on the Gandi server and cover all the possible cases.
|
124
|
+
|
125
|
+
Example using rspec-mocks:
|
126
|
+
connection_mock = double()
|
127
|
+
connection_mock.should_receive(:call).with('version.info').and_return({"api_version"=>"2.0"})
|
128
|
+
Gandi.connection = connection_mock
|
129
|
+
Gandi.call('version.info') # => {"api_version"=>"2.0"}
|
130
|
+
|
131
|
+
Be aware that changing the apikey or URL will reset the connection variable (so you will have to set up your mock again).
|
data/gandirb.gemspec
CHANGED
@@ -9,25 +9,23 @@ Gem::Specification.new do |s|
|
|
9
9
|
|
10
10
|
s.authors = ["Pickabee"]
|
11
11
|
s.email = ""
|
12
|
-
s.homepage = "http://github.com/pickabee/
|
12
|
+
s.homepage = "http://github.com/pickabee/gandi"
|
13
13
|
s.summary = %q{Ruby library for using the Gandi XML-RPC API}
|
14
14
|
s.description = <<-EOL
|
15
|
-
|
16
|
-
|
15
|
+
A Ruby library for using the Gandi XML-RPC API.
|
16
|
+
At the moment support is planned for the Domain, Contact and Operation APIs only, but Hosting and Catalog APIs support may be added in the future.
|
17
17
|
EOL
|
18
18
|
s.rubyforge_project = "gandirb"
|
19
19
|
|
20
20
|
s.date = Date.today.strftime('%Y-%m-%d')
|
21
21
|
|
22
|
-
s.files = Dir["CHANGELOG", "LICENSE", "README.rdoc", "Gemfile", "Rakefile", "gandirb.gemspec", "{lib}/**/*.rb"]
|
23
|
-
s.test_files = Dir["{
|
22
|
+
s.files = Dir["CHANGELOG", "LICENSE", "README.rdoc", "USAGE.rdoc", "Gemfile", "Rakefile", "gandirb.gemspec", "{lib}/**/*.rb"]
|
23
|
+
s.test_files = Dir["{spec}/**/*.rb"]
|
24
24
|
s.rdoc_options = ["--line-numbers", "--charset=UTF-8", "--title", "Gandirb", "--main", "README.rdoc"]
|
25
|
-
s.extra_rdoc_files = %w[CHANGELOG LICENSE]
|
25
|
+
s.extra_rdoc_files = %w[USAGE.rdoc CHANGELOG LICENSE]
|
26
26
|
s.require_paths = ["lib"]
|
27
27
|
|
28
|
-
s.add_dependency 'activesupport', '>= 2.0'
|
29
28
|
s.add_development_dependency 'rake'
|
30
29
|
s.add_development_dependency 'rdoc'
|
31
|
-
s.add_development_dependency '
|
32
|
-
s.add_development_dependency 'mocha'
|
30
|
+
s.add_development_dependency 'rspec', '>= 2.8'
|
33
31
|
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'xmlrpc/client'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Gandi
|
5
|
+
class Connection
|
6
|
+
SSL_VERIFY_MODE = OpenSSL::SSL::VERIFY_NONE
|
7
|
+
|
8
|
+
#The 24-character API key used for authentication.
|
9
|
+
attr_reader :apikey
|
10
|
+
|
11
|
+
#URL used for connecting to the Gandi API.
|
12
|
+
attr_reader :url
|
13
|
+
|
14
|
+
def initialize(apikey, url)
|
15
|
+
raise DataError, "You must set the apikey before calling any method" unless apikey
|
16
|
+
@apikey = apikey
|
17
|
+
@url = url
|
18
|
+
connect
|
19
|
+
end
|
20
|
+
|
21
|
+
#Calls a RPC method, automatically setting the apikey as the first argument.
|
22
|
+
def call(method, *arguments)
|
23
|
+
raw_call(method.to_s, @apikey, *arguments)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
#Handles RPC calls and exceptions.
|
29
|
+
def raw_call(*args)
|
30
|
+
begin
|
31
|
+
@handler.call(*args)
|
32
|
+
rescue StandardError => e
|
33
|
+
case e
|
34
|
+
when XMLRPC::FaultException
|
35
|
+
case e.faultCode.to_s.chars.first
|
36
|
+
when '1'
|
37
|
+
raise Gandi::NoMethodError, e.faultString
|
38
|
+
when '5'
|
39
|
+
raise Gandi::DataError, e.faultString
|
40
|
+
else
|
41
|
+
raise Gandi::ServerError, e.faultString
|
42
|
+
end
|
43
|
+
else
|
44
|
+
raise e
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
#Instanciates the XMLRPC handler.
|
50
|
+
def connect
|
51
|
+
@handler = XMLRPC::Client.new_from_uri(@url)
|
52
|
+
#Get rid of SSL warnings "peer certificate won't be verified in this SSL session"
|
53
|
+
#See http://developer.amazonwebservices.com/connect/thread.jspa?threadID=37139
|
54
|
+
#and http://blog.chmouel.com/2008/03/21/ruby-xmlrpc-over-a-self-certified-ssl-with-a-warning/
|
55
|
+
#and http://stackoverflow.com/questions/4748633/how-can-i-make-rubys-xmlrpc-client-ignore-ssl-certificate-errors for ruby 1.9 (which does not set @ssl_context before a request)
|
56
|
+
if @handler.instance_variable_get('@http').use_ssl?
|
57
|
+
if @handler.instance_variable_get('@http').instance_variable_get("@ssl_context") #Ruby 1.8.7
|
58
|
+
@handler.instance_variable_get('@http').instance_variable_get("@ssl_context").verify_mode = SSL_VERIFY_MODE
|
59
|
+
else
|
60
|
+
@handler.instance_variable_get('@http').instance_variable_set(:@verify_mode, SSL_VERIFY_MODE) #Ruby 1.9
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Gandi
|
4
|
+
class Contact
|
5
|
+
include Gandi::GandiObjectMethods
|
6
|
+
|
7
|
+
#Contact types mapping
|
8
|
+
TYPES = {
|
9
|
+
0 => 'person',
|
10
|
+
1 => 'company',
|
11
|
+
2 => 'association',
|
12
|
+
3 => 'organization',
|
13
|
+
4 => 'reseller'
|
14
|
+
}
|
15
|
+
|
16
|
+
#Security questions mapping
|
17
|
+
SECURITY_QUESTION_NUM_VALUES = {
|
18
|
+
1 => "What is the name of your favorite city?",
|
19
|
+
2 => "What is your mother’s maiden name?",
|
20
|
+
3 => "What is your favorite food?",
|
21
|
+
4 => "What year were you born in?",
|
22
|
+
5 => "What is your cell phone number?",
|
23
|
+
6 => "In what year was your Gandi account created?"
|
24
|
+
}
|
25
|
+
|
26
|
+
#Settable contact attributes (ie. not the id or handle)
|
27
|
+
WRITABLE_ATTRIBUTES = :type, :orgname, :given, :family, :streetaddr, :city, :state, :zip, :country, :phone, :fax, :mobile,
|
28
|
+
:tva_number, :siren, :marque, :lang, :newsletter, :obfuscated, :whois_obfuscated, :resell, :shippingaddress,
|
29
|
+
:extra_parameters
|
30
|
+
|
31
|
+
#Additional attributes used when creating an account
|
32
|
+
CREATE_PARAMETERS_ATTRIBUTES = :password, :email,
|
33
|
+
:jo_announce_page, :jo_announce_number, :jo_declaration_date, :jo_publication_date,
|
34
|
+
:security_question_num, :security_question_answer
|
35
|
+
|
36
|
+
#Attributes returned when calling contact.info or creating/updating a contact
|
37
|
+
INFORMATION_ATTRIBUTES = WRITABLE_ATTRIBUTES + [:id]
|
38
|
+
|
39
|
+
attr_reader :handle
|
40
|
+
|
41
|
+
#A new instance of Contact.
|
42
|
+
#Takes a Gandi handle and/or a contact hash with string keys.
|
43
|
+
#When providing only a handle the contact info will be fetched from the API.
|
44
|
+
def initialize(handle = nil, contact = nil)
|
45
|
+
@handle = handle
|
46
|
+
@attributes = {}
|
47
|
+
self.attributes=(contact) if (@handle || contact)
|
48
|
+
end
|
49
|
+
|
50
|
+
#Test if a contact (defined by its handle) can create that domain.
|
51
|
+
#Takes a domain hash.
|
52
|
+
#TODO allow giving a string for the domain and converting it transparently, or a domain object.
|
53
|
+
#FIXME is checking multiple domains at once possible ? (it may be according to the Gandi documentation).
|
54
|
+
#FIXME OT&E seems to fail instead of returning an error hash (Error on object : OBJECT_APPLICATION (CAUSE_UNKNOWN) [Internal Server Error]).
|
55
|
+
def can_associate_domain(domain)
|
56
|
+
return false unless persisted?
|
57
|
+
self.class.call('contact.can_associate_domain', @handle, domain)
|
58
|
+
end
|
59
|
+
|
60
|
+
#TODO make this method return a boolean
|
61
|
+
alias_method :can_associate_domain?, :can_associate_domain
|
62
|
+
|
63
|
+
#Give all information on the given contact.
|
64
|
+
#This should not be directly used as initializing the class already fetches the contact info.
|
65
|
+
def info
|
66
|
+
raise DataError, "Cannot get informations for a new contact" unless persisted?
|
67
|
+
self.class.call('contact.info', @handle)
|
68
|
+
end
|
69
|
+
|
70
|
+
#Check the same way as check and then update.
|
71
|
+
#FIXME What is check ? Typo for create ?
|
72
|
+
def update(contact)
|
73
|
+
raise DataError, "Cannot update a new contact, use Gandi::Contact.create instead" unless persisted?
|
74
|
+
self.attributes = self.class.call('contact.update', @handle, contact)
|
75
|
+
end
|
76
|
+
|
77
|
+
(WRITABLE_ATTRIBUTES - [:type]).each do |attr|
|
78
|
+
define_method(attr) do
|
79
|
+
@attributes[attr.to_s]
|
80
|
+
end
|
81
|
+
|
82
|
+
define_method("#{attr}=") do |value|
|
83
|
+
@attributes[attr.to_s] = value
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#Returns the contact unique identifier.
|
88
|
+
def id
|
89
|
+
@attributes['id']
|
90
|
+
end
|
91
|
+
|
92
|
+
#Returns the contact type string.
|
93
|
+
def type
|
94
|
+
TYPES[@attributes['type']]
|
95
|
+
end
|
96
|
+
|
97
|
+
#Sets the contact type (provided with a type string or id).
|
98
|
+
def type=(type_string_or_id)
|
99
|
+
@attributes['type'] = TYPES.invert[type_string_or_id] || type_string_or_id
|
100
|
+
end
|
101
|
+
|
102
|
+
#Sets a contact attribute value.
|
103
|
+
def []=(attribute, value)
|
104
|
+
raise DataError, "Attribute #{attribute} is read-only" unless WRITABLE_ATTRIBUTES.include?(attribute.to_sym)
|
105
|
+
@attributes[attribute.to_s] = value
|
106
|
+
end
|
107
|
+
|
108
|
+
#Returns a string containing the handle of the contact.
|
109
|
+
def to_s
|
110
|
+
@handle || ''
|
111
|
+
end
|
112
|
+
|
113
|
+
#Returns true if the contact exists on Gandi databases.
|
114
|
+
def persisted?
|
115
|
+
!!@handle
|
116
|
+
end
|
117
|
+
|
118
|
+
class << self
|
119
|
+
#Should have a all optional contact dict then look if he is a person or a company and depending on that call create_person or create_company.
|
120
|
+
#Returns a contact object.
|
121
|
+
#TODO filter params.
|
122
|
+
def create(contact)
|
123
|
+
contact = call('contact.create', contact)
|
124
|
+
self.new(contact['handle'], contact)
|
125
|
+
end
|
126
|
+
|
127
|
+
#Give all information on the contact linked to the apikey currently used.
|
128
|
+
#Returns a hash.
|
129
|
+
def info
|
130
|
+
call('contact.info')
|
131
|
+
end
|
132
|
+
|
133
|
+
#Test if a contact (full contact description) can be associated to the domains.
|
134
|
+
#Takes a contact hash and a domain hash.
|
135
|
+
#TODO allow giving a string for the domain and converting it transparently, or a domain object.
|
136
|
+
#FIXME is checking multiple domains at once possible ? (it may be according to the Gandi documentation).
|
137
|
+
#FIXME OT&E seems to fail instead of returning an error hash (Error on object : OBJECT_APPLICATION (CAUSE_UNKNOWN) [Internal Server Error]).
|
138
|
+
def can_associate(contact, domain)
|
139
|
+
call('contact.can_associate', contact, domain)
|
140
|
+
end
|
141
|
+
|
142
|
+
#TODO make this method return a boolean
|
143
|
+
alias_method :can_associate?, :can_associate
|
144
|
+
|
145
|
+
#List all contacts linked to the connected user (it will only return contacts when the apikey belong to a reseller).
|
146
|
+
#The array of returned contacts are mapped to contact objects, set map_contacts to false to get contact info hashes.
|
147
|
+
def list(opts = {}, map_contacts = true)
|
148
|
+
contacts = call('contact.list', opts)
|
149
|
+
if map_contacts
|
150
|
+
contacts.map! do |contact|
|
151
|
+
self.new(contact['handle'], contact)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
contacts
|
155
|
+
end
|
156
|
+
|
157
|
+
#Check the same way as check and then update.
|
158
|
+
#Returns a contact object.
|
159
|
+
#TODO filter params.
|
160
|
+
def update(handle, contact)
|
161
|
+
contact = call('contact.update', handle, contact)
|
162
|
+
self.new(contact['handle'], contact)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def attributes=(contact = nil)
|
169
|
+
contact_attributes = contact || info
|
170
|
+
@attributes = contact_attributes.reject {|k,v| !INFORMATION_ATTRIBUTES.include?(k.to_sym) }
|
171
|
+
@attributes['handle'] = @handle || contact_attributes['handle']
|
172
|
+
return @attributes
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Gandi
|
2
|
+
class Domain
|
3
|
+
module Contacts
|
4
|
+
#Returns an hash of contacts, keys being the type of contact and values Gandi::Contact objects.
|
5
|
+
#TODO make the contact mapping optional.
|
6
|
+
def contacts
|
7
|
+
@attributes['contacts'].inject({}) { |h, contact| h[contact.first] = Gandi::Contact.new(contact.last['handle']); h }
|
8
|
+
end
|
9
|
+
|
10
|
+
#Change domain’s contact. Uses the API call domain.contacts.set
|
11
|
+
#Returns a Gandi::Operation object.
|
12
|
+
#NOTE: you cannot change the owner or reseller contacts.
|
13
|
+
#FIXME: is it possible to return the operation object and not the contacts hash passed as a param?
|
14
|
+
#TODO accept Gandi::Contact objects as values for the hash.
|
15
|
+
def contacts=(contacts)
|
16
|
+
operation_hash = self.class.call('domain.contacts.set', @fqdn, contacts)
|
17
|
+
Gandi::Operation.new(operation_hash['id'], operation_hash)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Gandi
|
2
|
+
class Domain
|
3
|
+
class Forward
|
4
|
+
include Gandi::GandiObjectMethods
|
5
|
+
|
6
|
+
attr_reader :domain, :source
|
7
|
+
|
8
|
+
def initialize(domain, source, attributes = nil)
|
9
|
+
@domain = domain
|
10
|
+
@source = source
|
11
|
+
@attributes = attributes || self.class.call('domain.forward.list', @domain.fqdn, {'source' => @source}).first
|
12
|
+
raise DataError, "Forward does not exist" unless @attributes
|
13
|
+
end
|
14
|
+
|
15
|
+
#Return the destinations emails for this forward.
|
16
|
+
def destinations
|
17
|
+
@attributes['destinations']
|
18
|
+
end
|
19
|
+
|
20
|
+
#Delete a forward.
|
21
|
+
#Return true.
|
22
|
+
def delete
|
23
|
+
self.class.call('domain.forward.delete', @domain.fqdn, @source)
|
24
|
+
end
|
25
|
+
|
26
|
+
#Update a forward.
|
27
|
+
#Return self.
|
28
|
+
def update(params)
|
29
|
+
@attributes = self.class.call('domain.forward.update', @domain.fqdn, @source, params)
|
30
|
+
return self
|
31
|
+
end
|
32
|
+
|
33
|
+
class << self
|
34
|
+
#Create a new forward.
|
35
|
+
#Return a Forward object.
|
36
|
+
def create(domain, source, params)
|
37
|
+
forward = call('domain.forward.create', domain.fqdn, source, params)
|
38
|
+
self.new(domain, source, forward)
|
39
|
+
end
|
40
|
+
|
41
|
+
#Count forwards for a domain.
|
42
|
+
#TODO: accept a fqdn string.
|
43
|
+
def count(domain, opts = {})
|
44
|
+
call('domain.forward.count', domain.fqdn, opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
#List forwards for specified domain.
|
48
|
+
#Return an array of Forward objects.
|
49
|
+
#TODO: accept a fqdn string.
|
50
|
+
def list(domain, opts = {})
|
51
|
+
call('domain.forward.list', domain.fqdn, opts).map do |forward|
|
52
|
+
self.new(domain, forward['source'], forward)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Gandi
|
2
|
+
class Domain
|
3
|
+
class Host
|
4
|
+
include Gandi::GandiObjectMethods
|
5
|
+
|
6
|
+
#The hostname of the Host
|
7
|
+
attr_reader :hostname
|
8
|
+
|
9
|
+
def initialize(hostname, attributes = nil)
|
10
|
+
@hostname = hostname
|
11
|
+
@attributes = attributes || info
|
12
|
+
end
|
13
|
+
|
14
|
+
#Delete a host.
|
15
|
+
#Returns a Gandi::Operation object.
|
16
|
+
def delete
|
17
|
+
operation_hash = self.class.call('domain.host.delete', @hostname)
|
18
|
+
Gandi::Operation.new(operation_hash['id'], operation_hash)
|
19
|
+
end
|
20
|
+
|
21
|
+
#Display host information for a given domain.
|
22
|
+
def info
|
23
|
+
self.class.call('domain.host.info', @hostname)
|
24
|
+
end
|
25
|
+
|
26
|
+
#Return the host IP adresses.
|
27
|
+
def ips
|
28
|
+
@attributes['ips']
|
29
|
+
end
|
30
|
+
|
31
|
+
#Update a host.
|
32
|
+
#Return a Gandi::Operation object.
|
33
|
+
def update(ips)
|
34
|
+
operation_hash = self.class.call('domain.host.update', @hostname, ips)
|
35
|
+
Gandi::Operation.new(operation_hash['id'], operation_hash)
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
#Create a host.
|
40
|
+
#Returns a Gandi::Operation object.
|
41
|
+
def create(hostname, ips)
|
42
|
+
operation_hash = call('domain.host.create', hostname, ips)
|
43
|
+
Gandi::Operation.new(operation_hash['id'], operation_hash)
|
44
|
+
end
|
45
|
+
|
46
|
+
#Count the glue records / hosts of a domain.
|
47
|
+
#TODO: accept a Domain object.
|
48
|
+
def count(fqdn, opts = {})
|
49
|
+
call('domain.host.count', fqdn, opts)
|
50
|
+
end
|
51
|
+
|
52
|
+
#List the glue records / hosts for a given domain.
|
53
|
+
#Return an array of Host objects.
|
54
|
+
#TODO: accept a Domain object.
|
55
|
+
def list(fqdn, opts = {})
|
56
|
+
call('domain.host.list', fqdn, opts).map do |host|
|
57
|
+
self.new(host['name'], host)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|