Merge branch 'master' of github.com:internetee/registry

Conflicts:
	db/schema.rb
This commit is contained in:
Andres Keskküla 2014-12-18 13:55:37 +02:00
commit e991ab36f9
48 changed files with 7925 additions and 143 deletions

View file

@ -160,4 +160,7 @@ group :development do
gem 'guard-rspec', '~> 4.3.1' gem 'guard-rspec', '~> 4.3.1'
gem 'rubocop', '~> 0.26.1' gem 'rubocop', '~> 0.26.1'
gem 'guard-rubocop', '~> 1.1.0' gem 'guard-rubocop', '~> 1.1.0'
# to generate database diagrams
gem 'railroady'
end end

View file

@ -210,6 +210,7 @@ GEM
rack (1.5.2) rack (1.5.2)
rack-test (0.6.2) rack-test (0.6.2)
rack (>= 1.0) rack (>= 1.0)
railroady (1.2.0)
rails (4.1.4) rails (4.1.4)
actionmailer (= 4.1.4) actionmailer (= 4.1.4)
actionpack (= 4.1.4) actionpack (= 4.1.4)
@ -403,6 +404,7 @@ DEPENDENCIES
phantomjs-binaries (~> 1.9.2.4) phantomjs-binaries (~> 1.9.2.4)
poltergeist (~> 1.5.1) poltergeist (~> 1.5.1)
pry (~> 0.10.1) pry (~> 0.10.1)
railroady
rails (= 4.1.4) rails (= 4.1.4)
rails-settings-cached (= 0.4.1) rails-settings-cached (= 0.4.1)
ransack (~> 1.3.0) ransack (~> 1.3.0)

105
README.md
View file

@ -3,6 +3,11 @@ Domain Registry
Full stack top-level domain (TLD) management. Full stack top-level domain (TLD) management.
* [Installation](https://github.com/internetee/registry#installation)
* [Testing](https://github.com/internetee/registry#testing)
* [Documentation](https://github.com/internetee/registry#documentation)
* [Deployment](https://github.com/internetee/registry#deployment)
Installation Installation
------------ ------------
@ -102,8 +107,6 @@ Note: Its best to go with two virtual hosts, one for test and one for dev,
then you don't have to worry about quitting then you don't have to worry about quitting
the dev appserver for running tests (because of colliding ports). the dev appserver for running tests (because of colliding ports).
For plain TCP EPP configuration, see below (may be useful for debugging purposes).
sudo a2ensite epp_ssl sudo a2ensite epp_ssl
sudo service apache2 restart sudo service apache2 restart
@ -148,9 +151,9 @@ Please follow WHOIS server readme:
https://github.com/internetee/whois https://github.com/internetee/whois
Testing Testing
--- -------
* Before running tests for the first time: `RAILS_ENV=test rake db:seed` * Before running tests for the first time: `RAILS_ENV=test rake db:seed`
* Run tests: `rake` * Run tests: `rake`
* Run EPP tests: `rake test:epp` * Run EPP tests: `rake test:epp`
@ -161,12 +164,7 @@ To see internal errors while testing EPP
unicorn -E test -p 8989 unicorn -E test -p 8989
rake spec:epp rake spec:epp
Visual testing ### Apache mod_epp testing/debugging
---
* For visual testing, install this [application](https://github.com/mlensment/epp-tester)
Apache mod_epp testing/debugging
--------------------------------
Testing Apache mod_epp without Registry app. Testing Apache mod_epp without Registry app.
@ -222,3 +220,90 @@ This needs a static greeting file, so you will have to make /var/www writable.
Copy the files from $mod_epp/examples/cgis to /usr/lib/cgi-bin/epp Copy the files from $mod_epp/examples/cgis to /usr/lib/cgi-bin/epp
Documentation
-------------
* [EPP request-response examples](https://github.com/internetee/registry/blob/master/doc/epp-doc.md)
* [Database diagram](https://github.com/internetee/registry/blob/master/doc/models_complete.svg)
* [Controllers diagram](https://github.com/internetee/registry/blob/master/doc/controllers_complete.svg)
Deployment
----------
### System build
Officially Debian 7 is supported and tested.
You can use or find ideas how to build up production servers using
sysadmin tool [Babushka](https://github.com/benhoskings/babushka).
Unofficial build scripts locate at: https://github.com/priit/babushka-deps
Those scripts are not dedicated to Registry, but more focuse on general
Ruby on Rails application deployment in various situatians.
Quick overview. Use 'registry' for username and app name when asked.
# on server side
apt-get install curl
sh -c "`curl https://babushka.me/up`"
babushka priit:app_user
babushka priit:app
Please inspect those scripts before running anything,
they might not be complete or might have serious bugs. You are free to fork it.
Alternatively you can build up everything manually, required components:
* Consider using [RBENV](https://github.com/sstephenson/rbenv)
* Compile requried [ruby version](https://github.com/internetee/registry/blob/master/.ruby-version)
* [Phusion passenger](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html)
* [Postgresql](http://www.postgresql.org/docs/)
Registry application is not tested with multi-threaded system (such as Puma) and
it's not officially supported. Please use multi-process system instead (Passenger, Unicorn, Mongrel)
We also recommend to investigate
[Passenger Optimization Guide](https://www.phusionpassenger.com/documentation/ServerOptimizationGuide.html) for proper configuration.
### Application build and update
For application deployment we are using faster [Mina](https://github.com/mina-deploy/mina)
instead of Capistrano.
All deploy code locates at config/deploy.rb file.
First add 'testregistry' and 'registry' to your .ssh/config file:
```
# staging
Host testregistry
HostName YOUR-SERVER-IP
User registry
# production
Host registry
HostName YOUR-SERVER-IP
User registry
```
Mina help and all mina commands:
mina -h
mina -T
Setup application directories for a new server:
mina setup # staging
mina pr setup # production
Deploy new code:
mina deploy # staging
mina pr deploy # production
Rollback to previous release:
mina rollback # staging
mina pr rollback # production

View file

@ -53,7 +53,7 @@ class Admin::UsersController < AdminController
end end
def user_params def user_params
params.require(:user).permit(:username, :password, :identity_code, :email, :registrar_id, params.require(:user).permit(:username, :password, :identity_code, :email,
:admin, :registrar_typeahead, :country_id) :admin, :country_id)
end end
end end

View file

@ -29,7 +29,8 @@ module Epp::Common
end end
def epp_session def epp_session
EppSession.find_or_initialize_by(session_id: cookies['session']) cookie = env['rack.request.cookie_hash'] || {}
EppSession.find_or_initialize_by(session_id: cookie['session'])
end end
def epp_errors def epp_errors

View file

@ -10,6 +10,12 @@ class Dnskey < ActiveRecord::Base
before_save -> { generate_digest if public_key_changed? && !ds_digest_changed? } before_save -> { generate_digest if public_key_changed? && !ds_digest_changed? }
before_save lambda {
if (public_key_changed? || flags_changed? || alg_changed? || protocol_changed?) && !ds_key_tag_changed?
generate_ds_key_tag
end
}
ALGORITHMS = %w(3 5 6 7 8 252 253 254 255) ALGORITHMS = %w(3 5 6 7 8 252 253 254 255)
PROTOCOLS = %w(3) PROTOCOLS = %w(3)
FLAGS = %w(0 256 257) FLAGS = %w(0 256 257)
@ -77,6 +83,23 @@ class Dnskey < ActiveRecord::Base
self.class.bin_to_hex(Base64.decode64(public_key)) self.class.bin_to_hex(Base64.decode64(public_key))
end end
def generate_ds_key_tag
public_key.gsub!(' ', '')
wire_format = [flags, protocol, alg].pack('S!>CC')
wire_format += Base64.decode64(public_key)
c = 0
wire_format.each_byte.with_index do |b, i|
if i.even?
c += b << 8
else
c += b
end
end
self.ds_key_tag = ((c & 0xFFFF) + (c >> 16)) & 0xFFFF
end
class << self class << self
def int_to_hex(s) def int_to_hex(s)
s = s.to_s(16) s = s.to_s(16)

View file

@ -43,7 +43,7 @@ class Domain < ActiveRecord::Base
before_create :generate_auth_info before_create :generate_auth_info
before_create :set_validity_dates before_create :set_validity_dates
after_create :attach_default_contacts before_create :attach_default_contacts
after_save :manage_automatic_statuses after_save :manage_automatic_statuses
validates :name_dirty, domain_name: true, uniqueness: true validates :name_dirty, domain_name: true, uniqueness: true
@ -186,7 +186,7 @@ class Domain < ActiveRecord::Base
next unless existing.length > 1 next unless existing.length > 1
validated << dc validated << dc
errors.add(:domain_contacts, :invalid) if errors[:domain_contacts].blank? errors.add(:domain_contacts, :invalid) if errors[:domain_contacts].blank?
dc.errors.add(:contact, :taken) dc.errors.add(:contact_code_cache, :taken)
end end
end end
@ -243,11 +243,6 @@ class Domain < ActiveRecord::Base
(errors.keys - assoc_errors).empty? (errors.keys - assoc_errors).empty?
end end
def general_tab_valid?
status_errors = errors.keys.select { |x| x.match(/domain_statuses/) }
(errors.keys - status_errors).empty?
end
def statuses_tab_valid? def statuses_tab_valid?
!errors.keys.any? { |x| x.match(/domain_statuses/) } !errors.keys.any? { |x| x.match(/domain_statuses/) }
end end
@ -258,8 +253,8 @@ class Domain < ActiveRecord::Base
res = '' res = ''
parts = name.split('.') parts = name.split('.')
parts.each do |x| parts.each do |x|
res += sprintf('%02X', x.length) res += sprintf('%02X', x.length) # length of label in hex
res += x.each_byte.map { |b| sprintf('%02X', b) }.join res += x.each_byte.map { |b| sprintf('%02X', b) }.join # label
end end
res += '00' res += '00'
@ -280,8 +275,22 @@ class Domain < ActiveRecord::Base
# rubocop:enable Lint/Loop # rubocop:enable Lint/Loop
def attach_default_contacts def attach_default_contacts
tech_contacts << owner_contact if tech_contacts_count.zero? if tech_contacts_count.zero?
admin_contacts << owner_contact if admin_contacts_count.zero? && owner_contact.citizen? attach_contact(DomainContact::TECH, owner_contact)
end
return unless admin_contacts_count.zero? && owner_contact.citizen?
attach_contact(DomainContact::ADMIN, owner_contact)
end
def attach_contact(type, contact)
domain_contacts.build(
contact: contact, contact_type: DomainContact::TECH, contact_code_cache: contact.code
) if type.to_sym == :tech
domain_contacts.build(
contact: contact, contact_type: DomainContact::ADMIN, contact_code_cache: contact.code
) if type.to_sym == :admin
end end
def set_validity_dates def set_validity_dates
@ -301,7 +310,7 @@ class Domain < ActiveRecord::Base
def manage_automatic_statuses def manage_automatic_statuses
if domain_statuses.empty? && valid? if domain_statuses.empty? && valid?
domain_statuses.create(value: DomainStatus::OK) domain_statuses.create(value: DomainStatus::OK)
else elsif domain_statuses.length > 1 || !valid?
domain_statuses.find_by(value: DomainStatus::OK).try(:destroy) domain_statuses.find_by(value: DomainStatus::OK).try(:destroy)
end end
end end

View file

@ -12,7 +12,7 @@ class DomainContact < ActiveRecord::Base
def epp_code_map def epp_code_map
{ {
'2302' => [ '2302' => [
[:contact, :taken, { value: { obj: 'contact', val: contact.code } }] [:contact_code_cache, :taken, { value: { obj: 'contact', val: contact_code_cache } }]
] ]
} }
end end

View file

@ -54,7 +54,6 @@ class Epp::EppDomain < Domain
attach_contacts(self.class.parse_contacts_from_frame(parsed_frame)) attach_contacts(self.class.parse_contacts_from_frame(parsed_frame))
attach_nameservers(self.class.parse_nameservers_from_frame(parsed_frame)) attach_nameservers(self.class.parse_nameservers_from_frame(parsed_frame))
attach_statuses(self.class.parse_statuses_from_frame(parsed_frame)) attach_statuses(self.class.parse_statuses_from_frame(parsed_frame))
errors.empty? errors.empty?
end end
@ -115,15 +114,7 @@ class Epp::EppDomain < Domain
end end
end end
return unless owner_contact attach_default_contacts if new_record? && owner_contact
attach_contact(DomainContact::TECH, owner_contact) if tech_contacts_count.zero?
attach_contact(DomainContact::ADMIN, owner_contact) if admin_contacts_count.zero? && owner_contact.citizen?
end
def attach_contact(type, contact)
domain_contacts.build(contact: contact, contact_type: DomainContact::TECH) if type.to_sym == :tech
domain_contacts.build(contact: contact, contact_type: DomainContact::ADMIN) if type.to_sym == :admin
end end
def attach_nameservers(ns_list) def attach_nameservers(ns_list)
@ -134,7 +125,7 @@ class Epp::EppDomain < Domain
def attach_statuses(status_list) def attach_statuses(status_list)
status_list.each do |x| status_list.each do |x|
unless DomainStatus::STATUSES.include?(x[:value]) unless DomainStatus::CLIENT_STATUSES.include?(x[:value])
add_epp_error('2303', 'status', x[:value], [:domain_statuses, :not_found]) add_epp_error('2303', 'status', x[:value], [:domain_statuses, :not_found])
next next
end end
@ -178,6 +169,11 @@ class Epp::EppDomain < Domain
def detach_statuses(status_list) def detach_statuses(status_list)
to_delete = [] to_delete = []
status_list.each do |x| status_list.each do |x|
unless DomainStatus::CLIENT_STATUSES.include?(x[:value])
add_epp_error('2303', 'status', x[:value], [:domain_statuses, :not_found])
next
end
status = domain_statuses.find_by(value: x[:value]) status = domain_statuses.find_by(value: x[:value])
if status.blank? if status.blank?
add_epp_error('2303', 'status', x[:value], [:domain_statuses, :not_found]) add_epp_error('2303', 'status', x[:value], [:domain_statuses, :not_found])
@ -198,7 +194,6 @@ class Epp::EppDomain < Domain
dnssec_data[:key_data].each do |x| dnssec_data[:key_data].each do |x|
dnskeys.build({ dnskeys.build({
ds_key_tag: SecureRandom.hex(5),
ds_alg: 3, ds_alg: 3,
ds_digest_type: Setting.ds_algorithm ds_digest_type: Setting.ds_algorithm
}.merge(x)) }.merge(x))
@ -303,7 +298,6 @@ class Epp::EppDomain < Domain
end end
return pt if pt return pt if pt
if Setting.transfer_wait_time > 0 if Setting.transfer_wait_time > 0
dt = domain_transfers.create( dt = domain_transfers.create(
status: DomainTransfer::PENDING, status: DomainTransfer::PENDING,

View file

@ -3,7 +3,6 @@ class Registrar < ActiveRecord::Base
has_many :domains, dependent: :restrict_with_error has_many :domains, dependent: :restrict_with_error
has_many :contacts, dependent: :restrict_with_error has_many :contacts, dependent: :restrict_with_error
has_many :epp_users, dependent: :restrict_with_error has_many :epp_users, dependent: :restrict_with_error
has_many :users, dependent: :restrict_with_error
has_many :messages has_many :messages
validates :name, :reg_no, :address, :country, presence: true validates :name, :reg_no, :address, :country, presence: true

View file

@ -7,29 +7,19 @@ class User < ActiveRecord::Base
# TODO: Estonian id validation # TODO: Estonian id validation
belongs_to :role belongs_to :role
belongs_to :registrar
belongs_to :country belongs_to :country
validates :username, :password, presence: true validates :username, :password, presence: true
validates :identity_code, uniqueness: true, allow_blank: true validates :identity_code, uniqueness: true, allow_blank: true
validates :identity_code, presence: true, if: -> { country.iso == 'EE' } validates :identity_code, presence: true, if: -> { country.iso == 'EE' }
validates :email, presence: true, if: -> { country.iso != 'EE' } validates :email, presence: true, if: -> { country.iso != 'EE' }
validates :registrar, presence: true, if: -> { !admin }
validate :validate_identity_code validate :validate_identity_code
before_save -> { self.registrar = nil if admin? }
attr_accessor :registrar_typeahead
def to_s def to_s
username username
end end
def registrar_typeahead
@registrar_typeahead || registrar || nil
end
private private
def validate_identity_code def validate_identity_code

View file

@ -44,26 +44,6 @@
%dt= t('shared.billing_address') %dt= t('shared.billing_address')
%dd= @registrar.billing_address %dd= @registrar.billing_address
.row
.col-md-12
#users.panel.panel-default
.panel-heading.clearfix
= t('shared.users')
.table-responsive
%table.table.table-hover.table-bordered.table-condensed
%thead
%tr
%th{class: 'col-xs-3'}= t('shared.username')
%th{class: 'col-xs-3'}= t('shared.email')
%th{class: 'col-xs-3'}= t('shared.identity_code')
%th{class: 'col-xs-3'}= t('shared.admin')
%tbody
- @registrar.users.each do |x|
%tr
%td= link_to(x, [:admin, x])
%td= x.email
%td= x.identity_code
%td= x.admin
.row .row
.col-md-12 .col-md-12

View file

@ -25,13 +25,6 @@
.form-group .form-group
= f.label :email = f.label :email
= f.text_field(:email, class: 'form-control') = f.text_field(:email, class: 'form-control')
.form-group
.form-group.has-feedback.js-typeahead-container
= f.label :registrar_typeahead, t('shared.registrar')
= f.text_field(:registrar_typeahead, class: 'form-control js-registrar-typeahead', placeholder: t('shared.registrar'), autocomplete: 'off')
%span.glyphicon.glyphicon-ok.form-control-feedback.js-typeahead-ok.hidden
%span.glyphicon.glyphicon-remove.form-control-feedback.js-typeahead-remove
= f.hidden_field(:registrar_id, class: 'js-registrar-id')
.form-group .form-group
.checkbox .checkbox
%label{for: 'user_admin'} %label{for: 'user_admin'}
@ -41,19 +34,3 @@
.row .row
.col-md-12.text-right .col-md-12.text-right
= button_tag(t('shared.save'), class: 'btn btn-primary') = button_tag(t('shared.save'), class: 'btn btn-primary')
:javascript
Autocomplete.bindAdminRegistrarSearch();
toggleRegistrar();
$('#user_admin').click(function() {
toggleRegistrar();
});
function toggleRegistrar() {
if($('.js-admin').is(':checked')) {
$('.js-registrar-typeahead, .js-registrar-id').attr('disabled', true);
} else {
$('.js-registrar-typeahead, .js-registrar-id').attr('disabled', false);
}
}

View file

@ -19,8 +19,6 @@
= sort_link(@q, 'identity_code', t('shared.identity_code')) = sort_link(@q, 'identity_code', t('shared.identity_code'))
%th{class: 'col-xs-2'} %th{class: 'col-xs-2'}
= sort_link(@q, 'admin', t('shared.admin')) = sort_link(@q, 'admin', t('shared.admin'))
%th{class: 'col-xs-2'}
= sort_link(@q, 'registrar', t('shared.registrar'))
%tbody %tbody
- @users.each do |x| - @users.each do |x|
%tr %tr
@ -28,7 +26,6 @@
%td= x.email %td= x.email
%td= x.identity_code %td= x.identity_code
%td= x.admin %td= x.admin
%td= x.registrar
.row .row
.col-md-12 .col-md-12
= paginate @users = paginate @users

View file

@ -39,8 +39,5 @@
%dt= t('shared.email') %dt= t('shared.email')
%dd= @user.email %dd= @user.email
%dt= t('shared.registrar')
%dd= @user.registrar
%dt= t('shared.admin') %dt= t('shared.admin')
%dd= @user.admin %dd= @user.admin

View file

@ -16,13 +16,11 @@ set :deploy_to, '/home/app/registry'
set :repository, 'https://github.com/internetee/registry' set :repository, 'https://github.com/internetee/registry'
set :branch, 'master' set :branch, 'master'
task :eedirekt do # production
set :deploy_to, '/home/app/eedirekt' task :pr do
end set :domain, 'registry'
set :deploy_to, '/home/registry/registry'
# shortcut for eedirekt set :branch, 'master' # temp
task :ee do
set :deploy_to, '/home/app/eedirekt'
end end
# Manually create these paths in shared/ (eg: shared/config/database.yml) in your server. # Manually create these paths in shared/ (eg: shared/config/database.yml) in your server.
@ -88,11 +86,29 @@ task deploy: :environment do
invoke :'rails:db_migrate' invoke :'rails:db_migrate'
invoke :'rails:assets_precompile' invoke :'rails:assets_precompile'
invoke :'whenever:update' invoke :'whenever:update'
to :launch do to :launch do
invoke :restart
end
end
end
desc 'Rolls back the latest release'
task rollback: :environment do
queue! %(echo "-----> Rolling back to previous release for instance: #{domain}")
queue %(ls "#{deploy_to}/releases" -Art | sort | tail -n 2 | head -n 1)
queue! %(
ls -Art "#{deploy_to}/releases" | sort | tail -n 2 | head -n 1 |
xargs -I active ln -nfs "#{deploy_to}/releases/active" "#{deploy_to}/current"
)
invoke :'whenever:update'
to :launch do
invoke :restart
end
end
desc 'Restart Passenger application'
task restart: :environment do
queue "mkdir -p #{deploy_to}/current/tmp; touch #{deploy_to}/current/tmp/restart.txt" queue "mkdir -p #{deploy_to}/current/tmp; touch #{deploy_to}/current/tmp/restart.txt"
end
end
end end
# For help in making your deploy script, see the Mina documentation: # For help in making your deploy script, see the Mina documentation:

View file

@ -34,6 +34,9 @@ Rails.application.configure do
# Print deprecation notices to the stderr. # Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr config.active_support.deprecation = :stderr
# For rails-settings-cached conflict
config.cache_store = :file_store, 'tmp/cache_test'
# Raises error for missing translations # Raises error for missing translations
# config.action_view.raise_on_missing_translations = true # config.action_view.raise_on_missing_translations = true

View file

@ -139,6 +139,8 @@ en:
contact: contact:
blank: 'Contact was not found' blank: 'Contact was not found'
taken: 'Contact already exists on this domain!' taken: 'Contact already exists on this domain!'
contact_code_cache:
taken: 'Contact already exists on this domain!'
domain_status: domain_status:
attributes: attributes:

View file

@ -1,4 +1,5 @@
class CreateZonefileSetting < ActiveRecord::Migration class CreateZonefileSetting < ActiveRecord::Migration
# rubocop:disable Metrics/MethodLength
def change def change
create_table :zonefile_settings do |t| create_table :zonefile_settings do |t|
t.string :origin t.string :origin

View file

@ -0,0 +1,10 @@
class AddCodeCacheForDomainContact < ActiveRecord::Migration
def change
add_column :domain_contacts, :contact_code_cache, :string
DomainContact.all.each do |x|
x.contact_code_cache = x.contact.code
x.save
end
end
end

View file

@ -0,0 +1,123 @@
class GlueRecordsFixInZonefileProcedure < ActiveRecord::Migration
# rubocop:disable Metrics/MethodLength
def up
execute <<-SQL
CREATE OR REPLACE FUNCTION generate_zonefile(i_origin varchar)
RETURNS text AS $$
DECLARE
zone_header text := concat('$ORIGIN ', i_origin, '.');
serial_num varchar;
include_filter varchar := '';
exclude_filter varchar := '';
ns_records text := '';
a_records text := '';
a4_records text := '';
ds_records text := '';
BEGIN
-- define filters
include_filter = '%' || i_origin;
-- for %.%.%
IF i_origin ~ '\\.' THEN
exclude_filter := '';
-- for %.%
ELSE
exclude_filter := '%.%.' || i_origin;
END IF;
SELECT ROUND(extract(epoch from now() at time zone 'utc')) INTO serial_num;
-- zonefile header
SELECT concat(
format('%-10s', '$ORIGIN .'), chr(10),
format('%-10s', '$TTL'), zf.ttl, chr(10), chr(10),
format('%-10s', i_origin || '.'), 'IN SOA ', zf.master_nameserver, '. ', zf.email, '. (', chr(10),
format('%-17s', ''), format('%-12s', serial_num), '; serial number', chr(10),
format('%-17s', ''), format('%-12s', zf.refresh), '; refresh, seconds', chr(10),
format('%-17s', ''), format('%-12s', zf.retry), '; retry, seconds', chr(10),
format('%-17s', ''), format('%-12s', zf.expire), '; expire, seconds', chr(10),
format('%-17s', ''), format('%-12s', zf.minimum_ttl), '; minimum TTL, seconds', chr(10),
format('%-17s', ''), ')'
) FROM zonefile_settings zf WHERE i_origin = zf.origin INTO zone_header;
-- ns records
SELECT array_to_string(
array(
SELECT concat(d.name_puny, '. IN NS ', ns.hostname, '.')
FROM domains d
JOIN nameservers ns ON ns.domain_id = d.id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
ORDER BY d.name
),
chr(10)
) INTO ns_records;
-- a glue records
SELECT array_to_string(
array(
SELECT concat(cns.hostname, '. IN A ', cns.ipv4) FROM cached_nameservers cns WHERE EXISTS (
SELECT 1
FROM nameservers ns
JOIN domains d ON d.id = ns.domain_id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
AND ns.hostname = cns.hostname
AND ns.ipv4 IS NOT DISTINCT FROM cns.ipv4
AND ns.ipv6 IS NOT DISTINCT FROM cns.ipv6
AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> ''
AND ns.hostname LIKE '%.' || d.name
)
),
chr(10)
) INTO a_records;
-- aaaa glue records
SELECT array_to_string(
array(
SELECT concat(cns.hostname, '. IN AAAA ', cns.ipv6) FROM cached_nameservers cns WHERE EXISTS (
SELECT 1
FROM nameservers ns
JOIN domains d ON d.id = ns.domain_id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
AND ns.hostname = cns.hostname
AND ns.ipv4 IS NOT DISTINCT FROM cns.ipv4
AND ns.ipv6 IS NOT DISTINCT FROM cns.ipv6
AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> ''
AND ns.hostname LIKE '%.' || d.name
)
),
chr(10)
) INTO a4_records;
-- ds records
SELECT array_to_string(
array(
SELECT concat(
d.name_puny, '. IN DS ', dk.ds_key_tag, ' ',
dk.ds_alg, ' ', dk.ds_digest_type, ' ( ', dk.ds_digest, ' )'
)
FROM domains d
JOIN dnskeys dk ON dk.domain_id = d.id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
),
chr(10)
) INTO ds_records;
RETURN concat(
zone_header, chr(10), chr(10),
'; Zone NS Records', chr(10), ns_records, chr(10), chr(10),
'; Zone A Records', chr(10), a_records, chr(10), chr(10),
'; Zone AAAA Records', chr(10), a4_records, chr(10), chr(10),
'; Zone DS Records', chr(10), ds_records, chr(10)
);
END;
$$
LANGUAGE plpgsql;
SQL
end
def down
execute <<-SQL
DROP FUNCTION generate_zonefile(i_origin varchar);
SQL
end
end

View file

@ -0,0 +1,168 @@
class RemoveNsCaching < ActiveRecord::Migration
# rubocop:disable Metrics/MethodLength
def up
execute <<-SQL
CREATE OR REPLACE FUNCTION generate_zonefile(i_origin varchar)
RETURNS text AS $$
DECLARE
zone_header text := concat('$ORIGIN ', i_origin, '.');
serial_num varchar;
include_filter varchar := '';
exclude_filter varchar := '';
tmp_var text;
ret text;
BEGIN
-- define filters
include_filter = '%' || i_origin;
-- for %.%.%
IF i_origin ~ '\\.' THEN
exclude_filter := '';
-- for %.%
ELSE
exclude_filter := '%.%.' || i_origin;
END IF;
SELECT ROUND(extract(epoch from now() at time zone 'utc')) INTO serial_num;
-- zonefile header
SELECT concat(
format('%-10s', '$ORIGIN .'), chr(10),
format('%-10s', '$TTL'), zf.ttl, chr(10), chr(10),
format('%-10s', i_origin || '.'), 'IN SOA ', zf.master_nameserver, '. ', zf.email, '. (', chr(10),
format('%-17s', ''), format('%-12s', serial_num), '; serial number', chr(10),
format('%-17s', ''), format('%-12s', zf.refresh), '; refresh, seconds', chr(10),
format('%-17s', ''), format('%-12s', zf.retry), '; retry, seconds', chr(10),
format('%-17s', ''), format('%-12s', zf.expire), '; expire, seconds', chr(10),
format('%-17s', ''), format('%-12s', zf.minimum_ttl), '; minimum TTL, seconds', chr(10),
format('%-17s', ''), ')'
) FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var;
ret = concat(tmp_var, chr(10), chr(10));
-- ns records
SELECT array_to_string(
array(
SELECT concat(d.name_puny, '. IN NS ', ns.hostname, '.')
FROM domains d
JOIN nameservers ns ON ns.domain_id = d.id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
ORDER BY d.name
),
chr(10)
) INTO tmp_var;
ret := concat(ret, '; Zone NS Records', chr(10), tmp_var, chr(10), chr(10));
-- a glue records for origin nameservers
SELECT array_to_string(
array(
SELECT concat(ns.hostname, '. IN A ', ns.ipv4)
FROM nameservers ns
JOIN domains d ON d.id = ns.domain_id
WHERE d.name = i_origin
AND ns.hostname LIKE '%.' || d.name
AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> ''
), chr(10)
) INTO tmp_var;
ret := concat(ret, '; Zone A Records', chr(10), tmp_var);
-- a glue records for other nameservers
SELECT array_to_string(
array(
SELECT concat(ns.hostname, '. IN A ', ns.ipv4)
FROM nameservers ns
JOIN domains d ON d.id = ns.domain_id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
AND ns.hostname LIKE '%.' || d.name
AND d.name <> i_origin
AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> ''
AND NOT EXISTS ( -- filter out glue records that already appeared in origin glue recrods
SELECT 1 FROM nameservers nsi
JOIN domains di ON nsi.domain_id = di.id
WHERE di.name = i_origin
AND nsi.hostname = ns.hostname
)
), chr(10)
) INTO tmp_var;
-- TODO This is a possible subtitition to the previous query, stress testing is needed to see which is faster
-- SELECT ns.*
-- FROM nameservers ns
-- JOIN domains d ON d.id = ns.domain_id
-- WHERE d.name LIKE '%ee' AND d.name NOT LIKE '%pri.ee'
-- AND ns.hostname LIKE '%.' || d.name
-- AND d.name <> 'ee'
-- AND ns.ipv4 IS NOT NULL AND ns.ipv4 <> ''
-- AND ns.hostname NOT IN (
-- SELECT ns.hostname FROM domains d JOIN nameservers ns ON d.id = ns.domain_id WHERE d.name = 'ee'
-- )
ret := concat(ret, chr(10), tmp_var, chr(10), chr(10));
-- aaaa glue records for origin nameservers
SELECT array_to_string(
array(
SELECT concat(ns.hostname, '. IN AAAA ', ns.ipv6)
FROM nameservers ns
JOIN domains d ON d.id = ns.domain_id
WHERE d.name = i_origin
AND ns.hostname LIKE '%.' || d.name
AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> ''
), chr(10)
) INTO tmp_var;
ret := concat(ret, '; Zone AAAA Records', chr(10), tmp_var);
-- aaaa glue records for other nameservers
SELECT array_to_string(
array(
SELECT concat(ns.hostname, '. IN AAAA ', ns.ipv6)
FROM nameservers ns
JOIN domains d ON d.id = ns.domain_id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
AND ns.hostname LIKE '%.' || d.name
AND d.name <> i_origin
AND ns.ipv6 IS NOT NULL AND ns.ipv6 <> ''
AND NOT EXISTS ( -- filter out glue records that already appeared in origin glue recrods
SELECT 1 FROM nameservers nsi
JOIN domains di ON nsi.domain_id = di.id
WHERE di.name = i_origin
AND nsi.hostname = ns.hostname
)
), chr(10)
) INTO tmp_var;
ret := concat(ret, chr(10), tmp_var, chr(10), chr(10));
-- ds records
SELECT array_to_string(
array(
SELECT concat(
d.name_puny, '. IN DS ', dk.ds_key_tag, ' ',
dk.ds_alg, ' ', dk.ds_digest_type, ' ( ', dk.ds_digest, ' )'
)
FROM domains d
JOIN dnskeys dk ON dk.domain_id = d.id
WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter
),
chr(10)
) INTO tmp_var;
ret := concat(ret, '; Zone DS Records', chr(10), tmp_var, chr(10));
RETURN ret;
END;
$$
LANGUAGE plpgsql;
SQL
end
def down
execute <<-SQL
DROP FUNCTION generate_zonefile(i_origin varchar);
SQL
end
end

View file

@ -0,0 +1,5 @@
class RemoveRegistrarFromUser < ActiveRecord::Migration
def change
remove_column :users, :registrar_id
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20141216075056) do ActiveRecord::Schema.define(version: 20141216133831) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -147,6 +147,7 @@ ActiveRecord::Schema.define(version: 20141216075056) do
t.string "contact_type" t.string "contact_type"
t.datetime "created_at" t.datetime "created_at"
t.datetime "updated_at" t.datetime "updated_at"
t.string "contact_code_cache"
end end
create_table "domain_status_versions", force: true do |t| create_table "domain_status_versions", force: true do |t|
@ -333,7 +334,6 @@ ActiveRecord::Schema.define(version: 20141216075056) do
t.inet "last_sign_in_ip" t.inet "last_sign_in_ip"
t.boolean "admin", default: false t.boolean "admin", default: false
t.string "identity_code" t.string "identity_code"
t.integer "registrar_id"
t.integer "country_id" t.integer "country_id"
end end

101
doc/controllers_brief.svg Normal file
View file

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: controllers_diagram Pages: 1 -->
<svg width="643pt" height="500pt"
viewBox="0.00 0.00 642.58 500.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(220.343 256)">
<title>controllers_diagram</title>
<polygon fill="white" stroke="none" points="-220.343,244 -220.343,-256 422.24,-256 422.24,244 -220.343,244"/>
<!-- _diagram_info -->
<g id="node1" class="node"><title>_diagram_info</title>
<text text-anchor="start" x="104" y="-159.6" font-family="Times,serif" font-size="13.00">Controllers diagram</text>
<text text-anchor="start" x="104" y="-145.6" font-family="Times,serif" font-size="13.00">Date: Dec 15 2014 &#45; 14:23</text>
<text text-anchor="start" x="104" y="-131.6" font-family="Times,serif" font-size="13.00">Migration version: 20141202114457</text>
<text text-anchor="start" x="104" y="-117.6" font-family="Times,serif" font-size="13.00">Generated by RailRoady 1.2.0</text>
<text text-anchor="start" x="104" y="-103.6" font-family="Times,serif" font-size="13.00">http://railroady.prestonlee.com</text>
</g>
<!-- ApplicationController -->
<g id="node2" class="node"><title>ApplicationController</title>
<ellipse fill="none" stroke="black" cx="-116" cy="186" rx="88.2844" ry="18"/>
<text text-anchor="middle" x="-116" y="189.7" font-family="Times,serif" font-size="14.00">ApplicationController</text>
</g>
<!-- SessionsController -->
<g id="node3" class="node"><title>SessionsController</title>
<ellipse fill="none" stroke="black" cx="-139" cy="-234" rx="77.1866" ry="18"/>
<text text-anchor="middle" x="-139" y="-230.3" font-family="Times,serif" font-size="14.00">SessionsController</text>
</g>
<!-- Epp::CommandsController -->
<g id="node4" class="node"><title>Epp::CommandsController</title>
<ellipse fill="none" stroke="black" cx="-37" cy="-162" rx="106.681" ry="18"/>
<text text-anchor="middle" x="-37" y="-158.3" font-family="Times,serif" font-size="14.00">Epp::CommandsController</text>
</g>
<!-- Epp::SessionsController -->
<g id="node5" class="node"><title>Epp::SessionsController</title>
<ellipse fill="none" stroke="black" cx="-120" cy="66" rx="96.3833" ry="18"/>
<text text-anchor="middle" x="-120" y="69.7" font-family="Times,serif" font-size="14.00">Epp::SessionsController</text>
</g>
<!-- Epp::ErrorsController -->
<g id="node6" class="node"><title>Epp::ErrorsController</title>
<ellipse fill="none" stroke="black" cx="328" cy="222" rx="87.9851" ry="18"/>
<text text-anchor="middle" x="328" y="225.7" font-family="Times,serif" font-size="14.00">Epp::ErrorsController</text>
</g>
<!-- AdminController -->
<g id="node7" class="node"><title>AdminController</title>
<ellipse fill="none" stroke="black" cx="323" cy="162" rx="71.4873" ry="18"/>
<text text-anchor="middle" x="323" y="165.7" font-family="Times,serif" font-size="14.00">AdminController</text>
</g>
<!-- Admin::UsersController -->
<g id="node8" class="node"><title>Admin::UsersController</title>
<ellipse fill="none" stroke="black" cx="-119" cy="126" rx="96.6831" ry="18"/>
<text text-anchor="middle" x="-119" y="129.7" font-family="Times,serif" font-size="14.00">Admin::UsersController</text>
</g>
<!-- Admin::EppUsersController -->
<g id="node9" class="node"><title>Admin::EppUsersController</title>
<ellipse fill="none" stroke="black" cx="266" cy="6" rx="110.48" ry="18"/>
<text text-anchor="middle" x="266" y="9.7" font-family="Times,serif" font-size="14.00">Admin::EppUsersController</text>
</g>
<!-- Admin::RegistrarsController -->
<g id="node10" class="node"><title>Admin::RegistrarsController</title>
<ellipse fill="none" stroke="black" cx="112" cy="126" rx="112.38" ry="18"/>
<text text-anchor="middle" x="112" y="129.7" font-family="Times,serif" font-size="14.00">Admin::RegistrarsController</text>
</g>
<!-- Admin::DomainVersionsController -->
<g id="node11" class="node"><title>Admin::DomainVersionsController</title>
<ellipse fill="none" stroke="black" cx="-8" cy="6" rx="136.476" ry="18"/>
<text text-anchor="middle" x="-8" y="9.7" font-family="Times,serif" font-size="14.00">Admin::DomainVersionsController</text>
</g>
<!-- Admin::DomainsController -->
<g id="node12" class="node"><title>Admin::DomainsController</title>
<ellipse fill="none" stroke="black" cx="109" cy="186" rx="108.581" ry="18"/>
<text text-anchor="middle" x="109" y="189.7" font-family="Times,serif" font-size="14.00">Admin::DomainsController</text>
</g>
<!-- Admin::DelayedJobsController -->
<g id="node13" class="node"><title>Admin::DelayedJobsController</title>
<ellipse fill="none" stroke="black" cx="122" cy="66" rx="121.578" ry="18"/>
<text text-anchor="middle" x="122" y="69.7" font-family="Times,serif" font-size="14.00">Admin::DelayedJobsController</text>
</g>
<!-- Admin::ZonefileSettingsController -->
<g id="node14" class="node"><title>Admin::ZonefileSettingsController</title>
<ellipse fill="none" stroke="black" cx="171" cy="-54" rx="134.576" ry="18"/>
<text text-anchor="middle" x="171" y="-50.3" font-family="Times,serif" font-size="14.00">Admin::ZonefileSettingsController</text>
</g>
<!-- Admin::ContactsController -->
<g id="node15" class="node"><title>Admin::ContactsController</title>
<ellipse fill="none" stroke="black" cx="311" cy="-222" rx="107.482" ry="18"/>
<text text-anchor="middle" x="311" y="-218.3" font-family="Times,serif" font-size="14.00">Admin::ContactsController</text>
</g>
<!-- Admin::SettingsController -->
<g id="node16" class="node"><title>Admin::SettingsController</title>
<ellipse fill="none" stroke="black" cx="-99" cy="-102" rx="104.782" ry="18"/>
<text text-anchor="middle" x="-99" y="-98.3" font-family="Times,serif" font-size="14.00">Admin::SettingsController</text>
</g>
<!-- Admin::ZonefilesController -->
<g id="node17" class="node"><title>Admin::ZonefilesController</title>
<ellipse fill="none" stroke="black" cx="74" cy="-222" rx="109.681" ry="18"/>
<text text-anchor="middle" x="74" y="-218.3" font-family="Times,serif" font-size="14.00">Admin::ZonefilesController</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View file

@ -0,0 +1,238 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: controllers_diagram Pages: 1 -->
<svg width="897pt" height="906pt"
viewBox="0.00 0.00 896.50 906.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(382 524)">
<title>controllers_diagram</title>
<polygon fill="white" stroke="none" points="-382,382 -382,-524 514.5,-524 514.5,382 -382,382"/>
<!-- _diagram_info -->
<g id="node1" class="node"><title>_diagram_info</title>
<text text-anchor="start" x="-298" y="242.4" font-family="Times,serif" font-size="13.00">Controllers diagram</text>
<text text-anchor="start" x="-298" y="256.4" font-family="Times,serif" font-size="13.00">Date: Dec 15 2014 &#45; 14:23</text>
<text text-anchor="start" x="-298" y="270.4" font-family="Times,serif" font-size="13.00">Migration version: 20141202114457</text>
<text text-anchor="start" x="-298" y="284.4" font-family="Times,serif" font-size="13.00">Generated by RailRoady 1.2.0</text>
<text text-anchor="start" x="-298" y="298.4" font-family="Times,serif" font-size="13.00">http://railroady.prestonlee.com</text>
</g>
<!-- ApplicationController -->
<g id="node2" class="node"><title>ApplicationController</title>
<path fill="none" stroke="black" d="M354,-324.5C354,-324.5 470,-324.5 470,-324.5 476,-324.5 482,-330.5 482,-336.5 482,-336.5 482,-405.5 482,-405.5 482,-411.5 476,-417.5 470,-417.5 470,-417.5 354,-417.5 354,-417.5 348,-417.5 342,-411.5 342,-405.5 342,-405.5 342,-336.5 342,-336.5 342,-330.5 348,-324.5 354,-324.5"/>
<text text-anchor="middle" x="412" y="-402.3" font-family="Times,serif" font-size="14.00">ApplicationController</text>
<polyline fill="none" stroke="black" points="342,-394.5 482,-394.5 "/>
<text text-anchor="start" x="350" y="-379.3" font-family="Times,serif" font-size="14.00">after_sign_in_path_for</text>
<polyline fill="none" stroke="black" points="342,-371.5 482,-371.5 "/>
<polyline fill="none" stroke="black" points="342,-347.5 482,-347.5 "/>
<text text-anchor="start" x="350" y="-332.3" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
<!-- SessionsController -->
<g id="node3" class="node"><title>SessionsController</title>
<path fill="none" stroke="black" d="M192.5,-396.5C192.5,-396.5 287.5,-396.5 287.5,-396.5 293.5,-396.5 299.5,-402.5 299.5,-408.5 299.5,-408.5 299.5,-507.5 299.5,-507.5 299.5,-513.5 293.5,-519.5 287.5,-519.5 287.5,-519.5 192.5,-519.5 192.5,-519.5 186.5,-519.5 180.5,-513.5 180.5,-507.5 180.5,-507.5 180.5,-408.5 180.5,-408.5 180.5,-402.5 186.5,-396.5 192.5,-396.5"/>
<text text-anchor="middle" x="240" y="-504.3" font-family="Times,serif" font-size="14.00">SessionsController</text>
<polyline fill="none" stroke="black" points="180.5,-496.5 299.5,-496.5 "/>
<text text-anchor="start" x="188.5" y="-481.3" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="188.5" y="-466.3" font-family="Times,serif" font-size="14.00">login</text>
<text text-anchor="start" x="188.5" y="-451.3" font-family="Times,serif" font-size="14.00">switch_registrar</text>
<polyline fill="none" stroke="black" points="180.5,-443.5 299.5,-443.5 "/>
<polyline fill="none" stroke="black" points="180.5,-419.5 299.5,-419.5 "/>
<text text-anchor="start" x="188.5" y="-404.3" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
<!-- Epp::CommandsController -->
<g id="node4" class="node"><title>Epp::CommandsController</title>
<path fill="none" stroke="black" d="M156,-144C156,-144 296,-144 296,-144 302,-144 308,-150 308,-156 308,-156 308,-346 308,-346 308,-352 302,-358 296,-358 296,-358 156,-358 156,-358 150,-358 144,-352 144,-346 144,-346 144,-156 144,-156 144,-150 150,-144 156,-144"/>
<text text-anchor="middle" x="226" y="-342.8" font-family="Times,serif" font-size="14.00">Epp::CommandsController</text>
<polyline fill="none" stroke="black" points="144,-335 308,-335 "/>
<polyline fill="none" stroke="black" points="144,-311 308,-311 "/>
<polyline fill="none" stroke="black" points="144,-287 308,-287 "/>
<text text-anchor="start" x="152" y="-271.8" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="152" y="-256.8" font-family="Times,serif" font-size="14.00">check</text>
<text text-anchor="start" x="152" y="-241.8" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="152" y="-226.8" font-family="Times,serif" font-size="14.00">delete</text>
<text text-anchor="start" x="152" y="-211.8" font-family="Times,serif" font-size="14.00">info</text>
<text text-anchor="start" x="152" y="-196.8" font-family="Times,serif" font-size="14.00">renew</text>
<text text-anchor="start" x="152" y="-181.8" font-family="Times,serif" font-size="14.00">transfer</text>
<text text-anchor="start" x="152" y="-166.8" font-family="Times,serif" font-size="14.00">update</text>
<text text-anchor="start" x="152" y="-151.8" font-family="Times,serif" font-size="14.00">user_for_paper_trail</text>
</g>
<!-- Epp::SessionsController -->
<g id="node5" class="node"><title>Epp::SessionsController</title>
<path fill="none" stroke="black" d="M-258,197C-258,197 -134,197 -134,197 -128,197 -122,191 -122,185 -122,185 -122,55 -122,55 -122,49 -128,43 -134,43 -134,43 -258,43 -258,43 -264,43 -270,49 -270,55 -270,55 -270,185 -270,185 -270,191 -264,197 -258,197"/>
<text text-anchor="middle" x="-196" y="58.2" font-family="Times,serif" font-size="14.00">Epp::SessionsController</text>
<polyline fill="none" stroke="black" points="-270,66 -122,66 "/>
<polyline fill="none" stroke="black" points="-270,90 -122,90 "/>
<polyline fill="none" stroke="black" points="-270,114 -122,114 "/>
<text text-anchor="start" x="-262" y="129.2" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="-262" y="144.2" font-family="Times,serif" font-size="14.00">hello</text>
<text text-anchor="start" x="-262" y="159.2" font-family="Times,serif" font-size="14.00">login</text>
<text text-anchor="start" x="-262" y="174.2" font-family="Times,serif" font-size="14.00">login_params</text>
<text text-anchor="start" x="-262" y="189.2" font-family="Times,serif" font-size="14.00">logout</text>
</g>
<!-- Epp::ErrorsController -->
<g id="node6" class="node"><title>Epp::ErrorsController</title>
<path fill="none" stroke="black" d="M246.5,377.5C246.5,377.5 357.5,377.5 357.5,377.5 363.5,377.5 369.5,371.5 369.5,365.5 369.5,365.5 369.5,296.5 369.5,296.5 369.5,290.5 363.5,284.5 357.5,284.5 357.5,284.5 246.5,284.5 246.5,284.5 240.5,284.5 234.5,290.5 234.5,296.5 234.5,296.5 234.5,365.5 234.5,365.5 234.5,371.5 240.5,377.5 246.5,377.5"/>
<text text-anchor="middle" x="302" y="299.7" font-family="Times,serif" font-size="14.00">Epp::ErrorsController</text>
<polyline fill="none" stroke="black" points="234.5,307.5 369.5,307.5 "/>
<text text-anchor="start" x="242.5" y="322.7" font-family="Times,serif" font-size="14.00">error</text>
<polyline fill="none" stroke="black" points="234.5,330.5 369.5,330.5 "/>
<polyline fill="none" stroke="black" points="234.5,354.5 369.5,354.5 "/>
<text text-anchor="start" x="242.5" y="369.7" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
<!-- AdminController -->
<g id="node7" class="node"><title>AdminController</title>
<path fill="none" stroke="black" d="M-366,-378.5C-366,-378.5 -280,-378.5 -280,-378.5 -274,-378.5 -268,-384.5 -268,-390.5 -268,-390.5 -268,-459.5 -268,-459.5 -268,-465.5 -274,-471.5 -280,-471.5 -280,-471.5 -366,-471.5 -366,-471.5 -372,-471.5 -378,-465.5 -378,-459.5 -378,-459.5 -378,-390.5 -378,-390.5 -378,-384.5 -372,-378.5 -366,-378.5"/>
<text text-anchor="middle" x="-323" y="-456.3" font-family="Times,serif" font-size="14.00">AdminController</text>
<polyline fill="none" stroke="black" points="-378,-448.5 -268,-448.5 "/>
<text text-anchor="start" x="-370" y="-433.3" font-family="Times,serif" font-size="14.00">verify_admin</text>
<polyline fill="none" stroke="black" points="-378,-425.5 -268,-425.5 "/>
<polyline fill="none" stroke="black" points="-378,-401.5 -268,-401.5 "/>
<text text-anchor="start" x="-370" y="-386.3" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
<!-- Admin::UsersController -->
<g id="node8" class="node"><title>Admin::UsersController</title>
<path fill="none" stroke="black" d="M-24.5,-144.5C-24.5,-144.5 100.5,-144.5 100.5,-144.5 106.5,-144.5 112.5,-150.5 112.5,-156.5 112.5,-156.5 112.5,-345.5 112.5,-345.5 112.5,-351.5 106.5,-357.5 100.5,-357.5 100.5,-357.5 -24.5,-357.5 -24.5,-357.5 -30.5,-357.5 -36.5,-351.5 -36.5,-345.5 -36.5,-345.5 -36.5,-156.5 -36.5,-156.5 -36.5,-150.5 -30.5,-144.5 -24.5,-144.5"/>
<text text-anchor="middle" x="38" y="-342.3" font-family="Times,serif" font-size="14.00">Admin::UsersController</text>
<polyline fill="none" stroke="black" points="-36.5,-334.5 112.5,-334.5 "/>
<text text-anchor="start" x="-28.5" y="-319.3" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="-28.5" y="-304.3" font-family="Times,serif" font-size="14.00">destroy</text>
<text text-anchor="start" x="-28.5" y="-289.3" font-family="Times,serif" font-size="14.00">edit</text>
<text text-anchor="start" x="-28.5" y="-274.3" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="-28.5" y="-259.3" font-family="Times,serif" font-size="14.00">new</text>
<text text-anchor="start" x="-28.5" y="-244.3" font-family="Times,serif" font-size="14.00">show</text>
<text text-anchor="start" x="-28.5" y="-229.3" font-family="Times,serif" font-size="14.00">update</text>
<polyline fill="none" stroke="black" points="-36.5,-221.5 112.5,-221.5 "/>
<polyline fill="none" stroke="black" points="-36.5,-197.5 112.5,-197.5 "/>
<text text-anchor="start" x="-28.5" y="-182.3" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="-28.5" y="-167.3" font-family="Times,serif" font-size="14.00">set_user</text>
<text text-anchor="start" x="-28.5" y="-152.3" font-family="Times,serif" font-size="14.00">user_params</text>
</g>
<!-- Admin::EppUsersController -->
<g id="node9" class="node"><title>Admin::EppUsersController</title>
<path fill="none" stroke="black" d="M-78,107.5C-78,107.5 68,107.5 68,107.5 74,107.5 80,101.5 80,95.5 80,95.5 80,-93.5 80,-93.5 80,-99.5 74,-105.5 68,-105.5 68,-105.5 -78,-105.5 -78,-105.5 -84,-105.5 -90,-99.5 -90,-93.5 -90,-93.5 -90,95.5 -90,95.5 -90,101.5 -84,107.5 -78,107.5"/>
<text text-anchor="middle" x="-5" y="-90.3" font-family="Times,serif" font-size="14.00">Admin::EppUsersController</text>
<polyline fill="none" stroke="black" points="-90,-82.5 80,-82.5 "/>
<text text-anchor="start" x="-82" y="-67.3" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="-82" y="-52.3" font-family="Times,serif" font-size="14.00">destroy</text>
<text text-anchor="start" x="-82" y="-37.3" font-family="Times,serif" font-size="14.00">edit</text>
<text text-anchor="start" x="-82" y="-22.3" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="-82" y="-7.3" font-family="Times,serif" font-size="14.00">new</text>
<text text-anchor="start" x="-82" y="7.7" font-family="Times,serif" font-size="14.00">show</text>
<text text-anchor="start" x="-82" y="22.7" font-family="Times,serif" font-size="14.00">update</text>
<polyline fill="none" stroke="black" points="-90,30.5 80,30.5 "/>
<polyline fill="none" stroke="black" points="-90,54.5 80,54.5 "/>
<text text-anchor="start" x="-82" y="69.7" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="-82" y="84.7" font-family="Times,serif" font-size="14.00">epp_user_params</text>
<text text-anchor="start" x="-82" y="99.7" font-family="Times,serif" font-size="14.00">set_epp_user</text>
</g>
<!-- Admin::RegistrarsController -->
<g id="node10" class="node"><title>Admin::RegistrarsController</title>
<path fill="none" stroke="black" d="M120.5,107.5C120.5,107.5 269.5,107.5 269.5,107.5 275.5,107.5 281.5,101.5 281.5,95.5 281.5,95.5 281.5,-93.5 281.5,-93.5 281.5,-99.5 275.5,-105.5 269.5,-105.5 269.5,-105.5 120.5,-105.5 120.5,-105.5 114.5,-105.5 108.5,-99.5 108.5,-93.5 108.5,-93.5 108.5,95.5 108.5,95.5 108.5,101.5 114.5,107.5 120.5,107.5"/>
<text text-anchor="middle" x="195" y="-90.3" font-family="Times,serif" font-size="14.00">Admin::RegistrarsController</text>
<polyline fill="none" stroke="black" points="108.5,-82.5 281.5,-82.5 "/>
<text text-anchor="start" x="116.5" y="-67.3" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="116.5" y="-52.3" font-family="Times,serif" font-size="14.00">destroy</text>
<text text-anchor="start" x="116.5" y="-37.3" font-family="Times,serif" font-size="14.00">edit</text>
<text text-anchor="start" x="116.5" y="-22.3" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="116.5" y="-7.3" font-family="Times,serif" font-size="14.00">new</text>
<text text-anchor="start" x="116.5" y="7.7" font-family="Times,serif" font-size="14.00">search</text>
<text text-anchor="start" x="116.5" y="22.7" font-family="Times,serif" font-size="14.00">update</text>
<polyline fill="none" stroke="black" points="108.5,30.5 281.5,30.5 "/>
<polyline fill="none" stroke="black" points="108.5,54.5 281.5,54.5 "/>
<text text-anchor="start" x="116.5" y="69.7" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="116.5" y="84.7" font-family="Times,serif" font-size="14.00">registrar_params</text>
<text text-anchor="start" x="116.5" y="99.7" font-family="Times,serif" font-size="14.00">set_registrar</text>
</g>
<!-- Admin::DomainVersionsController -->
<g id="node11" class="node"><title>Admin::DomainVersionsController</title>
<path fill="none" stroke="black" d="M246,251C246,251 432,251 432,251 438,251 444,245 444,239 444,239 444,155 444,155 444,149 438,143 432,143 432,143 246,143 246,143 240,143 234,149 234,155 234,155 234,239 234,239 234,245 240,251 246,251"/>
<text text-anchor="middle" x="339" y="158.2" font-family="Times,serif" font-size="14.00">Admin::DomainVersionsController</text>
<polyline fill="none" stroke="black" points="234,166 444,166 "/>
<text text-anchor="start" x="242" y="181.2" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="242" y="196.2" font-family="Times,serif" font-size="14.00">show</text>
<polyline fill="none" stroke="black" points="234,204 444,204 "/>
<polyline fill="none" stroke="black" points="234,228 444,228 "/>
<text text-anchor="start" x="242" y="243.2" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
<!-- Admin::DomainsController -->
<g id="node12" class="node"><title>Admin::DomainsController</title>
<path fill="none" stroke="black" d="M-222.5,-235C-222.5,-235 -79.5,-235 -79.5,-235 -73.5,-235 -67.5,-241 -67.5,-247 -67.5,-247 -67.5,-421 -67.5,-421 -67.5,-427 -73.5,-433 -79.5,-433 -79.5,-433 -222.5,-433 -222.5,-433 -228.5,-433 -234.5,-427 -234.5,-421 -234.5,-421 -234.5,-247 -234.5,-247 -234.5,-241 -228.5,-235 -222.5,-235"/>
<text text-anchor="middle" x="-151" y="-417.8" font-family="Times,serif" font-size="14.00">Admin::DomainsController</text>
<polyline fill="none" stroke="black" points="-234.5,-410 -67.5,-410 "/>
<text text-anchor="start" x="-226.5" y="-394.8" font-family="Times,serif" font-size="14.00">edit</text>
<text text-anchor="start" x="-226.5" y="-379.8" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="-226.5" y="-364.8" font-family="Times,serif" font-size="14.00">show</text>
<text text-anchor="start" x="-226.5" y="-349.8" font-family="Times,serif" font-size="14.00">update</text>
<polyline fill="none" stroke="black" points="-234.5,-342 -67.5,-342 "/>
<polyline fill="none" stroke="black" points="-234.5,-318 -67.5,-318 "/>
<text text-anchor="start" x="-226.5" y="-302.8" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="-226.5" y="-287.8" font-family="Times,serif" font-size="14.00">add_prefix_to_statuses</text>
<text text-anchor="start" x="-226.5" y="-272.8" font-family="Times,serif" font-size="14.00">build_associations</text>
<text text-anchor="start" x="-226.5" y="-257.8" font-family="Times,serif" font-size="14.00">domain_params</text>
<text text-anchor="start" x="-226.5" y="-242.8" font-family="Times,serif" font-size="14.00">set_domain</text>
</g>
<!-- Admin::DelayedJobsController -->
<g id="node13" class="node"><title>Admin::DelayedJobsController</title>
<path fill="none" stroke="black" d="M335.5,107.5C335.5,107.5 498.5,107.5 498.5,107.5 504.5,107.5 510.5,101.5 510.5,95.5 510.5,95.5 510.5,26.5 510.5,26.5 510.5,20.5 504.5,14.5 498.5,14.5 498.5,14.5 335.5,14.5 335.5,14.5 329.5,14.5 323.5,20.5 323.5,26.5 323.5,26.5 323.5,95.5 323.5,95.5 323.5,101.5 329.5,107.5 335.5,107.5"/>
<text text-anchor="middle" x="417" y="29.7" font-family="Times,serif" font-size="14.00">Admin::DelayedJobsController</text>
<polyline fill="none" stroke="black" points="323.5,37.5 510.5,37.5 "/>
<text text-anchor="start" x="331.5" y="52.7" font-family="Times,serif" font-size="14.00">index</text>
<polyline fill="none" stroke="black" points="323.5,60.5 510.5,60.5 "/>
<polyline fill="none" stroke="black" points="323.5,84.5 510.5,84.5 "/>
<text text-anchor="start" x="331.5" y="99.7" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
<!-- Admin::ZonefileSettingsController -->
<g id="node14" class="node"><title>Admin::ZonefileSettingsController</title>
<path fill="none" stroke="black" d="M12.5,305.5C12.5,305.5 195.5,305.5 195.5,305.5 201.5,305.5 207.5,299.5 207.5,293.5 207.5,293.5 207.5,164.5 207.5,164.5 207.5,158.5 201.5,152.5 195.5,152.5 195.5,152.5 12.5,152.5 12.5,152.5 6.5,152.5 0.5,158.5 0.5,164.5 0.5,164.5 0.5,293.5 0.5,293.5 0.5,299.5 6.5,305.5 12.5,305.5"/>
<text text-anchor="middle" x="104" y="167.7" font-family="Times,serif" font-size="14.00">Admin::ZonefileSettingsController</text>
<polyline fill="none" stroke="black" points="0.5,175.5 207.5,175.5 "/>
<text text-anchor="start" x="8.5" y="190.7" font-family="Times,serif" font-size="14.00">edit</text>
<text text-anchor="start" x="8.5" y="205.7" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="8.5" y="220.7" font-family="Times,serif" font-size="14.00">update</text>
<polyline fill="none" stroke="black" points="0.5,228.5 207.5,228.5 "/>
<polyline fill="none" stroke="black" points="0.5,252.5 207.5,252.5 "/>
<text text-anchor="start" x="8.5" y="267.7" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="8.5" y="282.7" font-family="Times,serif" font-size="14.00">set_zonefile_setting</text>
<text text-anchor="start" x="8.5" y="297.7" font-family="Times,serif" font-size="14.00">zonefile_setting_params</text>
</g>
<!-- Admin::ContactsController -->
<g id="node15" class="node"><title>Admin::ContactsController</title>
<path fill="none" stroke="black" d="M354.5,-18.5C354.5,-18.5 495.5,-18.5 495.5,-18.5 501.5,-18.5 507.5,-24.5 507.5,-30.5 507.5,-30.5 507.5,-129.5 507.5,-129.5 507.5,-135.5 501.5,-141.5 495.5,-141.5 495.5,-141.5 354.5,-141.5 354.5,-141.5 348.5,-141.5 342.5,-135.5 342.5,-129.5 342.5,-129.5 342.5,-30.5 342.5,-30.5 342.5,-24.5 348.5,-18.5 354.5,-18.5"/>
<text text-anchor="middle" x="425" y="-126.3" font-family="Times,serif" font-size="14.00">Admin::ContactsController</text>
<polyline fill="none" stroke="black" points="342.5,-118.5 507.5,-118.5 "/>
<text text-anchor="start" x="350.5" y="-103.3" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="350.5" y="-88.3" font-family="Times,serif" font-size="14.00">search</text>
<polyline fill="none" stroke="black" points="342.5,-80.5 507.5,-80.5 "/>
<polyline fill="none" stroke="black" points="342.5,-56.5 507.5,-56.5 "/>
<text text-anchor="start" x="350.5" y="-41.3" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="350.5" y="-26.3" font-family="Times,serif" font-size="14.00">set_contact</text>
</g>
<!-- Admin::SettingsController -->
<g id="node16" class="node"><title>Admin::SettingsController</title>
<path fill="none" stroke="black" d="M-275.5,-0.5C-275.5,-0.5 -138.5,-0.5 -138.5,-0.5 -132.5,-0.5 -126.5,-6.5 -126.5,-12.5 -126.5,-12.5 -126.5,-171.5 -126.5,-171.5 -126.5,-177.5 -132.5,-183.5 -138.5,-183.5 -138.5,-183.5 -275.5,-183.5 -275.5,-183.5 -281.5,-183.5 -287.5,-177.5 -287.5,-171.5 -287.5,-171.5 -287.5,-12.5 -287.5,-12.5 -287.5,-6.5 -281.5,-0.5 -275.5,-0.5"/>
<text text-anchor="middle" x="-207" y="-168.3" font-family="Times,serif" font-size="14.00">Admin::SettingsController</text>
<polyline fill="none" stroke="black" points="-287.5,-160.5 -126.5,-160.5 "/>
<text text-anchor="start" x="-279.5" y="-145.3" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="-279.5" y="-130.3" font-family="Times,serif" font-size="14.00">index</text>
<text text-anchor="start" x="-279.5" y="-115.3" font-family="Times,serif" font-size="14.00">show</text>
<text text-anchor="start" x="-279.5" y="-100.3" font-family="Times,serif" font-size="14.00">update</text>
<polyline fill="none" stroke="black" points="-287.5,-92.5 -126.5,-92.5 "/>
<polyline fill="none" stroke="black" points="-287.5,-68.5 -126.5,-68.5 "/>
<text text-anchor="start" x="-279.5" y="-53.3" font-family="Times,serif" font-size="14.00">_layout</text>
<text text-anchor="start" x="-279.5" y="-38.3" font-family="Times,serif" font-size="14.00">casted_settings</text>
<text text-anchor="start" x="-279.5" y="-23.3" font-family="Times,serif" font-size="14.00">set_setting_group</text>
<text text-anchor="start" x="-279.5" y="-8.3" font-family="Times,serif" font-size="14.00">setting_group_params</text>
</g>
<!-- Admin::ZonefilesController -->
<g id="node17" class="node"><title>Admin::ZonefilesController</title>
<path fill="none" stroke="black" d="M353.5,-181C353.5,-181 498.5,-181 498.5,-181 504.5,-181 510.5,-187 510.5,-193 510.5,-193 510.5,-277 510.5,-277 510.5,-283 504.5,-289 498.5,-289 498.5,-289 353.5,-289 353.5,-289 347.5,-289 341.5,-283 341.5,-277 341.5,-277 341.5,-193 341.5,-193 341.5,-187 347.5,-181 353.5,-181"/>
<text text-anchor="middle" x="426" y="-273.8" font-family="Times,serif" font-size="14.00">Admin::ZonefilesController</text>
<polyline fill="none" stroke="black" points="341.5,-266 510.5,-266 "/>
<text text-anchor="start" x="349.5" y="-250.8" font-family="Times,serif" font-size="14.00">create</text>
<text text-anchor="start" x="349.5" y="-235.8" font-family="Times,serif" font-size="14.00">index</text>
<polyline fill="none" stroke="black" points="341.5,-228 510.5,-228 "/>
<polyline fill="none" stroke="black" points="341.5,-204 510.5,-204 "/>
<text text-anchor="start" x="349.5" y="-188.8" font-family="Times,serif" font-size="14.00">_layout</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 22 KiB

5735
doc/epp-doc.md Normal file

File diff suppressed because it is too large Load diff

421
doc/models_brief.svg Normal file
View file

@ -0,0 +1,421 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: models_diagram Pages: 1 -->
<svg width="2230pt" height="580pt"
viewBox="0.00 0.00 2229.69 580.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 576)">
<title>models_diagram</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-576 2225.69,-576 2225.69,4 -4,4"/>
<!-- _diagram_info -->
<g id="node1" class="node"><title>_diagram_info</title>
<text text-anchor="start" x="521.243" y="-557.6" font-family="Times,serif" font-size="13.00">Models diagram</text>
<text text-anchor="start" x="521.243" y="-543.6" font-family="Times,serif" font-size="13.00">Date: Dec 15 2014 &#45; 14:23</text>
<text text-anchor="start" x="521.243" y="-529.6" font-family="Times,serif" font-size="13.00">Migration version: 20141202114457</text>
<text text-anchor="start" x="521.243" y="-515.6" font-family="Times,serif" font-size="13.00">Generated by RailRoady 1.2.0</text>
<text text-anchor="start" x="521.243" y="-501.6" font-family="Times,serif" font-size="13.00">http://railroady.prestonlee.com</text>
</g>
<!-- Ability -->
<g id="node2" class="node"><title>Ability</title>
<polygon fill="none" stroke="black" points="800.743,-551 745.743,-551 745.743,-515 800.743,-515 800.743,-551"/>
<text text-anchor="middle" x="773.243" y="-529.3" font-family="Times,serif" font-size="14.00">Ability</text>
</g>
<!-- ContactDisclosure -->
<g id="node3" class="node"><title>ContactDisclosure</title>
<ellipse fill="none" stroke="black" cx="904.243" cy="-192" rx="75.2868" ry="18"/>
<text text-anchor="middle" x="904.243" y="-188.3" font-family="Times,serif" font-size="14.00">ContactDisclosure</text>
</g>
<!-- DomainStatusVersion -->
<g id="node4" class="node"><title>DomainStatusVersion</title>
<ellipse fill="none" stroke="black" cx="569.243" cy="-18" rx="89.0842" ry="18"/>
<text text-anchor="middle" x="569.243" y="-14.3" font-family="Times,serif" font-size="14.00">DomainStatusVersion</text>
</g>
<!-- DomainContact -->
<g id="node5" class="node"><title>DomainContact</title>
<ellipse fill="none" stroke="black" cx="869.243" cy="-105" rx="66.8882" ry="18"/>
<text text-anchor="middle" x="869.243" y="-101.3" font-family="Times,serif" font-size="14.00">DomainContact</text>
</g>
<!-- Right -->
<g id="node6" class="node"><title>Right</title>
<ellipse fill="none" stroke="black" cx="849.243" cy="-533" rx="30.5947" ry="18"/>
<text text-anchor="middle" x="849.243" y="-529.3" font-family="Times,serif" font-size="14.00">Right</text>
</g>
<!-- Role -->
<g id="node25" class="node"><title>Role</title>
<ellipse fill="none" stroke="black" cx="849.243" cy="-425" rx="27.0966" ry="18"/>
<text text-anchor="middle" x="849.243" y="-421.3" font-family="Times,serif" font-size="14.00">Role</text>
</g>
<!-- Right&#45;&gt;Role -->
<g id="edge1" class="edge"><title>Right&#45;&gt;Role</title>
<path fill="none" stroke="#52fd86" d="M849.243,-504.931C849.243,-489.187 849.243,-469.393 849.243,-453.566"/>
<polygon fill="#52fd86" stroke="#52fd86" points="849.243,-504.969 844.743,-514.969 849.243,-509.969 849.243,-514.969 849.243,-514.969 849.243,-514.969 849.243,-509.969 853.743,-514.969 849.243,-504.969 849.243,-504.969"/>
<polygon fill="#52fd86" stroke="#52fd86" points="849.243,-453.341 853.743,-443.341 849.243,-448.341 849.243,-443.341 849.243,-443.341 849.243,-443.341 849.243,-448.341 844.743,-443.341 849.243,-453.341 849.243,-453.341"/>
</g>
<!-- Contact -->
<g id="node7" class="node"><title>Contact</title>
<ellipse fill="none" stroke="black" cx="794.243" cy="-279" rx="38.1938" ry="18"/>
<text text-anchor="middle" x="794.243" y="-275.3" font-family="Times,serif" font-size="14.00">Contact</text>
</g>
<!-- Contact&#45;&gt;ContactDisclosure -->
<g id="edge3" class="edge"><title>Contact&#45;&gt;ContactDisclosure</title>
<path fill="none" stroke="#73d146" d="M819.887,-258.184C836.832,-245.09 859.036,-227.932 876.41,-214.507"/>
<ellipse fill="none" stroke="#73d146" cx="816.568" cy="-260.748" rx="4.00002" ry="4.00002"/>
<ellipse fill="#73d146" stroke="#73d146" cx="879.885" cy="-211.822" rx="4.00002" ry="4.00002"/>
<text text-anchor="middle" x="883.743" y="-231.8" font-family="Times,serif" font-size="14.00">disclosure</text>
</g>
<!-- Contact&#45;&gt;DomainContact -->
<g id="edge4" class="edge"><title>Contact&#45;&gt;DomainContact</title>
<path fill="none" stroke="#250a3e" d="M797.806,-252.712C801.492,-231.076 808.411,-199.483 820.243,-174 827.413,-158.558 838.264,-143.028 847.934,-130.715"/>
<ellipse fill="none" stroke="#250a3e" cx="797.144" cy="-256.815" rx="4.00001" ry="4.00001"/>
<polygon fill="#250a3e" stroke="#250a3e" points="848.091,-130.52 857.879,-125.575 851.235,-126.633 854.38,-122.745 854.38,-122.745 854.38,-122.745 851.235,-126.633 850.881,-119.915 848.091,-130.52 848.091,-130.52"/>
</g>
<!-- ContactVersion -->
<g id="node20" class="node"><title>ContactVersion</title>
<ellipse fill="none" stroke="black" cx="1063.24" cy="-192" rx="65.7887" ry="18"/>
<text text-anchor="middle" x="1063.24" y="-188.3" font-family="Times,serif" font-size="14.00">ContactVersion</text>
</g>
<!-- Contact&#45;&gt;ContactVersion -->
<g id="edge6" class="edge"><title>Contact&#45;&gt;ContactVersion</title>
<path fill="none" stroke="#32efde" d="M834.2,-266.922C857.845,-260.247 888.339,-251.431 915.243,-243 948.58,-232.553 985.839,-219.96 1014.63,-210.026"/>
<ellipse fill="none" stroke="#32efde" cx="830.309" cy="-268.017" rx="4.00001" ry="4.00001"/>
<polygon fill="#32efde" stroke="#32efde" points="1014.99,-209.901 1025.92,-210.883 1019.72,-208.266 1024.45,-206.631 1024.45,-206.631 1024.45,-206.631 1019.72,-208.266 1022.97,-202.378 1014.99,-209.901 1014.99,-209.901"/>
<text text-anchor="middle" x="983.243" y="-231.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Address -->
<g id="node26" class="node"><title>Address</title>
<ellipse fill="none" stroke="black" cx="1186.24" cy="-192" rx="39.7935" ry="18"/>
<text text-anchor="middle" x="1186.24" y="-188.3" font-family="Times,serif" font-size="14.00">Address</text>
</g>
<!-- Contact&#45;&gt;Address -->
<g id="edge2" class="edge"><title>Contact&#45;&gt;Address</title>
<path fill="none" stroke="#544287" d="M838.894,-271.985C882.727,-265.793 951.384,-255.329 1010.24,-243 1067.74,-230.956 1082.05,-227.157 1138.24,-210 1141.66,-208.955 1145.2,-207.816 1148.74,-206.638"/>
<ellipse fill="none" stroke="#544287" cx="834.699" cy="-272.573" rx="4.00001" ry="4.00001"/>
<ellipse fill="#544287" stroke="#544287" cx="1152.63" cy="-205.31" rx="4.00001" ry="4.00001"/>
</g>
<!-- Domain -->
<g id="node27" class="node"><title>Domain</title>
<ellipse fill="none" stroke="black" cx="569.243" cy="-192" rx="39.7935" ry="18"/>
<text text-anchor="middle" x="569.243" y="-188.3" font-family="Times,serif" font-size="14.00">Domain</text>
</g>
<!-- Contact&#45;&gt;Domain -->
<g id="edge5" class="edge"><title>Contact&#45;&gt;Domain</title>
<path fill="none" stroke="#ae13eb" d="M745.73,-275.751C691.324,-272.249 607.626,-263.602 584.243,-243 577.668,-237.207 573.92,-228.658 571.801,-220.261"/>
<polygon fill="#ae13eb" stroke="#ae13eb" points="745.879,-275.76 755.588,-280.858 750.87,-276.063 755.86,-276.366 755.86,-276.366 755.86,-276.366 750.87,-276.063 756.133,-271.875 745.879,-275.76 745.879,-275.76"/>
<polygon fill="#ae13eb" stroke="#ae13eb" points="571.775,-220.119 574.368,-209.465 570.86,-215.204 569.944,-210.288 569.944,-210.288 569.944,-210.288 570.86,-215.204 565.521,-211.112 571.775,-220.119 571.775,-220.119"/>
</g>
<!-- DomainVersion -->
<g id="node8" class="node"><title>DomainVersion</title>
<ellipse fill="none" stroke="black" cx="716.243" cy="-105" rx="67.6881" ry="18"/>
<text text-anchor="middle" x="716.243" y="-101.3" font-family="Times,serif" font-size="14.00">DomainVersion</text>
</g>
<!-- Setting -->
<g id="node9" class="node"><title>Setting</title>
<ellipse fill="none" stroke="black" cx="933.243" cy="-533" rx="35.9954" ry="18"/>
<text text-anchor="middle" x="933.243" y="-529.3" font-family="Times,serif" font-size="14.00">Setting</text>
</g>
<!-- Nameserver -->
<g id="node10" class="node"><title>Nameserver</title>
<ellipse fill="none" stroke="black" cx="81.2428" cy="-105" rx="53.8905" ry="18"/>
<text text-anchor="middle" x="81.2428" y="-101.3" font-family="Times,serif" font-size="14.00">Nameserver</text>
</g>
<!-- NameserverVersion -->
<g id="node15" class="node"><title>NameserverVersion</title>
<ellipse fill="none" stroke="black" cx="81.2428" cy="-18" rx="81.4863" ry="18"/>
<text text-anchor="middle" x="81.2428" y="-14.3" font-family="Times,serif" font-size="14.00">NameserverVersion</text>
</g>
<!-- Nameserver&#45;&gt;NameserverVersion -->
<g id="edge7" class="edge"><title>Nameserver&#45;&gt;NameserverVersion</title>
<path fill="none" stroke="#cfe7f4" d="M81.2428,-78.6937C81.2428,-68.5119 81.2428,-56.7466 81.2428,-46.3666"/>
<ellipse fill="none" stroke="#cfe7f4" cx="81.2428" cy="-82.799" rx="4" ry="4"/>
<polygon fill="#cfe7f4" stroke="#cfe7f4" points="81.2429,-46.1754 85.7428,-36.1754 81.2428,-41.1754 81.2428,-36.1754 81.2428,-36.1754 81.2428,-36.1754 81.2428,-41.1754 76.7428,-36.1755 81.2429,-46.1754 81.2429,-46.1754"/>
<text text-anchor="middle" x="104.243" y="-57.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- EppUser -->
<g id="node11" class="node"><title>EppUser</title>
<ellipse fill="none" stroke="black" cx="622.243" cy="-352" rx="41.6928" ry="18"/>
<text text-anchor="middle" x="622.243" y="-348.3" font-family="Times,serif" font-size="14.00">EppUser</text>
</g>
<!-- EppUser&#45;&gt;Contact -->
<g id="edge8" class="edge"><title>EppUser&#45;&gt;Contact</title>
<path fill="none" stroke="#bed6a7" d="M658.869,-335.881C687.759,-323.955 727.89,-307.39 756.951,-295.394"/>
<ellipse fill="none" stroke="#bed6a7" cx="655.118" cy="-337.43" rx="4.00002" ry="4.00002"/>
<polygon fill="#bed6a7" stroke="#bed6a7" points="757.106,-295.33 768.067,-295.674 761.728,-293.422 766.35,-291.514 766.35,-291.514 766.35,-291.514 761.728,-293.422 764.632,-287.355 757.106,-295.33 757.106,-295.33"/>
</g>
<!-- Country -->
<g id="node12" class="node"><title>Country</title>
<ellipse fill="none" stroke="black" cx="1026.24" cy="-533" rx="39.7935" ry="18"/>
<text text-anchor="middle" x="1026.24" y="-529.3" font-family="Times,serif" font-size="14.00">Country</text>
</g>
<!-- ZonefileSetting -->
<g id="node13" class="node"><title>ZonefileSetting</title>
<ellipse fill="none" stroke="black" cx="1149.24" cy="-533" rx="65.7887" ry="18"/>
<text text-anchor="middle" x="1149.24" y="-529.3" font-family="Times,serif" font-size="14.00">ZonefileSetting</text>
</g>
<!-- CachedNameserver -->
<g id="node14" class="node"><title>CachedNameserver</title>
<ellipse fill="none" stroke="black" cx="1313.24" cy="-533" rx="79.8859" ry="18"/>
<text text-anchor="middle" x="1313.24" y="-529.3" font-family="Times,serif" font-size="14.00">CachedNameserver</text>
</g>
<!-- Epp::EppDomain -->
<g id="node16" class="node"><title>Epp::EppDomain</title>
<ellipse fill="none" stroke="black" cx="1484.24" cy="-533" rx="72.5877" ry="18"/>
<text text-anchor="middle" x="1484.24" y="-529.3" font-family="Times,serif" font-size="14.00">Epp::EppDomain</text>
</g>
<!-- Epp::DomainContact -->
<g id="node31" class="node"><title>Epp::DomainContact</title>
<ellipse fill="none" stroke="black" cx="1004.24" cy="-425" rx="85.5853" ry="18"/>
<text text-anchor="middle" x="1004.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::DomainContact</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainContact -->
<g id="edge9" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainContact</title>
<path fill="none" stroke="#3e691d" d="M1449.54,-512.535C1435.31,-505.464 1418.41,-498.189 1402.24,-494 1296.12,-466.507 1263.78,-497.287 1156.24,-476 1120.37,-468.9 1081.21,-455.884 1051.62,-444.911"/>
<ellipse fill="none" stroke="#3e691d" cx="1453.15" cy="-514.379" rx="4.00002" ry="4.00002"/>
<polygon fill="#3e691d" stroke="#3e691d" points="1051.33,-444.802 1043.55,-437.069 1046.65,-443.041 1041.97,-441.28 1041.97,-441.28 1041.97,-441.28 1046.65,-443.041 1040.38,-445.492 1051.33,-444.802 1051.33,-444.802"/>
</g>
<!-- Epp::Contact -->
<g id="node32" class="node"><title>Epp::Contact</title>
<ellipse fill="none" stroke="black" cx="1165.24" cy="-425" rx="57.3905" ry="18"/>
<text text-anchor="middle" x="1165.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::Contact</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Contact -->
<g id="edge10" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Contact</title>
<path fill="none" stroke="#8126a8" d="M1447.56,-511.587C1433.75,-504.832 1417.66,-498.02 1402.24,-494 1376.8,-487.365 1184.31,-495.11 1166.24,-476 1160.54,-469.967 1158.96,-461.464 1159.21,-453.179"/>
<polygon fill="#8126a8" stroke="#8126a8" points="1447.79,-511.704 1454.68,-520.234 1452.25,-513.961 1456.71,-516.219 1456.71,-516.219 1456.71,-516.219 1452.25,-513.961 1458.74,-512.204 1447.79,-511.704 1447.79,-511.704"/>
<polygon fill="#8126a8" stroke="#8126a8" points="1159.24,-452.942 1164.82,-443.502 1159.79,-447.972 1160.35,-443.003 1160.35,-443.003 1160.35,-443.003 1159.79,-447.972 1155.88,-442.504 1159.24,-452.942 1159.24,-452.942"/>
<text text-anchor="middle" x="1203.24" y="-464.8" font-family="Times,serif" font-size="14.00">tech_contacts</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Contact -->
<g id="edge11" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Contact</title>
<path fill="none" stroke="#6800cc" d="M1446.71,-511.896C1433.04,-505.307 1417.26,-498.524 1402.24,-494 1351.45,-478.695 1335.31,-490.384 1284.24,-476 1256.5,-468.185 1226.59,-455.601 1203.7,-445.013"/>
<polygon fill="#6800cc" stroke="#6800cc" points="1446.84,-511.959 1453.81,-520.429 1451.32,-514.177 1455.8,-516.396 1455.8,-516.396 1455.8,-516.396 1451.32,-514.177 1457.8,-512.363 1446.84,-511.959 1446.84,-511.959"/>
<polygon fill="#6800cc" stroke="#6800cc" points="1203.4,-444.87 1196.26,-436.544 1198.87,-442.743 1194.35,-440.617 1194.35,-440.617 1194.35,-440.617 1198.87,-442.743 1192.43,-444.69 1203.4,-444.87 1203.4,-444.87"/>
<text text-anchor="middle" x="1327.24" y="-464.8" font-family="Times,serif" font-size="14.00">admin_contacts</text>
</g>
<!-- Epp::Nameserver -->
<g id="node33" class="node"><title>Epp::Nameserver</title>
<ellipse fill="none" stroke="black" cx="1313.24" cy="-425" rx="72.5877" ry="18"/>
<text text-anchor="middle" x="1313.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::Nameserver</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Nameserver -->
<g id="edge12" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Nameserver</title>
<path fill="none" stroke="#b2a1df" d="M1451.52,-511.715C1421.72,-493.241 1377.86,-466.055 1347.57,-447.277"/>
<ellipse fill="none" stroke="#b2a1df" cx="1455.24" cy="-514.023" rx="4.00002" ry="4.00002"/>
<polygon fill="#b2a1df" stroke="#b2a1df" points="1347.52,-447.246 1341.39,-438.153 1343.27,-444.612 1339.02,-441.978 1339.02,-441.978 1339.02,-441.978 1343.27,-444.612 1336.65,-445.803 1347.52,-447.246 1347.52,-447.246"/>
</g>
<!-- Epp::DomainStatus -->
<g id="node34" class="node"><title>Epp::DomainStatus</title>
<ellipse fill="none" stroke="black" cx="1484.24" cy="-425" rx="79.8859" ry="18"/>
<text text-anchor="middle" x="1484.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::DomainStatus</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainStatus -->
<g id="edge13" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainStatus</title>
<path fill="none" stroke="#3c4c88" d="M1484.24,-506.795C1484.24,-490.735 1484.24,-469.927 1484.24,-453.45"/>
<ellipse fill="none" stroke="#3c4c88" cx="1484.24" cy="-510.969" rx="4" ry="4"/>
<polygon fill="#3c4c88" stroke="#3c4c88" points="1484.24,-453.341 1488.74,-443.341 1484.24,-448.341 1484.24,-443.341 1484.24,-443.341 1484.24,-443.341 1484.24,-448.341 1479.74,-443.341 1484.24,-453.341 1484.24,-453.341"/>
</g>
<!-- Epp::DomainTransfer -->
<g id="node35" class="node"><title>Epp::DomainTransfer</title>
<ellipse fill="none" stroke="black" cx="1670.24" cy="-425" rx="88.2844" ry="18"/>
<text text-anchor="middle" x="1670.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::DomainTransfer</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainTransfer -->
<g id="edge14" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainTransfer</title>
<path fill="none" stroke="#20469a" d="M1519.37,-511.983C1551.82,-493.49 1599.87,-466.105 1632.98,-447.234"/>
<ellipse fill="none" stroke="#20469a" cx="1515.56" cy="-514.15" rx="4.00002" ry="4.00002"/>
<polygon fill="#20469a" stroke="#20469a" points="1633.21,-447.103 1644.13,-446.061 1637.56,-444.628 1641.9,-442.152 1641.9,-442.152 1641.9,-442.152 1637.56,-444.628 1639.67,-438.242 1633.21,-447.103 1633.21,-447.103"/>
</g>
<!-- Epp::Dnskey -->
<g id="node36" class="node"><title>Epp::Dnskey</title>
<ellipse fill="none" stroke="black" cx="1833.24" cy="-425" rx="56.59" ry="18"/>
<text text-anchor="middle" x="1833.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::Dnskey</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Dnskey -->
<g id="edge15" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Dnskey</title>
<path fill="none" stroke="#549b6f" d="M1521.5,-512.958C1535.32,-506.371 1551.27,-499.316 1566.24,-494 1653.09,-463.158 1677.95,-465.828 1767.24,-443 1771.62,-441.882 1776.15,-440.719 1780.71,-439.55"/>
<ellipse fill="none" stroke="#549b6f" cx="1517.66" cy="-514.814" rx="4.00002" ry="4.00002"/>
<polygon fill="#549b6f" stroke="#549b6f" points="1780.96,-439.486 1791.76,-441.355 1785.8,-438.241 1790.64,-436.996 1790.64,-436.996 1790.64,-436.996 1785.8,-438.241 1789.52,-432.638 1780.96,-439.486 1780.96,-439.486"/>
</g>
<!-- Epp::Keyrelay -->
<g id="node37" class="node"><title>Epp::Keyrelay</title>
<ellipse fill="none" stroke="black" cx="1969.24" cy="-425" rx="61.99" ry="18"/>
<text text-anchor="middle" x="1969.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::Keyrelay</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Keyrelay -->
<g id="edge16" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Keyrelay</title>
<path fill="none" stroke="#b750d6" d="M1520.2,-512.66C1534.23,-505.837 1550.65,-498.703 1566.24,-494 1602.08,-483.19 1862.52,-450.257 1899.24,-443 1904.25,-442.01 1909.44,-440.904 1914.63,-439.743"/>
<ellipse fill="none" stroke="#b750d6" cx="1516.26" cy="-514.619" rx="4.00002" ry="4.00002"/>
<polygon fill="#b750d6" stroke="#b750d6" points="1914.81,-439.701 1925.57,-441.845 1919.69,-438.581 1924.56,-437.46 1924.56,-437.46 1924.56,-437.46 1919.69,-438.581 1923.55,-433.074 1914.81,-439.701 1914.81,-439.701"/>
</g>
<!-- Epp::DomainVersion -->
<g id="node38" class="node"><title>Epp::DomainVersion</title>
<ellipse fill="none" stroke="black" cx="2135.24" cy="-425" rx="86.3847" ry="18"/>
<text text-anchor="middle" x="2135.24" y="-421.3" font-family="Times,serif" font-size="14.00">Epp::DomainVersion</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainVersion -->
<g id="edge17" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainVersion</title>
<path fill="none" stroke="#fc9fa3" d="M1519.37,-512.648C1533.53,-505.669 1550.28,-498.428 1566.24,-494 1566.64,-493.889 2039.83,-443.059 2040.24,-443 2047.82,-441.915 2055.72,-440.676 2063.59,-439.372"/>
<ellipse fill="none" stroke="#fc9fa3" cx="1515.78" cy="-514.456" rx="4.00002" ry="4.00002"/>
<polygon fill="#fc9fa3" stroke="#fc9fa3" points="2063.65,-439.362 2074.26,-442.129 2068.58,-438.527 2073.51,-437.692 2073.51,-437.692 2073.51,-437.692 2068.58,-438.527 2072.76,-433.256 2063.65,-439.362 2063.65,-439.362"/>
<text text-anchor="middle" x="1882.24" y="-464.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Message -->
<g id="node17" class="node"><title>Message</title>
<ellipse fill="none" stroke="black" cx="724.243" cy="-352" rx="42.4939" ry="18"/>
<text text-anchor="middle" x="724.243" y="-348.3" font-family="Times,serif" font-size="14.00">Message</text>
</g>
<!-- EppSession -->
<g id="node18" class="node"><title>EppSession</title>
<ellipse fill="none" stroke="black" cx="1627.24" cy="-533" rx="51.9908" ry="18"/>
<text text-anchor="middle" x="1627.24" y="-529.3" font-family="Times,serif" font-size="14.00">EppSession</text>
</g>
<!-- AddressVersion -->
<g id="node19" class="node"><title>AddressVersion</title>
<ellipse fill="none" stroke="black" cx="1186.24" cy="-105" rx="67.6881" ry="18"/>
<text text-anchor="middle" x="1186.24" y="-101.3" font-family="Times,serif" font-size="14.00">AddressVersion</text>
</g>
<!-- Keyrelay -->
<g id="node21" class="node"><title>Keyrelay</title>
<ellipse fill="none" stroke="black" cx="196.243" cy="-105" rx="42.7926" ry="18"/>
<text text-anchor="middle" x="196.243" y="-101.3" font-family="Times,serif" font-size="14.00">Keyrelay</text>
</g>
<!-- ReservedDomain -->
<g id="node22" class="node"><title>ReservedDomain</title>
<ellipse fill="none" stroke="black" cx="1769.24" cy="-533" rx="72.2875" ry="18"/>
<text text-anchor="middle" x="1769.24" y="-529.3" font-family="Times,serif" font-size="14.00">ReservedDomain</text>
</g>
<!-- Registrar -->
<g id="node23" class="node"><title>Registrar</title>
<ellipse fill="none" stroke="black" cx="724.243" cy="-425" rx="42.7926" ry="18"/>
<text text-anchor="middle" x="724.243" y="-421.3" font-family="Times,serif" font-size="14.00">Registrar</text>
</g>
<!-- Registrar&#45;&gt;Contact -->
<g id="edge19" class="edge"><title>Registrar&#45;&gt;Contact</title>
<path fill="none" stroke="#0d46eb" d="M749.334,-402.956C758.796,-393.761 768.814,-382.276 775.243,-370 785.462,-350.488 790.185,-325.875 792.367,-307.322"/>
<ellipse fill="none" stroke="#0d46eb" cx="746.163" cy="-405.921" rx="4.00002" ry="4.00002"/>
<polygon fill="#0d46eb" stroke="#0d46eb" points="792.386,-307.134 797.859,-297.631 792.884,-302.159 793.381,-297.183 793.381,-297.183 793.381,-297.183 792.884,-302.159 788.904,-296.736 792.386,-307.134 792.386,-307.134"/>
</g>
<!-- Registrar&#45;&gt;EppUser -->
<g id="edge20" class="edge"><title>Registrar&#45;&gt;EppUser</title>
<path fill="none" stroke="#0f6841" d="M696.232,-404.502C682.399,-394.873 665.711,-383.257 651.688,-373.496"/>
<ellipse fill="none" stroke="#0f6841" cx="699.825" cy="-407.004" rx="4.00002" ry="4.00002"/>
<polygon fill="#0f6841" stroke="#0f6841" points="651.558,-373.405 645.921,-363.999 647.454,-370.549 643.35,-367.692 643.35,-367.692 643.35,-367.692 647.454,-370.549 640.779,-371.386 651.558,-373.405 651.558,-373.405"/>
</g>
<!-- Registrar&#45;&gt;Message -->
<g id="edge22" class="edge"><title>Registrar&#45;&gt;Message</title>
<path fill="none" stroke="#5bd5eb" d="M724.243,-398.791C724.243,-392.832 724.243,-386.45 724.243,-380.399"/>
<ellipse fill="none" stroke="#5bd5eb" cx="724.243" cy="-402.813" rx="4" ry="4"/>
<polygon fill="#5bd5eb" stroke="#5bd5eb" points="724.243,-380.029 728.743,-370.029 724.243,-375.029 724.243,-370.029 724.243,-370.029 724.243,-370.029 724.243,-375.029 719.743,-370.029 724.243,-380.029 724.243,-380.029"/>
</g>
<!-- User -->
<g id="node24" class="node"><title>User</title>
<ellipse fill="none" stroke="black" cx="849.243" cy="-352" rx="27.0966" ry="18"/>
<text text-anchor="middle" x="849.243" y="-348.3" font-family="Times,serif" font-size="14.00">User</text>
</g>
<!-- Registrar&#45;&gt;User -->
<g id="edge21" class="edge"><title>Registrar&#45;&gt;User</title>
<path fill="none" stroke="#7c58ec" d="M764.698,-410.232C778.96,-404.589 794.783,-397.395 808.243,-389 814.874,-384.864 821.489,-379.655 827.41,-374.495"/>
<ellipse fill="none" stroke="#7c58ec" cx="760.693" cy="-411.771" rx="4.00001" ry="4.00001"/>
<polygon fill="#7c58ec" stroke="#7c58ec" points="827.596,-374.325 838.019,-370.919 831.293,-370.959 834.989,-367.592 834.989,-367.592 834.989,-367.592 831.293,-370.959 831.96,-364.265 827.596,-374.325 827.596,-374.325"/>
</g>
<!-- Registrar&#45;&gt;Domain -->
<g id="edge18" class="edge"><title>Registrar&#45;&gt;Domain</title>
<path fill="none" stroke="#d8ef9b" d="M673.49,-420.669C638.545,-415.428 594.395,-402.334 571.243,-370 539.354,-325.464 550.901,-257.14 560.858,-219.743"/>
<ellipse fill="none" stroke="#d8ef9b" cx="677.738" cy="-421.246" rx="4.00001" ry="4.00001"/>
<polygon fill="#d8ef9b" stroke="#d8ef9b" points="560.874,-219.686 567.918,-211.281 562.23,-214.873 563.587,-210.061 563.587,-210.061 563.587,-210.061 562.23,-214.873 559.256,-208.84 560.874,-219.686 560.874,-219.686"/>
</g>
<!-- Role&#45;&gt;User -->
<g id="edge23" class="edge"><title>Role&#45;&gt;User</title>
<path fill="none" stroke="#4adefa" d="M849.243,-398.791C849.243,-392.832 849.243,-386.45 849.243,-380.399"/>
<ellipse fill="none" stroke="#4adefa" cx="849.243" cy="-402.813" rx="4" ry="4"/>
<polygon fill="#4adefa" stroke="#4adefa" points="849.243,-380.029 853.743,-370.029 849.243,-375.029 849.243,-370.029 849.243,-370.029 849.243,-370.029 849.243,-375.029 844.743,-370.029 849.243,-380.029 849.243,-380.029"/>
</g>
<!-- Address&#45;&gt;AddressVersion -->
<g id="edge24" class="edge"><title>Address&#45;&gt;AddressVersion</title>
<path fill="none" stroke="#6aa72f" d="M1186.24,-165.694C1186.24,-155.512 1186.24,-143.747 1186.24,-133.367"/>
<ellipse fill="none" stroke="#6aa72f" cx="1186.24" cy="-169.799" rx="4" ry="4"/>
<polygon fill="#6aa72f" stroke="#6aa72f" points="1186.24,-133.175 1190.74,-123.175 1186.24,-128.175 1186.24,-123.175 1186.24,-123.175 1186.24,-123.175 1186.24,-128.175 1181.74,-123.175 1186.24,-133.175 1186.24,-133.175"/>
<text text-anchor="middle" x="1209.24" y="-144.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Domain&#45;&gt;DomainContact -->
<g id="edge25" class="edge"><title>Domain&#45;&gt;DomainContact</title>
<path fill="none" stroke="#6209cb" d="M610.816,-180.442C637.091,-173.675 671.727,-164.581 702.243,-156 740.924,-145.123 784.4,-132.08 817.295,-122.043"/>
<ellipse fill="none" stroke="#6209cb" cx="606.818" cy="-181.469" rx="4.00001" ry="4.00001"/>
<polygon fill="#6209cb" stroke="#6209cb" points="817.583,-121.955 828.462,-123.334 822.365,-120.492 827.146,-119.03 827.146,-119.03 827.146,-119.03 822.365,-120.492 825.83,-114.727 817.583,-121.955 817.583,-121.955"/>
</g>
<!-- Domain&#45;&gt;Contact -->
<g id="edge26" class="edge"><title>Domain&#45;&gt;Contact</title>
<path fill="none" stroke="#12675c" d="M581.884,-218.779C587.529,-227.764 595.016,-237.072 604.243,-243 627.36,-257.854 698.715,-268.031 747.093,-273.433"/>
<polygon fill="#12675c" stroke="#12675c" points="581.842,-218.706 580.756,-207.794 579.348,-214.372 576.855,-210.038 576.855,-210.038 576.855,-210.038 579.348,-214.372 572.955,-212.282 581.842,-218.706 581.842,-218.706"/>
<polygon fill="#12675c" stroke="#12675c" points="747.1,-273.434 756.556,-278.987 752.071,-273.974 757.041,-274.514 757.041,-274.514 757.041,-274.514 752.071,-273.974 757.527,-270.04 747.1,-273.434 747.1,-273.434"/>
<text text-anchor="middle" x="641.243" y="-231.8" font-family="Times,serif" font-size="14.00">tech_contacts</text>
</g>
<!-- Domain&#45;&gt;Contact -->
<g id="edge27" class="edge"><title>Domain&#45;&gt;Contact</title>
<path fill="none" stroke="#50d0e3" d="M613.153,-204.192C633.448,-210.093 657.577,-218.162 678.243,-228 689.262,-233.246 690.356,-237.485 701.243,-243 717.967,-251.472 737.25,-259.059 753.907,-264.985"/>
<polygon fill="#50d0e3" stroke="#50d0e3" points="613.152,-204.192 604.754,-197.141 608.341,-202.831 603.529,-201.471 603.529,-201.471 603.529,-201.471 608.341,-202.831 602.305,-205.801 613.152,-204.192 613.152,-204.192"/>
<polygon fill="#50d0e3" stroke="#50d0e3" points="753.927,-264.991 761.894,-272.526 758.649,-266.634 763.372,-268.276 763.372,-268.276 763.372,-268.276 758.649,-266.634 764.85,-264.026 753.927,-264.991 753.927,-264.991"/>
<text text-anchor="middle" x="744.243" y="-231.8" font-family="Times,serif" font-size="14.00">admin_contacts</text>
</g>
<!-- Domain&#45;&gt;DomainVersion -->
<g id="edge33" class="edge"><title>Domain&#45;&gt;DomainVersion</title>
<path fill="none" stroke="#9123f3" d="M599.978,-173.228C623.455,-159.653 655.859,-140.916 680.496,-126.67"/>
<ellipse fill="none" stroke="#9123f3" cx="596.324" cy="-175.341" rx="4.00002" ry="4.00002"/>
<polygon fill="#9123f3" stroke="#9123f3" points="680.533,-126.649 691.442,-125.539 684.861,-124.146 689.19,-121.643 689.19,-121.643 689.19,-121.643 684.861,-124.146 686.937,-117.747 680.533,-126.649 680.533,-126.649"/>
<text text-anchor="middle" x="675.243" y="-144.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Domain&#45;&gt;Nameserver -->
<g id="edge28" class="edge"><title>Domain&#45;&gt;Nameserver</title>
<path fill="none" stroke="#aaaeb3" d="M523.187,-185.604C444.792,-175.98 280.648,-153.924 144.243,-123 139.899,-122.015 135.404,-120.932 130.907,-119.804"/>
<ellipse fill="none" stroke="#aaaeb3" cx="527.439" cy="-186.122" rx="4.00001" ry="4.00001"/>
<polygon fill="#aaaeb3" stroke="#aaaeb3" points="130.798,-119.776 122.236,-112.925 125.956,-118.53 121.114,-117.283 121.114,-117.283 121.114,-117.283 125.956,-118.53 119.992,-121.641 130.798,-119.776 130.798,-119.776"/>
</g>
<!-- Domain&#45;&gt;Keyrelay -->
<g id="edge32" class="edge"><title>Domain&#45;&gt;Keyrelay</title>
<path fill="none" stroke="#67d30a" d="M524.763,-183.212C462.45,-171.932 345.847,-149.475 248.243,-123 244.887,-122.09 241.427,-121.092 237.963,-120.051"/>
<ellipse fill="none" stroke="#67d30a" cx="528.885" cy="-183.954" rx="4.00001" ry="4.00001"/>
<polygon fill="#67d30a" stroke="#67d30a" points="237.815,-120.005 229.601,-112.739 233.04,-118.521 228.265,-117.037 228.265,-117.037 228.265,-117.037 233.04,-118.521 226.93,-121.334 237.815,-120.005 237.815,-120.005"/>
</g>
<!-- Dnskey -->
<g id="node28" class="node"><title>Dnskey</title>
<ellipse fill="none" stroke="black" cx="295.243" cy="-105" rx="37.8943" ry="18"/>
<text text-anchor="middle" x="295.243" y="-101.3" font-family="Times,serif" font-size="14.00">Dnskey</text>
</g>
<!-- Domain&#45;&gt;Dnskey -->
<g id="edge31" class="edge"><title>Domain&#45;&gt;Dnskey</title>
<path fill="none" stroke="#64c75b" d="M528.27,-179.637C482.44,-166.728 406.116,-144.637 341.243,-123 338.681,-122.146 336.048,-121.242 333.4,-120.314"/>
<ellipse fill="none" stroke="#64c75b" cx="532.336" cy="-180.779" rx="4.00001" ry="4.00001"/>
<polygon fill="#64c75b" stroke="#64c75b" points="333.267,-120.267 325.369,-112.659 328.559,-118.581 323.852,-116.896 323.852,-116.896 323.852,-116.896 328.559,-118.581 322.335,-121.132 333.267,-120.267 333.267,-120.267"/>
</g>
<!-- DomainTransfer -->
<g id="node29" class="node"><title>DomainTransfer</title>
<ellipse fill="none" stroke="black" cx="420.243" cy="-105" rx="69.5877" ry="18"/>
<text text-anchor="middle" x="420.243" y="-101.3" font-family="Times,serif" font-size="14.00">DomainTransfer</text>
</g>
<!-- Domain&#45;&gt;DomainTransfer -->
<g id="edge30" class="edge"><title>Domain&#45;&gt;DomainTransfer</title>
<path fill="none" stroke="#510602" d="M538.409,-173.41C514.558,-159.804 481.478,-140.933 456.384,-126.617"/>
<ellipse fill="none" stroke="#510602" cx="542.159" cy="-175.549" rx="4.00002" ry="4.00002"/>
<polygon fill="#510602" stroke="#510602" points="456.218,-126.523 449.762,-117.659 451.875,-124.045 447.532,-121.568 447.532,-121.568 447.532,-121.568 451.875,-124.045 445.302,-125.476 456.218,-126.523 456.218,-126.523"/>
</g>
<!-- DomainStatus -->
<g id="node30" class="node"><title>DomainStatus</title>
<ellipse fill="none" stroke="black" cx="569.243" cy="-105" rx="61.1893" ry="18"/>
<text text-anchor="middle" x="569.243" y="-101.3" font-family="Times,serif" font-size="14.00">DomainStatus</text>
</g>
<!-- Domain&#45;&gt;DomainStatus -->
<g id="edge29" class="edge"><title>Domain&#45;&gt;DomainStatus</title>
<path fill="none" stroke="#2dc06d" d="M569.243,-165.694C569.243,-155.512 569.243,-143.747 569.243,-133.367"/>
<ellipse fill="none" stroke="#2dc06d" cx="569.243" cy="-169.799" rx="4" ry="4"/>
<polygon fill="#2dc06d" stroke="#2dc06d" points="569.243,-133.175 573.743,-123.175 569.243,-128.175 569.243,-123.175 569.243,-123.175 569.243,-123.175 569.243,-128.175 564.743,-123.175 569.243,-133.175 569.243,-133.175"/>
</g>
<!-- DomainStatus&#45;&gt;DomainStatusVersion -->
<g id="edge34" class="edge"><title>DomainStatus&#45;&gt;DomainStatusVersion</title>
<path fill="none" stroke="#e1e0ae" d="M569.243,-78.6937C569.243,-68.5119 569.243,-56.7466 569.243,-46.3666"/>
<ellipse fill="none" stroke="#e1e0ae" cx="569.243" cy="-82.799" rx="4" ry="4"/>
<polygon fill="#e1e0ae" stroke="#e1e0ae" points="569.243,-46.1754 573.743,-36.1754 569.243,-41.1754 569.243,-36.1754 569.243,-36.1754 569.243,-36.1754 569.243,-41.1754 564.743,-36.1755 569.243,-46.1754 569.243,-46.1754"/>
<text text-anchor="middle" x="592.243" y="-57.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 32 KiB

691
doc/models_complete.svg Normal file
View file

@ -0,0 +1,691 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.38.0 (20140413.2041)
-->
<!-- Title: models_diagram Pages: 1 -->
<svg width="2763pt" height="1905pt"
viewBox="0.00 0.00 2762.94 1905.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 1901)">
<title>models_diagram</title>
<polygon fill="white" stroke="none" points="-4,4 -4,-1901 2758.94,-1901 2758.94,4 -4,4"/>
<!-- _diagram_info -->
<g id="node1" class="node"><title>_diagram_info</title>
<text text-anchor="start" x="873.5" y="-1793.1" font-family="Times,serif" font-size="13.00">Models diagram</text>
<text text-anchor="start" x="873.5" y="-1779.1" font-family="Times,serif" font-size="13.00">Date: Dec 15 2014 &#45; 14:23</text>
<text text-anchor="start" x="873.5" y="-1765.1" font-family="Times,serif" font-size="13.00">Migration version: 20141202114457</text>
<text text-anchor="start" x="873.5" y="-1751.1" font-family="Times,serif" font-size="13.00">Generated by RailRoady 1.2.0</text>
<text text-anchor="start" x="873.5" y="-1737.1" font-family="Times,serif" font-size="13.00">http://railroady.prestonlee.com</text>
</g>
<!-- Ability -->
<g id="node2" class="node"><title>Ability</title>
<polygon fill="none" stroke="black" points="1098,-1745.5 1098,-1791.5 1153,-1791.5 1153,-1745.5 1098,-1745.5"/>
<text text-anchor="middle" x="1125.5" y="-1776.3" font-family="Times,serif" font-size="14.00">Ability</text>
<polyline fill="none" stroke="black" points="1098,-1768.5 1153,-1768.5 "/>
<text text-anchor="middle" x="1125.5" y="-1753.3" font-family="Times,serif" font-size="14.00"> </text>
</g>
<!-- ContactDisclosure -->
<g id="node3" class="node"><title>ContactDisclosure</title>
<path fill="none" stroke="black" d="M1058,-519C1058,-519 1165,-519 1165,-519 1171,-519 1177,-525 1177,-531 1177,-531 1177,-688 1177,-688 1177,-694 1171,-700 1165,-700 1165,-700 1058,-700 1058,-700 1052,-700 1046,-694 1046,-688 1046,-688 1046,-531 1046,-531 1046,-525 1052,-519 1058,-519"/>
<text text-anchor="middle" x="1111.5" y="-684.8" font-family="Times,serif" font-size="14.00">ContactDisclosure</text>
<polyline fill="none" stroke="black" points="1046,-677 1177,-677 "/>
<text text-anchor="start" x="1054" y="-661.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1054" y="-646.8" font-family="Times,serif" font-size="14.00">contact_id :integer</text>
<text text-anchor="start" x="1054" y="-631.8" font-family="Times,serif" font-size="14.00">phone :boolean</text>
<text text-anchor="start" x="1054" y="-616.8" font-family="Times,serif" font-size="14.00">fax :boolean</text>
<text text-anchor="start" x="1054" y="-601.8" font-family="Times,serif" font-size="14.00">email :boolean</text>
<text text-anchor="start" x="1054" y="-586.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1054" y="-571.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="1054" y="-556.8" font-family="Times,serif" font-size="14.00">name :boolean</text>
<text text-anchor="start" x="1054" y="-541.8" font-family="Times,serif" font-size="14.00">org_name :boolean</text>
<text text-anchor="start" x="1054" y="-526.8" font-family="Times,serif" font-size="14.00">address :boolean</text>
</g>
<!-- DomainStatusVersion -->
<g id="node4" class="node"><title>DomainStatusVersion</title>
<path fill="none" stroke="black" d="M731,-0.5C731,-0.5 844,-0.5 844,-0.5 850,-0.5 856,-6.5 856,-12.5 856,-12.5 856,-124.5 856,-124.5 856,-130.5 850,-136.5 844,-136.5 844,-136.5 731,-136.5 731,-136.5 725,-136.5 719,-130.5 719,-124.5 719,-124.5 719,-12.5 719,-12.5 719,-6.5 725,-0.5 731,-0.5"/>
<text text-anchor="middle" x="787.5" y="-121.3" font-family="Times,serif" font-size="14.00">DomainStatusVersion</text>
<polyline fill="none" stroke="black" points="719,-113.5 856,-113.5 "/>
<text text-anchor="start" x="727" y="-98.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="727" y="-83.3" font-family="Times,serif" font-size="14.00">item_type :string</text>
<text text-anchor="start" x="727" y="-68.3" font-family="Times,serif" font-size="14.00">item_id :integer</text>
<text text-anchor="start" x="727" y="-53.3" font-family="Times,serif" font-size="14.00">event :string</text>
<text text-anchor="start" x="727" y="-38.3" font-family="Times,serif" font-size="14.00">whodunnit :string</text>
<text text-anchor="start" x="727" y="-23.3" font-family="Times,serif" font-size="14.00">object :text</text>
<text text-anchor="start" x="727" y="-8.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
</g>
<!-- DomainContact -->
<g id="node5" class="node"><title>DomainContact</title>
<path fill="none" stroke="black" d="M1023,-248.5C1023,-248.5 1130,-248.5 1130,-248.5 1136,-248.5 1142,-254.5 1142,-260.5 1142,-260.5 1142,-357.5 1142,-357.5 1142,-363.5 1136,-369.5 1130,-369.5 1130,-369.5 1023,-369.5 1023,-369.5 1017,-369.5 1011,-363.5 1011,-357.5 1011,-357.5 1011,-260.5 1011,-260.5 1011,-254.5 1017,-248.5 1023,-248.5"/>
<text text-anchor="middle" x="1076.5" y="-354.3" font-family="Times,serif" font-size="14.00">DomainContact</text>
<polyline fill="none" stroke="black" points="1011,-346.5 1142,-346.5 "/>
<text text-anchor="start" x="1019" y="-331.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1019" y="-316.3" font-family="Times,serif" font-size="14.00">contact_id :integer</text>
<text text-anchor="start" x="1019" y="-301.3" font-family="Times,serif" font-size="14.00">domain_id :integer</text>
<text text-anchor="start" x="1019" y="-286.3" font-family="Times,serif" font-size="14.00">contact_type :string</text>
<text text-anchor="start" x="1019" y="-271.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1019" y="-256.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- Right -->
<g id="node6" class="node"><title>Right</title>
<path fill="none" stroke="black" d="M1183,-1723C1183,-1723 1290,-1723 1290,-1723 1296,-1723 1302,-1729 1302,-1735 1302,-1735 1302,-1802 1302,-1802 1302,-1808 1296,-1814 1290,-1814 1290,-1814 1183,-1814 1183,-1814 1177,-1814 1171,-1808 1171,-1802 1171,-1802 1171,-1735 1171,-1735 1171,-1729 1177,-1723 1183,-1723"/>
<text text-anchor="middle" x="1236.5" y="-1798.8" font-family="Times,serif" font-size="14.00">Right</text>
<polyline fill="none" stroke="black" points="1171,-1791 1302,-1791 "/>
<text text-anchor="start" x="1179" y="-1775.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1179" y="-1760.8" font-family="Times,serif" font-size="14.00">code :string</text>
<text text-anchor="start" x="1179" y="-1745.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1179" y="-1730.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- Role -->
<g id="node25" class="node"><title>Role</title>
<path fill="none" stroke="black" d="M1183,-1460C1183,-1460 1290,-1460 1290,-1460 1296,-1460 1302,-1466 1302,-1472 1302,-1472 1302,-1539 1302,-1539 1302,-1545 1296,-1551 1290,-1551 1290,-1551 1183,-1551 1183,-1551 1177,-1551 1171,-1545 1171,-1539 1171,-1539 1171,-1472 1171,-1472 1171,-1466 1177,-1460 1183,-1460"/>
<text text-anchor="middle" x="1236.5" y="-1535.8" font-family="Times,serif" font-size="14.00">Role</text>
<polyline fill="none" stroke="black" points="1171,-1528 1302,-1528 "/>
<text text-anchor="start" x="1179" y="-1512.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1179" y="-1497.8" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="1179" y="-1482.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1179" y="-1467.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- Right&#45;&gt;Role -->
<g id="edge1" class="edge"><title>Right&#45;&gt;Role</title>
<path fill="none" stroke="#d92d82" d="M1236.5,-1712.73C1236.5,-1668.27 1236.5,-1605.87 1236.5,-1561.38"/>
<polygon fill="#d92d82" stroke="#d92d82" points="1236.5,-1712.93 1232,-1722.93 1236.5,-1717.93 1236.5,-1722.93 1236.5,-1722.93 1236.5,-1722.93 1236.5,-1717.93 1241,-1722.93 1236.5,-1712.93 1236.5,-1712.93"/>
<polygon fill="#d92d82" stroke="#d92d82" points="1236.5,-1561.32 1241,-1551.32 1236.5,-1556.32 1236.5,-1551.32 1236.5,-1551.32 1236.5,-1551.32 1236.5,-1556.32 1232,-1551.32 1236.5,-1561.32 1236.5,-1561.32"/>
</g>
<!-- Contact -->
<g id="node7" class="node"><title>Contact</title>
<path fill="none" stroke="black" d="M958.5,-789.5C958.5,-789.5 1076.5,-789.5 1076.5,-789.5 1082.5,-789.5 1088.5,-795.5 1088.5,-801.5 1088.5,-801.5 1088.5,-1063.5 1088.5,-1063.5 1088.5,-1069.5 1082.5,-1075.5 1076.5,-1075.5 1076.5,-1075.5 958.5,-1075.5 958.5,-1075.5 952.5,-1075.5 946.5,-1069.5 946.5,-1063.5 946.5,-1063.5 946.5,-801.5 946.5,-801.5 946.5,-795.5 952.5,-789.5 958.5,-789.5"/>
<text text-anchor="middle" x="1017.5" y="-1060.3" font-family="Times,serif" font-size="14.00">Contact</text>
<polyline fill="none" stroke="black" points="946.5,-1052.5 1088.5,-1052.5 "/>
<text text-anchor="start" x="954.5" y="-1037.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="954.5" y="-1022.3" font-family="Times,serif" font-size="14.00">code :string</text>
<text text-anchor="start" x="954.5" y="-1007.3" font-family="Times,serif" font-size="14.00">type :string</text>
<text text-anchor="start" x="954.5" y="-992.3" font-family="Times,serif" font-size="14.00">reg_no :string</text>
<text text-anchor="start" x="954.5" y="-977.3" font-family="Times,serif" font-size="14.00">phone :string</text>
<text text-anchor="start" x="954.5" y="-962.3" font-family="Times,serif" font-size="14.00">email :string</text>
<text text-anchor="start" x="954.5" y="-947.3" font-family="Times,serif" font-size="14.00">fax :string</text>
<text text-anchor="start" x="954.5" y="-932.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="954.5" y="-917.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="954.5" y="-902.3" font-family="Times,serif" font-size="14.00">ident :string</text>
<text text-anchor="start" x="954.5" y="-887.3" font-family="Times,serif" font-size="14.00">ident_type :string</text>
<text text-anchor="start" x="954.5" y="-872.3" font-family="Times,serif" font-size="14.00">created_by_id :integer</text>
<text text-anchor="start" x="954.5" y="-857.3" font-family="Times,serif" font-size="14.00">updated_by_id :integer</text>
<text text-anchor="start" x="954.5" y="-842.3" font-family="Times,serif" font-size="14.00">auth_info :string</text>
<text text-anchor="start" x="954.5" y="-827.3" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="954.5" y="-812.3" font-family="Times,serif" font-size="14.00">org_name :string</text>
<text text-anchor="start" x="954.5" y="-797.3" font-family="Times,serif" font-size="14.00">registrar_id :integer</text>
</g>
<!-- Contact&#45;&gt;ContactDisclosure -->
<g id="edge3" class="edge"><title>Contact&#45;&gt;ContactDisclosure</title>
<path fill="none" stroke="#846881" d="M1061.44,-781.461C1068.77,-756.435 1076.19,-731.07 1083,-707.811"/>
<ellipse fill="none" stroke="#846881" cx="1060.26" cy="-785.464" rx="4.00001" ry="4.00001"/>
<ellipse fill="#846881" stroke="#846881" cx="1084.16" cy="-703.846" rx="4.00001" ry="4.00001"/>
<text text-anchor="middle" x="1095" y="-759.8" font-family="Times,serif" font-size="14.00">disclosure</text>
</g>
<!-- Contact&#45;&gt;DomainContact -->
<g id="edge4" class="edge"><title>Contact&#45;&gt;DomainContact</title>
<path fill="none" stroke="#171045" d="M1016.81,-781.213C1018.15,-693.334 1022.89,-580.466 1036.5,-481 1041.12,-447.201 1049.35,-410.28 1057.14,-379.424"/>
<ellipse fill="none" stroke="#171045" cx="1016.75" cy="-785.37" rx="4" ry="4"/>
<polygon fill="#171045" stroke="#171045" points="1057.17,-379.317 1064.01,-370.747 1058.41,-374.474 1059.65,-369.63 1059.65,-369.63 1059.65,-369.63 1058.41,-374.474 1055.29,-368.513 1057.17,-379.317 1057.17,-379.317"/>
</g>
<!-- ContactVersion -->
<g id="node20" class="node"><title>ContactVersion</title>
<path fill="none" stroke="black" d="M1207,-541.5C1207,-541.5 1310,-541.5 1310,-541.5 1316,-541.5 1322,-547.5 1322,-553.5 1322,-553.5 1322,-665.5 1322,-665.5 1322,-671.5 1316,-677.5 1310,-677.5 1310,-677.5 1207,-677.5 1207,-677.5 1201,-677.5 1195,-671.5 1195,-665.5 1195,-665.5 1195,-553.5 1195,-553.5 1195,-547.5 1201,-541.5 1207,-541.5"/>
<text text-anchor="middle" x="1258.5" y="-662.3" font-family="Times,serif" font-size="14.00">ContactVersion</text>
<polyline fill="none" stroke="black" points="1195,-654.5 1322,-654.5 "/>
<text text-anchor="start" x="1203" y="-639.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1203" y="-624.3" font-family="Times,serif" font-size="14.00">item_type :string</text>
<text text-anchor="start" x="1203" y="-609.3" font-family="Times,serif" font-size="14.00">item_id :integer</text>
<text text-anchor="start" x="1203" y="-594.3" font-family="Times,serif" font-size="14.00">event :string</text>
<text text-anchor="start" x="1203" y="-579.3" font-family="Times,serif" font-size="14.00">whodunnit :string</text>
<text text-anchor="start" x="1203" y="-564.3" font-family="Times,serif" font-size="14.00">object :text</text>
<text text-anchor="start" x="1203" y="-549.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
</g>
<!-- Contact&#45;&gt;ContactVersion -->
<g id="edge6" class="edge"><title>Contact&#45;&gt;ContactVersion</title>
<path fill="none" stroke="#7a300b" d="M1094.1,-850.457C1124.16,-816.871 1157.98,-776.758 1185.5,-738 1196.94,-721.884 1208.15,-703.842 1218.21,-686.517"/>
<ellipse fill="none" stroke="#7a300b" cx="1091.21" cy="-853.675" rx="4.00002" ry="4.00002"/>
<polygon fill="#7a300b" stroke="#7a300b" points="1218.39,-686.21 1227.27,-679.776 1220.87,-681.873 1223.36,-677.536 1223.36,-677.536 1223.36,-677.536 1220.87,-681.873 1219.46,-675.297 1218.39,-686.21 1218.39,-686.21"/>
<text text-anchor="middle" x="1192.5" y="-759.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Address -->
<g id="node26" class="node"><title>Address</title>
<path fill="none" stroke="black" d="M1352,-519C1352,-519 1459,-519 1459,-519 1465,-519 1471,-525 1471,-531 1471,-531 1471,-688 1471,-688 1471,-694 1465,-700 1459,-700 1459,-700 1352,-700 1352,-700 1346,-700 1340,-694 1340,-688 1340,-688 1340,-531 1340,-531 1340,-525 1346,-519 1352,-519"/>
<text text-anchor="middle" x="1405.5" y="-684.8" font-family="Times,serif" font-size="14.00">Address</text>
<polyline fill="none" stroke="black" points="1340,-677 1471,-677 "/>
<text text-anchor="start" x="1348" y="-661.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1348" y="-646.8" font-family="Times,serif" font-size="14.00">contact_id :integer</text>
<text text-anchor="start" x="1348" y="-631.8" font-family="Times,serif" font-size="14.00">country_id :integer</text>
<text text-anchor="start" x="1348" y="-616.8" font-family="Times,serif" font-size="14.00">city :string</text>
<text text-anchor="start" x="1348" y="-601.8" font-family="Times,serif" font-size="14.00">street :string</text>
<text text-anchor="start" x="1348" y="-586.8" font-family="Times,serif" font-size="14.00">zip :string</text>
<text text-anchor="start" x="1348" y="-571.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1348" y="-556.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="1348" y="-541.8" font-family="Times,serif" font-size="14.00">street2 :string</text>
<text text-anchor="start" x="1348" y="-526.8" font-family="Times,serif" font-size="14.00">street3 :string</text>
</g>
<!-- Contact&#45;&gt;Address -->
<g id="edge2" class="edge"><title>Contact&#45;&gt;Address</title>
<path fill="none" stroke="#e6e9ed" d="M1095.96,-896.462C1164.1,-863.114 1262.29,-807.729 1330.5,-738 1339.57,-728.726 1347.98,-718.148 1355.64,-707.141"/>
<ellipse fill="none" stroke="#e6e9ed" cx="1092.23" cy="-898.272" rx="4.00002" ry="4.00002"/>
<ellipse fill="#e6e9ed" stroke="#e6e9ed" cx="1358.07" cy="-703.553" rx="4.00002" ry="4.00002"/>
</g>
<!-- Domain -->
<g id="node27" class="node"><title>Domain</title>
<path fill="none" stroke="black" d="M719.5,-481.5C719.5,-481.5 853.5,-481.5 853.5,-481.5 859.5,-481.5 865.5,-487.5 865.5,-493.5 865.5,-493.5 865.5,-725.5 865.5,-725.5 865.5,-731.5 859.5,-737.5 853.5,-737.5 853.5,-737.5 719.5,-737.5 719.5,-737.5 713.5,-737.5 707.5,-731.5 707.5,-725.5 707.5,-725.5 707.5,-493.5 707.5,-493.5 707.5,-487.5 713.5,-481.5 719.5,-481.5"/>
<text text-anchor="middle" x="786.5" y="-722.3" font-family="Times,serif" font-size="14.00">Domain</text>
<polyline fill="none" stroke="black" points="707.5,-714.5 865.5,-714.5 "/>
<text text-anchor="start" x="715.5" y="-699.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="715.5" y="-684.3" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="715.5" y="-669.3" font-family="Times,serif" font-size="14.00">registrar_id :integer</text>
<text text-anchor="start" x="715.5" y="-654.3" font-family="Times,serif" font-size="14.00">registered_at :datetime</text>
<text text-anchor="start" x="715.5" y="-639.3" font-family="Times,serif" font-size="14.00">status :string</text>
<text text-anchor="start" x="715.5" y="-624.3" font-family="Times,serif" font-size="14.00">valid_from :datetime</text>
<text text-anchor="start" x="715.5" y="-609.3" font-family="Times,serif" font-size="14.00">valid_to :datetime</text>
<text text-anchor="start" x="715.5" y="-594.3" font-family="Times,serif" font-size="14.00">owner_contact_id :integer</text>
<text text-anchor="start" x="715.5" y="-579.3" font-family="Times,serif" font-size="14.00">auth_info :string</text>
<text text-anchor="start" x="715.5" y="-564.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="715.5" y="-549.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="715.5" y="-534.3" font-family="Times,serif" font-size="14.00">name_dirty :string</text>
<text text-anchor="start" x="715.5" y="-519.3" font-family="Times,serif" font-size="14.00">name_puny :string</text>
<text text-anchor="start" x="715.5" y="-504.3" font-family="Times,serif" font-size="14.00">period :integer</text>
<text text-anchor="start" x="715.5" y="-489.3" font-family="Times,serif" font-size="14.00">period_unit :string</text>
</g>
<!-- Contact&#45;&gt;Domain -->
<g id="edge5" class="edge"><title>Contact&#45;&gt;Domain</title>
<path fill="none" stroke="#099468" d="M937.434,-894.164C889.123,-867.14 831.16,-825.751 800.5,-771 796.325,-763.545 792.948,-755.584 790.236,-747.344"/>
<polygon fill="#099468" stroke="#099468" points="937.565,-894.236 944.171,-902.989 941.95,-896.64 946.334,-899.043 946.334,-899.043 946.334,-899.043 941.95,-896.64 948.497,-895.097 937.565,-894.236 937.565,-894.236"/>
<polygon fill="#099468" stroke="#099468" points="790.178,-747.148 791.668,-736.284 788.765,-742.352 787.351,-737.556 787.351,-737.556 787.351,-737.556 788.765,-742.352 783.035,-738.829 790.178,-747.148 790.178,-747.148"/>
</g>
<!-- DomainVersion -->
<g id="node8" class="node"><title>DomainVersion</title>
<path fill="none" stroke="black" d="M878,-233.5C878,-233.5 981,-233.5 981,-233.5 987,-233.5 993,-239.5 993,-245.5 993,-245.5 993,-372.5 993,-372.5 993,-378.5 987,-384.5 981,-384.5 981,-384.5 878,-384.5 878,-384.5 872,-384.5 866,-378.5 866,-372.5 866,-372.5 866,-245.5 866,-245.5 866,-239.5 872,-233.5 878,-233.5"/>
<text text-anchor="middle" x="929.5" y="-369.3" font-family="Times,serif" font-size="14.00">DomainVersion</text>
<polyline fill="none" stroke="black" points="866,-361.5 993,-361.5 "/>
<text text-anchor="start" x="874" y="-346.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="874" y="-331.3" font-family="Times,serif" font-size="14.00">item_type :string</text>
<text text-anchor="start" x="874" y="-316.3" font-family="Times,serif" font-size="14.00">item_id :integer</text>
<text text-anchor="start" x="874" y="-301.3" font-family="Times,serif" font-size="14.00">event :string</text>
<text text-anchor="start" x="874" y="-286.3" font-family="Times,serif" font-size="14.00">whodunnit :string</text>
<text text-anchor="start" x="874" y="-271.3" font-family="Times,serif" font-size="14.00">object :text</text>
<text text-anchor="start" x="874" y="-256.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="874" y="-241.3" font-family="Times,serif" font-size="14.00">snapshot :text</text>
</g>
<!-- Setting -->
<g id="node9" class="node"><title>Setting</title>
<path fill="none" stroke="black" d="M1332,-1700.5C1332,-1700.5 1439,-1700.5 1439,-1700.5 1445,-1700.5 1451,-1706.5 1451,-1712.5 1451,-1712.5 1451,-1824.5 1451,-1824.5 1451,-1830.5 1445,-1836.5 1439,-1836.5 1439,-1836.5 1332,-1836.5 1332,-1836.5 1326,-1836.5 1320,-1830.5 1320,-1824.5 1320,-1824.5 1320,-1712.5 1320,-1712.5 1320,-1706.5 1326,-1700.5 1332,-1700.5"/>
<text text-anchor="middle" x="1385.5" y="-1821.3" font-family="Times,serif" font-size="14.00">Setting</text>
<polyline fill="none" stroke="black" points="1320,-1813.5 1451,-1813.5 "/>
<text text-anchor="start" x="1328" y="-1798.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1328" y="-1783.3" font-family="Times,serif" font-size="14.00">var :string</text>
<text text-anchor="start" x="1328" y="-1768.3" font-family="Times,serif" font-size="14.00">value :text</text>
<text text-anchor="start" x="1328" y="-1753.3" font-family="Times,serif" font-size="14.00">thing_id :integer</text>
<text text-anchor="start" x="1328" y="-1738.3" font-family="Times,serif" font-size="14.00">thing_type :string</text>
<text text-anchor="start" x="1328" y="-1723.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1328" y="-1708.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- Nameserver -->
<g id="node10" class="node"><title>Nameserver</title>
<path fill="none" stroke="black" d="M12,-241C12,-241 119,-241 119,-241 125,-241 131,-247 131,-253 131,-253 131,-365 131,-365 131,-371 125,-377 119,-377 119,-377 12,-377 12,-377 6,-377 0,-371 0,-365 0,-365 0,-253 0,-253 0,-247 6,-241 12,-241"/>
<text text-anchor="middle" x="65.5" y="-361.8" font-family="Times,serif" font-size="14.00">Nameserver</text>
<polyline fill="none" stroke="black" points="0,-354 131,-354 "/>
<text text-anchor="start" x="8" y="-338.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="8" y="-323.8" font-family="Times,serif" font-size="14.00">hostname :string</text>
<text text-anchor="start" x="8" y="-308.8" font-family="Times,serif" font-size="14.00">ipv4 :string</text>
<text text-anchor="start" x="8" y="-293.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="8" y="-278.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="8" y="-263.8" font-family="Times,serif" font-size="14.00">ipv6 :string</text>
<text text-anchor="start" x="8" y="-248.8" font-family="Times,serif" font-size="14.00">domain_id :integer</text>
</g>
<!-- NameserverVersion -->
<g id="node15" class="node"><title>NameserverVersion</title>
<path fill="none" stroke="black" d="M14,-0.5C14,-0.5 117,-0.5 117,-0.5 123,-0.5 129,-6.5 129,-12.5 129,-12.5 129,-124.5 129,-124.5 129,-130.5 123,-136.5 117,-136.5 117,-136.5 14,-136.5 14,-136.5 8,-136.5 2,-130.5 2,-124.5 2,-124.5 2,-12.5 2,-12.5 2,-6.5 8,-0.5 14,-0.5"/>
<text text-anchor="middle" x="65.5" y="-121.3" font-family="Times,serif" font-size="14.00">NameserverVersion</text>
<polyline fill="none" stroke="black" points="2,-113.5 129,-113.5 "/>
<text text-anchor="start" x="10" y="-98.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="10" y="-83.3" font-family="Times,serif" font-size="14.00">item_type :string</text>
<text text-anchor="start" x="10" y="-68.3" font-family="Times,serif" font-size="14.00">item_id :integer</text>
<text text-anchor="start" x="10" y="-53.3" font-family="Times,serif" font-size="14.00">event :string</text>
<text text-anchor="start" x="10" y="-38.3" font-family="Times,serif" font-size="14.00">whodunnit :string</text>
<text text-anchor="start" x="10" y="-23.3" font-family="Times,serif" font-size="14.00">object :text</text>
<text text-anchor="start" x="10" y="-8.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
</g>
<!-- Nameserver&#45;&gt;NameserverVersion -->
<g id="edge7" class="edge"><title>Nameserver&#45;&gt;NameserverVersion</title>
<path fill="none" stroke="#3620af" d="M65.5,-232.805C65.5,-205.547 65.5,-174.716 65.5,-147.244"/>
<ellipse fill="none" stroke="#3620af" cx="65.5" cy="-236.93" rx="4" ry="4"/>
<polygon fill="#3620af" stroke="#3620af" points="65.5001,-146.893 70,-136.893 65.5,-141.893 65.5,-136.893 65.5,-136.893 65.5,-136.893 65.5,-141.893 61,-136.893 65.5001,-146.893 65.5001,-146.893"/>
<text text-anchor="middle" x="88.5" y="-158.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- EppUser -->
<g id="node11" class="node"><title>EppUser</title>
<path fill="none" stroke="black" d="M802,-1166C802,-1166 909,-1166 909,-1166 915,-1166 921,-1172 921,-1178 921,-1178 921,-1320 921,-1320 921,-1326 915,-1332 909,-1332 909,-1332 802,-1332 802,-1332 796,-1332 790,-1326 790,-1320 790,-1320 790,-1178 790,-1178 790,-1172 796,-1166 802,-1166"/>
<text text-anchor="middle" x="855.5" y="-1316.8" font-family="Times,serif" font-size="14.00">EppUser</text>
<polyline fill="none" stroke="black" points="790,-1309 921,-1309 "/>
<text text-anchor="start" x="798" y="-1293.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="798" y="-1278.8" font-family="Times,serif" font-size="14.00">registrar_id :integer</text>
<text text-anchor="start" x="798" y="-1263.8" font-family="Times,serif" font-size="14.00">username :string</text>
<text text-anchor="start" x="798" y="-1248.8" font-family="Times,serif" font-size="14.00">password :string</text>
<text text-anchor="start" x="798" y="-1233.8" font-family="Times,serif" font-size="14.00">active :boolean</text>
<text text-anchor="start" x="798" y="-1218.8" font-family="Times,serif" font-size="14.00">csr :text</text>
<text text-anchor="start" x="798" y="-1203.8" font-family="Times,serif" font-size="14.00">crt :text</text>
<text text-anchor="start" x="798" y="-1188.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="798" y="-1173.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- EppUser&#45;&gt;Contact -->
<g id="edge8" class="edge"><title>EppUser&#45;&gt;Contact</title>
<path fill="none" stroke="#8a341c" d="M901.553,-1158.59C914.099,-1134.24 928.028,-1107.2 941.756,-1080.55"/>
<ellipse fill="none" stroke="#8a341c" cx="899.684" cy="-1162.22" rx="4.00002" ry="4.00002"/>
<polygon fill="#8a341c" stroke="#8a341c" points="941.822,-1080.42 950.402,-1073.59 944.112,-1075.97 946.401,-1071.53 946.401,-1071.53 946.401,-1071.53 944.112,-1075.97 942.401,-1069.47 941.822,-1080.42 941.822,-1080.42"/>
</g>
<!-- Country -->
<g id="node12" class="node"><title>Country</title>
<path fill="none" stroke="black" d="M1481,-1715.5C1481,-1715.5 1588,-1715.5 1588,-1715.5 1594,-1715.5 1600,-1721.5 1600,-1727.5 1600,-1727.5 1600,-1809.5 1600,-1809.5 1600,-1815.5 1594,-1821.5 1588,-1821.5 1588,-1821.5 1481,-1821.5 1481,-1821.5 1475,-1821.5 1469,-1815.5 1469,-1809.5 1469,-1809.5 1469,-1727.5 1469,-1727.5 1469,-1721.5 1475,-1715.5 1481,-1715.5"/>
<text text-anchor="middle" x="1534.5" y="-1806.3" font-family="Times,serif" font-size="14.00">Country</text>
<polyline fill="none" stroke="black" points="1469,-1798.5 1600,-1798.5 "/>
<text text-anchor="start" x="1477" y="-1783.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1477" y="-1768.3" font-family="Times,serif" font-size="14.00">iso :string</text>
<text text-anchor="start" x="1477" y="-1753.3" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="1477" y="-1738.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1477" y="-1723.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- ZonefileSetting -->
<g id="node13" class="node"><title>ZonefileSetting</title>
<path fill="none" stroke="black" d="M1630,-1670.5C1630,-1670.5 1767,-1670.5 1767,-1670.5 1773,-1670.5 1779,-1676.5 1779,-1682.5 1779,-1682.5 1779,-1854.5 1779,-1854.5 1779,-1860.5 1773,-1866.5 1767,-1866.5 1767,-1866.5 1630,-1866.5 1630,-1866.5 1624,-1866.5 1618,-1860.5 1618,-1854.5 1618,-1854.5 1618,-1682.5 1618,-1682.5 1618,-1676.5 1624,-1670.5 1630,-1670.5"/>
<text text-anchor="middle" x="1698.5" y="-1851.3" font-family="Times,serif" font-size="14.00">ZonefileSetting</text>
<polyline fill="none" stroke="black" points="1618,-1843.5 1779,-1843.5 "/>
<text text-anchor="start" x="1626" y="-1828.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1626" y="-1813.3" font-family="Times,serif" font-size="14.00">origin :string</text>
<text text-anchor="start" x="1626" y="-1798.3" font-family="Times,serif" font-size="14.00">ttl :integer</text>
<text text-anchor="start" x="1626" y="-1783.3" font-family="Times,serif" font-size="14.00">refresh :integer</text>
<text text-anchor="start" x="1626" y="-1768.3" font-family="Times,serif" font-size="14.00">retry :integer</text>
<text text-anchor="start" x="1626" y="-1753.3" font-family="Times,serif" font-size="14.00">expire :integer</text>
<text text-anchor="start" x="1626" y="-1738.3" font-family="Times,serif" font-size="14.00">minimum_ttl :integer</text>
<text text-anchor="start" x="1626" y="-1723.3" font-family="Times,serif" font-size="14.00">email :string</text>
<text text-anchor="start" x="1626" y="-1708.3" font-family="Times,serif" font-size="14.00">master_nameserver :string</text>
<text text-anchor="start" x="1626" y="-1693.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1626" y="-1678.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- CachedNameserver -->
<g id="node14" class="node"><title>CachedNameserver</title>
<path fill="none" stroke="black" d="M1809,-1730.5C1809,-1730.5 1908,-1730.5 1908,-1730.5 1914,-1730.5 1920,-1736.5 1920,-1742.5 1920,-1742.5 1920,-1794.5 1920,-1794.5 1920,-1800.5 1914,-1806.5 1908,-1806.5 1908,-1806.5 1809,-1806.5 1809,-1806.5 1803,-1806.5 1797,-1800.5 1797,-1794.5 1797,-1794.5 1797,-1742.5 1797,-1742.5 1797,-1736.5 1803,-1730.5 1809,-1730.5"/>
<text text-anchor="middle" x="1858.5" y="-1791.3" font-family="Times,serif" font-size="14.00">CachedNameserver</text>
<polyline fill="none" stroke="black" points="1797,-1783.5 1920,-1783.5 "/>
<text text-anchor="start" x="1805" y="-1768.3" font-family="Times,serif" font-size="14.00">hostname :string</text>
<text text-anchor="start" x="1805" y="-1753.3" font-family="Times,serif" font-size="14.00">ipv4 :string</text>
<text text-anchor="start" x="1805" y="-1738.3" font-family="Times,serif" font-size="14.00">ipv6 :string</text>
</g>
<!-- Epp::EppDomain -->
<g id="node16" class="node"><title>Epp::EppDomain</title>
<path fill="none" stroke="black" d="M1950.5,-1640.5C1950.5,-1640.5 2084.5,-1640.5 2084.5,-1640.5 2090.5,-1640.5 2096.5,-1646.5 2096.5,-1652.5 2096.5,-1652.5 2096.5,-1884.5 2096.5,-1884.5 2096.5,-1890.5 2090.5,-1896.5 2084.5,-1896.5 2084.5,-1896.5 1950.5,-1896.5 1950.5,-1896.5 1944.5,-1896.5 1938.5,-1890.5 1938.5,-1884.5 1938.5,-1884.5 1938.5,-1652.5 1938.5,-1652.5 1938.5,-1646.5 1944.5,-1640.5 1950.5,-1640.5"/>
<text text-anchor="middle" x="2017.5" y="-1881.3" font-family="Times,serif" font-size="14.00">Epp::EppDomain</text>
<polyline fill="none" stroke="black" points="1938.5,-1873.5 2096.5,-1873.5 "/>
<text text-anchor="start" x="1946.5" y="-1858.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1946.5" y="-1843.3" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="1946.5" y="-1828.3" font-family="Times,serif" font-size="14.00">registrar_id :integer</text>
<text text-anchor="start" x="1946.5" y="-1813.3" font-family="Times,serif" font-size="14.00">registered_at :datetime</text>
<text text-anchor="start" x="1946.5" y="-1798.3" font-family="Times,serif" font-size="14.00">status :string</text>
<text text-anchor="start" x="1946.5" y="-1783.3" font-family="Times,serif" font-size="14.00">valid_from :datetime</text>
<text text-anchor="start" x="1946.5" y="-1768.3" font-family="Times,serif" font-size="14.00">valid_to :datetime</text>
<text text-anchor="start" x="1946.5" y="-1753.3" font-family="Times,serif" font-size="14.00">owner_contact_id :integer</text>
<text text-anchor="start" x="1946.5" y="-1738.3" font-family="Times,serif" font-size="14.00">auth_info :string</text>
<text text-anchor="start" x="1946.5" y="-1723.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1946.5" y="-1708.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="1946.5" y="-1693.3" font-family="Times,serif" font-size="14.00">name_dirty :string</text>
<text text-anchor="start" x="1946.5" y="-1678.3" font-family="Times,serif" font-size="14.00">name_puny :string</text>
<text text-anchor="start" x="1946.5" y="-1663.3" font-family="Times,serif" font-size="14.00">period :integer</text>
<text text-anchor="start" x="1946.5" y="-1648.3" font-family="Times,serif" font-size="14.00">period_unit :string</text>
</g>
<!-- Epp::DomainContact -->
<g id="node31" class="node"><title>Epp::DomainContact</title>
<ellipse fill="none" stroke="black" cx="1537.5" cy="-1505.5" rx="85.5853" ry="18"/>
<text text-anchor="middle" x="1537.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::DomainContact</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainContact -->
<g id="edge9" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainContact</title>
<path fill="none" stroke="#4900e5" d="M1931.66,-1641.87C1930.62,-1641.23 1929.56,-1640.61 1928.5,-1640 1881.84,-1613.41 1738.69,-1638.25 1687.5,-1622 1634.24,-1605.09 1585.56,-1559.7 1558.87,-1531.11"/>
<ellipse fill="none" stroke="#4900e5" cx="1935.07" cy="-1644.14" rx="4.00002" ry="4.00002"/>
<polygon fill="#4900e5" stroke="#4900e5" points="1558.69,-1530.91 1555.26,-1520.5 1555.32,-1527.22 1551.94,-1523.53 1551.94,-1523.53 1551.94,-1523.53 1555.32,-1527.22 1548.62,-1526.57 1558.69,-1530.91 1558.69,-1530.91"/>
</g>
<!-- Epp::Contact -->
<g id="node32" class="node"><title>Epp::Contact</title>
<ellipse fill="none" stroke="black" cx="1698.5" cy="-1505.5" rx="57.3905" ry="18"/>
<text text-anchor="middle" x="1698.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::Contact</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Contact -->
<g id="edge10" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Contact</title>
<path fill="none" stroke="#7ef3c3" d="M1929.77,-1640.74C1929.35,-1640.49 1928.92,-1640.24 1928.5,-1640 1884.2,-1614.64 1734.31,-1659.33 1699.5,-1622 1677.65,-1598.57 1682.68,-1559.39 1689.56,-1533.25"/>
<polygon fill="#7ef3c3" stroke="#7ef3c3" points="1930.02,-1640.9 1935.93,-1650.14 1934.21,-1643.64 1938.39,-1646.37 1938.39,-1646.37 1938.39,-1646.37 1934.21,-1643.64 1940.85,-1642.61 1930.02,-1640.9 1930.02,-1640.9"/>
<polygon fill="#7ef3c3" stroke="#7ef3c3" points="1689.57,-1533.21 1696.66,-1524.84 1690.95,-1528.4 1692.33,-1523.6 1692.33,-1523.6 1692.33,-1523.6 1690.95,-1528.4 1688.01,-1522.35 1689.57,-1533.21 1689.57,-1533.21"/>
<text text-anchor="middle" x="1736.5" y="-1610.8" font-family="Times,serif" font-size="14.00">tech_contacts</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Contact -->
<g id="edge11" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Contact</title>
<path fill="none" stroke="#b2fe58" d="M1930.09,-1641.04C1929.56,-1640.69 1929.03,-1640.34 1928.5,-1640 1890.08,-1615.44 1870.64,-1636.75 1827.5,-1622 1797.59,-1611.77 1788.89,-1609.1 1764.5,-1589 1744.73,-1572.71 1726.89,-1549.64 1714.76,-1532.04"/>
<polygon fill="#b2fe58" stroke="#b2fe58" points="1930.34,-1641.21 1935.82,-1650.71 1934.4,-1644.14 1938.45,-1647.06 1938.45,-1647.06 1938.45,-1647.06 1934.4,-1644.14 1941.08,-1643.41 1930.34,-1641.21 1930.34,-1641.21"/>
<polygon fill="#b2fe58" stroke="#b2fe58" points="1714.53,-1531.7 1712.69,-1520.88 1711.74,-1527.54 1708.95,-1523.39 1708.95,-1523.39 1708.95,-1523.39 1711.74,-1527.54 1705.22,-1525.9 1714.53,-1531.7 1714.53,-1531.7"/>
<text text-anchor="middle" x="1870.5" y="-1610.8" font-family="Times,serif" font-size="14.00">admin_contacts</text>
</g>
<!-- Epp::Nameserver -->
<g id="node33" class="node"><title>Epp::Nameserver</title>
<ellipse fill="none" stroke="black" cx="1846.5" cy="-1505.5" rx="72.5877" ry="18"/>
<text text-anchor="middle" x="1846.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::Nameserver</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Nameserver -->
<g id="edge12" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Nameserver</title>
<path fill="none" stroke="#182824" d="M1933.83,-1639.79C1907.07,-1598.95 1880.08,-1557.75 1863.33,-1532.19"/>
<ellipse fill="none" stroke="#182824" cx="1936.07" cy="-1643.2" rx="4.00002" ry="4.00002"/>
<polygon fill="#182824" stroke="#182824" points="1863.12,-1531.87 1861.41,-1521.04 1860.38,-1527.69 1857.64,-1523.51 1857.64,-1523.51 1857.64,-1523.51 1860.38,-1527.69 1853.88,-1525.97 1863.12,-1531.87 1863.12,-1531.87"/>
</g>
<!-- Epp::DomainStatus -->
<g id="node34" class="node"><title>Epp::DomainStatus</title>
<ellipse fill="none" stroke="black" cx="2017.5" cy="-1505.5" rx="79.8859" ry="18"/>
<text text-anchor="middle" x="2017.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::DomainStatus</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainStatus -->
<g id="edge13" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainStatus</title>
<path fill="none" stroke="#a5b2f7" d="M2017.5,-1632.37C2017.5,-1594.92 2017.5,-1557.97 2017.5,-1533.89"/>
<ellipse fill="none" stroke="#a5b2f7" cx="2017.5" cy="-1636.44" rx="4" ry="4"/>
<polygon fill="#a5b2f7" stroke="#a5b2f7" points="2017.5,-1533.78 2022,-1523.78 2017.5,-1528.78 2017.5,-1523.78 2017.5,-1523.78 2017.5,-1523.78 2017.5,-1528.78 2013,-1523.78 2017.5,-1533.78 2017.5,-1533.78"/>
</g>
<!-- Epp::DomainTransfer -->
<g id="node35" class="node"><title>Epp::DomainTransfer</title>
<ellipse fill="none" stroke="black" cx="2203.5" cy="-1505.5" rx="88.2844" ry="18"/>
<text text-anchor="middle" x="2203.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::DomainTransfer</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainTransfer -->
<g id="edge14" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainTransfer</title>
<path fill="none" stroke="#baf988" d="M2101.65,-1646.83C2103.28,-1644.53 2104.89,-1642.25 2106.5,-1640 2133.49,-1602.1 2165.28,-1558.55 2184.91,-1531.78"/>
<ellipse fill="none" stroke="#baf988" cx="2099.04" cy="-1650.5" rx="4.00002" ry="4.00002"/>
<polygon fill="#baf988" stroke="#baf988" points="2184.92,-1531.77 2194.47,-1526.37 2187.88,-1527.74 2190.84,-1523.71 2190.84,-1523.71 2190.84,-1523.71 2187.88,-1527.74 2187.21,-1521.04 2184.92,-1531.77 2184.92,-1531.77"/>
</g>
<!-- Epp::Dnskey -->
<g id="node36" class="node"><title>Epp::Dnskey</title>
<ellipse fill="none" stroke="black" cx="2366.5" cy="-1505.5" rx="56.59" ry="18"/>
<text text-anchor="middle" x="2366.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::Dnskey</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Dnskey -->
<g id="edge15" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Dnskey</title>
<path fill="none" stroke="#7ceff2" d="M2103.11,-1642.45C2104.23,-1641.61 2105.36,-1640.8 2106.5,-1640 2179.61,-1588.98 2225.76,-1637.6 2300.5,-1589 2322.47,-1574.71 2340.47,-1550.68 2352.09,-1532.23"/>
<ellipse fill="none" stroke="#7ceff2" cx="2099.93" cy="-1644.95" rx="4.00002" ry="4.00002"/>
<polygon fill="#7ceff2" stroke="#7ceff2" points="2352.24,-1531.98 2361.28,-1525.76 2354.84,-1527.7 2357.43,-1523.43 2357.43,-1523.43 2357.43,-1523.43 2354.84,-1527.7 2353.58,-1521.09 2352.24,-1531.98 2352.24,-1531.98"/>
</g>
<!-- Epp::Keyrelay -->
<g id="node37" class="node"><title>Epp::Keyrelay</title>
<ellipse fill="none" stroke="black" cx="2502.5" cy="-1505.5" rx="61.99" ry="18"/>
<text text-anchor="middle" x="2502.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::Keyrelay</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::Keyrelay -->
<g id="edge16" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::Keyrelay</title>
<path fill="none" stroke="#d875be" d="M2103.41,-1641.99C2104.43,-1641.31 2105.46,-1640.65 2106.5,-1640 2114.27,-1635.14 2424.51,-1593.48 2432.5,-1589 2456.15,-1575.73 2475.39,-1551.19 2487.67,-1532.31"/>
<ellipse fill="none" stroke="#d875be" cx="2100.07" cy="-1644.39" rx="4.00002" ry="4.00002"/>
<polygon fill="#d875be" stroke="#d875be" points="2487.83,-1532.05 2496.95,-1525.95 2490.48,-1527.81 2493.13,-1523.57 2493.13,-1523.57 2493.13,-1523.57 2490.48,-1527.81 2489.31,-1521.19 2487.83,-1532.05 2487.83,-1532.05"/>
</g>
<!-- Epp::DomainVersion -->
<g id="node38" class="node"><title>Epp::DomainVersion</title>
<ellipse fill="none" stroke="black" cx="2668.5" cy="-1505.5" rx="86.3847" ry="18"/>
<text text-anchor="middle" x="2668.5" y="-1501.8" font-family="Times,serif" font-size="14.00">Epp::DomainVersion</text>
</g>
<!-- Epp::EppDomain&#45;&gt;Epp::DomainVersion -->
<g id="edge17" class="edge"><title>Epp::EppDomain&#45;&gt;Epp::DomainVersion</title>
<path fill="none" stroke="#fdbc02" d="M2103.37,-1641.91C2104.4,-1641.26 2105.45,-1640.62 2106.5,-1640 2140.39,-1620.07 2243.41,-1626.22 2282.5,-1622 2411.91,-1608.04 2454.33,-1641.36 2573.5,-1589 2603.21,-1575.95 2630.42,-1550.27 2648.04,-1531.01"/>
<ellipse fill="none" stroke="#fdbc02" cx="2099.97" cy="-1644.23" rx="4.00002" ry="4.00002"/>
<polygon fill="#fdbc02" stroke="#fdbc02" points="2648.1,-1530.93 2658.11,-1526.45 2651.43,-1527.2 2654.75,-1523.46 2654.75,-1523.46 2654.75,-1523.46 2651.43,-1527.2 2651.39,-1520.47 2648.1,-1530.93 2648.1,-1530.93"/>
<text text-anchor="middle" x="2544.5" y="-1610.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Message -->
<g id="node17" class="node"><title>Message</title>
<path fill="none" stroke="black" d="M951.5,-1173.5C951.5,-1173.5 1081.5,-1173.5 1081.5,-1173.5 1087.5,-1173.5 1093.5,-1179.5 1093.5,-1185.5 1093.5,-1185.5 1093.5,-1312.5 1093.5,-1312.5 1093.5,-1318.5 1087.5,-1324.5 1081.5,-1324.5 1081.5,-1324.5 951.5,-1324.5 951.5,-1324.5 945.5,-1324.5 939.5,-1318.5 939.5,-1312.5 939.5,-1312.5 939.5,-1185.5 939.5,-1185.5 939.5,-1179.5 945.5,-1173.5 951.5,-1173.5"/>
<text text-anchor="middle" x="1016.5" y="-1309.3" font-family="Times,serif" font-size="14.00">Message</text>
<polyline fill="none" stroke="black" points="939.5,-1301.5 1093.5,-1301.5 "/>
<text text-anchor="start" x="947.5" y="-1286.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="947.5" y="-1271.3" font-family="Times,serif" font-size="14.00">registrar_id :integer</text>
<text text-anchor="start" x="947.5" y="-1256.3" font-family="Times,serif" font-size="14.00">body :string</text>
<text text-anchor="start" x="947.5" y="-1241.3" font-family="Times,serif" font-size="14.00">attached_obj_type :string</text>
<text text-anchor="start" x="947.5" y="-1226.3" font-family="Times,serif" font-size="14.00">attached_obj_id :string</text>
<text text-anchor="start" x="947.5" y="-1211.3" font-family="Times,serif" font-size="14.00">queued :boolean</text>
<text text-anchor="start" x="947.5" y="-1196.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="947.5" y="-1181.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- EppSession -->
<g id="node18" class="node"><title>EppSession</title>
<path fill="none" stroke="black" d="M2127,-1715.5C2127,-1715.5 2234,-1715.5 2234,-1715.5 2240,-1715.5 2246,-1721.5 2246,-1727.5 2246,-1727.5 2246,-1809.5 2246,-1809.5 2246,-1815.5 2240,-1821.5 2234,-1821.5 2234,-1821.5 2127,-1821.5 2127,-1821.5 2121,-1821.5 2115,-1815.5 2115,-1809.5 2115,-1809.5 2115,-1727.5 2115,-1727.5 2115,-1721.5 2121,-1715.5 2127,-1715.5"/>
<text text-anchor="middle" x="2180.5" y="-1806.3" font-family="Times,serif" font-size="14.00">EppSession</text>
<polyline fill="none" stroke="black" points="2115,-1798.5 2246,-1798.5 "/>
<text text-anchor="start" x="2123" y="-1783.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="2123" y="-1768.3" font-family="Times,serif" font-size="14.00">session_id :string</text>
<text text-anchor="start" x="2123" y="-1753.3" font-family="Times,serif" font-size="14.00">data :text</text>
<text text-anchor="start" x="2123" y="-1738.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="2123" y="-1723.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- AddressVersion -->
<g id="node19" class="node"><title>AddressVersion</title>
<path fill="none" stroke="black" d="M1354,-241C1354,-241 1457,-241 1457,-241 1463,-241 1469,-247 1469,-253 1469,-253 1469,-365 1469,-365 1469,-371 1463,-377 1457,-377 1457,-377 1354,-377 1354,-377 1348,-377 1342,-371 1342,-365 1342,-365 1342,-253 1342,-253 1342,-247 1348,-241 1354,-241"/>
<text text-anchor="middle" x="1405.5" y="-361.8" font-family="Times,serif" font-size="14.00">AddressVersion</text>
<polyline fill="none" stroke="black" points="1342,-354 1469,-354 "/>
<text text-anchor="start" x="1350" y="-338.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1350" y="-323.8" font-family="Times,serif" font-size="14.00">item_type :string</text>
<text text-anchor="start" x="1350" y="-308.8" font-family="Times,serif" font-size="14.00">item_id :integer</text>
<text text-anchor="start" x="1350" y="-293.8" font-family="Times,serif" font-size="14.00">event :string</text>
<text text-anchor="start" x="1350" y="-278.8" font-family="Times,serif" font-size="14.00">whodunnit :string</text>
<text text-anchor="start" x="1350" y="-263.8" font-family="Times,serif" font-size="14.00">object :text</text>
<text text-anchor="start" x="1350" y="-248.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
</g>
<!-- Keyrelay -->
<g id="node21" class="node"><title>Keyrelay</title>
<path fill="none" stroke="black" d="M161.5,-188.5C161.5,-188.5 297.5,-188.5 297.5,-188.5 303.5,-188.5 309.5,-194.5 309.5,-200.5 309.5,-200.5 309.5,-417.5 309.5,-417.5 309.5,-423.5 303.5,-429.5 297.5,-429.5 297.5,-429.5 161.5,-429.5 161.5,-429.5 155.5,-429.5 149.5,-423.5 149.5,-417.5 149.5,-417.5 149.5,-200.5 149.5,-200.5 149.5,-194.5 155.5,-188.5 161.5,-188.5"/>
<text text-anchor="middle" x="229.5" y="-414.3" font-family="Times,serif" font-size="14.00">Keyrelay</text>
<polyline fill="none" stroke="black" points="149.5,-406.5 309.5,-406.5 "/>
<text text-anchor="start" x="157.5" y="-391.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="157.5" y="-376.3" font-family="Times,serif" font-size="14.00">domain_id :integer</text>
<text text-anchor="start" x="157.5" y="-361.3" font-family="Times,serif" font-size="14.00">pa_date :datetime</text>
<text text-anchor="start" x="157.5" y="-346.3" font-family="Times,serif" font-size="14.00">key_data_flags :string</text>
<text text-anchor="start" x="157.5" y="-331.3" font-family="Times,serif" font-size="14.00">key_data_protocol :string</text>
<text text-anchor="start" x="157.5" y="-316.3" font-family="Times,serif" font-size="14.00">key_data_alg :string</text>
<text text-anchor="start" x="157.5" y="-301.3" font-family="Times,serif" font-size="14.00">key_data_public_key :text</text>
<text text-anchor="start" x="157.5" y="-286.3" font-family="Times,serif" font-size="14.00">auth_info_pw :string</text>
<text text-anchor="start" x="157.5" y="-271.3" font-family="Times,serif" font-size="14.00">expiry_relative :string</text>
<text text-anchor="start" x="157.5" y="-256.3" font-family="Times,serif" font-size="14.00">expiry_absolute :datetime</text>
<text text-anchor="start" x="157.5" y="-241.3" font-family="Times,serif" font-size="14.00">requester_id :integer</text>
<text text-anchor="start" x="157.5" y="-226.3" font-family="Times,serif" font-size="14.00">accepter_id :integer</text>
<text text-anchor="start" x="157.5" y="-211.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="157.5" y="-196.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- ReservedDomain -->
<g id="node22" class="node"><title>ReservedDomain</title>
<path fill="none" stroke="black" d="M2276,-1723C2276,-1723 2383,-1723 2383,-1723 2389,-1723 2395,-1729 2395,-1735 2395,-1735 2395,-1802 2395,-1802 2395,-1808 2389,-1814 2383,-1814 2383,-1814 2276,-1814 2276,-1814 2270,-1814 2264,-1808 2264,-1802 2264,-1802 2264,-1735 2264,-1735 2264,-1729 2270,-1723 2276,-1723"/>
<text text-anchor="middle" x="2329.5" y="-1798.8" font-family="Times,serif" font-size="14.00">ReservedDomain</text>
<polyline fill="none" stroke="black" points="2264,-1791 2395,-1791 "/>
<text text-anchor="start" x="2272" y="-1775.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="2272" y="-1760.8" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="2272" y="-1745.8" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="2272" y="-1730.8" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- Registrar -->
<g id="node23" class="node"><title>Registrar</title>
<path fill="none" stroke="black" d="M960,-1422.5C960,-1422.5 1073,-1422.5 1073,-1422.5 1079,-1422.5 1085,-1428.5 1085,-1434.5 1085,-1434.5 1085,-1576.5 1085,-1576.5 1085,-1582.5 1079,-1588.5 1073,-1588.5 1073,-1588.5 960,-1588.5 960,-1588.5 954,-1588.5 948,-1582.5 948,-1576.5 948,-1576.5 948,-1434.5 948,-1434.5 948,-1428.5 954,-1422.5 960,-1422.5"/>
<text text-anchor="middle" x="1016.5" y="-1573.3" font-family="Times,serif" font-size="14.00">Registrar</text>
<polyline fill="none" stroke="black" points="948,-1565.5 1085,-1565.5 "/>
<text text-anchor="start" x="956" y="-1550.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="956" y="-1535.3" font-family="Times,serif" font-size="14.00">name :string</text>
<text text-anchor="start" x="956" y="-1520.3" font-family="Times,serif" font-size="14.00">reg_no :string</text>
<text text-anchor="start" x="956" y="-1505.3" font-family="Times,serif" font-size="14.00">vat_no :string</text>
<text text-anchor="start" x="956" y="-1490.3" font-family="Times,serif" font-size="14.00">address :string</text>
<text text-anchor="start" x="956" y="-1475.3" font-family="Times,serif" font-size="14.00">country_id :integer</text>
<text text-anchor="start" x="956" y="-1460.3" font-family="Times,serif" font-size="14.00">billing_address :string</text>
<text text-anchor="start" x="956" y="-1445.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="956" y="-1430.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
</g>
<!-- Registrar&#45;&gt;Contact -->
<g id="edge19" class="edge"><title>Registrar&#45;&gt;Contact</title>
<path fill="none" stroke="#6448d9" d="M1089.16,-1415.46C1094.54,-1405.61 1099.15,-1395.38 1102.5,-1385 1139.6,-1269.94 1129.01,-1230.95 1102.5,-1113 1099.8,-1100.99 1096.2,-1088.84 1092,-1076.81"/>
<ellipse fill="none" stroke="#6448d9" cx="1087.1" cy="-1419.09" rx="4.00002" ry="4.00002"/>
<polygon fill="#6448d9" stroke="#6448d9" points="1091.93,-1076.61 1092.74,-1065.67 1090.22,-1071.91 1088.51,-1067.21 1088.51,-1067.21 1088.51,-1067.21 1090.22,-1071.91 1084.28,-1068.74 1091.93,-1076.61 1091.93,-1076.61"/>
</g>
<!-- Registrar&#45;&gt;EppUser -->
<g id="edge20" class="edge"><title>Registrar&#45;&gt;EppUser</title>
<path fill="none" stroke="#7596d4" d="M950.893,-1415.73C943.837,-1405.48 936.904,-1395.09 930.5,-1385 921.614,-1371 912.643,-1355.88 904.147,-1341"/>
<ellipse fill="none" stroke="#7596d4" cx="953.264" cy="-1419.15" rx="4.00002" ry="4.00002"/>
<polygon fill="#7596d4" stroke="#7596d4" points="904.135,-1340.98 903.119,-1330.06 901.669,-1336.63 899.204,-1332.28 899.204,-1332.28 899.204,-1332.28 901.669,-1336.63 895.289,-1334.5 904.135,-1340.98 904.135,-1340.98"/>
</g>
<!-- Registrar&#45;&gt;Message -->
<g id="edge22" class="edge"><title>Registrar&#45;&gt;Message</title>
<path fill="none" stroke="#ecee2a" d="M1016.5,-1414.05C1016.5,-1388.32 1016.5,-1360.4 1016.5,-1335.01"/>
<ellipse fill="none" stroke="#ecee2a" cx="1016.5" cy="-1418.22" rx="4" ry="4"/>
<polygon fill="#ecee2a" stroke="#ecee2a" points="1016.5,-1334.68 1021,-1324.68 1016.5,-1329.68 1016.5,-1324.68 1016.5,-1324.68 1016.5,-1324.68 1016.5,-1329.68 1012,-1324.68 1016.5,-1334.68 1016.5,-1334.68"/>
</g>
<!-- User -->
<g id="node24" class="node"><title>User</title>
<path fill="none" stroke="black" d="M1162,-1113.5C1162,-1113.5 1311,-1113.5 1311,-1113.5 1317,-1113.5 1323,-1119.5 1323,-1125.5 1323,-1125.5 1323,-1372.5 1323,-1372.5 1323,-1378.5 1317,-1384.5 1311,-1384.5 1311,-1384.5 1162,-1384.5 1162,-1384.5 1156,-1384.5 1150,-1378.5 1150,-1372.5 1150,-1372.5 1150,-1125.5 1150,-1125.5 1150,-1119.5 1156,-1113.5 1162,-1113.5"/>
<text text-anchor="middle" x="1236.5" y="-1369.3" font-family="Times,serif" font-size="14.00">User</text>
<polyline fill="none" stroke="black" points="1150,-1361.5 1323,-1361.5 "/>
<text text-anchor="start" x="1158" y="-1346.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="1158" y="-1331.3" font-family="Times,serif" font-size="14.00">username :string</text>
<text text-anchor="start" x="1158" y="-1316.3" font-family="Times,serif" font-size="14.00">password :string</text>
<text text-anchor="start" x="1158" y="-1301.3" font-family="Times,serif" font-size="14.00">role_id :integer</text>
<text text-anchor="start" x="1158" y="-1286.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="1158" y="-1271.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="1158" y="-1256.3" font-family="Times,serif" font-size="14.00">email :string</text>
<text text-anchor="start" x="1158" y="-1241.3" font-family="Times,serif" font-size="14.00">sign_in_count :integer</text>
<text text-anchor="start" x="1158" y="-1226.3" font-family="Times,serif" font-size="14.00">current_sign_in_at :datetime</text>
<text text-anchor="start" x="1158" y="-1211.3" font-family="Times,serif" font-size="14.00">last_sign_in_at :datetime</text>
<text text-anchor="start" x="1158" y="-1196.3" font-family="Times,serif" font-size="14.00">current_sign_in_ip :inet</text>
<text text-anchor="start" x="1158" y="-1181.3" font-family="Times,serif" font-size="14.00">last_sign_in_ip :inet</text>
<text text-anchor="start" x="1158" y="-1166.3" font-family="Times,serif" font-size="14.00">admin :boolean</text>
<text text-anchor="start" x="1158" y="-1151.3" font-family="Times,serif" font-size="14.00">identity_code :string</text>
<text text-anchor="start" x="1158" y="-1136.3" font-family="Times,serif" font-size="14.00">registrar_id :integer</text>
<text text-anchor="start" x="1158" y="-1121.3" font-family="Times,serif" font-size="14.00">country_id :integer</text>
</g>
<!-- Registrar&#45;&gt;User -->
<g id="edge21" class="edge"><title>Registrar&#45;&gt;User</title>
<path fill="none" stroke="#163d67" d="M1091.2,-1447.13C1106.62,-1433.76 1122.2,-1419.01 1135.5,-1404 1138.71,-1400.38 1141.89,-1396.64 1145.04,-1392.82"/>
<ellipse fill="none" stroke="#163d67" cx="1088.11" cy="-1449.78" rx="4.00002" ry="4.00002"/>
<polygon fill="#163d67" stroke="#163d67" points="1145.18,-1392.66 1154.96,-1387.7 1148.32,-1388.77 1151.46,-1384.88 1151.46,-1384.88 1151.46,-1384.88 1148.32,-1388.77 1147.95,-1382.05 1145.18,-1392.66 1145.18,-1392.66"/>
</g>
<!-- Registrar&#45;&gt;Domain -->
<g id="edge18" class="edge"><title>Registrar&#45;&gt;Domain</title>
<path fill="none" stroke="#f9eadf" d="M939.757,-1488.06C884.928,-1471.87 814.992,-1441.13 780.5,-1385 660.651,-1189.98 702.849,-911.846 744.575,-747.375"/>
<ellipse fill="none" stroke="#f9eadf" cx="943.885" cy="-1489.24" rx="4.00001" ry="4.00001"/>
<polygon fill="#f9eadf" stroke="#f9eadf" points="744.577,-747.368 751.425,-738.804 745.822,-742.526 747.067,-737.683 747.067,-737.683 747.067,-737.683 745.822,-742.526 742.708,-736.563 744.577,-747.368 744.577,-747.368"/>
</g>
<!-- Role&#45;&gt;User -->
<g id="edge23" class="edge"><title>Role&#45;&gt;User</title>
<path fill="none" stroke="#d471c1" d="M1236.5,-1451.64C1236.5,-1434.65 1236.5,-1414.93 1236.5,-1394.61"/>
<ellipse fill="none" stroke="#d471c1" cx="1236.5" cy="-1455.88" rx="4" ry="4"/>
<polygon fill="#d471c1" stroke="#d471c1" points="1236.5,-1394.6 1241,-1384.6 1236.5,-1389.6 1236.5,-1384.6 1236.5,-1384.6 1236.5,-1384.6 1236.5,-1389.6 1232,-1384.6 1236.5,-1394.6 1236.5,-1394.6"/>
</g>
<!-- Address&#45;&gt;AddressVersion -->
<g id="edge24" class="edge"><title>Address&#45;&gt;AddressVersion</title>
<path fill="none" stroke="#17d730" d="M1405.5,-510.854C1405.5,-470.863 1405.5,-425.236 1405.5,-387.586"/>
<ellipse fill="none" stroke="#17d730" cx="1405.5" cy="-514.94" rx="4" ry="4"/>
<polygon fill="#17d730" stroke="#17d730" points="1405.5,-387.19 1410,-377.19 1405.5,-382.19 1405.5,-377.19 1405.5,-377.19 1405.5,-377.19 1405.5,-382.19 1401,-377.19 1405.5,-387.19 1405.5,-387.19"/>
<text text-anchor="middle" x="1428.5" y="-451.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Domain&#45;&gt;DomainContact -->
<g id="edge25" class="edge"><title>Domain&#45;&gt;DomainContact</title>
<path fill="none" stroke="#7c1bfd" d="M872.037,-547.693C913.877,-515.523 963.314,-473.693 1001.5,-430 1015.19,-414.341 1028.02,-395.918 1039.07,-378.27"/>
<ellipse fill="none" stroke="#7c1bfd" cx="868.835" cy="-550.141" rx="4.00002" ry="4.00002"/>
<polygon fill="#7c1bfd" stroke="#7c1bfd" points="1039.11,-378.203 1048.18,-372.041 1041.73,-373.944 1044.35,-369.684 1044.35,-369.684 1044.35,-369.684 1041.73,-373.944 1040.52,-367.328 1039.11,-378.203 1039.11,-378.203"/>
</g>
<!-- Domain&#45;&gt;Contact -->
<g id="edge26" class="edge"><title>Domain&#45;&gt;Contact</title>
<path fill="none" stroke="#82fe6f" d="M808.506,-747.141C811.947,-755.461 815.918,-763.492 820.5,-771 849.203,-818.032 896.789,-857.374 938.001,-885.336"/>
<polygon fill="#82fe6f" stroke="#82fe6f" points="808.439,-746.968 809.04,-736.018 806.641,-742.303 804.842,-737.637 804.842,-737.637 804.842,-737.637 806.641,-742.303 800.643,-739.256 808.439,-746.968 808.439,-746.968"/>
<polygon fill="#82fe6f" stroke="#82fe6f" points="938.101,-885.403 943.923,-894.696 942.26,-888.178 946.42,-890.952 946.42,-890.952 946.42,-890.952 942.26,-888.178 948.917,-887.209 938.101,-885.403 938.101,-885.403"/>
<text text-anchor="middle" x="857.5" y="-759.8" font-family="Times,serif" font-size="14.00">tech_contacts</text>
</g>
<!-- Domain&#45;&gt;Contact -->
<g id="edge27" class="edge"><title>Domain&#45;&gt;Contact</title>
<path fill="none" stroke="#f74388" d="M871.55,-724.465C879.347,-735.098 887.094,-745.733 894.5,-756 909.555,-776.87 925.453,-799.274 940.64,-820.859"/>
<polygon fill="#f74388" stroke="#f74388" points="871.503,-724.4 869.21,-713.677 868.543,-720.371 865.583,-716.341 865.583,-716.341 865.583,-716.341 868.543,-720.371 861.956,-719.005 871.503,-724.4 871.503,-724.4"/>
<polygon fill="#f74388" stroke="#f74388" points="940.673,-820.905 942.741,-831.674 943.548,-824.995 946.423,-829.086 946.423,-829.086 946.423,-829.086 943.548,-824.995 950.104,-826.499 940.673,-820.905 940.673,-820.905"/>
<text text-anchor="middle" x="948.5" y="-759.8" font-family="Times,serif" font-size="14.00">admin_contacts</text>
</g>
<!-- Domain&#45;&gt;DomainVersion -->
<g id="edge33" class="edge"><title>Domain&#45;&gt;DomainVersion</title>
<path fill="none" stroke="#9b111b" d="M850.883,-474.106C863.993,-446.741 877.425,-418.703 889.392,-393.721"/>
<ellipse fill="none" stroke="#9b111b" cx="849.08" cy="-477.869" rx="4.00002" ry="4.00002"/>
<polygon fill="#9b111b" stroke="#9b111b" points="889.412,-393.681 897.79,-386.607 891.572,-389.172 893.732,-384.662 893.732,-384.662 893.732,-384.662 891.572,-389.172 889.674,-382.718 889.412,-393.681 889.412,-393.681"/>
<text text-anchor="middle" x="885.5" y="-451.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
<!-- Domain&#45;&gt;Nameserver -->
<g id="edge28" class="edge"><title>Domain&#45;&gt;Nameserver</title>
<path fill="none" stroke="#6ee754" d="M699.265,-604.193C566.349,-593.594 310.646,-556.917 140.5,-430 124.821,-418.304 111.639,-402.276 100.919,-385.741"/>
<ellipse fill="none" stroke="#6ee754" cx="703.462" cy="-604.517" rx="4" ry="4"/>
<polygon fill="#6ee754" stroke="#6ee754" points="100.81,-385.565 99.3609,-374.696 98.1738,-381.317 95.5373,-377.068 95.5373,-377.068 95.5373,-377.068 98.1738,-381.317 91.7137,-379.441 100.81,-385.565 100.81,-385.565"/>
</g>
<!-- Domain&#45;&gt;Keyrelay -->
<g id="edge32" class="edge"><title>Domain&#45;&gt;Keyrelay</title>
<path fill="none" stroke="#dea5bb" d="M699.371,-590.882C599.525,-567.367 434.73,-518.087 318.5,-430 318.219,-429.787 317.938,-429.573 317.658,-429.358"/>
<ellipse fill="none" stroke="#dea5bb" cx="703.442" cy="-591.829" rx="4.00001" ry="4.00001"/>
<polygon fill="#dea5bb" stroke="#dea5bb" points="317.413,-429.157 312.523,-419.341 313.543,-425.99 309.673,-422.824 309.673,-422.824 309.673,-422.824 313.543,-425.99 306.824,-426.307 317.413,-429.157 317.413,-429.157"/>
</g>
<!-- Dnskey -->
<g id="node28" class="node"><title>Dnskey</title>
<path fill="none" stroke="black" d="M340,-211C340,-211 491,-211 491,-211 497,-211 503,-217 503,-223 503,-223 503,-395 503,-395 503,-401 497,-407 491,-407 491,-407 340,-407 340,-407 334,-407 328,-401 328,-395 328,-395 328,-223 328,-223 328,-217 334,-211 340,-211"/>
<text text-anchor="middle" x="415.5" y="-391.8" font-family="Times,serif" font-size="14.00">Dnskey</text>
<polyline fill="none" stroke="black" points="328,-384 503,-384 "/>
<text text-anchor="start" x="336" y="-368.8" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="336" y="-353.8" font-family="Times,serif" font-size="14.00">domain_id :integer</text>
<text text-anchor="start" x="336" y="-338.8" font-family="Times,serif" font-size="14.00">flags :integer</text>
<text text-anchor="start" x="336" y="-323.8" font-family="Times,serif" font-size="14.00">protocol :integer</text>
<text text-anchor="start" x="336" y="-308.8" font-family="Times,serif" font-size="14.00">alg :integer</text>
<text text-anchor="start" x="336" y="-293.8" font-family="Times,serif" font-size="14.00">public_key :text</text>
<text text-anchor="start" x="336" y="-278.8" font-family="Times,serif" font-size="14.00">delegation_signer_id :integer</text>
<text text-anchor="start" x="336" y="-263.8" font-family="Times,serif" font-size="14.00">ds_key_tag :string</text>
<text text-anchor="start" x="336" y="-248.8" font-family="Times,serif" font-size="14.00">ds_alg :integer</text>
<text text-anchor="start" x="336" y="-233.8" font-family="Times,serif" font-size="14.00">ds_digest_type :integer</text>
<text text-anchor="start" x="336" y="-218.8" font-family="Times,serif" font-size="14.00">ds_digest :string</text>
</g>
<!-- Domain&#45;&gt;Dnskey -->
<g id="edge31" class="edge"><title>Domain&#45;&gt;Dnskey</title>
<path fill="none" stroke="#20855b" d="M700.33,-561.834C643.758,-528.997 569.894,-481.798 512.5,-430 507.099,-425.126 501.753,-419.936 496.51,-414.551"/>
<ellipse fill="none" stroke="#20855b" cx="704.027" cy="-563.968" rx="4.00002" ry="4.00002"/>
<polygon fill="#20855b" stroke="#20855b" points="496.318,-414.349 492.692,-404 492.874,-410.724 489.43,-407.099 489.43,-407.099 489.43,-407.099 492.874,-410.724 486.168,-410.199 496.318,-414.349 496.318,-414.349"/>
</g>
<!-- DomainTransfer -->
<g id="node29" class="node"><title>DomainTransfer</title>
<path fill="none" stroke="black" d="M533.5,-218.5C533.5,-218.5 697.5,-218.5 697.5,-218.5 703.5,-218.5 709.5,-224.5 709.5,-230.5 709.5,-230.5 709.5,-387.5 709.5,-387.5 709.5,-393.5 703.5,-399.5 697.5,-399.5 697.5,-399.5 533.5,-399.5 533.5,-399.5 527.5,-399.5 521.5,-393.5 521.5,-387.5 521.5,-387.5 521.5,-230.5 521.5,-230.5 521.5,-224.5 527.5,-218.5 533.5,-218.5"/>
<text text-anchor="middle" x="615.5" y="-384.3" font-family="Times,serif" font-size="14.00">DomainTransfer</text>
<polyline fill="none" stroke="black" points="521.5,-376.5 709.5,-376.5 "/>
<text text-anchor="start" x="529.5" y="-361.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="529.5" y="-346.3" font-family="Times,serif" font-size="14.00">domain_id :integer</text>
<text text-anchor="start" x="529.5" y="-331.3" font-family="Times,serif" font-size="14.00">status :string</text>
<text text-anchor="start" x="529.5" y="-316.3" font-family="Times,serif" font-size="14.00">transfer_requested_at :datetime</text>
<text text-anchor="start" x="529.5" y="-301.3" font-family="Times,serif" font-size="14.00">transferred_at :datetime</text>
<text text-anchor="start" x="529.5" y="-286.3" font-family="Times,serif" font-size="14.00">transfer_from_id :integer</text>
<text text-anchor="start" x="529.5" y="-271.3" font-family="Times,serif" font-size="14.00">transfer_to_id :integer</text>
<text text-anchor="start" x="529.5" y="-256.3" font-family="Times,serif" font-size="14.00">created_at :datetime</text>
<text text-anchor="start" x="529.5" y="-241.3" font-family="Times,serif" font-size="14.00">updated_at :datetime</text>
<text text-anchor="start" x="529.5" y="-226.3" font-family="Times,serif" font-size="14.00">wait_until :datetime</text>
</g>
<!-- Domain&#45;&gt;DomainTransfer -->
<g id="edge30" class="edge"><title>Domain&#45;&gt;DomainTransfer</title>
<path fill="none" stroke="#bdb231" d="M709.667,-474.379C697.021,-452.304 684.12,-429.784 672.085,-408.776"/>
<ellipse fill="none" stroke="#bdb231" cx="711.744" cy="-478.005" rx="4.00002" ry="4.00002"/>
<polygon fill="#bdb231" stroke="#bdb231" points="671.954,-408.548 670.888,-397.634 669.469,-404.209 666.984,-399.871 666.984,-399.871 666.984,-399.871 669.469,-404.209 663.079,-402.107 671.954,-408.548 671.954,-408.548"/>
</g>
<!-- DomainStatus -->
<g id="node30" class="node"><title>DomainStatus</title>
<path fill="none" stroke="black" d="M739.5,-263.5C739.5,-263.5 835.5,-263.5 835.5,-263.5 841.5,-263.5 847.5,-269.5 847.5,-275.5 847.5,-275.5 847.5,-342.5 847.5,-342.5 847.5,-348.5 841.5,-354.5 835.5,-354.5 835.5,-354.5 739.5,-354.5 739.5,-354.5 733.5,-354.5 727.5,-348.5 727.5,-342.5 727.5,-342.5 727.5,-275.5 727.5,-275.5 727.5,-269.5 733.5,-263.5 739.5,-263.5"/>
<text text-anchor="middle" x="787.5" y="-339.3" font-family="Times,serif" font-size="14.00">DomainStatus</text>
<polyline fill="none" stroke="black" points="727.5,-331.5 847.5,-331.5 "/>
<text text-anchor="start" x="735.5" y="-316.3" font-family="Times,serif" font-size="14.00">id :integer</text>
<text text-anchor="start" x="735.5" y="-301.3" font-family="Times,serif" font-size="14.00">domain_id :integer</text>
<text text-anchor="start" x="735.5" y="-286.3" font-family="Times,serif" font-size="14.00">description :string</text>
<text text-anchor="start" x="735.5" y="-271.3" font-family="Times,serif" font-size="14.00">value :string</text>
</g>
<!-- Domain&#45;&gt;DomainStatus -->
<g id="edge29" class="edge"><title>Domain&#45;&gt;DomainStatus</title>
<path fill="none" stroke="#602509" d="M786.953,-473.235C787.082,-434.833 787.215,-395.184 787.317,-364.58"/>
<ellipse fill="none" stroke="#602509" cx="786.939" cy="-477.476" rx="4" ry="4"/>
<polygon fill="#602509" stroke="#602509" points="787.317,-364.563 791.851,-354.578 787.334,-359.563 787.351,-354.563 787.351,-354.563 787.351,-354.563 787.334,-359.563 782.851,-354.548 787.317,-364.563 787.317,-364.563"/>
</g>
<!-- DomainStatus&#45;&gt;DomainStatusVersion -->
<g id="edge34" class="edge"><title>DomainStatus&#45;&gt;DomainStatusVersion</title>
<path fill="none" stroke="#5f5f07" d="M787.5,-255.259C787.5,-223.525 787.5,-182.553 787.5,-147.165"/>
<ellipse fill="none" stroke="#5f5f07" cx="787.5" cy="-259.42" rx="4" ry="4"/>
<polygon fill="#5f5f07" stroke="#5f5f07" points="787.5,-146.863 792,-136.863 787.5,-141.863 787.5,-136.863 787.5,-136.863 787.5,-136.863 787.5,-141.863 783,-136.863 787.5,-146.863 787.5,-146.863"/>
<text text-anchor="middle" x="810.5" y="-158.8" font-family="Times,serif" font-size="14.00">versions</text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 68 KiB

View file

@ -22,6 +22,12 @@ if Rails.env.test? || Rails.env.development?
t.rspec_opts = '--tag ~feature' t.rspec_opts = '--tag ~feature'
end end
desc 'Generate EPP doc from specs'
RSpec::Core::RakeTask.new('test:epp_doc') do |t|
ENV['EPP_DOC'] = 'true'
t.rspec_opts = '--tag epp --require support/epp_doc.rb --format EppDoc'
end
Rake::Task[:default].prerequisites.clear Rake::Task[:default].prerequisites.clear
task default: :test task default: :test

View file

@ -14,7 +14,7 @@ describe 'EPP Contact', epp: true do
let(:server_zone) { Epp::Server.new({ server: 'localhost', tag: 'zone', password: 'ghyt9e4fu', port: 701 }) } let(:server_zone) { Epp::Server.new({ server: 'localhost', tag: 'zone', password: 'ghyt9e4fu', port: 701 }) }
let(:server_elkdata) { Epp::Server.new({ server: 'localhost', tag: 'elkdata', password: 'ghyt9e4fu', port: 701 }) } let(:server_elkdata) { Epp::Server.new({ server: 'localhost', tag: 'elkdata', password: 'ghyt9e4fu', port: 701 }) }
let(:elkdata) { Fabricate(:registrar, { name: 'Elkdata', reg_no: '123' }) } let(:elkdata) { Fabricate(:registrar, { name: 'Elkdata', reg_no: '123' }) }
let(:zone) { Registrar.where(reg_no: '10577829').first || Fabricate(:registrar) } let(:zone) { Registrar.where(reg_no: '12345678').first || Fabricate(:registrar) }
context 'with valid user' do context 'with valid user' do
before(:each) do before(:each) do

View file

@ -66,7 +66,7 @@ describe 'EPP Domain', epp: true do
expect(trn_data.css('trStatus').text).to eq('serverApproved') expect(trn_data.css('trStatus').text).to eq('serverApproved')
expect(trn_data.css('reID').text).to eq('123') expect(trn_data.css('reID').text).to eq('123')
expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s) expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s)
expect(trn_data.css('acID').text).to eq('10577829') expect(trn_data.css('acID').text).to eq('12345678')
expect(trn_data.css('acDate').text).to eq(dtl.transferred_at.to_time.utc.to_s) expect(trn_data.css('acDate').text).to eq(dtl.transferred_at.to_time.utc.to_s)
expect(trn_data.css('exDate').text).to eq(domain.valid_to.to_time.utc.to_s) expect(trn_data.css('exDate').text).to eq(domain.valid_to.to_time.utc.to_s)
@ -88,7 +88,7 @@ describe 'EPP Domain', epp: true do
expect(trn_data.css('name').text).to eq('example.ee') expect(trn_data.css('name').text).to eq('example.ee')
expect(trn_data.css('trStatus').text).to eq('pending') expect(trn_data.css('trStatus').text).to eq('pending')
expect(trn_data.css('reID').text).to eq('10577829') expect(trn_data.css('reID').text).to eq('12345678')
expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s) expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s)
expect(trn_data.css('acDate').text).to eq(dtl.wait_until.to_time.utc.to_s) expect(trn_data.css('acDate').text).to eq(dtl.wait_until.to_time.utc.to_s)
expect(trn_data.css('acID').text).to eq('123') expect(trn_data.css('acID').text).to eq('123')
@ -103,7 +103,7 @@ describe 'EPP Domain', epp: true do
expect(domain.domain_transfers.count).to eq(2) expect(domain.domain_transfers.count).to eq(2)
expect(trn_data.css('name').text).to eq('example.ee') expect(trn_data.css('name').text).to eq('example.ee')
expect(trn_data.css('trStatus').text).to eq('pending') expect(trn_data.css('trStatus').text).to eq('pending')
expect(trn_data.css('reID').text).to eq('10577829') expect(trn_data.css('reID').text).to eq('12345678')
expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s) expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s)
expect(trn_data.css('acDate').text).to eq(dtl.wait_until.to_time.utc.to_s) expect(trn_data.css('acDate').text).to eq(dtl.wait_until.to_time.utc.to_s)
expect(trn_data.css('acID').text).to eq('123') expect(trn_data.css('acID').text).to eq('123')
@ -165,7 +165,7 @@ describe 'EPP Domain', epp: true do
expect(trn_data.css('trStatus').text).to eq('clientApproved') expect(trn_data.css('trStatus').text).to eq('clientApproved')
expect(trn_data.css('reID').text).to eq('123') expect(trn_data.css('reID').text).to eq('123')
expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s) expect(trn_data.css('reDate').text).to eq(dtl.transfer_requested_at.to_time.utc.to_s)
expect(trn_data.css('acID').text).to eq('10577829') expect(trn_data.css('acID').text).to eq('12345678')
expect(trn_data.css('exDate').text).to eq(domain.valid_to.to_time.utc.to_s) expect(trn_data.css('exDate').text).to eq(domain.valid_to.to_time.utc.to_s)
end end
@ -223,7 +223,7 @@ describe 'EPP Domain', epp: true do
expect(response[:clTRID]).to eq('ABC-12345') expect(response[:clTRID]).to eq('ABC-12345')
expect(d.registrar.name).to eq('Zone Media OÜ') expect(d.registrar.name).to eq('Registrar OÜ')
expect(d.tech_contacts.count).to eq 2 expect(d.tech_contacts.count).to eq 2
expect(d.admin_contacts.count).to eq 1 expect(d.admin_contacts.count).to eq 1
@ -892,7 +892,7 @@ describe 'EPP Domain', epp: true do
expect(response[:results][0][:msg]).to eq('Domain not found') expect(response[:results][0][:msg]).to eq('Domain not found')
end end
it 'updates domain and adds objects', pending: true do it 'updates domain and adds objects' do
xml = domain_update_xml({ xml = domain_update_xml({
add: [ add: [
{ {
@ -1062,6 +1062,25 @@ describe 'EPP Domain', epp: true do
expect(response[:results][2][:value]).to eq('clientHold') expect(response[:results][2][:value]).to eq('clientHold')
end end
it 'does not remove server statuses' do
d = Domain.last
d.domain_statuses.create(value: DomainStatus::SERVER_HOLD)
xml = domain_update_xml({
rem: [
_anonymus: [
{ status: { value: '', attrs: { s: 'serverHold' } } }
]
]
})
response = epp_request(xml, :xml)
expect(response[:results][0][:result_code]).to eq('2303')
expect(response[:results][0][:msg]).to eq('Status was not found')
expect(response[:results][0][:value]).to eq('serverHold')
end
it 'does not add duplicate objects to domain' do it 'does not add duplicate objects to domain' do
Fabricate(:contact, code: 'mak21') Fabricate(:contact, code: 'mak21')

View file

@ -0,0 +1,7 @@
Fabricator(:domain_contact) do
contact { Fabricate(:contact) }
contact_type 'admin'
after_build do |x|
x.contact_code_cache = x.contact.code
end
end

View file

@ -5,7 +5,7 @@ Fabricator(:domain) do
period_unit 'y' period_unit 'y'
owner_contact(fabricator: :contact) owner_contact(fabricator: :contact)
nameservers(count: 3) nameservers(count: 3)
admin_contacts(count: 1) { Fabricate(:contact) } domain_contacts(count: 1) { Fabricate(:domain_contact, contact_type: 'admin') }
registrar registrar
auth_info '98oiewslkfkd' auth_info '98oiewslkfkd'
dnskeys(count: 1) dnskeys(count: 1)

View file

@ -0,0 +1 @@
Fabricator(:epp_domain, from: :domain, class_name: 'Epp::EppDomain')

View file

@ -1,3 +1,4 @@
Fabricator(:nameserver) do Fabricator(:nameserver) do
hostname { "ns.#{Faker::Internet.domain_word}.ee" } hostname { sequence(:hostname) { |i| "ns.#{Faker::Internet.domain_word}#{i}.ee" } }
ipv4 '192.168.1.1'
end end

View file

@ -1,6 +1,6 @@
Fabricator(:registrar) do Fabricator(:registrar) do
name 'Zone Media OÜ' name 'Registrar OÜ'
reg_no '10577829' reg_no '12345678'
address 'Lõõtsa 2, Tallinna linn, Harju maakond, 11415' address 'Street 999, Town, County, Postal'
country country
end end

View file

@ -5,5 +5,4 @@ Fabricator(:user) do
identity_code '37810013108' identity_code '37810013108'
admin true admin true
country country
registrar
end end

View file

@ -6,8 +6,8 @@ feature 'Sessions', type: :feature do
background do background do
create_settings create_settings
Fabricate(:user, registrar: nil, identity_code: '37810013261') Fabricate(:user, identity_code: '37810013261')
Fabricate(:user, registrar: zone, username: 'zone', admin: false, identity_code: '37810013087') Fabricate(:user, username: 'zone', admin: false, identity_code: '37810013087')
Fabricate.times(2, :domain, registrar: zone) Fabricate.times(2, :domain, registrar: zone)
Fabricate.times(2, :domain, registrar: elkdata) Fabricate.times(2, :domain, registrar: elkdata)
end end
@ -23,6 +23,6 @@ feature 'Sessions', type: :feature do
expect(uri.path).to eq(admin_root_path) expect(uri.path).to eq(admin_root_path)
expect(page).to have_link('Elkdata', count: 2) expect(page).to have_link('Elkdata', count: 2)
expect(page).to have_link('Zone Media OÜ', count: 2) expect(page).to have_link('Registrar OÜ', count: 2)
end end
end end

View file

@ -1,13 +1,12 @@
require 'rails_helper' require 'rails_helper'
feature 'Setting management', type: :feature do feature 'Setting management', type: :feature do
let(:zone) { Fabricate(:registrar) } let(:user) { Fabricate(:user, username: 'user1', admin: true, identity_code: '37810013087') }
let(:zone_user) { Fabricate(:user, registrar: zone, username: 'user1', admin: true, identity_code: '37810013087') }
background { create_settings } background { create_settings }
scenario 'User changes a setting' do scenario 'User changes a setting' do
sign_in zone_user sign_in user
visit admin_settings_path visit admin_settings_path
val_min = find_field('_settings_ns_min_count').value val_min = find_field('_settings_ns_min_count').value

View file

@ -7,11 +7,36 @@ describe Dnskey do
it { should belong_to(:domain) } it { should belong_to(:domain) }
it 'generates digest' do # rubocop: disable Style/NumericLiterals
it 'generates correct DS digest and DS key tag for ria.ee' do
d = Fabricate(:domain, name: 'ria.ee') d = Fabricate(:domain, name: 'ria.ee')
ds = d.dnskeys.first dk = d.dnskeys.first
ds.generate_digest dk.generate_digest
expect(ds.ds_digest).to eq('0B62D1BC64EFD1EE652FB102BDF1011BF514CCD9A1A0CFB7472AEA3B01F38C92') expect(dk.ds_digest).to eq('0B62D1BC64EFD1EE652FB102BDF1011BF514CCD9A1A0CFB7472AEA3B01F38C92')
expect(dk.ds_key_tag).to eq(30607)
end
it 'generates correct DS digest and DS key tag for emta.ee' do
d = Fabricate(:domain, name: 'emta.ee')
dk = d.dnskeys.first
dk.public_key = 'AwEAAfB9jK8rj/FAdE3t9bYXiTLpelwlgUyxbHEtvMvhdxs+yHv0h9fE '\
'710u94LPAeVmXumT6SZPsoo+ALKdmTexkcU9DGQvb2+sPfModBKM/num '\
'rScUw1FBe3HwRa9SqQpgpnCjIt0kEVKHAQdLOP86YznSA9uHAg9TTJuT '\
'LkUtgtmwNAVFr6/mG+smE1v5NbxPccsFwVTA/T1IyaI4Z48VGCP2WNro '\
'R7P6vet1gWhssirnnVYnur8DwWuMJ89o/HjzXeiEGUB8k5SOX+//67FN '\
'm8Zs+1ObuAfY8xAHe0L5bxluEbh1T1ARp41QX77EMKVbkcSj7nuBeY8H '\
'KiN8HsTvmZyDbRAQQaAJi68qOXsUIoQcpn89PoNoc60F7WlueA6ExSGX '\
'KMWIH6nfLXFgidoZ6HxteyUUnZbHEdULjpAoCRuUDjjUnUgFS7eRANfw '\
'RCcu9aLziMDp4UU61zVjtmQ7xn3G2W2+2ycqn/vEl/yFyBmHZ+7stpoC '\
'd6NTZUn4/ellYSm9lx/vaXdPSinARpYMWtU79Hu/VRifaCQjYkBGAMwK '\
'DshX4yJPjza/bqo0XV4WHj1szDFHe0tLN7g1Ojwtf5FR0zyHU3FN9uUa '\
'y8a+dowd/fqOQA1jXR04g2PIfFYe0VudCEpmxSV9YDoqjghHeIKUX7Jn '\
'KiHL5gk404S5a/Bv'
dk.save
expect(dk.ds_digest).to eq('D7045D3C2EF7332409A132D935C8E2834A2AAB769B35BC370FA68C9445398288')
expect(dk.ds_key_tag).to eq(31051)
end end
end end

View file

@ -95,6 +95,28 @@ describe Domain do
d = Fabricate(:domain) d = Fabricate(:domain)
expect(d.auth_info).to_not be_empty expect(d.auth_info).to_not be_empty
end end
it 'manages statuses automatically' do
d = Fabricate(:domain)
expect(d.domain_statuses.count).to eq(1)
expect(d.domain_statuses.first.value).to eq(DomainStatus::OK)
d.period = 2
d.save
d.reload
expect(d.domain_statuses.count).to eq(1)
expect(d.domain_statuses.first.reload.value).to eq(DomainStatus::OK)
d.domain_statuses.build(value: DomainStatus::CLIENT_DELETE_PROHIBITED)
d.save
d.reload
expect(d.domain_statuses.count).to eq(1)
expect(d.domain_statuses.first.value).to eq(DomainStatus::CLIENT_DELETE_PROHIBITED)
end
end end
with_versioning do with_versioning do

View file

@ -4,9 +4,9 @@ describe DomainVersion do
with_versioning do with_versioning do
before(:each) do before(:each) do
Setting.ns_min_count = 1 Setting.ns_min_count = 1
Fabricate(:domain, name: 'version.ee', dnskeys: []) do Fabricate(:domain, name: 'version.ee', dnskeys: [], domain_contacts: []) do
owner_contact { Fabricate(:contact, name: 'owner_contact', code: 'asd', email: 'owner1@v.ee') } owner_contact { Fabricate(:contact, name: 'owner_contact', code: 'asd', email: 'owner1@v.ee') }
nameservers(count: 1) { Fabricate(:nameserver, hostname: 'ns.test.ee') } nameservers(count: 1) { Fabricate(:nameserver, hostname: 'ns.test.ee', ipv4: nil) }
admin_contacts(count: 1) { Fabricate(:contact, name: 'admin_contact 1', code: 'qwe', email: 'admin1@v.ee') } admin_contacts(count: 1) { Fabricate(:contact, name: 'admin_contact 1', code: 'qwe', email: 'admin1@v.ee') }
tech_contacts(count: 1) { Fabricate(:contact, name: 'tech_contact 1', code: 'zxc', email: 'tech1@v.ee') } tech_contacts(count: 1) { Fabricate(:contact, name: 'tech_contact 1', code: 'zxc', email: 'tech1@v.ee') }
end end
@ -99,7 +99,6 @@ describe DomainVersion do
expect(DomainVersion.count).to eq(1) expect(DomainVersion.count).to eq(1)
Contact.find_by(name: 'tech_contact 1').destroy Contact.find_by(name: 'tech_contact 1').destroy
expect(DomainVersion.count).to eq(2) expect(DomainVersion.count).to eq(2)
expect(DomainVersion.last.load_snapshot[:admin_contacts].size).to eq(1) expect(DomainVersion.last.load_snapshot[:admin_contacts].size).to eq(1)
expect(DomainVersion.last.load_snapshot[:admin_contacts].first).to include( expect(DomainVersion.last.load_snapshot[:admin_contacts].first).to include(
name: 'admin_contact 1', phone: '+372.12345678', ident: '37605030299', email: 'admin1@v.ee' name: 'admin_contact 1', phone: '+372.12345678', ident: '37605030299', email: 'admin1@v.ee'

View file

@ -0,0 +1,94 @@
require 'rails_helper'
describe Epp::EppDomain do
context 'with sufficient settings' do
let(:domain) { Fabricate(:epp_domain) }
before(:each) do
create_settings
end
it 'attaches valid statuses' do
domain.attach_statuses([
{
value: DomainStatus::CLIENT_HOLD,
description: 'payment overdue'
},
{
value: DomainStatus::CLIENT_DELETE_PROHIBITED
}
])
domain.save
domain.reload
expect(domain.domain_statuses.first.value).to eq(DomainStatus::CLIENT_HOLD)
expect(domain.domain_statuses.first.description).to eq('payment overdue')
expect(domain.domain_statuses.last.value).to eq(DomainStatus::CLIENT_DELETE_PROHIBITED)
end
it 'adds an epp error when invalid statuses are attached' do
domain.attach_statuses([
{
value: DomainStatus::SERVER_HOLD,
description: 'payment overdue'
},
{
value: DomainStatus::CLIENT_DELETE_PROHIBITED
}
])
expect(domain.errors[:epp_errors].length).to eq(1)
err = domain.errors[:epp_errors].first
expect(err[:msg]).to eq('Status was not found')
expect(err[:value][:val]).to eq(DomainStatus::SERVER_HOLD)
end
it 'detaches valid statuses' do
domain.attach_statuses([
{
value: DomainStatus::CLIENT_HOLD,
description: 'payment overdue'
},
{
value: DomainStatus::CLIENT_DELETE_PROHIBITED
}
])
domain.save
domain.detach_statuses([
{
value: DomainStatus::CLIENT_HOLD
}
])
domain.save
domain.reload
expect(domain.domain_statuses.count).to eq(1)
expect(domain.domain_statuses.first.value).to eq(DomainStatus::CLIENT_DELETE_PROHIBITED)
end
it 'adds an epp error when invalid statuses are detached' do
domain.domain_statuses.create(value: DomainStatus::SERVER_HOLD)
domain.detach_statuses([
{
value: DomainStatus::SERVER_HOLD
}
])
expect(domain.errors[:epp_errors].length).to eq(1)
err = domain.errors[:epp_errors].first
expect(err[:msg]).to eq('Status was not found')
expect(err[:value][:val]).to eq(DomainStatus::SERVER_HOLD)
end
end
end

View file

@ -4,6 +4,5 @@ describe Registrar do
it { should belong_to(:country) } it { should belong_to(:country) }
it { should have_many(:domains) } it { should have_many(:domains) }
it { should have_many(:epp_users) } it { should have_many(:epp_users) }
it { should have_many(:users) }
it { should have_many(:messages) } it { should have_many(:messages) }
end end

View file

@ -2,5 +2,4 @@ require 'rails_helper'
describe User do describe User do
it { should belong_to(:role) } it { should belong_to(:role) }
it { should belong_to(:registrar) }
end end

View file

@ -8,8 +8,16 @@ module Epp
server = server_zone server = server_zone
server = server_elkdata if args.include?(:elkdata) server = server_elkdata if args.include?(:elkdata)
return parse_response(server.request(data)) if args.include?(:xml) res = parse_response(server.request(data)) if args.include?(:xml)
return parse_response(server.request(read_body(data))) if res
log(data, res[:parsed])
return res
end
res = parse_response(server.request(read_body(data)))
log(read_body(data), res[:parsed])
return res
rescue => e rescue => e
e e
end end
@ -19,8 +27,15 @@ module Epp
server = server_elkdata if args.include?(:elkdata) server = server_elkdata if args.include?(:elkdata)
server = server_zone if args.include?(:zone) server = server_zone if args.include?(:zone)
return parse_response(server.send_request(data)) if args.include?(:xml) res = parse_response(server.send_request(data)) if args.include?(:xml)
return parse_response(server.send_request(read_body(data))) if res
log(data, res[:parsed])
return res
end
res = parse_response(server.send_request(read_body(data)))
log(read_body(data), res[:parsed])
return res
rescue => e rescue => e
e e
end end
@ -36,7 +51,9 @@ module Epp
} }
res.css('epp response result').each do |x| res.css('epp response result').each do |x|
obj[:results] << { result_code: x[:code], msg: x.css('msg').text, value: x.css('value > *').try(:first).try(:text) } obj[:results] << {
result_code: x[:code], msg: x.css('msg').text, value: x.css('value > *').try(:first).try(:text)
}
end end
obj[:result_code] = obj[:results][0][:result_code] obj[:result_code] = obj[:results][0][:result_code]
@ -202,6 +219,12 @@ module Epp
xml_params = defaults.deep_merge(xml_params) xml_params = defaults.deep_merge(xml_params)
EppXml::Domain.transfer(xml_params, op) EppXml::Domain.transfer(xml_params, op)
end end
def log(req, res)
return unless ENV['EPP_DOC']
puts "REQUEST:\n\n```xml\n#{Nokogiri(req)}```\n\n"
puts "RESPONSE:\n\n```xml\n#{res}```\n\n"
end
end end
RSpec.configure do |c| RSpec.configure do |c|

18
spec/support/epp_doc.rb Normal file
View file

@ -0,0 +1,18 @@
class EppDoc
RSpec::Core::Formatters.register self, :start, :example_started
def initialize(output)
@output = output
end
def start(example_count)
@output.puts '# EPP REQUEST - RESPONSE DOCUMENTATION'
@output.puts "GENERATED AT: #{Time.now} "
@output.puts "EXAMPLE COUNT: #{example_count.count} "
@output.puts "\n---\n\n"
end
def example_started(notification)
@output.puts "### #{notification.example.full_description} \n\n"
end
end