epp-client-afnic 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +5 -0
- data/EXAMPLE.AFNIC +70 -0
- data/Gemfile +6 -0
- data/MIT-LICENSE +19 -0
- data/README +5 -0
- data/Rakefile +37 -0
- data/epp-client-afnic.gemspec +40 -0
- data/lib/epp-client/afnic.rb +505 -0
- data/vendor/afnic/frnic-1.0.xsd +393 -0
- data/vendor/afnic/frnic-1.1.xsd +406 -0
- data/vendor/afnic/frnic-1.2.xsd +560 -0
- metadata +174 -0
data/ChangeLog
ADDED
data/EXAMPLE.AFNIC
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pp'
|
4
|
+
require 'rubygems'
|
5
|
+
require 'epp-client/afnic'
|
6
|
+
|
7
|
+
c = EPPClient::AFNIC.new(
|
8
|
+
:client_id => '-test-.fr',
|
9
|
+
:password => 'pass',
|
10
|
+
:ssl_cert => 'server.crt',
|
11
|
+
:ssl_key => 'server.key',
|
12
|
+
:test => true
|
13
|
+
)
|
14
|
+
|
15
|
+
begin
|
16
|
+
|
17
|
+
c.open_connection
|
18
|
+
c.login
|
19
|
+
if c.msgQ_count > 0
|
20
|
+
pp msg = c.poll_req
|
21
|
+
pp c.poll_ack if Hash === msg[:obj]
|
22
|
+
end
|
23
|
+
pp c.domain_check('mat.fr', 'nonexistantdomain.fr', 'paris.fr', 'trafiquants.fr', 'toto.wf')
|
24
|
+
pp c.domain_info('afnic.fr')
|
25
|
+
# pas de contact check
|
26
|
+
pp c.contact_info('A7534') # legal
|
27
|
+
pp c.contact_info('CT214') # particulier
|
28
|
+
pp contact = c.contact_create( {
|
29
|
+
:email=>"foo@example.org",
|
30
|
+
:authInfo => "foobar",
|
31
|
+
:voice=>"+33.123456787",
|
32
|
+
:postalInfo=> { "loc"=> { :addr=> { :city=>"Paris", :cc=>"FR", :pc=>"75001", :street=>["BP 18", "1, rue Royale"] }, :name=>"Dupond", :org => 'FooBar Inc.' }, },
|
33
|
+
#:list => 'restrictedPublication',
|
34
|
+
#:individualInfos => {:birthDate => '1978-01-01', :birthCc => 'FR', :birthPc => '75013', :birthCity => 'Paris'},
|
35
|
+
#:firstName => 'Jean',
|
36
|
+
:legalEntityInfos=> {:siren=>"418565404", :legalStatus=>"company"},
|
37
|
+
#:legalEntityInfos=> {:siren=>"418565404", :legalStatus=>"association", :asso => { :decl => '2001-01-01', :publ => {:date => '2001-01-02', :announce => 5, :page => 3}}},
|
38
|
+
#:legalEntityInfos=> {:siren=>"418565404", :legalStatus=>"association", :asso => { :waldec => 2 }},
|
39
|
+
})
|
40
|
+
pp c.contact_info(contact[:id])
|
41
|
+
pp c.contact_update({
|
42
|
+
:id => contact[:id],
|
43
|
+
:chg => {
|
44
|
+
:email => 'bazar@example.com',
|
45
|
+
}})
|
46
|
+
pp c.contact_info(contact[:id])
|
47
|
+
pp c.contact_info(contact[:id])
|
48
|
+
pp c.domain_create({
|
49
|
+
:registrant => "A7534",
|
50
|
+
:contacts => {:tech => ["ADM3"], :admin => ["ADM3"]},
|
51
|
+
:name => "truc-#{$$}.fr",
|
52
|
+
:authInfo => "PN16IZ0V"
|
53
|
+
})
|
54
|
+
pp c.domain_info(:name => "truc-#{$$}.fr")
|
55
|
+
pp c.domain_update({
|
56
|
+
:name => "truc-#{$$}.fr",
|
57
|
+
#:chg => { :authInfo => 'bazar' },
|
58
|
+
:add => {
|
59
|
+
:ns => %w(ns1.absolight.net ns2.absolight.net ns3.absolight.net ns4.absolight.net),
|
60
|
+
},
|
61
|
+
})
|
62
|
+
pp c.domain_info(:name => "truc-#{$$}.fr")
|
63
|
+
pp c.domain_delete("truc-#{$$}.fr")
|
64
|
+
pp c.domain_info(:name => "truc-#{$$}.fr")
|
65
|
+
pp c.domain_restore(:name => "truc-#{$$}.fr")
|
66
|
+
pp c.domain_info(:name => "truc-#{$$}.fr")
|
67
|
+
|
68
|
+
ensure
|
69
|
+
c.logout
|
70
|
+
end
|
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (C) 2010 Mathieu Arnold, Absolight
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
4
|
+
this software and associated documentation files (the "Software"), to deal in
|
5
|
+
the Software without restriction, including without limitation the rights to
|
6
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
7
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
8
|
+
so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake'
|
3
|
+
require 'rdoc/task'
|
4
|
+
require 'rubygems/package_task'
|
5
|
+
require "bundler/gem_helper"
|
6
|
+
|
7
|
+
MY_GEMS = Dir['*.gemspec'].map {|g| g.sub(/.*-(.*)\.gemspec/, '\1')}
|
8
|
+
|
9
|
+
MY_GEMS.each do |g|
|
10
|
+
namespace g do
|
11
|
+
Bundler::GemHelper.new(Dir.pwd, "epp-client-#{g}").install
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :all do
|
16
|
+
task :build => MY_GEMS.map { |f| "#{f}:build" }
|
17
|
+
task :install => MY_GEMS.map { |f| "#{f}:install" }
|
18
|
+
task :release => MY_GEMS.map { |f| "#{f}:release" }
|
19
|
+
end
|
20
|
+
|
21
|
+
task :build => 'all:build'
|
22
|
+
task :install => 'all:install'
|
23
|
+
task :release => 'all:release'
|
24
|
+
|
25
|
+
desc "Generate documentation for the Rails framework"
|
26
|
+
Rake::RDocTask.new do |rdoc|
|
27
|
+
rdoc.rdoc_dir = 'doc/rdoc'
|
28
|
+
rdoc.title = "Documentation"
|
29
|
+
|
30
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
31
|
+
rdoc.options << '--charset' << 'utf-8'
|
32
|
+
|
33
|
+
rdoc.rdoc_files.include('README')
|
34
|
+
rdoc.rdoc_files.include('ChangeLog')
|
35
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
36
|
+
end
|
37
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/epp-client/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'epp-client-afnic'
|
6
|
+
gem.version = EPPClient::VERSION
|
7
|
+
gem.date = '2010-05-14'
|
8
|
+
gem.authors = ['Mathieu Arnold']
|
9
|
+
gem.email = ['m@absolight.fr']
|
10
|
+
gem.description = 'AFNIC EPP client library.'
|
11
|
+
gem.summary = 'AFNIC EPP client library'
|
12
|
+
gem.homepage = "https://github.com/Absolight/epp-client"
|
13
|
+
|
14
|
+
gem.required_ruby_version = '>= 1.8.7'
|
15
|
+
gem.required_rubygems_version = ">= 1.3.6"
|
16
|
+
|
17
|
+
gem.files = [
|
18
|
+
'ChangeLog',
|
19
|
+
'EXAMPLE.AFNIC',
|
20
|
+
'Gemfile',
|
21
|
+
'MIT-LICENSE',
|
22
|
+
'README',
|
23
|
+
'Rakefile',
|
24
|
+
'epp-client-afnic.gemspec',
|
25
|
+
'lib/epp-client/afnic.rb',
|
26
|
+
'vendor/afnic/frnic-1.0.xsd',
|
27
|
+
'vendor/afnic/frnic-1.1.xsd',
|
28
|
+
'vendor/afnic/frnic-1.2.xsd',
|
29
|
+
]
|
30
|
+
|
31
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
32
|
+
gem.require_paths = ['lib']
|
33
|
+
|
34
|
+
gem.add_development_dependency "bundler", ">= 1.0.0"
|
35
|
+
gem.add_dependency('nokogiri', '~> 1.4')
|
36
|
+
gem.add_dependency('builder', '>= 2.1.2')
|
37
|
+
gem.add_dependency('epp-client-base', "~> #{EPPClient::VERSION}")
|
38
|
+
gem.add_dependency('epp-client-rgp', "~> #{EPPClient::VERSION}")
|
39
|
+
gem.add_dependency('epp-client-secdns', "~> #{EPPClient::VERSION}")
|
40
|
+
end
|
@@ -0,0 +1,505 @@
|
|
1
|
+
require 'epp-client/base'
|
2
|
+
require 'epp-client/rgp'
|
3
|
+
require 'epp-client/secdns'
|
4
|
+
|
5
|
+
module EPPClient
|
6
|
+
class AFNIC < Base
|
7
|
+
SCHEMAS_AFNIC = %w[
|
8
|
+
frnic-1.2
|
9
|
+
]
|
10
|
+
|
11
|
+
EPPClient::SCHEMAS_URL.merge!(SCHEMAS_AFNIC.inject({}) do |a,s|
|
12
|
+
a[s.sub(/-1\.2$/, '')] = "http://www.afnic.fr/xml/epp/#{s}" if s =~ /-1\.2$/
|
13
|
+
a[s] = "http://www.afnic.fr/xml/epp/#{s}"
|
14
|
+
a
|
15
|
+
end)
|
16
|
+
|
17
|
+
# Sets the default for AFNIC, that is, server and port, according to
|
18
|
+
# AFNIC's documentation.
|
19
|
+
# http://www.afnic.fr/doc/interface/epp
|
20
|
+
#
|
21
|
+
# ==== Optional Attributes
|
22
|
+
# [<tt>:test</tt>] sets the server to be the test server.
|
23
|
+
def initialize(args)
|
24
|
+
if args.delete(:test) == true
|
25
|
+
args[:server] ||= 'epp.test.nic.fr'
|
26
|
+
else
|
27
|
+
args[:server] ||= 'epp.nic.fr'
|
28
|
+
end
|
29
|
+
@services = EPPClient::SCHEMAS_URL.values_at('domain', 'contact')
|
30
|
+
args[:port] ||= 700
|
31
|
+
super(args)
|
32
|
+
@extensions << EPPClient::SCHEMAS_URL['frnic']
|
33
|
+
end
|
34
|
+
|
35
|
+
# Extends the base domain check so that the specific afnic check
|
36
|
+
# informations are processed, the additionnal informations are :
|
37
|
+
#
|
38
|
+
# [<tt>:reserved</tt>] the domain is a reserved name.
|
39
|
+
# [<tt>:rsvReason</tt>] the optional reason why the domain is reserved.
|
40
|
+
# [<tt>:forbidden</tt>] the domain is a forbidden name.
|
41
|
+
# [<tt>:fbdReason</tt>] the optional reason why the domain is forbidden.
|
42
|
+
def domain_check(*domains)
|
43
|
+
super # placeholder so that I can add some doc
|
44
|
+
end
|
45
|
+
|
46
|
+
def domain_check_process(xml) # :nodoc:
|
47
|
+
ret = super
|
48
|
+
xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:chkData/frnic:domain/frnic:cd', EPPClient::SCHEMAS_URL).each do |dom|
|
49
|
+
name = dom.xpath('frnic:name', EPPClient::SCHEMAS_URL)
|
50
|
+
hash = ret.select {|d| d[:name] == name.text}.first
|
51
|
+
hash[:reserved] = name.attr('reserved').value == "1"
|
52
|
+
unless (reason = dom.xpath('frnic:rsvReason', EPPClient::SCHEMAS_URL).text).empty?
|
53
|
+
hash[:rsvReason] = reason
|
54
|
+
end
|
55
|
+
hash[:forbidden] = name.attr('forbidden').value == "1"
|
56
|
+
unless (reason = dom.xpath('frnic:fbdReason', EPPClient::SCHEMAS_URL).text).empty?
|
57
|
+
hash[:fbdReason] = reason
|
58
|
+
end
|
59
|
+
end
|
60
|
+
return ret
|
61
|
+
end
|
62
|
+
|
63
|
+
# Extends the base domain info so that the specific afnic <tt>:status</tt>
|
64
|
+
# can be added.
|
65
|
+
def domain_info(domain)
|
66
|
+
super # placeholder so that I can add some doc
|
67
|
+
end
|
68
|
+
|
69
|
+
def domain_info_process(xml) #:nodoc:
|
70
|
+
ret = super
|
71
|
+
if (frnic_status = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:infData/frnic:domain/frnic:status', EPPClient::SCHEMAS_URL)).size > 0
|
72
|
+
ret[:status] += frnic_status.map {|s| s.attr('s')}
|
73
|
+
end
|
74
|
+
ret
|
75
|
+
end
|
76
|
+
|
77
|
+
# parse legalEntityInfos content.
|
78
|
+
def legalEntityInfos(leI) #:nodoc:
|
79
|
+
ret = {}
|
80
|
+
ret[:legalStatus] = leI.xpath('frnic:legalStatus', EPPClient::SCHEMAS_URL).attr('s').value
|
81
|
+
if (r = leI.xpath("frnic:idStatus", EPPClient::SCHEMAS_URL)).size > 0
|
82
|
+
ret[:idStatus] = {:value => r.text}
|
83
|
+
ret[:idStatus][:when] = r.attr('when').value if r.attr('when')
|
84
|
+
ret[:idStatus][:source] = r.attr('source').value if r.attr('source')
|
85
|
+
end
|
86
|
+
%w(siren VAT trademark DUNS local).each do |val|
|
87
|
+
if (r = leI.xpath("frnic:#{val}", EPPClient::SCHEMAS_URL)).size > 0
|
88
|
+
ret[val.to_sym] = r.text
|
89
|
+
end
|
90
|
+
end
|
91
|
+
if (asso = leI.xpath("frnic:asso", EPPClient::SCHEMAS_URL)).size > 0
|
92
|
+
ret[:asso] = {}
|
93
|
+
if (r = asso.xpath("frnic:waldec", EPPClient::SCHEMAS_URL)).size > 0
|
94
|
+
ret[:asso][:waldec] = r.text
|
95
|
+
else
|
96
|
+
if (decl = asso.xpath('frnic:decl', EPPClient::SCHEMAS_URL)).size > 0
|
97
|
+
ret[:asso][:decl] = Date.parse(decl.text)
|
98
|
+
end
|
99
|
+
publ = asso.xpath('frnic:publ', EPPClient::SCHEMAS_URL)
|
100
|
+
ret[:asso][:publ] = {
|
101
|
+
:date => Date.parse(publ.text),
|
102
|
+
:page => publ.attr('page').value,
|
103
|
+
}
|
104
|
+
if (announce = publ.attr('announce')) && announce.value != '0'
|
105
|
+
ret[:asso][:publ][:announce] = announce.value
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
ret
|
110
|
+
end
|
111
|
+
private :legalEntityInfos
|
112
|
+
|
113
|
+
# Extends the base contact info so that the specific afnic check
|
114
|
+
# informations are processed, the additionnal informations are :
|
115
|
+
#
|
116
|
+
# either :
|
117
|
+
# [<tt>:legalEntityInfos</tt>]
|
118
|
+
# indicating that the contact is an organisation with the following
|
119
|
+
# informations :
|
120
|
+
# [<tt>:legalStatus</tt>]
|
121
|
+
# should be either +company+, +association+ or +other+.
|
122
|
+
# [<tt>:idStatus</tt>]
|
123
|
+
# indicates the identification process status. Has optional
|
124
|
+
# <tt>:when</tt> and <tt>:source</tt> attributes.
|
125
|
+
# [<tt>:siren</tt>] contains the SIREN number of the organisation.
|
126
|
+
# [<tt>:VAT</tt>]
|
127
|
+
# is optional and contains the VAT number of the organisation.
|
128
|
+
# [<tt>:trademark</tt>]
|
129
|
+
# is optional and contains the trademark number of the organisation.
|
130
|
+
# [<tt>:DUNS</tt>]
|
131
|
+
# is optional and contains the Data Universal Numbering System number of
|
132
|
+
# the organisation.
|
133
|
+
# [<tt>:local</tt>]
|
134
|
+
# is optional and contains an identifier local to the eligible country.
|
135
|
+
# [<tt>:asso</tt>]
|
136
|
+
# indicates the organisation is an association and contains either a
|
137
|
+
# +waldec+ or a +decl+ and a +publ+ :
|
138
|
+
# [<tt>:waldec</tt>] contains the waldec id of the association.
|
139
|
+
# [<tt>:decl</tt>]
|
140
|
+
# optionally indicate the date of the association was declared at the
|
141
|
+
# prefecture.
|
142
|
+
# [<tt>:publ</tt>]
|
143
|
+
# contains informations regarding the publication in the "Journal
|
144
|
+
# Officiel" :
|
145
|
+
# [<tt>:date</tt>] the date of publication.
|
146
|
+
# [<tt>:page</tt>] the page the announce is on.
|
147
|
+
# [<tt>:announce</tt>] the announce number on the page (optional).
|
148
|
+
# [<tt>:individualInfos</tt>]
|
149
|
+
# indicating that the contact is a person with the following
|
150
|
+
# informations :
|
151
|
+
# [<tt>:idStatus</tt>]
|
152
|
+
# indicates the identification process status. Has optional
|
153
|
+
# <tt>:when</tt> and <tt>:source</tt> attributes.
|
154
|
+
# [<tt>:birthDate</tt>] the date of birth of the contact.
|
155
|
+
# [<tt>:birthCity</tt>] the city of birth of the contact.
|
156
|
+
# [<tt>:birthPc</tt>] the postal code of the city of birth.
|
157
|
+
# [<tt>:birthCc</tt>] the country code of the place of birth.
|
158
|
+
#
|
159
|
+
# Additionnaly, when the contact is a person, there can be the following
|
160
|
+
# informations :
|
161
|
+
# [<tt>:firstName</tt>]
|
162
|
+
# the first name of the person. (The last name being stored in the +name+
|
163
|
+
# field in the +postalInfo+.)
|
164
|
+
# [<tt>:list</tt>]
|
165
|
+
# with the value of +restrictedPublication+ mean that the element
|
166
|
+
# diffusion should be restricted.
|
167
|
+
#
|
168
|
+
# Optionnaly, there can be :
|
169
|
+
# [<tt>:obsoleted</tt>]
|
170
|
+
# the contact info is obsolete since/from the optional date <tt>:when</tt>.
|
171
|
+
# [<tt>:reachable</tt>]
|
172
|
+
# the contact is reachable through the optional <tt>:media</tt> since/from
|
173
|
+
# the optional date <tt>:when</tt>. The info having been specified by the
|
174
|
+
# <tt>:source</tt>.
|
175
|
+
def contact_info(contact)
|
176
|
+
super # placeholder so that I can add some doc
|
177
|
+
end
|
178
|
+
|
179
|
+
def contact_info_process(xml) #:nodoc:
|
180
|
+
ret = super
|
181
|
+
if (contact = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:infData/frnic:contact', EPPClient::SCHEMAS_URL)).size > 0
|
182
|
+
if (list = contact.xpath('frnic:list', EPPClient::SCHEMAS_URL)).size > 0
|
183
|
+
ret[:list] = list.map {|l| l.text}
|
184
|
+
end
|
185
|
+
if (firstName = contact.xpath('frnic:firstName', EPPClient::SCHEMAS_URL)).size > 0
|
186
|
+
ret[:firstName] = firstName.text
|
187
|
+
end
|
188
|
+
if (iI = contact.xpath('frnic:individualInfos', EPPClient::SCHEMAS_URL)).size > 0
|
189
|
+
ret[:individualInfos] = {}
|
190
|
+
ret[:individualInfos][:birthDate] = Date.parse(iI.xpath('frnic:birthDate', EPPClient::SCHEMAS_URL).text)
|
191
|
+
if (r = iI.xpath("frnic:idStatus", EPPClient::SCHEMAS_URL)).size > 0
|
192
|
+
ret[:individualInfos][:idStatus] = {:value => r.text}
|
193
|
+
ret[:individualInfos][:idStatus][:when] = r.attr('when').value if r.attr('when')
|
194
|
+
ret[:individualInfos][:idStatus][:source] = r.attr('source').value if r.attr('source')
|
195
|
+
end
|
196
|
+
%w(birthCity birthPc birthCc).each do |val|
|
197
|
+
if (r = iI.xpath("frnic:#{val}", EPPClient::SCHEMAS_URL)).size > 0
|
198
|
+
ret[:individualInfos][val.to_sym] = r.text
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if (leI = contact.xpath('frnic:legalEntityInfos', EPPClient::SCHEMAS_URL)).size > 0
|
203
|
+
ret[:legalEntityInfos] = legalEntityInfos(leI)
|
204
|
+
end
|
205
|
+
if (obsoleted = contact.xpath('frnic:obsoleted', EPPClient::SCHEMAS_URL)).size > 0
|
206
|
+
if obsoleted.text != '0'
|
207
|
+
ret[:obsoleted] = {}
|
208
|
+
ret[:obsoleted][:when] = DateTime.parse(v_when.value) if v_when = obsoleted.attr('when')
|
209
|
+
end
|
210
|
+
end
|
211
|
+
if (reachable = contact.xpath('frnic:reachable', EPPClient::SCHEMAS_URL)).size > 0
|
212
|
+
if reachable.text != '0'
|
213
|
+
ret[:reachable] = {}
|
214
|
+
if v_when = reachable.attr('when')
|
215
|
+
ret[:reachable][:when] = DateTime.parse(v_when.value)
|
216
|
+
end
|
217
|
+
if media = reachable.attr('media')
|
218
|
+
ret[:reachable][:media] = media.value
|
219
|
+
end
|
220
|
+
if source = reachable.attr('source')
|
221
|
+
ret[:reachable][:source] = source.value
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
ret
|
227
|
+
end
|
228
|
+
|
229
|
+
def contact_create_xml(contact) #:nodoc:
|
230
|
+
ret = super
|
231
|
+
|
232
|
+
ext = extension do |xml|
|
233
|
+
xml.ext( :xmlns => EPPClient::SCHEMAS_URL['frnic']) do
|
234
|
+
xml.create do
|
235
|
+
xml.contact do
|
236
|
+
if contact.key?(:legalEntityInfos)
|
237
|
+
lEI = contact[:legalEntityInfos]
|
238
|
+
xml.legalEntityInfos do
|
239
|
+
xml.idStatus(lEI[:idStatus]) if lEI.key?(:idStatus)
|
240
|
+
xml.legalStatus(:s => lEI[:legalStatus])
|
241
|
+
[:siren, :VAT, :trademark, :DUNS, :local].each do |val|
|
242
|
+
if lEI.key?(val)
|
243
|
+
xml.__send__(val, lEI[val])
|
244
|
+
end
|
245
|
+
end
|
246
|
+
if lEI.key?(:asso)
|
247
|
+
asso = lEI[:asso]
|
248
|
+
xml.asso do
|
249
|
+
if asso.key?(:waldec)
|
250
|
+
xml.waldec(asso[:waldec])
|
251
|
+
else
|
252
|
+
xml.decl(asso[:decl]) if asso.key?(:decl)
|
253
|
+
attrs = {:page => asso[:publ][:page]}
|
254
|
+
attrs[:announce] = asso[:publ][:announce] if asso[:publ].key?(:announce)
|
255
|
+
xml.publ(attrs, asso[:publ][:date])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
else
|
261
|
+
if contact.key?(:list)
|
262
|
+
xml.list(contact[:list])
|
263
|
+
end
|
264
|
+
if contact.key?(:individualInfos)
|
265
|
+
iI = contact[:individualInfos]
|
266
|
+
xml.individualInfos do
|
267
|
+
xml.idStatus(iI[:idStatus]) if iI.key?(:idStatus)
|
268
|
+
xml.birthDate(iI[:birthDate])
|
269
|
+
if iI.key?(:birthCity)
|
270
|
+
xml.birthCity(iI[:birthCity])
|
271
|
+
end
|
272
|
+
if iI.key?(:birthPc)
|
273
|
+
xml.birthPc(iI[:birthPc])
|
274
|
+
end
|
275
|
+
xml.birthCc(iI[:birthCc])
|
276
|
+
end
|
277
|
+
end
|
278
|
+
if contact.key?(:firstName)
|
279
|
+
xml.firstName(contact[:firstName])
|
280
|
+
end
|
281
|
+
end
|
282
|
+
if contact.key?(:reachable)
|
283
|
+
if Hash === (reachable = contact[:reachable])
|
284
|
+
xml.reachable(reachable, 1)
|
285
|
+
else
|
286
|
+
raise ArgumentError, "reachable has to be a Hash"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
insert_extension(ret, ext)
|
295
|
+
end
|
296
|
+
|
297
|
+
# Extends the base contact create so that the specific afnic create
|
298
|
+
# informations can be sent, the additionnal informations are :
|
299
|
+
#
|
300
|
+
# either :
|
301
|
+
# [<tt>:legalEntityInfos</tt>]
|
302
|
+
# indicating that the contact is an organisation with the following
|
303
|
+
# informations :
|
304
|
+
# [<tt>:idStatus</tt>]
|
305
|
+
# indicates the identification process status.
|
306
|
+
# [<tt>:legalStatus</tt>]
|
307
|
+
# should be either +company+, +association+ or +other+.
|
308
|
+
# [<tt>:siren</tt>] contains the SIREN number of the organisation.
|
309
|
+
# [<tt>:VAT</tt>]
|
310
|
+
# is optional and contains the VAT number of the organisation.
|
311
|
+
# [<tt>:trademark</tt>]
|
312
|
+
# is optional and contains the trademark number of the organisation.
|
313
|
+
# [<tt>:DUNS</tt>]
|
314
|
+
# is optional and contains the Data Universal Numbering System number of
|
315
|
+
# the organisation.
|
316
|
+
# [<tt>:local</tt>]
|
317
|
+
# is optional and contains an identifier local to the eligible country.
|
318
|
+
# [<tt>:asso</tt>]
|
319
|
+
# indicates the organisation is an association and contains either a
|
320
|
+
# +waldec+ or a +decl+ and a +publ+ :
|
321
|
+
# [<tt>:waldec</tt>] contains the waldec id of the association.
|
322
|
+
# [<tt>:decl</tt>]
|
323
|
+
# optionally indicate the date of the association was declared at the
|
324
|
+
# prefecture.
|
325
|
+
# [<tt>:publ</tt>]
|
326
|
+
# contains informations regarding the publication in the "Journal
|
327
|
+
# Officiel" :
|
328
|
+
# [<tt>:date</tt>] the date of publication.
|
329
|
+
# [<tt>:page</tt>] the page the announce is on.
|
330
|
+
# [<tt>:announce</tt>] the announce number on the page (optional).
|
331
|
+
# [<tt>:individualInfos</tt>]
|
332
|
+
# indicating that the contact is a person with the following
|
333
|
+
# informations :
|
334
|
+
# [<tt>:idStatus</tt>]
|
335
|
+
# indicates the identification process status.
|
336
|
+
# [<tt>:birthDate</tt>] the date of birth of the contact.
|
337
|
+
# [<tt>:birthCity</tt>] the city of birth of the contact.
|
338
|
+
# [<tt>:birthPc</tt>] the postal code of the city of birth.
|
339
|
+
# [<tt>:birthCc</tt>] the country code of the place of birth.
|
340
|
+
#
|
341
|
+
# Additionnaly, when the contact is a person, there can be the following
|
342
|
+
# informations :
|
343
|
+
# [<tt>:firstName</tt>]
|
344
|
+
# the first name of the person. (The last name being stored in the +name+
|
345
|
+
# field in the +postalInfo+.)
|
346
|
+
# [<tt>:list</tt>]
|
347
|
+
# with the value of +restrictedPublication+ mean that the element
|
348
|
+
# diffusion should be restricted.
|
349
|
+
#
|
350
|
+
# Optionnaly, there can be :
|
351
|
+
# [<tt>:reachable</tt>]
|
352
|
+
# the contact is reachable through the optional <tt>:media</tt>.
|
353
|
+
#
|
354
|
+
# The returned information contains new keys :
|
355
|
+
# [<tt>:idStatus</tt>]
|
356
|
+
# indicates the identification process status. It's only present when the
|
357
|
+
# created contact was created with the +:individualInfos+ or
|
358
|
+
# +:legalEntityInfos+ extensions.
|
359
|
+
# [<tt>:nhStatus</tt>]
|
360
|
+
# is a boolean indicating wether the contact is really new, or if there
|
361
|
+
# was already a contact with the exact same informations in the database,
|
362
|
+
# in which case, it has been returned.
|
363
|
+
def contact_create(contact)
|
364
|
+
super # placeholder so that I can add some doc
|
365
|
+
end
|
366
|
+
|
367
|
+
def contact_create_process(xml) #:nodoc:
|
368
|
+
ret = super
|
369
|
+
if (creData = xml.xpath('epp:extension/frnic:ext/frnic:resData/frnic:creData', EPPClient::SCHEMAS_URL)).size > 0
|
370
|
+
ret[:nhStatus] = creData.xpath('frnic:nhStatus', EPPClient::SCHEMAS_URL).attr('new').value == '1'
|
371
|
+
ret[:idStatus] = creData.xpath('frnic:idStatus', EPPClient::SCHEMAS_URL).text
|
372
|
+
end
|
373
|
+
ret
|
374
|
+
end
|
375
|
+
|
376
|
+
# Make sure there's no <tt>:ns</tt>, <tt>:dsData</tt> or <tt>:keyData</tt>
|
377
|
+
# records, AFNIC's servers sends quite a strange error when there is.
|
378
|
+
def domain_create(args)
|
379
|
+
raise ArgumentError, "You can't create a domain with ns records, you must do an update afterwards" if args.key?(:ns)
|
380
|
+
raise ArgumentError, "You can't create a domain with ds or key records, you must do an update afterwards" if args.key?(:dsData) || args.key?(:keyData)
|
381
|
+
super
|
382
|
+
end
|
383
|
+
|
384
|
+
# Raises an exception, as contacts are deleted with a garbage collector.
|
385
|
+
def contact_delete(args)
|
386
|
+
raise NotImplementedError, "Contacts are deleted with a garbage collector"
|
387
|
+
end
|
388
|
+
|
389
|
+
def contact_update_xml(args) #:nodoc:
|
390
|
+
ret = super
|
391
|
+
|
392
|
+
if [:add, :rem].any? {|c| args.key?(c) && [:list, :reachable, :idStatus].any? {|k| args[c].key?(k)}}
|
393
|
+
ext = extension do |xml|
|
394
|
+
xml.ext( :xmlns => EPPClient::SCHEMAS_URL['frnic']) do
|
395
|
+
xml.update do
|
396
|
+
xml.contact do
|
397
|
+
[:add, :rem].each do |c|
|
398
|
+
if args.key?(c) && [:list, :reachable, :idStatus].any? {|k| args[c].key?(k)}
|
399
|
+
xml.__send__(c) do
|
400
|
+
if args[c].key?(:list)
|
401
|
+
xml.list(args[c][:list])
|
402
|
+
end
|
403
|
+
if args[c].key?(:idStatus)
|
404
|
+
xml.idStatus(args[c][:idStatus])
|
405
|
+
end
|
406
|
+
if args[c].key?(:reachable)
|
407
|
+
if Hash === (reachable = args[c][:reachable])
|
408
|
+
xml.reachable(reachable, 1)
|
409
|
+
else
|
410
|
+
raise ArgumentError, "reachable has to be a Hash"
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|
420
|
+
|
421
|
+
return insert_extension(ret, ext)
|
422
|
+
else
|
423
|
+
return ret
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
# Extends the base contact update so that the specific afnic update
|
428
|
+
# informations can be sent, the additionnal informations are :
|
429
|
+
#
|
430
|
+
# [<tt>:add</tt>/<tt>:rem</tt>]
|
431
|
+
# adds or removes the following datas :
|
432
|
+
# [<tt>:list</tt>]
|
433
|
+
# with the value of +restrictedPublication+ mean that the element
|
434
|
+
# diffusion should/should not be restricted.
|
435
|
+
# [<tt>:idStatus</tt>]
|
436
|
+
# indicates the identification process status.
|
437
|
+
# [<tt>:reachable</tt>]
|
438
|
+
# the contact is reachable through the optional <tt>:media</tt>.
|
439
|
+
def contact_update(args)
|
440
|
+
super # placeholder so that I can add some doc
|
441
|
+
end
|
442
|
+
|
443
|
+
# Extends the base domain update so that afnic's weirdnesses can be taken
|
444
|
+
# into account.
|
445
|
+
#
|
446
|
+
# AFNIC does not support ns/hostObj, only ns/hostAttr/Host*, so, take care
|
447
|
+
# of this here.
|
448
|
+
# Also, you can only do one of the following at a time :
|
449
|
+
# * update contacts
|
450
|
+
# * update name servers
|
451
|
+
# * update status & authInfo
|
452
|
+
def domain_update(args)
|
453
|
+
if args.key?(:chg) && args[:chg].key?(:registrant)
|
454
|
+
raise ArgumentError, "You need to do a trade or recover operation to change the registrant"
|
455
|
+
end
|
456
|
+
has_contacts = args.key?(:add) && args[:add].key?(:contacts) || args.key?(:add) && args[:add].key?(:contacts)
|
457
|
+
has_ns = args.key?(:add) && args[:add].key?(:ns) || args.key?(:add) && args[:add].key?(:ns)
|
458
|
+
has_other = args.key?(:add) && args[:add].key?(:status) || args.key?(:add) && args[:add].key?(:status) || args.key?(:chg) && args[:chg].key?(:authInfo)
|
459
|
+
if [has_contacts, has_ns, has_other].select {|v| v}.size > 1
|
460
|
+
raise ArgumentError, "You can't update all that at one time"
|
461
|
+
end
|
462
|
+
[:add, :rem].each do |ar|
|
463
|
+
if args.key?(ar) && args[ar].key?(:ns) && String === args[ar][:ns].first
|
464
|
+
args[ar][:ns] = args[ar][:ns].map {|ns| {:hostName => ns}}
|
465
|
+
end
|
466
|
+
end
|
467
|
+
super
|
468
|
+
end
|
469
|
+
|
470
|
+
# Extends the base poll req to be able to parse quallification response
|
471
|
+
# extension.
|
472
|
+
def poll_req
|
473
|
+
super # placeholder so that I can add some doc
|
474
|
+
end
|
475
|
+
|
476
|
+
def poll_req_process(xml) #:nodoc:
|
477
|
+
ret = super(xml)
|
478
|
+
if (quaData = xml.xpath('epp:extension/frnic:resData/frnic:quaData', EPPClient::SCHEMAS_URL)).size > 0
|
479
|
+
if (contact = xml.xpath('frnic:contact', EPPClient::SCHEMAS_URL)).size > 0
|
480
|
+
cret = {:id => contact.xpath('frnic:id', EPPClient::SCHEMAS_URL).text}
|
481
|
+
qP = contact.xpath('frnic:qualificationProcess', EPPClient::SCHEMAS_URL)
|
482
|
+
cret[:qualificationProcess][:s] = qP.attr('s').value
|
483
|
+
cret[:qualificationProcess][:lang] = qP.attr('lang').value if qP.attr('lang')
|
484
|
+
if (leI = contact.xpath('frnic:legalEntityInfos', EPPClient::SCHEMAS_URL)).size > 0
|
485
|
+
ret[:legalEntityInfos] = legalEntityInfos(leI)
|
486
|
+
end
|
487
|
+
reach = contact.xpath('frnic:reachability', EPPClient::SCHEMAS_URL)
|
488
|
+
cret[:reachability] = {:reStatus => reach.xpath('frnic:reStatus', EPPClient::SCHEMAS_URL).text}
|
489
|
+
if (voice = reach.xpath('frnic:voice', EPPClient::SCHEMAS_URL)).size > 0
|
490
|
+
cret[:reachability][:voice] = voice.text
|
491
|
+
end
|
492
|
+
if (email = reach.xpath('frnic:email', EPPClient::SCHEMAS_URL)).size > 0
|
493
|
+
cret[:reachability][:email] = email.text
|
494
|
+
end
|
495
|
+
ret[:quaData] = {:contact => cret}
|
496
|
+
end
|
497
|
+
end
|
498
|
+
ret
|
499
|
+
end
|
500
|
+
|
501
|
+
# keep that at the end.
|
502
|
+
include EPPClient::RGP
|
503
|
+
include EPPClient::SecDNS
|
504
|
+
end
|
505
|
+
end
|