FEATURE: Hidden SiteSetting.keep_old_ip_address_count to track IP history.

This commit is contained in:
Guo Xiang Tan 2020-09-17 10:55:29 +08:00
parent c2a660ead3
commit b47b640598
No known key found for this signature in database
GPG Key ID: FBD110179AAC1F20
5 changed files with 101 additions and 0 deletions

View File

@ -724,6 +724,28 @@ class User < ActiveRecord::Base
def update_ip_address!(new_ip_address)
unless ip_address == new_ip_address || new_ip_address.blank?
update_column(:ip_address, new_ip_address)
if SiteSetting.keep_old_ip_address_count > 0
DB.exec(<<~SQL, user_id: self.id, ip_address: new_ip_address, current_timestamp: Time.zone.now)
INSERT INTO user_ip_address_histories (user_id, ip_address, created_at, updated_at)
VALUES (:user_id, :ip_address, :current_timestamp, :current_timestamp)
ON CONFLICT (user_id, ip_address)
DO
UPDATE SET updated_at = :current_timestamp
SQL
DB.exec(<<~SQL, user_id: self.id, offset: SiteSetting.keep_old_ip_address_count)
DELETE FROM user_ip_address_histories
WHERE id IN (
SELECT
id
FROM user_ip_address_histories
WHERE user_id = :user_id
ORDER BY updated_at DESC
OFFSET :offset
)
SQL
end
end
end

View File

@ -0,0 +1,8 @@
# frozen_string_literal: true
class UserIpAddressHistory < ActiveRecord::Base
belongs_to :user
validates :user_id, presence: true
validates :ip_address, presence: true, uniqueness: { scope: :user_id }
end

View File

@ -1483,6 +1483,9 @@ security:
cors_origins:
default: ""
type: list
keep_old_ip_address_count:
default: 0
hidden: true
use_admin_ip_allowlist:
default: false
client: true

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class CreateUserIpAddressHistories < ActiveRecord::Migration[6.0]
def up
create_table :user_ip_address_histories do |t|
t.integer :user_id, null: false
t.inet :ip_address, null: false
t.timestamps
end
add_index :user_ip_address_histories, [:user_id, :ip_address], unique: true
end
def down
drop_table :user_ip_address_histories
end
end

View File

@ -2431,4 +2431,54 @@ describe User do
expect(user.encoded_username(lower: true)).to eq("l%C3%B6we")
end
end
describe '#update_ip_address!' do
it 'updates ip_address correctly' do
expect do
user.update_ip_address!('127.0.0.1')
end.to change { user.reload.ip_address.to_s }.to('127.0.0.1')
expect do
user.update_ip_address!('127.0.0.1')
end.to_not change { user.reload.ip_address }
end
describe 'keeping old ip address' do
before do
SiteSetting.keep_old_ip_address_count = 2
end
it 'tracks old user record correctly' do
expect do
user.update_ip_address!('127.0.0.1')
end.to change { UserIpAddressHistory.where(user_id: user.id).count }.by(1)
freeze_time 10.minutes.from_now
expect do
user.update_ip_address!('0.0.0.0')
end.to change { UserIpAddressHistory.where(user_id: user.id).count }.by(1)
freeze_time 11.minutes.from_now
expect do
user.update_ip_address!('127.0.0.1')
end.to_not change { UserIpAddressHistory.where(user_id: user.id).count }
expect(UserIpAddressHistory.find_by(
user_id: user.id, ip_address: '127.0.0.1'
).updated_at).to eq_time(Time.zone.now)
freeze_time 12.minutes.from_now
expect do
user.update_ip_address!('0.0.0.1')
end.to change { UserIpAddressHistory.where(user_id: user.id).count }.by(0)
expect(
UserIpAddressHistory.where(user_id: user.id).pluck(:ip_address).map(&:to_s)
).to eq(['127.0.0.1', '0.0.0.1'])
end
end
end
end