FIX: remove duplicated holidays because of timezone change (#489)

When a user updates timezone, it creates duplicated holidays.

Beside the fix, migration was added to remove duplicated records. Timezone change can only update date for 24 hours, so we are searching for records with start date around that range.
This commit is contained in:
Krzysztof Kotlarek 2023-11-23 19:48:47 -08:00 committed by GitHub
parent 71b45a9a04
commit 61ec1f7545
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 55 additions and 10 deletions

View File

@ -0,0 +1,25 @@
# frozen_string_literal: true
class DeleteSimilarHolidays < ActiveRecord::Migration[7.0]
def up
execute <<~SQL
DELETE
FROM calendar_events ce
WHERE
ce.id IN (SELECT DISTINCT(ce3.id) FROM calendar_events ce2
LEFT JOIN calendar_events ce3 ON ce3.user_id = ce2.user_id AND ce3.description = ce2.description
WHERE ce2.start_date >= (ce3.start_date - INTERVAL '1 days')
AND ce2.start_date <= (ce3.start_date + INTERVAL '1 days')
AND ce2.timezone IS NOT NULL
AND ce3.timezone IS NULL
AND ce3.id != ce2.id
AND ce2.post_id IS NULL
AND ce3.post_id IS NULL
)
SQL
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -76,17 +76,24 @@ module Jobs
end
event =
CalendarEvent.find_or_initialize_by(
topic_id: topic_id,
user_id: user_id,
description: holiday[:name],
start_date: date,
region: region,
)
CalendarEvent
.where(topic_id: topic_id, user_id: user_id, description: holiday[:name])
.where(
"start_date >= :from AND start_date <= :to",
from: date - 1.day,
to: date + 1.day,
)
.first_or_initialize
event.username = usernames[user_id]
event.timezone = tz.name if tz
event.save!
event.update!(
topic_id: topic_id,
user_id: user_id,
description: holiday[:name],
start_date: date,
region: region,
username: usernames[user_id],
timezone: tz&.name,
)
end
end
end

View File

@ -124,6 +124,19 @@ describe DiscourseCalendar::CreateHolidayEvents do
expect(created_event.reload.username).to eq("new_username")
end
it "does not create duplicates when timezone is changed" do
frenchy
DiscourseCalendar::CreateHolidayEvents.new.execute(nil)
created_event = CalendarEvent.last
expect(created_event.timezone).to eq(frenchy.user_option.timezone)
frenchy.user_option.update!(timezone: "Asia/Taipei")
expect { DiscourseCalendar::CreateHolidayEvents.new.execute(nil) }.not_to change {
CalendarEvent.count
}
expect(created_event.reload.timezone).to eq("Asia/Taipei")
end
it "cleans up holidays from deactivated/silenced/suspended users" do
frenchy
freeze_time Time.zone.local(2019, 8, 1)