diff --git a/app/models/concerns/domain/force_delete.rb b/app/models/concerns/domain/force_delete.rb
index 96f1a94b3..9f69316d7 100644
--- a/app/models/concerns/domain/force_delete.rb
+++ b/app/models/concerns/domain/force_delete.rb
@@ -1,30 +1,50 @@
module Concerns::Domain::ForceDelete
extend ActiveSupport::Concern
- included do
- alias_attribute :force_delete_time, :force_delete_at
- end
-
def force_delete_scheduled?
statuses.include?(DomainStatus::FORCE_DELETE)
end
def schedule_force_delete
- self.statuses_backup = statuses
- statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
- statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
+ if discarded?
+ raise StandardError, 'Force delete procedure cannot be scheduled while a domain is discarded'
+ end
+
+ preserve_current_statuses_for_force_delete
+ add_force_delete_statuses
+ self.force_delete_at = (Time.zone.now + (Setting.redemption_grace_period.days + 1.day)).utc
+ .beginning_of_day
+ stop_all_pending_actions
+ allow_deletion
+ save(validate: false)
+ end
+
+ def cancel_force_delete
+ restore_statuses_before_force_delete
+ remove_force_delete_statuses
+ self.force_delete_at = nil
+ save(validate: false)
+ end
+
+ private
+
+ def stop_all_pending_actions
statuses.delete(DomainStatus::PENDING_UPDATE)
statuses.delete(DomainStatus::PENDING_TRANSFER)
statuses.delete(DomainStatus::PENDING_RENEW)
statuses.delete(DomainStatus::PENDING_CREATE)
+ end
- statuses.delete(DomainStatus::FORCE_DELETE)
- statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
- statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
- statuses.delete(DomainStatus::SERVER_UPDATE_PROHIBITED)
- statuses.delete(DomainStatus::SERVER_MANUAL_INZONE)
- statuses.delete(DomainStatus::PENDING_DELETE)
+ def preserve_current_statuses_for_force_delete
+ self.statuses_before_force_delete = statuses
+ end
+ def restore_statuses_before_force_delete
+ self.statuses = statuses_before_force_delete
+ self.statuses_before_force_delete = nil
+ end
+
+ def add_force_delete_statuses
statuses << DomainStatus::FORCE_DELETE
statuses << DomainStatus::SERVER_RENEW_PROHIBITED
statuses << DomainStatus::SERVER_TRANSFER_PROHIBITED
@@ -34,21 +54,19 @@ module Concerns::Domain::ForceDelete
if (statuses & [DomainStatus::SERVER_HOLD, DomainStatus::CLIENT_HOLD]).empty?
statuses << DomainStatus::SERVER_MANUAL_INZONE
end
-
- self.force_delete_at = (Time.zone.now + (Setting.redemption_grace_period.days + 1.day)).utc.beginning_of_day unless force_delete_at
- save!(validate: false)
end
- def cancel_force_delete
- s = []
- s << DomainStatus::EXPIRED if statuses.include?(DomainStatus::EXPIRED)
- s << DomainStatus::SERVER_HOLD if statuses.include?(DomainStatus::SERVER_HOLD)
- s << DomainStatus::DELETE_CANDIDATE if statuses.include?(DomainStatus::DELETE_CANDIDATE)
+ def remove_force_delete_statuses
+ statuses.delete(DomainStatus::FORCE_DELETE)
+ statuses.delete(DomainStatus::SERVER_RENEW_PROHIBITED)
+ statuses.delete(DomainStatus::SERVER_TRANSFER_PROHIBITED)
+ statuses.delete(DomainStatus::SERVER_UPDATE_PROHIBITED)
+ statuses.delete(DomainStatus::PENDING_DELETE)
+ statuses.delete(DomainStatus::SERVER_MANUAL_INZONE)
+ end
- self.statuses = (statuses_backup + s).uniq
-
- self.force_delete_at = nil
- self.statuses_backup = []
- save(validate: false)
+ def allow_deletion
+ statuses.delete(DomainStatus::CLIENT_DELETE_PROHIBITED)
+ statuses.delete(DomainStatus::SERVER_DELETE_PROHIBITED)
end
end
diff --git a/app/models/domain.rb b/app/models/domain.rb
index 30ed0b580..33f8a8f09 100644
--- a/app/models/domain.rb
+++ b/app/models/domain.rb
@@ -583,6 +583,7 @@ class Domain < ActiveRecord::Base
hash = super
hash['auth_info'] = hash.delete('transfer_code') # API v1 requirement
hash['valid_from'] = hash['registered_at'] # API v1 requirement
+ hash.delete('statuses_before_force_delete')
hash
end
diff --git a/app/presenters/domain_presenter.rb b/app/presenters/domain_presenter.rb
index aac3c1527..b82d4df3f 100644
--- a/app/presenters/domain_presenter.rb
+++ b/app/presenters/domain_presenter.rb
@@ -34,7 +34,7 @@ class DomainPresenter
end
def force_delete_date
- view.l(domain.force_delete_time, format: :date) if domain.force_delete_time
+ view.l(domain.force_delete_at, format: :date) if domain.force_delete_at
end
def admin_contact_names
@@ -50,25 +50,43 @@ class DomainPresenter
end
def force_delete_toggle_btn
- if !domain.force_delete_scheduled?
- view.content_tag(:a, view.t('admin.domains.force_delete_toggle_btn.schedule'),
- class: 'btn btn-default',
- data: {
- toggle: 'modal',
- target: '.domain-edit-force-delete-dialog',
- }
- )
+ return inactive_schedule_force_delete_btn if domain.discarded?
+
+ if domain.force_delete_scheduled?
+ cancel_force_delete_btn
else
- view.link_to(view.t('admin.domains.force_delete_toggle_btn.cancel'),
- view.admin_domain_force_delete_path(domain),
- method: :delete,
- data: { confirm: view.t('admin.domains.force_delete_toggle_btn.cancel_confirm') },
- class: 'btn btn-primary')
+ schedule_force_delete_btn
end
end
private
+ def schedule_force_delete_btn
+ view.content_tag(:a, view.t('admin.domains.force_delete_toggle_btn.schedule'),
+ class: 'btn btn-default',
+ data: {
+ toggle: 'modal',
+ target: '.domain-edit-force-delete-dialog',
+ })
+ end
+
+ def cancel_force_delete_btn
+ view.link_to view.t('admin.domains.force_delete_toggle_btn.cancel'),
+ view.admin_domain_force_delete_path(domain),
+ method: :delete,
+ data: {
+ confirm: view.t('admin.domains.force_delete_toggle_btn.cancel_confirm'),
+ },
+ class: 'btn btn-primary'
+ end
+
+ def inactive_schedule_force_delete_btn
+ view.content_tag :button, view.t('admin.domains.force_delete_toggle_btn.schedule'),
+ title: view.t('admin.domains.force_delete_toggle_btn.unable_to_schedule'),
+ disabled: true,
+ class: 'btn btn-default'
+ end
+
attr_reader :domain
attr_reader :view
end
diff --git a/app/views/admin/domains/edit.html.erb b/app/views/admin/domains/edit.html.erb
index 3f831e86b..30028e09e 100644
--- a/app/views/admin/domains/edit.html.erb
+++ b/app/views/admin/domains/edit.html.erb
@@ -1,20 +1,22 @@
<% domain = DomainPresenter.new(domain: @domain, view: self) %>
-
-
-
- Edit: <%= domain.name %>
-
-
-
-
+
+ - <%= link_to t('admin.domains.index.header'), admin_domains_path %>
+ - <%= link_to @domain, admin_domain_path(@domain) %>
+
+
+
-
<%= render 'form' %>
-<%= render 'force_delete_dialog', domain: @domain, templates: force_delete_templates %>
+<%= render 'force_delete_dialog', domain: @domain, templates: force_delete_templates %>
\ No newline at end of file
diff --git a/app/views/admin/domains/partials/_general.html.erb b/app/views/admin/domains/partials/_general.html.erb
index 7e09a7756..5be18eba4 100644
--- a/app/views/admin/domains/partials/_general.html.erb
+++ b/app/views/admin/domains/partials/_general.html.erb
@@ -31,8 +31,8 @@
<%= t('.delete_time') %>
<%= l(@domain.delete_at) %>
- <%= t('.force_delete_time') %>
- <%= l(@domain.force_delete_at) %>
+ <%= Domain.human_attribute_name :force_delete_at %>
+ <%= l @domain.force_delete_at %>
diff --git a/config/locales/admin/domains.en.yml b/config/locales/admin/domains.en.yml
index 87c2c9c6a..ed93eb647 100644
--- a/config/locales/admin/domains.en.yml
+++ b/config/locales/admin/domains.en.yml
@@ -13,8 +13,8 @@ en:
reset_btn: Reset
edit:
+ header: "Edit: %{domain}"
add_new_status_btn: Add new status
- back_btn: Back to domain
force_delete_dialog:
title: Force delete
@@ -33,7 +33,6 @@ en:
general:
outzone_time: Outzone time
delete_time: Delete time
- force_delete_time: Force delete time
admin_contacts:
title: Admin. contacts
@@ -46,5 +45,7 @@ en:
force_delete_toggle_btn:
schedule: Schedule force delete
+ unable_to_schedule: >
+ Force delete procedure cannot be scheduled while a domain has deleteCandidate status
cancel: Cancel force delete
- cancel_confirm: Are you sure you want cancel force delete procedure?
+ cancel_confirm: Are you sure you want cancel force delete procedure?
\ No newline at end of file
diff --git a/db/migrate/20180422154642_rename_domains_statuses_backup_to_statuses_before_force_delete.rb b/db/migrate/20180422154642_rename_domains_statuses_backup_to_statuses_before_force_delete.rb
new file mode 100644
index 000000000..a6784f02e
--- /dev/null
+++ b/db/migrate/20180422154642_rename_domains_statuses_backup_to_statuses_before_force_delete.rb
@@ -0,0 +1,5 @@
+class RenameDomainsStatusesBackupToStatusesBeforeForceDelete < ActiveRecord::Migration
+ def change
+ rename_column :domains, :statuses_backup, :statuses_before_force_delete
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 40ae46e6d..14d5ffffd 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -909,7 +909,7 @@ CREATE TABLE public.domains (
statuses character varying[],
reserved boolean DEFAULT false,
status_notes public.hstore,
- statuses_backup character varying[] DEFAULT '{}'::character varying[],
+ statuses_before_force_delete character varying[] DEFAULT '{}'::character varying[],
upid integer,
up_date timestamp without time zone,
uuid uuid DEFAULT public.gen_random_uuid() NOT NULL
@@ -4747,6 +4747,8 @@ INSERT INTO schema_migrations (version) VALUES ('20180327151906');
INSERT INTO schema_migrations (version) VALUES ('20180331200125');
+INSERT INTO schema_migrations (version) VALUES ('20180422154642');
+
INSERT INTO schema_migrations (version) VALUES ('20180612042234');
INSERT INTO schema_migrations (version) VALUES ('20180612042625');
diff --git a/doc/repp/v1/domain.md b/doc/repp/v1/domain.md
index adb9c4c8e..4c9476125 100644
--- a/doc/repp/v1/domain.md
+++ b/doc/repp/v1/domain.md
@@ -63,10 +63,7 @@ Content-Type: application/json
],
"reserved": false,
"status_notes": {
- },
- "statuses_backup": [
-
- ]
+ }
}
],
"total_number_of_records": 2
diff --git a/spec/models/concerns/domain/force_delete_spec.rb b/spec/models/concerns/domain/force_delete_spec.rb
deleted file mode 100644
index cc022a6d7..000000000
--- a/spec/models/concerns/domain/force_delete_spec.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-require 'rails_helper'
-
-RSpec.describe Domain do
- it { is_expected.to alias_attribute(:force_delete_time, :force_delete_at) }
-
- before :example do
- create(:zone, origin: 'ee')
- end
-
- it 'should set force delete time' do
- domain = build(:domain)
- domain.nameservers.build(attributes_for(:nameserver))
- domain.nameservers.build(attributes_for(:nameserver))
- domain.save!
-
- domain.statuses = ['ok']
- domain.schedule_force_delete
-
- domain.statuses.should match_array([
- "serverForceDelete",
- "pendingDelete",
- "serverManualInzone",
- "serverRenewProhibited",
- "serverTransferProhibited",
- "serverUpdateProhibited"
- ])
-
- domain.cancel_force_delete
-
- domain.statuses.should == ['ok']
-
- domain.statuses = [
- DomainStatus::CLIENT_DELETE_PROHIBITED,
- DomainStatus::SERVER_DELETE_PROHIBITED,
- DomainStatus::PENDING_UPDATE,
- DomainStatus::PENDING_TRANSFER,
- DomainStatus::PENDING_RENEW,
- DomainStatus::PENDING_CREATE,
- DomainStatus::CLIENT_HOLD,
- DomainStatus::EXPIRED,
- DomainStatus::SERVER_HOLD,
- DomainStatus::DELETE_CANDIDATE
- ]
-
- domain.save
-
- domain.schedule_force_delete
-
- domain.statuses.should match_array([
- "clientHold",
- "deleteCandidate",
- "expired",
- "serverForceDelete",
- "pendingDelete",
- "serverHold",
- "serverRenewProhibited",
- "serverTransferProhibited",
- "serverUpdateProhibited"
- ])
-
- domain.cancel_force_delete
-
- domain.statuses.should match_array([
- "clientDeleteProhibited",
- "clientHold",
- "deleteCandidate",
- "expired",
- "pendingCreate",
- "pendingRenew",
- "pendingTransfer",
- "pendingUpdate",
- "serverDeleteProhibited",
- "serverHold"
- ])
- end
-
- it 'should should be manual in zone and held after force delete' do
- domain = create(:domain)
- Setting.redemption_grace_period = 1
-
- domain.valid?
- domain.outzone_at = Time.zone.now + 1.day # before redemption grace period
- # what should this be?
- # domain.server_holdable?.should be true
- domain.statuses.include?(DomainStatus::SERVER_HOLD).should be false
- domain.statuses.include?(DomainStatus::SERVER_MANUAL_INZONE).should be false
- domain.schedule_force_delete
- domain.server_holdable?.should be false
- domain.statuses.include?(DomainStatus::SERVER_MANUAL_INZONE).should be true
- domain.statuses.include?(DomainStatus::SERVER_HOLD).should be false
- end
-
- it 'should not allow update after force delete' do
- domain = create(:domain)
- domain.valid?
- domain.pending_update_prohibited?.should be false
- domain.update_prohibited?.should be false
- domain.schedule_force_delete
- domain.pending_update_prohibited?.should be true
- domain.update_prohibited?.should be true
- end
-end
diff --git a/spec/presenters/domain_presenter_spec.rb b/spec/presenters/domain_presenter_spec.rb
index 3726960b4..c83ca58ca 100644
--- a/spec/presenters/domain_presenter_spec.rb
+++ b/spec/presenters/domain_presenter_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe DomainPresenter do
subject(:force_delete_date) { presenter.force_delete_date }
context 'when present' do
- let(:domain) { instance_double(Domain, force_delete_time: '05.07.2010') }
+ let(:domain) { instance_double(Domain, force_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')
@@ -72,7 +72,7 @@ RSpec.describe DomainPresenter do
end
context 'when absent' do
- let(:domain) { instance_double(Domain, force_delete_time: nil) }
+ let(:domain) { instance_double(Domain, force_delete_at: nil) }
specify { expect(force_delete_date).to be_nil }
end
diff --git a/test/models/domain/force_delete_test.rb b/test/models/domain/force_delete_test.rb
new file mode 100644
index 000000000..706af1ef0
--- /dev/null
+++ b/test/models/domain/force_delete_test.rb
@@ -0,0 +1,117 @@
+require 'test_helper'
+
+class DomainForceDeleteTest < ActiveSupport::TestCase
+ def setup
+ @domain = domains(:shop)
+ end
+
+ def test_schedule_force_delete
+ @original_redemption_grace_period = Setting.redemption_grace_period
+ Setting.redemption_grace_period = 30
+ travel_to Time.zone.parse('2010-07-05 00:00')
+
+ @domain.schedule_force_delete
+ @domain.reload
+
+ assert @domain.force_delete_scheduled?
+ assert_equal Time.zone.parse('2010-08-04 03:00'), @domain.force_delete_at
+
+ travel_back
+ Setting.redemption_grace_period = @original_redemption_grace_period
+ end
+
+ def test_scheduling_force_delete_adds_corresponding_statuses
+ statuses_to_be_added = [
+ DomainStatus::FORCE_DELETE,
+ DomainStatus::SERVER_RENEW_PROHIBITED,
+ DomainStatus::SERVER_TRANSFER_PROHIBITED,
+ DomainStatus::SERVER_UPDATE_PROHIBITED,
+ DomainStatus::PENDING_DELETE,
+ ]
+
+ @domain.schedule_force_delete
+ @domain.reload
+ assert (@domain.statuses & statuses_to_be_added) == statuses_to_be_added
+ end
+
+ def test_scheduling_force_delete_allows_domain_deletion
+ statuses_to_be_removed = [
+ DomainStatus::CLIENT_DELETE_PROHIBITED,
+ DomainStatus::SERVER_DELETE_PROHIBITED,
+ ]
+
+ @domain.statuses = statuses_to_be_removed + %w[other-status]
+ @domain.schedule_force_delete
+ @domain.reload
+ assert_empty @domain.statuses & statuses_to_be_removed
+ end
+
+ def test_scheduling_force_delete_stops_pending_actions
+ statuses_to_be_removed = [
+ DomainStatus::PENDING_UPDATE,
+ DomainStatus::PENDING_TRANSFER,
+ DomainStatus::PENDING_RENEW,
+ DomainStatus::PENDING_CREATE,
+ ]
+
+ @domain.statuses = statuses_to_be_removed + %w[other-status]
+ @domain.schedule_force_delete
+ @domain.reload
+ assert_empty @domain.statuses & statuses_to_be_removed, 'Pending actions should be stopped'
+ end
+
+ def test_scheduling_force_delete_preserves_current_statuses
+ @domain.statuses = %w[test1 test2]
+ @domain.schedule_force_delete
+ @domain.reload
+ assert_equal %w[test1 test2], @domain.statuses_before_force_delete
+ end
+
+ def test_scheduling_force_delete_bypasses_validation
+ @domain = domains(:invalid)
+ @domain.schedule_force_delete
+ assert @domain.force_delete_scheduled?
+ end
+
+ def test_force_delete_cannot_be_scheduled_when_a_domain_is_discarded
+ @domain.discard
+ assert_raises StandardError do
+ @domain.schedule_force_delete
+ end
+ end
+
+ def test_cancelling_force_delete_bypasses_validation
+ @domain = domains(:invalid)
+ @domain.schedule_force_delete
+ @domain.cancel_force_delete
+ assert_not @domain.force_delete_scheduled?
+ end
+
+ def test_cancelling_force_delete_removes_statuses_that_were_set_on_force_delete
+ statuses = [
+ DomainStatus::FORCE_DELETE,
+ DomainStatus::SERVER_RENEW_PROHIBITED,
+ DomainStatus::SERVER_TRANSFER_PROHIBITED,
+ DomainStatus::SERVER_UPDATE_PROHIBITED,
+ DomainStatus::PENDING_DELETE,
+ DomainStatus::SERVER_MANUAL_INZONE
+ ]
+ @domain.statuses = @domain.statuses + statuses
+ @domain.schedule_force_delete
+
+ @domain.cancel_force_delete
+ @domain.reload
+
+ assert_empty @domain.statuses & statuses
+ end
+
+ def test_cancelling_force_delete_restores_statuses_that_a_domain_had_before_force_delete
+ @domain.statuses_before_force_delete = ['test1', DomainStatus::DELETE_CANDIDATE]
+
+ @domain.cancel_force_delete
+ @domain.reload
+
+ assert_equal ['test1', DomainStatus::DELETE_CANDIDATE], @domain.statuses
+ assert_nil @domain.statuses_before_force_delete
+ end
+end
diff --git a/test/system/admin_area/domains/force_delete_test.rb b/test/system/admin_area/domains/force_delete_test.rb
index f98401173..22bb23d38 100644
--- a/test/system/admin_area/domains/force_delete_test.rb
+++ b/test/system/admin_area/domains/force_delete_test.rb
@@ -44,8 +44,7 @@ class AdminAreaDomainForceDeleteTest < ApplicationSystemTestCase
end
def test_cancels_scheduled_domain_force_delete
- @domain.update_attribute(:statuses, [DomainStatus::FORCE_DELETE])
- assert @domain.force_delete_scheduled?
+ @domain.schedule_force_delete
visit edit_admin_domain_url(@domain)
click_link_or_button 'Cancel force delete'
@@ -55,4 +54,12 @@ class AdminAreaDomainForceDeleteTest < ApplicationSystemTestCase
assert_current_path edit_admin_domain_path(@domain)
assert_text 'Force delete procedure has been cancelled'
end
-end
+
+ def test_force_delete_procedure_cannot_be_scheduled_on_a_discarded_domain
+ @domain.discard
+
+ visit edit_admin_domain_url(@domain)
+ assert_no_button 'Schedule force delete'
+ assert_no_link 'Schedule force delete'
+ end
+end
\ No newline at end of file