From 2f41b0dd572648716b82b38cd90820cf3d3f10dc Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Fri, 4 Apr 2025 20:27:46 +0200 Subject: [PATCH 1/3] Add active_until to users --- ...82629_set_active_until_for_selfhosted_users.rb | 15 +++++++++++++++ db/data_schema.rb | 2 +- .../20250404182437_add_active_until_to_users.rb | 7 +++++++ db/schema.rb | 3 ++- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 db/data/20250404182629_set_active_until_for_selfhosted_users.rb create mode 100644 db/migrate/20250404182437_add_active_until_to_users.rb diff --git a/db/data/20250404182629_set_active_until_for_selfhosted_users.rb b/db/data/20250404182629_set_active_until_for_selfhosted_users.rb new file mode 100644 index 00000000..2d622774 --- /dev/null +++ b/db/data/20250404182629_set_active_until_for_selfhosted_users.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class SetActiveUntilForSelfhostedUsers < ActiveRecord::Migration[8.0] + def up + return unless DawarichSettings.self_hosted? + + # rubocop:disable Rails/SkipsModelValidations + User.where(active_until: nil).update_all(active_until: 1000.years.from_now) + # rubocop:enable Rails/SkipsModelValidations + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb index c8d2c368..c483f963 100644 --- a/db/data_schema.rb +++ b/db/data_schema.rb @@ -1 +1 @@ -DataMigrate::Data.define(version: 20250403204658) +DataMigrate::Data.define(version: 20250404182629) diff --git a/db/migrate/20250404182437_add_active_until_to_users.rb b/db/migrate/20250404182437_add_active_until_to_users.rb new file mode 100644 index 00000000..f42ca9b4 --- /dev/null +++ b/db/migrate/20250404182437_add_active_until_to_users.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddActiveUntilToUsers < ActiveRecord::Migration[8.0] + def change + add_column :users, :active_until, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index f6e71855..2c9db849 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_03_24_180755) do +ActiveRecord::Schema[8.0].define(version: 2025_04_04_182437) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" enable_extension "postgis" @@ -230,6 +230,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_03_24_180755) do t.string "current_sign_in_ip" t.string "last_sign_in_ip" t.integer "status", default: 0 + t.datetime "active_until" t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end From 6839ecdbdafccb95318b4197c98cc4427bf48baa Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Fri, 4 Apr 2025 21:12:42 +0200 Subject: [PATCH 2/3] Update specs for new user active_until column --- app/controllers/api_controller.rb | 2 +- app/controllers/application_controller.rb | 2 +- app/models/user.rb | 2 +- ...404182629_set_active_until_for_selfhosted_users.rb | 6 +++++- spec/factories/users.rb | 6 ++++++ spec/models/user_spec.rb | 11 ++++++----- spec/requests/api/v1/overland/batches_spec.rb | 2 +- spec/requests/api/v1/owntracks/points_spec.rb | 2 +- spec/requests/api/v1/points_spec.rb | 6 +++--- spec/requests/api/v1/settings_spec.rb | 2 +- spec/requests/settings_spec.rb | 2 +- spec/requests/stats_spec.rb | 4 ++-- spec/requests/trips_spec.rb | 4 ++-- 13 files changed, 31 insertions(+), 20 deletions(-) diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 868c72c0..ab8038cd 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -13,7 +13,7 @@ class ApiController < ApplicationController end def authenticate_active_api_user! - render json: { error: 'User is not active' }, status: :unauthorized unless current_api_user&.active? + render json: { error: 'User is not active' }, status: :unauthorized unless current_api_user&.active_until&.future? true end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 78071582..314c143c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -26,7 +26,7 @@ class ApplicationController < ActionController::Base end def authenticate_active_user! - return if current_user&.active? + return if current_user&.active_until&.future? redirect_to root_path, notice: 'Your account is not active.', status: :see_other end diff --git a/app/models/user.rb b/app/models/user.rb index 69fecdf5..4b463637 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -109,7 +109,7 @@ class User < ApplicationRecord end def activate - update(status: :active) + update(status: :active, active_until: 1000.years.from_now) end def sanitize_input diff --git a/db/data/20250404182629_set_active_until_for_selfhosted_users.rb b/db/data/20250404182629_set_active_until_for_selfhosted_users.rb index 2d622774..ffc410db 100644 --- a/db/data/20250404182629_set_active_until_for_selfhosted_users.rb +++ b/db/data/20250404182629_set_active_until_for_selfhosted_users.rb @@ -10,6 +10,10 @@ class SetActiveUntilForSelfhostedUsers < ActiveRecord::Migration[8.0] end def down - raise ActiveRecord::IrreversibleMigration + return unless DawarichSettings.self_hosted? + + # rubocop:disable Rails/SkipsModelValidations + User.where.not(active_until: nil).update_all(active_until: nil) + # rubocop:enable Rails/SkipsModelValidations end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 1f1c54bc..2b6c8c17 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -7,6 +7,7 @@ FactoryBot.define do end status { :active } + active_until { 1000.years.from_now } password { SecureRandom.hex(8) } @@ -25,6 +26,11 @@ FactoryBot.define do admin { true } end + trait :inactive do + status { :inactive } + active_until { 1.day.ago } + end + trait :with_immich_integration do settings do { diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 3e808a4d..0f5c73d3 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -31,7 +31,7 @@ RSpec.describe User, type: :model do describe '#activate' do context 'when self-hosted' do - let!(:user) { create(:user, status: :inactive) } + let!(:user) { create(:user, status: :inactive, active_until: 1.day.ago) } before do allow(DawarichSettings).to receive(:self_hosted?).and_return(true) @@ -39,19 +39,20 @@ RSpec.describe User, type: :model do it 'activates user after creation' do expect(user.active?).to be_truthy + expect(user.active_until).to be_within(1.minute).of(1000.years.from_now) end end context 'when not self-hosted' do - let!(:user) { create(:user, status: :inactive) } - before do - stub_const('SELF_HOSTED', false) allow(DawarichSettings).to receive(:self_hosted?).and_return(false) end - xit 'does not activate user' do + it 'does not activate user' do + user = create(:user, status: :inactive, active_until: 1.day.ago) + expect(user.active?).to be_falsey + expect(user.active_until).to be_within(1.minute).of(1.day.ago) end end end diff --git a/spec/requests/api/v1/overland/batches_spec.rb b/spec/requests/api/v1/overland/batches_spec.rb index a673480b..df5f74e0 100644 --- a/spec/requests/api/v1/overland/batches_spec.rb +++ b/spec/requests/api/v1/overland/batches_spec.rb @@ -34,7 +34,7 @@ RSpec.describe 'Api::V1::Overland::Batches', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns http unauthorized' do diff --git a/spec/requests/api/v1/owntracks/points_spec.rb b/spec/requests/api/v1/owntracks/points_spec.rb index 39cf486f..f8e6128e 100644 --- a/spec/requests/api/v1/owntracks/points_spec.rb +++ b/spec/requests/api/v1/owntracks/points_spec.rb @@ -34,7 +34,7 @@ RSpec.describe 'Api::V1::Owntracks::Points', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns http unauthorized' do diff --git a/spec/requests/api/v1/points_spec.rb b/spec/requests/api/v1/points_spec.rb index f218d085..1983640c 100644 --- a/spec/requests/api/v1/points_spec.rb +++ b/spec/requests/api/v1/points_spec.rb @@ -129,7 +129,7 @@ RSpec.describe 'Api::V1::Points', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns an unauthorized response' do @@ -150,7 +150,7 @@ RSpec.describe 'Api::V1::Points', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns an unauthorized response' do @@ -171,7 +171,7 @@ RSpec.describe 'Api::V1::Points', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns an unauthorized response' do diff --git a/spec/requests/api/v1/settings_spec.rb b/spec/requests/api/v1/settings_spec.rb index 075e3dca..3f6673e5 100644 --- a/spec/requests/api/v1/settings_spec.rb +++ b/spec/requests/api/v1/settings_spec.rb @@ -28,7 +28,7 @@ RSpec.describe 'Api::V1::Settings', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns http unauthorized' do diff --git a/spec/requests/settings_spec.rb b/spec/requests/settings_spec.rb index f457855c..a06d0b40 100644 --- a/spec/requests/settings_spec.rb +++ b/spec/requests/settings_spec.rb @@ -85,7 +85,7 @@ RSpec.describe 'Settings', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'redirects to the root path' do diff --git a/spec/requests/stats_spec.rb b/spec/requests/stats_spec.rb index 516f4cd3..b6755cb9 100644 --- a/spec/requests/stats_spec.rb +++ b/spec/requests/stats_spec.rb @@ -72,7 +72,7 @@ RSpec.describe '/stats', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns an unauthorized response' do @@ -99,7 +99,7 @@ RSpec.describe '/stats', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'returns an unauthorized response' do diff --git a/spec/requests/trips_spec.rb b/spec/requests/trips_spec.rb index 3f536edc..af654048 100644 --- a/spec/requests/trips_spec.rb +++ b/spec/requests/trips_spec.rb @@ -56,7 +56,7 @@ RSpec.describe '/trips', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'redirects to the root path' do @@ -93,7 +93,7 @@ RSpec.describe '/trips', type: :request do context 'when user is inactive' do before do - user.update(status: :inactive) + user.update(status: :inactive, active_until: 1.day.ago) end it 'redirects to the root path' do From f3e4ff1a7ef232b91d20699fadffed61a5601845 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Fri, 4 Apr 2025 21:15:33 +0200 Subject: [PATCH 3/3] Add deprecation notice for the `status` column. --- app/models/user.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/models/user.rb b/app/models/user.rb index 4b463637..fd56c07b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -109,6 +109,7 @@ class User < ApplicationRecord end def activate + # TODO: Remove the `status` column in the future. update(status: :active, active_until: 1000.years.from_now) end