diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b3f92b6..d61a6fbd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +07.07.2015 +* Before applyling 20150707104937_refactor_reserved_domains.rb migration, enable hstore extension in db + 01.07.2015 * Added que init script example at doc/que directory, please setup que accornding to doc/que/README.md diff --git a/app/controllers/admin/blocked_domains_controller.rb b/app/controllers/admin/blocked_domains_controller.rb index 82b1dcc5a..2df3f90d9 100644 --- a/app/controllers/admin/blocked_domains_controller.rb +++ b/app/controllers/admin/blocked_domains_controller.rb @@ -13,10 +13,11 @@ class Admin::BlockedDomainsController < AdminController if bd.update(names: names) flash[:notice] = I18n.t('record_updated') + redirect_to :back else + @blocked_domains = params[:blocked_domains] flash.now[:alert] = I18n.t('failed_to_update_record') + render :index end - - redirect_to :back end end diff --git a/app/controllers/admin/reserved_domains_controller.rb b/app/controllers/admin/reserved_domains_controller.rb new file mode 100644 index 000000000..eb3a5faae --- /dev/null +++ b/app/controllers/admin/reserved_domains_controller.rb @@ -0,0 +1,30 @@ +class Admin::ReservedDomainsController < AdminController + load_and_authorize_resource + + def index + rd = ReservedDomain.first_or_initialize + @reserved_domains = rd.names.to_yaml + end + + def create + @reserved_domains = params[:reserved_domains] + + begin + names = YAML.load(params[:reserved_domains]) + rescue + flash.now[:alert] = I18n.t('invalid_yaml') + logger.warn 'Invalid YAML' + render :index and return + end + + rd = ReservedDomain.first_or_create + + if rd.update(names: names) + flash[:notice] = I18n.t('record_updated') + redirect_to :back + else + flash.now[:alert] = I18n.t('failed_to_update_record') + render :index + end + end +end diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index a50b96003..e3188786f 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -179,7 +179,7 @@ class Epp::DomainsController < EppController requires 'name' @prefix = nil - requires_attribute 'transfer', 'op', values: %(approve, query, reject) + requires_attribute 'transfer', 'op', values: %(approve, query, reject, request) end def find_domain diff --git a/app/models/ability.rb b/app/models/ability.rb index c02e5847c..b7c763708 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -107,6 +107,7 @@ class Ability customer_service can :manage, Setting can :manage, BlockedDomain + can :manage, ReservedDomain can :manage, ZonefileSetting can :manage, DomainVersion can :manage, Pricelist diff --git a/app/models/depp/domain.rb b/app/models/depp/domain.rb index 649d00964..fa252819e 100644 --- a/app/models/depp/domain.rb +++ b/app/models/depp/domain.rb @@ -79,7 +79,8 @@ module Depp end def transfer(params) - op = params[:query] ? 'query' : nil + op = params[:request] ? 'request' : nil + op = params[:query] ? 'query' : op op = params[:approve] ? 'approve' : op op = params[:reject] ? 'reject' : op @@ -132,7 +133,7 @@ module Depp # rubocop:disable Metrics/MethodLength # rubocop:disable Metrics/AbcSize - def construct_params_from_server_data(data) + def construct_params_from_server_data(data) ret = default_params ret[:name] = data.css('name').text ret[:registrant] = data.css('registrant').text @@ -182,16 +183,18 @@ module Depp # rubocop:enable Metrics/AbcSize def construct_custom_params_hash(domain_params) - custom_params = {} + custom_params = { _anonymus: [] } if domain_params[:legal_document].present? type = domain_params[:legal_document].original_filename.split('.').last.downcase - custom_params = { - _anonymus: [ - legalDocument: { value: Base64.encode64(domain_params[:legal_document].read), attrs: { type: type } } - ] + custom_params[:_anonymus] << { + legalDocument: { value: Base64.encode64(domain_params[:legal_document].read), attrs: { type: type } } } end + if domain_params[:reserved_pw].present? + custom_params[:_anonymus] << { reserved: { pw: { value: domain_params[:reserved_pw] } } } + end + custom_params end diff --git a/app/models/domain.rb b/app/models/domain.rb index ae81ce474..49dcb9cfc 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -61,6 +61,7 @@ class Domain < ActiveRecord::Base before_create :generate_auth_info before_create :set_validity_dates + before_create -> { self.reserved = in_reserved_list?; nil } before_update :manage_statuses def manage_statuses return unless registrant_id_changed? @@ -78,12 +79,32 @@ class Domain < ActiveRecord::Base after_initialize -> { self.statuses = [] if statuses.nil? } + after_create :update_reserved_domains + def update_reserved_domains + return unless in_reserved_list? + rd = ReservedDomain.first + rd.names[name] = SecureRandom.hex + rd.save + end + validates :name_dirty, domain_name: true, uniqueness: true validates :puny_label, length: { maximum: 63 } validates :period, numericality: { only_integer: true } validates :registrant, :registrar, presence: true validate :validate_period + validate :validate_reservation + def validate_reservation + return if persisted? || !in_reserved_list? + + if reserved_pw.blank? + errors.add(:base, :required_parameter_missing_reserved) + return false + end + + return if ReservedDomain.pw_for(name) == reserved_pw + errors.add(:base, :invalid_auth_information_reserved) + end validates :nameservers, object_count: { min: -> { Setting.ns_min_count }, @@ -134,7 +155,7 @@ class Domain < ActiveRecord::Base end attr_accessor :registrant_typeahead, :update_me, :deliver_emails, - :epp_pending_update, :epp_pending_delete + :epp_pending_update, :epp_pending_delete, :reserved_pw def subordinate_nameservers nameservers.select { |x| x.hostname.end_with?(name) } @@ -247,6 +268,10 @@ class Domain < ActiveRecord::Base @registrant_typeahead || registrant.try(:name) || nil end + def in_reserved_list? + ReservedDomain.pw_for(name).present? + end + def pending_transfer domain_transfers.find_by(status: DomainTransfer::PENDING) end diff --git a/app/models/domain_status.rb b/app/models/domain_status.rb index b33b5446c..0f984b4e7 100644 --- a/app/models/domain_status.rb +++ b/app/models/domain_status.rb @@ -71,6 +71,7 @@ class DomainStatus < ActiveRecord::Base FORCE_DELETE = 'forceDelete' DELETE_CANDIDATE = 'deleteCandidate' EXPIRED = 'expired' + RESERVED = 'reserved' STATUSES = [ CLIENT_DELETE_PROHIBITED, SERVER_DELETE_PROHIBITED, CLIENT_HOLD, SERVER_HOLD, diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index 69072a398..bb9ab55ce 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -25,7 +25,8 @@ class Epp::Domain < Domain ], '2003' => [ # Required parameter missing [:registrant, :blank], - [:registrar, :blank] + [:registrar, :blank], + [:base, :required_parameter_missing_reserved] ], '2004' => [ # Parameter value range error [:nameservers, :out_of_range, @@ -60,6 +61,9 @@ class Epp::Domain < Domain '2201' => [ # Authorisation error [:auth_info, :wrong_pw] ], + '2202' => [ + [:base, :invalid_auth_information_reserved] + ], '2302' => [ # Object exists [:name_dirty, :taken, { value: { obj: 'name', val: name_dirty } }], [:name_dirty, :reserved, { value: { obj: 'name', val: name_dirty } }], @@ -112,6 +116,8 @@ class Epp::Domain < Domain at[:period_unit] = Epp::Domain.parse_period_unit_from_frame(frame) || 'y' + at[:reserved_pw] = frame.css('reserved > pw').text + # at[:statuses] = domain_statuses_attrs(frame, action) # binding.pry at[:nameservers_attributes] = nameservers_attrs(frame, action) @@ -455,6 +461,8 @@ class Epp::Domain < Domain def transfer(frame, action, current_user) case action when 'query' + return domain_transfers.last if domain_transfers.any? + when 'request' return pending_transfer if pending_transfer return query_transfer(frame, current_user) when 'approve' @@ -462,7 +470,7 @@ class Epp::Domain < Domain when 'reject' return reject_transfer(frame, current_user) if pending_transfer end - add_epp_error('2303', nil, nil, I18n.t('pending_transfer_was_not_found')) + add_epp_error('2303', nil, nil, I18n.t('no_transfers_found')) end # TODO: Eager load problems here. Investigate how it's possible not to query contact again @@ -742,7 +750,7 @@ class Epp::Domain < Domain next end - unless DomainNameValidator.validate_reservation(x) + if ReservedDomain.pw_for(x).present? res << { name: x, avail: 0, reason: I18n.t('errors.messages.epp_domain_reserved') } next end diff --git a/app/models/reserved_domain.rb b/app/models/reserved_domain.rb index 807c44f91..61a57ec50 100644 --- a/app/models/reserved_domain.rb +++ b/app/models/reserved_domain.rb @@ -1,3 +1,9 @@ class ReservedDomain < ActiveRecord::Base include Versions # version/reserved_domain_version.rb + + class << self + def pw_for(domain_name) + select("names -> '#{domain_name}' AS pw").first.try(:pw) + end + end end diff --git a/app/validators/domain_name_validator.rb b/app/validators/domain_name_validator.rb index ff6ef69f6..79fec0291 100644 --- a/app/validators/domain_name_validator.rb +++ b/app/validators/domain_name_validator.rb @@ -1,17 +1,11 @@ class DomainNameValidator < ActiveModel::EachValidator - # rubocop: disable Metrics/PerceivedComplexity - # rubocop: disable Metrics/CyclomaticComplexity def validate_each(record, attribute, value) if !self.class.validate_format(value) record.errors[attribute] << (options[:message] || record.errors.generate_message(attribute, :invalid)) elsif !self.class.validate_blocked(value) record.errors.add(attribute, (options[:message] || record.errors.generate_message(attribute, :blocked))) - elsif !self.class.validate_reservation(value) - record.errors.add(attribute, (options[:message] || record.errors.generate_message(attribute, :reserved))) end end - # rubocop: enable Metrics/PerceivedComplexity - # rubocop: enable Metrics/CyclomaticComplexity class << self def validate_format(value) @@ -41,10 +35,5 @@ class DomainNameValidator < ActiveModel::EachValidator return true unless value BlockedDomain.where("names @> ?::varchar[]", "{#{value}}").count == 0 end - - def validate_reservation(value) - return true unless value - !ReservedDomain.exists?(name: value.mb_chars.downcase.strip) - end end end diff --git a/app/views/admin/reserved_domains/index.haml b/app/views/admin/reserved_domains/index.haml new file mode 100644 index 000000000..9dd6955bd --- /dev/null +++ b/app/views/admin/reserved_domains/index.haml @@ -0,0 +1,10 @@ += render 'shared/title', name: t(:reserved_domains) + += form_tag([:admin, :reserved_domains]) do |f| + .row + .col-md-12 + = text_area_tag :reserved_domains, @reserved_domains, class: 'form-control', rows: 30 + %hr + .row + .col-md-12.text-right + %button.btn.btn-warning=t(:save) diff --git a/app/views/layouts/admin/application.haml b/app/views/layouts/admin/application.haml index 8fac692f5..da411864c 100644 --- a/app/views/layouts/admin/application.haml +++ b/app/views/layouts/admin/application.haml @@ -60,6 +60,7 @@ %li= link_to t(:settings), admin_settings_path %li= link_to t(:zonefile), admin_zonefile_settings_path %li= link_to t(:blocked_domains), admin_blocked_domains_path + %li= link_to t(:reserved_domains), admin_reserved_domains_path -# %li= link_to t(:domains_history), admin_domain_versions_path %li= link_to t(:epp_logs), admin_epp_logs_path %li= link_to t(:repp_logs), admin_repp_logs_path diff --git a/app/views/registrar/domains/form_partials/_general.haml b/app/views/registrar/domains/form_partials/_general.haml index bde4ff67f..8057a1848 100644 --- a/app/views/registrar/domains/form_partials/_general.haml +++ b/app/views/registrar/domains/form_partials/_general.haml @@ -5,7 +5,7 @@ = label_tag :domain_name, t(:name), class: 'required' .col-md-7 - readonly = params[:domain_name] ? true : false - = text_field_tag('domain[name]', @domain_params[:name], + = text_field_tag('domain[name]', @domain_params[:name], class: 'form-control', readonly: readonly, required: true) - unless params[:domain_name] @@ -13,13 +13,20 @@ .col-md-3.control-label = label_tag :domain_period, t(:period), class: 'required' .col-md-7 - = select_tag 'domain[period]', + = select_tag 'domain[period]', options_for_select(Depp::Domain::PERIODS, @domain_params[:period]), { class: 'form-control' } .form-group .col-md-3.control-label = label_tag :domain_registrant, t(:registrant), class: 'required' .col-md-7 - = select_tag "domain[registrant]", + = select_tag "domain[registrant]", options_for_select(@contacts_autocomplete_map, selected: @domain_params[:registrant]), include_blank: true, class: 'js-combobox', required: true + + - unless params[:domain_name] + .form-group + .col-md-3.control-label + = label_tag :domain_reserved_pw, t(:reserved_pw) + .col-md-7 + = text_field_tag('domain[reserved_pw]', @domain_params[:reserved_pw], class: 'form-control') diff --git a/app/views/registrar/domains/transfer_index.haml b/app/views/registrar/domains/transfer_index.haml index ecc5ff1a4..ccdfea305 100644 --- a/app/views/registrar/domains/transfer_index.haml +++ b/app/views/registrar/domains/transfer_index.haml @@ -22,6 +22,6 @@ = file_field_tag 'legal_document' .form-group .col-md-10.text-right - %button.btn.btn-warning{ name: 'query' }= t(:transfer) + %button.btn.btn-warning{ name: 'request' }= t(:transfer) /%button.btn.btn-warning{ name: 'approve' }= t(:approve) /%button.btn.btn-warning{ name: 'reject' }= t(:reject) diff --git a/config/locales/en.yml b/config/locales/en.yml index bd358aaac..5c2bcd344 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -60,6 +60,8 @@ en: ds_data_not_allowed: 'dsData object is not allowed' ds_data_with_key_not_allowed: 'dsData object with key data is not allowed' key_data_not_allowed: 'keyData object is not allowed' + required_parameter_missing_reserved: 'Required parameter missing; reserved>pw element required for reserved domains' + invalid_auth_information_reserved: 'Invalid authorization information; invalid reserved>pw value' name_dirty: invalid: 'Domain name is invalid' reserved: 'Domain name is reserved' @@ -238,7 +240,7 @@ en: errors: messages: blank: 'is missing' - epp_domain_reserved: 'Domain name is reserved or restricted' + epp_domain_reserved: 'Domain name is reserved' epp_obj_does_not_exist: 'Object does not exist' epp_command_failed: 'Command failed' epp_authorization_error: 'Authorization error' @@ -861,3 +863,7 @@ en: receipt_date_until: 'Receipt date until' add_credit: 'Add credit' export_csv: 'Export CSV' + reserved_domains: 'Reserved domains' + invalid_yaml: 'Invalid YAML' + reserved_pw: 'Reserved pw' + no_transfers_found: 'No transfers found' diff --git a/config/routes.rb b/config/routes.rb index e7ad5a63b..96cddbdf2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -190,6 +190,7 @@ Rails.application.routes.draw do resources :settings resources :blocked_domains + resources :reserved_domains resources :registrars do resources :api_users diff --git a/db/migrate/20150707104937_refactor_reserved_domains.rb b/db/migrate/20150707104937_refactor_reserved_domains.rb new file mode 100644 index 000000000..6f6c00682 --- /dev/null +++ b/db/migrate/20150707104937_refactor_reserved_domains.rb @@ -0,0 +1,6 @@ +class RefactorReservedDomains < ActiveRecord::Migration + def change + remove_column :reserved_domains, :name + add_column :reserved_domains, :names, :hstore + end +end diff --git a/db/migrate/20150707154543_increase_decimal_precision.rb b/db/migrate/20150707154543_increase_decimal_precision.rb new file mode 100644 index 000000000..47cf59997 --- /dev/null +++ b/db/migrate/20150707154543_increase_decimal_precision.rb @@ -0,0 +1,11 @@ +class IncreaseDecimalPrecision < ActiveRecord::Migration + def change + change_column :account_activities, :sum, :decimal, precision: 10, scale: 2 + change_column :accounts, :balance, :decimal, precision: 10, scale: 2, default: 0.0, null: false + change_column :bank_transactions, :sum, :decimal, precision: 10, scale: 2 + change_column :banklink_transactions, :vk_amount, :decimal, precision: 10, scale: 2 + change_column :invoice_items, :price, :decimal, precision: 10, scale: 2 + change_column :invoices, :vat_prc, :decimal, precision: 10, scale: 2 + change_column :invoices, :sum_cache, :decimal, precision: 10, scale: 2 + end +end diff --git a/db/migrate/20150709092549_add_reserved_field_to_domain.rb b/db/migrate/20150709092549_add_reserved_field_to_domain.rb new file mode 100644 index 000000000..676253575 --- /dev/null +++ b/db/migrate/20150709092549_add_reserved_field_to_domain.rb @@ -0,0 +1,5 @@ +class AddReservedFieldToDomain < ActiveRecord::Migration + def change + add_column :domains, :reserved, :boolean, default: false + end +end diff --git a/db/schema-read-only.rb b/db/schema-read-only.rb index 768be3160..21e70ef04 100644 --- a/db/schema-read-only.rb +++ b/db/schema-read-only.rb @@ -11,10 +11,11 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20150706091724) do +ActiveRecord::Schema.define(version: 20150709092549) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + enable_extension "hstore" create_table "account_activities", force: :cascade do |t| t.integer "account_id" @@ -212,6 +213,12 @@ ActiveRecord::Schema.define(version: 20150706091724) do t.string "updator_str" end + create_table "data_migrations", id: false, force: :cascade do |t| + t.string "version", null: false + end + + add_index "data_migrations", ["version"], name: "unique_data_migrations", unique: true, using: :btree + create_table "delegation_signers", force: :cascade do |t| t.integer "domain_id" t.string "key_tag" @@ -316,7 +323,8 @@ ActiveRecord::Schema.define(version: 20150706091724) do t.string "registrant_verification_token" t.json "pending_json" t.datetime "force_delete_at" - t.string "statuses", array: true + t.string "statuses", array: true + t.boolean "reserved", default: false end add_index "domains", ["delete_at"], name: "index_domains_on_delete_at", using: :btree @@ -978,11 +986,11 @@ ActiveRecord::Schema.define(version: 20150706091724) do add_index "registrars", ["code"], name: "index_registrars_on_code", using: :btree create_table "reserved_domains", force: :cascade do |t| - t.string "name" t.datetime "created_at" t.datetime "updated_at" t.string "creator_str" t.string "updator_str" + t.hstore "names" end create_table "settings", force: :cascade do |t| @@ -1020,7 +1028,7 @@ ActiveRecord::Schema.define(version: 20150706091724) do t.text "crt" t.string "type" t.string "registrant_ident" - t.string "encrypted_password", default: "" + t.string "encrypted_password", default: "", null: false t.datetime "remember_created_at" t.integer "failed_attempts", default: 0, null: false t.datetime "locked_at" diff --git a/db/structure.sql b/db/structure.sql index 7b0a41ae6..f102344a1 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -23,6 +23,20 @@ CREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog; COMMENT ON EXTENSION plpgsql IS 'PL/pgSQL procedural language'; +-- +-- Name: hstore; Type: EXTENSION; Schema: -; Owner: - +-- + +CREATE EXTENSION IF NOT EXISTS hstore WITH SCHEMA public; + + +-- +-- Name: EXTENSION hstore; Type: COMMENT; Schema: -; Owner: - +-- + +COMMENT ON EXTENSION hstore IS 'data type for storing sets of (key, value) pairs'; + + SET search_path = public, pg_catalog; -- @@ -41,7 +55,7 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text ret text; BEGIN -- define filters - include_filter = '%' || i_origin; + include_filter = '%.' || i_origin; -- for %.%.% IF i_origin ~ '\.' THEN @@ -74,7 +88,7 @@ CREATE FUNCTION generate_zonefile(i_origin character varying) RETURNS text 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 + WHERE d.name LIKE include_filter AND d.name NOT LIKE exclude_filter OR d.name = i_origin ORDER BY d.name ), chr(10) @@ -237,7 +251,7 @@ CREATE TABLE accounts ( id integer NOT NULL, registrar_id integer, account_type character varying, - balance numeric(10,2) DEFAULT 0 NOT NULL, + balance numeric(10,2) DEFAULT 0.0 NOT NULL, created_at timestamp without time zone, updated_at timestamp without time zone, currency character varying, @@ -673,6 +687,15 @@ CREATE SEQUENCE countries_id_seq ALTER SEQUENCE countries_id_seq OWNED BY countries.id; +-- +-- Name: data_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE data_migrations ( + version character varying NOT NULL +); + + -- -- Name: delegation_signers; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -919,7 +942,8 @@ CREATE TABLE domains ( registrant_verification_token character varying, pending_json json, force_delete_at timestamp without time zone, - statuses character varying[] + statuses character varying[], + reserved boolean DEFAULT false ); @@ -2358,7 +2382,7 @@ CREATE TABLE pricelists ( id integer NOT NULL, "desc" character varying, category character varying, - price_cents numeric(10,2) DEFAULT 0 NOT NULL, + price_cents numeric(10,2) DEFAULT 0.0 NOT NULL, price_currency character varying DEFAULT 'EUR'::character varying NOT NULL, valid_from timestamp without time zone, valid_to timestamp without time zone, @@ -2497,11 +2521,11 @@ ALTER SEQUENCE registrars_id_seq OWNED BY registrars.id; CREATE TABLE reserved_domains ( id integer NOT NULL, - name character varying, created_at timestamp without time zone, updated_at timestamp without time zone, creator_str character varying, - updator_str character varying + updator_str character varying, + names hstore ); @@ -2596,7 +2620,7 @@ CREATE TABLE users ( crt text, type character varying, registrant_ident character varying, - encrypted_password character varying DEFAULT ''::character varying, + encrypted_password character varying DEFAULT ''::character varying NOT NULL, remember_created_at timestamp without time zone, failed_attempts integer DEFAULT 0 NOT NULL, locked_at timestamp without time zone @@ -4452,6 +4476,13 @@ CREATE INDEX index_whois_records_on_domain_id ON whois_records USING btree (doma CREATE INDEX index_whois_records_on_registrar_id ON whois_records USING btree (registrar_id); +-- +-- Name: unique_data_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX unique_data_migrations ON data_migrations USING btree (version); + + -- -- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -4667,8 +4698,6 @@ INSERT INTO schema_migrations (version) VALUES ('20150227092508'); INSERT INTO schema_migrations (version) VALUES ('20150227113121'); -INSERT INTO schema_migrations (version) VALUES ('20150302130224'); - INSERT INTO schema_migrations (version) VALUES ('20150302161712'); INSERT INTO schema_migrations (version) VALUES ('20150303130729'); @@ -4727,8 +4756,6 @@ INSERT INTO schema_migrations (version) VALUES ('20150417082723'); INSERT INTO schema_migrations (version) VALUES ('20150421134820'); -INSERT INTO schema_migrations (version) VALUES ('20150422090645'); - INSERT INTO schema_migrations (version) VALUES ('20150422092514'); INSERT INTO schema_migrations (version) VALUES ('20150422132631'); @@ -4773,8 +4800,6 @@ INSERT INTO schema_migrations (version) VALUES ('20150519115050'); INSERT INTO schema_migrations (version) VALUES ('20150519140853'); -INSERT INTO schema_migrations (version) VALUES ('20150519142542'); - INSERT INTO schema_migrations (version) VALUES ('20150519144118'); INSERT INTO schema_migrations (version) VALUES ('20150520163237'); @@ -4783,12 +4808,6 @@ INSERT INTO schema_migrations (version) VALUES ('20150520164507'); INSERT INTO schema_migrations (version) VALUES ('20150521120145'); -INSERT INTO schema_migrations (version) VALUES ('20150522164020'); - -INSERT INTO schema_migrations (version) VALUES ('20150525075550'); - -INSERT INTO schema_migrations (version) VALUES ('20150603141054'); - INSERT INTO schema_migrations (version) VALUES ('20150603141549'); INSERT INTO schema_migrations (version) VALUES ('20150603211318'); @@ -4810,3 +4829,10 @@ INSERT INTO schema_migrations (version) VALUES ('20150701074344'); INSERT INTO schema_migrations (version) VALUES ('20150703084632'); INSERT INTO schema_migrations (version) VALUES ('20150706091724'); + +INSERT INTO schema_migrations (version) VALUES ('20150707104937'); + +INSERT INTO schema_migrations (version) VALUES ('20150707154543'); + +INSERT INTO schema_migrations (version) VALUES ('20150709092549'); + diff --git a/doc/schemas/eis-1.0.xsd b/doc/schemas/eis-1.0.xsd index 262d94581..2612b5e57 100644 --- a/doc/schemas/eis-1.0.xsd +++ b/doc/schemas/eis-1.0.xsd @@ -15,22 +15,40 @@ Child elements found in EPP commands. --> - + - + + + + + + + + + + + + + + + + + diff --git a/spec/epp/domain_spec.rb b/spec/epp/domain_spec.rb index d4430ac15..c19c9cbff 100644 --- a/spec/epp/domain_spec.rb +++ b/spec/epp/domain_spec.rb @@ -144,6 +144,7 @@ describe 'EPP Domain', epp: true do response[:result_code].should == '1000' d = Domain.last d.legal_documents.count.should == 1 + d.reserved.should == false end # it 'creates ria.ee with valid ds record' do @@ -224,9 +225,47 @@ describe 'EPP Domain', epp: true do xml = domain_create_xml(name: { value: '1162.ee' }) response = epp_plain_request(xml) - response[:result_code].should == '2302' - response[:msg].should == 'Domain name is reserved [name_dirty]' + response[:msg].should == 'Required parameter missing; reserved>pw element required for reserved domains' + response[:result_code].should == '2003' response[:clTRID].should == 'ABC-12345' + + xml = domain_create_xml({name: { value: '1162.ee' }}, {}, { + _anonymus: [ + legalDocument: { + value: 'dGVzdCBmYWlsCg==', + attrs: { type: 'pdf' } + }, + reserved: { + pw: { value: 'wrong_pw' } + } + ] + }) + + response = epp_plain_request(xml) + response[:msg].should == 'Invalid authorization information; invalid reserved>pw value' + response[:result_code].should == '2202' + end + + it 'creates a reserved domain with correct auth info' do + xml = domain_create_xml({name: { value: '1162.ee' }}, {}, { + _anonymus: [ + legalDocument: { + value: 'dGVzdCBmYWlsCg==', + attrs: { type: 'pdf' } + }, + reserved: { + pw: { value: 'abc' } + } + ] + }) + + response = epp_plain_request(xml) + response[:msg].should == 'Command completed successfully' + response[:result_code].should == '1000' + + d = Domain.last + d.statuses.should match_array(['ok']) + d.reserved.should == true end it 'does not create blocked domain' do @@ -800,7 +839,7 @@ describe 'EPP Domain', epp: true do xml = domain_transfer_xml({ name: { value: domain.name }, authInfo: { pw: { value: pw } } - }, 'query', { + }, 'request', { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -848,7 +887,7 @@ describe 'EPP Domain', epp: true do xml = domain_transfer_xml({ name: { value: domain.name }, authInfo: { pw: { value: pw } } - }, 'query', { + }, 'request', { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -926,7 +965,7 @@ describe 'EPP Domain', epp: true do xml = domain_transfer_xml({ name: { value: domain.name }, authInfo: { pw: { value: pw } } - }, 'query', { + }, 'request', { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -1362,7 +1401,7 @@ describe 'EPP Domain', epp: true do xml = domain_transfer_xml({ name: { value: domain.name }, authInfo: { pw: { value: 'test' } } - }, 'query', { + }, 'request', { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -1376,12 +1415,12 @@ describe 'EPP Domain', epp: true do response[:msg].should == 'Authorization error' end - it 'ignores transfer wha registrant registrar requests transfer' do + it 'ignores transfer when domain already belongs to registrar' do pw = domain.auth_info xml = domain_transfer_xml({ name: { value: domain.name }, authInfo: { pw: { value: pw } } - }, 'query', { + }, 'request', { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -1407,7 +1446,7 @@ describe 'EPP Domain', epp: true do xml = domain_transfer_xml({ name: { value: domain.name }, authInfo: { pw: { value: pw } } - }, 'query', { + }, 'request', { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -1419,8 +1458,8 @@ describe 'EPP Domain', epp: true do login_as :registrar2 do epp_plain_request(xml) # transfer domain response = epp_plain_request(xml) # attempt second transfer - response[:result_code].should == '2201' response[:msg].should == 'Authorization error' + response[:result_code].should == '2201' end end @@ -1439,10 +1478,118 @@ describe 'EPP Domain', epp: true do }) response = epp_plain_request(xml) - response[:msg].should == 'Pending transfer was not found' + response[:msg].should == 'No transfers found' response[:result_code].should == '2303' end + it 'should not return transfers when there are none' do + xml = domain_transfer_xml({ + name: { value: domain.name }, + authInfo: { pw: { value: domain.auth_info } } + }, 'query') + + response = epp_plain_request(xml) + response[:results][0][:msg].should == 'No transfers found' + response[:results][0][:result_code].should == '2303' + end + + it 'should allow querying domain transfer' do + Setting.transfer_wait_time = 1 + pw = domain.auth_info + xml = domain_transfer_xml({ + name: { value: domain.name }, + authInfo: { pw: { value: pw } } + }, 'request', { + _anonymus: [ + legalDocument: { + value: 'dGVzdCBmYWlsCg==', + attrs: { type: 'pdf' } + } + ] + }) + + login_as :registrar2 do + response = epp_plain_request(xml) + response[:results][0][:msg].should == 'Command completed successfully' + response[:results][0][:result_code].should == '1000' + + trn_data = response[:parsed].css('trnData') + + dtl = domain.domain_transfers.last + + trn_data.css('name').text.should == domain.name + trn_data.css('trStatus').text.should == 'pending' + trn_data.css('reID').text.should == 'REGDOMAIN2' + trn_data.css('reDate').text.should == dtl.transfer_requested_at.in_time_zone.utc.utc.iso8601 + trn_data.css('acDate').text.should == dtl.wait_until.in_time_zone.utc.utc.iso8601 + trn_data.css('acID').text.should == 'REGDOMAIN1' + trn_data.css('exDate').text.should == domain.valid_to.in_time_zone.utc.utc.iso8601 + + xml = domain_transfer_xml({ + name: { value: domain.name }, + authInfo: { pw: { value: pw } } + }, 'query') + + response = epp_plain_request(xml) + response[:results][0][:msg].should == 'Command completed successfully' + response[:results][0][:result_code].should == '1000' + + trn_data = response[:parsed].css('trnData') + + dtl = domain.domain_transfers.last + trn_data.css('name').text.should == domain.name + trn_data.css('trStatus').text.should == 'pending' + trn_data.css('reID').text.should == 'REGDOMAIN2' + trn_data.css('reDate').text.should == dtl.transfer_requested_at.in_time_zone.utc.utc.iso8601 + trn_data.css('acDate').text.should == dtl.wait_until.in_time_zone.utc.utc.iso8601 + trn_data.css('acID').text.should == 'REGDOMAIN1' + trn_data.css('exDate').text.should == domain.valid_to.in_time_zone.utc.utc.iso8601 + end + + # approves pending transfer + xml = domain_transfer_xml({ + name: { value: domain.name }, + authInfo: { pw: { value: pw } } + }, 'approve', { + _anonymus: [ + legalDocument: { + value: 'dGVzdCBmYWlsCg==', + attrs: { type: 'pdf' } + } + ] + }) + + response = epp_plain_request(xml) + response[:results][0][:msg].should == 'Command completed successfully' + response[:results][0][:result_code].should == '1000' + + # query should return last completed transfer + domain.reload + pw = domain.auth_info + xml = domain_transfer_xml({ + name: { value: domain.name }, + authInfo: { pw: { value: pw } } + }, 'query') + + response = epp_plain_request(xml) + response[:results][0][:msg].should == 'Command completed successfully' + response[:results][0][:result_code].should == '1000' + + trn_data = response[:parsed].css('trnData') + + dtl = domain.domain_transfers.last + + trn_data.css('name').text.should == domain.name + trn_data.css('trStatus').text.should == 'clientApproved' + trn_data.css('reID').text.should == 'REGDOMAIN2' + trn_data.css('reDate').text.should == dtl.transfer_requested_at.in_time_zone.utc.utc.iso8601 + trn_data.css('acDate').text.should == dtl.transferred_at.in_time_zone.utc.utc.iso8601 + trn_data.css('acID').text.should == 'REGDOMAIN1' + trn_data.css('exDate').text.should == domain.valid_to.in_time_zone.utc.utc.iso8601 + + Setting.transfer_wait_time = 0 + end + ### UPDATE ### it 'should update right away without update pending status' do existing_pw = domain.auth_info diff --git a/spec/epp/epp_helper_spec.rb b/spec/epp/epp_helper_spec.rb index 65a9fcc8d..7b85a1ab1 100644 --- a/spec/epp/epp_helper_spec.rb +++ b/spec/epp/epp_helper_spec.rb @@ -10,7 +10,7 @@ describe 'EPP Helper', epp: true do expected = Nokogiri::XML(' - + ' + dn + ' diff --git a/spec/fabricators/reserved_domain_fabricator.rb b/spec/fabricators/reserved_domain_fabricator.rb index f14948902..672fa3e53 100644 --- a/spec/fabricators/reserved_domain_fabricator.rb +++ b/spec/fabricators/reserved_domain_fabricator.rb @@ -1,3 +1,3 @@ Fabricator(:reserved_domain) do - name '1162.ee' + names { { '1162.ee': 'abc' } } end diff --git a/spec/features/admin/reserved_domain_spec.rb b/spec/features/admin/reserved_domain_spec.rb new file mode 100644 index 000000000..9c780285f --- /dev/null +++ b/spec/features/admin/reserved_domain_spec.rb @@ -0,0 +1,43 @@ +require 'rails_helper' + +feature 'ReservedDomain', type: :feature do + before :all do + @user = Fabricate(:admin_user) + end + + before do + sign_in @user + end + + it 'should manage reserved domains' do + visit admin_reserved_domains_url + page.should have_content('Reserved domains') + + d = Fabricate.build(:domain, name: '110.ee') + d.valid? + d.errors.full_messages.should match_array([]) + + fill_in 'reserved_domains', with: "110.ee: testpw" + click_button 'Save' + + page.should have_content('Record updated') + page.should have_content('110.ee: testpw') + + d.valid?.should == false + d.errors.full_messages.should match_array( + ["Required parameter missing; reserved>pw element required for reserved domains"] + ) + + d.reserved_pw = 'wrongpw' + d.valid?.should == false + + d.reserved_pw = 'testpw' + d.valid?.should == true + d.errors.full_messages.should match_array([]) + + d.save + visit admin_reserved_domains_url + page.should have_content('110.ee') + page.should_not have_content('110.ee: testpw') + end +end diff --git a/spec/support/epp.rb b/spec/support/epp.rb index 5e9847d48..698284735 100644 --- a/spec/support/epp.rb +++ b/spec/support/epp.rb @@ -144,7 +144,7 @@ module Epp end # rubocop: disable Metrics/MethodLength - def domain_create_xml(xml_params = {}, dnssec_params = {}) + def domain_create_xml(xml_params = {}, dnssec_params = {}, custom_params = {}) defaults = { name: { value: next_domain_name }, period: { value: '1', attrs: { unit: 'y' } }, @@ -185,7 +185,7 @@ module Epp dnssec_params = dnssec_defaults.deep_merge(dnssec_params) if dnssec_params != false - custom_params = { + custom_defaults = { _anonymus: [ legalDocument: { value: 'dGVzdCBmYWlsCg==', @@ -194,6 +194,8 @@ module Epp ] } + custom_params = custom_defaults.deep_merge(custom_params) if custom_params != false + epp_xml = EppXml::Domain.new(cl_trid: 'ABC-12345') epp_xml.create(xml_params, dnssec_params, custom_params) end @@ -347,7 +349,7 @@ module Epp epp_xml.check(xml_params) end - def domain_transfer_xml(xml_params = {}, op = 'query', custom_params = {}) + def domain_transfer_xml(xml_params = {}, op = 'request', custom_params = {}) defaults = { name: { value: next_domain_name }, authInfo: {