diff --git a/.rubocop.yml b/.rubocop.yml index cc32da4b9..3d8fd0b90 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1 +1,4 @@ inherit_from: .rubocop_todo.yml + +Style/Alias: + EnforcedStyle: prefer_alias_method diff --git a/app/api/repp/domain_transfers_v1.rb b/app/api/repp/domain_transfers_v1.rb index eca21b62d..c6a48df6d 100644 --- a/app/api/repp/domain_transfers_v1.rb +++ b/app/api/repp/domain_transfers_v1.rb @@ -25,7 +25,7 @@ module Repp if domain if domain.transfer_code == transfer_code - domain.transfer(new_registrar) + DomainTransfer.request(domain, new_registrar) successful_domain_transfers << { type: 'domain_transfer', attributes: { domain_name: domain.name } } else errors << { title: "#{domain_name} transfer code is wrong" } diff --git a/app/controllers/epp/domains_controller.rb b/app/controllers/epp/domains_controller.rb index 02c75c7da..3b8b94155 100644 --- a/app/controllers/epp/domains_controller.rb +++ b/app/controllers/epp/domains_controller.rb @@ -142,6 +142,13 @@ class Epp::DomainsController < EppController authorize! :transfer, @domain, @password action = params[:parsed_frame].css('transfer').first[:op] + if @domain.non_transferable? + throw :epp_error, { + code: '2304', + msg: I18n.t(:object_status_prohibits_operation) + } + end + @domain_transfer = @domain.transfer(params[:parsed_frame], action, current_user) if @domain_transfer diff --git a/app/controllers/epp/polls_controller.rb b/app/controllers/epp/polls_controller.rb index fb032975f..44f8afdc1 100644 --- a/app/controllers/epp/polls_controller.rb +++ b/app/controllers/epp/polls_controller.rb @@ -6,6 +6,8 @@ class Epp::PollsController < EppController ack_poll if params[:parsed_frame].css('poll').first['op'] == 'ack' end + private + def req_poll @message = current_user.queued_messages.last @@ -49,8 +51,6 @@ class Epp::PollsController < EppController render_epp_response 'epp/poll/poll_ack' end - private - def validate_poll requires_attribute 'poll', 'op', values: %(ack req), allow_blank: true end diff --git a/app/controllers/epp_controller.rb b/app/controllers/epp_controller.rb index eee6cef7a..36bdcd6cc 100644 --- a/app/controllers/epp_controller.rb +++ b/app/controllers/epp_controller.rb @@ -335,7 +335,6 @@ class EppController < ApplicationController # rubocop: disable Metrics/CyclomaticComplexity # rubocop: disable Metrics/PerceivedComplexity def write_to_epp_log - # return nil if EPP_LOG_ENABLED request_command = params[:command] || params[:action] # error receives :command, other methods receive :action frame = params[:raw_frame] || params[:frame] diff --git a/app/models/concerns/domain/transferable.rb b/app/models/concerns/domain/transferable.rb index 62b70a71b..f2e7736c2 100644 --- a/app/models/concerns/domain/transferable.rb +++ b/app/models/concerns/domain/transferable.rb @@ -2,31 +2,18 @@ module Concerns::Domain::Transferable extend ActiveSupport::Concern included do - after_initialize :generate_transfer_code, if: 'new_record? && transfer_code.blank?' + after_initialize :generate_transfer_code, if: :generate_transfer_code? + end + + def non_transferable? + !transferable? end def transfer(new_registrar) - old_registrar = registrar - self.registrar = new_registrar regenerate_transfer_code - contact_codes = contacts.pluck(:code).sort.uniq - registrant_code = registrant.code - transaction do - old_registrar.messages.create!( - body: I18n.t('domain_transfer_was_approved', contacts: contact_codes, registrant: registrant_code), - attached_obj_id: id, - attached_obj_type: self.class.name - ) - - domain_transfers.create!( - transfer_requested_at: Time.zone.now, - old_registrar: old_registrar, - new_registrar: new_registrar - ) - transfer_contacts(new_registrar) save! end @@ -34,6 +21,24 @@ module Concerns::Domain::Transferable private + def transferable? + (statuses & [ + DomainStatus::PENDING_DELETE_CONFIRMATION, + DomainStatus::PENDING_CREATE, + DomainStatus::PENDING_UPDATE, + DomainStatus::PENDING_DELETE, + DomainStatus::PENDING_RENEW, + DomainStatus::PENDING_TRANSFER, + DomainStatus::FORCE_DELETE, + DomainStatus::SERVER_TRANSFER_PROHIBITED, + DomainStatus::CLIENT_TRANSFER_PROHIBITED + ]).empty? + end + + def generate_transfer_code? + new_record? && transfer_code.blank? + end + def generate_transfer_code self.transfer_code = SecureRandom.hex end diff --git a/app/models/domain.rb b/app/models/domain.rb index 31ba838f2..54dfe608e 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -49,7 +49,7 @@ class Domain < ActiveRecord::Base accepts_nested_attributes_for :domain_statuses, allow_destroy: true, reject_if: proc { |attrs| attrs[:value].blank? } - has_many :domain_transfers, dependent: :destroy + has_many :transfers, class_name: 'DomainTransfer', dependent: :destroy has_many :dnskeys, dependent: :destroy @@ -280,7 +280,7 @@ class Domain < ActiveRecord::Base end def pending_transfer - domain_transfers.find_by(status: DomainTransfer::PENDING) + transfers.find_by(status: DomainTransfer::PENDING) end def server_holdable? diff --git a/app/models/domain_transfer.rb b/app/models/domain_transfer.rb index 6dd539bb8..6982f36b6 100644 --- a/app/models/domain_transfer.rb +++ b/app/models/domain_transfer.rb @@ -10,6 +10,26 @@ class DomainTransfer < ActiveRecord::Base SERVER_APPROVED = 'serverApproved' before_create :set_wait_until + + class << self + def request(domain, new_registrar) + domain_transfer = create!( + transfer_requested_at: Time.zone.now, + domain: domain, + old_registrar: domain.registrar, + new_registrar: new_registrar + ) + + domain_transfer.approve if approve_automatically? + end + + private + + def approve_automatically? + Setting.transfer_wait_time.zero? + end + end + def set_wait_until wait_time = Setting.transfer_wait_time return if wait_time == 0 @@ -17,6 +37,7 @@ class DomainTransfer < ActiveRecord::Base end before_create :set_status + def set_status if Setting.transfer_wait_time > 0 self.status = PENDING unless status @@ -36,11 +57,29 @@ class DomainTransfer < ActiveRecord::Base status == PENDING end - def notify_losing_registrar(contacts, registrant) + def approve + transaction do + self.status = SERVER_APPROVED + save! + + notify_old_registrar + domain.transfer(new_registrar) + end + end + + private + + def notify_old_registrar + old_contacts_codes = domain.contacts.pluck(:code).sort.uniq.join(', ') + old_registrant_code = domain.registrant.code + old_registrar.messages.create!( - body: I18n.t('domain_transfer_was_approved', contacts: contacts, registrant: registrant), + body: I18n.t('messages.texts.domain_transfer', + domain_name: domain.name, + old_contacts_codes: old_contacts_codes, + old_registrant_code: old_registrant_code), attached_obj_id: id, - attached_obj_type: self.class.to_s + attached_obj_type: self.class.name ) end end diff --git a/app/models/epp/domain.rb b/app/models/epp/domain.rb index a59094d1e..8c9e8bcc8 100644 --- a/app/models/epp/domain.rb +++ b/app/models/epp/domain.rb @@ -628,7 +628,7 @@ class Epp::Domain < Domain case action when 'query' - return domain_transfers.last if domain_transfers.any? + return transfers.last if transfers.any? when 'request' return pending_transfer if pending_transfer return query_transfer(frame, current_user) @@ -644,13 +644,6 @@ class Epp::Domain < Domain # rubocop: disable Metrics/MethodLength # rubocop: disable Metrics/AbcSize def query_transfer(frame, current_user) - unless transferrable? - throw :epp_error, { - code: '2304', - msg: I18n.t(:object_status_prohibits_operation) - } - end - if current_user.registrar == registrar throw :epp_error, { code: '2002', @@ -658,11 +651,8 @@ class Epp::Domain < Domain } end - old_contact_codes = contacts.pluck(:code).sort.uniq - old_registrant_code = registrant.code - transaction do - dt = domain_transfers.create!( + dt = transfers.create!( transfer_requested_at: Time.zone.now, old_registrar: registrar, new_registrar: current_user.registrar @@ -677,8 +667,8 @@ class Epp::Domain < Domain end if dt.approved? + dt.send(:notify_old_registrar) transfer_contacts(current_user.registrar) - dt.notify_losing_registrar(old_contact_codes, old_registrant_code) regenerate_transfer_code self.registrar = current_user.registrar end @@ -811,20 +801,6 @@ class Epp::Domain < Domain true end - def transferrable? - (statuses & [ - DomainStatus::PENDING_DELETE_CONFIRMATION, - DomainStatus::PENDING_CREATE, - DomainStatus::PENDING_UPDATE, - DomainStatus::PENDING_DELETE, - DomainStatus::PENDING_RENEW, - DomainStatus::PENDING_TRANSFER, - DomainStatus::FORCE_DELETE, - DomainStatus::SERVER_TRANSFER_PROHIBITED, - DomainStatus::CLIENT_TRANSFER_PROHIBITED - ]).empty? - end - ## SHARED # For domain transfer diff --git a/app/models/message.rb b/app/models/message.rb index 10d823e63..1f01842c8 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -1,6 +1,6 @@ class Message < ActiveRecord::Base include Versions # version/message_version.rb - belongs_to :registrar + belongs_to :registrar, required: true before_create -> { self.queued = true } diff --git a/app/models/registrar.rb b/app/models/registrar.rb index 7646b2ceb..46022808f 100644 --- a/app/models/registrar.rb +++ b/app/models/registrar.rb @@ -137,15 +137,6 @@ class Registrar < ActiveRecord::Base cash_account.account_activities.create!(args) end - def domain_transfers - at = DomainTransfer.arel_table - DomainTransfer.where( - at[:new_registrar_id].eq(id).or( - at[:old_registrar_id].eq(id) - ) - ) - end - def address [street, city, state, zip].reject(&:blank?).compact.join(', ') end diff --git a/app/views/registrar/polls/show.haml b/app/views/registrar/polls/show.haml index 69e74751b..c4c337749 100644 --- a/app/views/registrar/polls/show.haml +++ b/app/views/registrar/polls/show.haml @@ -2,7 +2,7 @@ - msg_q = @data.css('msgQ').first .row .col-sm-12 - %h2= t('messages', count: msg_q['count']) + %h2= t '.header', count: msg_q['count'] %hr .row .col-md-12 @@ -75,7 +75,7 @@ - else .row .col-sm-12 - %h2= t('messages', count: 0) + %h2= t '.header', count: 0 %hr .row .col-md-12 diff --git a/config/initializers/initial_settings.rb b/config/initializers/initial_settings.rb index 94ff1dc7e..5ae521bc5 100644 --- a/config/initializers/initial_settings.rb +++ b/config/initializers/initial_settings.rb @@ -73,6 +73,3 @@ if con.present? && con.table_exists?('settings') Setting.save_default(:registry_swift, 'LHVBEE22') Setting.save_default(:registry_invoice_contact, 'Martti Õigus') end - -# dev only setting -EPP_LOG_ENABLED = true # !Rails.env.test? diff --git a/config/locales/en.yml b/config/locales/en.yml index da6df608a..c37cb9a48 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -214,20 +214,12 @@ en: blank: 'is missing' 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' - epp_authentication_error: 'Authentication error' epp_id_taken: 'Contact id already exists' epp_domain_not_found: 'Domain not found' epp_exp_dates_do_not_match: 'Given and current expire dates do not match' - epp_registrant_not_found: 'Registrant not found' - epp_command_syntax_error: 'Command syntax error' required_parameter_missing: 'Required parameter missing: %{key}' - attr_missing: 'Required parameter missing: %{key}' - repeating_postal_info: 'Only one of each postal info types may be provided' - invalid_type: 'PostalInfo type is invalid' unimplemented_command: 'Unimplemented command' - domain_exists_but_belongs_to_other_registrar: 'Domain exists but belongs to other registrar' required_ident_attribute_missing: "Required ident attribute missing: %{key}" invalid_iso31661_alpha2: does not conform to ISO 3166-1 alpha-2 standard invalid_iso8601_date: has invalid date format YYYY-MM-DD (ISO 8601) @@ -451,7 +443,6 @@ en: client_side_status_editing_error: 'Parameter value policy error. Client-side object status management not supported' switch_to: Switch to admin_menu: Admin - domain_transfer_was_approved: 'Domain transfer was approved, associated contacts were: %{contacts} and registrant was %{registrant}' business_registry_service_not_available: "Business Registry service Ärireg is not available" # DEPP @@ -526,7 +517,6 @@ en: address: 'Address' street: 'Street' city: 'City' - messages: 'Messages (%{count})' message: 'Message' message_no: 'Message #%{id}' queue_date: 'Queue date' @@ -754,7 +744,6 @@ en: parameter_value_range_error: 'Parameter value range error: %{key}' payment_received: 'Payment received' api_user_not_found: 'API user not found' - domain_already_belongs_to_the_querying_registrar: 'Domain already belongs to the querying registrar' notes: Notes active_price_for_this_operation_is: 'Active price for this operation is %{price}' active_price_missing_for_this_operation: 'Active price missing for this operation!' diff --git a/config/locales/messages.en.yml b/config/locales/messages.en.yml new file mode 100644 index 000000000..0c85bb49c --- /dev/null +++ b/config/locales/messages.en.yml @@ -0,0 +1,7 @@ +en: + messages: + texts: + domain_transfer: >- + Transfer of domain %{domain_name} has been approved. + It was associated with registrant %{old_registrant_code} + and contacts %{old_contacts_codes}. diff --git a/config/locales/registrar/polls.en.yml b/config/locales/registrar/polls.en.yml new file mode 100644 index 000000000..4d09e54f4 --- /dev/null +++ b/config/locales/registrar/polls.en.yml @@ -0,0 +1,5 @@ +en: + registrar: + polls: + show: + header: Messages (%{count}) diff --git a/db/migrate/20180211011450_change_messages_registrar_id_to_not_null.rb b/db/migrate/20180211011450_change_messages_registrar_id_to_not_null.rb new file mode 100644 index 000000000..962022ae0 --- /dev/null +++ b/db/migrate/20180211011450_change_messages_registrar_id_to_not_null.rb @@ -0,0 +1,5 @@ +class ChangeMessagesRegistrarIdToNotNull < ActiveRecord::Migration + def change + change_column_null :messages, :registrar_id, false + end +end diff --git a/db/migrate/20180211011948_add_messages_registrar_id_fk.rb b/db/migrate/20180211011948_add_messages_registrar_id_fk.rb new file mode 100644 index 000000000..af8df7b97 --- /dev/null +++ b/db/migrate/20180211011948_add_messages_registrar_id_fk.rb @@ -0,0 +1,5 @@ +class AddMessagesRegistrarIdFk < ActiveRecord::Migration + def change + add_foreign_key :messages, :registrars, name: 'messages_registrar_id_fk' + end +end diff --git a/db/migrate/20180214200224_add_domain_transfers_constraints.rb b/db/migrate/20180214200224_add_domain_transfers_constraints.rb new file mode 100644 index 000000000..bd4023deb --- /dev/null +++ b/db/migrate/20180214200224_add_domain_transfers_constraints.rb @@ -0,0 +1,7 @@ +class AddDomainTransfersConstraints < ActiveRecord::Migration + def change + change_column_null :domain_transfers, :domain_id, false + change_column_null :domain_transfers, :old_registrar_id, false + change_column_null :domain_transfers, :new_registrar_id, false + end +end diff --git a/db/migrate/20180214213743_change_messages_body_to_not_null.rb b/db/migrate/20180214213743_change_messages_body_to_not_null.rb new file mode 100644 index 000000000..4a09101f1 --- /dev/null +++ b/db/migrate/20180214213743_change_messages_body_to_not_null.rb @@ -0,0 +1,5 @@ +class ChangeMessagesBodyToNotNull < ActiveRecord::Migration + def change + change_column_null :messages, :body, false + end +end diff --git a/db/migrate/20180218004148_change_messages_attached_obj_id_type_to_int.rb b/db/migrate/20180218004148_change_messages_attached_obj_id_type_to_int.rb new file mode 100644 index 000000000..9996b5e67 --- /dev/null +++ b/db/migrate/20180218004148_change_messages_attached_obj_id_type_to_int.rb @@ -0,0 +1,5 @@ +class ChangeMessagesAttachedObjIdTypeToInt < ActiveRecord::Migration + def change + change_column :messages, :attached_obj_id, 'integer USING attached_obj_id::integer' + end +end diff --git a/db/structure.sql b/db/structure.sql index 449ec44f8..237c82e66 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -954,12 +954,12 @@ ALTER SEQUENCE domain_statuses_id_seq OWNED BY domain_statuses.id; CREATE TABLE domain_transfers ( id integer NOT NULL, - domain_id integer, + domain_id integer NOT NULL, status character varying, transfer_requested_at timestamp without time zone, transferred_at timestamp without time zone, - old_registrar_id integer, - new_registrar_id integer, + old_registrar_id integer NOT NULL, + new_registrar_id integer NOT NULL, created_at timestamp without time zone, updated_at timestamp without time zone, wait_until timestamp without time zone @@ -2183,10 +2183,10 @@ ALTER SEQUENCE mail_templates_id_seq OWNED BY mail_templates.id; CREATE TABLE messages ( id integer NOT NULL, - registrar_id integer, - body character varying, + registrar_id integer NOT NULL, + body character varying NOT NULL, attached_obj_type character varying, - attached_obj_id character varying, + attached_obj_id integer, queued boolean, created_at timestamp without time zone, updated_at timestamp without time zone, @@ -4524,6 +4524,14 @@ ALTER TABLE ONLY account_activities ADD CONSTRAINT fk_rails_d2cc3c2fa9 FOREIGN KEY (price_id) REFERENCES prices(id); +-- +-- Name: messages_registrar_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY messages + ADD CONSTRAINT messages_registrar_id_fk FOREIGN KEY (registrar_id) REFERENCES registrars(id); + + -- -- Name: user_registrar_id_fk; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -5086,6 +5094,10 @@ INSERT INTO schema_migrations (version) VALUES ('20180207071528'); INSERT INTO schema_migrations (version) VALUES ('20180207072139'); +INSERT INTO schema_migrations (version) VALUES ('20180211011450'); + +INSERT INTO schema_migrations (version) VALUES ('20180211011948'); + INSERT INTO schema_migrations (version) VALUES ('20180212123810'); INSERT INTO schema_migrations (version) VALUES ('20180212152810'); @@ -5094,3 +5106,9 @@ INSERT INTO schema_migrations (version) VALUES ('20180212154731'); INSERT INTO schema_migrations (version) VALUES ('20180213183818'); +INSERT INTO schema_migrations (version) VALUES ('20180214200224'); + +INSERT INTO schema_migrations (version) VALUES ('20180214213743'); + +INSERT INTO schema_migrations (version) VALUES ('20180218004148'); + diff --git a/doc/controllers_complete.svg b/doc/controllers_complete.svg index 68d02cf4a..765d4a08b 100644 --- a/doc/controllers_complete.svg +++ b/doc/controllers_complete.svg @@ -86,9 +86,7 @@ Epp::PollsController -ack_poll poll -req_poll _layout diff --git a/spec/factories/message.rb b/spec/factories/message.rb deleted file mode 100644 index 6ae235aaf..000000000 --- a/spec/factories/message.rb +++ /dev/null @@ -1,5 +0,0 @@ -FactoryBot.define do - factory :message do - body 'fabricator body' - end -end diff --git a/spec/models/message_spec.rb b/spec/models/message_spec.rb deleted file mode 100644 index a71988701..000000000 --- a/spec/models/message_spec.rb +++ /dev/null @@ -1,47 +0,0 @@ -require 'rails_helper' - -describe Message do - context 'with invalid attribute' do - before :all do - @mssage = Message.new - end - - it 'should not be valid' do - @mssage.valid? - @mssage.errors.full_messages.should match_array([ - "Body is missing" - ]) - end - - it 'should not have any versions' do - @mssage.versions.should == [] - end - end - - context 'with valid attributes' do - before :all do - @mssage = create(:message) - end - - it 'should be valid' do - @mssage.valid? - @mssage.errors.full_messages.should match_array([]) - end - - it 'should be valid twice' do - @mssage = create(:message) - @mssage.valid? - @mssage.errors.full_messages.should match_array([]) - end - - it 'should have one version' do - with_versioning do - @mssage.versions.should == [] - @mssage.body = 'New body' - @mssage.save - @mssage.errors.full_messages.should match_array([]) - @mssage.versions.size.should == 1 - end - end - end -end diff --git a/spec/requests/epp/domain/transfer/discarded_spec.rb b/spec/requests/epp/domain/transfer/discarded_spec.rb deleted file mode 100644 index 26596d993..000000000 --- a/spec/requests/epp/domain/transfer/discarded_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'EPP domain:transfer' do - let(:registrar) { create(:registrar) } - let(:user) { create(:api_user_epp, registrar: registrar) } - let(:session_id) { create(:epp_session, user: user).session_id } - let(:request_xml) { <<-XML - - - - - - test.com - - 98oiewslkfkd - - - - - - XML - } - - before :example do - login_as user - end - - context 'when domain is not discarded' do - let!(:domain) { create(:domain, name: 'test.com') } - - it 'returns epp code of 1000' do - post '/epp/command/transfer', { frame: request_xml }, 'HTTP_COOKIE' => "session=#{session_id}" - expect(response).to have_code_of(1000) - end - end - - context 'when domain is discarded' do - let!(:domain) { create(:domain_discarded, name: 'test.com') } - - it 'returns epp code of 2105' do - post '/epp/command/transfer', { frame: request_xml }, 'HTTP_COOKIE' => "session=#{session_id}" - expect(response).to have_code_of(2105) - end - end -end diff --git a/test/fixtures/contacts.yml b/test/fixtures/contacts.yml index 8c0fb4e10..eaf4401b7 100644 --- a/test/fixtures/contacts.yml +++ b/test/fixtures/contacts.yml @@ -9,6 +9,17 @@ john: code: john-001 auth_info: cacb5b +william: + name: William + email: william@inbox.test + phone: '+555.555' + ident: 1234 + ident_type: priv + ident_country_code: US + registrar: bestnames + code: william-001 + auth_info: 6573d0 + jane: name: Jane email: jane@mail.test diff --git a/test/fixtures/domain_contacts.yml b/test/fixtures/domain_contacts.yml index fd60e8c99..3442278a1 100644 --- a/test/fixtures/domain_contacts.yml +++ b/test/fixtures/domain_contacts.yml @@ -3,6 +3,11 @@ shop_jane: contact: jane type: AdminDomainContact +shop_william: + domain: shop + contact: william + type: TechDomainContact + airport_john: domain: airport contact: john diff --git a/test/fixtures/domain_transfers.yml b/test/fixtures/domain_transfers.yml new file mode 100644 index 000000000..c8b4181f2 --- /dev/null +++ b/test/fixtures/domain_transfers.yml @@ -0,0 +1,7 @@ +shop: + status: serverApproved + transfer_requested_at: 2010-07-05 + transferred_at: 2010-07-05 + domain: shop + old_registrar: bestnames + new_registrar: goodnames diff --git a/test/fixtures/messages.yml b/test/fixtures/messages.yml new file mode 100644 index 000000000..47cbdd0f2 --- /dev/null +++ b/test/fixtures/messages.yml @@ -0,0 +1,4 @@ +greeting: + body: Welcome! + queued: true + registrar: bestnames diff --git a/test/integration/api/domain_transfers_test.rb b/test/integration/api/domain_transfers_test.rb index 69d1e7d52..b90b59be4 100644 --- a/test/integration/api/domain_transfers_test.rb +++ b/test/integration/api/domain_transfers_test.rb @@ -1,11 +1,13 @@ require 'test_helper' class APIDomainTransfersTest < ActionDispatch::IntegrationTest - def test_transfers_domain - request_params = { format: :json, - data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } } + def setup + @domain = domains(:shop) + Setting.transfer_wait_time = 0 # Auto-approval + end + + def test_returns_domain_transfers post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } - assert_equal registrars(:goodnames), domains(:shop).registrar assert_response 200 assert_equal ({ data: [{ type: 'domain_transfer', @@ -16,6 +18,45 @@ class APIDomainTransfersTest < ActionDispatch::IntegrationTest JSON.parse(response.body, symbolize_names: true) end + def test_creates_new_domain_transfer + assert_difference -> { @domain.transfers.size } do + post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + end + end + + def test_approves_automatically_if_auto_approval_is_enabled + post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + assert @domain.transfers.last.approved? + end + + def test_changes_registrar + post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + @domain.reload + assert_equal registrars(:goodnames), @domain.registrar + end + + def test_regenerates_transfer_code + @old_transfer_code = @domain.transfer_code + + post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + @domain.reload + refute_equal @domain.transfer_code, @old_transfer_code + end + + def test_notifies_old_registrar + @old_registrar = @domain.registrar + + assert_difference -> { @old_registrar.messages.count } do + post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + end + end + + def test_duplicates_registrant_admin_and_tech_contacts + assert_difference 'Contact.count', 3 do + post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } + end + end + def test_fails_if_domain_does_not_exist request_params = { format: :json, data: { domainTransfers: [{ domainName: 'non-existent.test', transferCode: 'any' }] } } @@ -30,13 +71,18 @@ class APIDomainTransfersTest < ActionDispatch::IntegrationTest data: { domainTransfers: [{ domainName: 'shop.test', transferCode: 'wrong' }] } } post '/repp/v1/domain_transfers', request_params, { 'HTTP_AUTHORIZATION' => http_auth_key } assert_response 400 - refute_equal registrars(:goodnames), domains(:shop).registrar + refute_equal registrars(:goodnames), @domain.registrar assert_equal ({ errors: [{ title: 'shop.test transfer code is wrong' }] }), JSON.parse(response.body, symbolize_names: true) end private + def request_params + { format: :json, + data: { domainTransfers: [{ domainName: 'shop.test', transferCode: '65078d5' }] } } + end + def http_auth_key ActionController::HttpAuthentication::Basic.encode_credentials('test_goodnames', 'testtest') end diff --git a/test/integration/epp/domain/create/transfer_code_test.rb b/test/integration/epp/domain/create/transfer_code_test.rb index f7d70a4ea..276386851 100644 --- a/test/integration/epp/domain/create/transfer_code_test.rb +++ b/test/integration/epp/domain/create/transfer_code_test.rb @@ -3,7 +3,6 @@ require 'test_helper' class EppDomainCreateTransferCodeTest < ActionDispatch::IntegrationTest def setup travel_to Time.zone.parse('2010-07-05') - login_as users(:api_bestnames) end def test_generates_default @@ -27,9 +26,10 @@ class EppDomainCreateTransferCodeTest < ActionDispatch::IntegrationTest XML - session_id = epp_sessions(:api_bestnames).session_id - post '/epp/command/create', { frame: request_xml }, { 'HTTP_COOKIE' => "session=#{session_id}" } + post '/epp/command/create', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } refute_empty Domain.find_by(name: 'brandnew.test').transfer_code + assert_equal '1000', Nokogiri::XML(response.body).at_css('result')[:code] + assert_equal 1, Nokogiri::XML(response.body).css('result').size end def test_honors_custom @@ -56,8 +56,9 @@ class EppDomainCreateTransferCodeTest < ActionDispatch::IntegrationTest XML - session_id = epp_sessions(:api_bestnames).session_id - post '/epp/command/create', { frame: request_xml }, { 'HTTP_COOKIE' => "session=#{session_id}" } + post '/epp/command/create', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_equal '1058ad73', Domain.find_by(name: 'brandnew.test').transfer_code + assert_equal '1000', Nokogiri::XML(response.body).at_css('result')[:code] + assert_equal 1, Nokogiri::XML(response.body).css('result').size end end diff --git a/test/integration/epp/domain/transfer/transfer_code_test.rb b/test/integration/epp/domain/transfer/base_test.rb similarity index 53% rename from test/integration/epp/domain/transfer/transfer_code_test.rb rename to test/integration/epp/domain/transfer/base_test.rb index 0db6ba0d6..aa9f841b6 100644 --- a/test/integration/epp/domain/transfer/transfer_code_test.rb +++ b/test/integration/epp/domain/transfer/base_test.rb @@ -1,20 +1,16 @@ require 'test_helper' -class EppDomainTransferTransferCodeTest < ActionDispatch::IntegrationTest - def setup - login_as users(:api_goodnames) - end - - def test_wrong +class EppDomainTransferBaseTest < ActionDispatch::IntegrationTest + def test_non_existent_domain request_xml = <<-XML - shop.test + non-existent.test - wrong + any @@ -22,9 +18,7 @@ class EppDomainTransferTransferCodeTest < ActionDispatch::IntegrationTest XML - session_id = epp_sessions(:api_goodnames).session_id - post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => "session=#{session_id}" } - refute_equal registrars(:goodnames), domains(:shop).registrar - assert Nokogiri::XML(response.body).at_css('result[code="2201"]') + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + assert_equal '2303', Nokogiri::XML(response.body).at_css('result')[:code] end end diff --git a/test/integration/epp/domain/transfer/domain_transfer_test.rb b/test/integration/epp/domain/transfer/domain_transfer_test.rb deleted file mode 100644 index 1b1e604ba..000000000 --- a/test/integration/epp/domain/transfer/domain_transfer_test.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'test_helper' - -class EppDomainTransferTest < ActionDispatch::IntegrationTest - def setup - login_as users(:api_goodnames) - end - - def test_successfully_transfers_domain - request_xml = <<-XML - - - - - - shop.test - - 65078d5 - - - - - - XML - - session_id = epp_sessions(:api_goodnames).session_id - post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => "session=#{session_id}" } - assert_equal registrars(:goodnames), domains(:shop).registrar - assert Nokogiri::XML(response.body).at_css('result[code="1000"]') - assert_equal 1, Nokogiri::XML(response.body).css('result').size - end - - def test_non_existent_domain - request_xml = <<-XML - - - - - - non-existent.test - - any - - - - - - XML - - session_id = epp_sessions(:api_goodnames).session_id - post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => "session=#{session_id}" } - assert Nokogiri::XML(response.body).at_css('result[code="2303"]') - end -end diff --git a/test/integration/epp/domain/transfer/query_test.rb b/test/integration/epp/domain/transfer/query_test.rb new file mode 100644 index 000000000..1412dd9b3 --- /dev/null +++ b/test/integration/epp/domain/transfer/query_test.rb @@ -0,0 +1,61 @@ +require 'test_helper' + +class EppDomainTransferQueryTest < ActionDispatch::IntegrationTest + def test_returns_domain_transfer_details + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + xml_doc = Nokogiri::XML(response.body) + assert_equal '1000', xml_doc.at_css('result')[:code] + assert_equal 1, xml_doc.css('result').size + assert_equal 'shop.test', xml_doc.xpath('//domain:name', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + assert_equal 'serverApproved', xml_doc.xpath('//domain:trStatus', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + assert_equal 'goodnames', xml_doc.xpath('//domain:reID', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + assert_equal 'bestnames', xml_doc.xpath('//domain:acID', 'domain' => 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + end + + def test_wrong_transfer_code + request_xml = <<-XML + + + + + + shop.test + + wrong + + + + + + XML + + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + assert_equal '2201', Nokogiri::XML(response.body).at_css('result')[:code] + end + + def test_no_domain_transfer + domains(:shop).transfers.delete_all + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + assert_equal '2303', Nokogiri::XML(response.body).at_css('result')[:code] + end + + private + + def request_xml + <<-XML + + + + + + shop.test + + 65078d5 + + + + + + XML + end +end diff --git a/test/integration/epp/domain/transfer/request_test.rb b/test/integration/epp/domain/transfer/request_test.rb new file mode 100644 index 000000000..03c5e7daf --- /dev/null +++ b/test/integration/epp/domain/transfer/request_test.rb @@ -0,0 +1,137 @@ +require 'test_helper' + +class EppDomainTransferRequestTest < ActionDispatch::IntegrationTest + def setup + @domain = domains(:shop) + Setting.transfer_wait_time = 0 + end + + def test_transfers_domain_at_once + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + assert_equal '1000', Nokogiri::XML(response.body).at_css('result')[:code] + assert_equal 1, Nokogiri::XML(response.body).css('result').size + end + + def test_creates_new_domain_transfer + assert_difference -> { @domain.transfers.size } do + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + end + end + + def test_approves_automatically_if_auto_approval_is_enabled + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + assert_equal 'serverApproved', Nokogiri::XML(response.body).xpath('//domain:trStatus', 'domain' => + 'https://epp.tld.ee/schema/domain-eis-1.0.xsd').text + end + + def test_changes_registrar + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + @domain.reload + assert_equal registrars(:goodnames), @domain.registrar + end + + def test_regenerates_transfer_code + @old_transfer_code = @domain.transfer_code + + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + + @domain.reload + refute_equal @domain.transfer_code, @old_transfer_code + end + + def test_notifies_old_registrar + @old_registrar = @domain.registrar + + assert_difference -> { @old_registrar.messages.count } do + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + end + end + + def test_duplicates_registrant_admin_and_tech_contacts + assert_difference 'Contact.count', 3 do + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + end + end + + def test_saves_legal_document + assert_difference -> { @domain.legal_documents(true).size } do + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + end + end + + def test_non_transferable_domain + @domain.update!(statuses: [DomainStatus::SERVER_TRANSFER_PROHIBITED]) + + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + domains(:shop).reload + + assert_equal registrars(:bestnames), domains(:shop).registrar + assert_equal '2304', Nokogiri::XML(response.body).at_css('result')[:code] + end + + def test_discarded_domain + @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) + + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + @domain.reload + + assert_equal registrars(:bestnames), @domain.registrar + assert_equal '2105', Nokogiri::XML(response.body).at_css('result')[:code] + end + + def test_same_registrar + assert_no_difference -> { @domain.transfers.size } do + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + end + + assert_equal '2002', Nokogiri::XML(response.body).at_css('result')[:code] + end + + def test_wrong_transfer_code + request_xml = <<-XML + + + + + + shop.test + + wrong + + + + + + XML + + post '/epp/command/transfer', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_goodnames' } + @domain.reload + refute_equal registrars(:goodnames), @domain.registrar + assert_equal '2201', Nokogiri::XML(response.body).at_css('result')[:code] + end + + private + + def request_xml + <<-XML + + + + + + shop.test + + 65078d5 + + + + + + test + + + + + XML + end +end diff --git a/test/integration/epp/domain/update/transfer_code_test.rb b/test/integration/epp/domain/update/transfer_code_test.rb index 6208c2899..92ee58a02 100644 --- a/test/integration/epp/domain/update/transfer_code_test.rb +++ b/test/integration/epp/domain/update/transfer_code_test.rb @@ -1,10 +1,6 @@ require 'test_helper' class EppDomainUpdateTest < ActionDispatch::IntegrationTest - def setup - login_as users(:api_bestnames) - end - def test_overwrites_existing request_xml = <<-XML @@ -24,8 +20,9 @@ class EppDomainUpdateTest < ActionDispatch::IntegrationTest XML - session_id = epp_sessions(:api_bestnames).session_id - post '/epp/command/update', { frame: request_xml }, { 'HTTP_COOKIE' => "session=#{session_id}" } + post '/epp/command/update', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } assert_equal 'f0ff7d17b0', domains(:shop).transfer_code + assert_equal '1000', Nokogiri::XML(response.body).at_css('result')[:code] + assert_equal 1, Nokogiri::XML(response.body).css('result').size end end diff --git a/test/integration/epp/poll_test.rb b/test/integration/epp/poll_test.rb new file mode 100644 index 000000000..db6091cb0 --- /dev/null +++ b/test/integration/epp/poll_test.rb @@ -0,0 +1,30 @@ +require 'test_helper' + +class EppPollTest < ActionDispatch::IntegrationTest + def test_messages + post '/epp/command/poll', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + assert_equal '1301', Nokogiri::XML(response.body).at_css('result')[:code] + assert_equal 1, Nokogiri::XML(response.body).css('msgQ').size + assert_equal 1, Nokogiri::XML(response.body).css('result').size + end + + def test_no_messages + registrars(:bestnames).messages.delete_all(:delete_all) + post '/epp/command/poll', { frame: request_xml }, { 'HTTP_COOKIE' => 'session=api_bestnames' } + assert_equal '1300', Nokogiri::XML(response.body).at_css('result')[:code] + assert_equal 1, Nokogiri::XML(response.body).css('result').size + end + + private + + def request_xml + <<-XML + + + + + + + XML + end +end diff --git a/test/models/domain/domain_transfer_test.rb b/test/models/domain/transferable_test.rb similarity index 72% rename from test/models/domain/domain_transfer_test.rb rename to test/models/domain/transferable_test.rb index ad8088718..42613aa45 100644 --- a/test/models/domain/domain_transfer_test.rb +++ b/test/models/domain/transferable_test.rb @@ -1,6 +1,6 @@ require 'test_helper' -class DomainTransferTest < ActiveSupport::TestCase +class DomainTransferableTest < ActiveSupport::TestCase def setup @domain = domains(:shop) @new_registrar = registrars(:goodnames) @@ -44,22 +44,4 @@ class DomainTransferTest < ActiveSupport::TestCase @domain.transfer(@new_registrar) refute_same old_transfer_code, @domain.transfer_code end - - def test_creates_domain_transfer - assert_difference 'DomainTransfer.count' do - @domain.transfer(@new_registrar) - end - end - - def test_creates_message - assert_difference 'Message.count' do - @domain.transfer(@new_registrar) - end - end - - def test_copies_contacts - assert_difference 'Contact.count', 2 do - @domain.transfer(@new_registrar) - end - end end diff --git a/test/models/domain_transfer_test.rb b/test/models/domain_transfer_test.rb new file mode 100644 index 000000000..7f11caf80 --- /dev/null +++ b/test/models/domain_transfer_test.rb @@ -0,0 +1,32 @@ +require 'test_helper' + +class DomainTransferTest < ActiveSupport::TestCase + def setup + @domain_transfer = domain_transfers(:shop) + end + + def test_approval + @domain_transfer.approve + @domain_transfer.reload + assert @domain_transfer.approved? + end + + def test_notifies_old_registrar_on_approval + old_registrar = @domain_transfer.old_registrar + + assert_difference -> { old_registrar.messages.count } do + @domain_transfer.approve + end + + body = 'Transfer of domain shop.test has been approved.' \ + ' It was associated with registrant john-001' \ + ' and contacts jane-001, william-001.' + id = @domain_transfer.id + class_name = @domain_transfer.class.name + + message = old_registrar.messages.last + assert_equal body, message.body + assert_equal id, message.attached_obj_id + assert_equal class_name, message.attached_obj_type + end +end diff --git a/test/models/message_test.rb b/test/models/message_test.rb new file mode 100644 index 000000000..1c7c7bad1 --- /dev/null +++ b/test/models/message_test.rb @@ -0,0 +1,21 @@ +require 'test_helper' + +class MessageTest < ActiveSupport::TestCase + def setup + @message = messages(:greeting) + end + + def test_valid + assert @message.valid? + end + + def test_invalid_without_body + @message.body = nil + assert @message.invalid? + end + + def test_invalid_without_registrar + @message.registrar = nil + assert @message.invalid? + end +end