From a8aaf62e629f0c67b938b6c27657a225364d3c39 Mon Sep 17 00:00:00 2001 From: Anton Khorev Date: Tue, 24 Oct 2023 20:42:23 +0300 Subject: [PATCH] Add earliest allowed deletion time to user model --- .rubocop_todo.yml | 2 +- app/models/changeset.rb | 11 ++-- app/models/user.rb | 12 ++++ ...70422_add_closed_at_index_to_changesets.rb | 7 +++ db/structure.sql | 8 +++ test/models/user_test.rb | 58 +++++++++++++++++++ 6 files changed, 92 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20231117170422_add_closed_at_index_to_changesets.rb diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e3407c6dc..bd2f92309 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -61,7 +61,7 @@ Metrics/BlockNesting: # Offense count: 26 # Configuration parameters: CountComments, CountAsOne. Metrics/ClassLength: - Max: 286 + Max: 297 # Offense count: 59 # Configuration parameters: AllowedMethods, AllowedPatterns. diff --git a/app/models/changeset.rb b/app/models/changeset.rb index ce0943824..137de18fd 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -14,11 +14,12 @@ # # Indexes # -# changesets_bbox_idx (min_lat,max_lat,min_lon,max_lon) USING gist -# changesets_closed_at_idx (closed_at) -# changesets_created_at_idx (created_at) -# changesets_user_id_created_at_idx (user_id,created_at) -# changesets_user_id_id_idx (user_id,id) +# changesets_bbox_idx (min_lat,max_lat,min_lon,max_lon) USING gist +# changesets_closed_at_idx (closed_at) +# changesets_created_at_idx (created_at) +# changesets_user_id_created_at_idx (user_id,created_at) +# changesets_user_id_id_idx (user_id,id) +# index_changesets_on_user_id_and_closed_at (user_id,closed_at) # # Foreign Keys # diff --git a/app/models/user.rb b/app/models/user.rb index 7571dd9dc..1942a25cc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -419,6 +419,18 @@ class User < ApplicationRecord end end + def deletion_allowed_at + unless Settings.user_account_deletion_delay.nil? + last_changeset = changesets.reorder(:closed_at => :desc).first + return last_changeset.closed_at.utc + Settings.user_account_deletion_delay.hours if last_changeset + end + creation_time.utc + end + + def deletion_allowed? + deletion_allowed_at <= Time.now.utc + end + private def encrypt_password diff --git a/db/migrate/20231117170422_add_closed_at_index_to_changesets.rb b/db/migrate/20231117170422_add_closed_at_index_to_changesets.rb new file mode 100644 index 000000000..e9d7e62f7 --- /dev/null +++ b/db/migrate/20231117170422_add_closed_at_index_to_changesets.rb @@ -0,0 +1,7 @@ +class AddClosedAtIndexToChangesets < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + add_index :changesets, [:user_id, :closed_at], :algorithm => :concurrently + end +end diff --git a/db/structure.sql b/db/structure.sql index 56e778523..f74d4d571 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -2499,6 +2499,13 @@ CREATE INDEX index_changeset_comments_on_changeset_id_and_created_at ON public.c CREATE INDEX index_changeset_comments_on_created_at ON public.changeset_comments USING btree (created_at); +-- +-- Name: index_changesets_on_user_id_and_closed_at; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_changesets_on_user_id_and_closed_at ON public.changesets USING btree (user_id, closed_at); + + -- -- Name: index_changesets_subscribers_on_changeset_id; Type: INDEX; Schema: public; Owner: - -- @@ -3499,6 +3506,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('23'), ('22'), ('21'), +('20231117170422'), ('20231101222146'), ('20231029151516'), ('20231010194809'), diff --git a/test/models/user_test.rb b/test/models/user_test.rb index a4ed07e09..5c48bb969 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -282,4 +282,62 @@ class UserTest < ActiveSupport::TestCase oauth_access_token.reload assert_predicate oauth_access_token, :revoked? end + + def test_deletion_allowed_when_no_changesets + with_user_account_deletion_delay(10000) do + user = create(:user) + assert_predicate user, :deletion_allowed? + end + end + + def test_deletion_allowed_without_delay + with_user_account_deletion_delay(nil) do + user = create(:user) + create(:changeset, :user => user) + user.reload + assert_predicate user, :deletion_allowed? + end + end + + def test_deletion_allowed_past_delay + with_user_account_deletion_delay(10) do + user = create(:user) + create(:changeset, :user => user, :created_at => Time.now.utc - 12.hours, :closed_at => Time.now.utc - 10.hours) + user.reload + assert_predicate user, :deletion_allowed? + end + end + + def test_deletion_allowed_during_delay + with_user_account_deletion_delay(10) do + user = create(:user) + create(:changeset, :user => user, :created_at => Time.now.utc - 11.hours, :closed_at => Time.now.utc - 9.hours) + user.reload + assert_not_predicate user, :deletion_allowed? + assert_equal Time.now.utc + 1.hour, user.deletion_allowed_at + end + end + + def test_deletion_allowed_past_zero_delay + with_user_account_deletion_delay(0) do + user = create(:user) + create(:changeset, :user => user, :created_at => Time.now.utc, :closed_at => Time.now.utc + 1.hour) + travel 90.minutes do + user.reload + assert_predicate user, :deletion_allowed? + end + end + end + + def test_deletion_allowed_during_zero_delay + with_user_account_deletion_delay(0) do + user = create(:user) + create(:changeset, :user => user, :created_at => Time.now.utc, :closed_at => Time.now.utc + 1.hour) + travel 30.minutes do + user.reload + assert_not_predicate user, :deletion_allowed? + assert_equal Time.now.utc + 30.minutes, user.deletion_allowed_at + end + end + end end -- 2.39.5