From 96aaeb37ad0ed939b62dca30880e9d3c24a8b8d2 Mon Sep 17 00:00:00 2001
From: Heinrich Lee Yu <heinrich@gitlab.com>
Date: Thu, 7 Apr 2022 16:58:48 +0800
Subject: [PATCH] Keep edited timestamp when reacting to old notes

Copies updated_at to last_edited_at before bumping updated_at.
last_edited_at was added later and we decided not to do a backfill
migration so we just did a fallback to updated_at for old notes.

Changelog: fixed
---
 app/models/note.rb       | 10 +++++++++-
 spec/models/note_spec.rb | 23 +++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/app/models/note.rb b/app/models/note.rb
index 7803a1c1deac..c24d47fc61f5 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -504,7 +504,15 @@ def bump_updated_at
     # Instead of calling touch which is throttled via ThrottledTouch concern,
     # we bump the updated_at column directly. This also prevents executing
     # after_commit callbacks that we don't need.
-    update_column(:updated_at, Time.current)
+    attributes_to_update = { updated_at: Time.current }
+
+    # Notes that were edited before the `last_edited_at` column was added, fall back to `updated_at` for the edit time.
+    # We copy this over to the correct column so we don't erroneously change the edit timestamp.
+    if updated_by_id.present? && read_attribute(:last_edited_at).blank?
+      attributes_to_update[:last_edited_at] = updated_at
+    end
+
+    update_columns(attributes_to_update)
   end
 
   def expire_etag_cache
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index da76c4975b43..b17cc659ff68 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -1685,4 +1685,27 @@ def expect_expiration(noteable)
       expect(note.commands_changes.keys).to contain_exactly(:emoji_award, :time_estimate, :spend_time)
     end
   end
+
+  describe '#bump_updated_at', :freeze_time do
+    it 'sets updated_at to the current timestamp' do
+      note = create(:note, updated_at: 1.day.ago)
+
+      note.bump_updated_at
+      note.reload
+
+      expect(note.updated_at).to be_like_time(Time.current)
+    end
+
+    context 'with legacy edited note' do
+      it 'copies updated_at to last_edited_at before bumping the timestamp' do
+        note = create(:note, updated_at: 1.day.ago, updated_by: create(:user), last_edited_at: nil)
+
+        note.bump_updated_at
+        note.reload
+
+        expect(note.last_edited_at).to be_like_time(1.day.ago)
+        expect(note.updated_at).to be_like_time(Time.current)
+      end
+    end
+  end
 end
-- 
GitLab