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: {