mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Enable RSpec/InstanceVariable rule globally
This commit is contained in:
@@ -35,3 +35,6 @@ Discourse/Plugins/NoMonkeyPatching:
|
||||
Lint/Debugger:
|
||||
Exclude:
|
||||
- script/**/*
|
||||
|
||||
RSpec/InstanceVariable:
|
||||
Enabled: true
|
||||
|
@@ -30,7 +30,7 @@ describe "ZapierWebhook" do
|
||||
|
||||
it "logs an error and do nothing" do
|
||||
expect { automation.trigger! }.not_to change {
|
||||
Jobs::DiscourseAutomation::CallZapierWebhook.jobs.length
|
||||
Jobs::DiscourseAutomation::CallZapierWebhook.jobs.size
|
||||
}
|
||||
|
||||
expect(Rails.logger.warnings.first).to match(/is not a valid Zapier/)
|
||||
|
@@ -1,26 +1,24 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
describe Jobs::Chat::ChannelDelete do
|
||||
RSpec.describe Jobs::Chat::ChannelDelete do
|
||||
fab!(:chat_channel)
|
||||
fab!(:user1) { Fabricate(:user) }
|
||||
fab!(:user2) { Fabricate(:user) }
|
||||
fab!(:user3) { Fabricate(:user) }
|
||||
let(:users) { [user1, user2, user3] }
|
||||
fab!(:users) { [user1, user2, user3] }
|
||||
fab!(:messages) { Array.new(20) { Fabricate(:chat_message, chat_channel:, user: users.sample) } }
|
||||
fab!(:incoming_chat_webhook) { Fabricate(:incoming_chat_webhook, chat_channel:) }
|
||||
|
||||
let(:message_ids) { messages.map(&:id) }
|
||||
|
||||
before do
|
||||
messages = []
|
||||
20.times do
|
||||
messages << Fabricate(:chat_message, chat_channel: chat_channel, user: users.sample)
|
||||
end
|
||||
@message_ids = messages.map(&:id)
|
||||
|
||||
10.times { Chat::MessageReaction.create(chat_message: messages.sample, user: users.sample) }
|
||||
|
||||
10.times do
|
||||
upload = Fabricate(:upload, user: users.sample)
|
||||
message = messages.sample
|
||||
|
||||
UploadReference.create(target: message, upload: upload)
|
||||
UploadReference.create(target: message, upload:)
|
||||
end
|
||||
|
||||
Chat::UserMention.create(
|
||||
@@ -29,11 +27,7 @@ describe Jobs::Chat::ChannelDelete do
|
||||
notifications: [Fabricate(:notification)],
|
||||
)
|
||||
|
||||
@incoming_chat_webhook_id = Fabricate(:incoming_chat_webhook, chat_channel: chat_channel)
|
||||
Chat::WebhookEvent.create(
|
||||
incoming_chat_webhook: @incoming_chat_webhook_id,
|
||||
chat_message: messages.sample,
|
||||
)
|
||||
Chat::WebhookEvent.create(incoming_chat_webhook:, chat_message: messages.sample)
|
||||
|
||||
revision_message = messages.sample
|
||||
Fabricate(
|
||||
@@ -43,31 +37,30 @@ describe Jobs::Chat::ChannelDelete do
|
||||
new_message: revision_message.message,
|
||||
)
|
||||
|
||||
Chat::Draft.create(chat_channel: chat_channel, user: users.sample, data: "wow some draft")
|
||||
Chat::Draft.create(chat_channel:, user: users.sample, data: "wow some draft")
|
||||
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: chat_channel, user: user1)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: chat_channel, user: user2)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: chat_channel, user: user3)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel:, user: user1)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel:, user: user2)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel:, user: user3)
|
||||
|
||||
chat_channel.trash!
|
||||
end
|
||||
|
||||
def counts
|
||||
{
|
||||
incoming_webhooks: Chat::IncomingWebhook.where(chat_channel_id: chat_channel.id).count,
|
||||
webhook_events:
|
||||
Chat::WebhookEvent.where(incoming_chat_webhook_id: @incoming_chat_webhook_id).count,
|
||||
drafts: Chat::Draft.where(chat_channel: chat_channel).count,
|
||||
incoming_webhooks: Chat::IncomingWebhook.where(chat_channel:).count,
|
||||
webhook_events: Chat::WebhookEvent.where(incoming_chat_webhook:).count,
|
||||
drafts: Chat::Draft.where(chat_channel:).count,
|
||||
channel_memberships: Chat::UserChatChannelMembership.where(chat_channel: chat_channel).count,
|
||||
revisions: Chat::MessageRevision.where(chat_message_id: @message_ids).count,
|
||||
mentions: Chat::Mention.where(chat_message_id: @message_ids).count,
|
||||
revisions: Chat::MessageRevision.where(chat_message_id: message_ids).count,
|
||||
mentions: Chat::Mention.where(chat_message_id: message_ids).count,
|
||||
upload_references:
|
||||
UploadReference.where(
|
||||
target_id: @message_ids,
|
||||
target_id: message_ids,
|
||||
target_type: Chat::Message.polymorphic_name,
|
||||
).count,
|
||||
messages: Chat::Message.where(id: @message_ids).count,
|
||||
reactions: Chat::MessageReaction.where(chat_message_id: @message_ids).count,
|
||||
messages: Chat::Message.where(id: message_ids).count,
|
||||
reactions: Chat::MessageReaction.where(chat_message_id: message_ids).count,
|
||||
}
|
||||
end
|
||||
|
||||
|
@@ -6,24 +6,22 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
fab!(:user_1) { Fabricate(:user, refresh_auto_groups: true) }
|
||||
fab!(:user_2) { Fabricate(:user, refresh_auto_groups: true) }
|
||||
fab!(:public_channel) { Fabricate(:category_channel) }
|
||||
fab!(:chat_group) { Fabricate(:group, users: [user_1, user_2]) }
|
||||
|
||||
let!(:result) do
|
||||
Chat::CreateDirectMessageChannel.call(
|
||||
guardian: user_1.guardian,
|
||||
params: {
|
||||
target_usernames: [user_1.username, user_2.username],
|
||||
},
|
||||
) do |result|
|
||||
on_success { result }
|
||||
on_failure { service_failed!(result) }
|
||||
end
|
||||
end
|
||||
let(:personal_chat_channel) { result.channel }
|
||||
|
||||
before do
|
||||
user_1.reload
|
||||
user_2.reload
|
||||
|
||||
@chat_group = Fabricate(:group, users: [user_1, user_2])
|
||||
result =
|
||||
Chat::CreateDirectMessageChannel.call(
|
||||
guardian: user_1.guardian,
|
||||
params: {
|
||||
target_usernames: [user_1.username, user_2.username],
|
||||
},
|
||||
)
|
||||
|
||||
service_failed!(result) if result.failure?
|
||||
|
||||
@personal_chat_channel = result.channel
|
||||
|
||||
[user_1, user_2].each do |u|
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: public_channel, user: u)
|
||||
end
|
||||
@@ -147,10 +145,10 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
|
||||
it "does nothing if user is not participating in a private channel" do
|
||||
user_3 = Fabricate(:user)
|
||||
@chat_group.add(user_3)
|
||||
chat_group.add(user_3)
|
||||
to_notify_map = { direct_mentions: [user_3.id] }
|
||||
|
||||
message = create_chat_message(channel: @personal_chat_channel)
|
||||
message = create_chat_message(channel: personal_chat_channel)
|
||||
|
||||
PostAlerter.expects(:push_notification).never
|
||||
|
||||
@@ -227,7 +225,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
message = create_chat_message
|
||||
Fabricate(:all_chat_mention, chat_message: message)
|
||||
Fabricate(:here_chat_mention, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: @chat_group, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: chat_group, chat_message: message)
|
||||
|
||||
desktop_notification =
|
||||
track_desktop_notification(message: message, to_notify_ids_map: to_notify_ids_map)
|
||||
@@ -248,7 +246,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
message = create_chat_message
|
||||
Fabricate(:all_chat_mention, chat_message: message)
|
||||
Fabricate(:here_chat_mention, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: @chat_group, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: chat_group, chat_message: message)
|
||||
|
||||
PostAlerter.expects(:push_notification).with(
|
||||
user_2,
|
||||
@@ -275,7 +273,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
message = create_chat_message
|
||||
Fabricate(:all_chat_mention, chat_message: message)
|
||||
Fabricate(:here_chat_mention, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: @chat_group, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: chat_group, chat_message: message)
|
||||
|
||||
created_notification =
|
||||
track_core_notification(message: message, to_notify_ids_map: to_notify_ids_map)
|
||||
@@ -334,7 +332,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
|
||||
context "with private channels" do
|
||||
it "users a different translated title" do
|
||||
message = create_chat_message(channel: @personal_chat_channel)
|
||||
message = create_chat_message(channel: personal_chat_channel)
|
||||
Fabricate(:all_chat_mention, chat_message: message)
|
||||
|
||||
desktop_notification =
|
||||
@@ -389,7 +387,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
|
||||
context "with private channels" do
|
||||
it "uses a different translated title" do
|
||||
message = create_chat_message(channel: @personal_chat_channel)
|
||||
message = create_chat_message(channel: personal_chat_channel)
|
||||
Fabricate(:here_chat_mention, chat_message: message)
|
||||
|
||||
desktop_notification =
|
||||
@@ -462,7 +460,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
|
||||
context "with private channels" do
|
||||
it "users a different translated title" do
|
||||
message = create_chat_message(channel: @personal_chat_channel)
|
||||
message = create_chat_message(channel: personal_chat_channel)
|
||||
|
||||
desktop_notification =
|
||||
track_desktop_notification(message: message, to_notify_ids_map: to_notify_ids_map)
|
||||
@@ -480,13 +478,13 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
end
|
||||
|
||||
describe "group mentions" do
|
||||
let(:to_notify_ids_map) { { @chat_group.name.to_sym => [user_2.id] } }
|
||||
let(:to_notify_ids_map) { { chat_group.name.to_sym => [user_2.id] } }
|
||||
|
||||
let(:payload_translated_title) do
|
||||
I18n.t(
|
||||
"discourse_push_notifications.popup.chat_mention.other_type",
|
||||
username: user_1.username,
|
||||
identifier: "@#{@chat_group.name}",
|
||||
identifier: "@#{chat_group.name}",
|
||||
channel: public_channel.title(user_2),
|
||||
)
|
||||
end
|
||||
@@ -495,19 +493,19 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
|
||||
it "includes here mention specific data to core notifications" do
|
||||
message = create_chat_message
|
||||
Fabricate(:group_chat_mention, group: @chat_group, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: chat_group, chat_message: message)
|
||||
|
||||
created_notification =
|
||||
track_core_notification(message: message, to_notify_ids_map: to_notify_ids_map)
|
||||
data_hash = created_notification.data_hash
|
||||
|
||||
expect(data_hash[:identifier]).to eq(@chat_group.name)
|
||||
expect(data_hash[:identifier]).to eq(chat_group.name)
|
||||
expect(data_hash[:is_group_mention]).to eq(true)
|
||||
end
|
||||
|
||||
it "includes here mention specific data to desktop notifications" do
|
||||
message = create_chat_message
|
||||
Fabricate(:group_chat_mention, group: @chat_group, chat_message: message)
|
||||
Fabricate(:group_chat_mention, group: chat_group, chat_message: message)
|
||||
|
||||
desktop_notification =
|
||||
track_desktop_notification(message: message, to_notify_ids_map: to_notify_ids_map)
|
||||
@@ -517,8 +515,8 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
|
||||
context "with private channels" do
|
||||
it "uses a different translated title" do
|
||||
message = create_chat_message(channel: @personal_chat_channel)
|
||||
Fabricate(:group_chat_mention, group: @chat_group, chat_message: message)
|
||||
message = create_chat_message(channel: personal_chat_channel)
|
||||
Fabricate(:group_chat_mention, group: chat_group, chat_message: message)
|
||||
|
||||
desktop_notification =
|
||||
track_desktop_notification(message: message, to_notify_ids_map: to_notify_ids_map)
|
||||
@@ -527,7 +525,7 @@ describe Jobs::Chat::NotifyMentioned do
|
||||
I18n.t(
|
||||
"discourse_push_notifications.popup.direct_message_chat_mention.other_type",
|
||||
username: user_1.username,
|
||||
identifier: "@#{@chat_group.name}",
|
||||
identifier: "@#{chat_group.name}",
|
||||
)
|
||||
|
||||
expect(desktop_notification.data[:translated_title]).to eq(expected_title)
|
||||
|
@@ -96,13 +96,12 @@ describe Chat::ChannelArchiveService do
|
||||
thread.update!(replies_count: num - 1)
|
||||
end
|
||||
|
||||
def start_archive
|
||||
@channel_archive =
|
||||
described_class.create_archive_process(
|
||||
chat_channel: channel,
|
||||
acting_user: user,
|
||||
topic_params: topic_params,
|
||||
)
|
||||
let(:channel_archive) do
|
||||
described_class.create_archive_process(
|
||||
chat_channel: channel,
|
||||
acting_user: user,
|
||||
topic_params: topic_params,
|
||||
)
|
||||
end
|
||||
|
||||
context "when archiving to a new topic" do
|
||||
@@ -111,7 +110,7 @@ describe Chat::ChannelArchiveService do
|
||||
end
|
||||
|
||||
it "makes a topic, deletes all the messages, creates posts for batches of messages, and changes the channel to archived" do
|
||||
create_messages(50) && start_archive
|
||||
create_messages(50) && channel_archive
|
||||
reaction_message = Chat::Message.last
|
||||
Chat::MessageReaction.create!(
|
||||
chat_message: reaction_message,
|
||||
@@ -119,16 +118,16 @@ describe Chat::ChannelArchiveService do
|
||||
emoji: "+1",
|
||||
)
|
||||
stub_const(Chat::ChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
||||
described_class.new(@channel_archive).execute
|
||||
described_class.new(channel_archive).execute
|
||||
end
|
||||
|
||||
@channel_archive.reload
|
||||
expect(@channel_archive.destination_topic.title).to eq("This will be a new topic")
|
||||
expect(@channel_archive.destination_topic.category).to eq(category)
|
||||
expect(@channel_archive.destination_topic.user).to eq(Discourse.system_user)
|
||||
expect(@channel_archive.destination_topic.tags.map(&:name)).to match_array(%w[news gossip])
|
||||
channel_archive.reload
|
||||
expect(channel_archive.destination_topic.title).to eq("This will be a new topic")
|
||||
expect(channel_archive.destination_topic.category).to eq(category)
|
||||
expect(channel_archive.destination_topic.user).to eq(Discourse.system_user)
|
||||
expect(channel_archive.destination_topic.tags.map(&:name)).to match_array(%w[news gossip])
|
||||
|
||||
topic = @channel_archive.destination_topic
|
||||
topic = channel_archive.destination_topic
|
||||
expect(topic.posts.count).to eq(11)
|
||||
topic
|
||||
.posts
|
||||
@@ -144,9 +143,9 @@ describe Chat::ChannelArchiveService do
|
||||
end
|
||||
expect(topic.archived).to eq(true)
|
||||
|
||||
expect(@channel_archive.archived_messages).to eq(50)
|
||||
expect(@channel_archive.chat_channel.status).to eq("archived")
|
||||
expect(@channel_archive.chat_channel.chat_messages.count).to eq(0)
|
||||
expect(channel_archive.archived_messages).to eq(50)
|
||||
expect(channel_archive.chat_channel.status).to eq("archived")
|
||||
expect(channel_archive.chat_channel.chat_messages.count).to eq(0)
|
||||
end
|
||||
|
||||
xit "creates the correct posts for a channel with messages and threads" do
|
||||
@@ -159,14 +158,14 @@ describe Chat::ChannelArchiveService do
|
||||
create_threaded_messages(27, title: "another long thread")
|
||||
create_messages(10)
|
||||
|
||||
start_archive
|
||||
channel_archive
|
||||
|
||||
stub_const(Chat::ChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
||||
described_class.new(@channel_archive).execute
|
||||
described_class.new(channel_archive).execute
|
||||
end
|
||||
|
||||
@channel_archive.reload
|
||||
topic = @channel_archive.destination_topic
|
||||
channel_archive.reload
|
||||
topic = channel_archive.destination_topic
|
||||
expect(topic.posts.count).to eq(14)
|
||||
|
||||
topic
|
||||
@@ -201,32 +200,32 @@ describe Chat::ChannelArchiveService do
|
||||
end
|
||||
expect(topic.archived).to eq(true)
|
||||
|
||||
expect(@channel_archive.archived_messages).to eq(55)
|
||||
expect(@channel_archive.chat_channel.status).to eq("archived")
|
||||
expect(@channel_archive.chat_channel.chat_messages.count).to eq(0)
|
||||
expect(channel_archive.archived_messages).to eq(55)
|
||||
expect(channel_archive.chat_channel.status).to eq("archived")
|
||||
expect(channel_archive.chat_channel.chat_messages.count).to eq(0)
|
||||
end
|
||||
|
||||
it "does not stop the process if the post length is too high (validations disabled)" do
|
||||
create_messages(50) && start_archive
|
||||
create_messages(50) && channel_archive
|
||||
SiteSetting.max_post_length = 1
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(true)
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(true)
|
||||
end
|
||||
|
||||
it "successfully links uploads from messages to the post" do
|
||||
create_messages(3) && start_archive
|
||||
create_messages(3) && channel_archive
|
||||
UploadReference.create!(target: Chat::Message.last, upload: Fabricate(:upload))
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(true)
|
||||
expect(@channel_archive.destination_topic.posts.last.upload_references.count).to eq(1)
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(true)
|
||||
expect(channel_archive.destination_topic.posts.last.upload_references.count).to eq(1)
|
||||
end
|
||||
|
||||
it "successfully sends a private message to the archiving user" do
|
||||
create_messages(3) && start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(true)
|
||||
create_messages(3) && channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(true)
|
||||
pm_topic = Topic.private_messages.last
|
||||
expect(pm_topic.topic_allowed_users.first.user).to eq(@channel_archive.archived_by)
|
||||
expect(pm_topic.topic_allowed_users.first.user).to eq(channel_archive.archived_by)
|
||||
expect(pm_topic.title).to eq(
|
||||
I18n.t("system_messages.chat_channel_archive_complete.subject_template"),
|
||||
)
|
||||
@@ -235,12 +234,12 @@ describe Chat::ChannelArchiveService do
|
||||
it "does not continue archiving if the destination topic fails to be created" do
|
||||
SiteSetting.max_emojis_in_title = 1
|
||||
|
||||
create_messages(3) && start_archive
|
||||
@channel_archive.update!(destination_topic_title: "Wow this is the new title :tada: :joy:")
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(false)
|
||||
expect(@channel_archive.reload.failed?).to eq(true)
|
||||
expect(@channel_archive.archive_error).to eq("Title can't have more than 1 emoji")
|
||||
create_messages(3) && channel_archive
|
||||
channel_archive.update!(destination_topic_title: "Wow this is the new title :tada: :joy:")
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(false)
|
||||
expect(channel_archive.reload.failed?).to eq(true)
|
||||
expect(channel_archive.archive_error).to eq("Title can't have more than 1 emoji")
|
||||
|
||||
pm_topic = Topic.private_messages.last
|
||||
expect(pm_topic.title).to eq(
|
||||
@@ -250,9 +249,9 @@ describe Chat::ChannelArchiveService do
|
||||
end
|
||||
|
||||
it "uses the channel slug to autolink a hashtag for the channel in the PM" do
|
||||
create_messages(3) && start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(true)
|
||||
create_messages(3) && channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(true)
|
||||
pm_topic = Topic.private_messages.last
|
||||
expect(pm_topic.first_post.cooked).to have_tag(
|
||||
"a",
|
||||
@@ -289,9 +288,9 @@ describe Chat::ChannelArchiveService do
|
||||
expect(
|
||||
Chat::UserChatChannelMembership.where(chat_channel: channel, following: true).count,
|
||||
).to eq(3)
|
||||
start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(true)
|
||||
channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(true)
|
||||
expect(
|
||||
Chat::UserChatChannelMembership.where(chat_channel: channel, following: true).count,
|
||||
).to eq(0)
|
||||
@@ -301,9 +300,9 @@ describe Chat::ChannelArchiveService do
|
||||
Chat::UserChatChannelMembership.last.update!(
|
||||
last_read_message_id: channel.chat_messages.first.id,
|
||||
)
|
||||
start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
expect(@channel_archive.reload.complete?).to eq(true)
|
||||
channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
expect(channel_archive.reload.complete?).to eq(true)
|
||||
expect(Chat::UserChatChannelMembership.last.last_read_message_id).to eq(
|
||||
channel.chat_messages.last.id,
|
||||
)
|
||||
@@ -315,9 +314,9 @@ describe Chat::ChannelArchiveService do
|
||||
before { SiteSetting.chat_archive_destination_topic_status = "archived" }
|
||||
|
||||
it "archives the topic" do
|
||||
create_messages(3) && start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
topic = @channel_archive.destination_topic
|
||||
create_messages(3) && channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
topic = channel_archive.destination_topic
|
||||
topic.reload
|
||||
expect(topic.archived).to eq(true)
|
||||
end
|
||||
@@ -327,9 +326,9 @@ describe Chat::ChannelArchiveService do
|
||||
before { SiteSetting.chat_archive_destination_topic_status = "open" }
|
||||
|
||||
it "leaves the topic open" do
|
||||
create_messages(3) && start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
topic = @channel_archive.destination_topic
|
||||
create_messages(3) && channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
topic = channel_archive.destination_topic
|
||||
topic.reload
|
||||
expect(topic.archived).to eq(false)
|
||||
expect(topic.open?).to eq(true)
|
||||
@@ -340,9 +339,9 @@ describe Chat::ChannelArchiveService do
|
||||
before { SiteSetting.chat_archive_destination_topic_status = "closed" }
|
||||
|
||||
it "closes the topic" do
|
||||
create_messages(3) && start_archive
|
||||
described_class.new(@channel_archive).execute
|
||||
topic = @channel_archive.destination_topic
|
||||
create_messages(3) && channel_archive
|
||||
described_class.new(channel_archive).execute
|
||||
topic = channel_archive.destination_topic
|
||||
topic.reload
|
||||
expect(topic.archived).to eq(false)
|
||||
expect(topic.closed?).to eq(true)
|
||||
@@ -351,13 +350,13 @@ describe Chat::ChannelArchiveService do
|
||||
|
||||
context "when archiving to an existing topic" do
|
||||
it "does not change the status of the topic" do
|
||||
create_messages(3) && start_archive
|
||||
@channel_archive.update(
|
||||
create_messages(3) && channel_archive
|
||||
channel_archive.update(
|
||||
destination_topic_title: nil,
|
||||
destination_topic_id: Fabricate(:topic).id,
|
||||
)
|
||||
described_class.new(@channel_archive).execute
|
||||
topic = @channel_archive.destination_topic
|
||||
described_class.new(channel_archive).execute
|
||||
topic = channel_archive.destination_topic
|
||||
topic.reload
|
||||
expect(topic.archived).to eq(false)
|
||||
expect(topic.closed?).to eq(false)
|
||||
@@ -373,7 +372,7 @@ describe Chat::ChannelArchiveService do
|
||||
before { 3.times { Fabricate(:post, topic: topic) } }
|
||||
|
||||
it "deletes all the messages, creates posts for batches of messages, and changes the channel to archived" do
|
||||
create_messages(50) && start_archive
|
||||
create_messages(50) && channel_archive
|
||||
reaction_message = Chat::Message.last
|
||||
Chat::MessageReaction.create!(
|
||||
chat_message: reaction_message,
|
||||
@@ -381,15 +380,15 @@ describe Chat::ChannelArchiveService do
|
||||
emoji: "+1",
|
||||
)
|
||||
stub_const(Chat::ChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
||||
described_class.new(@channel_archive).execute
|
||||
described_class.new(channel_archive).execute
|
||||
end
|
||||
|
||||
@channel_archive.reload
|
||||
expect(@channel_archive.destination_topic.title).to eq(topic.title)
|
||||
expect(@channel_archive.destination_topic.category).to eq(topic.category)
|
||||
expect(@channel_archive.destination_topic.user).to eq(topic.user)
|
||||
channel_archive.reload
|
||||
expect(channel_archive.destination_topic.title).to eq(topic.title)
|
||||
expect(channel_archive.destination_topic.category).to eq(topic.category)
|
||||
expect(channel_archive.destination_topic.user).to eq(topic.user)
|
||||
|
||||
topic = @channel_archive.destination_topic
|
||||
topic = channel_archive.destination_topic
|
||||
|
||||
# existing posts + 10 archive posts
|
||||
expect(topic.posts.count).to eq(13)
|
||||
@@ -407,13 +406,13 @@ describe Chat::ChannelArchiveService do
|
||||
end
|
||||
expect(topic.archived).to eq(false)
|
||||
|
||||
expect(@channel_archive.archived_messages).to eq(50)
|
||||
expect(@channel_archive.chat_channel.status).to eq("archived")
|
||||
expect(@channel_archive.chat_channel.chat_messages.count).to eq(0)
|
||||
expect(channel_archive.archived_messages).to eq(50)
|
||||
expect(channel_archive.chat_channel.status).to eq("archived")
|
||||
expect(channel_archive.chat_channel.chat_messages.count).to eq(0)
|
||||
end
|
||||
|
||||
it "handles errors gracefully, sends a private message to the archiving user, and is idempotent on retry" do
|
||||
create_messages(35) && start_archive
|
||||
create_messages(35) && channel_archive
|
||||
|
||||
Chat::ChannelArchiveService
|
||||
.any_instance
|
||||
@@ -421,26 +420,26 @@ describe Chat::ChannelArchiveService do
|
||||
.raises(FakeArchiveError.new("this is a test error"))
|
||||
|
||||
stub_const(Chat::ChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
||||
expect { described_class.new(@channel_archive).execute }.to raise_error(FakeArchiveError)
|
||||
expect { described_class.new(channel_archive).execute }.to raise_error(FakeArchiveError)
|
||||
end
|
||||
|
||||
expect(@channel_archive.reload.archive_error).to eq("this is a test error")
|
||||
expect(channel_archive.reload.archive_error).to eq("this is a test error")
|
||||
|
||||
pm_topic = Topic.private_messages.last
|
||||
expect(pm_topic.topic_allowed_users.first.user).to eq(@channel_archive.archived_by)
|
||||
expect(pm_topic.topic_allowed_users.first.user).to eq(channel_archive.archived_by)
|
||||
expect(pm_topic.title).to eq(
|
||||
I18n.t("system_messages.chat_channel_archive_failed.subject_template"),
|
||||
)
|
||||
|
||||
Chat::ChannelArchiveService.any_instance.unstub(:create_post)
|
||||
stub_const(Chat::ChannelArchiveService, "ARCHIVED_MESSAGES_PER_POST", 5) do
|
||||
described_class.new(@channel_archive).execute
|
||||
described_class.new(channel_archive).execute
|
||||
end
|
||||
|
||||
@channel_archive.reload
|
||||
expect(@channel_archive.archive_error).to eq(nil)
|
||||
expect(@channel_archive.archived_messages).to eq(35)
|
||||
expect(@channel_archive.complete?).to eq(true)
|
||||
channel_archive.reload
|
||||
expect(channel_archive.archive_error).to eq(nil)
|
||||
expect(channel_archive.archived_messages).to eq(35)
|
||||
expect(channel_archive.complete?).to eq(true)
|
||||
# existing posts + 7 archive posts
|
||||
expect(topic.posts.count).to eq(10)
|
||||
end
|
||||
|
@@ -5,16 +5,12 @@ describe Chat::Notifier do
|
||||
fab!(:channel) { Fabricate(:category_channel) }
|
||||
fab!(:user_1) { Fabricate(:user, refresh_auto_groups: true) }
|
||||
fab!(:user_2) { Fabricate(:user) }
|
||||
fab!(:chat_group) do
|
||||
Fabricate(:group, users: [user_1, user_2], mentionable_level: Group::ALIAS_LEVELS[:everyone])
|
||||
end
|
||||
|
||||
before do
|
||||
@chat_group =
|
||||
Fabricate(
|
||||
:group,
|
||||
users: [user_1, user_2],
|
||||
mentionable_level: Group::ALIAS_LEVELS[:everyone],
|
||||
)
|
||||
SiteSetting.chat_allowed_groups = @chat_group.id
|
||||
|
||||
SiteSetting.chat_allowed_groups = chat_group.id
|
||||
[user_1, user_2].each do |u|
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: channel, user: u)
|
||||
end
|
||||
@@ -104,7 +100,7 @@ describe Chat::Notifier do
|
||||
shared_examples "ensure only channel members are notified" do
|
||||
it "will never include someone outside the channel" do
|
||||
user3 = Fabricate(:user)
|
||||
@chat_group.add(user3)
|
||||
chat_group.add(user3)
|
||||
another_channel = Fabricate(:category_channel)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: another_channel, user: user3)
|
||||
msg = build_cooked_msg(mention, user_1)
|
||||
@@ -116,7 +112,7 @@ describe Chat::Notifier do
|
||||
|
||||
it "will never include someone not following the channel anymore" do
|
||||
user3 = Fabricate(:user)
|
||||
@chat_group.add(user3)
|
||||
chat_group.add(user3)
|
||||
Fabricate(
|
||||
:user_chat_channel_membership,
|
||||
following: false,
|
||||
@@ -132,7 +128,7 @@ describe Chat::Notifier do
|
||||
|
||||
it "will never include someone who is suspended" do
|
||||
user3 = Fabricate(:user, suspended_till: 2.years.from_now)
|
||||
@chat_group.add(user3)
|
||||
chat_group.add(user3)
|
||||
Fabricate(
|
||||
:user_chat_channel_membership,
|
||||
following: true,
|
||||
@@ -258,7 +254,7 @@ describe Chat::Notifier do
|
||||
describe "direct_mentions" do
|
||||
it "only include mentioned users who are already in the channel" do
|
||||
user_3 = Fabricate(:user)
|
||||
@chat_group.add(user_3)
|
||||
chat_group.add(user_3)
|
||||
another_channel = Fabricate(:category_channel)
|
||||
Fabricate(:user_chat_channel_membership, chat_channel: another_channel, user: user_3)
|
||||
msg = build_cooked_msg("Is @#{user_3.username} here? And @#{user_2.username}", user_1)
|
||||
@@ -326,7 +322,7 @@ describe Chat::Notifier do
|
||||
end
|
||||
fab!(:other_channel) { Fabricate(:category_channel) }
|
||||
|
||||
before { @chat_group.add(user_3) }
|
||||
before { chat_group.add(user_3) }
|
||||
|
||||
let(:mention) { "hello @#{group.name}!" }
|
||||
let(:list_key) { group.name }
|
||||
@@ -346,19 +342,19 @@ describe Chat::Notifier do
|
||||
user: user_3,
|
||||
following: true,
|
||||
)
|
||||
msg = build_cooked_msg("Hello @#{@chat_group.name} and @#{group.name}", user_1)
|
||||
msg = build_cooked_msg("Hello @#{chat_group.name} and @#{group.name}", user_1)
|
||||
|
||||
to_notify = described_class.new(msg, msg.created_at).notify_new
|
||||
|
||||
expect(to_notify[@chat_group.name]).to contain_exactly(user_2.id, user_3.id)
|
||||
expect(to_notify[chat_group.name]).to contain_exactly(user_2.id, user_3.id)
|
||||
expect(to_notify[list_key]).to be_empty
|
||||
|
||||
second_msg = build_cooked_msg("Hello @#{group.name} and @#{@chat_group.name}", user_1)
|
||||
second_msg = build_cooked_msg("Hello @#{group.name} and @#{chat_group.name}", user_1)
|
||||
|
||||
to_notify_2 = described_class.new(second_msg, second_msg.created_at).notify_new
|
||||
|
||||
expect(to_notify_2[list_key]).to contain_exactly(user_2.id, user_3.id)
|
||||
expect(to_notify_2[@chat_group.name]).to be_empty
|
||||
expect(to_notify_2[chat_group.name]).to be_empty
|
||||
end
|
||||
|
||||
it "skips groups with too many members" do
|
||||
@@ -478,7 +474,7 @@ describe Chat::Notifier do
|
||||
result.channel
|
||||
end
|
||||
|
||||
before { @chat_group.add(user_3) }
|
||||
before { chat_group.add(user_3) }
|
||||
|
||||
it "notify posts of users who are not participating in a personal message" do
|
||||
msg =
|
||||
@@ -533,7 +529,7 @@ describe Chat::Notifier do
|
||||
describe "users who can be invited to join the channel" do
|
||||
fab!(:user_3) { Fabricate(:user) }
|
||||
|
||||
before { @chat_group.add(user_3) }
|
||||
before { chat_group.add(user_3) }
|
||||
|
||||
it "can invite chat user without channel membership" do
|
||||
msg = build_cooked_msg("Hello @#{user_3.username}", user_1)
|
||||
|
@@ -292,18 +292,19 @@ RSpec.shared_examples "a chat channel model" do
|
||||
end
|
||||
|
||||
describe "#remove" do
|
||||
let!(:membership) { private_category_channel.add(user1) }
|
||||
|
||||
before do
|
||||
group.add(user1)
|
||||
@membership = private_category_channel.add(user1)
|
||||
private_category_channel.reload
|
||||
private_category_channel.update!(user_count_stale: false)
|
||||
end
|
||||
|
||||
it "updates the membership for the user and decreases the count" do
|
||||
membership = private_category_channel.remove(user1)
|
||||
private_category_channel.remove(user1)
|
||||
private_category_channel.reload
|
||||
|
||||
expect(@membership.reload.following).to eq(false)
|
||||
expect(membership.reload.following).to eq(false)
|
||||
expect(private_category_channel.user_count_stale).to eq(true)
|
||||
expect_job_enqueued(
|
||||
job: Jobs::Chat::UpdateChannelUserCount,
|
||||
@@ -318,7 +319,7 @@ RSpec.shared_examples "a chat channel model" do
|
||||
end
|
||||
|
||||
it "does nothing if the user is not following the channel" do
|
||||
@membership.update!(following: false)
|
||||
membership.update!(following: false)
|
||||
|
||||
private_category_channel.remove(user1)
|
||||
private_category_channel.reload
|
||||
|
@@ -760,23 +760,22 @@ RSpec.describe DiscourseNarrativeBot::TrackSelector do
|
||||
end
|
||||
|
||||
context "when new and advanced user triggers overlap" do
|
||||
before do
|
||||
@overrides = []
|
||||
|
||||
@overrides << TranslationOverride.upsert!(
|
||||
I18n.locale,
|
||||
"discourse_narrative_bot.new_user_narrative.reset_trigger",
|
||||
"tutorial",
|
||||
)
|
||||
|
||||
@overrides << TranslationOverride.upsert!(
|
||||
I18n.locale,
|
||||
"discourse_narrative_bot.advanced_user_narrative.reset_trigger",
|
||||
"tutorial advanced",
|
||||
)
|
||||
let!(:overrides) do
|
||||
[
|
||||
TranslationOverride.upsert!(
|
||||
I18n.locale,
|
||||
"discourse_narrative_bot.new_user_narrative.reset_trigger",
|
||||
"tutorial",
|
||||
),
|
||||
TranslationOverride.upsert!(
|
||||
I18n.locale,
|
||||
"discourse_narrative_bot.advanced_user_narrative.reset_trigger",
|
||||
"tutorial advanced",
|
||||
),
|
||||
]
|
||||
end
|
||||
|
||||
after { @overrides.each(&:destroy!) }
|
||||
after { overrides.each(&:destroy!) }
|
||||
|
||||
it "should start the right track" do
|
||||
post.update!(
|
||||
|
@@ -1310,56 +1310,55 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
describe "local attribute override from SSO payload" do
|
||||
fab!(:user)
|
||||
|
||||
let!(:sso) { get_sso("/hello/world") }
|
||||
let(:reversed_username) { user.username.reverse }
|
||||
let(:suggested_username) { UserNameSuggester.suggest(sso.username || sso.name || sso.email) }
|
||||
let(:suggested_name) { User.suggest_name(sso.name || sso.username || sso.email) }
|
||||
|
||||
before do
|
||||
SiteSetting.email_editable = false
|
||||
SiteSetting.auth_overrides_email = true
|
||||
SiteSetting.auth_overrides_username = true
|
||||
SiteSetting.auth_overrides_name = true
|
||||
|
||||
@user = Fabricate(:user)
|
||||
sso.external_id = "997"
|
||||
sso.username = reversed_username
|
||||
sso.email = "#{reversed_username}@garbage.org"
|
||||
sso.name = user.name.reverse
|
||||
|
||||
@sso = get_sso("/hello/world")
|
||||
@sso.external_id = "997"
|
||||
|
||||
@reversed_username = @user.username.reverse
|
||||
@sso.username = @reversed_username
|
||||
@sso.email = "#{@reversed_username}@garbage.org"
|
||||
@reversed_name = @user.name.reverse
|
||||
@sso.name = @reversed_name
|
||||
|
||||
@suggested_username = UserNameSuggester.suggest(@sso.username || @sso.name || @sso.email)
|
||||
@suggested_name = User.suggest_name(@sso.name || @sso.username || @sso.email)
|
||||
@user.create_single_sign_on_record(external_id: "997", last_payload: "")
|
||||
user.create_single_sign_on_record(external_id: "997", last_payload: "")
|
||||
end
|
||||
|
||||
it "stores the external attributes" do
|
||||
get "/session/sso_login", params: Rack::Utils.parse_query(@sso.payload), headers: headers
|
||||
@user.single_sign_on_record.reload
|
||||
expect(@user.single_sign_on_record.external_username).to eq(@sso.username)
|
||||
expect(@user.single_sign_on_record.external_email).to eq(@sso.email)
|
||||
expect(@user.single_sign_on_record.external_name).to eq(@sso.name)
|
||||
get "/session/sso_login", params: Rack::Utils.parse_query(sso.payload), headers: headers
|
||||
user.single_sign_on_record.reload
|
||||
expect(user.single_sign_on_record.external_username).to eq(sso.username)
|
||||
expect(user.single_sign_on_record.external_email).to eq(sso.email)
|
||||
expect(user.single_sign_on_record.external_name).to eq(sso.name)
|
||||
end
|
||||
|
||||
it "overrides attributes" do
|
||||
get "/session/sso_login", params: Rack::Utils.parse_query(@sso.payload), headers: headers
|
||||
get "/session/sso_login", params: Rack::Utils.parse_query(sso.payload), headers: headers
|
||||
|
||||
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
|
||||
expect(logged_on_user.username).to eq(@suggested_username)
|
||||
expect(logged_on_user.email).to eq("#{@reversed_username}@garbage.org")
|
||||
expect(logged_on_user.name).to eq(@sso.name)
|
||||
expect(logged_on_user.username).to eq(suggested_username)
|
||||
expect(logged_on_user.email).to eq("#{reversed_username}@garbage.org")
|
||||
expect(logged_on_user.name).to eq(sso.name)
|
||||
end
|
||||
|
||||
it "does not change matching attributes for an existing account" do
|
||||
@sso.username = @user.username
|
||||
@sso.name = @user.name
|
||||
@sso.email = @user.email
|
||||
sso.username = user.username
|
||||
sso.name = user.name
|
||||
sso.email = user.email
|
||||
|
||||
get "/session/sso_login", params: Rack::Utils.parse_query(@sso.payload), headers: headers
|
||||
get "/session/sso_login", params: Rack::Utils.parse_query(sso.payload), headers: headers
|
||||
|
||||
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
|
||||
expect(logged_on_user.username).to eq(@user.username)
|
||||
expect(logged_on_user.name).to eq(@user.name)
|
||||
expect(logged_on_user.email).to eq(@user.email)
|
||||
expect(logged_on_user.username).to eq(user.username)
|
||||
expect(logged_on_user.name).to eq(user.name)
|
||||
expect(logged_on_user.email).to eq(user.email)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1375,9 +1374,11 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
describe "#sso_provider" do
|
||||
fab!(:user) { Fabricate(:user, password: "myfrogs123ADMIN", active: true, admin: true) }
|
||||
|
||||
let(:headers) { { host: Discourse.current_hostname } }
|
||||
let(:logo_fixture) { "http://#{Discourse.current_hostname}/uploads/logo.png" }
|
||||
fab!(:user) { Fabricate(:user, password: "myfrogs123ADMIN", active: true, admin: true) }
|
||||
let(:sso) { DiscourseConnectProvider.new }
|
||||
|
||||
before do
|
||||
stub_request(:any, %r{#{Discourse.current_hostname}/uploads}).to_return(
|
||||
@@ -1397,35 +1398,33 @@ RSpec.describe SessionController do
|
||||
somewhere.over.rainbow|newSecretForOverRainbow
|
||||
].join("\n")
|
||||
|
||||
@sso = DiscourseConnectProvider.new
|
||||
@sso.nonce = "mynonce"
|
||||
@sso.return_sso_url = "http://somewhere.over.rainbow/sso"
|
||||
sso.nonce = "mynonce"
|
||||
sso.return_sso_url = "http://somewhere.over.rainbow/sso"
|
||||
|
||||
@user = user
|
||||
group = Fabricate(:group)
|
||||
group.add(@user)
|
||||
group.add(user)
|
||||
|
||||
@user.create_user_avatar!
|
||||
UserAvatar.import_url_for_user(logo_fixture, @user)
|
||||
UserProfile.import_url_for_user(logo_fixture, @user, is_card_background: false)
|
||||
UserProfile.import_url_for_user(logo_fixture, @user, is_card_background: true)
|
||||
user.create_user_avatar!
|
||||
UserAvatar.import_url_for_user(logo_fixture, user)
|
||||
UserProfile.import_url_for_user(logo_fixture, user, is_card_background: false)
|
||||
UserProfile.import_url_for_user(logo_fixture, user, is_card_background: true)
|
||||
|
||||
@user.reload
|
||||
@user.user_avatar.reload
|
||||
@user.user_profile.reload
|
||||
user.reload
|
||||
user.user_avatar.reload
|
||||
user.user_profile.reload
|
||||
EmailToken.update_all(confirmed: true)
|
||||
end
|
||||
|
||||
describe "can act as an SSO provider" do
|
||||
it "successfully logs in and redirects user to return_sso_url when the user is not logged in" do
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
expect(response).to redirect_to("/login")
|
||||
|
||||
post "/session.json",
|
||||
params: {
|
||||
login: @user.username,
|
||||
login: user.username,
|
||||
password: "myfrogs123ADMIN",
|
||||
},
|
||||
xhr: true,
|
||||
@@ -1438,13 +1437,13 @@ RSpec.describe SessionController do
|
||||
payload = location.split("?")[1]
|
||||
sso2 = DiscourseConnectProvider.parse(payload)
|
||||
|
||||
expect(sso2.email).to eq(@user.email)
|
||||
expect(sso2.name).to eq(@user.name)
|
||||
expect(sso2.username).to eq(@user.username)
|
||||
expect(sso2.external_id).to eq(@user.id.to_s)
|
||||
expect(sso2.email).to eq(user.email)
|
||||
expect(sso2.name).to eq(user.name)
|
||||
expect(sso2.username).to eq(user.username)
|
||||
expect(sso2.external_id).to eq(user.id.to_s)
|
||||
expect(sso2.admin).to eq(true)
|
||||
expect(sso2.moderator).to eq(false)
|
||||
expect(sso2.groups).to eq(@user.groups.pluck(:name).join(","))
|
||||
expect(sso2.groups).to eq(user.groups.pluck(:name).join(","))
|
||||
|
||||
expect(sso2.avatar_url.blank?).to_not eq(true)
|
||||
expect(sso2.profile_background_url.blank?).to_not eq(true)
|
||||
@@ -1458,10 +1457,10 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
it "correctly logs in for secondary domain secrets" do
|
||||
sign_in @user
|
||||
sign_in user
|
||||
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("newSecretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("newSecretForOverRainbow"))
|
||||
expect(response.status).to eq(302)
|
||||
redirect_uri = URI.parse(response.location)
|
||||
expect(redirect_uri.host).to eq("somewhere.over.rainbow")
|
||||
@@ -1471,7 +1470,7 @@ RSpec.describe SessionController do
|
||||
expect(redirect_query["sig"][0]).to eq(expected_sig)
|
||||
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("oldSecretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("oldSecretForOverRainbow"))
|
||||
expect(response.status).to eq(302)
|
||||
redirect_uri = URI.parse(response.location)
|
||||
expect(redirect_uri.host).to eq("somewhere.over.rainbow")
|
||||
@@ -1483,7 +1482,7 @@ RSpec.describe SessionController do
|
||||
|
||||
it "fails to log in if secret is wrong" do
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForRandomSite"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForRandomSite"))
|
||||
expect(response.status).to eq(422)
|
||||
end
|
||||
|
||||
@@ -1504,10 +1503,10 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
it "successfully redirects user to return_sso_url when the user is logged in" do
|
||||
sign_in(@user)
|
||||
sign_in(user)
|
||||
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
location = response.header["Location"]
|
||||
expect(location).to match(%r{^http://somewhere.over.rainbow/sso})
|
||||
@@ -1515,13 +1514,13 @@ RSpec.describe SessionController do
|
||||
payload = location.split("?")[1]
|
||||
sso2 = DiscourseConnectProvider.parse(payload)
|
||||
|
||||
expect(sso2.email).to eq(@user.email)
|
||||
expect(sso2.name).to eq(@user.name)
|
||||
expect(sso2.username).to eq(@user.username)
|
||||
expect(sso2.external_id).to eq(@user.id.to_s)
|
||||
expect(sso2.email).to eq(user.email)
|
||||
expect(sso2.name).to eq(user.name)
|
||||
expect(sso2.username).to eq(user.username)
|
||||
expect(sso2.external_id).to eq(user.id.to_s)
|
||||
expect(sso2.admin).to eq(true)
|
||||
expect(sso2.moderator).to eq(false)
|
||||
expect(sso2.groups).to eq(@user.groups.pluck(:name).join(","))
|
||||
expect(sso2.groups).to eq(user.groups.pluck(:name).join(","))
|
||||
|
||||
expect(sso2.avatar_url.blank?).to_not eq(true)
|
||||
expect(sso2.profile_background_url.blank?).to_not eq(true)
|
||||
@@ -1535,10 +1534,10 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
it "fails with a nice error message if `prompt` parameter has an invalid value" do
|
||||
@sso.prompt = "xyzpdq"
|
||||
sso.prompt = "xyzpdq"
|
||||
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
expect(response.status).to eq(400)
|
||||
expect(response.body).to eq(
|
||||
@@ -1547,10 +1546,10 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
it "redirects browser to return_sso_url with auth failure when prompt=none is requested and the user is not logged in" do
|
||||
@sso.prompt = "none"
|
||||
sso.prompt = "none"
|
||||
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
location = response.header["Location"]
|
||||
expect(location).to match(%r{^http://somewhere.over.rainbow/sso})
|
||||
@@ -1588,7 +1587,7 @@ RSpec.describe SessionController do
|
||||
},
|
||||
)
|
||||
|
||||
@user.create_user_avatar!
|
||||
user.create_user_avatar!
|
||||
upload =
|
||||
Fabricate(
|
||||
:upload,
|
||||
@@ -1604,29 +1603,28 @@ RSpec.describe SessionController do
|
||||
url: "//s3-upload-bucket.s3.amazonaws.com/something/else",
|
||||
)
|
||||
|
||||
@user.update_columns(uploaded_avatar_id: upload.id)
|
||||
user.update_columns(uploaded_avatar_id: upload.id)
|
||||
|
||||
upload1 = Fabricate(:upload_s3)
|
||||
upload2 = Fabricate(:upload_s3)
|
||||
|
||||
@user.user_profile.update!(
|
||||
user.user_profile.update!(
|
||||
profile_background_upload: upload1,
|
||||
card_background_upload: upload2,
|
||||
)
|
||||
|
||||
@user.reload
|
||||
@user.user_avatar.reload
|
||||
@user.user_profile.reload
|
||||
user.reload
|
||||
user.user_avatar.reload
|
||||
user.user_profile.reload
|
||||
|
||||
sign_in(@user)
|
||||
sign_in(user)
|
||||
|
||||
stub_request(:get, "http://cdn.com/something/else").to_return(
|
||||
body: lambda { |request| File.new(Rails.root + "spec/fixtures/images/logo.png") },
|
||||
)
|
||||
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
location = response.header["Location"]
|
||||
# javascript code will handle redirection of user to return_sso_url
|
||||
expect(location).to match(%r{^http://somewhere.over.rainbow/sso})
|
||||
@@ -1646,11 +1644,11 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
it "successfully logs out and redirects user to return_sso_url when the user is logged in" do
|
||||
sign_in(@user)
|
||||
sign_in(user)
|
||||
|
||||
@sso.logout = true
|
||||
sso.logout = true
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
location = response.header["Location"]
|
||||
expect(location).to match(%r{^http://somewhere.over.rainbow/sso$})
|
||||
@@ -1661,9 +1659,9 @@ RSpec.describe SessionController do
|
||||
end
|
||||
|
||||
it "successfully logs out and redirects user to return_sso_url when the user is not logged in" do
|
||||
@sso.logout = true
|
||||
sso.logout = true
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
location = response.header["Location"]
|
||||
expect(location).to match(%r{^http://somewhere.over.rainbow/sso$})
|
||||
@@ -1676,12 +1674,12 @@ RSpec.describe SessionController do
|
||||
|
||||
describe "can act as a 2FA provider" do
|
||||
fab!(:user_totp) { Fabricate(:user_second_factor_totp, user: user) }
|
||||
before { @sso.require_2fa = true }
|
||||
before { sso.require_2fa = true }
|
||||
|
||||
it "requires the user to confirm 2FA before they are redirected to the SSO return URL" do
|
||||
sign_in(user)
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
uri = URI(response.location)
|
||||
expect(uri.hostname).to eq(Discourse.current_hostname)
|
||||
expect(uri.path).to eq("/session/2fa")
|
||||
@@ -1698,7 +1696,7 @@ RSpec.describe SessionController do
|
||||
# attempt no. 2 to bypass 2fa
|
||||
get "/session/sso_provider",
|
||||
params: { second_factor_nonce: nonce }.merge(
|
||||
Rack::Utils.parse_query(@sso.payload("secretForOverRainbow")),
|
||||
Rack::Utils.parse_query(sso.payload("secretForOverRainbow")),
|
||||
)
|
||||
expect(response.status).to eq(401)
|
||||
expect(response.parsed_body["error"]).to eq(
|
||||
@@ -1734,7 +1732,7 @@ RSpec.describe SessionController do
|
||||
backup_codes = user.generate_backup_codes
|
||||
sign_in(user)
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
uri = URI(response.location)
|
||||
expect(uri.hostname).to eq(Discourse.current_hostname)
|
||||
expect(uri.path).to eq("/session/2fa")
|
||||
@@ -1764,7 +1762,7 @@ RSpec.describe SessionController do
|
||||
it "redirects the user back to the SSO return url and indicates in the payload that they do not have 2fa methods" do
|
||||
sign_in(user)
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
expect(response.status).to eq(302)
|
||||
redirect_url = response.location
|
||||
@@ -1780,14 +1778,14 @@ RSpec.describe SessionController do
|
||||
context "when there is no logged in user" do
|
||||
it "redirects the user to login first" do
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
expect(response.status).to eq(302)
|
||||
expect(response.location).to eq("http://#{Discourse.current_hostname}/login")
|
||||
end
|
||||
|
||||
it "doesn't make the user confirm 2fa twice if they've just logged in and confirmed 2fa while doing so" do
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
post "/session.json",
|
||||
params: {
|
||||
@@ -1813,7 +1811,7 @@ RSpec.describe SessionController do
|
||||
user_totp.destroy!
|
||||
user.reload
|
||||
get "/session/sso_provider",
|
||||
params: Rack::Utils.parse_query(@sso.payload("secretForOverRainbow"))
|
||||
params: Rack::Utils.parse_query(sso.payload("secretForOverRainbow"))
|
||||
|
||||
post "/session.json",
|
||||
params: {
|
||||
|
@@ -2958,39 +2958,40 @@ RSpec.describe TopicsController do
|
||||
json["post_stream"]["posts"].map { |post| post["id"] }
|
||||
end
|
||||
|
||||
let(:post_ids) { topic.posts.pluck(:id) }
|
||||
|
||||
before do
|
||||
TopicView.stubs(:chunk_size).returns(2)
|
||||
@post_ids = topic.posts.pluck(:id)
|
||||
3.times { @post_ids << Fabricate(:post, user: post_author1, topic: topic).id }
|
||||
3.times { post_ids << Fabricate(:post, user: post_author1, topic: topic).id }
|
||||
end
|
||||
|
||||
it "grabs the correct set of posts" do
|
||||
get "/t/#{topic.slug}/#{topic.id}.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[0..1])
|
||||
expect(extract_post_stream).to eq(post_ids[0..1])
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 1 }
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[0..1])
|
||||
expect(extract_post_stream).to eq(post_ids[0..1])
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 2 }
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[2..3])
|
||||
expect(extract_post_stream).to eq(post_ids[2..3])
|
||||
|
||||
post_number = topic.posts.pluck(:post_number).sort[3]
|
||||
get "/t/#{topic.slug}/#{topic.id}/#{post_number}.json"
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[-2..-1])
|
||||
expect(extract_post_stream).to eq(post_ids[-2..-1])
|
||||
|
||||
TopicView.stubs(:chunk_size).returns(3)
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 1 }
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[0..2])
|
||||
expect(extract_post_stream).to eq(post_ids[0..2])
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 2 }
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[3..3])
|
||||
expect(extract_post_stream).to eq(post_ids[3..3])
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 3 }
|
||||
expect(response.status).to eq(404)
|
||||
@@ -2999,7 +3000,7 @@ RSpec.describe TopicsController do
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 1 }
|
||||
expect(response.status).to eq(200)
|
||||
expect(extract_post_stream).to eq(@post_ids[0..3])
|
||||
expect(extract_post_stream).to eq(post_ids[0..3])
|
||||
|
||||
get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 2 }
|
||||
expect(response.status).to eq(404)
|
||||
|
@@ -718,15 +718,16 @@ RSpec.describe UsersController do
|
||||
params
|
||||
end
|
||||
|
||||
let(:user) { Fabricate.build(:user, email: "foobar@example.com", password: "strongpassword") }
|
||||
|
||||
before do
|
||||
UsersController.any_instance.stubs(:honeypot_value).returns(nil)
|
||||
UsersController.any_instance.stubs(:challenge_value).returns(nil)
|
||||
SiteSetting.allow_new_registrations = true
|
||||
@user = Fabricate.build(:user, email: "foobar@example.com", password: "strongpassword")
|
||||
end
|
||||
|
||||
let(:post_user_params) do
|
||||
{ name: @user.name, username: @user.username, password: "strongpassword", email: @user.email }
|
||||
{ name: user.name, username: user.username, password: "strongpassword", email: user.email }
|
||||
end
|
||||
|
||||
def post_user(extra_params = {})
|
||||
@@ -737,8 +738,8 @@ RSpec.describe UsersController do
|
||||
it "should raise the right error" do
|
||||
post "/u.json",
|
||||
params: {
|
||||
name: @user.name,
|
||||
username: @user.username,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
password: "testing12352343",
|
||||
}
|
||||
expect(response.status).to eq(400)
|
||||
@@ -772,7 +773,7 @@ RSpec.describe UsersController do
|
||||
SiteSetting.default_locale = "en"
|
||||
I18n.stubs(:locale).returns(:fr)
|
||||
post_user
|
||||
expect(User.find_by(username: @user.username).locale).to eq("fr")
|
||||
expect(User.find_by(username: user.username).locale).to eq("fr")
|
||||
end
|
||||
|
||||
it "requires invite code when specified" do
|
||||
@@ -796,7 +797,7 @@ RSpec.describe UsersController do
|
||||
it "sets the timezone" do
|
||||
post_user(timezone: "Australia/Brisbane")
|
||||
expect(response.status).to eq(200)
|
||||
expect(User.find_by(username: @user.username).user_option.timezone).to eq(
|
||||
expect(User.find_by(username: user.username).user_option.timezone).to eq(
|
||||
"Australia/Brisbane",
|
||||
)
|
||||
end
|
||||
@@ -1412,7 +1413,7 @@ RSpec.describe UsersController do
|
||||
expect(response.status).to eq(200)
|
||||
json = response.parsed_body
|
||||
expect(json["success"]).to eq(true)
|
||||
expect(User.find_by(username: @user.username).active).to eq(false)
|
||||
expect(User.find_by(username: user.username).active).to eq(false)
|
||||
end
|
||||
|
||||
shared_examples "honeypot fails" do
|
||||
@@ -1436,10 +1437,10 @@ RSpec.describe UsersController do
|
||||
before { UsersController.any_instance.stubs(:honeypot_value).returns("abc") }
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
username: @user.username,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
password: "strongpassword",
|
||||
email: @user.email,
|
||||
email: user.email,
|
||||
password_confirmation: "wrong",
|
||||
}
|
||||
end
|
||||
@@ -1450,10 +1451,10 @@ RSpec.describe UsersController do
|
||||
before { UsersController.any_instance.stubs(:challenge_value).returns("abc") }
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
username: @user.username,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
password: "strongpassword",
|
||||
email: @user.email,
|
||||
email: user.email,
|
||||
challenge: "abc",
|
||||
}
|
||||
end
|
||||
@@ -1464,12 +1465,7 @@ RSpec.describe UsersController do
|
||||
before { SiteSetting.invite_only = true }
|
||||
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
username: @user.username,
|
||||
password: "strongpassword",
|
||||
email: @user.email,
|
||||
}
|
||||
{ name: user.name, username: user.username, password: "strongpassword", email: user.email }
|
||||
end
|
||||
|
||||
include_examples "honeypot fails"
|
||||
@@ -1494,7 +1490,7 @@ RSpec.describe UsersController do
|
||||
|
||||
context "when password is blank" do
|
||||
let(:create_params) do
|
||||
{ name: @user.name, username: @user.username, password: "", email: @user.email }
|
||||
{ name: user.name, username: user.username, password: "", email: user.email }
|
||||
end
|
||||
include_examples "failed signup"
|
||||
end
|
||||
@@ -1502,23 +1498,23 @@ RSpec.describe UsersController do
|
||||
context "when password is too long" do
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
username: @user.username,
|
||||
name: user.name,
|
||||
username: user.username,
|
||||
password: "x" * (User.max_password_length + 1),
|
||||
email: @user.email,
|
||||
email: user.email,
|
||||
}
|
||||
end
|
||||
include_examples "failed signup"
|
||||
end
|
||||
|
||||
context "when password param is missing" do
|
||||
let(:create_params) { { name: @user.name, username: @user.username, email: @user.email } }
|
||||
let(:create_params) { { name: user.name, username: user.username, email: user.email } }
|
||||
include_examples "failed signup"
|
||||
end
|
||||
|
||||
context "with a reserved username" do
|
||||
let(:create_params) do
|
||||
{ name: @user.name, username: "Reserved", email: @user.email, password: "strongpassword" }
|
||||
{ name: user.name, username: "Reserved", email: user.email, password: "strongpassword" }
|
||||
end
|
||||
before { SiteSetting.reserved_usernames = "a|reserved|b" }
|
||||
include_examples "failed signup"
|
||||
@@ -1527,9 +1523,9 @@ RSpec.describe UsersController do
|
||||
context "with a username that matches a user route" do
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
name: user.name,
|
||||
username: "account-created",
|
||||
email: @user.email,
|
||||
email: user.email,
|
||||
password: "strongpassword",
|
||||
}
|
||||
end
|
||||
@@ -1537,7 +1533,7 @@ RSpec.describe UsersController do
|
||||
end
|
||||
|
||||
context "with a missing username" do
|
||||
let(:create_params) { { name: @user.name, email: @user.email, password: "x" * 20 } }
|
||||
let(:create_params) { { name: user.name, email: user.email, password: "x" * 20 } }
|
||||
|
||||
it "should not create a new User" do
|
||||
expect { post "/u.json", params: create_params }.to_not change { User.count }
|
||||
@@ -1549,12 +1545,7 @@ RSpec.describe UsersController do
|
||||
before { User.any_instance.stubs(:save).raises(ActiveRecord::StatementInvalid.new("Oh no")) }
|
||||
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
username: @user.username,
|
||||
password: "strongpassword",
|
||||
email: @user.email,
|
||||
}
|
||||
{ name: user.name, username: user.username, password: "strongpassword", email: user.email }
|
||||
end
|
||||
|
||||
include_examples "failed signup"
|
||||
@@ -1567,7 +1558,7 @@ RSpec.describe UsersController do
|
||||
|
||||
context "without a value for the fields" do
|
||||
let(:create_params) do
|
||||
{ name: @user.name, password: "watwatwat", username: @user.username, email: @user.email }
|
||||
{ name: user.name, password: "watwatwat", username: user.username, email: user.email }
|
||||
end
|
||||
include_examples "failed signup"
|
||||
end
|
||||
@@ -1712,10 +1703,10 @@ RSpec.describe UsersController do
|
||||
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
name: user.name,
|
||||
password: "suChS3cuRi7y",
|
||||
username: @user.username,
|
||||
email: @user.email,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
user_fields: {
|
||||
user_field.id.to_s => "value1",
|
||||
another_field.id.to_s => "value2",
|
||||
@@ -1726,7 +1717,7 @@ RSpec.describe UsersController do
|
||||
it "should succeed without the optional field" do
|
||||
post "/u.json", params: create_params
|
||||
expect(response.status).to eq(200)
|
||||
inserted = User.find_by_email(@user.email)
|
||||
inserted = User.find_by_email(user.email)
|
||||
expect(inserted).to be_present
|
||||
expect(inserted.custom_fields).to be_present
|
||||
expect(inserted.custom_fields["user_field_#{user_field.id}"]).to eq("value1")
|
||||
@@ -1738,7 +1729,7 @@ RSpec.describe UsersController do
|
||||
create_params[:user_fields][optional_field.id.to_s] = "value3"
|
||||
post "/u.json", params: create_params.merge(create_params)
|
||||
expect(response.status).to eq(200)
|
||||
inserted = User.find_by_email(@user.email)
|
||||
inserted = User.find_by_email(user.email)
|
||||
expect(inserted).to be_present
|
||||
expect(inserted.custom_fields).to be_present
|
||||
expect(inserted.custom_fields["user_field_#{user_field.id}"]).to eq("value1")
|
||||
@@ -1750,7 +1741,7 @@ RSpec.describe UsersController do
|
||||
create_params[:user_fields][optional_field.id.to_s] = ("x" * 3000)
|
||||
post "/u.json", params: create_params.merge(create_params)
|
||||
expect(response.status).to eq(200)
|
||||
inserted = User.find_by_email(@user.email)
|
||||
inserted = User.find_by_email(user.email)
|
||||
|
||||
val = inserted.custom_fields["user_field_#{optional_field.id}"]
|
||||
expect(val.length).to eq(UserField.max_length)
|
||||
@@ -1763,18 +1754,13 @@ RSpec.describe UsersController do
|
||||
|
||||
context "without values for the fields" do
|
||||
let(:create_params) do
|
||||
{
|
||||
name: @user.name,
|
||||
password: "suChS3cuRi7y",
|
||||
username: @user.username,
|
||||
email: @user.email,
|
||||
}
|
||||
{ name: user.name, password: "suChS3cuRi7y", username: user.username, email: user.email }
|
||||
end
|
||||
|
||||
it "should succeed" do
|
||||
post "/u.json", params: create_params
|
||||
expect(response.status).to eq(200)
|
||||
inserted = User.find_by_email(@user.email)
|
||||
inserted = User.find_by_email(user.email)
|
||||
expect(inserted).to be_present
|
||||
expect(inserted.custom_fields).not_to be_present
|
||||
expect(inserted.custom_fields["user_field_#{user_field.id}"]).to be_blank
|
||||
|
@@ -15,6 +15,7 @@ RSpec.describe ExternalUploadManager do
|
||||
let(:external_upload_stub_metadata) { {} }
|
||||
let!(:external_upload_stub) { Fabricate(:image_external_upload_stub, created_by: user) }
|
||||
let(:s3_bucket_name) { SiteSetting.s3_upload_bucket }
|
||||
let(:fake_s3) { FakeS3.create }
|
||||
|
||||
before do
|
||||
SiteSetting.authorized_extensions += "|pdf"
|
||||
@@ -25,7 +26,12 @@ RSpec.describe ExternalUploadManager do
|
||||
SiteSetting.s3_backup_bucket = "s3-backup-bucket"
|
||||
SiteSetting.backup_location = BackupLocationSiteSetting::S3
|
||||
|
||||
prepare_fake_s3
|
||||
fake_s3.bucket(s3_bucket_name).put_object(
|
||||
key: external_upload_stub.key,
|
||||
size: object_size,
|
||||
last_modified: Time.zone.now,
|
||||
metadata: external_upload_stub_metadata,
|
||||
)
|
||||
stub_download_object_filehelper
|
||||
end
|
||||
|
||||
@@ -73,8 +79,8 @@ RSpec.describe ExternalUploadManager do
|
||||
it "copies the stubbed upload on S3 to its new destination and deletes it" do
|
||||
upload = manager.transform!
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(@fake_s3.operation_called?(:copy_object)).to eq(true)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(fake_s3.operation_called?(:copy_object)).to eq(true)
|
||||
expect(bucket.find_object(Discourse.store.get_path_for_upload(upload))).to be_present
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_nil
|
||||
end
|
||||
@@ -117,8 +123,8 @@ RSpec.describe ExternalUploadManager do
|
||||
it "creates a new upload in s3 (not copy) and deletes the original stubbed upload" do
|
||||
upload = manager.transform!
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(@fake_s3.operation_called?(:copy_object)).to eq(false)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(fake_s3.operation_called?(:copy_object)).to eq(false)
|
||||
expect(bucket.find_object(Discourse.store.get_path_for_upload(upload))).to be_present
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_nil
|
||||
end
|
||||
@@ -136,7 +142,7 @@ RSpec.describe ExternalUploadManager do
|
||||
)
|
||||
expect(ExternalUploadStub.exists?(id: external_upload_stub.id)).to eq(false)
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_nil
|
||||
end
|
||||
|
||||
@@ -148,7 +154,7 @@ RSpec.describe ExternalUploadManager do
|
||||
external_stub = ExternalUploadStub.find(external_upload_stub.id)
|
||||
expect(external_stub.status).to eq(ExternalUploadStub.statuses[:failed])
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_present
|
||||
end
|
||||
end
|
||||
@@ -168,7 +174,7 @@ RSpec.describe ExternalUploadManager do
|
||||
),
|
||||
).to eq("1")
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_nil
|
||||
end
|
||||
|
||||
@@ -178,7 +184,7 @@ RSpec.describe ExternalUploadManager do
|
||||
external_stub = ExternalUploadStub.find(external_upload_stub.id)
|
||||
expect(external_stub.status).to eq(ExternalUploadStub.statuses[:failed])
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_present
|
||||
end
|
||||
end
|
||||
@@ -218,7 +224,7 @@ RSpec.describe ExternalUploadManager do
|
||||
it "copies the stubbed upload on S3 to its new destination and deletes it" do
|
||||
upload = manager.transform!
|
||||
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_upload_bucket)
|
||||
expect(bucket.find_object(Discourse.store.get_path_for_upload(upload))).to be_present
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_nil
|
||||
end
|
||||
@@ -259,7 +265,7 @@ RSpec.describe ExternalUploadManager do
|
||||
end
|
||||
|
||||
it "copies the stubbed upload on S3 to its new destination and deletes it" do
|
||||
bucket = @fake_s3.bucket(SiteSetting.s3_backup_bucket)
|
||||
bucket = fake_s3.bucket(SiteSetting.s3_backup_bucket)
|
||||
expect(bucket.find_object(external_upload_stub.key)).to be_present
|
||||
|
||||
manager.transform!
|
||||
@@ -283,15 +289,4 @@ RSpec.describe ExternalUploadManager do
|
||||
body: object_file.read,
|
||||
)
|
||||
end
|
||||
|
||||
def prepare_fake_s3
|
||||
@fake_s3 = FakeS3.create
|
||||
|
||||
@fake_s3.bucket(s3_bucket_name).put_object(
|
||||
key: external_upload_stub.key,
|
||||
size: object_size,
|
||||
last_modified: Time.zone.now,
|
||||
metadata: external_upload_stub_metadata,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
@@ -319,10 +319,9 @@ RSpec.describe UserDestroyer do
|
||||
|
||||
context "when user has posts with links" do
|
||||
context "with external links" do
|
||||
before do
|
||||
@post = Fabricate(:post_with_external_links, user: user)
|
||||
TopicLink.extract_from(@post)
|
||||
end
|
||||
let(:post) { Fabricate(:post_with_external_links, user: user) }
|
||||
|
||||
before { TopicLink.extract_from(post) }
|
||||
|
||||
it "doesn't add ScreenedUrl records by default" do
|
||||
ScreenedUrl.expects(:watch).never
|
||||
@@ -336,9 +335,10 @@ RSpec.describe UserDestroyer do
|
||||
end
|
||||
|
||||
context "with internal links" do
|
||||
let(:post) { Fabricate(:post_with_external_links, user: user) }
|
||||
|
||||
before do
|
||||
@post = Fabricate(:post_with_external_links, user: user)
|
||||
TopicLink.extract_from(@post)
|
||||
TopicLink.extract_from(post)
|
||||
TopicLink.where(user: user).update_all(internal: true)
|
||||
end
|
||||
|
||||
@@ -349,10 +349,9 @@ RSpec.describe UserDestroyer do
|
||||
end
|
||||
|
||||
context "with oneboxed links" do
|
||||
before do
|
||||
@post = Fabricate(:post_with_youtube, user: user)
|
||||
TopicLink.extract_from(@post)
|
||||
end
|
||||
let(:post) { Fabricate(:post_with_youtube, user: user) }
|
||||
|
||||
before { TopicLink.extract_from(post) }
|
||||
|
||||
it "doesn't add ScreenedUrl records" do
|
||||
ScreenedUrl.expects(:watch).never
|
||||
@@ -415,17 +414,16 @@ RSpec.describe UserDestroyer do
|
||||
end
|
||||
|
||||
context "when user liked things" do
|
||||
before do
|
||||
@topic = Fabricate(:topic, user: Fabricate(:user))
|
||||
@post = Fabricate(:post, user: @topic.user, topic: @topic)
|
||||
PostActionCreator.like(user, @post)
|
||||
end
|
||||
let!(:topic) { Fabricate(:topic, user: Fabricate(:user)) }
|
||||
let!(:post) { Fabricate(:post, user: topic.user, topic: topic) }
|
||||
|
||||
before { PostActionCreator.like(user, post) }
|
||||
|
||||
it "should destroy the like" do
|
||||
expect { UserDestroyer.new(admin).destroy(user, delete_posts: true) }.to change {
|
||||
PostAction.count
|
||||
}.by(-1)
|
||||
expect(@post.reload.like_count).to eq(0)
|
||||
expect(post.reload.like_count).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
|
@@ -69,16 +69,16 @@ RSpec.describe UserSilencer do
|
||||
end
|
||||
|
||||
context "with a plugin hook" do
|
||||
before do
|
||||
@override_silence_message = ->(opts) do
|
||||
let(:override_silence_message) do
|
||||
->(opts) do
|
||||
opts[:silence_message_params][:message_title] = "override title"
|
||||
opts[:silence_message_params][:message_raw] = "override raw"
|
||||
end
|
||||
|
||||
DiscourseEvent.on(:user_silenced, &@override_silence_message)
|
||||
end
|
||||
|
||||
after { DiscourseEvent.off(:user_silenced, &@override_silence_message) }
|
||||
before { DiscourseEvent.on(:user_silenced, &override_silence_message) }
|
||||
|
||||
after { DiscourseEvent.off(:user_silenced, &override_silence_message) }
|
||||
|
||||
it "allows the message to be overridden" do
|
||||
UserSilencer.silence(user, admin)
|
||||
|
@@ -12,12 +12,13 @@ RSpec.describe UsernameChanger do
|
||||
it "should change the username" do
|
||||
new_username = "#{user.username}1234"
|
||||
|
||||
result = nil
|
||||
events =
|
||||
DiscourseEvent
|
||||
.track_events { @result = UsernameChanger.change(user, new_username) }
|
||||
.track_events { result = UsernameChanger.change(user, new_username) }
|
||||
.last(2)
|
||||
|
||||
expect(@result).to eq(true)
|
||||
expect(result).to eq(true)
|
||||
|
||||
event = events.first
|
||||
expect(event[:event_name]).to eq(:username_changed)
|
||||
@@ -36,10 +37,10 @@ RSpec.describe UsernameChanger do
|
||||
it "do nothing if the new username is the same" do
|
||||
new_username = user.username
|
||||
|
||||
events =
|
||||
DiscourseEvent.track_events { @result = UsernameChanger.change(user, new_username) }
|
||||
result = nil
|
||||
events = DiscourseEvent.track_events { result = UsernameChanger.change(user, new_username) }
|
||||
|
||||
expect(@result).to eq(false)
|
||||
expect(result).to eq(false)
|
||||
expect(events.count).to be_zero
|
||||
end
|
||||
end
|
||||
@@ -50,8 +51,7 @@ RSpec.describe UsernameChanger do
|
||||
let(:username_lower_before_change) { user.username_lower }
|
||||
|
||||
it "should not change the username" do
|
||||
@result = UsernameChanger.change(user, wrong_username)
|
||||
expect(@result).to eq(false)
|
||||
expect(UsernameChanger.change(user, wrong_username)).to eq(false)
|
||||
|
||||
user.reload
|
||||
expect(user.username).to eq(username_before_change)
|
||||
@@ -82,18 +82,17 @@ RSpec.describe UsernameChanger do
|
||||
end
|
||||
|
||||
describe "allow custom minimum username length from site settings" do
|
||||
before do
|
||||
@custom_min = 2
|
||||
SiteSetting.min_username_length = @custom_min
|
||||
end
|
||||
let(:custom_min) { 2 }
|
||||
|
||||
before { SiteSetting.min_username_length = custom_min }
|
||||
|
||||
it "should allow a shorter username than default" do
|
||||
result = UsernameChanger.change(user, "a" * @custom_min)
|
||||
result = UsernameChanger.change(user, "a" * custom_min)
|
||||
expect(result).not_to eq(false)
|
||||
end
|
||||
|
||||
it "should not allow a shorter username than limit" do
|
||||
result = UsernameChanger.change(user, "a" * (@custom_min - 1))
|
||||
result = UsernameChanger.change(user, "a" * (custom_min - 1))
|
||||
expect(result).to eq(false)
|
||||
end
|
||||
|
||||
|
@@ -2,30 +2,27 @@
|
||||
|
||||
RSpec.describe UsernameCheckerService do
|
||||
describe "#check_username" do
|
||||
before do
|
||||
@service = UsernameCheckerService.new
|
||||
@nil_email = nil
|
||||
@email = "vincentvega@example.com"
|
||||
end
|
||||
let(:service) { UsernameCheckerService.new }
|
||||
let(:email) { nil }
|
||||
|
||||
context "when username is invalid" do
|
||||
it "rejects too short usernames" do
|
||||
result = @service.check_username("a", @nil_email)
|
||||
result = service.check_username("a", email)
|
||||
expect(result).to have_key(:errors)
|
||||
end
|
||||
|
||||
it "rejects too long usernames" do
|
||||
result = @service.check_username("a123456789b123456789c123456789", @nil_email)
|
||||
result = service.check_username("a123456789b123456789c123456789", email)
|
||||
expect(result).to have_key(:errors)
|
||||
end
|
||||
|
||||
it "rejects usernames with invalid characters" do
|
||||
result = @service.check_username("vincent-", @nil_email)
|
||||
result = service.check_username("vincent-", email)
|
||||
expect(result).to have_key(:errors)
|
||||
end
|
||||
|
||||
it "rejects usernames that do not start with an alphanumeric character" do
|
||||
result = @service.check_username(".vincent", @nil_email)
|
||||
result = service.check_username(".vincent", email)
|
||||
expect(result).to have_key(:errors)
|
||||
end
|
||||
|
||||
@@ -33,13 +30,13 @@ RSpec.describe UsernameCheckerService do
|
||||
before { SiteSetting.reserved_usernames = "test|donkey" }
|
||||
|
||||
it "rejects usernames that are reserved" do
|
||||
result = @service.check_username("test", @nil_email)
|
||||
result = service.check_username("test", email)
|
||||
expect(result[:available]).to eq(false)
|
||||
end
|
||||
|
||||
it "allows reserved username checker to be skipped" do
|
||||
@service = UsernameCheckerService.new(allow_reserved_username: true)
|
||||
result = @service.check_username("test", @nil_email)
|
||||
service = UsernameCheckerService.new(allow_reserved_username: true)
|
||||
result = service.check_username("test", email)
|
||||
expect(result[:available]).to eq(true)
|
||||
end
|
||||
end
|
||||
@@ -48,14 +45,14 @@ RSpec.describe UsernameCheckerService do
|
||||
it "username not available locally" do
|
||||
User.stubs(:username_available?).returns(false)
|
||||
UserNameSuggester.stubs(:suggest).returns("einar-j")
|
||||
result = @service.check_username("vincent", @nil_email)
|
||||
result = service.check_username("vincent", email)
|
||||
expect(result[:available]).to eq(false)
|
||||
expect(result[:suggestion]).to eq("einar-j")
|
||||
end
|
||||
|
||||
it "username available locally" do
|
||||
User.stubs(:username_available?).returns(true)
|
||||
result = @service.check_username("vincent", @nil_email)
|
||||
result = service.check_username("vincent", email)
|
||||
expect(result[:available]).to eq(true)
|
||||
end
|
||||
end
|
||||
|
@@ -71,16 +71,15 @@ shared_examples "forgot password scenarios" do
|
||||
end
|
||||
|
||||
context "when user only has security key configured" do
|
||||
before do
|
||||
@authenticator =
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
|
||||
create_user_security_key(user)
|
||||
let!(:authenticator) do
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
end
|
||||
|
||||
after { @authenticator.remove! }
|
||||
before { create_user_security_key(user) }
|
||||
|
||||
after { authenticator.remove! }
|
||||
|
||||
it "should allow a user to reset password with a security key" do
|
||||
visit_reset_password_link
|
||||
@@ -116,16 +115,15 @@ shared_examples "forgot password scenarios" do
|
||||
context "when user has security key and backup codes configured" do
|
||||
fab!(:user_second_factor_backup) { Fabricate(:user_second_factor_backup, user:) }
|
||||
|
||||
before do
|
||||
@authenticator =
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
|
||||
create_user_security_key(user)
|
||||
let!(:authenticator) do
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
end
|
||||
|
||||
after { @authenticator.remove! }
|
||||
before { create_user_security_key(user) }
|
||||
|
||||
after { authenticator.remove! }
|
||||
|
||||
it "should allow a user to reset password with backup code instead of security key" do
|
||||
visit_reset_password_link
|
||||
@@ -148,16 +146,15 @@ shared_examples "forgot password scenarios" do
|
||||
fab!(:user_second_factor_totp) { Fabricate(:user_second_factor_totp, user:) }
|
||||
fab!(:user_second_factor_backup) { Fabricate(:user_second_factor_backup, user:) }
|
||||
|
||||
before do
|
||||
@authenticator =
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
|
||||
create_user_security_key(user)
|
||||
let!(:authenticator) do
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
end
|
||||
|
||||
after { @authenticator.remove! }
|
||||
before { create_user_security_key(user) }
|
||||
|
||||
after { authenticator.remove! }
|
||||
|
||||
it "should allow a user to toggle from security key to TOTP and between TOTP and backup codes" do
|
||||
visit_reset_password_link
|
||||
@@ -179,16 +176,15 @@ shared_examples "forgot password scenarios" do
|
||||
context "when user has TOTP and security key configured but no backup codes" do
|
||||
fab!(:user_second_factor_totp) { Fabricate(:user_second_factor_totp, user:) }
|
||||
|
||||
before do
|
||||
@authenticator =
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
|
||||
create_user_security_key(user)
|
||||
let!(:authenticator) do
|
||||
page.driver.browser.add_virtual_authenticator(
|
||||
Selenium::WebDriver::VirtualAuthenticatorOptions.new,
|
||||
)
|
||||
end
|
||||
|
||||
after { @authenticator.remove! }
|
||||
before { create_user_security_key(user) }
|
||||
|
||||
after { authenticator.remove! }
|
||||
|
||||
it "should allow a user to reset password with TOTP instead of security key" do
|
||||
visit_reset_password_link
|
||||
|
Reference in New Issue
Block a user