discourse/plugins/discourse-calendar/spec/requests/events_controller_spec.rb
Gabriel Grubba 9dc7064af1
FIX: Events should not lose their multiline formatting (#40277)
## Summary

This patch fixes a regression where event descriptions lost their
multiline formatting by ensuring newline characters are converted to
<br> tags in the server-generated description_html. It updates the
linkify_description utility to handle both URL linkification and line
break preservation, ensuring the UI correctly renders multiline text.

## Source

- Patch Triage: https://patch.discourse.org/patch-triage/886
- Original commit: 

---

🤖 Auto-generated from the patch diff via Patch Triage. Review carefully
before merging.

Co-authored-by: discourse-patch-triage
<272280883+discourse-patch-triage[bot]@users.noreply.github.com>
2026-05-25 18:08:18 -03:00

855 lines
31 KiB
Ruby
Vendored
Raw Permalink 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
module DiscoursePostEvent
describe EventsController do
before do
Jobs.run_immediately!
SiteSetting.calendar_enabled = true
SiteSetting.discourse_post_event_enabled = true
SiteSetting.displayed_invitees_limit = 3
end
describe "#index" do
it "should not result in N+1 queries problem when multiple events are returned" do
# Warmup
get "/discourse-post-event/events.json"
# Test with 1 event
Fabricate(:event, original_starts_at: 1.day.from_now)
queries_with_1_event = track_sql_queries { get "/discourse-post-event/events.json" }
expect(response.status).to eq(200)
expect(response.parsed_body["events"].length).to eq(1)
# Test with 3 events
Fabricate(:event, original_starts_at: 2.days.from_now)
Fabricate(:event, original_starts_at: 3.days.from_now)
queries_with_3_events = track_sql_queries { get "/discourse-post-event/events.json" }
expect(response.status).to eq(200)
expect(response.parsed_body["events"].length).to eq(3)
expect(queries_with_3_events.count).to eq(queries_with_1_event.count)
end
it "should not show deleted events" do
active_event1 = Fabricate(:event, original_starts_at: 1.day.from_now)
active_event2 = Fabricate(:event, original_starts_at: 2.days.from_now)
deleted_event =
Fabricate(:event, original_starts_at: 3.days.from_now, deleted_at: 1.hour.ago)
get "/discourse-post-event/events.json"
expect(response.status).to eq(200)
events = response.parsed_body["events"]
event_ids = events.map { |e| e["id"] }
expect(event_ids).to match_array([active_event1.id, active_event2.id])
end
it "should not show closed events" do
active_event1 = Fabricate(:event, original_starts_at: 1.day.from_now)
active_event2 = Fabricate(:event, original_starts_at: 2.days.from_now)
closed_event = Fabricate(:event, original_starts_at: 3.days.from_now, closed: true)
get "/discourse-post-event/events.json"
expect(response.status).to eq(200)
events = response.parsed_body["events"]
event_ids = events.map { |e| e["id"] }
expect(event_ids).to match_array([active_event1.id, active_event2.id])
end
it "includes linkified multiline description HTML in detailed JSON" do
event =
Fabricate(
:event,
original_starts_at: 1.day.from_now,
description: "Visit https://example.com\n\nBring snacks",
)
get "/discourse-post-event/events.json", params: { include_details: "true" }
expect(response.status).to eq(200)
description_html =
response.parsed_body["events"].find { |event_json| event_json["id"] == event.id }[
"description_html"
]
expect(description_html).to include('<a href="https://example.com"')
expect(description_html).to include("<br>")
end
it "should return events in ics format" do
event1 = Fabricate(:event, original_starts_at: 1.day.from_now, name: "Test Event 1")
event2 = Fabricate(:event, original_starts_at: 2.days.from_now, name: "Test Event 2")
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
expect(response.content_type).to include("text/calendar")
event_ids_sorted = [event1.id, event2.id].sort.join("-")
expected_filename = "events-#{Digest::SHA1.hexdigest(event_ids_sorted)}.ics"
expect(response.headers["Content-Disposition"]).to eq(
"attachment; filename=\"#{expected_filename}\"",
)
body = response.body
calendar_name =
I18n.t(
"discourse_calendar.calendar_subscriptions.all_events_feed_name",
site_title: SiteSetting.title,
)
expect(body).to include("BEGIN:VCALENDAR")
expect(body).to include("END:VCALENDAR")
expect(body).to include("X-WR-CALNAME:#{IcalEncoder.encode(calendar_name)}")
expect(body).to include("BEGIN:VEVENT")
expect(body).to include("END:VEVENT")
expect(body).to include("SUMMARY:Test Event 1")
expect(body).to include("SUMMARY:Test Event 2")
end
it "should include location and description in ics format" do
event =
Fabricate(
:event,
original_starts_at: 1.day.from_now,
name: "Tech Conference",
location: "https://meet.google.com/abc-defg-hij",
description: "Bring your laptop and questions!",
url: "https://example.com/event-info",
)
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
expect(response.content_type).to include("text/calendar")
body = response.body
expect(body).to include("SUMMARY:Tech Conference")
expect(body).to include("LOCATION:https://meet.google.com/abc-defg-hij")
expect(body).to include("DESCRIPTION:Bring your laptop and questions!")
expect(body).to include("URL:https://example.com/event-info")
end
it "should not HTML-encode ampersands in ics format" do
Fabricate(
:event,
original_starts_at: 1.day.from_now,
name: "Tom & Jerry",
location: "Room A & B",
description: "Q & A session",
url: "https://example.com/event?a=1&b=2",
)
get "/discourse-post-event/events.ics"
expect(response.body).to include("SUMMARY:Tom & Jerry")
expect(response.body).not_to include("&amp;")
end
it "should not HTML-encode topic title used as ics summary" do
event = Fabricate(:event, original_starts_at: 1.day.from_now)
event.post.topic.update!(title: "Rock & Roll Music Festival 2026")
get "/discourse-post-event/events.ics"
expect(response.body).to include("SUMMARY:Rock & Roll Music Festival 2026")
end
it "should handle events without location and description in ics format" do
event = Fabricate(:event, original_starts_at: 1.day.from_now, name: "Simple Event")
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
body = response.body
expect(body).to include("SUMMARY:Simple Event")
# Should still generate valid ICS even without LOCATION/DESCRIPTION
expect(body).to include("BEGIN:VEVENT")
expect(body).to include("END:VEVENT")
end
it "should include post url in description when no custom description is set" do
event =
Fabricate(:event, original_starts_at: 1.day.from_now, name: "Event Without Description")
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
body = response.body
description_line = body.lines.find { |l| l.start_with?("DESCRIPTION:") }
post_url = "#{Discourse.base_url}#{event.post.url}"
expect(description_line).to include(post_url)
end
it "excludes events older than 3 months from ics feed by default" do
recent_event = Fabricate(:event, original_starts_at: 1.day.from_now, name: "Future Event")
old_event = Fabricate(:event, original_starts_at: 4.months.ago, name: "Old Event")
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
body = response.body
expect(body).to include("SUMMARY:Future Event")
expect(body).not_to include("SUMMARY:Old Event")
end
it "expands recurring events into multiple occurrences" do
Fabricate(
:event,
original_starts_at: 1.day.from_now,
original_ends_at: 1.day.from_now + 1.hour,
recurrence: "every_week",
name: "Weekly Standup",
)
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
body = response.body
occurrences = body.scan("SUMMARY:Weekly Standup").size
expect(occurrences).to be > 1
expect(occurrences).to be <= 52
end
it "gives recurring and non-recurring events unique UIDs" do
Fabricate(
:event,
original_starts_at: 1.day.from_now,
recurrence: "every_week",
name: "Recurring",
)
Fabricate(:event, original_starts_at: 2.days.from_now, name: "One-off")
get "/discourse-post-event/events.ics"
body = response.body
uids = body.scan(/^UID:(.+)$/).flatten
expect(uids.size).to eq(uids.uniq.size)
end
it "skips events with nil starts_at in ics feed" do
event = Fabricate(:event, original_starts_at: 1.day.from_now, name: "Valid Event")
get "/discourse-post-event/events.ics"
expect(response.status).to eq(200)
expect(response.body).to include("SUMMARY:Valid Event")
end
context "when include_interested is requested for an attending user" do
fab!(:target_user, :user)
fab!(:going_event) do
Fabricate(:event, original_starts_at: 1.day.from_now, name: "Going Event")
end
fab!(:interested_event) do
Fabricate(:event, original_starts_at: 2.days.from_now, name: "Interested Event")
end
let(:events_params) { { attending_user: target_user.username, include_interested: true } }
before do
going_event.create_invitees(
[{ user_id: target_user.id, status: Invitee.statuses[:going] }],
)
interested_event.create_invitees(
[{ user_id: target_user.id, status: Invitee.statuses[:interested] }],
)
end
it "does not expose interested events to anonymous requests" do
get "/discourse-post-event/events.json", params: events_params
expect(response.status).to eq(200)
expect(response.parsed_body["events"].pluck("id")).to contain_exactly(going_event.id)
end
it "includes interested events for the same authenticated user" do
sign_in(target_user)
get "/discourse-post-event/events.json", params: events_params
expect(response.status).to eq(200)
expect(response.parsed_body["events"].pluck("id")).to contain_exactly(
going_event.id,
interested_event.id,
)
end
it "includes interested events for the owner's user api key feed" do
user_api_key =
Fabricate(
:user_api_key,
user: target_user,
scopes: [
Fabricate.build(:user_api_key_scope, name: "discourse-calendar:events_calendar"),
],
)
get "/discourse-post-event/events.ics",
params: events_params.merge(user_api_key: user_api_key.key)
expect(response.status).to eq(200)
calendar_name =
I18n.t(
"discourse_calendar.calendar_subscriptions.my_events_feed_name",
site_title: SiteSetting.title,
)
expect(response.body).to include("X-WR-CALNAME:#{IcalEncoder.encode(calendar_name)}")
expect(response.body).to include("SUMMARY:Going Event")
expect(response.body).to include("SUMMARY:Interested Event")
end
end
end
context "with an all-day event" do
it "returns date-only strings for starts_at and ends_at" do
Fabricate(
:event,
original_starts_at: Time.utc(2026, 3, 12),
original_ends_at: Time.utc(2026, 3, 14),
all_day: true,
)
get "/discourse-post-event/events.json"
expect(response.status).to eq(200)
event = response.parsed_body["events"].first
expect(event["starts_at"]).to eq("2026-03-12")
expect(event["ends_at"]).to eq("2026-03-14")
expect(event["all_day"]).to eq(true)
end
end
context "with an existing post" do
let(:user) { Fabricate(:user, admin: true) }
let(:topic) { Fabricate(:topic, user: user, category: Fabricate(:category)) }
let(:post1) { Fabricate(:post, user: user, topic: topic) }
let(:invitee1) { Fabricate(:user) }
let(:invitee2) { Fabricate(:user) }
context "with an existing event" do
let(:event_1) { Fabricate(:event, post: post1) }
before { sign_in(user) }
context "when updating" do
context "when doing csv bulk invite" do
let(:valid_file) do
file = Tempfile.new("valid.csv")
file.write("bob,going\n")
file.write("sam,interested\n")
file.write("the_foo_bar_group,not_going\n")
file.rewind
file
end
let(:empty_file) do
file = Tempfile.new("invalid.pdf")
file.rewind
file
end
context "when current user can manage the event" do
context "when no file is given" do
it "returns an error" do
post "/discourse-post-event/events/#{event_1.id}/csv-bulk-invite.json"
expect(response.parsed_body["error_type"]).to eq("invalid_parameters")
end
end
context "when an empty file is given" do
it "returns an error" do
post "/discourse-post-event/events/#{event_1.id}/csv-bulk-invite.json",
params: {
file: fixture_file_upload(empty_file),
}
expect(response.status).to eq(422)
end
end
context "when a valid file is given" do
before { Jobs.run_later! }
it "enqueues the job and returns 200" do
expect_enqueued_with(
job: :discourse_post_event_bulk_invite,
args: {
"event_id" => event_1.id,
"invitees" => [
{ "identifier" => "bob", "attendance" => "going" },
{ "identifier" => "sam", "attendance" => "interested" },
{ "identifier" => "the_foo_bar_group", "attendance" => "not_going" },
],
"current_user_id" => user.id,
},
) do
post "/discourse-post-event/events/#{event_1.id}/csv-bulk-invite.json",
params: {
file: fixture_file_upload(valid_file),
}
end
expect(response.status).to eq(200)
end
end
end
context "when current user cant manage the event" do
let(:lurker) { Fabricate(:user) }
before { sign_in(lurker) }
it "returns an error" do
post "/discourse-post-event/events/#{event_1.id}/csv-bulk-invite.json"
expect(response.status).to eq(403)
end
end
end
context "when doing bulk invite" do
context "when current user can manage the event" do
context "when no invitees are given" do
it "returns an error" do
post "/discourse-post-event/events/#{event_1.id}/bulk-invite.json"
expect(response.parsed_body["error_type"]).to eq("invalid_parameters")
end
end
context "when empty invitees are given" do
it "returns an error" do
post "/discourse-post-event/events/#{event_1.id}/bulk-invite.json",
params: {
invitees: [],
}
expect(response.status).to eq(400)
end
end
context "when valid invitees are given" do
before { Jobs.run_later! }
it "enqueues the job and returns 200" do
expect_enqueued_with(
job: :discourse_post_event_bulk_invite,
args: {
"event_id" => event_1.id,
"invitees" => [
{ "identifier" => "bob", "attendance" => "going" },
{ "identifier" => "sam", "attendance" => "interested" },
{ "identifier" => "the_foo_bar_group", "attendance" => "not_going" },
],
"current_user_id" => user.id,
},
) do
post "/discourse-post-event/events/#{event_1.id}/bulk-invite.json",
params: {
invitees: [
{ "identifier" => "bob", "attendance" => "going" },
{ "identifier" => "sam", "attendance" => "interested" },
{ "identifier" => "the_foo_bar_group", "attendance" => "not_going" },
],
}
end
expect(response.status).to eq(200)
end
end
end
context "when current user cant manage the event" do
let(:lurker) { Fabricate(:user) }
before { sign_in(lurker) }
it "returns an error" do
post "/discourse-post-event/events/#{event_1.id}/bulk-invite.json"
expect(response.status).to eq(403)
end
end
end
end
context "when acting user has created the event" do
it "destroys a event" do
expect(event_1.persisted?).to be(true)
messages =
MessageBus.track_publish { delete "/discourse-post-event/events/#{event_1.id}.json" }
expect(messages.count).to eq(1)
message = messages.first
expect(message.channel).to eq("/discourse-post-event/#{event_1.post.topic_id}")
expect(message.data[:id]).to eq(event_1.id)
expect(response.status).to eq(200)
expect(Event).to_not exist(id: event_1.id)
end
end
context "when acting user has not created the event" do
let(:lurker) { Fabricate(:user) }
before { sign_in(lurker) }
it "doesnt destroy the event" do
expect(event_1.persisted?).to be(true)
delete "/discourse-post-event/events/#{event_1.id}.json"
expect(response.status).to eq(403)
expect(Event).to exist(id: event_1.id)
end
end
context "when watching user is not logged" do
before { sign_out }
context "when topic is public" do
it "can see the event" do
get "/discourse-post-event/events/#{event_1.id}.json"
expect(response.status).to eq(200)
end
end
context "when topic is not public" do
before { event_1.post.topic.convert_to_private_message(Discourse.system_user) }
it "cant see the event" do
get "/discourse-post-event/events/#{event_1.id}.json"
expect(response.status).to eq(404)
end
end
end
context "when filtering by category" do
fab!(:category)
fab!(:subcategory) do
Fabricate(:category, parent_category: category, name: "category subcategory")
end
fab!(:event_1) do
Fabricate(
:event,
original_starts_at: 2.days.from_now,
post: Fabricate(:post, post_number: 1, topic: Fabricate(:topic, category: category)),
)
end
fab!(:event_2) do
Fabricate(
:event,
original_starts_at: 1.day.from_now,
post:
Fabricate(:post, post_number: 1, topic: Fabricate(:topic, category: subcategory)),
)
end
fab!(:event_3) do
Fabricate(
:event,
post: Fabricate(:post, post_number: 1, topic: Fabricate(:topic, category: category)),
original_starts_at: 10.days.ago,
original_ends_at: 9.days.ago,
)
end
it "can filter the event by category" do
get "/discourse-post-event/events.json?category_id=#{category.id}"
expect(response.status).to eq(200)
events = response.parsed_body["events"]
expect(events.length).to eq(2) # Now includes expired event_3
event_ids = events.map { |e| e["id"] }
expect(event_ids).to include(event_1.id)
expect(event_ids).to include(event_3.id)
end
it "includes subcategory events when param provided" do
get "/discourse-post-event/events.json?category_id=#{category.id}&include_subcategories=true"
expect(response.status).to eq(200)
events = response.parsed_body["events"]
expect(events.length).to eq(3) # Now includes expired event_3
expect(events).to match_array(
[
hash_including("id" => event_1.id),
hash_including("id" => event_2.id),
hash_including("id" => event_3.id),
],
)
end
it "limits the number of events returned when limit param provided" do
get "/discourse-post-event/events.json?category_id=#{category.id}&include_subcategories=true&limit=1"
expect(response.status).to eq(200)
events = response.parsed_body["events"]
expect(events.length).to eq(1)
expect(events[0]["id"]).to eq(event_3.id) # Expired event sorts first (NULL starts_at)
end
it "filters events before the provided datetime if before param provided" do
get "/discourse-post-event/events.json?category_id=#{category.id}&include_subcategories=true&before=#{event_2.starts_at}"
expect(response.status).to eq(200)
events = response.parsed_body["events"]
expect(events.length).to eq(1)
expect(events[0]["id"]).to eq(event_3.id)
end
end
end
end
context "with a private event" do
let(:moderator) { Fabricate(:moderator) }
let(:topic) { Fabricate(:topic, user: moderator) }
let(:first_post) { Fabricate(:post, user: moderator, topic: topic) }
let(:private_event) { Fabricate(:event, post: first_post, status: Event.statuses[:private]) }
before { sign_in(moderator) }
context "when bulk inviting via CSV file" do
def csv_file(content)
file = Tempfile.new("invites.csv")
file.write(content)
file.rewind
file
end
it "doesn't invite a private group" do
private_group = Fabricate(:group, visibility_level: Group.visibility_levels[:owners])
file = csv_file("#{private_group.name},going\n")
params = { file: fixture_file_upload(file) }
post "/discourse-post-event/events/#{private_event.id}/csv-bulk-invite.json",
params: params
expect(response.status).to eq(200)
private_event.reload
expect(private_event.raw_invitees).to be_nil
end
it "returns 200 when inviting a non-existent group" do
file = csv_file("non-existent group name,going\n")
params = { file: fixture_file_upload(file) }
post "/discourse-post-event/events/#{private_event.id}/csv-bulk-invite.json",
params: params
expect(response.status).to eq(200)
end
it "doesn't invite a public group with private members" do
public_group_with_private_members =
Fabricate(
:group,
visibility_level: Group.visibility_levels[:public],
members_visibility_level: Group.visibility_levels[:owners],
)
file = csv_file("#{public_group_with_private_members.name},going\n")
params = { file: fixture_file_upload(file) }
post "/discourse-post-event/events/#{private_event.id}/csv-bulk-invite.json",
params: params
expect(response.status).to eq(200)
private_event.reload
expect(private_event.raw_invitees).to be_nil
end
end
context "when doing bulk inviting via UI" do
it "doesn't invite a private group" do
private_group = Fabricate(:group, visibility_level: Group.visibility_levels[:owners])
params = { invitees: [{ "identifier" => private_group.name, "attendance" => "going" }] }
post "/discourse-post-event/events/#{private_event.id}/bulk-invite.json", params: params
expect(response.status).to eq(200)
private_event.reload
expect(private_event.raw_invitees).to be_nil
end
it "returns 200 when inviting a non-existent group" do
params = {
invitees: [{ "identifier" => "non-existent group name", "attendance" => "going" }],
}
post "/discourse-post-event/events/#{private_event.id}/bulk-invite.json", params: params
expect(response.status).to eq(200)
end
it "doesn't invite a public group with private members" do
public_group_with_private_members =
Fabricate(
:group,
visibility_level: Group.visibility_levels[:public],
members_visibility_level: Group.visibility_levels[:owners],
)
params = {
invitees: [
{ "identifier" => public_group_with_private_members.name, "attendance" => "going" },
],
}
post "/discourse-post-event/events/#{private_event.id}/bulk-invite.json", params: params
expect(response.status).to eq(200)
private_event.reload
expect(private_event.raw_invitees).to be_nil
end
end
end
end
describe "bulk invite respects capacity" do
before do
SiteSetting.calendar_enabled = true
SiteSetting.discourse_post_event_enabled = true
end
let(:user) { Fabricate(:user, admin: true) }
let(:topic) { Fabricate(:topic, user: user) }
let(:post1) { Fabricate(:post, user: user, topic: topic) }
let!(:event) { Fabricate(:event, post: post1, max_attendees: 1) }
it "skips creating going when full" do
sign_in(user)
user1 = Fabricate(:user)
user2 = Fabricate(:user)
expect_enqueued_with(
job: :discourse_post_event_bulk_invite,
args: {
"event_id" => event.id,
"invitees" => [
{ "identifier" => user1.username, "attendance" => "going" },
{ "identifier" => user2.username, "attendance" => "going" },
],
"current_user_id" => user.id,
},
) do
post "/discourse-post-event/events/#{event.id}/bulk-invite.json",
params: {
invitees: [
{ "identifier" => user1.username, "attendance" => "going" },
{ "identifier" => user2.username, "attendance" => "going" },
],
}
end
Jobs.run_immediately!
event.reload
expect(event.invitees.with_status(:going).count).to be <= 1
end
end
describe "#show" do
before do
SiteSetting.calendar_enabled = true
SiteSetting.discourse_post_event_enabled = true
end
fab!(:admin_user) { Fabricate(:user, admin: true) }
fab!(:category)
fab!(:topic) { Fabricate(:topic, user: admin_user, category: category) }
fab!(:post_1) { Fabricate(:post, user: admin_user, topic: topic) }
fab!(:chat_channel) { Fabricate(:chat_channel, chatable: category) }
fab!(:event) { Fabricate(:event, post: post_1, chat_enabled: true, chat_channel: chat_channel) }
fab!(:chat_message) do
Fabricate(
:chat_message,
chat_channel: chat_channel,
user: admin_user,
message: "private chat message body",
)
end
before { chat_channel.update!(last_message: chat_message) }
context "when the viewer is anonymous" do
before do
SiteSetting.chat_enabled = true
SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:everyone]
end
it "does not include the chat channel block or last message body" do
get "/discourse-post-event/events/#{event.id}.json"
expect(response.status).to eq(200)
expect(response.parsed_body["event"]).not_to have_key("channel")
expect(response.body).not_to include("private chat message body")
end
end
context "when the viewer cannot join the chat channel" do
fab!(:viewer, :user)
before do
SiteSetting.chat_enabled = true
SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:staff]
sign_in(viewer)
end
it "does not include the chat channel block or last message body" do
get "/discourse-post-event/events/#{event.id}.json"
expect(response.status).to eq(200)
expect(response.parsed_body["event"]).not_to have_key("channel")
expect(response.body).not_to include("private chat message body")
end
end
context "when the viewer can join the chat channel" do
before do
SiteSetting.chat_enabled = true
SiteSetting.chat_allowed_groups = Group::AUTO_GROUPS[:everyone]
sign_in(admin_user)
end
it "includes the chat channel block with the last message body" do
get "/discourse-post-event/events/#{event.id}.json"
expect(response.status).to eq(200)
expect(response.parsed_body["event"]["channel"]).to be_present
expect(response.body).to include("private chat message body")
end
end
end
describe "anonymous access to EventsController" do
before do
SiteSetting.calendar_enabled = true
SiteSetting.discourse_post_event_enabled = true
end
fab!(:admin_user) { Fabricate(:user, admin: true) }
fab!(:topic) { Fabricate(:topic, user: admin_user) }
fab!(:post_1) { Fabricate(:post, user: admin_user, topic: topic) }
fab!(:event) { Fabricate(:event, post: post_1) }
it "requires login for invite" do
post "/discourse-post-event/events/#{event.id}/invite.json"
expect(response.status).to eq(403)
end
it "requires login for destroy" do
delete "/discourse-post-event/events/#{event.id}.json"
expect(response.status).to eq(403)
end
it "requires login for bulk_invite" do
post "/discourse-post-event/events/#{event.id}/bulk-invite.json",
params: {
invitees: [{ "identifier" => "bob", "attendance" => "going" }],
}
expect(response.status).to eq(403)
end
it "requires login for csv_bulk_invite" do
post "/discourse-post-event/events/#{event.id}/csv-bulk-invite.json"
expect(response.status).to eq(403)
end
end
end