discourse-calendar/spec/integration/post_spec.rb

827 lines
30 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frozen_string_literal: true
require "rails_helper"
require "securerandom"
describe Post do
before do
freeze_time
Jobs.run_immediately!
SiteSetting.calendar_enabled = true
SiteSetting.discourse_post_event_enabled = true
end
let(:user) { Fabricate(:user, admin: true, refresh_auto_groups: true) }
context "with a public event" do
let(:post_1) { Fabricate(:post) }
let(:event_1) { Fabricate(:event, post: post_1, raw_invitees: ["trust_level_0"]) }
context "when a post is updated" do
context "when the post has a valid event" do
context "when the event markup is removed" do
it "destroys the associated event" do
start = Time.now.utc.iso8601(3)
post = create_post_with_event(user)
expect(post.reload.event.persisted?).to eq(true)
revisor = PostRevisor.new(post, post.topic)
revisor.revise!(user, raw: "The event is over. Come back another day.")
expect(post.reload.event).to be(nil)
end
end
context "when event is on going" do
let(:going_user) { Fabricate(:user) }
let(:interested_user) { Fabricate(:user) }
before do
SiteSetting.editing_grace_period = 1.minute
PostActionNotifier.enable
SiteSetting.discourse_post_event_edit_notifications_time_extension = 180
end
context "when in edit grace period" do
before do
event_1.event_dates.first.update_columns(starts_at: 3.hours.ago, ends_at: 2.hours.ago)
# clean state
Notification.destroy_all
interested_user.reload
going_user.reload
end
it "sends a post revision to going invitees" do
DiscoursePostEvent::Invitee.create_attendance!(going_user.id, post_1.id, :going)
DiscoursePostEvent::Invitee.create_attendance!(
interested_user.id,
post_1.id,
:interested,
)
expect {
revisor = PostRevisor.new(post_1)
revisor.revise!(
user,
{ raw: post_1.raw + "\nWe are bout half way into our event!" },
revised_at: Time.now + 2.minutes,
)
}.to change { going_user.notifications.count }.by(1)
expect(interested_user.notifications.count).to eq(0)
end
end
context "when not edit grace period" do
before { event_1.event_dates.first.update_columns(starts_at: 5.hours.ago) }
it "doesnt send a post revision to anyone" do
DiscoursePostEvent::Invitee.create_attendance!(going_user.id, post_1.id, :going)
DiscoursePostEvent::Invitee.create_attendance!(
interested_user.id,
event_1.id,
:interested,
)
expect {
revisor = PostRevisor.new(event_1.post)
revisor.revise!(
user,
{ raw: event_1.post.raw + "\nWe are bout half way into our event!" },
revised_at: Time.now + 2.minutes,
)
}.to change {
going_user.notifications.count + interested_user.notifications.count
}.by(0)
end
end
context "with an event with recurrence" do
before do
freeze_time Time.utc(2020, 8, 12, 16, 32)
event_1.update_with_params!(
recurrence: "FREQ=WEEKLY;BYDAY=MO",
original_starts_at: 3.hours.ago,
original_ends_at: nil,
)
DiscoursePostEvent::Invitee.create_attendance!(going_user.id, event_1.id, :going)
DiscoursePostEvent::Invitee.create_attendance!(
interested_user.id,
event_1.id,
:interested,
)
event_1.reload
# we stop processing jobs immediately at this point to prevent infinite loop
# as future event ended job would finish now, trigger next recurrence, and anodther job...
Jobs.run_later!
end
context "when the event ends" do
it "sets the next dates" do
event_1.update_with_params!(original_ends_at: Time.now)
expect(event_1.starts_at.to_s).to eq("2020-08-19 13:32:00 UTC")
expect(event_1.ends_at.to_s).to eq("2020-08-19 16:32:00 UTC")
end
it "it removes status from every invitees" do
expect(event_1.invitees.pluck(:status)).to match_array(
[
DiscoursePostEvent::Invitee.statuses[:going],
DiscoursePostEvent::Invitee.statuses[:interested],
],
)
event_1.update_with_params!(original_ends_at: Time.now)
expect(event_1.invitees.pluck(:status).compact).to eq([])
end
# that will be handled by new job, uncomment when finishedh
it "doesnt resend event creation notification to invitees" do
expect { event_1.update_with_params!(original_ends_at: Time.now) }.not_to change {
going_user.notifications.count
}
end
end
end
context "when updating raw_invitees" do
let(:lurker_1) { Fabricate(:user) }
let(:group_1) { Fabricate(:group) }
it "doesnt accept usernames" do
event_1.update_with_params!(raw_invitees: [lurker_1.username])
expect(event_1.raw_invitees).to eq(["trust_level_0"])
end
it "doesnt accept another group than trust_level_0" do
event_1.update_with_params!(raw_invitees: [group_1.name])
expect(event_1.raw_invitees).to eq(["trust_level_0"])
end
end
context "when updating status to private" do
it "it changes the status and force invitees" do
expect(event_1.raw_invitees).to eq(["trust_level_0"])
expect(event_1.status).to eq(DiscoursePostEvent::Event.statuses[:public])
event_1.update_with_params!(status: DiscoursePostEvent::Event.statuses[:private])
expect(event_1.raw_invitees).to eq([])
expect(event_1.status).to eq(DiscoursePostEvent::Event.statuses[:private])
end
end
end
end
end
context "when a post is created" do
context "when the post contains one valid event" do
context "when the acting user is admin" do
it "creates the post event" do
start = Time.now.utc.iso8601(3)
post =
PostCreator.create!(
user,
title: "Sell a boat party",
raw: "[event start=\"#{start}\"]\n[/event]",
)
expect(post.reload.persisted?).to eq(true)
expect(post.event.persisted?).to eq(true)
expect(post.event.original_starts_at).to eq_time(Time.parse(start))
end
it "works with name attribute" do
post = create_post_with_event(user, 'name="foo bar"').reload
expect(post.event.name).to eq("foo bar")
post = create_post_with_event(user, 'name=""').reload
expect(post.event.name).to be_blank
post = create_post_with_event(user, "name=").reload
expect(post.event.name).to be_blank
end
it "works with url attribute" do
url = "https://www.discourse.org"
post = create_post_with_event(user, "url=\"#{url}\"").reload
expect(post.event.url).to eq(url)
post = create_post_with_event(user, 'url=""').reload
expect(post.event.url).to be_blank
post = create_post_with_event(user, "url=").reload
expect(post.event.url).to be_blank
end
it "works with status attribute" do
post = create_post_with_event(user, 'status="private"').reload
expect(post.event.status).to eq(DiscoursePostEvent::Event.statuses[:private])
post = create_post_with_event(user, 'status=""').reload
expect(post.event.status).to eq(DiscoursePostEvent::Event.statuses[:standalone])
post = create_post_with_event(user, "status=").reload
expect(post.event.status).to eq(DiscoursePostEvent::Event.statuses[:standalone])
end
it "works with allowedGroups attribute" do
Fabricate(:group, name: "euro")
Fabricate(:group, name: "america")
post = create_post_with_event(user, 'allowedGroups="euro"').reload
expect(post.event.raw_invitees).to eq([])
post = create_post_with_event(user, 'status="public" allowedGroups="euro"').reload
expect(post.event.raw_invitees).to eq(%w[trust_level_0])
post = create_post_with_event(user, 'status="standalone" allowedGroups="euro"').reload
expect(post.event.raw_invitees).to eq([])
post = create_post_with_event(user, 'status="private" allowedGroups="euro"').reload
expect(post.event.raw_invitees).to eq(%w[euro])
post =
create_post_with_event(user, 'status="private" allowedGroups="euro,america"').reload
expect(post.event.raw_invitees).to match_array(%w[euro america])
post = create_post_with_event(user, 'status="private" allowedGroups=""').reload
expect(post.event.raw_invitees).to eq([])
post = create_post_with_event(user, 'status="private" allowedGroups=').reload
expect(post.event.raw_invitees).to eq([])
end
it "works with localised automatic group names" do
I18n.locale = SiteSetting.default_locale = "fr"
group = Group.find(Group::AUTO_GROUPS[:trust_level_0])
group.update!(name: I18n.t("groups.default_names.trust_level_0"))
post =
create_post_with_event(user, 'status="public" allowedGroups="trust_level_0"').reload
expect(post.event.raw_invitees).to eq(%w[trust_level_0])
end
it "works with reminders attribute" do
post = create_post_with_event(user).reload
expect(post.event.reminders).to eq(nil)
post =
create_post_with_event(
user,
'reminders="notification.1.hours,bumpTopic.-3.days"',
).reload
expect(post.event.reminders).to eq("notification.1.hours,bumpTopic.-3.days")
end
context "with custom fields" do
before { SiteSetting.discourse_post_event_allowed_custom_fields = "foo-bar|bar" }
it "works with allowed custom fields" do
post = create_post_with_event(user, 'fooBar="1"').reload
expect(post.event.custom_fields["foo-bar"]).to eq("1")
post = create_post_with_event(user, 'bar="2"').reload
expect(post.event.custom_fields["bar"]).to eq("2")
end
it "doesnt work with not allowed custom fields" do
post = create_post_with_event(user, 'baz="3"').reload
expect(post.event.custom_fields["baz"]).to eq(nil)
end
end
end
context "when the acting user has rights to create events" do
let(:user_with_rights) { Fabricate(:user, refresh_auto_groups: true) }
let(:group) { Fabricate(:group, users: [user_with_rights]) }
before { SiteSetting.discourse_post_event_allowed_on_groups = group.id.to_s }
it "creates the post event" do
start = Time.now.utc.iso8601(3)
post =
PostCreator.create!(
user_with_rights,
title: "Sell a boat party",
raw: "[event start=\"#{start}\"]\n[/event]",
)
expect(post.reload.persisted?).to eq(true)
expect(post.event.persisted?).to eq(true)
expect(post.event.original_starts_at).to eq_time(Time.parse(start))
end
end
context "when the acting user doesnt have rights to create events" do
let(:user_without_rights) { Fabricate(:user, refresh_auto_groups: true) }
let(:group) { Fabricate(:group, users: [user]) }
before { SiteSetting.discourse_post_event_allowed_on_groups = group.id.to_s }
it "raises an error" do
start = Time.now.utc.iso8601(3)
expect do
PostCreator.create!(
user_without_rights,
title: "Sell a boat party",
raw: "[event start=\"#{start}\"]\n[/event]",
)
end.to(
raise_error(ActiveRecord::RecordNotSaved).with_message(
I18n.t(
"discourse_calendar.discourse_post_event.errors.models.event.acting_user_not_allowed_to_create_event",
),
),
)
end
end
end
context "when the post contains one invalid event" do
context "when start is invalid" do
it "raises an error" do
expect do
PostCreator.create!(
user,
title: "Sell a boat party",
raw: "[event start=\"x\"]\n[/event]",
)
end.to(
raise_error(ActiveRecord::RecordNotSaved).with_message(
I18n.t(
"discourse_calendar.discourse_post_event.errors.models.event.start_must_be_present_and_a_valid_date",
),
),
)
end
end
context "when recurrence is invalid" do
it "raises an error" do
expect { create_post_with_event(user, 'recurrence="foo"') }.to raise_error(
I18n.t(
"discourse_calendar.discourse_post_event.errors.models.event.invalid_recurrence",
),
)
end
end
context "when start is not provided or" do
it "is not cooked" do
post = PostCreator.create!(user, title: "Sell a boat party", raw: <<~TXT)
[event end=\"1\"]
[/event]
TXT
expect(!post.cooked.include?("discourse-post-event")).to be(true)
end
end
context "when end is provided and is invalid" do
it "raises an error" do
expect do
PostCreator.create!(
user,
title: "Sell a boat party",
raw: "[event start=\"#{Time.now.utc.iso8601(3)}\" end=\"d\"]\n[/event]",
)
end.to(
raise_error(ActiveRecord::RecordNotSaved).with_message(
I18n.t(
"discourse_calendar.discourse_post_event.errors.models.event.end_must_be_a_valid_date",
),
),
)
end
end
end
context "when the post contains multiple events" do
it "raises an error" do
expect { PostCreator.create!(user, title: "Sell a boat party", raw: <<~TXT) }.to(
[event start=\"#{Time.now.utc.iso8601(3)}\"]
[/event]
[event start=\"#{Time.now.utc.iso8601(3)}\"]
[/event]
TXT
raise_error(ActiveRecord::RecordNotSaved).with_message(
I18n.t("discourse_calendar.discourse_post_event.errors.models.event.only_one_event"),
),
)
end
end
end
context "when a post with an event is destroyed" do
it "sets deleted_at on the post_event" do
expect(event_1.deleted_at).to be_nil
PostDestroyer.new(user, event_1.post).destroy
event_1.reload
expect(event_1.deleted_at).to eq_time(Time.now)
end
end
context "when a post with an event is recovered" do
it "nullifies deleted_at on the post_event" do
PostDestroyer.new(user, event_1.post).destroy
expect(event_1.reload.deleted_at).to eq_time(Time.now)
PostDestroyer.new(user, Post.with_deleted.find(event_1.id)).recover
expect(event_1.reload.deleted_at).to be_nil
end
end
end
context "with a private event" do
before { freeze_time Time.utc(2020, 8, 12, 16, 32) }
let(:invitee_1) { Fabricate(:user) }
let(:invitee_2) { Fabricate(:user) }
let(:group_1) do
Fabricate(:group).tap do |g|
g.add(invitee_1)
g.add(invitee_2)
g.save!
end
end
let(:post_1) { Fabricate(:post) }
let(:event_1) do
Fabricate(
:event,
post: post_1,
status: DiscoursePostEvent::Event.statuses[:private],
raw_invitees: [group_1.name],
original_starts_at: 3.hours.ago,
original_ends_at: nil,
)
end
context "with an event with recurrence" do
let(:event_1) do
Fabricate(
:event,
post: post_1,
status: DiscoursePostEvent::Event.statuses[:private],
raw_invitees: [group_1.name],
recurrence: "FREQ=WEEKLY;BYDAY=MO",
original_starts_at: 2.hours.from_now,
original_ends_at: nil,
)
end
before do
# we stop processing jobs immediately at this point to prevent infinite loop
# as future event ended job would finish now, trigger next recurrence, and anodther job...
Jobs.run_later!
end
context "when updating the end" do
it "resends event creation notification to invitees and possible invitees" do
expect { event_1.update_with_params!(original_ends_at: 3.hours.from_now) }.to change {
invitee_1.notifications.count + invitee_2.notifications.count
}.by(2)
end
end
end
context "when updating raw_invitees" do
let(:lurker_1) { Fabricate(:user) }
let(:group_2) { Fabricate(:group) }
it "doesnt accept usernames" do
expect { event_1.update_with_params!(raw_invitees: [lurker_1.username]) }.to raise_error(
ActiveRecord::RecordInvalid,
)
end
it "accepts another group than trust_level_0" do
event_1.update_with_params!(raw_invitees: [group_2.name])
expect(event_1.raw_invitees).to eq([group_2.name])
end
end
context "when updating status to public" do
it "it changes the status and force invitees" do
expect(event_1.raw_invitees).to eq([group_1.name])
expect(event_1.status).to eq(DiscoursePostEvent::Event.statuses[:private])
event_1.update_with_params!(status: DiscoursePostEvent::Event.statuses[:public])
expect(event_1.raw_invitees).to eq(["trust_level_0"])
expect(event_1.status).to eq(DiscoursePostEvent::Event.statuses[:public])
end
end
it "rejects private groups in allowedGroups" do
moderator = Fabricate(:user, moderator: true)
private_group = Fabricate(:group, visibility_level: Group.visibility_levels[:owners])
expect {
create_post_with_event(moderator, "allowedGroups='#{private_group.name}'")
}.to raise_error(ActiveRecord::RecordNotSaved)
end
it "rejects non-existent groups in allowedGroups" do
moderator = Fabricate(:user, moderator: true)
expect {
create_post_with_event(moderator, "allowedGroups='non-existent_group_name'")
}.to raise_error(ActiveRecord::RecordNotSaved)
end
it "rejects public groups with private members in allowedGroups" do
moderator = Fabricate(:user, moderator: true)
public_group_with_private_members =
Fabricate(
:group,
visibility_level: Group.visibility_levels[:public],
members_visibility_level: Group.visibility_levels[:owners],
)
expect {
create_post_with_event(
moderator,
"allowedGroups='#{public_group_with_private_members.name}'",
)
}.to raise_error(ActiveRecord::RecordNotSaved)
end
end
context "with holiday events" do
let(:calendar_post) { create_post(raw: "[calendar]\n[/calendar]") }
before do
SiteSetting.holiday_calendar_topic_id = calendar_post.topic_id
SiteSetting.enable_user_status = true
end
context "when adding a post with an event" do
it "sets holiday user status" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
raw = 'Vacation [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: calendar_post.topic)
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(I18n.t("discourse_calendar.holiday_status.description"))
expect(status.emoji).to eq(SiteSetting.holiday_status_emoji)
expect(status.ends_at).to eq_time(Time.utc(2018, 6, 6, 10, 20))
end
it "doesn't set holiday user status if user already has custom user status" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
# user sets a custom status
custom_status = { description: "I am working on holiday", emoji: "construction_worker_man" }
user.set_status!(custom_status[:description], custom_status[:emoji])
raw = 'Vacation [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: calendar_post.topic, user: user)
# a holiday status wasn't set:
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(custom_status[:description])
expect(status.emoji).to eq(custom_status[:emoji])
end
context "when using multiple calendars" do
let(:regular_calendar_post) { create_post(raw: "[calendar]\n[/calendar]") }
it "doesn't set holiday user status for a non-holiday calendar" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
raw = 'Meeting [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: regular_calendar_post.topic, user: user)
# a holiday status wasn't set:
expect(post.user.user_status).to be_nil
end
end
context "when custom emoji is set" do
custom_emoji = "palm_tree"
before { SiteSetting.holiday_status_emoji = custom_emoji }
it "sets holiday user status with custom emoji" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
raw =
'Vacation [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: calendar_post.topic)
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(I18n.t("discourse_calendar.holiday_status.description"))
expect(status.emoji).to eq(custom_emoji)
expect(status.ends_at).to eq_time(Time.utc(2018, 6, 6, 10, 20))
end
end
context "when custom emoji is blank" do
before { SiteSetting.holiday_status_emoji = "" }
it "sets holiday user status with the default emoji" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
raw =
'Vacation [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: calendar_post.topic)
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(I18n.t("discourse_calendar.holiday_status.description"))
expect(status.emoji).to eq("date")
expect(status.ends_at).to eq_time(Time.utc(2018, 6, 6, 10, 20))
end
end
end
context "when updating event dates" do
it "sets holiday user status" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
today = "2018-06-05"
tomorrow = "2018-06-06"
raw = "Vacation [date='#{tomorrow}']"
post = create_post(raw: raw, topic: calendar_post.topic)
expect(post.user.user_status).to be_blank
PostRevisor.new(post).revise!(post.user, { raw: "Vacation [date='#{today}']" })
post.reload
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(I18n.t("discourse_calendar.holiday_status.description"))
expect(status.emoji).to eq(SiteSetting.holiday_status_emoji)
expect(status.ends_at).to eq_time(Time.utc(2018, 6, 6, 0, 0))
end
it "doesn't set holiday user status if user already has custom user status" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
today = "2018-06-05"
tomorrow = "2018-06-06"
raw = "Vacation [date='#{tomorrow}']"
post = create_post(raw: raw, topic: calendar_post.topic)
expect(post.user.user_status).to be_blank
# user sets a custom status
custom_status = { description: "I am working on holiday", emoji: "construction_worker_man" }
post.user.set_status!(custom_status[:description], custom_status[:emoji])
PostRevisor.new(post).revise!(post.user, { raw: "Vacation [date='#{today}']" })
post.reload
# a holiday status wasn't set:
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(custom_status[:description])
expect(status.emoji).to eq(custom_status[:emoji])
end
end
context "when deleting a post with an event" do
it "clears user status that was previously set by the calendar plugin" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
raw = 'Vacation [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: calendar_post.topic)
DiscourseCalendar::UpdateHolidayUsernames.new.execute(nil)
# the job has set the holiday status:
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(I18n.t("discourse_calendar.holiday_status.description"))
expect(status.emoji).to eq(SiteSetting.holiday_status_emoji)
expect(status.ends_at).to eq_time(Time.utc(2018, 6, 6, 10, 20))
# after destroying the post the holiday status disappears:
PostDestroyer.new(user, post).destroy
post.user.reload
expect(post.user.user_status).to be_nil
end
it "doesn't clear user status that wasn't set by the calendar plugin" do
freeze_time Time.utc(2018, 6, 5, 10, 30)
raw = 'Vacation [date="2018-06-05" time="10:20:00"] to [date="2018-06-06" time="10:20:00"]'
post = create_post(raw: raw, topic: calendar_post.topic)
DiscourseCalendar::UpdateHolidayUsernames.new.execute(nil)
# the job has set the holiday status:
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(I18n.t("discourse_calendar.holiday_status.description"))
expect(status.emoji).to eq(SiteSetting.holiday_status_emoji)
expect(status.ends_at).to eq_time(Time.utc(2018, 6, 6, 10, 20))
# user sets a custom status
custom_status = { description: "I am working on holiday", emoji: "construction_worker_man" }
post.user.set_status!(custom_status[:description], custom_status[:emoji])
# the status that was set by user doesn't disappear after destroying the post:
PostDestroyer.new(user, post).destroy
post.user.reload
status = post.user.user_status
expect(status).to be_present
expect(status.description).to eq(custom_status[:description])
expect(status.emoji).to eq(custom_status[:emoji])
end
end
end
describe "timezone handling" do
before { freeze_time Time.utc(2022, 7, 24, 13, 00) }
it "stores the correct information in the database" do
expected_datetime = ActiveSupport::TimeZone["Australia/Sydney"].parse("2022-07-24 14:01")
post =
PostCreator.create!(
user,
title: "Beach party",
raw: "[event start='2022-07-24 14:01' timezone='Australia/Sydney']\n[/event]",
).reload
expect(post.event.timezone).to eq("Australia/Sydney")
expect(post.event.original_starts_at).to eq_time(expected_datetime)
expect(post.event.starts_at).to eq_time(expected_datetime)
expect(post.event.event_dates.first.starts_at).to eq_time(expected_datetime)
end
it "raises an error for invalid timezone" do
expect {
PostCreator.create!(
user,
title: "Beach party",
raw: "[event start='2022-07-24 14:01' timezone='Westeros/Winterfell']\n[/event]",
)
}.to raise_error(
I18n.t("discourse_calendar.discourse_post_event.errors.models.event.invalid_timezone"),
)
end
it "handles simple weekly recurrence correctly" do
# Friday in Aus, Thursday in UTC
expected_original_datetime =
ActiveSupport::TimeZone["Australia/Sydney"].parse("2022-07-01 09:01")
expected_next_datetime = ActiveSupport::TimeZone["Australia/Sydney"].parse("2022-07-29 09:01")
post =
PostCreator.create!(
user,
title: "Friday beach party",
raw:
"[event start='2022-07-01 09:01' end='2022-07-01 10:01' timezone='Australia/Sydney' recurrence='every_week']\n[/event]",
).reload
expect(post.event.timezone).to eq("Australia/Sydney")
expect(post.event.original_starts_at).to eq_time(expected_original_datetime)
expect(post.event.starts_at).to eq_time(expected_next_datetime)
end
it "handles recurrence across daylight saving" do
# DST starts on 27th March. Original datetime is before that. Expecting
# local time to be correct after the DST change
expected_original_datetime = ActiveSupport::TimeZone["Europe/Paris"].parse("2022-03-20 09:01")
expected_next_datetime = ActiveSupport::TimeZone["Europe/Paris"].parse("2022-07-25 09:01")
post =
PostCreator.create!(
user,
title: "Friday beach party",
raw:
"[event start='2022-03-20 09:01' end='2022-03-20 10:01' timezone='Europe/Paris' recurrence='every_day']\n[/event]",
).reload
expect(post.event.timezone).to eq("Europe/Paris")
expect(post.event.original_starts_at).to eq_time(expected_original_datetime)
expect(post.event.starts_at).to eq_time(expected_next_datetime)
end
end
end