diff --git a/.ruby-version b/.ruby-version index 00355e29d..79a614418 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.3.7 +2.4.4 diff --git a/Dockerfile b/Dockerfile index bd0cbc07b..b5871bfed 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM internetee/ruby:2.3 +FROM internetee/ruby:2.4 MAINTAINER maciej.szlosarczyk@internet.ee RUN mkdir -p /opt/webapps/app/tmp/pids diff --git a/app/api/repp/domain_v1.rb b/app/api/repp/domain_v1.rb index 5e6c286ca..cf45bfc6f 100644 --- a/app/api/repp/domain_v1.rb +++ b/app/api/repp/domain_v1.rb @@ -29,7 +29,7 @@ module Repp # example: curl -u registrar1:password localhost:3000/repp/v1/domains/1/transfer_info -H "Auth-Code: authinfopw1" get '/:id/transfer_info', requirements: { id: /.*/ } do ident = params[:id] - domain = ident =~ /\A[0-9]+\z/ ? Domain.find_by(id: ident) : Domain.find_by_idn(ident) + domain = ident.match?(/\A[0-9]+\z/) ? Domain.find_by(id: ident) : Domain.find_by_idn(ident) error! I18n.t('errors.messages.epp_domain_not_found'), 404 unless domain error! I18n.t('errors.messages.epp_authorization_error'), 401 unless domain.transfer_code.eql? request.headers['Auth-Code'] diff --git a/app/controllers/admin/domains_controller.rb b/app/controllers/admin/domains_controller.rb index 1a525a72c..69276df0e 100644 --- a/app/controllers/admin/domains_controller.rb +++ b/app/controllers/admin/domains_controller.rb @@ -1,7 +1,7 @@ module Admin class DomainsController < BaseController - load_and_authorize_resource - before_action :set_domain, only: [:show, :edit, :update, :zonefile] + before_action :set_domain, only: %i[show edit update keep] + authorize_resource helper_method :force_delete_templates def index @@ -33,7 +33,8 @@ module Admin end def show - @domain.valid? + # Validation is needed to warn users + @domain.validate end def edit @@ -60,6 +61,11 @@ module Admin @versions = @domain.versions end + def keep + @domain.keep + redirect_to edit_admin_domain_url(@domain), notice: t('.kept') + end + private def set_domain diff --git a/app/controllers/epp_controller.rb b/app/controllers/epp_controller.rb index 93da33ead..496526d71 100644 --- a/app/controllers/epp_controller.rb +++ b/app/controllers/epp_controller.rb @@ -145,7 +145,9 @@ class EppController < ApplicationController # VALIDATION def latin_only return true if params['frame'].blank? - return true if params['frame'].match(/\A[\p{Latin}\p{Z}\p{P}\p{S}\p{Cc}\p{Cf}\w_\'\+\-\.\(\)\/]*\Z/i) + if params['frame'].match?(/\A[\p{Latin}\p{Z}\p{P}\p{S}\p{Cc}\p{Cf}\w_\'\+\-\.\(\)\/]*\Z/i) + return true + end epp_errors << { msg: 'Parameter value policy error. Allowed only Latin characters.', diff --git a/app/models/certificate.rb b/app/models/certificate.rb index 50976a73e..cb28f629b 100644 --- a/app/models/certificate.rb +++ b/app/models/certificate.rb @@ -87,14 +87,14 @@ class Certificate < ActiveRecord::Base -extensions usr_cert -notext -md sha256 \ -in #{csr_file.path} -out #{crt_file.path} -key '#{ENV['ca_key_password']}' -batch") - if err.match(/Data Base Updated/) + if err.match?(/Data Base Updated/) crt_file.rewind self.crt = crt_file.read self.md5 = OpenSSL::Digest::MD5.new(parsed_crt.to_der).to_s save! else logger.error('FAILED TO CREATE CLIENT CERTIFICATE') - if err.match(/TXT_DB error number 2/) + if err.match?(/TXT_DB error number 2/) errors.add(:base, I18n.t('failed_to_create_crt_csr_already_signed')) logger.error('CSR ALREADY SIGNED') else diff --git a/app/models/concerns/domain/deletable.rb b/app/models/concerns/domain/deletable.rb index 86c296d88..8640277c8 100644 --- a/app/models/concerns/domain/deletable.rb +++ b/app/models/concerns/domain/deletable.rb @@ -1,16 +1,25 @@ module Concerns::Domain::Deletable extend ActiveSupport::Concern - included do - alias_attribute :delete_time, :delete_at + private + + def delete_later + deletion_time = Time.zone.at(rand(deletion_time_span)) + DomainDeleteJob.enqueue(id, run_at: deletion_time, priority: 1) + logger.info "Domain #{name} is scheduled to be deleted around #{deletion_time}" end - def discard - statuses << DomainStatus::DELETE_CANDIDATE - save + def do_not_delete_later + # Que job can be manually deleted in admin area UI + QueJob.find_by("args->>0 = '#{id}'", job_class: DomainDeleteJob.name)&.destroy end - def discarded? - statuses.include?(DomainStatus::DELETE_CANDIDATE) + def deletion_time_span + range_params = [Time.zone.now.to_i, deletion_deadline.to_i].sort + Range.new(*range_params) end -end + + def deletion_deadline + delete_at + 24.hours + end +end \ No newline at end of file diff --git a/app/models/concerns/domain/discardable.rb b/app/models/concerns/domain/discardable.rb new file mode 100644 index 000000000..e46492220 --- /dev/null +++ b/app/models/concerns/domain/discardable.rb @@ -0,0 +1,40 @@ +module Concerns::Domain::Discardable + extend ActiveSupport::Concern + + class_methods do + def discard_domains + domains = where('delete_at < ? AND ? != ALL(coalesce(statuses, array[]::varchar[])) AND' \ + ' ? != ALL(COALESCE(statuses, array[]::varchar[]))', + Time.zone.now, + DomainStatus::SERVER_DELETE_PROHIBITED, + DomainStatus::DELETE_CANDIDATE) + + domains.each do |domain| + domain.discard + yield domain if block_given? + end + end + end + + def discard + raise 'Domain is already discarded' if discarded? + + statuses << DomainStatus::DELETE_CANDIDATE + transaction do + save(validate: false) + delete_later + end + end + + def keep + statuses.delete(DomainStatus::DELETE_CANDIDATE) + transaction do + save(validate: false) + do_not_delete_later + end + end + + def discarded? + statuses.include?(DomainStatus::DELETE_CANDIDATE) + end +end diff --git a/app/models/domain.rb b/app/models/domain.rb index cf1a21d11..511f36006 100644 --- a/app/models/domain.rb +++ b/app/models/domain.rb @@ -4,6 +4,7 @@ class Domain < ActiveRecord::Base include Concerns::Domain::Expirable include Concerns::Domain::Activatable include Concerns::Domain::ForceDelete + include Concerns::Domain::Discardable include Concerns::Domain::Deletable include Concerns::Domain::Transferable include Concerns::Domain::RegistryLockable @@ -250,13 +251,6 @@ class Domain < ActiveRecord::Base true end - def delete_candidateable? - return false if delete_at > Time.zone.now - return false if statuses.include?(DomainStatus::DELETE_CANDIDATE) - return false if statuses.include?(DomainStatus::SERVER_DELETE_PROHIBITED) - true - end - def renewable? if Setting.days_to_renew_domain_before_expire != 0 # if you can renew domain at days_to_renew before domain expiration @@ -614,10 +608,6 @@ class Domain < ActiveRecord::Base where("#{attribute_alias(:outzone_time)} < ?", Time.zone.now) end - def self.delete_candidates - where("#{attribute_alias(:delete_time)} < ?", Time.zone.now) - end - def self.uses_zone?(zone) exists?(["name ILIKE ?", "%.#{zone.origin}"]) end diff --git a/app/models/domain_cron.rb b/app/models/domain_cron.rb index 8de52b226..2d208d647 100644 --- a/app/models/domain_cron.rb +++ b/app/models/domain_cron.rb @@ -84,22 +84,6 @@ class DomainCron c = 0 - domains = Domain.delete_candidates - - domains.each do |domain| - next unless domain.delete_candidateable? - - domain.statuses << DomainStatus::DELETE_CANDIDATE - - # If domain successfully saved, add it to delete schedule - if domain.save(validate: false) - ::PaperTrail.whodunnit = "cron - #{__method__}" - DomainDeleteJob.enqueue(domain.id, run_at: rand(((24*60) - (DateTime.now.hour * 60 + DateTime.now.minute))).minutes.from_now) - STDOUT << "#{Time.zone.now.utc} DomainCron.destroy_delete_candidates: job added by deleteCandidate status ##{domain.id} (#{domain.name})\n" unless Rails.env.test? - c += 1 - end - end - Domain.where('force_delete_at <= ?', Time.zone.now.end_of_day.utc).each do |x| DomainDeleteJob.enqueue(x.id, run_at: rand(((24*60) - (DateTime.now.hour * 60 + DateTime.now.minute))).minutes.from_now) STDOUT << "#{Time.zone.now.utc} DomainCron.destroy_delete_candidates: job added by force delete time ##{x.id} (#{x.name})\n" unless Rails.env.test? diff --git a/app/models/domain_status.rb b/app/models/domain_status.rb index 4da6a4a3c..2f7a457dd 100644 --- a/app/models/domain_status.rb +++ b/app/models/domain_status.rb @@ -153,13 +153,11 @@ class DomainStatus < ActiveRecord::Base [ ['Hold', SERVER_HOLD], ['ManualInzone', SERVER_MANUAL_INZONE], - # [''], ['RenewProhibited', SERVER_RENEW_PROHIBITED], ['TransferProhibited', SERVER_TRANSFER_PROHIBITED], ['RegistrantChangeProhibited', SERVER_REGISTRANT_CHANGE_PROHIBITED], ['AdminChangeProhibited', SERVER_ADMIN_CHANGE_PROHIBITED], ['TechChangeProhibited', SERVER_TECH_CHANGE_PROHIBITED], - # [''], ['UpdateProhibited', SERVER_UPDATE_PROHIBITED], ['DeleteProhibited', SERVER_DELETE_PROHIBITED] ] @@ -171,11 +169,11 @@ class DomainStatus < ActiveRecord::Base INACTIVE, FORCE_DELETE, PENDING_CREATE, - #PENDING_DELETE, PENDING_RENEW, PENDING_TRANSFER, PENDING_UPDATE, - PENDING_DELETE_CONFIRMATION + PENDING_DELETE_CONFIRMATION, + DELETE_CANDIDATE, ] end end diff --git a/app/models/nameserver.rb b/app/models/nameserver.rb index d9a5f2a75..d9fdde406 100644 --- a/app/models/nameserver.rb +++ b/app/models/nameserver.rb @@ -100,18 +100,18 @@ class Nameserver < ActiveRecord::Base def check_puny_symbols regexp = /(\A|\.)..--/ - errors.add(:hostname, :invalid) if hostname =~ regexp + errors.add(:hostname, :invalid) if hostname.match?(regexp) end def validate_ipv4_format ipv4.to_a.each do |ip| - errors.add(:ipv4, :invalid) unless ip =~ IPV4_REGEXP + errors.add(:ipv4, :invalid) unless ip.match?(IPV4_REGEXP) end end def validate_ipv6_format ipv6.to_a.each do |ip| - errors.add(:ipv6, :invalid) unless ip =~ IPV6_REGEXP + errors.add(:ipv6, :invalid) unless ip.match?(IPV6_REGEXP) end end end diff --git a/app/models/que_job.rb b/app/models/que_job.rb new file mode 100644 index 000000000..5eed581fc --- /dev/null +++ b/app/models/que_job.rb @@ -0,0 +1,4 @@ +# To be able to remove existing jobs +class QueJob < ActiveRecord::Base + self.primary_key = 'job_id' +end diff --git a/app/presenters/domain_presenter.rb b/app/presenters/domain_presenter.rb index f4d3864ad..a4b9423a5 100644 --- a/app/presenters/domain_presenter.rb +++ b/app/presenters/domain_presenter.rb @@ -35,7 +35,7 @@ class DomainPresenter end def delete_date - view.l(domain.delete_time, format: :date) if domain.delete_time + view.l(domain.delete_at, format: :date) if domain.delete_at end def force_delete_date @@ -73,6 +73,15 @@ class DomainPresenter class: 'dropdown-item') end + def keep_btn + return unless domain.discarded? + + view.link_to view.t('admin.domains.edit.keep_btn'), view.keep_admin_domain_path(@domain), + method: :patch, + data: { confirm: view.t('admin.domains.edit.keep_btn_confirm') }, + class: 'btn btn-default' + end + private def schedule_force_delete_btn diff --git a/app/validators/contact/ident/reg_no_validator.rb b/app/validators/contact/ident/reg_no_validator.rb index 611d13301..138aab56a 100644 --- a/app/validators/contact/ident/reg_no_validator.rb +++ b/app/validators/contact/ident/reg_no_validator.rb @@ -10,7 +10,8 @@ class Contact::Ident::RegNoValidator < ActiveModel::EachValidator return unless format - record.errors.add(attribute, :invalid_reg_no, country: record.country) unless value =~ format + return if value.match?(format) + record.errors.add(attribute, :invalid_reg_no, country: record.country) end private diff --git a/app/validators/domain_name_validator.rb b/app/validators/domain_name_validator.rb index 22fe0cb34..0d5638b37 100644 --- a/app/validators/domain_name_validator.rb +++ b/app/validators/domain_name_validator.rb @@ -22,7 +22,7 @@ class DomainNameValidator < ActiveModel::EachValidator # it's punycode if value[2] == '-' && value[3] == '-' regexp = /\Axn--[a-zA-Z0-9-]{0,59}\.#{general_domains}\z/ - return false unless value =~ regexp + return false unless value.match?(regexp) value = SimpleIDN.to_unicode(value).mb_chars.downcase.strip end diff --git a/app/views/admin/domains/edit.html.erb b/app/views/admin/domains/edit.html.erb index 0d5e4589e..2317bc330 100644 --- a/app/views/admin/domains/edit.html.erb +++ b/app/views/admin/domains/edit.html.erb @@ -22,6 +22,7 @@
diff --git a/config/locales/admin/domains.en.yml b/config/locales/admin/domains.en.yml index 10f72a556..7773331c8 100644 --- a/config/locales/admin/domains.en.yml +++ b/config/locales/admin/domains.en.yml @@ -15,6 +15,11 @@ en: edit: header: "Edit:" add_new_status_btn: Add new status + keep_btn: Remove deleteCandidate status + keep_btn_confirm: Are you sure you want to remove deleteCandidate status? + + keep: + kept: deleteCandidate status has been removed force_delete_dialog: title: Force delete diff --git a/config/routes.rb b/config/routes.rb index f364b5dbf..f173ccad4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -192,12 +192,16 @@ Rails.application.routes.draw do match 'forward', via: [:post, :get] end - resources :domains do + resources :domains, except: %i[new create destroy] do resources :domain_versions, controller: 'domains', action: 'versions' resources :pending_updates resources :pending_deletes resource :force_delete, controller: 'domains/force_delete', only: %i[create destroy] resource :registry_lock, controller: 'domains/registry_lock', only: :destroy + + member do + patch :keep + end end resources :domain_versions do @@ -264,4 +268,4 @@ Rails.application.routes.draw do # To prevent users seeing the default welcome message "Welcome aboard" from Rails root to: redirect('admin/sign_in') -end \ No newline at end of file +end diff --git a/config/schedule.rb b/config/schedule.rb index 6413a9c56..6ad7328b2 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -57,6 +57,10 @@ if @cron_group == 'registry' every :day, at: '19:00pm' do runner 'Directo.send_receipts' end if @environment == 'production' + + every 42.minutes do + rake 'domain:discard' + end end every 10.minutes do diff --git a/db/migrate/20180816123540_change_contacts_email_to_not_null.rb b/db/migrate/20180816123540_change_contacts_email_to_not_null.rb new file mode 100644 index 000000000..e6080e38b --- /dev/null +++ b/db/migrate/20180816123540_change_contacts_email_to_not_null.rb @@ -0,0 +1,5 @@ +class ChangeContactsEmailToNotNull < ActiveRecord::Migration + def change + change_column_null :contacts, :email, false + end +end \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 1a402a864..668e96be5 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -613,7 +613,7 @@ CREATE TABLE public.contacts ( id integer NOT NULL, code character varying NOT NULL, phone character varying, - email character varying, + email character varying NOT NULL, fax character varying, created_at timestamp without time zone, updated_at timestamp without time zone, @@ -4764,5 +4764,7 @@ INSERT INTO schema_migrations (version) VALUES ('20180713154915'); INSERT INTO schema_migrations (version) VALUES ('20180808064402'); +INSERT INTO schema_migrations (version) VALUES ('20180816123540'); + INSERT INTO schema_migrations (version) VALUES ('20180824092855'); diff --git a/lib/auth_token/auth_token_creator.rb b/lib/auth_token/auth_token_creator.rb index 9fff8e5cd..741cc3e8a 100644 --- a/lib/auth_token/auth_token_creator.rb +++ b/lib/auth_token/auth_token_creator.rb @@ -26,7 +26,10 @@ class AuthTokenCreator def encrypted_token encryptor = OpenSSL::Cipher::AES.new(256, :CBC) encryptor.encrypt - encryptor.key = key + + # OpenSSL used to automatically shrink oversized keys, it does not do that any longer. + # See: https://github.com/ruby/openssl/issues/116 + encryptor.key = key[0..31] encrypted_bytes = encryptor.update(hashable) + encryptor.final Base64.urlsafe_encode64(encrypted_bytes) end diff --git a/lib/auth_token/auth_token_decryptor.rb b/lib/auth_token/auth_token_decryptor.rb index be6bd99cd..acd67be99 100644 --- a/lib/auth_token/auth_token_decryptor.rb +++ b/lib/auth_token/auth_token_decryptor.rb @@ -16,7 +16,10 @@ class AuthTokenDecryptor def decrypt_token decipher = OpenSSL::Cipher::AES.new(256, :CBC) decipher.decrypt - decipher.key = key + + # OpenSSL used to automatically shrink oversized keys, it does not do that any longer. + # See: https://github.com/ruby/openssl/issues/116 + decipher.key = key[0..31] base64_decoded = Base64.urlsafe_decode64(token.to_s) plain = decipher.update(base64_decoded) + decipher.final diff --git a/lib/tasks/domain.rake b/lib/tasks/domain.rake new file mode 100644 index 000000000..a5cc6d557 --- /dev/null +++ b/lib/tasks/domain.rake @@ -0,0 +1,13 @@ +namespace :domain do + desc 'Discard domains' + task discard: :environment do + domain_count = 0 + + Domain.discard_domains do |domain| + puts "#{domain} is discarded" + domain_count = domain_count + 1 + end + + puts "Discarded total: #{domain_count}" + end +end \ No newline at end of file diff --git a/spec/models/domain_spec.rb b/spec/models/domain_spec.rb index e094b1a8a..000a7be97 100644 --- a/spec/models/domain_spec.rb +++ b/spec/models/domain_spec.rb @@ -795,22 +795,6 @@ RSpec.describe Domain do end end - describe '::delete_candidates', db: true do - before :example do - travel_to Time.zone.parse('05.07.2010 00:00') - - create(:zone, origin: 'ee') - - create(:domain, id: 1, delete_time: Time.zone.parse('04.07.2010 23:59')) - create(:domain, id: 2, delete_time: Time.zone.parse('05.07.2010 00:00')) - create(:domain, id: 3, delete_time: Time.zone.parse('05.07.2010 00:01')) - end - - it 'returns domains with delete time in the past' do - expect(described_class.delete_candidates.ids).to eq([1]) - end - end - describe '::uses_zone?', db: true do let!(:zone) { create(:zone, origin: 'domain.tld') } diff --git a/spec/presenters/domain_presenter_spec.rb b/spec/presenters/domain_presenter_spec.rb index c83ca58ca..ff4fc2841 100644 --- a/spec/presenters/domain_presenter_spec.rb +++ b/spec/presenters/domain_presenter_spec.rb @@ -44,7 +44,7 @@ RSpec.describe DomainPresenter do subject(:delete_date) { presenter.delete_date } context 'when present' do - let(:domain) { instance_double(Domain, delete_time: '05.07.2010') } + let(:domain) { instance_double(Domain, delete_at: '05.07.2010') } it 'returns localized date' do expect(view).to receive(:l).with('05.07.2010', format: :date).and_return('delete date') @@ -53,7 +53,7 @@ RSpec.describe DomainPresenter do end context 'when absent' do - let(:domain) { instance_double(Domain, delete_time: nil) } + let(:domain) { instance_double(Domain, delete_at: nil) } specify { expect(delete_date).to be_nil } end diff --git a/test/integration/epp/domain/domain_delete_test.rb b/test/integration/epp/domain/domain_delete_test.rb index 61cd7d6f3..438e20eeb 100644 --- a/test/integration/epp/domain/domain_delete_test.rb +++ b/test/integration/epp/domain/domain_delete_test.rb @@ -1,6 +1,10 @@ require 'test_helper' class EppDomainDeleteTest < ApplicationIntegrationTest + def setup + @domain = domains(:shop) + end + def test_bypasses_domain_and_registrant_and_contacts_validation request_xml = <<-XML @@ -27,7 +31,9 @@ class EppDomainDeleteTest < ApplicationIntegrationTest end def test_discarded_domain_cannot_be_deleted - domains(:shop).discard + travel_to Time.zone.parse('2010-07-05 10:30') + @domain.delete_at = Time.zone.parse('2010-07-05 10:00') + @domain.discard request_xml = <<-XML @@ -51,5 +57,6 @@ class EppDomainDeleteTest < ApplicationIntegrationTest post '/epp/command/delete', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' end assert_equal '2105', Nokogiri::XML(response.body).at_css('result')[:code] + travel_back end end diff --git a/test/integration/epp/domain/domain_update_test.rb b/test/integration/epp/domain/domain_update_test.rb index f1db1b087..26996c63f 100644 --- a/test/integration/epp/domain/domain_update_test.rb +++ b/test/integration/epp/domain/domain_update_test.rb @@ -1,6 +1,10 @@ require 'test_helper' class EppDomainUpdateTest < ApplicationIntegrationTest + def setup + @domain = domains(:shop) + end + def test_update_domain request_xml = <<-XML @@ -21,13 +25,16 @@ class EppDomainUpdateTest < ApplicationIntegrationTest XML post '/epp/command/update', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' - assert_equal 'f0ff7d17b0', domains(:shop).transfer_code + @domain.reload + assert_equal 'f0ff7d17b0', @domain.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_discarded_domain_cannot_be_updated - domains(:shop).discard + travel_to Time.zone.parse('2010-07-05 10:30') + @domain.delete_at = Time.zone.parse('2010-07-05 10:00') + @domain.discard request_xml = <<-XML @@ -44,5 +51,6 @@ class EppDomainUpdateTest < ApplicationIntegrationTest post '/epp/command/update', { frame: request_xml }, 'HTTP_COOKIE' => 'session=api_bestnames' assert_equal '2105', Nokogiri::XML(response.body).at_css('result')[:code] + travel_back end end diff --git a/test/integration/epp/domain/transfer/request_test.rb b/test/integration/epp/domain/transfer/request_test.rb index 6335fb27e..1a9f9ae75 100644 --- a/test/integration/epp/domain/transfer/request_test.rb +++ b/test/integration/epp/domain/transfer/request_test.rb @@ -1,12 +1,17 @@ require 'test_helper' class EppDomainTransferRequestTest < ApplicationIntegrationTest - setup do + def setup @domain = domains(:shop) @new_registrar = registrars(:goodnames) + @original_transfer_wait_time = Setting.transfer_wait_time Setting.transfer_wait_time = 0 end + def teardown + Setting.transfer_wait_time = @original_transfer_wait_time + 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] @@ -75,14 +80,17 @@ class EppDomainTransferRequestTest < ApplicationIntegrationTest assert_equal '2304', Nokogiri::XML(response.body).at_css('result')[:code] end - def test_discarded_domain - @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) + def test_discarded_domain_cannot_be_transferred + travel_to Time.zone.parse('2010-07-05 10:30') + @domain.delete_at = Time.zone.parse('2010-07-05 10:00') + @domain.discard 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] + travel_back end def test_same_registrar diff --git a/test/integration/tasks/discard_domain_test.rb b/test/integration/tasks/discard_domain_test.rb new file mode 100644 index 000000000..0da7014c7 --- /dev/null +++ b/test/integration/tasks/discard_domain_test.rb @@ -0,0 +1,51 @@ +require 'test_helper' + +class DiscardDomainTaskTest < TaskTestCase + setup do + travel_to Time.zone.parse('2010-07-05 08:00') + @domain = domains(:shop) + end + + def test_discard_domains_with_past_delete_at + @domain.update!(delete_at: Time.zone.parse('2010-07-05 07:59')) + Rake::Task['domain:discard'].execute + @domain.reload + assert @domain.discarded? + end + + def test_ignore_domains_with_delete_at_in_the_future_or_now + @domain.update!(delete_at: Time.zone.parse('2010-07-05 08:00')) + Rake::Task['domain:discard'].execute + @domain.reload + refute @domain.discarded? + end + + def test_ignore_already_discarded_domains + @domain.update!(delete_at: Time.zone.parse('2010-07-05 07:59')) + @domain.discard + + job_count = lambda do + QueJob.where("args->>0 = '#{@domain.id}'", job_class: DomainDeleteJob.name).count + end + + assert_no_difference job_count, 'A domain should not be discarded again' do + Rake::Task['domain:discard'].execute + end + end + + def test_ignore_domains_with_server_delete_prohibited_status + @domain.update!(delete_at: Time.zone.parse('2010-07-05 07:59'), + statuses: [DomainStatus::SERVER_DELETE_PROHIBITED]) + Rake::Task['domain:discard'].execute + @domain.reload + refute @domain.discarded? + end + + def test_show_results + @domain.update!(delete_at: Time.zone.parse('2010-07-05 07:59')) + $stdout = StringIO.new + + Rake::Task['domain:discard'].execute + assert_equal "shop.test is discarded\nDiscarded total: 1\n", $stdout.string + end +end \ No newline at end of file diff --git a/test/lib/auth_token/auth_token_creator_test.rb b/test/lib/auth_token/auth_token_creator_test.rb index 9d4cdd2c6..0465de9f4 100644 --- a/test/lib/auth_token/auth_token_creator_test.rb +++ b/test/lib/auth_token/auth_token_creator_test.rb @@ -8,7 +8,7 @@ class AuthTokenCreatorTest < ActiveSupport::TestCase @user = users(:registrant) time = Time.zone.parse('2010-07-05 00:30:00 +0000') - @random_bytes = SecureRandom.random_bytes(64) + @random_bytes = SecureRandom.random_bytes(32) @token_creator = AuthTokenCreator.new(@user, @random_bytes, time) end diff --git a/test/models/domain/deletable_test.rb b/test/models/domain/deletable_test.rb deleted file mode 100644 index dbec7bc7f..000000000 --- a/test/models/domain/deletable_test.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'test_helper' - -class DomainDeletableTest < ActiveSupport::TestCase - setup do - @domain = domains(:shop) - end - - def test_discard - refute @domain.discarded? - @domain.discard - @domain.reload - assert @domain.discarded? - end -end diff --git a/test/models/domain/discardable_test.rb b/test/models/domain/discardable_test.rb new file mode 100644 index 000000000..0181a6bb4 --- /dev/null +++ b/test/models/domain/discardable_test.rb @@ -0,0 +1,63 @@ +require 'test_helper' + +class DomainDiscardableTest < ActiveSupport::TestCase + setup do + travel_to Time.zone.parse('2010-07-05 10:30') + @domain = domains(:shop) + @domain.delete_at = Time.zone.parse('2010-07-05 10:00') + end + + teardown do + travel_back + end + + def test_discarding_a_domain_persists_the_state + @domain.discard + @domain.reload + assert @domain.discarded? + end + + def test_discarding_a_domain_schedules_deletion_at_random_time + @domain.discard + other_domain = domains(:airport) + other_domain.delete_at = Time.zone.parse('2010-07-04') + other_domain.discard + + background_job = QueJob.find_by("args->>0 = '#{@domain.id}'", job_class: DomainDeleteJob.name) + other_background_job = QueJob.find_by("args->>0 = '#{other_domain.id}'", + job_class: DomainDeleteJob.name) + assert_not_equal background_job.run_at, other_background_job.run_at + end + + def test_discarding_a_domain_bypasses_validation + domain = domains(:invalid) + domain.delete_at = Time.zone.parse('2010-07-05 10:00') + domain.discard + domain.reload + assert domain.discarded? + end + + def test_domain_cannot_be_discarded_repeatedly + @domain.discard + + exception = assert_raises do + @domain.discard + end + assert_equal 'Domain is already discarded', exception.message + end + + def test_keeping_a_domain_bypasses_validation + domain = domains(:invalid) + domain.delete_at = Time.zone.parse('2010-07-05 10:00') + domain.discard + domain.keep + domain.reload + assert_not domain.discarded? + end + + def test_keeping_a_domain_cancels_domain_deletion + @domain.discard + @domain.keep + assert_nil QueJob.find_by("args->>0 = '#{@domain.id}'", job_class: DomainDeleteJob.name) + end +end diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb index 706af1ef0..646a34015 100644 --- a/test/models/domain/force_delete_test.rb +++ b/test/models/domain/force_delete_test.rb @@ -1,7 +1,7 @@ require 'test_helper' class DomainForceDeleteTest < ActiveSupport::TestCase - def setup + setup do @domain = domains(:shop) end @@ -74,7 +74,7 @@ class DomainForceDeleteTest < ActiveSupport::TestCase end def test_force_delete_cannot_be_scheduled_when_a_domain_is_discarded - @domain.discard + @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) assert_raises StandardError do @domain.schedule_force_delete end diff --git a/test/system/admin_area/contact_versions_test.rb b/test/system/admin_area/contact_versions_test.rb index 10d20615a..8130706b6 100644 --- a/test/system/admin_area/contact_versions_test.rb +++ b/test/system/admin_area/contact_versions_test.rb @@ -21,8 +21,8 @@ class ContactVersionsTest < ApplicationSystemTestCase VALUES (75, 'test_registrar', 'test123', 'test@test.com', 'EE', 'TEST123', 'test123', 'en'); - INSERT INTO contacts (id, code, auth_info, registrar_id) - VALUES (75, 'test_code', '8b4d462aa04194ca78840a', 75); + INSERT INTO contacts (id, code, email, auth_info, registrar_id) + VALUES (75, 'test_code', 'test@inbox.test', '8b4d462aa04194ca78840a', 75); INSERT INTO log_contacts (item_type, item_id, event, whodunnit, object, object_changes, created_at, session, children, ident_updated_at, uuid) diff --git a/test/system/admin_area/domain_versions_test.rb b/test/system/admin_area/domain_versions_test.rb index 6c375cefe..dae7592c8 100644 --- a/test/system/admin_area/domain_versions_test.rb +++ b/test/system/admin_area/domain_versions_test.rb @@ -21,8 +21,8 @@ class DomainVersionsTest < ApplicationSystemTestCase VALUES (54, 'test_registrar', 'test123', 'test@test.com', 'EE', 'TEST123', 'test123', 'en'); - INSERT INTO contacts (id, code, auth_info, registrar_id) - VALUES (54, 'test_code', '8b4d462aa04194ca78840a', 54); + INSERT INTO contacts (id, code, email, auth_info, registrar_id) + VALUES (54, 'test_code', 'test@inbox.test', '8b4d462aa04194ca78840a', 54); INSERT INTO domains (id, registrar_id, valid_to, registrant_id, transfer_code) diff --git a/test/system/admin_area/domains/details_test.rb b/test/system/admin_area/domains/details_test.rb index 31a46a19b..04cdb06e3 100644 --- a/test/system/admin_area/domains/details_test.rb +++ b/test/system/admin_area/domains/details_test.rb @@ -7,9 +7,14 @@ class AdminAreaDomainDetailsTest < ApplicationSystemTestCase end def test_discarded_domain_has_corresponding_label + travel_to Time.zone.parse('2010-07-05 10:30') + @domain.delete_at = Time.zone.parse('2010-07-05 10:00') + visit admin_domain_url(@domain) assert_no_css 'span.label.label-warning', text: 'deleteCandidate' + @domain.discard + visit admin_domain_url(@domain) assert_css 'span.label.label-warning', text: 'deleteCandidate' end diff --git a/test/system/admin_area/domains/force_delete_test.rb b/test/system/admin_area/domains/force_delete_test.rb index 22bb23d38..75835cf59 100644 --- a/test/system/admin_area/domains/force_delete_test.rb +++ b/test/system/admin_area/domains/force_delete_test.rb @@ -56,7 +56,7 @@ class AdminAreaDomainForceDeleteTest < ApplicationSystemTestCase end def test_force_delete_procedure_cannot_be_scheduled_on_a_discarded_domain - @domain.discard + @domain.update!(statuses: [DomainStatus::DELETE_CANDIDATE]) visit edit_admin_domain_url(@domain) assert_no_button 'Schedule force delete' diff --git a/test/system/admin_area/domains_test.rb b/test/system/admin_area/domains_test.rb index fddb1b328..91e484fc7 100644 --- a/test/system/admin_area/domains_test.rb +++ b/test/system/admin_area/domains_test.rb @@ -27,4 +27,17 @@ class AdminDomainsTestTest < ApplicationSystemTestCase assert_text 'Registry lock time 2010-07-05 00:30' assert_text 'registryLock' end + + def test_keep_a_domain + @domain.delete_at = Time.zone.parse('2010-07-05 10:00') + @domain.discard + + visit edit_admin_domain_url(@domain) + click_link_or_button 'Remove deleteCandidate status' + @domain.reload + + assert_not @domain.discarded? + assert_text 'deleteCandidate status has been removed' + assert_no_link 'Remove deleteCandidate status' + end end