mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 10:47:18 +08:00
Move the `invite`, `destroy`, `bulk_invite` and `csv_bulk_invite` actions of `DiscoursePostEvent::EventsController` into one service per endpoint: - `DiscoursePostEvent::Invite` - `DiscoursePostEvent::DestroyEvent` - `DiscoursePostEvent::BulkInvite` - `DiscoursePostEvent::CsvBulkInvite` CSV row parsing lives in `DiscoursePostEvent::Action::ParseInviteesCsv`. Behaviour is preserved exactly. Notably: - Input presence (invitees/file) is enforced via policies after the authorization policies, so unauthorized requests still return 403 rather than 400/422. - The CSV endpoint renders every outcome inside `hijack` instead of raising, since exceptions raised there would surface as a 500. - `destroy` builds the webhook payload from live state before deleting the event, then enqueues the webhook after the deletion commits.
63 lines
1.8 KiB
Ruby
Vendored
63 lines
1.8 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe(DiscoursePostEvent::Invite) do
|
|
describe described_class::Contract, type: :model do
|
|
it { is_expected.to validate_presence_of(:event_id) }
|
|
end
|
|
|
|
describe ".call" do
|
|
subject(:result) { described_class.call(params:, **dependencies) }
|
|
|
|
fab!(:admin, :admin)
|
|
fab!(:topic) { Fabricate(:topic, user: admin) }
|
|
fab!(:post) { Fabricate(:post, user: admin, topic: topic) }
|
|
fab!(:event) { Fabricate(:event, post: post) }
|
|
fab!(:invited_user, :user)
|
|
|
|
let(:params) { { event_id: event.id, invites: [invited_user.username] } }
|
|
let(:dependencies) { { guardian: admin.guardian } }
|
|
|
|
before do
|
|
Jobs.run_immediately!
|
|
SiteSetting.calendar_enabled = true
|
|
SiteSetting.discourse_post_event_enabled = true
|
|
end
|
|
|
|
context "when contract is invalid" do
|
|
let(:params) { { event_id: nil, invites: [invited_user.username] } }
|
|
|
|
it { is_expected.to fail_a_contract }
|
|
end
|
|
|
|
context "when event does not exist" do
|
|
let(:params) { { event_id: -1, invites: [invited_user.username] } }
|
|
|
|
it { is_expected.to fail_to_find_a_model(:event) }
|
|
end
|
|
|
|
context "when user cannot act on the event" do
|
|
fab!(:other_user, :user)
|
|
let(:dependencies) { { guardian: other_user.guardian } }
|
|
|
|
it { is_expected.to fail_a_policy(:can_act_on_event) }
|
|
end
|
|
|
|
context "when everything is valid" do
|
|
it { is_expected.to run_successfully }
|
|
|
|
it "notifies the invited users" do
|
|
expect { result }.to change { invited_user.notifications.count }.by(1)
|
|
end
|
|
end
|
|
|
|
context "when invites is empty" do
|
|
let(:params) { { event_id: event.id, invites: [] } }
|
|
|
|
it { is_expected.to run_successfully }
|
|
|
|
it "notifies no one" do
|
|
expect { result }.not_to change { Notification.count }
|
|
end
|
|
end
|
|
end
|
|
end
|