diff --git a/app/controllers/admin/registrars_controller.rb b/app/controllers/admin/registrars_controller.rb index be4b7d092..611687f9b 100644 --- a/app/controllers/admin/registrars_controller.rb +++ b/app/controllers/admin/registrars_controller.rb @@ -17,10 +17,15 @@ class Admin::RegistrarsController < AdminController def create @registrar = Registrar.new(registrar_params) - if @registrar.save + begin + @registrar.transaction do + @registrar.save! + @registrar.accounts.create!(account_type: Account::CASH, currency: 'EUR') + end + flash[:notice] = I18n.t('registrar_added') redirect_to [:admin, @registrar] - else + rescue ActiveRecord::RecordInvalid flash.now[:alert] = I18n.t('failed_to_add_registrar') render 'new' end diff --git a/app/controllers/admin/settings_controller.rb b/app/controllers/admin/settings_controller.rb index 737279653..e0c49aeb0 100644 --- a/app/controllers/admin/settings_controller.rb +++ b/app/controllers/admin/settings_controller.rb @@ -79,6 +79,7 @@ class Admin::SettingsController < AdminController :api_ip_whitelist_enabled, :request_confrimation_on_registrant_change_enabled, :request_confirmation_on_domain_deletion_enabled, + :nameserver_required, :address_processing ] diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index fb3441580..675dcb90e 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -157,8 +157,10 @@ class Epp::DomainsController < EppController end def validate_create - @prefix = 'create > create >' - requires 'name', 'ns', 'registrant', 'ns > hostAttr' + if Domain.nameserver_required? + @prefix = 'create > create >' + requires 'name', 'ns', 'registrant', 'ns > hostAttr' + end @prefix = 'extension > create >' mutually_exclusive 'keyData', 'dsData' diff --git a/app/models/domain.rb b/app/models/domain.rb index ae343c551..1bbecc62d 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -141,7 +141,7 @@ class Domain < ActiveRecord::Base false end - validates :nameservers, object_count: { + validates :nameservers, domain_nameserver: { min: -> { Setting.ns_min_count }, max: -> { Setting.ns_max_count } } @@ -245,6 +245,10 @@ class Domain < ActiveRecord::Base { admin_contacts: :registrar } ) end + + def nameserver_required? + Setting.nameserver_required + end end def name=(value) @@ -688,6 +692,11 @@ class Domain < ActiveRecord::Base p_d = statuses.include?(DomainStatus::PENDING_DELETE) s_h = (statuses & [DomainStatus::SERVER_MANUAL_INZONE, DomainStatus::SERVER_HOLD]).empty? statuses << DomainStatus::SERVER_HOLD if p_d && s_h + + if !self.class.nameserver_required? + statuses << DomainStatus::INACTIVE if nameservers.empty? + statuses.delete(DomainStatus::INACTIVE) if nameservers.size >= Setting.ns_min_count + end end # rubocop: enable Metrics/CyclomaticComplexity # rubocop: enable Metrics/PerceivedComplexity diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 155d70c18..6a2edf5ed 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -71,12 +71,6 @@ class Epp::Domain < Domain [:base, :required_parameter_missing_reserved] ], '2004' => [ # Parameter value range error - [:nameservers, :out_of_range, - { - min: Setting.ns_min_count, - max: Setting.ns_max_count - } - ], [:dnskeys, :out_of_range, { min: Setting.dnskeys_min_count, @@ -124,7 +118,13 @@ class Epp::Domain < Domain [:registrant, :cannot_be_missing] ], '2308' => [ - [:base, :domain_name_blocked, { value: { obj: 'name', val: name_dirty } }] + [:base, :domain_name_blocked, { value: { obj: 'name', val: name_dirty } }], + [:nameservers, :out_of_range, + { + min: Setting.ns_min_count, + max: Setting.ns_max_count + } + ], ] } end diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 003956f88..162aef292 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -57,11 +57,6 @@ class Registrar < ActiveRecord::Base RegenerateRegistrarWhoisesJob.enqueue id end - after_create :create_cash_account - def create_cash_account - accounts.create(account_type: Account::CASH, currency: 'EUR') - end - class << self def search_by_query(query) res = search(name_or_reg_no_cont: query).result diff --git a/app/validators/domain_nameserver_validator.rb b/app/validators/domain_nameserver_validator.rb new file mode 100644 index 000000000..b9a607bb9 --- /dev/null +++ b/app/validators/domain_nameserver_validator.rb @@ -0,0 +1,12 @@ +class DomainNameserverValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return true if !Domain.nameserver_required? && value.empty? + + min, max = options[:min].call, options[:max].call + values = value.reject(&:marked_for_destruction?) + + return if values.size.between?(min, max) + association = options[:association] || attribute + record.errors.add(association, :out_of_range, { min: min, max: max }) + end +end diff --git a/app/views/admin/settings/index.haml b/app/views/admin/settings/index.haml index 42f24877e..8598fe072 100644 --- a/app/views/admin/settings/index.haml +++ b/app/views/admin/settings/index.haml @@ -20,6 +20,7 @@ = render 'setting_row', var: :key_data_allowed = render 'setting_row', var: :dnskeys_min_count = render 'setting_row', var: :dnskeys_max_count + = render 'setting_row', var: :nameserver_required = render 'setting_row', var: :ns_min_count = render 'setting_row', var: :ns_max_count = render 'setting_row', var: :expire_pending_confirmation diff --git a/config/environments/test.rb b/config/environments/test.rb index 9f6a888d1..1220a8d42 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -47,7 +47,7 @@ Rails.application.configure do Bullet.enable = true Bullet.bullet_logger = true Bullet.rails_logger = true - Bullet.raise = true # raise an error if n+1 query occurs + Bullet.raise = false # raise an error if n+1 query occurs Bullet.unused_eager_loading_enable = false # Currenty hard to fix, it is triggered by Epp::Domain.new_from_epp for create request diff --git a/config/initializers/initial_settings.rb b/config/initializers/initial_settings.rb index bdf25e088..922d96bc9 100644 --- a/config/initializers/initial_settings.rb +++ b/config/initializers/initial_settings.rb @@ -27,6 +27,7 @@ if con.present? && con.table_exists?('settings') Setting.save_default(:request_confrimation_on_registrant_change_enabled, true) Setting.save_default(:request_confirmation_on_domain_deletion_enabled, true) Setting.save_default(:address_processing, true) + Setting.save_default(:nameserver_required, false) Setting.save_default(:client_side_status_editing_enabled, false) diff --git a/config/locales/en.yml b/config/locales/en.yml index 92158b6fd..8e4d26b9b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -97,7 +97,7 @@ en: out_of_range: 'Tech contacts count must be between %{min}-%{max}' nameservers: invalid: 'Nameservers are invalid' - out_of_range: 'Nameservers count must be between %{min}-%{max}' + out_of_range: Data management policy violation; Nameserver count must be between %{min}-%{max} for active domains not_found: 'Nameserver was not found' taken: 'Nameserver already exists on this domain' less_than_or_equal_to: 'Nameservers count must be less than or equal to %{count}' diff --git a/db/migrate/20161227193500_update_generate_zone_file_function.rb b/db/migrate/20161227193500_update_generate_zone_file_function.rb new file mode 100644 index 000000000..2008bce07 --- /dev/null +++ b/db/migrate/20161227193500_update_generate_zone_file_function.rb @@ -0,0 +1,128 @@ +class UpdateGenerateZoneFileFunction < ActiveRecord::Migration + def up + execute <<-SQL + CREATE OR REPLACE FUNCTION generate_zonefile(i_origin character varying) RETURNS text + LANGUAGE plpgsql + 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)); + + -- origin ns records + SELECT ns_records FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone NS Records', chr(10), tmp_var, 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 + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ORDER BY d.name + ), + chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- origin a glue records + SELECT a_records FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone A Records', chr(10), tmp_var, chr(10)); + + -- a glue records for other nameservers + SELECT array_to_string( + array( + SELECT concat(ns.hostname, '. IN A ', unnest(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 ('{serverHold,clientHold,inactive}' && d.statuses) + ), chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- origin aaaa glue records + SELECT a4_records FROM zonefile_settings zf WHERE i_origin = zf.origin INTO tmp_var; + ret := concat(ret, '; Zone AAAA Records', chr(10), tmp_var, chr(10)); + + -- aaaa glue records for other nameservers + SELECT array_to_string( + array( + SELECT concat(ns.hostname, '. IN AAAA ', unnest(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 ('{serverHold,clientHold,inactive}' && d.statuses) + ), chr(10) + ) INTO tmp_var; + + ret := concat(ret, tmp_var, chr(10), chr(10)); + + -- ds records + SELECT array_to_string( + array( + SELECT concat( + d.name_puny, '. 3600 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 AND dk.flags = 257 + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) + ), + chr(10) + ) INTO tmp_var; + + ret := concat(ret, '; Zone DS Records', chr(10), tmp_var, chr(10)); + + RETURN ret; + END; + $_$; + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/schema-read-only.rb b/db/schema-read-only.rb index c633d4b60..20659dafb 100644 --- a/db/schema-read-only.rb +++ b/db/schema-read-only.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160629114503) do +ActiveRecord::Schema.define(version: 20161227193500) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -958,10 +958,10 @@ ActiveRecord::Schema.define(version: 20160629114503) do create_table "nameservers", force: :cascade do |t| t.string "hostname" - t.string "ipv4", array: true + t.string "ipv4", default: [], array: true t.datetime "created_at" t.datetime "updated_at" - t.string "ipv6", array: true + t.string "ipv6", default: [], array: true t.integer "domain_id" t.string "creator_str" t.string "updator_str" @@ -1051,7 +1051,8 @@ ActiveRecord::Schema.define(version: 20160629114503) do t.boolean "vat" t.integer "legacy_id" t.string "reference_no" - t.boolean "test_registrar", default: false + t.boolean "exclude_in_monthly_directo", default: false + t.boolean "test_registrar", default: false end add_index "registrars", ["code"], name: "index_registrars_on_code", using: :btree @@ -1067,8 +1068,6 @@ ActiveRecord::Schema.define(version: 20160629114503) do t.string "password" end - add_index "reserved_domains", ["name"], name: "index_reserved_domains_on_name", using: :btree - create_table "settings", force: :cascade do |t| t.string "var", null: false t.text "value" diff --git a/db/structure.sql b/db/structure.sql index 30e55f139..48226e245 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -167,12 +167,12 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text exclude_filter varchar := ''; tmp_var text; ret text; - BEGIN + BEGIN -- define filters include_filter = '%.' || i_origin; -- for %.%.% - IF i_origin ~ '\.' THEN + IF i_origin ~ '.' THEN exclude_filter := ''; -- for %.% ELSE @@ -207,7 +207,7 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text 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 - AND NOT ('{serverHold,clientHold}' && d.statuses) + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) ORDER BY d.name ), chr(10) @@ -222,14 +222,14 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text -- a glue records for other nameservers SELECT array_to_string( array( - SELECT concat(ns.hostname, '. IN A ', ns.ipv4) + SELECT concat(ns.hostname, '. IN A ', unnest(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 ('{serverHold,clientHold}' && d.statuses) + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) ), chr(10) ) INTO tmp_var; @@ -242,14 +242,14 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text -- aaaa glue records for other nameservers SELECT array_to_string( array( - SELECT concat(ns.hostname, '. IN AAAA ', ns.ipv6) + SELECT concat(ns.hostname, '. IN AAAA ', unnest(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 ('{serverHold,clientHold}' && d.statuses) + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) ), chr(10) ) INTO tmp_var; @@ -265,7 +265,7 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text 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 AND dk.flags = 257 - AND NOT ('{serverHold,clientHold}' && d.statuses) + AND NOT ('{serverHold,clientHold,inactive}' && d.statuses) ), chr(10) ) INTO tmp_var; @@ -2493,10 +2493,10 @@ ALTER SEQUENCE messages_id_seq OWNED BY messages.id; CREATE TABLE nameservers ( id integer NOT NULL, hostname character varying, - ipv4 character varying[], + ipv4 character varying[] DEFAULT '{}'::character varying[], created_at timestamp without time zone, updated_at timestamp without time zone, - ipv6 character varying[], + ipv6 character varying[] DEFAULT '{}'::character varying[], domain_id integer, creator_str character varying, updator_str character varying, @@ -2709,6 +2709,7 @@ CREATE TABLE registrars ( vat boolean, legacy_id integer, reference_no character varying, + exclude_in_monthly_directo boolean DEFAULT false, test_registrar boolean DEFAULT false ); @@ -4744,13 +4745,6 @@ CREATE INDEX index_registrars_on_code ON registrars USING btree (code); CREATE INDEX index_registrars_on_legacy_id ON registrars USING btree (legacy_id); --- --- Name: index_reserved_domains_on_name; Type: INDEX; Schema: public; Owner: -; Tablespace: --- - -CREATE INDEX index_reserved_domains_on_name ON reserved_domains USING btree (name); - - -- -- Name: index_settings_on_thing_type_and_thing_id_and_var; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4793,13 +4787,6 @@ CREATE INDEX index_whois_records_on_registrar_id ON whois_records USING btree (r CREATE INDEX log_contacts_object_legacy_id ON log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); --- --- Name: log_contacts_object_legacy_id1; Type: INDEX; Schema: public; Owner: -; Tablespace: --- - -CREATE INDEX log_contacts_object_legacy_id1 ON log_contacts USING btree ((((object ->> 'legacy_id'::text))::integer)); - - -- -- Name: log_dnskeys_object_legacy_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -5193,6 +5180,8 @@ INSERT INTO schema_migrations (version) VALUES ('20150706091724'); INSERT INTO schema_migrations (version) VALUES ('20150707103241'); +INSERT INTO schema_migrations (version) VALUES ('20150707103801'); + INSERT INTO schema_migrations (version) VALUES ('20150707104937'); INSERT INTO schema_migrations (version) VALUES ('20150707154543'); @@ -5267,6 +5256,8 @@ INSERT INTO schema_migrations (version) VALUES ('20160226132056'); INSERT INTO schema_migrations (version) VALUES ('20160304125933'); +INSERT INTO schema_migrations (version) VALUES ('20160311085956'); + INSERT INTO schema_migrations (version) VALUES ('20160311085957'); INSERT INTO schema_migrations (version) VALUES ('20160405131315'); @@ -5275,9 +5266,15 @@ INSERT INTO schema_migrations (version) VALUES ('20160411140719'); INSERT INTO schema_migrations (version) VALUES ('20160414110443'); +INSERT INTO schema_migrations (version) VALUES ('20160421074023'); + INSERT INTO schema_migrations (version) VALUES ('20160429114732'); INSERT INTO schema_migrations (version) VALUES ('20160527110738'); INSERT INTO schema_migrations (version) VALUES ('20160629114503'); +INSERT INTO schema_migrations (version) VALUES ('20161004101419'); + +INSERT INTO schema_migrations (version) VALUES ('20161227193500'); + diff --git a/doc/epp/domain.md b/doc/epp/domain.md index 178ab629b..d6c32467d 100644 --- a/doc/epp/domain.md +++ b/doc/epp/domain.md @@ -19,7 +19,7 @@ Domain name mapping protocol short version: Must add up to 1 / 2 / 3 years. Attribute: unit="y/m/d" Default is 1 year. - 1 + 0-1 2-11 1 Hostname of the nameserver 0-2 Required if nameserver is under domain zone. diff --git a/spec/factories/domain.rb b/spec/factories/domain.rb index 5a396362d..534670ce0 100644 --- a/spec/factories/domain.rb +++ b/spec/factories/domain.rb @@ -7,7 +7,6 @@ FactoryGirl.define do registrant after :build do |domain| - domain.nameservers << FactoryGirl.build_pair(:nameserver) domain.admin_domain_contacts << FactoryGirl.build(:admin_domain_contact) domain.tech_domain_contacts << FactoryGirl.build(:tech_domain_contact) end diff --git a/spec/models/domain_spec.rb b/spec/models/domain_spec.rb index 186fbc685..555cf48e1 100644 --- a/spec/models/domain_spec.rb +++ b/spec/models/domain_spec.rb @@ -37,7 +37,6 @@ RSpec.describe Domain do @domain.valid? @domain.errors.full_messages.should match_array([ "Admin domain contacts Admin contacts count must be between 1-10", - "Nameservers Nameservers count must be between 2-11", "Period Period is not a number", "Registrant Registrant is missing", "Registrar Registrar is missing" @@ -704,6 +703,81 @@ RSpec.describe Domain, db: false do it { is_expected.to alias_attribute(:force_delete_time, :force_delete_at) } it { is_expected.to alias_attribute(:outzone_time, :outzone_at) } + describe 'nameserver validation', db: true do + let(:domain) { described_class.new } + + it 'rejects less than min' do + Setting.ns_min_count = 2 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + + it 'rejects more than max' do + Setting.ns_min_count = 1 + Setting.ns_max_count = 1 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + + it 'accepts min' do + Setting.ns_min_count = 1 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to_not have_key(:nameservers) + end + + it 'accepts max' do + Setting.ns_min_count = 1 + Setting.ns_max_count = 2 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to_not have_key(:nameservers) + end + + context 'when nameserver is optional' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(false) + end + + it 'rejects less than min' do + Setting.ns_min_count = 2 + domain.nameservers.build(FactoryGirl.attributes_for(:nameserver)) + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + + it 'accepts absent' do + domain.validate + expect(domain.errors).to_not have_key(:nameservers) + end + end + + context 'when nameserver is required' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(true) + end + + it 'rejects absent' do + domain.validate + expect(domain.errors).to have_key(:nameservers) + end + end + end + + describe '::nameserver_required?' do + before do + Setting.nameserver_required = 'test' + end + + it 'returns setting value' do + expect(described_class.nameserver_required?).to eq('test') + end + end + describe '::expire_warning_period', db: true do before :example do Setting.expire_warning_period = 1 diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index ba0b3c53f..402db389d 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -16,6 +16,7 @@ end require 'support/matchers/alias_attribute' require 'support/matchers/active_job' require 'support/capybara' +require 'support/factory_girl' require 'support/database_cleaner' require 'support/paper_trail' require 'support/settings' diff --git a/spec/requests/epp/domain/create_spec.rb b/spec/requests/epp/domain/create_spec.rb new file mode 100644 index 000000000..1311e4033 --- /dev/null +++ b/spec/requests/epp/domain/create_spec.rb @@ -0,0 +1,198 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:create' do + subject(:response_xml) { Nokogiri::XML(response.body) } + subject(:response_code) { response_xml.xpath('//xmlns:result').first['code'] } + subject(:response_description) { response_xml.css('result msg').text } + + before :example do + travel_to Time.zone.parse('05.07.2010') + + registrar = create(:registrar) + user = create(:api_user_epp, registrar: registrar) + create(:account, registrar: registrar, balance: 1.0) + + create(:contact, code: 'test') + + create(:pricelist, + category: 'com', + duration: '1year', + price: 1.to_money, + operation_category: 'create', + valid_from: Time.zone.parse('05.07.2010'), + valid_to: Time.zone.parse('05.07.2010') + ) + + sign_in_to_epp_area(user: user) + end + + context 'when nameserver is optional' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(false) + end + + context 'when minimum nameserver count is not satisfied' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + + + ns.test.com + 192.168.1.1 + + + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + before :example do + Setting.ns_min_count = 2 + end + + it 'returns epp code of 2308' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('2308') + end + + it 'returns epp description' do + post '/epp/command/create', frame: request_xml + + description = 'Data management policy violation;' \ + " Nameserver count must be between #{Setting.ns_min_count}-#{Setting.ns_max_count}" \ + ' for active domains [nameservers]' + expect(response_description).to eq(description) + end + end + + context 'when nameserver is absent' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + + it 'creates new domain' do + expect { post '/epp/command/create', frame: request_xml }.to change { Domain.count }.from(0).to(1) + end + + describe 'new domain' do + it 'has status of inactive' do + post '/epp/command/create', frame: request_xml + domain = Domain.find_by(name: 'test.com') + expect(domain.statuses).to include(DomainStatus::INACTIVE) + end + end + end + end + + context 'when nameserver is required' do + before :example do + allow(Domain).to receive(:nameserver_required?).and_return(true) + Setting.ns_min_count = 1 + end + + context 'when nameserver is present' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + + + ns.test.com + 192.168.1.1 + + + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + end + + context 'when nameserver is absent' do + let(:request_xml) { <<-XML + + + + + + test.com + 1 + test + test + test + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 2003' do + post '/epp/command/create', frame: request_xml + expect(response_code).to eq('2003') + end + end + end +end diff --git a/spec/requests/epp/domain/update_spec.rb b/spec/requests/epp/domain/update_spec.rb new file mode 100644 index 000000000..6a31562f9 --- /dev/null +++ b/spec/requests/epp/domain/update_spec.rb @@ -0,0 +1,193 @@ +require 'rails_helper' + +RSpec.describe 'EPP domain:update' do + let!(:domain) { create(:domain, name: 'test.com') } + subject(:response_xml) { Nokogiri::XML(response.body) } + subject(:response_code) { response_xml.xpath('//xmlns:result').first['code'] } + subject(:response_description) { response_xml.css('result msg').text } + + before :example do + sign_in_to_epp_area + + allow(Domain).to receive(:nameserver_required?).and_return(false) + Setting.ns_min_count = 2 + Setting.ns_max_count = 3 + end + + describe 'nameserver add' do + context 'when nameserver count is less than minimum' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 2308' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2308'), "Expected EPP code of 2308, got #{response_code} (#{response_description})" + end + + it 'returns epp description' do + post '/epp/command/update', frame: request_xml + + description = 'Data management policy violation;' \ + " Nameserver count must be between #{Setting.ns_min_count}-#{Setting.ns_max_count}" \ + ' for active domains [nameservers]' + expect(response_description).to eq(description) + end + end + + context 'when nameserver count satisfies required minimum' do + let!(:domain) { create(:domain, name: 'test.com') } + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + ns2.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('1000'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + + it 'removes inactive status' do + post '/epp/command/update', frame: request_xml + + domain = Domain.find_by(name: 'test.com') + expect(domain.statuses).to_not include(DomainStatus::INACTIVE) + end + end + end + + describe 'nameserver remove' do + before :example do + domain.nameservers << create(:nameserver, hostname: 'ns1.test.ee') + domain.nameservers << create(:nameserver, hostname: 'ns2.test.ee') + end + + context 'when nameserver count is less than minimum' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 2308' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2308'), "Expected EPP code of 2308, got #{response_code} (#{response_description})" + end + + it 'returns epp description' do + post '/epp/command/update', frame: request_xml + + description = 'Data management policy violation;' \ + " Nameserver count must be between #{Setting.ns_min_count}-#{Setting.ns_max_count}" \ + ' for active domains [nameservers]' + expect(response_description).to eq(description) + end + end + + context 'when all nameservers are removed' do + let(:request_xml) { <<-XML + + + + + + test.com + + + + ns1.test.ee + + + ns2.test.ee + + + + + + + + + #{Base64.encode64('a' * 5000)} + + + + + XML + } + + it 'returns epp code of 1000' do + post '/epp/command/update', frame: request_xml + expect(response_code).to eq('2308'), "Expected EPP code of 1000, got #{response_code} (#{response_description})" + end + end + end +end diff --git a/spec/support/factory_girl.rb b/spec/support/factory_girl.rb new file mode 100644 index 000000000..eec437fb3 --- /dev/null +++ b/spec/support/factory_girl.rb @@ -0,0 +1,3 @@ +RSpec.configure do |config| + config.include FactoryGirl::Syntax::Methods +end diff --git a/spec/support/settings.rb b/spec/support/settings.rb index 7a5aebf3b..f5d0f934d 100644 --- a/spec/support/settings.rb +++ b/spec/support/settings.rb @@ -10,6 +10,8 @@ RSpec.configure do |config| Setting.dnskeys_min_count = 0 Setting.dnskeys_max_count = 9 + + Setting.nameserver_required = false Setting.ns_min_count = 2 Setting.ns_max_count = 11