From 6c15effca2bf8421c6d9c36e4c6f1f0657d78ac4 Mon Sep 17 00:00:00 2001 From: Kris Date: Thu, 31 May 2018 18:11:24 -0400 Subject: [PATCH 0001/1439] envelope missing on invite page, long pre lines making modals wide --- app/assets/stylesheets/common/base/login.scss | 10 +++++++--- app/assets/stylesheets/common/base/modal.scss | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/common/base/login.scss b/app/assets/stylesheets/common/base/login.scss index 022030d4fa..683406cfef 100644 --- a/app/assets/stylesheets/common/base/login.scss +++ b/app/assets/stylesheets/common/base/login.scss @@ -114,12 +114,16 @@ $input-width: 220px; .invites-show { .two-col { position: relative; + display: flex; } .col-image { - position: absolute; - top: 0; - left: 0; + position: relative; + width: 150px; + margin-right: 20px; + @media screen and (max-width: 600px) { + display: none; + } } form { diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index 1b93f1b99a..da6cf2519c 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -274,6 +274,10 @@ .modal-body.forgot-password-modal p { font-size: $font-0; } + + pre code { + white-space: pre-wrap; + } } .reply-where-modal { From ba7aff62db500aa1df2b1f0ae98094650e2b7cc7 Mon Sep 17 00:00:00 2001 From: Kris Date: Thu, 31 May 2018 18:19:27 -0400 Subject: [PATCH 0002/1439] safety so pre blocks can't break modal width --- app/assets/stylesheets/common/base/modal.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index da6cf2519c..ce3ff6ca87 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -277,6 +277,7 @@ pre code { white-space: pre-wrap; + max-width: 700px; } } From 1a55948525d96b864bd774806b6a5a1e64039c4d Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 31 May 2018 18:29:10 -0400 Subject: [PATCH 0003/1439] Version bump to v2.1.0.beta1 --- lib/version.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/version.rb b/lib/version.rb index aeed4d4aa9..187efbb7c9 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -3,9 +3,9 @@ module Discourse unless defined? ::Discourse::VERSION module VERSION #:nodoc: MAJOR = 2 - MINOR = 0 + MINOR = 1 TINY = 0 - PRE = 'beta10' + PRE = 'beta1' STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end From 7750b30016fd1d045583bfc58d72c1698b5d5b22 Mon Sep 17 00:00:00 2001 From: Blake Erickson Date: Thu, 31 May 2018 17:10:52 -0600 Subject: [PATCH 0004/1439] FIX: Allow a user to remove their title Somewhere there was a regression and a user couldn't remove their own title. If they selected '(none)' in the UI it would say it was saved, but it would not actually be updated in the db. --- lib/guardian.rb | 1 + spec/components/guardian_spec.rb | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/lib/guardian.rb b/lib/guardian.rb index baa26363aa..528a190ff7 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -222,6 +222,7 @@ class Guardian def can_grant_title?(user, title = nil) return true if user && is_staff? return false if title.nil? + return true if title.empty? # A title set to '(none)' in the UI is an empty string return false if user != @user return true if user.badges.where(name: title, allow_title: true).exists? user.groups.where(title: title).exists? diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb index d849d583f5..5b29ff6f43 100644 --- a/spec/components/guardian_spec.rb +++ b/spec/components/guardian_spec.rb @@ -2243,6 +2243,10 @@ describe Guardian do it "returns false if title is from a group the user doesn't belong to" do expect(Guardian.new(user).can_grant_title?(user, group.title)).to eq(false) end + + it "returns true if the title is set to an empty string" do + expect(Guardian.new(user).can_grant_title?(user, '')).to eq(true) + end end end From 50be06af4735332499b922cbed4a1e5e314bc8af Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 1 Jun 2018 08:18:59 +0800 Subject: [PATCH 0005/1439] Remove stale code. --- config/environments/test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index 7a6f94612a..b7d3900e16 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -63,7 +63,6 @@ Discourse::Application.configure do s.set_regardless_of_locale(:crawl_images, false) s.set_regardless_of_locale(:download_remote_images_to_local, false) s.set_regardless_of_locale(:unique_posts_mins, 0) - s.set_regardless_of_locale(:queue_jobs, false) # disable plugins if ENV['LOAD_PLUGINS'] == '1' s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false) From 9ef61e0af56af430c28deb93b45e7633eaa863a4 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 1 Jun 2018 09:44:14 +0800 Subject: [PATCH 0006/1439] PERF: Prefer `exists?` instead of loading AR object. --- app/models/topic.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/topic.rb b/app/models/topic.rb index 78cc39584e..d179b12ee8 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -655,7 +655,7 @@ SQL end def changed_to_category(new_category) - return true if new_category.blank? || Category.find_by(topic_id: id).present? + return true if new_category.blank? || Category.exists?(topic_id: id) return false if new_category.id == SiteSetting.uncategorized_category_id && !SiteSetting.allow_uncategorized_topics Topic.transaction do From 560a950da9c78a479866f990e13c34fc997065a8 Mon Sep 17 00:00:00 2001 From: Joe <33972521+hnb-ku@users.noreply.github.com> Date: Fri, 1 Jun 2018 09:51:46 +0800 Subject: [PATCH 0007/1439] FIX: alignment for instructions on change email and 2FA fields --- app/assets/stylesheets/desktop/user.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index 92fedb9c39..3a031554b3 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -292,7 +292,7 @@ } .form-horizontal .instructions { - margin-left: 160px; + margin-left: 8px; } .pref-mailing-list-mode .controls { From 12a0f1253087c36119ba4e788d2b1d5fe5630058 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 1 Jun 2018 11:24:32 +0800 Subject: [PATCH 0008/1439] Fix the build. --- config/environments/test.rb | 3 +++ spec/rails_helper.rb | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/config/environments/test.rb b/config/environments/test.rb index b7d3900e16..df30b744fb 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -63,6 +63,9 @@ Discourse::Application.configure do s.set_regardless_of_locale(:crawl_images, false) s.set_regardless_of_locale(:download_remote_images_to_local, false) s.set_regardless_of_locale(:unique_posts_mins, 0) + # Running jobs are expensive and most of our tests are not concern with + # code that runs inside jobs + s.set_regardless_of_locale(:queue_jobs, true) # disable plugins if ENV['LOAD_PLUGINS'] == '1' s.set_regardless_of_locale(:discourse_narrative_bot_enabled, false) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index f86eb06bc6..fd977925cd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -158,10 +158,6 @@ RSpec.configure do |config| # very expensive IO operations SiteSetting.automatically_download_gravatars = false - # Running jobs are expensive and most of our tests are not concern with - # code that runs inside jobs - SiteSetting.queue_jobs = true - Discourse.clear_readonly! Sidekiq::Worker.clear_all From d57a5d3e8c62e763ce7f76a9d42ef5814bd5623a Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 1 Jun 2018 11:56:56 +0800 Subject: [PATCH 0009/1439] Fix brittle spec. --- spec/models/user_profile_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/models/user_profile_spec.rb b/spec/models/user_profile_spec.rb index ee05902c3e..98545ffabe 100644 --- a/spec/models/user_profile_spec.rb +++ b/spec/models/user_profile_spec.rb @@ -114,19 +114,19 @@ describe UserProfile do describe 'bio excerpt emojis' do let(:user) { Fabricate(:user) } + let(:upload) { Fabricate(:upload) } before do - CustomEmoji.create!(name: 'test', upload_id: 1) + CustomEmoji.create!(name: 'test', upload: upload) Emoji.clear_cache - user.user_profile.bio_raw = "hello :test: :woman_scientist:t5: 🤔" - user.user_profile.save - user.user_profile.reload + user.user_profile.update!( + bio_raw: "hello :test: :woman_scientist:t5: 🤔" + ) end it 'supports emoji images' do - - expect(user.user_profile.bio_excerpt(500, keep_emoji_images: true)).to eq("hello \":test:\" \":woman_scientist:t5:\" \":thinking:\"") + expect(user.user_profile.bio_excerpt(500, keep_emoji_images: true)).to eq("hello \":test:\" \":woman_scientist:t5:\" \":thinking:\"") end end From 474ff94df3c6dda7f8b12628c62985c7f9f2db27 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Fri, 1 Jun 2018 08:06:08 +0300 Subject: [PATCH 0010/1439] REFACTOR: convert invites controller specs to requests (#5898) REFACTOR: convert invites controller specs to requests --- spec/controllers/invites_controller_spec.rb | 396 -------------------- spec/requests/invites_controller_spec.rb | 382 ++++++++++++++++++- 2 files changed, 381 insertions(+), 397 deletions(-) delete mode 100644 spec/controllers/invites_controller_spec.rb diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb deleted file mode 100644 index 6433a2de7f..0000000000 --- a/spec/controllers/invites_controller_spec.rb +++ /dev/null @@ -1,396 +0,0 @@ -require 'rails_helper' - -describe InvitesController do - - context '.destroy' do - - it 'requires you to be logged in' do - delete :destroy, - params: { email: 'jake@adventuretime.ooo' }, - format: :json - expect(response.status).to eq(403) - end - - context 'while logged in' do - let!(:user) { log_in } - let!(:invite) { Fabricate(:invite, invited_by: user) } - let(:another_invite) { Fabricate(:invite, email: 'anotheremail@address.com') } - - it 'raises an error when the email is missing' do - expect { delete :destroy, format: :json }.to raise_error(ActionController::ParameterMissing) - end - - it "raises an error when the email cannot be found" do - delete :destroy, params: { email: 'finn@adventuretime.ooo' }, format: :json - expect(response.status).to eq(400) - end - - it 'raises an error when the invite is not yours' do - delete :destroy, params: { email: another_invite.email }, format: :json - expect(response.status).to eq(400) - end - - it "destroys the invite" do - Invite.any_instance.expects(:trash!).with(user) - delete :destroy, params: { email: invite.email }, format: :json - end - - end - - end - - context '#create' do - it 'requires you to be logged in' do - post :create, params: { email: 'jake@adventuretime.ooo' }, format: :json - expect(response.status).to eq(403) - end - - context 'while logged in' do - let(:email) { 'jake@adventuretime.ooo' } - - it "fails if you can't invite to the forum" do - log_in - post :create, params: { email: email }, format: :json - expect(response).not_to be_success - end - - it "fails for normal user if invite email already exists" do - user = log_in(:trust_level_4) - invite = Invite.invite_by_email("invite@example.com", user) - invite.reload - post :create, params: { email: invite.email }, format: :json - expect(response).not_to be_success - json = JSON.parse(response.body) - expect(json["failed"]).to be_present - end - - it "allows admins to invite to groups" do - group = Fabricate(:group) - log_in(:admin) - post :create, params: { email: email, group_names: group.name }, format: :json - expect(response).to be_success - expect(Invite.find_by(email: email).invited_groups.count).to eq(1) - end - - it 'allows group owners to invite to groups' do - group = Fabricate(:group) - user = log_in - user.update!(trust_level: TrustLevel[2]) - group.add_owner(user) - - post :create, params: { email: email, group_names: group.name }, format: :json - - expect(response).to be_success - expect(Invite.find_by(email: email).invited_groups.count).to eq(1) - end - - it "allows admin to send multiple invites to same email" do - user = log_in(:admin) - invite = Invite.invite_by_email("invite@example.com", user) - invite.reload - post :create, params: { email: invite.email }, format: :json - expect(response).to be_success - end - - it "responds with error message in case of validation failure" do - log_in(:admin) - post :create, params: { email: "test@mailinator.com" }, format: :json - expect(response).not_to be_success - json = JSON.parse(response.body) - expect(json["errors"]).to be_present - end - end - - end - - context '.create_invite_link' do - it 'requires you to be logged in' do - post :create_invite_link, params: { - email: 'jake@adventuretime.ooo' - }, format: :json - expect(response.status).to eq(403) - end - - context 'while logged in' do - let(:email) { 'jake@adventuretime.ooo' } - - it "fails if you can't invite to the forum" do - log_in - post :create_invite_link, params: { email: email }, format: :json - expect(response).not_to be_success - end - - it "fails for normal user if invite email already exists" do - user = log_in(:trust_level_4) - invite = Invite.invite_by_email("invite@example.com", user) - invite.reload - - post :create_invite_link, params: { - email: invite.email - }, format: :json - - expect(response).not_to be_success - end - - it "verifies that inviter is authorized to invite new user to a group-private topic" do - group = Fabricate(:group) - private_category = Fabricate(:private_category, group: group) - group_private_topic = Fabricate(:topic, category: private_category) - log_in(:trust_level_4) - - post :create_invite_link, params: { - email: email, topic_id: group_private_topic.id - }, format: :json - - expect(response).not_to be_success - end - - it "allows admins to invite to groups" do - group = Fabricate(:group) - log_in(:admin) - - post :create_invite_link, params: { - email: email, group_names: group.name - }, format: :json - - expect(response).to be_success - expect(Invite.find_by(email: email).invited_groups.count).to eq(1) - end - - it "allows multiple group invite" do - Fabricate(:group, name: "security") - Fabricate(:group, name: "support") - log_in(:admin) - - post :create_invite_link, params: { - email: email, group_names: "security,support" - }, format: :json - - expect(response).to be_success - expect(Invite.find_by(email: email).invited_groups.count).to eq(2) - end - end - end - - context '.perform_accept_invitation' do - - context 'with an invalid invite id' do - before do - put :perform_accept_invitation, params: { id: "doesn't exist" }, format: :json - end - - it "redirects to the root" do - expect(response).to be_success - json = JSON.parse(response.body) - expect(json["success"]).to eq(false) - expect(json["message"]).to eq(I18n.t('invite.not_found')) - end - - it "should not change the session" do - expect(session[:current_user_id]).to be_blank - end - end - - context 'with a deleted invite' do - let(:topic) { Fabricate(:topic) } - let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } - let(:deleted_invite) { invite.destroy; invite } - before do - put :perform_accept_invitation, params: { id: deleted_invite.invite_key }, format: :json - end - - it "redirects to the root" do - expect(response).to be_success - json = JSON.parse(response.body) - expect(json["success"]).to eq(false) - expect(json["message"]).to eq(I18n.t('invite.not_found')) - end - - it "should not change the session" do - expect(session[:current_user_id]).to be_blank - end - end - - context 'with a valid invite id' do - let(:topic) { Fabricate(:topic) } - let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } - - it 'redeems the invite' do - Invite.any_instance.expects(:redeem) - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - - context 'when redeem returns a user' do - let(:user) { Fabricate(:coding_horror) } - - context 'success' do - subject { put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json } - - before do - Invite.any_instance.expects(:redeem).returns(user) - end - - it 'logs in the user' do - events = DiscourseEvent.track_events { subject } - - expect(events.map { |event| event[:event_name] }).to include( - :user_logged_in, :user_first_logged_in - ) - - expect(session[:current_user_id]).to eq(user.id) - end - - it 'redirects to the first topic the user was invited to' do - subject - json = JSON.parse(response.body) - expect(json["success"]).to eq(true) - expect(json["redirect_to"]).to eq(topic.relative_url) - end - end - - context 'failure' do - subject { put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json } - - it "doesn't log in the user if there's a validation error" do - user.errors.add(:password, :common) - Invite.any_instance.expects(:redeem).raises(ActiveRecord::RecordInvalid.new(user)) - subject - expect(response).to be_success - json = JSON.parse(response.body) - expect(json["success"]).to eq(false) - expect(json["errors"]["password"]).to be_present - end - end - - context '.post_process_invite' do - before do - Invite.any_instance.stubs(:redeem).returns(user) - Jobs.expects(:enqueue).with(:invite_email, has_key(:invite_id)) - user.password_hash = nil - end - - it 'sends a welcome message if set' do - user.send_welcome_message = true - user.expects(:enqueue_welcome_message).with('welcome_invite') - Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_entries(username: user.username)) - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - - it "sends password reset email if password is not set" do - user.expects(:enqueue_welcome_message).with('welcome_invite').never - Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_entries(username: user.username)) - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - - it "does not send password reset email if sso is enabled" do - SiteSetting.sso_url = "https://www.example.com/sso" - SiteSetting.enable_sso = true - Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username)).never - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - - it "does not send password reset email if local login is disabled" do - SiteSetting.enable_local_logins = false - Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username)).never - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - - it 'sends an activation email if password is set' do - user.password_hash = 'qaw3ni3h2wyr63lakw7pea1nrtr44pls' - Jobs.expects(:enqueue).with(:invite_password_instructions_email, has_key(:username)).never - Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup, user_id: user.id)) - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - end - end - end - - context 'new registrations are disabled' do - let(:topic) { Fabricate(:topic) } - let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } - before { SiteSetting.allow_new_registrations = false } - - it "doesn't redeem the invite" do - Invite.any_instance.stubs(:redeem).never - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - end - - context 'user is already logged in' do - let!(:user) { log_in } - let(:topic) { Fabricate(:topic) } - let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } - - it "doesn't redeem the invite" do - Invite.any_instance.stubs(:redeem).never - put :perform_accept_invitation, params: { id: invite.invite_key }, format: :json - end - end - end - - context '.resend_invite' do - - it 'requires you to be logged in' do - delete :resend_invite, params: { email: 'first_name@example.com' }, format: :json - expect(response.status).to eq(403) - end - - context 'while logged in' do - let!(:user) { log_in } - let!(:invite) { Fabricate(:invite, invited_by: user) } - let(:another_invite) { Fabricate(:invite, email: 'last_name@example.com') } - - it 'raises an error when the email is missing' do - expect { post :resend_invite, format: :json }.to raise_error(ActionController::ParameterMissing) - end - - it "raises an error when the email cannot be found" do - post :resend_invite, params: { email: 'first_name@example.com' }, format: :json - expect(response.status).to eq(400) - end - - it 'raises an error when the invite is not yours' do - post :resend_invite, params: { email: another_invite.email }, format: :json - expect(response.status).to eq(400) - end - - it "resends the invite" do - Invite.any_instance.expects(:resend_invite) - post :resend_invite, params: { email: invite.email }, format: :json - end - - end - - end - - context '.upload_csv' do - it 'requires you to be logged in' do - post :upload_csv, format: :json - expect(response.status).to eq(403) - end - - context 'while logged in' do - let(:csv_file) { File.new("#{Rails.root}/spec/fixtures/csv/discourse.csv") } - - let(:file) do - Rack::Test::UploadedFile.new(File.open(csv_file)) - end - - let(:filename) { 'discourse.csv' } - - it "fails if you can't bulk invite to the forum" do - log_in - post :upload_csv, params: { file: file, name: filename }, format: :json - expect(response).not_to be_success - end - - it "allows admin to bulk invite" do - log_in(:admin) - post :upload_csv, params: { file: file, name: filename }, format: :json - expect(response).to be_success - end - end - - end - -end diff --git a/spec/requests/invites_controller_spec.rb b/spec/requests/invites_controller_spec.rb index 4f622c196a..05deb5a832 100644 --- a/spec/requests/invites_controller_spec.rb +++ b/spec/requests/invites_controller_spec.rb @@ -1,7 +1,6 @@ require 'rails_helper' describe InvitesController do - context 'show' do let(:invite) { Fabricate(:invite) } let(:user) { Fabricate(:coding_horror) } @@ -37,4 +36,385 @@ describe InvitesController do expect(CGI.unescapeHTML(body)).to include(I18n.t('invite.not_found_template', site_name: SiteSetting.title, base_url: Discourse.base_url)) end end + + context '#destroy' do + it 'requires you to be logged in' do + delete "/invites.json", + params: { email: 'jake@adventuretime.ooo' } + expect(response.status).to eq(403) + end + + context 'while logged in' do + let!(:user) { sign_in(Fabricate(:user)) } + let!(:invite) { Fabricate(:invite, invited_by: user) } + let(:another_invite) { Fabricate(:invite, email: 'anotheremail@address.com') } + + it 'raises an error when the email is missing' do + delete "/invites.json" + expect(response.status).to eq(400) + end + + it "raises an error when the email cannot be found" do + delete "/invites.json", params: { email: 'finn@adventuretime.ooo' } + expect(response.status).to eq(400) + end + + it 'raises an error when the invite is not yours' do + delete "/invites.json", params: { email: another_invite.email } + expect(response.status).to eq(400) + end + + it "destroys the invite" do + delete "/invites.json", params: { email: invite.email } + invite.reload + expect(invite.trashed?).to be_truthy + end + end + end + + context '#create' do + it 'requires you to be logged in' do + post "/invites.json", params: { email: 'jake@adventuretime.ooo' } + expect(response.status).to eq(403) + end + + context 'while logged in' do + let(:email) { 'jake@adventuretime.ooo' } + + it "fails if you can't invite to the forum" do + sign_in(Fabricate(:user)) + post "/invites.json", params: { email: email } + expect(response).to be_forbidden + end + + it "fails for normal user if invite email already exists" do + user = sign_in(Fabricate(:trust_level_4)) + invite = Invite.invite_by_email("invite@example.com", user) + post "/invites.json", params: { email: invite.email } + expect(response.status).to eq(422) + json = JSON.parse(response.body) + expect(json["failed"]).to be_present + end + + it "allows admins to invite to groups" do + group = Fabricate(:group) + sign_in(Fabricate(:admin)) + post "/invites.json", params: { email: email, group_names: group.name } + expect(response).to be_success + expect(Invite.find_by(email: email).invited_groups.count).to eq(1) + end + + it 'allows group owners to invite to groups' do + group = Fabricate(:group) + user = sign_in(Fabricate(:user)) + user.update!(trust_level: TrustLevel[2]) + group.add_owner(user) + + post "/invites.json", params: { email: email, group_names: group.name } + + expect(response).to be_success + expect(Invite.find_by(email: email).invited_groups.count).to eq(1) + end + + it "allows admin to send multiple invites to same email" do + user = sign_in(Fabricate(:admin)) + invite = Invite.invite_by_email("invite@example.com", user) + post "/invites.json", params: { email: invite.email } + expect(response).to be_success + end + + it "responds with error message in case of validation failure" do + sign_in(Fabricate(:admin)) + post "/invites.json", params: { email: "test@mailinator.com" } + expect(response.status).to eq(422) + json = JSON.parse(response.body) + expect(json["errors"]).to be_present + end + end + end + + context '#create_invite_link' do + it 'requires you to be logged in' do + post "/invites/link.json", params: { + email: 'jake@adventuretime.ooo' + } + expect(response.status).to eq(403) + end + + context 'while logged in' do + let(:email) { 'jake@adventuretime.ooo' } + + it "fails if you can't invite to the forum" do + sign_in(Fabricate(:user)) + post "/invites/link.json", params: { email: email } + expect(response).to be_forbidden + end + + it "fails for normal user if invite email already exists" do + user = sign_in(Fabricate(:trust_level_4)) + invite = Invite.invite_by_email("invite@example.com", user) + + post "/invites/link.json", params: { + email: invite.email + } + + expect(response.status).to eq(422) + end + + it "verifies that inviter is authorized to invite new user to a group-private topic" do + group = Fabricate(:group) + private_category = Fabricate(:private_category, group: group) + group_private_topic = Fabricate(:topic, category: private_category) + sign_in(Fabricate(:trust_level_4)) + + post "/invites/link.json", params: { + email: email, topic_id: group_private_topic.id + } + + expect(response).to be_forbidden + end + + it "allows admins to invite to groups" do + group = Fabricate(:group) + sign_in(Fabricate(:admin)) + + post "/invites/link.json", params: { + email: email, group_names: group.name + } + + expect(response).to be_success + expect(Invite.find_by(email: email).invited_groups.count).to eq(1) + end + + it "allows multiple group invite" do + Fabricate(:group, name: "security") + Fabricate(:group, name: "support") + sign_in(Fabricate(:admin)) + + post "/invites/link.json", params: { + email: email, group_names: "security,support" + } + + expect(response).to be_success + expect(Invite.find_by(email: email).invited_groups.count).to eq(2) + end + end + end + + context '#perform_accept_invitation' do + context 'with an invalid invite id' do + it "redirects to the root and doesn't change the session" do + put "/invites/show/doesntexist.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["success"]).to eq(false) + expect(json["message"]).to eq(I18n.t('invite.not_found')) + expect(session[:current_user_id]).to be_blank + end + end + + context 'with a deleted invite' do + let(:topic) { Fabricate(:topic) } + let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } + before do + invite.destroy + end + + it "redirects to the root" do + put "/invites/show/#{invite.invite_key}.json" + + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["success"]).to eq(false) + expect(json["message"]).to eq(I18n.t('invite.not_found')) + expect(session[:current_user_id]).to be_blank + end + end + + context 'with a valid invite id' do + let(:topic) { Fabricate(:topic) } + let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } + + it 'redeems the invite' do + put "/invites/show/#{invite.invite_key}.json" + invite.reload + expect(invite.redeemed?).to be_truthy + end + + context 'when redeem returns a user' do + let(:user) { Fabricate(:coding_horror) } + + context 'success' do + it 'logs in the user' do + events = DiscourseEvent.track_events do + put "/invites/show/#{invite.invite_key}.json" + end + + expect(events.map { |event| event[:event_name] }).to include( + :user_logged_in, :user_first_logged_in + ) + invite.reload + expect(response).to be_success + expect(session[:current_user_id]).to eq(invite.user_id) + expect(invite.redeemed?).to be_truthy + end + + it 'redirects to the first topic the user was invited to' do + put "/invites/show/#{invite.invite_key}.json" + expect(response.status).to eq(200) + json = JSON.parse(response.body) + expect(json["success"]).to eq(true) + expect(json["redirect_to"]).to eq(topic.relative_url) + end + end + + context 'failure' do + it "doesn't log in the user if there's a validation error" do + put "/invites/show/#{invite.invite_key}.json", params: { password: "password" } + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["success"]).to eq(false) + expect(json["errors"]["password"]).to be_present + end + end + + context '.post_process_invite' do + before do + SiteSetting.queue_jobs = true + end + + it 'sends a welcome message if set' do + user.send_welcome_message = true + put "/invites/show/#{invite.invite_key}.json" + expect(response).to be_success + expect(Jobs::SendSystemMessage.jobs.size).to eq(1) + end + + it "sends password reset email if password is not set" do + put "/invites/show/#{invite.invite_key}.json" + expect(response).to be_success + expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(1) + end + + it "does not send password reset email if sso is enabled" do + SiteSetting.sso_url = "https://www.example.com/sso" + SiteSetting.enable_sso = true + put "/invites/show/#{invite.invite_key}.json" + expect(response).to be_success + expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) + end + + it "does not send password reset email if local login is disabled" do + SiteSetting.enable_local_logins = false + put "/invites/show/#{invite.invite_key}.json" + expect(response).to be_success + expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) + end + + it 'sends an activation email if password is set' do + put "/invites/show/#{invite.invite_key}.json", params: { password: "verystrongpassword" } + expect(response).to be_success + expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) + expect(Jobs::CriticalUserEmail.jobs.size).to eq(1) + end + end + end + end + + context 'new registrations are disabled' do + let(:topic) { Fabricate(:topic) } + let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } + before { SiteSetting.allow_new_registrations = false } + + it "doesn't redeem the invite" do + put "/invites/show/#{invite.invite_key}.json" + expect(response.status).to eq(200) + invite.reload + expect(invite.user_id).to be_blank + expect(invite.redeemed?).to be_falsey + expect(response.body).to include(I18n.t("login.new_registrations_disabled")) + end + end + + context 'user is already logged in' do + let(:topic) { Fabricate(:topic) } + let(:invite) { topic.invite_by_email(topic.user, "iceking@adventuretime.ooo") } + let!(:user) { sign_in(Fabricate(:user)) } + + it "doesn't redeem the invite" do + put "/invites/show/#{invite.invite_key}.json", params: { id: invite.invite_key } + expect(response.status).to eq(200) + invite.reload + expect(invite.user_id).to be_blank + expect(invite.redeemed?).to be_falsey + expect(response.body).to include(I18n.t("login.already_logged_in", current_user: user.username)) + end + end + end + + context '#resend_invite' do + it 'requires you to be logged in' do + post "/invites/reinvite.json", params: { email: 'first_name@example.com' } + expect(response.status).to eq(403) + end + + context 'while logged in' do + let!(:user) { sign_in(Fabricate(:user)) } + let!(:invite) { Fabricate(:invite, invited_by: user) } + let(:another_invite) { Fabricate(:invite, email: 'last_name@example.com') } + + it 'raises an error when the email is missing' do + post "/invites/reinvite.json" + expect(response.status).to eq(400) + end + + it "raises an error when the email cannot be found" do + post "/invites/reinvite.json", params: { email: 'first_name@example.com' } + expect(response.status).to eq(400) + end + + it 'raises an error when the invite is not yours' do + post "/invites/reinvite.json", params: { email: another_invite.email } + expect(response.status).to eq(400) + end + + it "resends the invite" do + SiteSetting.queue_jobs = true + post "/invites/reinvite.json", params: { email: invite.email } + expect(response).to be_success + expect(Jobs::InviteEmail.jobs.size).to eq(1) + end + end + end + + context '#upload_csv' do + it 'requires you to be logged in' do + post "/invites/upload_csv.json" + expect(response.status).to eq(403) + end + + context 'while logged in' do + let(:csv_file) { File.new("#{Rails.root}/spec/fixtures/csv/discourse.csv") } + + let(:file) do + Rack::Test::UploadedFile.new(File.open(csv_file)) + end + + let(:filename) { 'discourse.csv' } + + it "fails if you can't bulk invite to the forum" do + sign_in(Fabricate(:user)) + post "/invites/upload_csv.json", params: { file: file, name: filename } + expect(response.status).to eq(403) + end + + it "allows admin to bulk invite" do + SiteSetting.queue_jobs = true + sign_in(Fabricate(:admin)) + post "/invites/upload_csv.json", params: { file: file, name: filename } + expect(response).to be_success + expect(Jobs::BulkInvite.jobs.size).to eq(1) + end + end + end end From 313ff264f2524bac4383a004bf575b461405b9c7 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Fri, 1 Jun 2018 14:20:41 +0530 Subject: [PATCH 0011/1439] use generic example domain --- lib/tasks/import.rake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index 15458e27cc..ad291fd96a 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -454,12 +454,11 @@ task "import:remap_old_phpbb_permalinks" => :environment do log 'Remapping Permalinks...' i = 0 - # discussions.flightaware.com - Post.where("raw LIKE ?", "%discussions.flightaware.com%").each do |p| + Post.where("raw LIKE ?", "%discussions.example.com%").each do |p| begin new_raw = p.raw.dup - # \((https?:\/\/discussions\.flightaware\.com\/\S*-t\d+.html)\) - new_raw.gsub!(/\((https?:\/\/discussions\.flightaware\.com\/\S*-t\d+.html)\)/) do + # \((https?:\/\/discussions\.example\.com\/\S*-t\d+.html)\) + new_raw.gsub!(/\((https?:\/\/discussions\.example\.com\/\S*-t\d+.html)\)/) do normalized_url = Permalink.normalize_url($1) permalink = Permalink.find_by_url(normalized_url) rescue nil if permalink && permalink.target_url From b970b072f6a5ab877f8174ec81f1513527596ce6 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Fri, 1 Jun 2018 16:23:21 +0200 Subject: [PATCH 0012/1439] FIX: User merge should not fail when primary email address is missing The merge process might move all email addresses of the source user to the target user. Destroying the source user failed in that case. --- app/services/user_merger.rb | 6 +++++- spec/services/user_merger_spec.rb | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/services/user_merger.rb b/app/services/user_merger.rb index d745bc0e7c..c8e8cc530e 100644 --- a/app/services/user_merger.rb +++ b/app/services/user_merger.rb @@ -347,7 +347,11 @@ class UserMerger def delete_source_user @source_user.reload - @source_user.update_attribute(:admin, false) + @source_user.update_attributes( + admin: false, + email: "#{@source_user.username}_#{SecureRandom.hex}@no-email.invalid" + ) + UserDestroyer.new(Discourse.system_user).destroy(@source_user) end diff --git a/spec/services/user_merger_spec.rb b/spec/services/user_merger_spec.rb index 2d81ad8e3b..6306291138 100644 --- a/spec/services/user_merger_spec.rb +++ b/spec/services/user_merger_spec.rb @@ -953,6 +953,15 @@ describe UserMerger do expect(User.find_by_username(source_user.username)).to be_nil end + it "deletes the source user even when it is a member of a group that grants a trust level" do + group = Fabricate(:group, grant_trust_level: 3) + group.bulk_add([source_user.id, target_user.id]) + + merge_users! + + expect(User.find_by_username(source_user.username)).to be_nil + end + it "deletes external auth infos of source user" do FacebookUserInfo.create(user_id: source_user.id, facebook_user_id: "example") GithubUserInfo.create(user_id: source_user.id, screen_name: "example", github_user_id: "examplel123123") From c0bab84dc11421226ca36649f69e299cdba988f9 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Fri, 1 Jun 2018 17:34:19 +0200 Subject: [PATCH 0013/1439] Fix random build error Spec usually failed when there was an UpdateGravatar job for the system user. --- spec/jobs/jobs_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/jobs/jobs_spec.rb b/spec/jobs/jobs_spec.rb index 9f49d3d5b6..01cbe6a225 100644 --- a/spec/jobs/jobs_spec.rb +++ b/spec/jobs/jobs_spec.rb @@ -77,6 +77,7 @@ describe Jobs do it 'deletes the matching job' do Sidekiq::Testing.disable! do + scheduled_jobs.clear expect(scheduled_jobs.size).to eq(0) Jobs.enqueue_in(1.year, :run_heartbeat, topic_id: 123) From 725859ba43d69a4e6ded33df947d79f77f09a081 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 1 Jun 2018 23:42:47 +0800 Subject: [PATCH 0014/1439] DEV: Test discourse-group-track plugin on travis. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 16ccc5722b..8924dce113 100644 --- a/.travis.yml +++ b/.travis.yml @@ -55,6 +55,7 @@ before_install: - git clone --depth=1 https://github.com/discourse/discourse-assign.git plugins/discourse-assign - git clone --depth=1 https://github.com/discourse/discourse-patreon.git plugins/discourse-patreon - git clone --depth=1 https://github.com/discourse/discourse-staff-notes.git plugins/discourse-staff-notes + - git clone --depth=1 https://github.com/discourse/discourse-group-tracker - export PATH=$HOME/.yarn/bin:$PATH install: From 41999b9949206c4ca3c743f00f73c732c4176f04 Mon Sep 17 00:00:00 2001 From: Kris Date: Fri, 1 Jun 2018 11:59:29 -0400 Subject: [PATCH 0015/1439] Limiting history modal height and width --- app/assets/stylesheets/common/base/modal.scss | 7 ++++--- app/assets/stylesheets/desktop/history.scss | 4 +++- app/assets/stylesheets/mobile/history.scss | 9 +++++++++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss index ce3ff6ca87..60c411eb57 100644 --- a/app/assets/stylesheets/common/base/modal.scss +++ b/app/assets/stylesheets/common/base/modal.scss @@ -130,9 +130,10 @@ height: 100%; z-index: z("modal","content"); overflow: auto; - - .modal-body { - max-height: none !important; + &:not(.history-modal) { + .modal-body { + max-height: none !important; + } } } diff --git a/app/assets/stylesheets/desktop/history.scss b/app/assets/stylesheets/desktop/history.scss index 3192d0b9b2..36af336c15 100644 --- a/app/assets/stylesheets/desktop/history.scss +++ b/app/assets/stylesheets/desktop/history.scss @@ -3,9 +3,11 @@ .modal.history-modal { .modal-inner-container { - min-height: 500px; max-width: 960px; } + .modal-body { + height: 70vh; + } #revision-controls { .btn[disabled] { cursor: not-allowed; diff --git a/app/assets/stylesheets/mobile/history.scss b/app/assets/stylesheets/mobile/history.scss index bae7149be0..cdcbd44d2e 100644 --- a/app/assets/stylesheets/mobile/history.scss +++ b/app/assets/stylesheets/mobile/history.scss @@ -2,6 +2,15 @@ button { float: none; } + .modal-body { + height: 62vh; + } + .modal-inner-container { + min-height: 400px; + } + #revisions { + max-width: 90vw; + } #display-modes { display: none; } From 89eca87f167bd20e670bf3c7dbaa090a52b40eb3 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Fri, 1 Jun 2018 19:42:31 +0530 Subject: [PATCH 0016/1439] FEATURE: add staff action log for post rejections --- app/models/queued_post.rb | 1 + app/models/user_history.rb | 2 ++ app/services/staff_action_logger.rb | 22 ++++++++++++++++++++++ config/locales/client.en.yml | 1 + spec/models/queued_post_spec.rb | 3 +++ spec/services/staff_action_logger_spec.rb | 18 ++++++++++++++++++ 6 files changed, 47 insertions(+) diff --git a/app/models/queued_post.rb b/app/models/queued_post.rb index b91d3af3de..fb4a390f7f 100644 --- a/app/models/queued_post.rb +++ b/app/models/queued_post.rb @@ -47,6 +47,7 @@ class QueuedPost < ActiveRecord::Base def reject!(rejected_by) change_to!(:rejected, rejected_by) + StaffActionLogger.new(rejected_by).log_post_rejected(self) DiscourseEvent.trigger(:rejected_post, self) end diff --git a/app/models/user_history.rb b/app/models/user_history.rb index f500d83179..c02e73f9af 100644 --- a/app/models/user_history.rb +++ b/app/models/user_history.rb @@ -80,6 +80,7 @@ class UserHistory < ActiveRecord::Base removed_suspend_user: 61, removed_unsilence_user: 62, removed_unsuspend_user: 63, + post_rejected: 64 ) end @@ -138,6 +139,7 @@ class UserHistory < ActiveRecord::Base :create_badge, :change_badge, :delete_badge, + :post_rejected ] end diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb index 07a47a4c48..38c1b90598 100644 --- a/app/services/staff_action_logger.rb +++ b/app/services/staff_action_logger.rb @@ -526,6 +526,28 @@ class StaffActionLogger )) end + def log_post_rejected(rejected_post, opts = {}) + raise Discourse::InvalidParameters.new(:rejected_post) unless rejected_post && rejected_post.is_a?(QueuedPost) + + topic = rejected_post.topic || Topic.with_deleted.find_by(id: rejected_post.topic_id) + topic_title = topic&.title || "not found" + username = rejected_post.user&.username || "unknown" + name = rejected_post.user&.name || "unknown" + + details = [ + "created_at: #{rejected_post.created_at}", + "rejected_at: #{rejected_post.rejected_at}", + "user: #{username} (#{name})", + "topic: #{topic_title}", + "raw: #{rejected_post.raw}", + ] + + UserHistory.create!(params(opts).merge( + action: UserHistory.actions[:post_rejected], + details: details.join("\n") + )) + end + private def params(opts = nil) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index e433e46f12..a1713ce316 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3406,6 +3406,7 @@ en: disabled_second_factor: "disable Two Factor Authentication" topic_published: "topic published" post_approved: "post approved" + post_rejected: "post rejected" create_badge: "create badge" change_badge: "change badge" delete_badge: "delete badge" diff --git a/spec/models/queued_post_spec.rb b/spec/models/queued_post_spec.rb index b6e5113efe..22e7331d83 100644 --- a/spec/models/queued_post_spec.rb +++ b/spec/models/queued_post_spec.rb @@ -86,6 +86,9 @@ describe QueuedPost do # It removes the pending action expect(UserAction.where(queued_post_id: qp.id).count).to eq(0) + # Logs staff action log for rejected post + expect(UserHistory.where(action: UserHistory.actions[:post_rejected]).count).to eq(1) + # We can't reject twice expect(-> { qp.reject!(admin) }).to raise_error(QueuedPost::InvalidStateTransition) end diff --git a/spec/services/staff_action_logger_spec.rb b/spec/services/staff_action_logger_spec.rb index 70132a7a51..bc72628558 100644 --- a/spec/services/staff_action_logger_spec.rb +++ b/spec/services/staff_action_logger_spec.rb @@ -488,4 +488,22 @@ describe StaffActionLogger do expect { log_post_approved }.to change { UserHistory.count }.by(1) end end + + describe 'log_post_rejected' do + let(:rejected_post) { Fabricate(:queued_post) } + + subject(:log_post_rejected) { described_class.new(admin).log_post_rejected(rejected_post) } + + it 'raises an error when post is nil' do + expect { logger.log_post_rejected(nil) }.to raise_error(Discourse::InvalidParameters) + end + + it 'raises an error when post is not a QueuedPosts' do + expect { logger.log_post_rejected(1) }.to raise_error(Discourse::InvalidParameters) + end + + it 'creates a new UserHistory record' do + expect { log_post_rejected }.to change { UserHistory.count }.by(1) + end + end end From 597ffd7e3ff1d1c40768f73eeb74be68883df70d Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 1 Jun 2018 14:38:09 -0400 Subject: [PATCH 0017/1439] FIX: Keyboard shortcuts didn't work on subfolders --- app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 index 6a1ddbdf9f..6568814501 100644 --- a/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 +++ b/app/assets/javascripts/discourse/lib/keyboard-shortcuts.js.es6 @@ -279,7 +279,7 @@ export default { }, _bindToPath(path, key) { - this.keyTrapper.bind(key, () => DiscourseURL.routeTo(path)); + this.keyTrapper.bind(key, () => DiscourseURL.routeTo(Discourse.BaseUri + path)); }, _bindToClick(selector, binding) { From 36f9af4fa46013dde8dffb47167db37d4a417aac Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Sat, 2 Jun 2018 09:25:41 +0530 Subject: [PATCH 0018/1439] minor optimizations for post rejected logs --- app/services/staff_action_logger.rb | 12 ++++++------ config/locales/server.en.yml | 4 ++++ spec/models/queued_post_spec.rb | 6 ++++-- spec/services/staff_action_logger_spec.rb | 3 +++ 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb index 38c1b90598..f9205e075e 100644 --- a/app/services/staff_action_logger.rb +++ b/app/services/staff_action_logger.rb @@ -46,9 +46,9 @@ class StaffActionLogger topic = deleted_post.topic || Topic.with_deleted.find_by(id: deleted_post.topic_id) - username = deleted_post.user.try(:username) || "unknown" - name = deleted_post.user.try(:name) || "unknown" - topic_title = topic.try(:title) || "not found" + username = deleted_post.user.try(:username) || I18n.t('staff_action_logs.unknown') + name = deleted_post.user.try(:name) || I18n.t('staff_action_logs.unknown') + topic_title = topic.try(:title) || I18n.t('staff_action_logs.not_found') details = [ "id: #{deleted_post.id}", @@ -530,9 +530,9 @@ class StaffActionLogger raise Discourse::InvalidParameters.new(:rejected_post) unless rejected_post && rejected_post.is_a?(QueuedPost) topic = rejected_post.topic || Topic.with_deleted.find_by(id: rejected_post.topic_id) - topic_title = topic&.title || "not found" - username = rejected_post.user&.username || "unknown" - name = rejected_post.user&.name || "unknown" + topic_title = topic&.title || I18n.t('staff_action_logs.not_found') + username = rejected_post.user&.username || I18n.t('staff_action_logs.unknown') + name = rejected_post.user&.name || I18n.t('staff_action_logs.unknown') details = [ "created_at: #{rejected_post.created_at}", diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 43d12c2588..4d10b61b92 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -3881,3 +3881,7 @@ en: linked: '%{username} linked to your post from "%{topic}" - %{site_title}' confirm_title: 'Notifications enabled - %{site_title}' confirm_body: 'Success! Notifications have been enabled.' + + staff_action_logs: + not_found: "not found" + unknown: "unknown" diff --git a/spec/models/queued_post_spec.rb b/spec/models/queued_post_spec.rb index 22e7331d83..5616ef41a0 100644 --- a/spec/models/queued_post_spec.rb +++ b/spec/models/queued_post_spec.rb @@ -86,8 +86,10 @@ describe QueuedPost do # It removes the pending action expect(UserAction.where(queued_post_id: qp.id).count).to eq(0) - # Logs staff action log for rejected post - expect(UserHistory.where(action: UserHistory.actions[:post_rejected]).count).to eq(1) + # Logs staff action for rejected post + post_rejected_logs = UserHistory.where(action: UserHistory.actions[:post_rejected]) + expect(post_rejected_logs.count).to eq(1) + expect(post_rejected_logs.first.details).to include(qp.raw) # We can't reject twice expect(-> { qp.reject!(admin) }).to raise_error(QueuedPost::InvalidStateTransition) diff --git a/spec/services/staff_action_logger_spec.rb b/spec/services/staff_action_logger_spec.rb index bc72628558..56c8a81c36 100644 --- a/spec/services/staff_action_logger_spec.rb +++ b/spec/services/staff_action_logger_spec.rb @@ -504,6 +504,9 @@ describe StaffActionLogger do it 'creates a new UserHistory record' do expect { log_post_rejected }.to change { UserHistory.count }.by(1) + user_history = UserHistory.last + expect(user_history.action).to eq(UserHistory.actions[:post_rejected]) + expect(user_history.details).to include(rejected_post.raw) end end end From 9b4a98695ed7422289e37b4e0dd6b68d74894106 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 06:09:59 +0300 Subject: [PATCH 0019/1439] REFACTOR: list controller specs to requests (#5902) --- spec/controllers/list_controller_spec.rb | 410 ----------------------- spec/requests/list_controller_spec.rb | 368 +++++++++++++++++++- 2 files changed, 367 insertions(+), 411 deletions(-) delete mode 100644 spec/controllers/list_controller_spec.rb diff --git a/spec/controllers/list_controller_spec.rb b/spec/controllers/list_controller_spec.rb deleted file mode 100644 index 1f1374c5c9..0000000000 --- a/spec/controllers/list_controller_spec.rb +++ /dev/null @@ -1,410 +0,0 @@ -require 'rails_helper' - -describe ListController do - - # we need some data - before do - @user = Fabricate(:coding_horror) - @post = Fabricate(:post, user: @user) - - SiteSetting.top_menu = 'latest|new|unread|categories' - end - - describe 'indexes' do - - (Discourse.anonymous_filters - [:categories]).each do |filter| - context "#{filter}" do - before { get filter } - it { is_expected.to respond_with(:success) } - end - end - - it 'allows users to filter on a set of topic ids' do - p = create_post - - get :latest, format: :json, params: { topic_ids: "#{p.topic_id}" } - expect(response).to be_success - parsed = JSON.parse(response.body) - expect(parsed["topic_list"]["topics"].length).to eq(1) - end - end - - describe 'RSS feeds' do - it 'renders latest RSS' do - get "latest_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders top RSS' do - get "top_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders all time top RSS' do - get "top_all_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders yearly top RSS' do - get "top_yearly_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders quarterly top RSS' do - get "top_quarterly_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders monthly top RSS' do - get "top_monthly_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders weekly top RSS' do - get "top_weekly_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - - it 'renders daily top RSS' do - get "top_daily_feed", format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - end - - context 'category' do - - context 'in a category' do - let(:category) { Fabricate(:category) } - - context 'without access to see the category' do - before do - Guardian.any_instance.expects(:can_see?).with(category).returns(false) - get :category_latest, params: { category: category.slug } - end - - it { is_expected.not_to respond_with(:success) } - end - - context 'with access to see the category' do - before do - get :category_latest, params: { category: category.slug } - end - - it { is_expected.to respond_with(:success) } - end - - context 'with a link that includes an id' do - before do - get :category_latest, params: { - category: "#{category.id}-#{category.slug}" - } - end - - it { is_expected.to respond_with(:success) } - end - - context 'with a link that has a parent slug, slug and id in its path' do - let(:child_category) { Fabricate(:category, parent_category: category) } - - context "with valid slug" do - before do - get :category_latest, params: { - parent_category: category.slug, - category: child_category.slug, - id: child_category.id - } - end - - it { is_expected.to redirect_to(child_category.url) } - end - - context "with invalid slug" do - before do - get :category_latest, params: { - parent_category: 'random slug', - category: 'random slug', - id: child_category.id - } - end - - it { is_expected.to redirect_to(child_category.url) } - end - end - - context 'another category exists with a number at the beginning of its name' do - # One category has another category's id at the beginning of its name - let!(:other_category) { Fabricate(:category, name: "#{category.id} name") } - - it 'uses the correct category' do - get :category_latest, - params: { category: other_category.slug }, - format: :json - - expect(response).to be_success - - body = JSON.parse(response.body) - - expect(body["topic_list"]["topics"].first["category_id"]) - .to eq(other_category.id) - end - end - - context 'a child category' do - let(:sub_category) { Fabricate(:category, parent_category_id: category.id) } - - context 'when parent and child are requested' do - before do - get :category_latest, params: { - parent_category: category.slug, category: sub_category.slug - } - end - - it { is_expected.to respond_with(:success) } - end - - context 'when child is requested with the wrong parent' do - before do - get :category_latest, params: { - parent_category: 'not_the_right_slug', category: sub_category.slug - } - end - - it { is_expected.not_to respond_with(:success) } - end - end - - describe 'feed' do - it 'renders RSS' do - get :category_feed, params: { category: category.slug }, format: :rss - expect(response).to be_success - expect(response.content_type).to eq('application/rss+xml') - end - end - - describe "category default views" do - it "has a top default view" do - category.update_attributes!(default_view: 'top', default_top_period: 'monthly') - described_class.expects(:best_period_with_topics_for).with(anything, category.id, :monthly).returns(:monthly) - get :category_default, params: { category: category.slug } - expect(response).to be_success - end - - it "has a default view of nil" do - category.update_attributes!(default_view: nil) - described_class.expects(:best_period_for).never - get :category_default, params: { category: category.slug } - expect(response).to be_success - end - - it "has a default view of ''" do - category.update_attributes!(default_view: '') - described_class.expects(:best_period_for).never - get :category_default, params: { category: category.slug } - expect(response).to be_success - end - - it "has a default view of latest" do - category.update_attributes!(default_view: 'latest') - described_class.expects(:best_period_for).never - get :category_default, params: { category: category.slug } - expect(response).to be_success - end - end - - describe "renders canonical tag" do - render_views - - it 'for category default view' do - get :category_default, params: { category: category.slug } - expect(response).to be_success - expect(css_select("link[rel=canonical]").length).to eq(1) - end - - it 'for category latest view' do - get :category_latest, params: { category: category.slug } - expect(response).to be_success - expect(css_select("link[rel=canonical]").length).to eq(1) - end - end - end - end - - describe "topics_by" do - let!(:user) { log_in } - - it "should respond with a list" do - get :topics_by, params: { username: @user.username } - expect(response).to be_success - end - end - - context "private_messages" do - let!(:user) { log_in } - - it "raises an error when can_see_private_messages? is false " do - Guardian.any_instance.expects(:can_see_private_messages?).returns(false) - get :private_messages, params: { username: @user.username } - expect(response).to be_forbidden - end - - it "succeeds when can_see_private_messages? is false " do - Guardian.any_instance.expects(:can_see_private_messages?).returns(true) - get :private_messages, params: { username: @user.username } - expect(response).to be_success - end - end - - context "private_messages_sent" do - let!(:user) { log_in } - - it "raises an error when can_see_private_messages? is false " do - Guardian.any_instance.expects(:can_see_private_messages?).returns(false) - get :private_messages_sent, params: { username: @user.username } - expect(response).to be_forbidden - end - - it "succeeds when can_see_private_messages? is false " do - Guardian.any_instance.expects(:can_see_private_messages?).returns(true) - get :private_messages_sent, params: { username: @user.username } - expect(response).to be_success - end - end - - context "private_messages_unread" do - let!(:user) { log_in } - - it "raises an error when can_see_private_messages? is false " do - Guardian.any_instance.expects(:can_see_private_messages?).returns(false) - get :private_messages_unread, params: { username: @user.username } - expect(response).to be_forbidden - end - - it "succeeds when can_see_private_messages? is false " do - Guardian.any_instance.expects(:can_see_private_messages?).returns(true) - get :private_messages_unread, params: { username: @user.username } - expect(response).to be_success - end - end - - context 'read' do - it 'raises an error when not logged in' do - get :read - expect(response.status).to eq(404) - end - - context 'when logged in' do - before do - log_in_user(@user) - get :read - end - - it { is_expected.to respond_with(:success) } - end - end - - describe "best_periods_for" do - - it "returns yearly for more than 180 days" do - expect(ListController.best_periods_for(nil, :all)).to eq([:yearly]) - expect(ListController.best_periods_for(180.days.ago, :all)).to eq([:yearly]) - end - - it "includes monthly when less than 180 days and more than 35 days" do - (35...180).each do |date| - expect(ListController.best_periods_for(date.days.ago, :all)).to eq([:monthly, :yearly]) - end - end - - it "includes weekly when less than 35 days and more than 8 days" do - (8...35).each do |date| - expect(ListController.best_periods_for(date.days.ago, :all)).to eq([:weekly, :monthly, :yearly]) - end - end - - it "includes daily when less than 8 days" do - (0...8).each do |date| - expect(ListController.best_periods_for(date.days.ago, :all)).to eq([:daily, :weekly, :monthly, :yearly]) - end - end - - it "returns default even for more than 180 days" do - expect(ListController.best_periods_for(nil, :monthly)).to eq([:monthly, :yearly]) - expect(ListController.best_periods_for(180.days.ago, :monthly)).to eq([:monthly, :yearly]) - end - - it "returns default even when less than 180 days and more than 35 days" do - (35...180).each do |date| - expect(ListController.best_periods_for(date.days.ago, :weekly)).to eq([:weekly, :monthly, :yearly]) - end - end - - it "returns default even when less than 35 days and more than 8 days" do - (8...35).each do |date| - expect(ListController.best_periods_for(date.days.ago, :daily)).to eq([:daily, :weekly, :monthly, :yearly]) - end - end - - it "doesn't return default when set to all" do - expect(ListController.best_periods_for(nil, :all)).to eq([:yearly]) - end - - it "doesn't return value twice when matches default" do - expect(ListController.best_periods_for(nil, :yearly)).to eq([:yearly]) - end - end - - describe "categories suppression" do - let(:category_one) { Fabricate(:category) } - let(:sub_category) { Fabricate(:category, parent_category: category_one, suppress_from_latest: true) } - let!(:topic_in_sub_category) { Fabricate(:topic, category: sub_category) } - - let(:category_two) { Fabricate(:category, suppress_from_latest: true) } - let!(:topic_in_category_two) { Fabricate(:topic, category: category_two) } - - it "suppresses categories from the latest list" do - get SiteSetting.homepage, format: :json - expect(response).to be_success - - topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } - expect(topic_titles).not_to include(topic_in_sub_category.title, topic_in_category_two.title) - end - - it "does not suppress" do - get SiteSetting.homepage, params: { category: category_one.id }, format: :json - expect(response).to be_success - - topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } - expect(topic_titles).to include(topic_in_sub_category.title) - end - - end - - describe "safe mode" do - render_views - - it "handles safe mode" do - get :latest - expect(response.body).to match(/plugin\.js/) - expect(response.body).to match(/plugin-third-party\.js/) - - get :latest, params: { safe_mode: "no_plugins" } - expect(response.body).not_to match(/plugin\.js/) - expect(response.body).not_to match(/plugin-third-party\.js/) - - get :latest, params: { safe_mode: "only_official" } - expect(response.body).to match(/plugin\.js/) - expect(response.body).not_to match(/plugin-third-party\.js/) - - end - - end - -end diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index 288d49cd29..5910aa3c57 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -1,8 +1,14 @@ require 'rails_helper' RSpec.describe ListController do - let(:topic) { Fabricate(:topic) } + let(:topic) { Fabricate(:topic, user: user) } let(:group) { Fabricate(:group) } + let(:user) { Fabricate(:user) } + let(:post) { Fabricate(:post, user: user) } + + before do + SiteSetting.top_menu = 'latest|new|unread|categories' + end describe '#index' do it "doesn't throw an error with a negative page" do @@ -14,6 +20,24 @@ RSpec.describe ListController do get "/#{Discourse.anonymous_filters[1]}", params: { page: ['7'] } expect(response).to be_success end + + (Discourse.anonymous_filters - [:categories]).each do |filter| + context "#{filter}" do + it "succeeds" do + get "/#{filter}" + expect(response).to be_success + end + end + end + + it 'allows users to filter on a set of topic ids' do + p = create_post + + get "/latest.json", params: { topic_ids: "#{p.topic_id}" } + expect(response).to be_success + parsed = JSON.parse(response.body) + expect(parsed["topic_list"]["topics"].length).to eq(1) + end end describe "categories and X" do @@ -210,4 +234,346 @@ RSpec.describe ListController do end end end + + describe 'RSS feeds' do + it 'renders latest RSS' do + get "/latest.rss" + expect(response).to be_success + expect(response.content_type).to eq('application/rss+xml') + end + + it 'renders top RSS' do + get "/top.rss" + expect(response).to be_success + expect(response.content_type).to eq('application/rss+xml') + end + + TopTopic.periods.each do |period| + it "renders #{period} top RSS" do + get "/top/#{period}.rss" + expect(response).to be_success + expect(response.content_type).to eq('application/rss+xml') + end + end + end + + describe 'category' do + context 'in a category' do + let(:category) { Fabricate(:category) } + let(:group) { Fabricate(:group) } + let(:private_category) { Fabricate(:private_category, group: group) } + + context 'without access to see the category' do + it "responds with a 404 error" do + get "/c/#{private_category.slug}/l/latest" + expect(response.status).to eq(404) + end + end + + context 'with access to see the category' do + it "succeeds" do + get "/c/#{category.slug}/l/latest" + expect(response.status).to eq(200) + end + end + + context 'with a link that includes an id' do + it "succeeds" do + get "/c/#{category.id}-#{category.slug}/l/latest" + expect(response.status).to eq(200) + end + end + + context 'with a link that has a parent slug, slug and id in its path' do + let(:child_category) { Fabricate(:category, parent_category: category) } + + context "with valid slug" do + it "redirects to the child category" do + get "/c/#{category.slug}/#{child_category.slug}/l/latest", params: { + id: child_category.id + } + expect(response).to redirect_to(child_category.url) + end + end + + context "with invalid slug" do + it "redirects to child category" do + get "/c/random_slug/another_random_slug/l/latest", params: { + id: child_category.id + } + expect(response).to redirect_to(child_category.url) + end + end + end + + context 'another category exists with a number at the beginning of its name' do + # One category has another category's id at the beginning of its name + let!(:other_category) { Fabricate(:category, name: "#{category.id} name") } + + it 'uses the correct category' do + get "/c/#{other_category.slug}/l/latest.json" + expect(response).to be_success + body = JSON.parse(response.body) + expect(body["topic_list"]["topics"].first["category_id"]) + .to eq(other_category.id) + end + end + + context 'a child category' do + let(:sub_category) { Fabricate(:category, parent_category_id: category.id) } + + context 'when parent and child are requested' do + it "succeeds" do + get "/c/#{category.slug}/#{sub_category.slug}/l/latest" + expect(response.status).to eq(200) + end + end + + context 'when child is requested with the wrong parent' do + it "responds with a 404 error" do + get "/c/not-the-right-slug/#{sub_category.slug}/l/latest" + expect(response.status).to eq(404) + end + end + end + + describe 'feed' do + it 'renders RSS' do + get "/c/#{category.slug}.rss" + expect(response).to be_success + expect(response.content_type).to eq('application/rss+xml') + end + end + + describe "category default views" do + it "has a top default view" do + category.update_attributes!(default_view: 'top', default_top_period: 'monthly') + get "/c/#{category.slug}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["for_period"]).to eq("monthly") + end + + it "has a default view of nil" do + category.update_attributes!(default_view: nil) + get "/c/#{category.slug}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["for_period"]).to be_blank + end + + it "has a default view of ''" do + category.update_attributes!(default_view: '') + get "/c/#{category.slug}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["for_period"]).to be_blank + end + + it "has a default view of latest" do + category.update_attributes!(default_view: 'latest') + get "/c/#{category.slug}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["for_period"]).to be_blank + end + end + + describe "renders canonical tag" do + it 'for category default view' do + get "/c/#{category.slug}" + expect(response).to be_success + expect(css_select("link[rel=canonical]").length).to eq(1) + end + + it 'for category latest view' do + get "/c/#{category.slug}/l/latest" + expect(response).to be_success + expect(css_select("link[rel=canonical]").length).to eq(1) + end + end + end + end + + describe "topics_by" do + before do + sign_in(Fabricate(:user)) + Fabricate(:topic, user: user) + end + + it "should respond with a list" do + get "/topics/created-by/#{user.username}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["topics"].size).to eq(1) + end + end + + describe "private_messages" do + it "returns 403 error when the user can't see private message" do + sign_in(Fabricate(:user)) + get "/topics/private-messages/#{user.username}.json" + expect(response).to be_forbidden + end + + it "succeeds when the user can see private messages" do + pm = Fabricate(:private_message_topic, user: Fabricate(:user)) + pm.topic_allowed_users.create!(user: user) + sign_in(user) + get "/topics/private-messages/#{user.username}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["topics"].size).to eq(1) + end + end + + describe "private_messages_sent" do + before do + pm = Fabricate(:private_message_topic, user: user) + Fabricate(:post, user: user, topic: pm, post_number: 1) + end + + it "returns 403 error when the user can't see private message" do + sign_in(Fabricate(:user)) + get "/topics/private-messages-sent/#{user.username}.json" + expect(response).to be_forbidden + end + + it "succeeds when the user can see private messages" do + sign_in(user) + get "/topics/private-messages-sent/#{user.username}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["topics"].size).to eq(1) + end + end + + describe "private_messages_unread" do + before do + u = Fabricate(:user) + pm = Fabricate(:private_message_topic, user: u) + Fabricate(:post, user: u, topic: pm, post_number: 1) + pm.topic_allowed_users.create!(user: user) + end + + it "returns 403 error when the user can't see private message" do + sign_in(Fabricate(:user)) + get "/topics/private-messages-unread/#{user.username}.json" + expect(response).to be_forbidden + end + + it "succeeds when the user can see private messages" do + sign_in(user) + get "/topics/private-messages-unread/#{user.username}.json" + expect(response).to be_success + json = JSON.parse(response.body) + expect(json["topic_list"]["topics"].size).to eq(1) + end + end + + describe 'read' do + it 'raises an error when not logged in' do + get "/read" + expect(response.status).to eq(404) + end + + context 'when logged in' do + it "succeeds" do + sign_in(user) + get "/read" + expect(response).to be_success + end + end + end + + describe "best_periods_for" do + it "returns yearly for more than 180 days" do + expect(ListController.best_periods_for(nil, :all)).to eq([:yearly]) + expect(ListController.best_periods_for(180.days.ago, :all)).to eq([:yearly]) + end + + it "includes monthly when less than 180 days and more than 35 days" do + (35...180).each do |date| + expect(ListController.best_periods_for(date.days.ago, :all)).to eq([:monthly, :yearly]) + end + end + + it "includes weekly when less than 35 days and more than 8 days" do + (8...35).each do |date| + expect(ListController.best_periods_for(date.days.ago, :all)).to eq([:weekly, :monthly, :yearly]) + end + end + + it "includes daily when less than 8 days" do + (0...8).each do |date| + expect(ListController.best_periods_for(date.days.ago, :all)).to eq([:daily, :weekly, :monthly, :yearly]) + end + end + + it "returns default even for more than 180 days" do + expect(ListController.best_periods_for(nil, :monthly)).to eq([:monthly, :yearly]) + expect(ListController.best_periods_for(180.days.ago, :monthly)).to eq([:monthly, :yearly]) + end + + it "returns default even when less than 180 days and more than 35 days" do + (35...180).each do |date| + expect(ListController.best_periods_for(date.days.ago, :weekly)).to eq([:weekly, :monthly, :yearly]) + end + end + + it "returns default even when less than 35 days and more than 8 days" do + (8...35).each do |date| + expect(ListController.best_periods_for(date.days.ago, :daily)).to eq([:daily, :weekly, :monthly, :yearly]) + end + end + + it "doesn't return default when set to all" do + expect(ListController.best_periods_for(nil, :all)).to eq([:yearly]) + end + + it "doesn't return value twice when matches default" do + expect(ListController.best_periods_for(nil, :yearly)).to eq([:yearly]) + end + end + + describe "categories suppression" do + let(:category_one) { Fabricate(:category) } + let(:sub_category) { Fabricate(:category, parent_category: category_one, suppress_from_latest: true) } + let!(:topic_in_sub_category) { Fabricate(:topic, category: sub_category) } + + let(:category_two) { Fabricate(:category, suppress_from_latest: true) } + let!(:topic_in_category_two) { Fabricate(:topic, category: category_two) } + + it "suppresses categories from the latest list" do + get "/#{SiteSetting.homepage}.json" + expect(response).to be_success + + topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } + expect(topic_titles).not_to include(topic_in_sub_category.title, topic_in_category_two.title) + end + + it "does not suppress" do + get "/#{SiteSetting.homepage}.json", params: { category: category_one.id } + expect(response).to be_success + + topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } + expect(topic_titles).to include(topic_in_sub_category.title) + end + end + + describe "safe mode" do + it "handles safe mode" do + get "/latest" + expect(response.body).to match(/plugin\.js/) + expect(response.body).to match(/plugin-third-party\.js/) + + get "/latest", params: { safe_mode: "no_plugins" } + expect(response.body).not_to match(/plugin\.js/) + expect(response.body).not_to match(/plugin-third-party\.js/) + + get "/latest", params: { safe_mode: "only_official" } + expect(response.body).to match(/plugin\.js/) + expect(response.body).not_to match(/plugin-third-party\.js/) + end + end end From cfea837e8866e94ddb99ab3506e9132bcd4608e9 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 06:12:38 +0300 Subject: [PATCH 0020/1439] REFACTOR: search controller specs to requests (#5906) --- .../search_controller_spec.rb | 101 +++++++++--------- 1 file changed, 49 insertions(+), 52 deletions(-) rename spec/{controllers => requests}/search_controller_spec.rb (80%) diff --git a/spec/controllers/search_controller_spec.rb b/spec/requests/search_controller_spec.rb similarity index 80% rename from spec/controllers/search_controller_spec.rb rename to spec/requests/search_controller_spec.rb index f81f9ef937..fae6e362d7 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/requests/search_controller_spec.rb @@ -1,7 +1,6 @@ require 'rails_helper' describe SearchController do - context "integration" do before do SearchIndexer.enable @@ -10,9 +9,9 @@ describe SearchController do it "can search correctly" do my_post = Fabricate(:post, raw: 'this is my really awesome post') - get :query, params: { + get "/search/query.json", params: { term: 'awesome', include_blurb: true - }, format: :json + } expect(response).to be_success data = JSON.parse(response.body) @@ -25,9 +24,9 @@ describe SearchController do user = Fabricate(:user) my_post = Fabricate(:post, raw: "#{user.username} is a cool person") - get :query, params: { + get "/search/query.json", params: { term: user.username, type_filter: 'topic' - }, format: :json + } expect(response).to be_success data = JSON.parse(response.body) @@ -35,9 +34,9 @@ describe SearchController do expect(data['posts'][0]['id']).to eq(my_post.id) expect(data['users']).to be_blank - get :query, params: { + get "/search/query.json", params: { term: user.username, type_filter: 'user' - }, format: :json + } expect(response).to be_success data = JSON.parse(response.body) @@ -52,11 +51,11 @@ describe SearchController do post = Fabricate(:post) - get :query, params: { + get "/search/query.json", params: { term: post.topic_id, type_filter: 'topic', search_for_id: true - }, format: :json + } expect(response).to be_success data = JSON.parse(response.body) @@ -68,11 +67,11 @@ describe SearchController do user = Fabricate(:user) my_post = Fabricate(:post, raw: "#{user.username} is a cool person") - get :query, params: { + get "/search/query.json", params: { term: my_post.topic_id, type_filter: 'topic', search_for_id: true - }, format: :json + } expect(response).to be_success data = JSON.parse(response.body) @@ -85,7 +84,7 @@ describe SearchController do context "#query" do it "logs the search term" do SiteSetting.log_search_queries = true - get :query, params: { term: 'wookie' }, format: :json + get "/search/query.json", params: { term: 'wookie' } expect(response).to be_success expect(SearchLog.where(term: 'wookie')).to be_present @@ -101,7 +100,7 @@ describe SearchController do it "doesn't log when disabled" do SiteSetting.log_search_queries = false - get :query, params: { term: 'wookie' }, format: :json + get "/search/query.json", params: { term: 'wookie' } expect(response).to be_success expect(SearchLog.where(term: 'wookie')).to be_blank end @@ -110,14 +109,14 @@ describe SearchController do context "#show" do it "logs the search term" do SiteSetting.log_search_queries = true - get :show, params: { q: 'bantha' }, format: :json + get "/search.json", params: { q: 'bantha' } expect(response).to be_success expect(SearchLog.where(term: 'bantha')).to be_present end it "doesn't log when disabled" do SiteSetting.log_search_queries = false - get :show, params: { q: 'bantha' }, format: :json + get "/search.json", params: { q: 'bantha' } expect(response).to be_success expect(SearchLog.where(term: 'bantha')).to be_blank end @@ -125,16 +124,15 @@ describe SearchController do context "search context" do it "raises an error with an invalid context type" do - get :query, params: { + get "/search/query.json", params: { term: 'test', search_context: { type: 'security', id: 'hole' } - }, format: :json + } expect(response.status).to eq(400) end it "raises an error with a missing id" do - get :query, - params: { term: 'test', search_context: { type: 'user' } }, - format: :json + get "/search/query.json", + params: { term: 'test', search_context: { type: 'user' } } expect(response.status).to eq(400) end @@ -142,17 +140,16 @@ describe SearchController do let(:user) { Fabricate(:user) } it "raises an error if the user can't see the context" do - Guardian.any_instance.expects(:can_see?).with(user).returns(false) - get :query, params: { - term: 'test', search_context: { type: 'user', id: user.username } - }, format: :json - expect(response).not_to be_success + get "/search/query.json", params: { + term: 'test', search_context: { type: 'private_messages', id: user.username } + } + expect(response).to be_forbidden end it 'performs the query with a search context' do - get :query, params: { + get "/search/query.json", params: { term: 'test', search_context: { type: 'user', id: user.username } - }, format: :json + } expect(response).to be_success end @@ -166,13 +163,12 @@ describe SearchController do end it "doesn't work wthout the necessary parameters" do - expect do - post :click, format: :json - end.to raise_error(ActionController::ParameterMissing) + post "/search/click.json" + expect(response.status).to eq(400) end it "doesn't record the click for a different user" do - log_in(:user) + sign_in(Fabricate(:user)) _, search_log_id = SearchLog.log( term: 'kitty', @@ -181,7 +177,7 @@ describe SearchController do ip_address: '127.0.0.1' ) - post :click, params: { + post "/search/click", params: { search_log_id: search_log_id, search_result_id: 12345, search_result_type: 'topic' @@ -192,7 +188,7 @@ describe SearchController do end it "records the click for a logged in user" do - user = log_in(:user) + user = sign_in(Fabricate(:user)) _, search_log_id = SearchLog.log( term: 'foobar', @@ -201,11 +197,11 @@ describe SearchController do ip_address: '127.0.0.1' ) - post :click, params: { + post "/search/click.json", params: { search_log_id: search_log_id, search_result_id: 12345, search_result_type: 'user' - }, format: :json + } expect(response).to be_success expect(SearchLog.find(search_log_id).search_result_id).to eq(12345) @@ -213,19 +209,20 @@ describe SearchController do end it "records the click for an anonymous user" do - request.remote_addr = '192.168.0.1'; + get "/" + ip_address = request.remote_ip _, search_log_id = SearchLog.log( term: 'kitty', search_type: :header, - ip_address: '192.168.0.1' + ip_address: ip_address ) - post :click, params: { + post "/search/click.json", params: { search_log_id: search_log_id, search_result_id: 22222, search_result_type: 'topic' - }, format: :json + } expect(response).to be_success expect(SearchLog.find(search_log_id).search_result_id).to eq(22222) @@ -233,15 +230,13 @@ describe SearchController do end it "doesn't record the click for a different IP" do - request.stubs(:remote_ip).returns('192.168.0.2') - _, search_log_id = SearchLog.log( term: 'kitty', search_type: :header, - ip_address: '192.168.0.1' + ip_address: '192.168.0.19' ) - post :click, params: { + post "/search/click", params: { search_log_id: search_log_id, search_result_id: 22222, search_result_type: 'topic' @@ -252,19 +247,20 @@ describe SearchController do end it "records the click for search result type category" do - request.remote_addr = '192.168.0.1'; + get "/" + ip_address = request.remote_ip _, search_log_id = SearchLog.log( term: 'dev', search_type: :header, - ip_address: '192.168.0.1' + ip_address: ip_address ) - post :click, params: { + post "/search/click.json", params: { search_log_id: search_log_id, search_result_id: 23456, search_result_type: 'category' - }, format: :json + } expect(response).to be_success expect(SearchLog.find(search_log_id).search_result_id).to eq(23456) @@ -272,20 +268,21 @@ describe SearchController do end it "records the click for search result type tag" do - request.remote_addr = '192.168.0.1'; - tag = Fabricate(:tag, name: 'test') + get "/" + ip_address = request.remote_ip + tag = Fabricate(:tag, name: 'test') _, search_log_id = SearchLog.log( term: 'test', search_type: :header, - ip_address: '192.168.0.1' + ip_address: ip_address ) - post :click, params: { + post "/search/click.json", params: { search_log_id: search_log_id, search_result_id: tag.name, search_result_type: 'tag' - }, format: :json + } expect(response).to be_success expect(SearchLog.find(search_log_id).search_result_id).to eq(tag.id) From e58ed247f2ffce1c500ee52d214ca7627364c340 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 06:13:52 +0300 Subject: [PATCH 0021/1439] REFACTOR: uploads controller specs to requests (#5907) --- spec/fixtures/images/image_no_extension | Bin 0 -> 2297 bytes .../uploads_controller_spec.rb | 182 +++++++++--------- 2 files changed, 87 insertions(+), 95 deletions(-) create mode 100644 spec/fixtures/images/image_no_extension rename spec/{controllers => requests}/uploads_controller_spec.rb (50%) diff --git a/spec/fixtures/images/image_no_extension b/spec/fixtures/images/image_no_extension new file mode 100644 index 0000000000000000000000000000000000000000..5c900b61f70312ad23e30265c92dca79feba84b4 GIT binary patch literal 2297 zcmb7_`9IT-1IOR)Na)gxVMifyQ?6_|HrFT%Ni0`Oj>6=~(P%5|L*>Z5IdhF_jSyX; znvBZXq%vnSA9s`b^!*dQkH_ovdOlu1zkYb#a>Jr`$$(`50NCY#u|4&dtABlBhuGir z^xs(t03u{JXPn*N3RhGAzXa5}0Sp088S$?V?9WdIP8B+;jF>+P=i9<9)SydVumwwa z8U(h@D_Kjmd#nOif8+zy#X>cY0QGs&>Fq#W_Lp!f$F1jk3OnQV)YKQ9;e9FyH3Rbvy5ABG_LF%<>TWO4K%3D(2;5)* zgQs{p9B6o?!0^}=OBXNx^1&7%-~3hNFixTSRU zHzCz83-DQA%JgS;tAGGNYLA003K#3kE97;xo6Ax>(;Jamp*`HSnZ?D$@L?`jkeqb= z0Y`G=*al>Lht3lr3t}#b*@4)@=o47WI#@DoW;b75>g7@n1OKqBpQG5}*7|Q{h zYYGpJ*sLm6q>`O|2K>m@ZtPCz;aW3Hd%>;rZ>cYJ>YOxEpR>EMfwJO6cRY2mq@b+K zuV{4Z482K8pOw|{*pONRg1k!P*CP{}s#>pZyh?9vf*_Bok z>sz&#e4AVff)1f3K0qa1T#}>2HH?%}9u}HhD$I<8NiWDPzj4aHO0_NI5*N1DKW@sF zS8uWkOk~6Hs;=332cOa2MQtS6e>7$On3JeCI5#p5K=CRz@3X zh4rvEzCDxF(;oX{7HL9eoIh)5rie;bGU$hZw1zgU>lpTDp4aYVY9Lp3uRK4-L_4m% zi!d~XYo&<%>wF8y^wx4Aa%Vn1nAFy(2oR+6|vxk$ik> zW=k_wthnK7Wqj$U7Mmds<%ibzZBU}?WLwxe>(Y27+b18!fH9ev&dnxngVbktKUn;A^ z2dm4ZmM#X0GjO>sE)$5_u%m{JJcY)QW+xL-j*hmM!_&5b1HyLo9m7}LtF^!H8+%-* zy@OS>U5L)zhq5*&EnQm;4%`&Uqv91xhl&h>@|4R0xbU%qL zaWO9y%KLi9R|ITG&Q0w0=R*2&OGLLO+-bw!A5PQy>o^_;#;z%CnU)(qX`qf3c@c~G zv9xm%V|nx&dCgU9+sP-8YmTZ*E$g_H+ru zwIR%JxS{SPS9RwTk`pOhH|{PIF9DI^xWSzvp`>CM|REGz4`G5$;+BIGom*^_xhHrEMyg@H+m;@89HwG zgO2;XNB4u2*#m=6icBKY#AG}x?#vaYySNMHf`qEh#Jl#kt(Lq6D4Wf!Ds|)gc3&6u&3XF4A^Ot9HCh-cCe2uxi+MU7YqfzJx|D#=2WJ=P{CEcWV|IG3NM~2xb%0VVU zmb&ZmlTiO)@$H3B#}482*LLdBCX#b~Q^3^HI&tb{xvjl{QK|EE&&yXh#z^bLca#R1 zd^UYc#IL6UBfFho`>W?$33aQ*bErj?^7ZusuN%`Z`1Mmab1i0Xj}n=D#z;0KaJSTm z#SEJol#S_wSi6jVoOD?`vx<^ahP0C&CxZ za-&zL&^lHrS%ER7H%f)w#%_(EgVY}W8v&M5U(&dj#C1(VxlhHg+abq`;-i@=DCFz;ZTHne#+Wf>~3v6!IQ9YhANvur+0& RsqXJ{0uFXqTgC}I=|2V|H;4cL literal 0 HcmV?d00001 diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/requests/uploads_controller_spec.rb similarity index 50% rename from spec/controllers/uploads_controller_spec.rb rename to spec/requests/uploads_controller_spec.rb index a98cd9ebe7..31130e15c0 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/requests/uploads_controller_spec.rb @@ -1,17 +1,14 @@ require 'rails_helper' describe UploadsController do - - context '.create' do - + describe '#create' do it 'requires you to be logged in' do - post :create, format: :json + post "/uploads.json" expect(response.status).to eq(403) end context 'logged in' do - - before { @user = log_in :user } + let!(:user) { sign_in(Fabricate(:user)) } let(:logo) do Rack::Test::UploadedFile.new(file_from_fixtures("logo.png")) @@ -26,151 +23,132 @@ describe UploadsController do end it 'expects a type' do - expect do - post :create, params: { format: :json, file: logo } - end.to raise_error(ActionController::ParameterMissing) - end - - it 'can look up long urls' do - upload = Fabricate(:upload) - post :lookup_urls, params: { short_urls: [upload.short_url], format: :json } - result = JSON.parse(response.body) - expect(result[0]["url"]).to eq(upload.url) + post "/uploads.json", params: { file: logo } + expect(response.status).to eq(400) end it 'is successful with an image' do - Jobs.expects(:enqueue).with(:create_avatar_thumbnails, anything) - - post :create, params: { file: logo, type: "avatar", format: :json } - + post "/uploads.json", params: { file: logo, type: "avatar" } expect(response.status).to eq 200 - expect(JSON.parse(response.body)["id"]).to be + expect(JSON.parse(response.body)["id"]).to be_present + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(1) end it 'is successful with an attachment' do SiteSetting.authorized_extensions = "*" - Jobs.expects(:enqueue).never - - post :create, params: { file: text_file, type: "composer", format: :json } - + post "/uploads.json", params: { file: text_file, type: "composer" } expect(response.status).to eq 200 + + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(0) id = JSON.parse(response.body)["id"] expect(id).to be end it 'is successful with api' do SiteSetting.authorized_extensions = "*" - controller.stubs(:is_api?).returns(true) - - FinalDestination.stubs(:lookup_ip).returns("1.2.3.4") - - Jobs.expects(:enqueue).with(:create_avatar_thumbnails, anything) + api_key = Fabricate(:api_key, user: user).key url = "http://example.com/image.png" png = File.read(Rails.root + "spec/fixtures/images/logo.png") stub_request(:get, url).to_return(status: 200, body: png) - post :create, params: { url: url, type: "avatar", format: :json } + post "/uploads.json", params: { url: url, type: "avatar", api_key: api_key, api_username: user.username } json = ::JSON.parse(response.body) - expect(response.status).to eq 200 - expect(json["id"]).to be + expect(response.status).to eq(200) + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(1) + expect(json["id"]).to be_present expect(json["short_url"]).to eq("upload://qUm0DGR49PAZshIi7HxMd3cAlzn.png") end it 'correctly sets retain_hours for admins' do - log_in :admin - Jobs.expects(:enqueue).with(:create_avatar_thumbnails, anything).never + sign_in(Fabricate(:admin)) - post :create, params: { + post "/uploads.json", params: { file: logo, retain_hours: 100, type: "profile_background", - format: :json } id = JSON.parse(response.body)["id"] + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(0) expect(Upload.find(id).retain_hours).to eq(100) end it 'requires a file' do - Jobs.expects(:enqueue).never - - post :create, params: { type: "composer", format: :json } + post "/uploads.json", params: { type: "composer" } + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(0) message = JSON.parse(response.body) expect(response.status).to eq 422 expect(message["errors"]).to contain_exactly(I18n.t("upload.file_missing")) end it 'properly returns errors' do + SiteSetting.authorized_extensions = "*" SiteSetting.max_attachment_size_kb = 1 - Jobs.expects(:enqueue).never + post "/uploads.json", params: { file: text_file, type: "avatar" } - post :create, params: { file: text_file, type: "avatar", format: :json } - - expect(response.status).to eq 422 + expect(response.status).to eq(422) + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(0) errors = JSON.parse(response.body)["errors"] - expect(errors).to be + expect(errors.first).to eq(I18n.t("upload.attachments.too_large", max_size_kb: 1)) end it 'ensures allow_uploaded_avatars is enabled when uploading an avatar' do SiteSetting.allow_uploaded_avatars = false - post :create, params: { file: logo, type: "avatar", format: :json } - expect(response).to_not be_success + post "/uploads.json", params: { file: logo, type: "avatar" } + expect(response.status).to eq(422) end it 'ensures sso_overrides_avatar is not enabled when uploading an avatar' do SiteSetting.sso_overrides_avatar = true - post :create, params: { file: logo, type: "avatar", format: :json } - expect(response).to_not be_success + post "/uploads.json", params: { file: logo, type: "avatar" } + expect(response.status).to eq(422) end it 'allows staff to upload any file in PM' do SiteSetting.authorized_extensions = "jpg" SiteSetting.allow_staff_to_upload_any_file_in_pm = true - @user.update_columns(moderator: true) + user.update_columns(moderator: true) - post :create, params: { + post "/uploads.json", params: { file: text_file, type: "composer", for_private_message: "true", - format: :json } expect(response).to be_success id = JSON.parse(response.body)["id"] - expect(id).to be + expect(id).to be_present end it 'respects `authorized_extensions_for_staff` setting when staff upload file' do SiteSetting.authorized_extensions = "" SiteSetting.authorized_extensions_for_staff = "*" - @user.update_columns(moderator: true) + user.update_columns(moderator: true) - post :create, params: { + post "/uploads.json", params: { file: text_file, type: "composer", - format: :json } expect(response).to be_success data = JSON.parse(response.body) - expect(data["id"]).to be + expect(data["id"]).to be_present end it 'ignores `authorized_extensions_for_staff` setting when non-staff upload file' do SiteSetting.authorized_extensions = "" SiteSetting.authorized_extensions_for_staff = "*" - post :create, params: { + post "/uploads.json", params: { file: text_file, type: "composer", - format: :json } data = JSON.parse(response.body) @@ -178,73 +156,87 @@ describe UploadsController do end it 'returns an error when it could not determine the dimensions of an image' do - Jobs.expects(:enqueue).with(:create_avatar_thumbnails, anything).never + post "/uploads.json", params: { file: fake_jpg, type: "composer" } - post :create, params: { file: fake_jpg, type: "composer", format: :json } - - expect(response.status).to eq 422 + expect(response.status).to eq(422) + expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(0) message = JSON.parse(response.body)["errors"] expect(message).to contain_exactly(I18n.t("upload.images.size_not_found")) end - end - end - context '.show' do - + describe '#show' do let(:site) { "default" } let(:sha) { Digest::SHA1.hexdigest("discourse") } + let(:user) { Fabricate(:user) } + + def upload_file(file) + fake_logo = Rack::Test::UploadedFile.new(file_from_fixtures(file)) + SiteSetting.authorized_extensions = "*" + sign_in(user) + + post "/uploads.json", params: { + file: fake_logo, + type: "composer", + } + url = JSON.parse(response.body)["url"] + upload = Upload.where(url: url).first + upload + end it "returns 404 when using external storage" do - store = stub(internal?: false) - Discourse.stubs(:store).returns(store) - Upload.expects(:find_by).never + SiteSetting.enable_s3_uploads = true + SiteSetting.s3_access_key_id = "fakeid7974664" + SiteSetting.s3_secret_access_key = "fakesecretid7974664" - get :show, params: { site: site, sha: sha, extension: "pdf" } + get "/uploads/#{site}/#{sha}.pdf" expect(response.response_code).to eq(404) end it "returns 404 when the upload doesn't exist" do - Upload.stubs(:find_by).returns(nil) - - get :show, params: { site: site, sha: sha, extension: "pdf" } - expect(response.response_code).to eq(404) + get "/uploads/#{site}/#{sha}.pdf" + expect(response.status).to eq(404) end it 'uses send_file' do - upload = build(:upload) - Upload.expects(:find_by).with(sha1: sha).returns(upload) - - controller.stubs(:render) - controller.expects(:send_file) - - get :show, params: { site: site, sha: sha, extension: "zip" } + upload = upload_file("logo.png") + get "/uploads/#{site}/#{upload.sha1}.#{upload.extension}" + expect(response.status).to eq(200) + expect(response.headers["Content-Disposition"]).to eq("attachment; filename=\"logo.png\"") end it "handles file without extension" do SiteSetting.authorized_extensions = "*" - Fabricate(:upload, original_filename: "image_file", sha1: sha) - controller.stubs(:render) - controller.expects(:send_file) + upload = upload_file("image_no_extension") - get :show, params: { site: site, sha: sha, format: :json } - expect(response).to be_success + get "/uploads/#{site}/#{upload.sha1}.json" + expect(response.status).to eq(200) + expect(response.headers["Content-Disposition"]).to eq("attachment; filename=\"image_no_extension\"") end context "prevent anons from downloading files" do - - before { SiteSetting.prevent_anons_from_downloading_files = true } - it "returns 404 when an anonymous user tries to download a file" do - Upload.expects(:find_by).never + upload = upload_file("logo.png") + delete "/session/#{user.username}.json" # upload a file, then sign out - get :show, params: { site: site, sha: sha, extension: "pdf", format: :json } - expect(response.response_code).to eq(404) + SiteSetting.prevent_anons_from_downloading_files = true + get "/uploads/#{site}/#{upload.sha1}.#{upload.extension}" + expect(response.status).to eq(404) end - end - end + describe '#lookup_urls' do + it 'can look up long urls' do + sign_in(Fabricate(:user)) + upload = Fabricate(:upload) + + post "/uploads/lookup-urls.json", params: { short_urls: [upload.short_url] } + expect(response.status).to eq(200) + + result = JSON.parse(response.body) + expect(result[0]["url"]).to eq(upload.url) + end + end end From e4bdafb550f0d4155d1865266dd9f51c12aa9eb0 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 07:04:32 +0300 Subject: [PATCH 0022/1439] REFACTOR: categories controller specs to requests (#5903) REFACTOR: categories controller specs to requests --- .../controllers/categories_controller_spec.rb | 364 ------------------ spec/requests/categories_controller_spec.rb | 316 ++++++++++++++- 2 files changed, 312 insertions(+), 368 deletions(-) delete mode 100644 spec/controllers/categories_controller_spec.rb diff --git a/spec/controllers/categories_controller_spec.rb b/spec/controllers/categories_controller_spec.rb deleted file mode 100644 index 695f06c41b..0000000000 --- a/spec/controllers/categories_controller_spec.rb +++ /dev/null @@ -1,364 +0,0 @@ -require "rails_helper" - -describe CategoriesController do - describe "create" do - - it "requires the user to be logged in" do - post :create, format: :json - expect(response.status).to eq(403) - end - - describe "logged in" do - before do - SiteSetting.queue_jobs = false - @user = log_in(:admin) - end - - it "raises an exception when they don't have permission to create it" do - Guardian.any_instance.expects(:can_create?).with(Category, nil).returns(false) - post :create, params: { - name: 'hello', color: 'ff0', text_color: 'fff' - }, format: :json - - expect(response).to be_forbidden - end - - it "raises an exception when the name is missing" do - expect do - post :create, params: { color: "ff0", text_color: "fff" }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "raises an exception when the color is missing" do - expect do - post :create, params: { name: "hello", text_color: "fff" }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "raises an exception when the text color is missing" do - expect do - post :create, params: { name: "hello", color: "ff0" }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - describe "failure" do - before do - @category = Fabricate(:category, user: @user) - - post :create, params: { - name: @category.name, color: "ff0", text_color: "fff" - }, format: :json - end - - it "returns errors on a duplicate category name" do - expect(response.status).to eq(422) - end - end - - describe "success" do - it "works" do - readonly = CategoryGroup.permission_types[:readonly] - create_post = CategoryGroup.permission_types[:create_post] - - post :create, params: { - name: "hello", - color: "ff0", - text_color: "fff", - slug: "hello-cat", - auto_close_hours: 72, - permissions: { - "everyone" => readonly, - "staff" => create_post - } - }, format: :json - - expect(response.status).to eq(200) - category = Category.find_by(name: "hello") - expect(category.category_groups.map { |g| [g.group_id, g.permission_type] }.sort).to eq([ - [Group[:everyone].id, readonly], [Group[:staff].id, create_post] - ]) - expect(category.name).to eq("hello") - expect(category.slug).to eq("hello-cat") - expect(category.color).to eq("ff0") - expect(category.auto_close_hours).to eq(72) - expect(UserHistory.count).to eq(4) # 1 + 3 (bootstrap mode) - end - end - end - end - - describe "destroy" do - - it "requires the user to be logged in" do - delete :destroy, params: { id: "category" }, format: :json - expect(response.status).to eq(403) - end - - describe "logged in" do - before do - @user = log_in - @category = Fabricate(:category, user: @user) - end - - it "raises an exception if they don't have permission to delete it" do - Guardian.any_instance.expects(:can_delete_category?).returns(false) - delete :destroy, params: { id: @category.slug }, format: :json - expect(response).to be_forbidden - end - - it "deletes the record" do - Guardian.any_instance.expects(:can_delete_category?).returns(true) - expect do - delete :destroy, params: { id: @category.slug }, format: :json - end.to change(Category, :count).by(-1) - - expect(UserHistory.count).to eq(1) - end - end - - end - - describe "reorder" do - it "reorders the categories" do - admin = log_in(:admin) - - c1 = Fabricate(:category) - c2 = Fabricate(:category) - c3 = Fabricate(:category) - c4 = Fabricate(:category) - if c3.id < c2.id - tmp = c3; c2 = c3; c3 = tmp; - end - c1.position = 8 - c2.position = 6 - c3.position = 7 - c4.position = 5 - - payload = {} - payload[c1.id] = 4 - payload[c2.id] = 6 - payload[c3.id] = 6 - payload[c4.id] = 5 - - post :reorder, params: { mapping: MultiJson.dump(payload) }, format: :json - - SiteSetting.fixed_category_positions = true - list = CategoryList.new(Guardian.new(admin)) - - expect(list.categories).to eq([ - Category.find(SiteSetting.uncategorized_category_id), - c1, - c4, - c2, - c3 - ]) - end - end - - describe "update" do - before do - SiteSetting.queue_jobs = false - end - - it "requires the user to be logged in" do - put :update, params: { id: 'category' }, format: :json - expect(response.status).to eq(403) - end - - describe "logged in" do - let(:valid_attrs) { { id: @category.id, name: "hello", color: "ff0", text_color: "fff" } } - - before do - @user = log_in(:admin) - @category = Fabricate(:category, user: @user) - end - - it "raises an exception if they don't have permission to edit it" do - Guardian.any_instance.expects(:can_edit?).returns(false) - put :update, params: { - id: @category.slug, - name: 'hello', - color: 'ff0', - text_color: 'fff' - }, format: :json - - expect(response).to be_forbidden - end - - it "requires a name" do - expect do - put :update, params: { - id: @category.slug, - color: 'fff', - text_color: '0ff', - }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "requires a color" do - expect do - put :update, params: { - id: @category.slug, - name: 'asdf', - text_color: '0ff', - }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "requires a text color" do - expect do - put :update, - params: { id: @category.slug, name: 'asdf', color: 'fff' }, - format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - describe "failure" do - before do - @other_category = Fabricate(:category, name: "Other", user: @user) - - put :update, params: { - id: @category.id, - name: @other_category.name, - color: "ff0", - text_color: "fff", - }, format: :json - end - - it "returns errors on a duplicate category name" do - expect(response).not_to be_success - end - - it "returns errors on a duplicate category name" do - expect(response.code.to_i).to eq(422) - end - end - - it "returns 422 if email_in address is already in use for other category" do - @other_category = Fabricate(:category, name: "Other", email_in: "mail@examle.com") - - put :update, params: { - id: @category.id, - name: "Email", - email_in: "mail@examle.com", - color: "ff0", - text_color: "fff", - }, format: :json - - expect(response).not_to be_success - expect(response.code.to_i).to eq(422) - end - - describe "success" do - - it "updates the group correctly" do - readonly = CategoryGroup.permission_types[:readonly] - create_post = CategoryGroup.permission_types[:create_post] - - put :update, params: { - id: @category.id, - name: "hello", - color: "ff0", - text_color: "fff", - slug: "hello-category", - auto_close_hours: 72, - permissions: { - "everyone" => readonly, - "staff" => create_post - }, - custom_fields: { - "dancing" => "frogs" - }, - }, format: :json - - expect(response.status).to eq(200) - @category.reload - expect(@category.category_groups.map { |g| [g.group_id, g.permission_type] }.sort).to eq([ - [Group[:everyone].id, readonly], [Group[:staff].id, create_post] - ]) - expect(@category.name).to eq("hello") - expect(@category.slug).to eq("hello-category") - expect(@category.color).to eq("ff0") - expect(@category.auto_close_hours).to eq(72) - expect(@category.custom_fields).to eq("dancing" => "frogs") - end - - it 'logs the changes correctly' do - @category.update!(permissions: { "admins" => CategoryGroup.permission_types[:create_post] }) - - put :update, params: { - id: @category.id, - name: 'new name', - color: @category.color, - text_color: @category.text_color, - slug: @category.slug, - permissions: { - "everyone" => CategoryGroup.permission_types[:create_post] - }, - }, format: :json - - expect(UserHistory.count).to eq(5) # 2 + 3 (bootstrap mode) - end - end - end - - end - - describe 'update_slug' do - it 'requires the user to be logged in' do - put :update_slug, params: { category_id: 'category' }, format: :json - expect(response.status).to eq(403) - end - - describe 'logged in' do - let(:valid_attrs) { { id: @category.id, slug: 'fff' } } - - before do - @user = log_in(:admin) - @category = Fabricate(:happy_category, user: @user) - end - - it 'rejects blank' do - put :update_slug, params: { category_id: @category.id, slug: nil }, format: :json - expect(response.status).to eq(422) - end - - it 'accepts valid custom slug' do - put :update_slug, - params: { category_id: @category.id, slug: 'valid-slug' }, - format: :json - - expect(response).to be_success - expect(@category.reload.slug).to eq('valid-slug') - end - - it 'accepts not well formed custom slug' do - put :update_slug, - params: { category_id: @category.id, slug: ' valid slug' }, - format: :json - - expect(response).to be_success - expect(@category.reload.slug).to eq('valid-slug') - end - - it 'accepts and sanitize custom slug when the slug generation method is not ascii' do - SiteSetting.slug_generation_method = 'none' - put :update_slug, - params: { category_id: @category.id, slug: ' another !_ slug @' }, - format: :json - - expect(response).to be_success - expect(@category.reload.slug).to eq('another-slug') - SiteSetting.slug_generation_method = 'ascii' - end - - it 'rejects invalid custom slug' do - put :update_slug, - params: { category_id: @category.id, slug: ' ' }, - format: :json - - expect(response.status).to eq(422) - end - end - end -end diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb index 9f0b113aec..3c1ca0ea2d 100644 --- a/spec/requests/categories_controller_spec.rb +++ b/spec/requests/categories_controller_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' describe CategoriesController do + let(:admin) { Fabricate(:admin) } + let!(:category) { Fabricate(:category, user: admin) } context 'index' do @@ -18,11 +20,7 @@ describe CategoriesController do end context 'extensibility event' do - let(:admin) { Fabricate(:admin) } - let(:category) { Fabricate(:category, user: admin) } - before do - category sign_in(admin) end @@ -39,4 +37,314 @@ describe CategoriesController do expect(event[:params].first).to eq(category) end end + + context '#create' do + it "requires the user to be logged in" do + post "/categories.json" + expect(response.status).to eq(403) + end + + describe "logged in" do + before do + SiteSetting.queue_jobs = false + sign_in(admin) + end + + it "raises an exception when they don't have permission to create it" do + sign_in(Fabricate(:user)) + post "/categories.json", params: { + name: 'hello', color: 'ff0', text_color: 'fff' + } + + expect(response).to be_forbidden + end + + it "raises an exception when the name is missing" do + post "/categories.json", params: { color: "ff0", text_color: "fff" } + expect(response.status).to eq(400) + end + + it "raises an exception when the color is missing" do + post "/categories.json", params: { name: "hello", text_color: "fff" } + expect(response.status).to eq(400) + end + + it "raises an exception when the text color is missing" do + post "/categories.json", params: { name: "hello", color: "ff0" } + end + + describe "failure" do + it "returns errors on a duplicate category name" do + category = Fabricate(:category, user: admin) + + post "/categories.json", params: { + name: category.name, color: "ff0", text_color: "fff" + } + + expect(response.status).to eq(422) + end + end + + describe "success" do + it "works" do + readonly = CategoryGroup.permission_types[:readonly] + create_post = CategoryGroup.permission_types[:create_post] + + post "/categories.json", params: { + name: "hello", + color: "ff0", + text_color: "fff", + slug: "hello-cat", + auto_close_hours: 72, + permissions: { + "everyone" => readonly, + "staff" => create_post + } + } + + expect(response.status).to eq(200) + category = Category.find_by(name: "hello") + expect(category.category_groups.map { |g| [g.group_id, g.permission_type] }.sort).to eq([ + [Group[:everyone].id, readonly], [Group[:staff].id, create_post] + ]) + expect(category.name).to eq("hello") + expect(category.slug).to eq("hello-cat") + expect(category.color).to eq("ff0") + expect(category.auto_close_hours).to eq(72) + expect(UserHistory.count).to eq(4) # 1 + 3 (bootstrap mode) + end + end + end + end + + context '#destroy' do + it "requires the user to be logged in" do + delete "/categories/category.json" + expect(response.status).to eq(403) + end + + describe "logged in" do + it "raises an exception if they don't have permission to delete it" do + admin.update!(admin: false) + sign_in(admin) + delete "/categories/#{category.slug}.json" + expect(response).to be_forbidden + end + + it "deletes the record" do + sign_in(admin) + expect do + delete "/categories/#{category.slug}.json" + end.to change(Category, :count).by(-1) + expect(response).to be_success + expect(UserHistory.count).to eq(1) + end + end + end + + context '#reorder' do + it "reorders the categories" do + sign_in(admin) + + c1 = category + c2 = Fabricate(:category) + c3 = Fabricate(:category) + c4 = Fabricate(:category) + if c3.id < c2.id + tmp = c3; c2 = c3; c3 = tmp; + end + c1.position = 8 + c2.position = 6 + c3.position = 7 + c4.position = 5 + + payload = {} + payload[c1.id] = 4 + payload[c2.id] = 6 + payload[c3.id] = 6 + payload[c4.id] = 5 + + post "/categories/reorder.json", params: { mapping: MultiJson.dump(payload) } + + SiteSetting.fixed_category_positions = true + list = CategoryList.new(Guardian.new(admin)) + + expect(list.categories).to eq([ + Category.find(SiteSetting.uncategorized_category_id), + c1, + c4, + c2, + c3 + ]) + end + end + + context '#update' do + before do + SiteSetting.queue_jobs = false + end + + it "requires the user to be logged in" do + put "/categories/category.json" + expect(response.status).to eq(403) + end + + describe "logged in" do + let(:valid_attrs) { { id: category.id, name: "hello", color: "ff0", text_color: "fff" } } + + before do + sign_in(admin) + end + + it "raises an exception if they don't have permission to edit it" do + sign_in(Fabricate(:user)) + put "/categories/#{category.slug}.json", params: { + name: 'hello', + color: 'ff0', + text_color: 'fff' + } + expect(response).to be_forbidden + end + + it "requires a name" do + put "/categories/#{category.slug}.json", params: { + color: 'fff', + text_color: '0ff', + } + expect(response.status).to eq(400) + end + + it "requires a color" do + put "/categories/#{category.slug}.json", params: { + name: 'asdf', + text_color: '0ff', + } + expect(response.status).to eq(400) + end + + it "requires a text color" do + put "/categories/#{category.slug}.json", params: { name: 'asdf', color: 'fff' } + expect(response.status).to eq(400) + end + + it "returns errors on a duplicate category name" do + other_category = Fabricate(:category, name: "Other", user: admin) + put "/categories/#{category.id}.json", params: { + name: other_category.name, + color: "ff0", + text_color: "fff", + } + expect(response.status).to eq(422) + end + + it "returns 422 if email_in address is already in use for other category" do + other_category = Fabricate(:category, name: "Other", email_in: "mail@examle.com") + + put "/categories/#{category.id}.json", params: { + name: "Email", + email_in: "mail@examle.com", + color: "ff0", + text_color: "fff", + } + expect(response.status).to eq(422) + end + + describe "success" do + it "updates the group correctly" do + readonly = CategoryGroup.permission_types[:readonly] + create_post = CategoryGroup.permission_types[:create_post] + + put "/categories/#{category.id}.json", params: { + name: "hello", + color: "ff0", + text_color: "fff", + slug: "hello-category", + auto_close_hours: 72, + permissions: { + "everyone" => readonly, + "staff" => create_post + }, + custom_fields: { + "dancing" => "frogs" + }, + } + + expect(response.status).to eq(200) + category.reload + expect(category.category_groups.map { |g| [g.group_id, g.permission_type] }.sort).to eq([ + [Group[:everyone].id, readonly], [Group[:staff].id, create_post] + ]) + expect(category.name).to eq("hello") + expect(category.slug).to eq("hello-category") + expect(category.color).to eq("ff0") + expect(category.auto_close_hours).to eq(72) + expect(category.custom_fields).to eq("dancing" => "frogs") + end + + it 'logs the changes correctly' do + category.update!(permissions: { "admins" => CategoryGroup.permission_types[:create_post] }) + + put "/categories/#{category.id}.json", params: { + name: 'new name', + color: category.color, + text_color: category.text_color, + slug: category.slug, + permissions: { + "everyone" => CategoryGroup.permission_types[:create_post] + }, + } + expect(response.status).to eq(200) + expect(UserHistory.count).to eq(5) # 2 + 3 (bootstrap mode) + end + end + end + end + + context '#update_slug' do + it 'requires the user to be logged in' do + put "/category/category/slug.json" + expect(response.status).to eq(403) + end + + describe 'logged in' do + let(:valid_attrs) { { id: category.id, slug: 'fff' } } + + before do + sign_in(admin) + end + + it 'rejects blank' do + put "/category/#{category.id}/slug.json", params: { slug: nil } + expect(response.status).to eq(422) + end + + it 'accepts valid custom slug' do + put "/category/#{category.id}/slug.json", params: { slug: 'valid-slug' } + + expect(response).to be_success + expect(category.reload.slug).to eq('valid-slug') + end + + it 'accepts not well formed custom slug' do + put "/category/#{category.id}/slug.json", params: { slug: ' valid slug' } + + expect(response).to be_success + expect(category.reload.slug).to eq('valid-slug') + end + + it 'accepts and sanitize custom slug when the slug generation method is not ascii' do + SiteSetting.slug_generation_method = 'none' + put "/category/#{category.id}/slug.json", params: { slug: ' another !_ slug @' } + + expect(response).to be_success + expect(category.reload.slug).to eq('another-slug') + SiteSetting.slug_generation_method = 'ascii' + end + + it 'rejects invalid custom slug' do + put "/category/#{category.id}/slug.json", params: { slug: ' ' } + expect(response.status).to eq(422) + end + end + end end From 807223deeff706f574a13fcb77b5e6d1a85ae6ac Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 06:33:55 +0300 Subject: [PATCH 0023/1439] REFACTOR: notifications controller specs to requests --- .../notifications_controller_spec.rb | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) rename spec/{controllers => requests}/notifications_controller_spec.rb (79%) diff --git a/spec/controllers/notifications_controller_spec.rb b/spec/requests/notifications_controller_spec.rb similarity index 79% rename from spec/controllers/notifications_controller_spec.rb rename to spec/requests/notifications_controller_spec.rb index d322abd848..a55ae2e5b1 100644 --- a/spec/controllers/notifications_controller_spec.rb +++ b/spec/requests/notifications_controller_spec.rb @@ -2,14 +2,19 @@ require 'rails_helper' def create_notification(user_id, resp_code, matcher) notification_count = Notification.count - post :create, params: { notification_type: Notification.types[:mentioned], user_id: user_id, data: { message: 'tada' }.to_json }, format: :json + post "/notifications.json", + params: { + notification_type: Notification.types[:mentioned], + user_id: user_id, + data: { message: 'tada' }.to_json + } expect(response.status).to eq(resp_code) expect(Notification.count).send(matcher, eq(notification_count)) end def update_notification(topic_id, resp_code, matcher) notification = Fabricate(:notification) - post :update, params: { id: notification.id, topic_id: topic_id }, format: :json + put "/notifications/#{notification.id}.json", params: { topic_id: topic_id } expect(response.status).to eq(resp_code) notification.reload expect(notification.topic_id).send(matcher, eq(topic_id)) @@ -18,67 +23,62 @@ end def delete_notification(resp_code, matcher) notification = Fabricate(:notification) notification_count = Notification.count - delete :destroy, params: { id: notification.id }, format: :json + delete "/notifications/#{notification.id}.json" expect(response.status).to eq(resp_code) expect(Notification.count).send(matcher, eq(notification_count)) end describe NotificationsController do - context 'when logged in' do - context 'as normal user' do - - let!(:user) { log_in } + let!(:user) { sign_in(Fabricate(:user)) } describe '#index' do it 'should succeed for recent' do - get :index, params: { recent: true } + get "/notifications", params: { recent: true } expect(response).to be_success end it 'should succeed for history' do - get :index + get "/notifications" expect(response).to be_success end it 'should mark notifications as viewed' do - _notification = Fabricate(:notification, user: user) + Fabricate(:notification, user: user) expect(user.reload.unread_notifications).to eq(1) expect(user.reload.total_unread_notifications).to eq(1) - get :index, params: { recent: true }, format: :json + get "/notifications.json", params: { recent: true } expect(user.reload.unread_notifications).to eq(0) expect(user.reload.total_unread_notifications).to eq(1) end it 'should not mark notifications as viewed if silent param is present' do - _notification = Fabricate(:notification, user: user) + Fabricate(:notification, user: user) expect(user.reload.unread_notifications).to eq(1) expect(user.reload.total_unread_notifications).to eq(1) - get :index, params: { recent: true, silent: true } + get "/notifications", params: { recent: true, silent: true } expect(user.reload.unread_notifications).to eq(1) expect(user.reload.total_unread_notifications).to eq(1) end context 'when username params is not valid' do it 'should raise the right error' do - get :index, params: { username: 'somedude' }, format: :json - - expect(response).to_not be_success + get "/notifications.json", params: { username: 'somedude' } expect(response.status).to eq(404) end end end it 'should succeed' do - put :mark_read, format: :json + put "/notifications/mark-read.json" expect(response).to be_success end it "can update a single notification" do notification = Fabricate(:notification, user: user) notification2 = Fabricate(:notification, user: user) - put :mark_read, params: { id: notification.id }, format: :json + put "/notifications/mark-read.json", params: { id: notification.id } expect(response).to be_success notification.reload @@ -89,10 +89,10 @@ describe NotificationsController do end it "updates the `read` status" do - _notification = Fabricate(:notification, user: user) + Fabricate(:notification, user: user) expect(user.reload.unread_notifications).to eq(1) expect(user.reload.total_unread_notifications).to eq(1) - put :mark_read, format: :json + put "/notifications/mark-read.json" user.reload expect(user.reload.unread_notifications).to eq(0) expect(user.reload.total_unread_notifications).to eq(0) @@ -115,12 +115,10 @@ describe NotificationsController do delete_notification(403, :to) end end - end context 'as admin' do - - let!(:admin) { log_in(:admin) } + let!(:admin) { sign_in(Fabricate(:admin)) } describe '#create' do it "can create notification" do @@ -141,16 +139,14 @@ describe NotificationsController do delete_notification(200, :to_not) end end - end - end context 'when not logged in' do describe '#index' do it 'should raise an error' do - get :index, params: { recent: true }, format: :json + get "/notifications.json", params: { recent: true } expect(response.status).to eq(403) end end @@ -173,7 +169,5 @@ describe NotificationsController do delete_notification(403, :to) end end - end - end From 1f8805d3af00270f971210aac607c7a91b1887a5 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 06:00:08 +0300 Subject: [PATCH 0024/1439] REFACTOR: user api keys contoller specs to request --- .../user_api_keys_controller_spec.rb | 70 ++++++++----------- 1 file changed, 30 insertions(+), 40 deletions(-) rename spec/{controllers => requests}/user_api_keys_controller_spec.rb (81%) diff --git a/spec/controllers/user_api_keys_controller_spec.rb b/spec/requests/user_api_keys_controller_spec.rb similarity index 81% rename from spec/controllers/user_api_keys_controller_spec.rb rename to spec/requests/user_api_keys_controller_spec.rb index 5e430cc5c0..34fc6c898b 100644 --- a/spec/controllers/user_api_keys_controller_spec.rb +++ b/spec/requests/user_api_keys_controller_spec.rb @@ -46,8 +46,8 @@ describe UserApiKeysController do context 'new' do it "supports a head request cleanly" do - head :new - expect(response.code).to eq("200") + head "/user-api-key/new" + expect(response.status).to eq(200) expect(response.headers["Auth-Api-Version"]).to eq("2") end end @@ -55,14 +55,14 @@ describe UserApiKeysController do context 'create' do it "does not allow anon" do - post :create, params: args, format: :json + post "/user-api-key.json", params: args expect(response.status).to eq(403) end it "refuses to redirect to disallowed place" do - log_in_user(Fabricate(:user)) - post :create, params: args, format: :json - expect(response.code).to eq("403") + sign_in(Fabricate(:user)) + post "/user-api-key.json", params: args + expect(response.status).to eq(403) end it "will allow tokens for staff without TL" do @@ -71,10 +71,10 @@ describe UserApiKeysController do user = Fabricate(:user, trust_level: 1, moderator: true) - log_in_user(user) + sign_in(user) - post :create, params: args, format: :json - expect(response.code).to eq("302") + post "/user-api-key.json", params: args + expect(response.status).to eq(302) end it "will not create token unless TL is met" do @@ -82,36 +82,29 @@ describe UserApiKeysController do SiteSetting.allowed_user_api_auth_redirects = args[:auth_redirect] user = Fabricate(:user, trust_level: 1) + sign_in(user) - log_in_user(user) - - post :create, params: args, format: :json - expect(response.code).to eq("403") - + post "/user-api-key.json", params: args + expect(response.status).to eq(403) end it "will deny access if requesting more rights than allowed" do - SiteSetting.min_trust_level_for_user_api_key = 0 SiteSetting.allowed_user_api_auth_redirects = args[:auth_redirect] SiteSetting.allow_user_api_key_scopes = "write" user = Fabricate(:user, trust_level: 0) + sign_in(user) - log_in_user(user) - - post :create, params: args, format: :json - expect(response.code).to eq("403") - + post "/user-api-key.json", params: args + expect(response.status).to eq(403) end it "allows for a revoke with no id" do key = Fabricate(:readonly_user_api_key) - request.env['HTTP_USER_API_KEY'] = key.key - post :revoke, format: :json + post "/user-api-key/revoke.json", headers: { HTTP_USER_API_KEY: key.key } expect(response.status).to eq(200) - key.reload expect(key.revoked_at).not_to eq(nil) end @@ -120,19 +113,20 @@ describe UserApiKeysController do key1 = Fabricate(:readonly_user_api_key) key2 = Fabricate(:readonly_user_api_key) - request.env['HTTP_USER_API_KEY'] = key1.key - post :revoke, params: { id: key2.id }, format: :json + post "/user-api-key/revoke.json", + params: { id: key2.id }, + headers: { HTTP_USER_API_KEY: key1.key } expect(response.status).to eq(403) end it "will allow readonly api keys to revoke self" do key = Fabricate(:readonly_user_api_key) - request.env['HTTP_USER_API_KEY'] = key.key - post :revoke, params: { id: key.id }, format: :json + post "/user-api-key/revoke.json", + params: { id: key.id }, + headers: { HTTP_USER_API_KEY: key.key } expect(response.status).to eq(200) - key.reload expect(key.revoked_at).not_to eq(nil) end @@ -145,11 +139,10 @@ describe UserApiKeysController do args[:push_url] = "https://push.it/here" user = Fabricate(:user, trust_level: 0) + sign_in(user) - log_in_user(user) - - post :create, params: args, format: :json - expect(response.code).to eq("302") + post "/user-api-key.json", params: args + expect(response.status).to eq(302) uri = URI.parse(response.redirect_url) @@ -168,7 +161,6 @@ describe UserApiKeysController do key = user.user_api_keys.first expect(key.scopes).to include("push") expect(key.push_url).to eq("https://push.it/here") - end it "will redirect correctly with valid token" do @@ -180,11 +172,10 @@ describe UserApiKeysController do args[:push_url] = "https://push.it/here" user = Fabricate(:user, trust_level: 0) + sign_in(user) - log_in_user(user) - - post :create, params: args, format: :json - expect(response.code).to eq("302") + post "/user-api-key.json", params: args + expect(response.status).to eq(302) uri = URI.parse(response.redirect_url) @@ -210,10 +201,9 @@ describe UserApiKeysController do # should overwrite if needed args["access"] = "pr" - post :create, params: args, format: :json + post "/user-api-key.json", params: args - expect(response.code).to eq("302") + expect(response.status).to eq(302) end - end end From bc75cfe4b5d1a3db43e8850e3de756fea9ae5896 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Mon, 4 Jun 2018 09:09:14 +0300 Subject: [PATCH 0025/1439] REFACTOR: tags controller specs (#5908) --- spec/controllers/tags_controller_spec.rb | 219 ----------------------- spec/requests/tags_controller_spec.rb | 197 ++++++++++++++++++++ 2 files changed, 197 insertions(+), 219 deletions(-) delete mode 100644 spec/controllers/tags_controller_spec.rb diff --git a/spec/controllers/tags_controller_spec.rb b/spec/controllers/tags_controller_spec.rb deleted file mode 100644 index 62c8c55d5a..0000000000 --- a/spec/controllers/tags_controller_spec.rb +++ /dev/null @@ -1,219 +0,0 @@ -require 'rails_helper' - -describe TagsController do - describe 'show_latest' do - let(:tag) { Fabricate(:tag) } - let(:other_tag) { Fabricate(:tag) } - let(:third_tag) { Fabricate(:tag) } - let(:category) { Fabricate(:category) } - let(:subcategory) { Fabricate(:category, parent_category_id: category.id) } - - let(:single_tag_topic) { Fabricate(:topic, tags: [tag]) } - let(:multi_tag_topic) { Fabricate(:topic, tags: [tag, other_tag]) } - let(:all_tag_topic) { Fabricate(:topic, tags: [tag, other_tag, third_tag]) } - - context 'tagging disabled' do - it "returns 404" do - get :show_latest, params: { tag_id: tag.name }, format: :json - expect(response.status).to eq(404) - end - end - - context 'tagging enabled' do - before do - SiteSetting.tagging_enabled = true - end - - it "can filter by tag" do - get :show_latest, params: { tag_id: tag.name }, format: :json - expect(response).to be_success - end - - it "can filter by two tags" do - single_tag_topic; multi_tag_topic; all_tag_topic - - get :show_latest, params: { - tag_id: tag.name, additional_tag_ids: other_tag.name - }, format: :json - - expect(response).to be_success - - topic_ids = JSON.parse(response.body)["topic_list"]["topics"] - .map { |topic| topic["id"] } - - expect(topic_ids).to include(all_tag_topic.id) - expect(topic_ids).to include(multi_tag_topic.id) - expect(topic_ids).to_not include(single_tag_topic.id) - end - - it "can filter by multiple tags" do - single_tag_topic; multi_tag_topic; all_tag_topic - - get :show_latest, params: { - tag_id: tag.name, additional_tag_ids: "#{other_tag.name}/#{third_tag.name}" - }, format: :json - - expect(response).to be_success - - topic_ids = JSON.parse(response.body)["topic_list"]["topics"] - .map { |topic| topic["id"] } - - expect(topic_ids).to include(all_tag_topic.id) - expect(topic_ids).to_not include(multi_tag_topic.id) - expect(topic_ids).to_not include(single_tag_topic.id) - end - - it "does not find any tags when a tag which doesn't exist is passed" do - single_tag_topic - - get :show_latest, params: { - tag_id: tag.name, additional_tag_ids: "notatag" - }, format: :json - - expect(response).to be_success - - topic_ids = JSON.parse(response.body)["topic_list"]["topics"] - .map { |topic| topic["id"] } - - expect(topic_ids).to_not include(single_tag_topic.id) - end - - it "can filter by category and tag" do - get :show_latest, params: { - tag_id: tag.name, category: category.slug - }, format: :json - - expect(response).to be_success - end - - it "can filter by category, sub-category, and tag" do - get :show_latest, params: { - tag_id: tag.name, category: subcategory.slug, parent_category: category.slug - }, format: :json - - expect(response).to be_success - end - - it "can filter by category, no sub-category, and tag" do - get :show_latest, params: { - tag_id: tag.name, category: 'none', parent_category: category.slug - }, format: :json - - expect(response).to be_success - end - - it "can handle subcategories with the same name" do - category2 = Fabricate(:category) - subcategory2 = Fabricate(:category, - parent_category_id: category2.id, - name: subcategory.name, - slug: subcategory.slug - ) - t = Fabricate(:topic, category_id: subcategory2.id, tags: [other_tag]) - get :show_latest, params: { - tag_id: other_tag.name, category: subcategory2.slug, parent_category: category2.slug - }, format: :json - - expect(response).to be_success - - topic_ids = JSON.parse(response.body)["topic_list"]["topics"] - .map { |topic| topic["id"] } - - expect(topic_ids).to include(t.id) - end - - it "can filter by bookmarked" do - log_in(:user) - get :show_bookmarks, params: { - tag_id: tag.name - }, format: :json - - expect(response).to be_success - end - end - end - - describe 'search' do - context 'tagging disabled' do - it "returns 404" do - get :search, params: { q: 'stuff' }, format: :json - expect(response.status).to eq(404) - end - end - - context 'tagging enabled' do - before do - SiteSetting.tagging_enabled = true - end - - it "can return some tags" do - tag_names = ['stuff', 'stinky', 'stumped'] - tag_names.each { |name| Fabricate(:tag, name: name) } - get :search, params: { q: 'stu' }, format: :json - expect(response).to be_success - json = ::JSON.parse(response.body) - expect(json["results"].map { |j| j["id"] }.sort).to eq(['stuff', 'stumped']) - end - - it "can say if given tag is not allowed" do - yup, nope = Fabricate(:tag, name: 'yup'), Fabricate(:tag, name: 'nope') - category = Fabricate(:category, tags: [yup]) - get :search, params: { q: 'nope', categoryId: category.id }, format: :json - expect(response).to be_success - json = ::JSON.parse(response.body) - expect(json["results"].map { |j| j["id"] }.sort).to eq([]) - expect(json["forbidden"]).to be_present - end - - it "can return tags that are in secured categories but are allowed to be used" do - c = Fabricate(:private_category, group: Fabricate(:group)) - Fabricate(:topic, category: c, tags: [Fabricate(:tag, name: "cooltag")]) - get :search, params: { q: "cool" }, format: :json - expect(response).to be_success - json = ::JSON.parse(response.body) - expect(json["results"].map { |j| j["id"] }).to eq(['cooltag']) - end - - it "supports Chinese and Russian" do - tag_names = ['房地产', 'тема-в-разработке'] - tag_names.each { |name| Fabricate(:tag, name: name) } - - get :search, params: { q: '房' }, format: :json - expect(response).to be_success - json = ::JSON.parse(response.body) - expect(json["results"].map { |j| j["id"] }).to eq(['房地产']) - - get :search, params: { q: 'тема' }, format: :json - expect(response).to be_success - json = ::JSON.parse(response.body) - expect(json["results"].map { |j| j["id"] }).to eq(['тема-в-разработке']) - end - end - end - - describe 'destroy' do - context 'tagging enabled' do - before do - log_in(:admin) - SiteSetting.tagging_enabled = true - end - - context 'with an existent tag name' do - it 'deletes the tag' do - tag = Fabricate(:tag) - delete :destroy, params: { tag_id: tag.name }, format: :json - expect(response).to be_success - end - end - - context 'with a nonexistent tag name' do - it 'returns a tag not found message' do - delete :destroy, params: { tag_id: 'idontexist' }, format: :json - expect(response).not_to be_success - json = ::JSON.parse(response.body) - expect(json['error_type']).to eq('not_found') - end - end - end - end -end diff --git a/spec/requests/tags_controller_spec.rb b/spec/requests/tags_controller_spec.rb index 65165852a9..107655ac6e 100644 --- a/spec/requests/tags_controller_spec.rb +++ b/spec/requests/tags_controller_spec.rb @@ -172,4 +172,201 @@ describe TagsController do end end end + + describe '#show_latest' do + let(:tag) { Fabricate(:tag) } + let(:other_tag) { Fabricate(:tag) } + let(:third_tag) { Fabricate(:tag) } + let(:category) { Fabricate(:category) } + let(:subcategory) { Fabricate(:category, parent_category_id: category.id) } + + let(:single_tag_topic) { Fabricate(:topic, tags: [tag]) } + let(:multi_tag_topic) { Fabricate(:topic, tags: [tag, other_tag]) } + let(:all_tag_topic) { Fabricate(:topic, tags: [tag, other_tag, third_tag]) } + + context 'tagging disabled' do + it "returns 404" do + SiteSetting.tagging_enabled = false + get "/tags/#{tag.name}/l/latest.json" + expect(response.status).to eq(404) + end + end + + context 'tagging enabled' do + it "can filter by tag" do + get "/tags/#{tag.name}/l/latest.json" + expect(response).to be_success + end + + it "can filter by two tags" do + single_tag_topic; multi_tag_topic; all_tag_topic + + get "/tags/#{tag.name}/l/latest.json", params: { + additional_tag_ids: other_tag.name + } + + expect(response).to be_success + + topic_ids = JSON.parse(response.body)["topic_list"]["topics"] + .map { |topic| topic["id"] } + + expect(topic_ids).to include(all_tag_topic.id) + expect(topic_ids).to include(multi_tag_topic.id) + expect(topic_ids).to_not include(single_tag_topic.id) + end + + it "can filter by multiple tags" do + single_tag_topic; multi_tag_topic; all_tag_topic + + get "/tags/#{tag.name}/l/latest.json", params: { + additional_tag_ids: "#{other_tag.name}/#{third_tag.name}" + } + + expect(response).to be_success + + topic_ids = JSON.parse(response.body)["topic_list"]["topics"] + .map { |topic| topic["id"] } + + expect(topic_ids).to include(all_tag_topic.id) + expect(topic_ids).to_not include(multi_tag_topic.id) + expect(topic_ids).to_not include(single_tag_topic.id) + end + + it "does not find any tags when a tag which doesn't exist is passed" do + single_tag_topic + + get "/tags/#{tag.name}/l/latest.json", params: { + additional_tag_ids: "notatag" + } + + expect(response).to be_success + + topic_ids = JSON.parse(response.body)["topic_list"]["topics"] + .map { |topic| topic["id"] } + + expect(topic_ids).to_not include(single_tag_topic.id) + end + + it "can filter by category and tag" do + get "/tags/c/#{category.slug}/#{tag.name}/l/latest.json" + expect(response).to be_success + end + + it "can filter by category, sub-category, and tag" do + get "/tags/c/#{category.slug}/#{subcategory.slug}/#{tag.name}/l/latest.json" + expect(response).to be_success + end + + it "can filter by category, no sub-category, and tag" do + get "/tags/c/#{category.slug}/none/#{tag.name}/l/latest.json" + expect(response).to be_success + end + + it "can handle subcategories with the same name" do + category2 = Fabricate(:category) + subcategory2 = Fabricate(:category, + parent_category_id: category2.id, + name: subcategory.name, + slug: subcategory.slug + ) + t = Fabricate(:topic, category_id: subcategory2.id, tags: [other_tag]) + get "/tags/c/#{category2.slug}/#{subcategory2.slug}/#{other_tag.name}/l/latest.json" + + expect(response).to be_success + + topic_ids = JSON.parse(response.body)["topic_list"]["topics"] + .map { |topic| topic["id"] } + + expect(topic_ids).to include(t.id) + end + + it "can filter by bookmarked" do + sign_in(Fabricate(:user)) + get "/tags/#{tag.name}/l/bookmarks.json" + + expect(response).to be_success + end + end + end + + describe '#search' do + context 'tagging disabled' do + it "returns 404" do + SiteSetting.tagging_enabled = false + get "/tags/filter/search.json", params: { q: 'stuff' } + expect(response.status).to eq(404) + end + end + + context 'tagging enabled' do + it "can return some tags" do + tag_names = ['stuff', 'stinky', 'stumped'] + tag_names.each { |name| Fabricate(:tag, name: name) } + get "/tags/filter/search.json", params: { q: 'stu' } + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["results"].map { |j| j["id"] }.sort).to eq(['stuff', 'stumped']) + end + + it "can say if given tag is not allowed" do + yup, nope = Fabricate(:tag, name: 'yup'), Fabricate(:tag, name: 'nope') + category = Fabricate(:category, tags: [yup]) + get "/tags/filter/search.json", params: { q: 'nope', categoryId: category.id } + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["results"].map { |j| j["id"] }.sort).to eq([]) + expect(json["forbidden"]).to be_present + end + + it "can return tags that are in secured categories but are allowed to be used" do + c = Fabricate(:private_category, group: Fabricate(:group)) + Fabricate(:topic, category: c, tags: [Fabricate(:tag, name: "cooltag")]) + get "/tags/filter/search.json", params: { q: "cool" } + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["results"].map { |j| j["id"] }).to eq(['cooltag']) + end + + it "supports Chinese and Russian" do + tag_names = ['房地产', 'тема-в-разработке'] + tag_names.each { |name| Fabricate(:tag, name: name) } + + get "/tags/filter/search.json", params: { q: '房' } + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["results"].map { |j| j["id"] }).to eq(['房地产']) + + get "/tags/filter/search.json", params: { q: 'тема' } + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["results"].map { |j| j["id"] }).to eq(['тема-в-разработке']) + end + end + end + + describe '#destroy' do + context 'tagging enabled' do + before do + sign_in(Fabricate(:admin)) + end + + context 'with an existent tag name' do + it 'deletes the tag' do + tag = Fabricate(:tag) + delete "/tags/#{tag.name}.json" + expect(response).to be_success + expect(Tag.where(id: tag.id)).to be_empty + end + end + + context 'with a nonexistent tag name' do + it 'returns a tag not found message' do + delete "/tags/doesntexists.json" + expect(response).not_to be_success + json = ::JSON.parse(response.body) + expect(json['error_type']).to eq('not_found') + end + end + end + end end From 685083491e08c6147f7162a953eabc177ab3da27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 4 Jun 2018 16:57:12 +0200 Subject: [PATCH 0026/1439] FEATURE: StackOverflow importer --- Gemfile | 1 + Gemfile.lock | 2 +- script/import_scripts/stack_overflow.rb | 290 ++++++++++++++++++++++++ 3 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 script/import_scripts/stack_overflow.rb diff --git a/Gemfile b/Gemfile index f5a03d7d5d..daf906ca0d 100644 --- a/Gemfile +++ b/Gemfile @@ -184,6 +184,7 @@ if ENV["IMPORT"] == "1" gem 'sqlite3', '~> 1.3.13' gem 'ruby-bbcode-to-md', github: 'nlalonde/ruby-bbcode-to-md' gem 'reverse_markdown' + gem 'tiny_tds' end gem 'webpush', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 50f5b5c693..99ed6d189c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -505,4 +505,4 @@ DEPENDENCIES webpush BUNDLED WITH - 1.16.1 + 1.16.2 diff --git a/script/import_scripts/stack_overflow.rb b/script/import_scripts/stack_overflow.rb new file mode 100644 index 0000000000..5bef8e127d --- /dev/null +++ b/script/import_scripts/stack_overflow.rb @@ -0,0 +1,290 @@ +# cf. https://github.com/rails-sqlserver/tiny_tds#install +require "tiny_tds" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") + +class ImportScripts::StackOverflow < ImportScripts::Base + + BATCH_SIZE ||= 1000 + + def initialize + super + + @client = TinyTds::Client.new( + host: ENV["DB_HOST"], + username: ENV["DB_USERNAME"], + password: ENV["DB_PASSWORD"], + database: ENV["DB_NAME"], + ) + end + + def execute + SiteSetting.tagging_enabled = true + + # TODO: import_groups + import_users + + import_topics + import_posts + + import_likes + + mark_topics_as_solved + end + + def import_users + puts "", "Importing users..." + + last_user_id = -1 + total = query("SELECT COUNT(*) count FROM Users WHERE Id > 0").first["count"] + + batches(BATCH_SIZE) do |offset| + users = query(<<~SQL + SELECT TOP #{BATCH_SIZE} + Id + , UserTypeId + , CreationDate + , LastLoginDate + , LastLoginIP + , Email + , DisplayName + , WebsiteUrl + , RealName + , Location + , Birthday + , ProfileImageUrl + FROM Users + WHERE Id > 0 + AND Id > #{last_user_id} + ORDER BY Id + SQL + ).to_a + + break if users.empty? + + last_user_id = users[-1]["Id"] + user_ids = users.map { |u| u["Id"] } + + next if all_records_exist?(:users, user_ids) + + create_users(users, total: total, offset: offset) do |u| + { + id: u["Id"], + admin: u["UserTypeId"] == 4, + created_at: u["CreationDate"], + last_seen_at: u["LastLoginDate"], + ip_address: u["LastLoginIP"], + email: u["Email"], + username: u["DisplayName"], + website: u["WebsiteUrl"], + name: u["RealName"], + location: u["Location"], + date_of_birth: u["Birthday"], + post_create_action: proc do |user| + if u["ProfileImageUrl"].present? + UserAvatar.import_url_for_user(u["ProfileImageUrl"], user) rescue nil + end + end + } + end + end + end + + def import_topics + puts "", "Importing topics..." + + last_post_id = -1 + total = query("SELECT COUNT(*) count FROM Posts WHERE PostTypeId IN (1,3)").first["count"] + + batches(BATCH_SIZE) do |offset| + posts = query(<<~SQL + SELECT TOP #{BATCH_SIZE} + Id + , PostTypeId + , CreationDate + , Body + , OwnerUserId + , Title + , Tags + , DeletionDate + , CASE WHEN (ClosedDate IS NOT NULL OR LockedDate IS NOT NULL) THEN 1 ELSE 0 END AS Closed + FROM Posts + WHERE PostTypeId IN (1,3) + AND Id > #{last_post_id} + ORDER BY Id + SQL + ).to_a + + break if posts.empty? + + last_post_id = posts[-1]["Id"] + post_ids = posts.map { |p| p["Id"] } + + next if all_records_exist?(:posts, post_ids) + + create_posts(posts, total: total, offset: offset) do |p| + { + id: p["Id"], + wiki: p["PostTypeId"] == 3, + created_at: p["CreationDate"], + raw: HtmlToMarkdown.new(p["Body"]).to_markdown, + user_id: user_id_from_imported_user_id(p["OwnerUserId"]) || -1, + title: p["Title"], + tags: p["Tags"].split("|"), + deleted_at: p["DeletionDate"], + closed: p["Closed"] == 1, + } + end + end + end + + def import_posts + puts "", "Importing posts..." + + last_post_id = -1 + total = query("SELECT COUNT(*) count FROM Posts WHERE PostTypeId = 2").first["count"] + + query("SELECT COUNT(*) count FROM PostComments WHERE PostId IN (SELECT Id FROM Posts WHERE PostTypeId = 2)").first["count"] + + batches(BATCH_SIZE) do |offset| + posts = query(<<~SQL + SELECT TOP #{BATCH_SIZE} + Id + , CreationDate + , Body + , OwnerUserId AS UserId + , ParentId + , IsAcceptedAnswer + FROM Posts + WHERE PostTypeId = 2 + AND Id > #{last_post_id} + ORDER BY Id + SQL + ).to_a + + break if posts.empty? + + last_post_id = posts[-1]["Id"] + post_ids = posts.map { |p| p["Id"] } + + comments = query(<<~SQL + SELECT CONCAT('Comment-', Id) AS Id + , PostId AS ParentId + , Text AS Body + , CreationDate + , UserId + FROM PostComments + WHERE PostId IN (#{post_ids.join(",")}) + ORDER BY Id + SQL + ).to_a + + posts_and_comments = (posts + comments).sort_by { |p| p["CreationDate"] } + post_and_comment_ids = posts_and_comments.map { |p| p["Id"] } + + next if all_records_exist?(:posts, post_and_comment_ids) + + create_posts(posts_and_comments) do |p| + next unless t = topic_lookup_from_imported_post_id(p["ParentId"]) + + post = { + id: p["Id"], + created_at: p["CreationDate"], + raw: HtmlToMarkdown.new(p["Body"]).to_markdown, + user_id: user_id_from_imported_user_id(p["UserId"]) || -1, + topic_id: t[:topic_id], + reply_to_post_number: t[:post_number], + } + + post[:custom_fields] = { is_accepted_answer: true } if p["IsAcceptedAnswer"] + + post + end + end + end + + LIKE ||= PostActionType.types[:like] + + def import_likes + puts "", "Importing likes..." + + last_like_id = -1 + total = query("SELECT COUNT(*) count FROM Posts2Votes WHERE VoteTypeId = 2 AND DeletionDate IS NULL").first["count"] + + batches(BATCH_SIZE) do |offset| + likes = query(<<~SQL + SELECT TOP #{BATCH_SIZE} + Id + , PostId + , UserId + , CreationDate + FROM Posts2Votes + WHERE VoteTypeId = 2 + AND DeletionDate IS NULL + AND Id > #{last_like_id} + ORDER BY Id + SQL + ).to_a + + break if likes.empty? + + last_like_id = likes[-1]["Id"] + + likes.each do |l| + next unless user_id = user_id_from_imported_user_id(l["UserId"]) + next unless post_id = post_id_from_imported_post_id(l["PostId"]) + next unless user = User.find_by(id: user_id) + next unless post = Post.find_by(id: post_id) + PostAction.act(user, post, LIKE) rescue nil + end + end + + last_like_id = -1 + total = query("SELECT COUNT(*) count FROM Comments2Votes WHERE VoteTypeId = 2 AND DeletionDate IS NULL").first["count"] + + batches(BATCH_SIZE) do |offset| + likes = query(<<~SQL + SELECT TOP #{BATCH_SIZE} + Id + , CONCAT('Comment-', PostCommentId) AS PostCommentId + , UserId + , CreationDate + FROM Comments2Votes + WHERE VoteTypeId = 2 + AND DeletionDate IS NULL + AND Id > #{last_like_id} + ORDER BY Id + SQL + ).to_a + + break if likes.empty? + + last_like_id = likes[-1]["Id"] + + likes.each do |l| + next unless user_id = user_id_from_imported_user_id(l["UserId"]) + next unless post_id = post_id_from_imported_post_id(l["PostCommentId"]) + next unless user = User.find_by(id: user_id) + next unless post = Post.find_by(id: post_id) + PostAction.act(user, post, LIKE) rescue nil + end + end + end + + def mark_topics_as_solved + puts "", "Marking topics as solved..." + + Topic.exec_sql <<~SQL + INSERT INTO topic_custom_fields (name, value, topic_id, created_at, updated_at) + SELECT 'accepted_answer_post_id', pcf.post_id, p.topic_id, p.created_at, p.created_at + FROM post_custom_fields pcf + JOIN posts p ON p.id = pcf.post_id + WHERE pcf.name = 'is_accepted_answer' + SQL + end + + def query(sql) + @client.execute(sql) + end + +end + +ImportScripts::StackOverflow.new.perform From 46fc57222f24add74d2d075eb36663565967622c Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Sat, 2 Jun 2018 19:27:52 +0530 Subject: [PATCH 0027/1439] FEATURE: improve handling of site setting secrets --- .../admin/mixins/setting-component.js.es6 | 9 ++++++-- .../templates/components/site-setting.hbs | 5 +++- .../components/site-settings/string.hbs | 2 ++ .../stylesheets/common/admin/admin_base.scss | 2 +- config/site_settings.yml | 17 +++++++++++--- lib/site_setting_extension.rb | 13 +++++++++-- .../components/site_setting_extension_spec.rb | 23 ++++++++++++++++++- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/admin/mixins/setting-component.js.es6 b/app/assets/javascripts/admin/mixins/setting-component.js.es6 index 71fc679f8d..e0da9d0a82 100644 --- a/app/assets/javascripts/admin/mixins/setting-component.js.es6 +++ b/app/assets/javascripts/admin/mixins/setting-component.js.es6 @@ -16,6 +16,7 @@ export default Ember.Mixin.create({ classNameBindings: [':row', ':setting', 'setting.overridden', 'typeClass'], content: Ember.computed.alias('setting'), validationMessage: null, + isSecret: Ember.computed.oneWay('setting.secret'), @computed("buffered.value", "setting.value") dirty(bufferVal, settingVal) { @@ -95,13 +96,17 @@ export default Ember.Mixin.create({ }); }, + cancel() { + this.rollbackBuffer(); + }, + resetDefault() { this.set('buffered.value', this.get('setting.default')); this._save(); }, - cancel() { - this.rollbackBuffer(); + toggleSecret() { + this.toggleProperty('isSecret'); } } }); diff --git a/app/assets/javascripts/admin/templates/components/site-setting.hbs b/app/assets/javascripts/admin/templates/components/site-setting.hbs index e91922f7a7..03e5433fd0 100644 --- a/app/assets/javascripts/admin/templates/components/site-setting.hbs +++ b/app/assets/javascripts/admin/templates/components/site-setting.hbs @@ -2,7 +2,7 @@

{{unbound settingName}}

- {{component componentName setting=setting value=buffered.value validationMessage=validationMessage preview=preview}} + {{component componentName setting=setting value=buffered.value validationMessage=validationMessage preview=preview isSecret=isSecret}}
{{#if dirty}}
@@ -10,5 +10,8 @@ {{d-button class="cancel" action="cancel" icon="times"}}
{{else if setting.overridden}} + {{#if setting.secret}} + {{d-button action="toggleSecret" icon="eye-slash"}} + {{/if}} {{d-button action="resetDefault" icon="undo" label="admin.settings.reset"}} {{/if}} diff --git a/app/assets/javascripts/admin/templates/components/site-settings/string.hbs b/app/assets/javascripts/admin/templates/components/site-settings/string.hbs index 77e254b42f..a2c53a1ee6 100644 --- a/app/assets/javascripts/admin/templates/components/site-settings/string.hbs +++ b/app/assets/javascripts/admin/templates/components/site-settings/string.hbs @@ -1,5 +1,7 @@ {{#if setting.textarea}} {{textarea value=value classNames="input-setting-textarea"}} +{{else if isSecret}} + {{input type="password" value=value classNames="input-setting-string"}} {{else}} {{text-field value=value classNames="input-setting-string"}} {{/if}} diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index 5557f7c795..9ec5ee5f9e 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -575,7 +575,7 @@ $mobile-breakpoint: 700px; } .setting.overridden.string { - input[type=text], textarea { + input[type=text], input[type=password], textarea { background-color: $highlight-medium; } } diff --git a/config/site_settings.yml b/config/site_settings.yml index 6686036b76..6b4bd9d0a1 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -8,6 +8,7 @@ # regex - A regex that the value must match. # validator - The name of the class that will be use to validate the value of the setting. # allow_any - For choice settings allow items not specified in the choice list (default true) +# secret - Set to true if input type should be password and value needs to be scrubbed from logs (default false). # enum - The setting has a fixed set of allowed values, and only one can be chosen. # Set to the class name that defines the set. # shadowed_by_global - "Shadow" a site setting with a GlobalSetting. If the GlobalSetting @@ -274,7 +275,9 @@ login: client: true default: false google_oauth2_client_id: '' - google_oauth2_client_secret: '' + google_oauth2_client_secret: + default: '' + secret: true google_oauth2_prompt: default: '' type: list @@ -297,6 +300,7 @@ login: twitter_consumer_secret: default: '' regex: "^[\\w+-]+$" + secret: true enable_instagram_logins: client: true default: false @@ -306,6 +310,7 @@ login: instagram_consumer_secret: default: '' regex: "^[a-z0-9]+$" + secret: true enable_facebook_logins: client: true default: false @@ -315,6 +320,7 @@ login: facebook_app_secret: default: '' regex: "^[a-f0-9]+$" + secret: true enable_github_logins: client: true default: false @@ -324,6 +330,7 @@ login: github_client_secret: default: '' regex: "^[a-f0-9]+$" + secret: true enable_sso: client: true default: false @@ -337,7 +344,9 @@ login: sso_url: default: '' regex: '^https?:\/\/.+[^\/]$' - sso_secret: '' + sso_secret: + default: '' + secret: true sso_overrides_groups: false sso_overrides_bio: false sso_overrides_email: @@ -884,7 +893,9 @@ files: client: true s3_use_iam_profile: false s3_access_key_id: '' - s3_secret_access_key: '' + s3_secret_access_key: + default: '' + secret: true s3_region: default: 'us-east-1' enum: 'S3RegionSiteSetting' diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index 412ded8bfd..8efee07032 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -66,6 +66,10 @@ module SiteSettingExtension @previews ||= {} end + def secret_settings + @secret_settings ||= [] + end + def setting(name_arg, default = nil, opts = {}) name = name_arg.to_sym @@ -106,6 +110,10 @@ module SiteSettingExtension previews[name] = opts[:preview] end + if opts[:secret] + secret_settings << name + end + type_supervisor.load_setting( name, opts.extract!(*SiteSettings::TypeSupervisor::CONSUMED_OPTS) @@ -149,7 +157,8 @@ module SiteSettingExtension default: defaults[s].to_s, value: value.to_s, category: categories[s], - preview: previews[s] + preview: previews[s], + secret: secret_settings.include?(s) }.merge(type_supervisor.type_hash(s)) opts @@ -284,7 +293,7 @@ module SiteSettingExtension prev_value = send(name) set(name, value) if has_setting?(name) - value = prev_value = "[FILTERED]" if name.to_s =~ /_secret/ + value = prev_value = "[FILTERED]" if secret_settings.include?(name.to_sym) StaffActionLogger.new(user).log_site_setting_change(name, prev_value, value) end end diff --git a/spec/components/site_setting_extension_spec.rb b/spec/components/site_setting_extension_spec.rb index 4171b9db4c..1c8491c009 100644 --- a/spec/components/site_setting_extension_spec.rb +++ b/spec/components/site_setting_extension_spec.rb @@ -439,7 +439,7 @@ describe SiteSettingExtension do describe ".set_and_log" do before do - settings.setting(:s3_secret_access_key, "old_secret_key") + settings.setting(:s3_secret_access_key, "old_secret_key", secret: true) settings.setting(:title, "Discourse v1") settings.refresh! end @@ -592,6 +592,27 @@ describe SiteSettingExtension do end end + describe "secret" do + before do + settings.setting(:superman_identity, 'Clark Kent', secret: true) + settings.refresh! + end + + it "is in the `secret_settings` collection" do + expect(settings.secret_settings.include?(:superman_identity)).to eq(true) + end + + it "can be retrieved" do + expect(settings.superman_identity).to eq("Clark Kent") + end + + it "is present in all_settings by default" do + secret_setting = settings.all_settings.find { |s| s[:setting] == :superman_identity } + expect(secret_setting).to be_present + expect(secret_setting[:secret]).to eq(true) + end + end + describe 'locale default overrides are respected' do before do settings.setting(:test_override, 'default', locale_default: { zh_CN: 'cn' }) From 085eaaf18d153f8a797921805d5b1c1695627deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 4 Jun 2018 18:40:57 +0200 Subject: [PATCH 0028/1439] FIX: always delete invalid upload records --- app/jobs/scheduled/clean_up_uploads.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/jobs/scheduled/clean_up_uploads.rb b/app/jobs/scheduled/clean_up_uploads.rb index 75d53dd283..dec8b0ec48 100644 --- a/app/jobs/scheduled/clean_up_uploads.rb +++ b/app/jobs/scheduled/clean_up_uploads.rb @@ -3,6 +3,15 @@ module Jobs every 1.hour def execute(args) + grace_period = [SiteSetting.clean_orphan_uploads_grace_period_hours, 1].max + + # always remove invalid upload records + Upload + .where("retain_hours IS NULL OR created_at < current_timestamp - interval '1 hour' * retain_hours") + .where("created_at < ?", grace_period.hour.ago) + .where(url: nil) + .destroy_all + return unless SiteSetting.clean_up_uploads? base_url = Discourse.store.internal? ? Discourse.store.relative_base_url : Discourse.store.absolute_base_url @@ -29,8 +38,6 @@ module Jobs end end.compact.uniq - grace_period = [SiteSetting.clean_orphan_uploads_grace_period_hours, 1].max - result = Upload.where("uploads.retain_hours IS NULL OR uploads.created_at < current_timestamp - interval '1 hour' * uploads.retain_hours") .where("uploads.created_at < ?", grace_period.hour.ago) .joins("LEFT JOIN post_uploads pu ON pu.upload_id = uploads.id") From ab8cdd6b5b3b7d9ece259fc127b38ca35516bcb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 4 Jun 2018 18:43:00 +0200 Subject: [PATCH 0029/1439] Upload.url can't be NULL --- app/jobs/scheduled/clean_up_uploads.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/jobs/scheduled/clean_up_uploads.rb b/app/jobs/scheduled/clean_up_uploads.rb index dec8b0ec48..d2d2cfe964 100644 --- a/app/jobs/scheduled/clean_up_uploads.rb +++ b/app/jobs/scheduled/clean_up_uploads.rb @@ -9,7 +9,7 @@ module Jobs Upload .where("retain_hours IS NULL OR created_at < current_timestamp - interval '1 hour' * retain_hours") .where("created_at < ?", grace_period.hour.ago) - .where(url: nil) + .where(url: "") .destroy_all return unless SiteSetting.clean_up_uploads? From 6024fb84cc0f0b8332d40dc7c42dd53cd56c06ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 4 Jun 2018 19:06:52 +0200 Subject: [PATCH 0030/1439] make rubocop happy --- app/jobs/scheduled/clean_up_uploads.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/jobs/scheduled/clean_up_uploads.rb b/app/jobs/scheduled/clean_up_uploads.rb index d2d2cfe964..d84fddce30 100644 --- a/app/jobs/scheduled/clean_up_uploads.rb +++ b/app/jobs/scheduled/clean_up_uploads.rb @@ -4,14 +4,14 @@ module Jobs def execute(args) grace_period = [SiteSetting.clean_orphan_uploads_grace_period_hours, 1].max - + # always remove invalid upload records Upload .where("retain_hours IS NULL OR created_at < current_timestamp - interval '1 hour' * retain_hours") .where("created_at < ?", grace_period.hour.ago) .where(url: "") .destroy_all - + return unless SiteSetting.clean_up_uploads? base_url = Discourse.store.internal? ? Discourse.store.relative_base_url : Discourse.store.absolute_base_url From fab59c66f0eff49fdadd7a50b64a7e4a7ae43970 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 4 Jun 2018 15:43:26 -0400 Subject: [PATCH 0031/1439] FIX: Protection against dangling category group records --- app/models/category.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/category.rb b/app/models/category.rb index 4d042500af..379cc5acc7 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -310,7 +310,9 @@ SQL def permissions_params hash = {} category_groups.includes(:group).each do |category_group| - hash[category_group.group_name] = category_group.permission_type + if category_group.group.present? + hash[category_group.group_name] = category_group.permission_type + end end hash end From 40b3efacaa4a0f2e29011464735f4256ba7129ce Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 5 Jun 2018 01:18:57 +0200 Subject: [PATCH 0032/1439] FIX: sharing popup not showing on macos/chrome Despite `navigator.share` being defined the call was failing with this error: ``` sharing DOMException: Internal error: could not connect to Web Share interface. ``` --- .../discourse/components/share-popup.js.es6 | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/discourse/components/share-popup.js.es6 b/app/assets/javascripts/discourse/components/share-popup.js.es6 index 54ffeaa21f..5705f3be59 100644 --- a/app/assets/javascripts/discourse/components/share-popup.js.es6 +++ b/app/assets/javascripts/discourse/components/share-popup.js.es6 @@ -83,10 +83,7 @@ export default Ember.Component.extend({ _webShare(url) { // We can pass title and text too, but most share targets do their own oneboxing - navigator.share({ - url: url - }) - .catch((error) => console.warn('Error sharing', error)); + return navigator.share({ url }); }, didInsertElement() { @@ -118,7 +115,13 @@ export default Ember.Component.extend({ // use native webshare only when the user clicks on the "chain" icon // navigator.share needs HTTPS, returns undefined on HTTP if (navigator.share && !$currentTarget.hasClass('post-date')) { - this._webShare(url); + this._webShare(url) + .catch(error => { + console.warn('Error sharing', error); + + // if navigator fails for unexpected reason fallback to popup + this._showUrl($currentTarget, url); + }); } else { this._showUrl($currentTarget, url); } From dcba320bf6ef7a30069483323477f51997f1c48e Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 09:30:02 +0800 Subject: [PATCH 0033/1439] Remove spec that isn't testing for anything. --- spec/jobs/clean_up_exports_spec.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 spec/jobs/clean_up_exports_spec.rb diff --git a/spec/jobs/clean_up_exports_spec.rb b/spec/jobs/clean_up_exports_spec.rb deleted file mode 100644 index 741ac87a30..0000000000 --- a/spec/jobs/clean_up_exports_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'rails_helper' - -require_dependency 'jobs/scheduled/clean_up_exports' - -describe Jobs::CleanUpExports do - it "runs correctly without crashing" do - Jobs::CleanUpExports.new.execute(nil) - end -end From d600e71b3da94c5122bdca1e6df0991fd2cc5850 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 09:41:40 +0800 Subject: [PATCH 0034/1439] FIX: Clean up stale `UserExport` records daily. * Add tests for `UserExport.remove_old_exports` --- app/jobs/scheduled/clean_up_exports.rb | 4 ++-- app/models/user_export.rb | 7 ++++--- spec/models/user_export_spec.rb | 28 ++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 spec/models/user_export_spec.rb diff --git a/app/jobs/scheduled/clean_up_exports.rb b/app/jobs/scheduled/clean_up_exports.rb index b439d7f71c..667d165bfa 100644 --- a/app/jobs/scheduled/clean_up_exports.rb +++ b/app/jobs/scheduled/clean_up_exports.rb @@ -1,9 +1,9 @@ module Jobs class CleanUpExports < Jobs::Scheduled - every 2.day + every 1.day def execute(args) - UserExport.remove_old_exports # delete exported CSV files older than 2 days + UserExport.remove_old_exports end end end diff --git a/app/models/user_export.rb b/app/models/user_export.rb index 10314c029b..6db61c3725 100644 --- a/app/models/user_export.rb +++ b/app/models/user_export.rb @@ -1,12 +1,13 @@ class UserExport < ActiveRecord::Base + belongs_to :user def self.remove_old_exports - UserExport.where('created_at < ?', 2.days.ago).find_each do |expired_export| - file_name = "#{expired_export.file_name}-#{expired_export.id}.csv.gz" + UserExport.where('created_at < ?', 2.days.ago).find_each do |user_export| + file_name = "#{user_export.file_name}-#{user_export.id}.csv.gz" file_path = "#{UserExport.base_directory}/#{file_name}" File.delete(file_path) if File.exist?(file_path) - expired_export.destroy + user_export.destroy! end end diff --git a/spec/models/user_export_spec.rb b/spec/models/user_export_spec.rb new file mode 100644 index 0000000000..f1d54324b1 --- /dev/null +++ b/spec/models/user_export_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe UserExport do + let(:user) { Fabricate(:user) } + + describe '.remove_old_exports' do + it 'should remove the right records' do + export = UserExport.create!( + file_name: "test", + user: user, + created_at: 3.days.ago + ) + + export2 = UserExport.create!( + file_name: "test2", + user: user, + created_at: 1.day.ago + ) + + expect do + UserExport.remove_old_exports + end.to change { UserExport.count }.by(-1) + + expect(UserExport.exists?(id: export.id)).to eq(false) + expect(UserExport.exists?(id: export2.id)).to eq(true) + end + end +end From aaea24448efc2d1d4db024a07a692db9ad510e68 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 10:03:26 +0800 Subject: [PATCH 0035/1439] DEV: Add specs for https://github.com/discourse/discourse/commit/085eaaf18d153f8a797921805d5b1c1695627deb. --- spec/jobs/clean_up_uploads_spec.rb | 93 ++++++++++++++++++------------ 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/spec/jobs/clean_up_uploads_spec.rb b/spec/jobs/clean_up_uploads_spec.rb index 6539655807..b042405821 100644 --- a/spec/jobs/clean_up_uploads_spec.rb +++ b/spec/jobs/clean_up_uploads_spec.rb @@ -4,23 +4,44 @@ require_dependency 'jobs/scheduled/clean_up_uploads' describe Jobs::CleanUpUploads do - def fabricate_upload - Fabricate(:upload, created_at: 2.hours.ago) + def fabricate_upload(attributes = {}) + Fabricate(:upload, { created_at: 2.hours.ago }.merge(attributes)) end + let(:upload) { fabricate_upload } + before do - Upload.destroy_all SiteSetting.clean_up_uploads = true SiteSetting.clean_orphan_uploads_grace_period_hours = 1 @upload = fabricate_upload end it "deletes orphan uploads" do - expect(Upload.count).to be(1) + expect do + Jobs::CleanUpUploads.new.execute(nil) + end.to change { Upload.count }.by(-1) - Jobs::CleanUpUploads.new.execute(nil) + expect(Upload.exists?(id: @upload.id)).to eq(false) + end - expect(Upload.count).to be(0) + describe 'when clean_up_uploads is disabled' do + before do + SiteSetting.clean_up_uploads = false + end + + it 'should still delete invalid upload records' do + upload2 = fabricate_upload( + url: "", + retain_hours: nil + ) + + expect do + Jobs::CleanUpUploads.new.execute(nil) + end.to change { Upload.count }.by(-1) + + expect(Upload.exists?(id: @upload.id)).to eq(true) + expect(Upload.exists?(id: upload2.id)).to eq(false) + end end it "does not clean up uploads in site settings" do @@ -29,8 +50,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: logo_upload.id)).to eq(logo_upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: logo_upload.id)).to eq(true) end it "does not clean up uploads in site settings when they use the CDN" do @@ -41,8 +62,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: logo_small_upload.id)).to eq(logo_small_upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: logo_small_upload.id)).to eq(true) end it "does not delete profile background uploads" do @@ -51,8 +72,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: profile_background_upload.id)).to eq(profile_background_upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: profile_background_upload.id)).to eq(true) end it "does not delete card background uploads" do @@ -61,8 +82,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: card_background_upload.id)).to eq(card_background_upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: card_background_upload.id)).to eq(true) end it "does not delete category logo uploads" do @@ -71,8 +92,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: category_logo_upload.id)).to eq(category_logo_upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: category_logo_upload.id)).to eq(true) end it "does not delete category background url uploads" do @@ -81,8 +102,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: category_logo_upload.id)).to eq(category_logo_upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: category_logo_upload.id)).to eq(true) end it "does not delete post uploads" do @@ -91,8 +112,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) end it "does not delete user uploaded avatar" do @@ -101,8 +122,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) end it "does not delete user gravatar" do @@ -111,8 +132,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) end it "does not delete user custom upload" do @@ -121,8 +142,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) end it "does not delete uploads in a queued post" do @@ -139,9 +160,9 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) - expect(Upload.find_by(id: upload2.id)).to eq(upload2) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) + expect(Upload.exists?(id: upload2.id)).to eq(true) end it "does not delete uploads in a draft" do @@ -152,9 +173,9 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) - expect(Upload.find_by(id: upload2.id)).to eq(upload2) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) + expect(Upload.exists?(id: upload2.id)).to eq(true) end it "does not delete custom emojis" do @@ -163,8 +184,8 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: upload.id)).to eq(upload) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: upload.id)).to eq(true) end it "does not delete user exported csv uploads" do @@ -173,7 +194,7 @@ describe Jobs::CleanUpUploads do Jobs::CleanUpUploads.new.execute(nil) - expect(Upload.find_by(id: @upload.id)).to eq(nil) - expect(Upload.find_by(id: csv_file.id)).to eq(csv_file) + expect(Upload.exists?(id: @upload.id)).to eq(false) + expect(Upload.exists?(id: csv_file.id)).to eq(true) end end From a508e6a5f6551cc923e8781bf79b5951781b4bd7 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 10:07:05 +0800 Subject: [PATCH 0036/1439] DEV: Stablize `requests/search_controller_spec`. --- spec/requests/search_controller_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb index fae6e362d7..7c8de16e56 100644 --- a/spec/requests/search_controller_spec.rb +++ b/spec/requests/search_controller_spec.rb @@ -6,6 +6,10 @@ describe SearchController do SearchIndexer.enable end + after do + $redis.flushall + end + it "can search correctly" do my_post = Fabricate(:post, raw: 'this is my really awesome post') From c27863aad2156bbad4be082768d3646b2b404d85 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 10:54:56 +0800 Subject: [PATCH 0037/1439] DEV: Better output when assertion fails in smoke test. --- test/smoke_test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/smoke_test.js b/test/smoke_test.js index 095d2b95ab..eb7beccedc 100644 --- a/test/smoke_test.js +++ b/test/smoke_test.js @@ -231,7 +231,14 @@ const path = require('path'); return promise; }, output => { - return output.match("I can even write a reply"); + const expected = "I can even write a reply"; + const matched = output.match(expected); + + if (!matched) { + console.log(`Expected '${output}' to match '${expected}'`); + } + + return matched; }); await exec("submit the topic", () => { From 79dcd794708ac2cd5722d5c7c3b8c8ff74a52a24 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 05:57:11 +0300 Subject: [PATCH 0038/1439] REFACTOR: email controller specs to requests (#5917) --- spec/controllers/email_controller_spec.rb | 128 ---------------------- spec/requests/email_controller_spec.rb | 113 +++++++++++++++++++ 2 files changed, 113 insertions(+), 128 deletions(-) delete mode 100644 spec/controllers/email_controller_spec.rb diff --git a/spec/controllers/email_controller_spec.rb b/spec/controllers/email_controller_spec.rb deleted file mode 100644 index 4fdab4cca6..0000000000 --- a/spec/controllers/email_controller_spec.rb +++ /dev/null @@ -1,128 +0,0 @@ -require 'rails_helper' - -describe EmailController do - - context '.preferences_redirect' do - - it 'requires you to be logged in' do - get :preferences_redirect, format: :json - expect(response.status).to eq(403) - end - - context 'when logged in' do - let!(:user) { log_in } - - it 'redirects to your user preferences' do - get :preferences_redirect, format: :json - expect(response).to redirect_to("/u/#{user.username}/preferences") - end - end - - end - - context '.unsubscribe' do - - render_views - - it 'displays logo ut button if wrong user logged in' do - log_in_user Fabricate(:admin) - user = Fabricate(:user) - key = UnsubscribeKey.create_key_for(user, "digest") - - get :unsubscribe, params: { key: key } - - expect(response.body).to include(I18n.t("unsubscribe.log_out")) - expect(response.body).to include(I18n.t("unsubscribe.different_user_description")) - end - - it 'displays not found if key is not found' do - get :unsubscribe, params: { key: SecureRandom.hex } - expect(response.body).to include(CGI.escapeHTML(I18n.t("unsubscribe.not_found_description"))) - end - - it 'correctly handles mailing list mode' do - - user = Fabricate(:user) - key = UnsubscribeKey.create_key_for(user, "digest") - - user.user_option.update_columns(mailing_list_mode: true) - - get :unsubscribe, params: { key: key } - expect(response.body).to include(I18n.t("unsubscribe.mailing_list_mode")) - - SiteSetting.disable_mailing_list_mode = true - - get :unsubscribe, params: { key: key } - expect(response.body).not_to include(I18n.t("unsubscribe.mailing_list_mode")) - - user.user_option.update_columns(mailing_list_mode: false) - SiteSetting.disable_mailing_list_mode = false - - get :unsubscribe, params: { key: key } - expect(response.body).not_to include(I18n.t("unsubscribe.mailing_list_mode")) - - end - - it 'correctly handles digest unsubscribe' do - - user = Fabricate(:user) - user.user_option.update_columns(email_digests: false) - key = UnsubscribeKey.create_key_for(user, "digest") - - # because we are type digest we will always show digest and it will be selected - get :unsubscribe, params: { key: key } - expect(response.body).to include(I18n.t("unsubscribe.disable_digest_emails")) - - source = Nokogiri::HTML::fragment(response.body) - expect(source.css("#disable_digest_emails")[0]["checked"]).to eq("checked") - - SiteSetting.disable_digest_emails = true - - get :unsubscribe, params: { key: key } - expect(response.body).not_to include(I18n.t("unsubscribe.disable_digest_emails")) - - SiteSetting.disable_digest_emails = false - key = UnsubscribeKey.create_key_for(user, "not_digest") - - get :unsubscribe, params: { key: key } - expect(response.body).to include(I18n.t("unsubscribe.disable_digest_emails")) - end - - it 'correctly handles watched categories' do - post = Fabricate(:post) - user = post.user - cu = CategoryUser.create!(user_id: user.id, - category_id: post.topic.category_id, - notification_level: CategoryUser.notification_levels[:watching]) - - key = UnsubscribeKey.create_key_for(user, post) - get :unsubscribe, params: { key: key } - expect(response.body).to include("unwatch_category") - - cu.destroy! - - get :unsubscribe, params: { key: key } - expect(response.body).not_to include("unwatch_category") - - end - - it 'correctly handles watched first post categories' do - post = Fabricate(:post) - user = post.user - cu = CategoryUser.create!(user_id: user.id, - category_id: post.topic.category_id, - notification_level: CategoryUser.notification_levels[:watching_first_post]) - - key = UnsubscribeKey.create_key_for(user, post) - get :unsubscribe, params: { key: key } - expect(response.body).to include("unwatch_category") - - cu.destroy! - - get :unsubscribe, params: { key: key } - expect(response.body).not_to include("unwatch_category") - - end - end - -end diff --git a/spec/requests/email_controller_spec.rb b/spec/requests/email_controller_spec.rb index 196b3b277a..188ac1807f 100644 --- a/spec/requests/email_controller_spec.rb +++ b/spec/requests/email_controller_spec.rb @@ -160,4 +160,117 @@ RSpec.describe EmailController do end end end + + context '#preferences_redirect' do + it 'requires you to be logged in' do + get "/email_preferences.json" + expect(response.status).to eq(403) + end + + context 'when logged in' do + let!(:user) { sign_in(Fabricate(:user)) } + + it 'redirects to your user preferences' do + get "/email_preferences.json" + expect(response).to redirect_to("/u/#{user.username}/preferences") + end + end + end + + context '#unsubscribe' do + it 'displays log out button if wrong user logged in' do + sign_in(Fabricate(:admin)) + user = Fabricate(:user) + key = UnsubscribeKey.create_key_for(user, "digest") + + get "/email/unsubscribe/#{key}" + + expect(response.body).to include(I18n.t("unsubscribe.log_out")) + expect(response.body).to include(I18n.t("unsubscribe.different_user_description")) + end + + it 'displays not found if key is not found' do + get "/email/unsubscribe/#{SecureRandom.hex}" + expect(response.body).to include(CGI.escapeHTML(I18n.t("unsubscribe.not_found_description"))) + end + + it 'correctly handles mailing list mode' do + user = Fabricate(:user) + key = UnsubscribeKey.create_key_for(user, "digest") + + user.user_option.update_columns(mailing_list_mode: true) + + get "/email/unsubscribe/#{key}" + expect(response.body).to include(I18n.t("unsubscribe.mailing_list_mode")) + + SiteSetting.disable_mailing_list_mode = true + + get "/email/unsubscribe/#{key}" + expect(response.body).not_to include(I18n.t("unsubscribe.mailing_list_mode")) + + user.user_option.update_columns(mailing_list_mode: false) + SiteSetting.disable_mailing_list_mode = false + + get "/email/unsubscribe/#{key}" + expect(response.body).not_to include(I18n.t("unsubscribe.mailing_list_mode")) + end + + it 'correctly handles digest unsubscribe' do + user = Fabricate(:user) + user.user_option.update_columns(email_digests: false) + key = UnsubscribeKey.create_key_for(user, "digest") + + # because we are type digest we will always show digest and it will be selected + get "/email/unsubscribe/#{key}" + expect(response.body).to include(I18n.t("unsubscribe.disable_digest_emails")) + + source = Nokogiri::HTML::fragment(response.body) + expect(source.css("#disable_digest_emails")[0]["checked"]).to eq("checked") + + SiteSetting.disable_digest_emails = true + + get "/email/unsubscribe/#{key}" + expect(response.body).not_to include(I18n.t("unsubscribe.disable_digest_emails")) + + SiteSetting.disable_digest_emails = false + key = UnsubscribeKey.create_key_for(user, "not_digest") + + get "/email/unsubscribe/#{key}" + expect(response.body).to include(I18n.t("unsubscribe.disable_digest_emails")) + end + + it 'correctly handles watched categories' do + post = Fabricate(:post) + user = post.user + cu = CategoryUser.create!(user_id: user.id, + category_id: post.topic.category_id, + notification_level: CategoryUser.notification_levels[:watching]) + + key = UnsubscribeKey.create_key_for(user, post) + get "/email/unsubscribe/#{key}" + expect(response.body).to include("unwatch_category") + + cu.destroy! + + get "/email/unsubscribe/#{key}" + expect(response.body).not_to include("unwatch_category") + end + + it 'correctly handles watched first post categories' do + post = Fabricate(:post) + user = post.user + cu = CategoryUser.create!(user_id: user.id, + category_id: post.topic.category_id, + notification_level: CategoryUser.notification_levels[:watching_first_post]) + + key = UnsubscribeKey.create_key_for(user, post) + get "/email/unsubscribe/#{key}" + expect(response.body).to include("unwatch_category") + + cu.destroy! + + get "/email/unsubscribe/#{key}" + expect(response.body).not_to include("unwatch_category") + end + end end From 22fcc04d38b48ee745c2becb73172bf773cdfee5 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 05:59:01 +0300 Subject: [PATCH 0039/1439] REFACTOR: user badges controller specs to requests (#5912) --- .../user_badges_controller_spec.rb | 84 +++++++++---------- 1 file changed, 41 insertions(+), 43 deletions(-) rename spec/{controllers => requests}/user_badges_controller_spec.rb (65%) diff --git a/spec/controllers/user_badges_controller_spec.rb b/spec/requests/user_badges_controller_spec.rb similarity index 65% rename from spec/controllers/user_badges_controller_spec.rb rename to spec/requests/user_badges_controller_spec.rb index 0d9dd609ef..20fd5d3b63 100644 --- a/spec/controllers/user_badges_controller_spec.rb +++ b/spec/requests/user_badges_controller_spec.rb @@ -8,9 +8,9 @@ describe UserBadgesController do let(:badge) { Fabricate(:badge, target_posts: true, show_posts: false) } it 'does not leak private info' do p = create_post - UserBadge.create(badge: badge, user: user, post_id: p.id, granted_by_id: -1, granted_at: Time.now) + UserBadge.create!(badge: badge, user: user, post_id: p.id, granted_by_id: -1, granted_at: Time.now) - get :index, params: { badge_id: badge.id }, format: :json + get "/user_badges.json", params: { badge_id: badge.id } expect(response).to be_success parsed = JSON.parse(response.body) @@ -21,7 +21,7 @@ describe UserBadgesController do it "fails when badges are disabled" do SiteSetting.enable_badges = false - get :index, params: { badge_id: badge.id }, format: :json + get "/user_badges.json", params: { badge_id: badge.id } expect(response.status).to eq(404) end end @@ -30,13 +30,12 @@ describe UserBadgesController do let!(:user_badge) { UserBadge.create(badge: badge, user: user, granted_by: Discourse.system_user, granted_at: Time.now) } it 'requires username or badge_id to be specified' do - expect do - get :index, format: :json - end.to raise_error(ActionController::ParameterMissing) + get "/user_badges.json" + expect(response.status).to eq(400) end it 'returns user_badges for a user' do - get :username, params: { username: user.username }, format: :json + get "/user-badges/#{user.username}.json" expect(response.status).to eq(200) parsed = JSON.parse(response.body) @@ -44,7 +43,7 @@ describe UserBadgesController do end it 'returns user_badges for a badge' do - get :index, params: { badge_id: badge.id }, format: :json + get "/user_badges.json", params: { badge_id: badge.id } expect(response.status).to eq(200) parsed = JSON.parse(response.body) @@ -52,9 +51,9 @@ describe UserBadgesController do end it 'includes counts when passed the aggregate argument' do - get :username, params: { - username: user.username, grouped: true - }, format: :json + get "/user-badges/#{user.username}.json", params: { + grouped: true + } expect(response.status).to eq(200) parsed = JSON.parse(response.body) @@ -64,17 +63,16 @@ describe UserBadgesController do context 'create' do it 'requires username to be specified' do - expect do - post :create, params: { badge_id: badge.id }, format: :json - end.to raise_error(ActionController::ParameterMissing) + post "/user_badges.json", params: { badge_id: badge.id } + expect(response.status).to eq(400) end it 'does not allow regular users to grant badges' do - log_in_user Fabricate(:user) + sign_in(Fabricate(:user)) - post :create, params: { + post "/user_badges.json", params: { badge_id: badge.id, username: user.username - }, format: :json + } expect(response.status).to eq(403) end @@ -83,15 +81,13 @@ describe UserBadgesController do admin = Fabricate(:admin) post_1 = create_post - log_in_user admin + sign_in(admin) - StaffActionLogger.any_instance.expects(:log_badge_grant).once - - post :create, params: { + post "/user_badges.json", params: { badge_id: badge.id, username: user.username, reason: Discourse.base_url + post_1.url - }, format: :json + } expect(response.status).to eq(200) @@ -100,43 +96,43 @@ describe UserBadgesController do expect(user_badge).to be_present expect(user_badge.granted_by).to eq(admin) expect(user_badge.post_id).to eq(post_1.id) + expect(UserHistory.where(acting_user: admin, target_user: user).count).to eq(1) end it 'does not grant badges from regular api calls' do Fabricate(:api_key, user: user) - post :create, params: { + post "/user_badges.json", params: { badge_id: badge.id, username: user.username, api_key: user.api_key.key - }, format: :json + } expect(response.status).to eq(403) end it 'grants badges from master api calls' do api_key = Fabricate(:api_key) - StaffActionLogger.any_instance.expects(:log_badge_grant).never - post :create, params: { + post "/user_badges.json", params: { badge_id: badge.id, username: user.username, api_key: api_key.key, api_username: "system" - }, format: :json + } expect(response.status).to eq(200) user_badge = UserBadge.find_by(user: user, badge: badge) expect(user_badge).to be_present expect(user_badge.granted_by).to eq(Discourse.system_user) + expect(UserHistory.where(acting_user: Discourse.system_user, target_user: user).count).to eq(0) end it 'will trigger :user_badge_granted' do - log_in :admin - user + sign_in(Fabricate(:admin)) - event = DiscourseEvent.track_events do - post :create, params: { + events = DiscourseEvent.track_events do + post "/user_badges.json", params: { badge_id: badge.id, username: user.username - }, format: :json - end.first + } + end.map { |event| event[:event_name] } - expect(event[:event_name]).to eq(:user_badge_granted) + expect(events).to include(:user_badge_granted) end end @@ -144,26 +140,28 @@ describe UserBadgesController do let!(:user_badge) { UserBadge.create(badge: badge, user: user, granted_by: Discourse.system_user, granted_at: Time.now) } it 'checks that the user is authorized to revoke a badge' do - delete :destroy, params: { id: user_badge.id }, format: :json + delete "/user_badges/#{user_badge.id}.json" expect(response.status).to eq(403) end it 'revokes the badge' do - log_in :admin - StaffActionLogger.any_instance.expects(:log_badge_revoke).once - delete :destroy, params: { id: user_badge.id }, format: :json + admin = Fabricate(:admin) + sign_in(admin) + delete "/user_badges/#{user_badge.id}.json" + expect(response.status).to eq(200) expect(UserBadge.find_by(id: user_badge.id)).to eq(nil) + expect(UserHistory.where(acting_user: admin, target_user: user).count).to eq(1) end it 'will trigger :user_badge_removed' do - log_in :admin + sign_in(Fabricate(:admin)) - event = DiscourseEvent.track_events do - delete :destroy, params: { id: user_badge.id }, format: :json - end.first + events = DiscourseEvent.track_events do + delete "/user_badges/#{user_badge.id}.json" + end.map { |event| event[:event_name] } - expect(event[:event_name]).to eq(:user_badge_removed) + expect(events).to include(:user_badge_removed) end end end From 475d944d741176c0f0a4a64b6c5b6aeb4f2ac174 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 06:36:08 +0300 Subject: [PATCH 0040/1439] REFACTOR: onebox controller specs to requests (#5914) --- spec/controllers/onebox_controller_spec.rb | 162 ------------------ spec/requests/onebox_controller_spec.rb | 182 +++++++++++++++++++++ 2 files changed, 182 insertions(+), 162 deletions(-) delete mode 100644 spec/controllers/onebox_controller_spec.rb create mode 100644 spec/requests/onebox_controller_spec.rb diff --git a/spec/controllers/onebox_controller_spec.rb b/spec/controllers/onebox_controller_spec.rb deleted file mode 100644 index 9e2008c848..0000000000 --- a/spec/controllers/onebox_controller_spec.rb +++ /dev/null @@ -1,162 +0,0 @@ -require 'rails_helper' - -describe OneboxController do - - let(:url) { "http://google.com" } - - it "requires the user to be logged in" do - get :show, params: { url: url }, format: :json - expect(response.status).to eq(403) - end - - describe "logged in" do - - before { @user = log_in(:admin) } - - it 'invalidates the cache if refresh is passed' do - Oneboxer.expects(:preview).with(url, invalidate_oneboxes: true, user_id: @user.id, category_id: 0, topic_id: 0) - get :show, params: { url: url, refresh: 'true' }, format: :json - end - - describe "cached onebox" do - - it "returns the cached onebox response in the body" do - onebox_html = <<~HTML - - - - - - -

body

- - - HTML - - url = "http://noodle.com/" - - stub_request(:head, url) - stub_request(:get, url).to_return(body: onebox_html).then.to_raise - - get :show, params: { url: url, refresh: "true" }, format: :json - - expect(response).to be_success - expect(response.body).to include('Fred') - expect(response.body).to include('bodycontent') - - get :show, params: { url: url }, format: :json - expect(response).to be_success - expect(response.body).to include('Fred') - expect(response.body).to include('bodycontent') - end - - end - - describe "only 1 outgoing preview per user" do - - it "returns 429" do - Oneboxer.expects(:is_previewing?).returns(true) - get :show, params: { url: url }, format: :json - expect(response.status).to eq(429) - end - - end - - describe "found onebox" do - - let(:body) { "this is the onebox body" } - - before do - Oneboxer.expects(:preview).returns(body) - get :show, params: { url: url }, format: :json - end - - it 'returns the onebox response in the body' do - expect(response).to be_success - expect(response.body).to eq(body) - end - - end - - describe "missing onebox" do - - it "returns 404 if the onebox is nil" do - Oneboxer.expects(:preview).returns(nil) - get :show, params: { url: url }, format: :json - expect(response.response_code).to eq(404) - end - - it "returns 404 if the onebox is an empty string" do - Oneboxer.expects(:preview).returns(" \t ") - get :show, params: { url: url }, format: :json - expect(response.response_code).to eq(404) - end - - end - - describe "local onebox" do - - it 'does not cache local oneboxes' do - post = create_post - url = Discourse.base_url + post.url - - get :show, params: { url: url, category_id: post.topic.category_id }, format: :json - expect(response.body).to include('blockquote') - - post.trash! - - get :show, params: { url: url, category_id: post.topic.category_id }, format: :json - expect(response.body).not_to include('blockquote') - end - end - - it 'does not onebox when you have no permission on category' do - log_in - - post = create_post - url = Discourse.base_url + post.url - - get :show, params: { url: url, category_id: post.topic.category_id }, format: :json - expect(response.body).to include('blockquote') - - post.topic.category.set_permissions(staff: :full) - post.topic.category.save - - get :show, params: { url: url, category_id: post.topic.category_id }, format: :json - expect(response.body).not_to include('blockquote') - end - - it 'does not allow onebox of PMs' do - user = log_in - - post = create_post(archetype: 'private_message', target_usernames: [user.username]) - url = Discourse.base_url + post.url - - get :show, params: { url: url }, format: :json - expect(response.body).not_to include('blockquote') - end - - it 'does not allow whisper onebox' do - log_in - - post = create_post - whisper = create_post(topic_id: post.topic_id, post_type: Post.types[:whisper]) - url = Discourse.base_url + whisper.url - - get :show, params: { url: url }, format: :json - expect(response.body).not_to include('blockquote') - end - - it 'allows onebox to public topics/posts in PM' do - log_in - - post = create_post - url = Discourse.base_url + post.url - - get :show, params: { url: url }, format: :json - expect(response.body).to include('blockquote') - end - - end - -end diff --git a/spec/requests/onebox_controller_spec.rb b/spec/requests/onebox_controller_spec.rb new file mode 100644 index 0000000000..3616c2a819 --- /dev/null +++ b/spec/requests/onebox_controller_spec.rb @@ -0,0 +1,182 @@ +require 'rails_helper' + +describe OneboxController do + + let(:url) { "http://google.com" } + + it "requires the user to be logged in" do + get "/onebox.json", params: { url: url } + expect(response.status).to eq(403) + end + + describe "logged in" do + let(:user) { Fabricate(:user) } + let(:html) do + html = <<~HTML + + + + + + +

body

+ + + HTML + html + end + + let(:html2) do + html = <<~HTML + + + + + + +

body

+ + + HTML + html + end + + def bypass_limiting + Oneboxer.onebox_previewed!(user.id) + end + + before do + sign_in(user) + end + + it 'invalidates the cache if refresh is passed' do + stub_request(:head, url) + stub_request(:get, url).to_return(status: 200, body: html).then.to_raise + + bypass_limiting + Rails.cache.delete("onebox__#{url}") + get "/onebox.json", params: { url: url } + expect(response).to be_success + expect(response.body).to include("Onebox1") + + bypass_limiting + stub_request(:get, url).to_return(status: 200, body: html2).then.to_raise + get "/onebox.json", params: { url: url, refresh: 'true' } + expect(response).to be_success + expect(response.body).to include("Onebox2") + end + + describe "cached onebox" do + it "returns the cached onebox response in the body" do + url = "http://noodle.com/" + + stub_request(:head, url) + stub_request(:get, url).to_return(body: html).then.to_raise + + get "/onebox.json", params: { url: url, refresh: "true" } + + expect(response).to be_success + expect(response.body).to include('Onebox1') + expect(response.body).to include('bodycontent') + + get "/onebox.json", params: { url: url } + expect(response).to be_success + expect(response.body).to include('Onebox1') + expect(response.body).to include('bodycontent') + end + end + + describe "only 1 outgoing preview per user" do + it "returns 429" do + Oneboxer.preview_onebox!(user.id) + + stub_request(:head, url) + stub_request(:get, url).to_return(body: html).then.to_raise + + get "/onebox.json", params: { url: url, refresh: "true" } + expect(response.status).to eq(429) + end + end + + describe "found onebox" do + it 'returns the onebox response in the body' do + stub_request(:head, url) + stub_request(:get, url).to_return(body: html).then.to_raise + get "/onebox.json", params: { url: url, refresh: "true" } + + expect(response).to be_success + expect(response.body).to include("Onebox1") + end + end + + describe "missing onebox" do + it "returns 404 if the onebox is nil" do + stub_request(:head, url) + stub_request(:get, url).to_return(body: nil).then.to_raise + get "/onebox.json", params: { url: url, refresh: "true" } + expect(response.response_code).to eq(404) + end + + it "returns 404 if the onebox is an empty string" do + stub_request(:head, url) + stub_request(:get, url).to_return(body: " \t ").then.to_raise + get "/onebox.json", params: { url: url, refresh: "true" } + expect(response.response_code).to eq(404) + end + end + + describe "local onebox" do + it 'does not cache local oneboxes' do + post = create_post + url = Discourse.base_url + post.url + + get "/onebox.json", params: { url: url, category_id: post.topic.category_id } + expect(response.body).to include('blockquote') + + post.trash! + + get "/onebox.json", params: { url: url, category_id: post.topic.category_id } + expect(response.body).not_to include('blockquote') + end + end + + it 'does not onebox when you have no permission on category' do + post = create_post + url = Discourse.base_url + post.url + + get "/onebox.json", params: { url: url, category_id: post.topic.category_id } + expect(response.body).to include('blockquote') + + post.topic.category.set_permissions(staff: :full) + post.topic.category.save + + get "/onebox.json", params: { url: url, category_id: post.topic.category_id } + expect(response.body).not_to include('blockquote') + end + + it 'does not allow onebox of PMs' do + post = create_post(archetype: 'private_message', target_usernames: [user.username]) + url = Discourse.base_url + post.url + + get "/onebox.json", params: { url: url } + expect(response.body).not_to include('blockquote') + end + + it 'does not allow whisper onebox' do + post = create_post + whisper = create_post(topic_id: post.topic_id, post_type: Post.types[:whisper]) + url = Discourse.base_url + whisper.url + + get "/onebox.json", params: { url: url } + expect(response.body).not_to include('blockquote') + end + + it 'allows onebox to public topics/posts in PM' do + post = create_post + url = Discourse.base_url + post.url + + get "/onebox.json", params: { url: url } + expect(response.body).to include('blockquote') + end + end +end From 41c4e32e6428dc2a215d6b30052bef24d3a84ec0 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 11:35:38 +0800 Subject: [PATCH 0041/1439] Initialize the v8 context after forking. --- lib/discourse.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/discourse.rb b/lib/discourse.rb index 79e5984598..92600ab61b 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -451,6 +451,7 @@ module Discourse # in case v8 was initialized we want to make sure it is nil PrettyText.reset_context + PrettyText.v8 Tilt::ES6ModuleTranspilerTemplate.reset_context if defined? Tilt::ES6ModuleTranspilerTemplate JsLocaleHelper.reset_context if defined? JsLocaleHelper From d3e610eed9e0b0b919dd639b92a5d8e14c686dcc Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 07:03:49 +0300 Subject: [PATCH 0042/1439] REFACTOR: topic controller (2) specs to requests (#5911) --- spec/controllers/topic_controller_spec.rb | 368 ---------------------- spec/requests/posts_controller_spec.rb | 69 +++- spec/requests/topics_controller_spec.rb | 247 ++++++++++++++- 3 files changed, 312 insertions(+), 372 deletions(-) delete mode 100644 spec/controllers/topic_controller_spec.rb diff --git a/spec/controllers/topic_controller_spec.rb b/spec/controllers/topic_controller_spec.rb deleted file mode 100644 index 16ecfc9e33..0000000000 --- a/spec/controllers/topic_controller_spec.rb +++ /dev/null @@ -1,368 +0,0 @@ -require 'rails_helper' - -describe TopicsController do - before do - TopicUser.stubs(:track_visit!) - end - - let :topic do - Fabricate(:post).topic - end - - def set_referer(ref) - request.env['HTTP_REFERER'] = ref - end - - def set_accept_language(locale) - request.env['HTTP_ACCEPT_LANGUAGE'] = locale - end - - describe "themes" do - let :theme do - Theme.create!(user_id: -1, name: 'bob', user_selectable: true) - end - - let :theme2 do - Theme.create!(user_id: -1, name: 'bobbob', user_selectable: true) - end - - it "selects the theme the user has selected" do - user = log_in - user.user_option.update_columns(theme_key: theme.key) - - get :show, params: { id: 666 } - expect(controller.theme_key).to eq(theme.key) - - theme.update_attribute(:user_selectable, false) - - get :show, params: { id: 666 } - expect(controller.theme_key).not_to eq(theme.key) - end - - it "can be overridden with a cookie" do - user = log_in - user.user_option.update_columns(theme_key: theme.key) - - cookies['theme_key'] = "#{theme2.key},#{user.user_option.theme_key_seq}" - - get :show, params: { id: 666 } - expect(controller.theme_key).to eq(theme2.key) - - end - - it "cookie can fail back to user if out of sync" do - user = log_in - user.user_option.update_columns(theme_key: theme.key) - cookies['theme_key'] = "#{theme2.key},#{user.user_option.theme_key_seq - 1}" - - get :show, params: { id: 666 } - expect(controller.theme_key).to eq(theme.key) - end - end - - it "doesn't store an incoming link when there's no referer" do - expect { - get :show, params: { id: topic.id }, format: :json - }.not_to change(IncomingLink, :count) - end - - it "doesn't raise an error on a very long link" do - set_referer("http://#{'a' * 2000}.com") - - expect do - get :show, params: { id: topic.id }, format: :json - end.not_to raise_error - end - - describe "has_escaped_fragment?" do - render_views - - context "when the SiteSetting is disabled" do - - it "uses the application layout even with an escaped fragment param" do - SiteSetting.enable_escaped_fragments = false - - get :show, params: { - 'topic_id' => topic.id, - 'slug' => topic.slug, - '_escaped_fragment_' => 'true' - } - - body = response.body - - expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) - expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) - end - - end - - context "when the SiteSetting is enabled" do - before do - SiteSetting.enable_escaped_fragments = true - end - - it "uses the application layout when there's no param" do - get :show, params: { topic_id: topic.id, slug: topic.slug } - - body = response.body - - expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) - expect(body).to have_tag(:meta, with: { name: 'fragment' }) - end - - it "uses the crawler layout when there's an _escaped_fragment_ param" do - get :show, params: { - topic_id: topic.id, - slug: topic.slug, - _escaped_fragment_: 'true' - } - - body = response.body - - expect(body).to have_tag(:body, with: { class: 'crawler' }) - expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) - end - end - end - - describe "print" do - render_views - - context "when the SiteSetting is enabled" do - it "uses the application layout when there's no param" do - get :show, params: { topic_id: topic.id, slug: topic.slug } - - body = response.body - - expect(body).to have_tag(:script, src: '/assets/application.js') - expect(body).to have_tag(:meta, with: { name: 'fragment' }) - end - - it "uses the crawler layout when there's an print param" do - get :show, params: { topic_id: topic.id, slug: topic.slug, print: 'true' } - - body = response.body - - expect(body).to have_tag(:body, class: 'crawler') - expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) - end - end - end - - describe 'clear_notifications' do - it 'correctly clears notifications if specified via cookie' do - notification = Fabricate(:notification) - log_in_user(notification.user) - - request.cookies['cn'] = "2828,100,#{notification.id}" - - get :show, params: { topic_id: 100, format: :json } - - expect(response.cookies['cn']).to eq nil - - notification.reload - expect(notification.read).to eq true - - end - - it 'correctly clears notifications if specified via header' do - notification = Fabricate(:notification) - log_in_user(notification.user) - - request.headers['Discourse-Clear-Notifications'] = "2828,100,#{notification.id}" - - get :show, params: { topic_id: 100, format: :json } - - notification.reload - expect(notification.read).to eq true - end - end - - describe "set_locale" do - context "allow_user_locale disabled" do - context "accept-language header differs from default locale" do - before do - SiteSetting.allow_user_locale = false - SiteSetting.default_locale = "en" - set_accept_language("fr") - end - - context "with an anonymous user" do - it "uses the default locale" do - get :show, params: { topic_id: topic.id, format: :json } - - expect(I18n.locale).to eq(:en) - end - end - - context "with a logged in user" do - it "it uses the default locale" do - user = Fabricate(:user, locale: :fr) - log_in_user(user) - - get :show, params: { topic_id: topic.id, format: :json } - - expect(I18n.locale).to eq(:en) - end - end - end - end - - context "set_locale_from_accept_language_header enabled" do - context "accept-language header differs from default locale" do - before do - SiteSetting.allow_user_locale = true - SiteSetting.set_locale_from_accept_language_header = true - SiteSetting.default_locale = "en" - set_accept_language("fr") - end - - context "with an anonymous user" do - it "uses the locale from the headers" do - get :show, params: { topic_id: topic.id, format: :json } - - expect(I18n.locale).to eq(:fr) - end - end - - context "with a logged in user" do - it "uses the user's preferred locale" do - user = Fabricate(:user, locale: :fr) - log_in_user(user) - - get :show, params: { topic_id: topic.id, format: :json } - - expect(I18n.locale).to eq(:fr) - end - end - end - - context "the preferred locale includes a region" do - it "returns the locale and region separated by an underscore" do - SiteSetting.allow_user_locale = true - SiteSetting.set_locale_from_accept_language_header = true - SiteSetting.default_locale = "en" - set_accept_language("zh-CN") - - get :show, params: { topic_id: topic.id, format: :json } - - expect(I18n.locale).to eq(:zh_CN) - end - end - - context 'accept-language header is not set' do - it 'uses the site default locale' do - SiteSetting.allow_user_locale = true - SiteSetting.default_locale = 'en' - set_accept_language('') - - get :show, params: { topic_id: topic.id, format: :json } - - expect(I18n.locale).to eq(:en) - end - end - end - end - - describe "read only header" do - it "returns no read only header by default" do - get :show, params: { topic_id: topic.id, format: :json } - expect(response.headers['Discourse-Readonly']).to eq(nil) - end - - it "returns a readonly header if the site is read only" do - Discourse.received_readonly! - get :show, params: { topic_id: topic.id, format: :json } - expect(response.headers['Discourse-Readonly']).to eq('true') - end - end -end - -describe 'api' do - - before do - ActionController::Base.allow_forgery_protection = true - end - - after do - ActionController::Base.allow_forgery_protection = false - end - - describe PostsController do - let(:user) do - Fabricate(:user) - end - - let(:post) do - Fabricate(:post) - end - - let(:api_key) { user.generate_api_key(user) } - let(:master_key) { ApiKey.create_master_key } - - # choosing an arbitrarily easy to mock trusted activity - it 'allows users with api key to bookmark posts' do - PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).once - - put :bookmark, params: { - bookmarked: "true", - post_id: post.id, - api_key: api_key.key - }, format: :json - - expect(response).to be_success - end - - it 'raises an error with a user key that does not match an optionally specified username' do - PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never - - put :bookmark, params: { - bookmarked: "true", - post_id: post.id, - api_key: api_key.key, - api_username: 'made_up' - }, format: :json - - expect(response).not_to be_success - end - - it 'allows users with a master api key to bookmark posts' do - PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).once - - put :bookmark, params: { - bookmarked: "true", - post_id: post.id, - api_key: master_key.key, - api_username: user.username - }, format: :json - - expect(response).to be_success - end - - it 'disallows phonies to bookmark posts' do - PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never - - put :bookmark, params: { - bookmarked: "true", - post_id: post.id, - api_key: SecureRandom.hex(32), - api_username: user.username - }, format: :json - - expect(response.code.to_i).to eq(403) - end - - it 'disallows blank api' do - PostAction.expects(:act).with(user, post, PostActionType.types[:bookmark]).never - - put :bookmark, params: { - bookmarked: "true", - post_id: post.id, - api_key: "", - api_username: user.username - }, format: :json - - expect(response.code.to_i).to eq(403) - end - end -end diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb index f43a5b511f..cd225dabf3 100644 --- a/spec/requests/posts_controller_spec.rb +++ b/spec/requests/posts_controller_spec.rb @@ -356,14 +356,14 @@ describe PostsController do describe '#bookmark' do include_examples 'action requires login', :put, "/posts/2/bookmark.json" + let(:post) { Fabricate(:post, user: user) } + let(:user) { Fabricate(:user) } describe 'when logged in' do before do sign_in(user) end - let(:user) { Fabricate(:user) } - let(:post) { Fabricate(:post, user: user) } let(:private_message) { Fabricate(:private_message_post) } it "raises an error if the user doesn't have permission to see the post" do @@ -423,6 +423,71 @@ describe PostsController do end end end + + context "api" do + let(:api_key) { user.generate_api_key(user) } + let(:master_key) { ApiKey.create_master_key } + + # choosing an arbitrarily easy to mock trusted activity + it 'allows users with api key to bookmark posts' do + put "/posts/#{post.id}/bookmark.json", params: { + bookmarked: "true", + api_key: api_key.key + } + + expect(response).to be_success + expect(PostAction.where( + post: post, + user: user, + post_action_type_id: PostActionType.types[:bookmark] + ).count).to eq(1) + end + + it 'raises an error with a user key that does not match an optionally specified username' do + put "/posts/#{post.id}/bookmark.json", params: { + bookmarked: "true", + api_key: api_key.key, + api_username: 'made_up' + } + + expect(response.status).to eq(403) + end + + it 'allows users with a master api key to bookmark posts' do + put "/posts/#{post.id}/bookmark.json", params: { + bookmarked: "true", + api_key: master_key.key, + api_username: user.username + } + + expect(response).to be_success + expect(PostAction.where( + post: post, + user: user, + post_action_type_id: PostActionType.types[:bookmark] + ).count).to eq(1) + end + + it 'disallows phonies to bookmark posts' do + put "/posts/#{post.id}/bookmark.json", params: { + bookmarked: "true", + api_key: SecureRandom.hex(32), + api_username: user.username + } + + expect(response.status).to eq(403) + end + + it 'disallows blank api' do + put "/posts/#{post.id}/bookmark.json", params: { + bookmarked: "true", + api_key: "", + api_username: user.username + } + + expect(response.status).to eq(403) + end + end end describe '#wiki' do diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index 597ced4be5..9c471ee1ee 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -1042,10 +1042,23 @@ RSpec.describe TopicsController do it 'renders the print view when enabled' do SiteSetting.max_prints_per_hour_per_user = 10 - - get "/t/#{topic.slug}/#{topic.id}/print" + get "/t/#{topic.slug}/#{topic.id}/print", headers: { HTTP_USER_AGENT: "Rails Testing" } expect(response).to be_successful + body = response.body + + expect(body).to have_tag(:body, class: 'crawler') + expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) + end + + it "uses the application layout when there's no param" do + SiteSetting.max_prints_per_hour_per_user = 10 + get "/t/#{topic.slug}/#{topic.id}", headers: { HTTP_USER_AGENT: "Rails Testing" } + + body = response.body + + expect(body).to have_tag(:script, src: '/assets/application.js') + expect(body).to have_tag(:meta, with: { name: 'fragment' }) end end @@ -1168,6 +1181,236 @@ RSpec.describe TopicsController do expect(response.headers['X-Robots-Tag']).to eq(nil) end + + describe "themes" do + let(:theme) { Theme.create!(user_id: -1, name: 'bob', user_selectable: true) } + let(:theme2) { Theme.create!(user_id: -1, name: 'bobbob', user_selectable: true) } + + before do + sign_in(user) + end + + it "selects the theme the user has selected" do + user.user_option.update_columns(theme_key: theme.key) + + get "/t/#{topic.id}" + expect(response).to be_redirect + expect(controller.theme_key).to eq(theme.key) + + theme.update_attribute(:user_selectable, false) + + get "/t/#{topic.id}" + expect(response).to be_redirect + expect(controller.theme_key).not_to eq(theme.key) + end + + it "can be overridden with a cookie" do + user.user_option.update_columns(theme_key: theme.key) + + cookies['theme_key'] = "#{theme2.key},#{user.user_option.theme_key_seq}" + + get "/t/#{topic.id}" + expect(response).to be_redirect + expect(controller.theme_key).to eq(theme2.key) + end + + it "cookie can fail back to user if out of sync" do + user.user_option.update_columns(theme_key: theme.key) + cookies['theme_key'] = "#{theme2.key},#{user.user_option.theme_key_seq - 1}" + + get "/t/#{topic.id}" + expect(response).to be_redirect + expect(controller.theme_key).to eq(theme.key) + end + end + + it "doesn't store an incoming link when there's no referer" do + expect { + get "/t/#{topic.id}.json" + }.not_to change(IncomingLink, :count) + expect(response).to be_success + end + + it "doesn't raise an error on a very long link" do + get "/t/#{topic.id}.json", headers: { HTTP_REFERER: "http://#{'a' * 2000}.com" } + expect(response.status).to eq(200) + end + + describe "has_escaped_fragment?" do + context "when the SiteSetting is disabled" do + it "uses the application layout even with an escaped fragment param" do + SiteSetting.enable_escaped_fragments = false + + get "/t/#{topic.slug}/#{topic.id}", params: { + _escaped_fragment_: 'true' + } + + body = response.body + + expect(response).to be_success + expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) + expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) + end + end + + context "when the SiteSetting is enabled" do + before do + SiteSetting.enable_escaped_fragments = true + end + + it "uses the application layout when there's no param" do + get "/t/#{topic.slug}/#{topic.id}" + + body = response.body + + expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) + expect(body).to have_tag(:meta, with: { name: 'fragment' }) + end + + it "uses the crawler layout when there's an _escaped_fragment_ param" do + get "/t/#{topic.slug}/#{topic.id}", params: { + _escaped_fragment_: true + }, headers: { HTTP_USER_AGENT: "Rails Testing" } + + body = response.body + + expect(response).to be_success + expect(body).to have_tag(:body, with: { class: 'crawler' }) + expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) + end + end + end + + describe 'clear_notifications' do + it 'correctly clears notifications if specified via cookie' do + notification = Fabricate(:notification) + sign_in(notification.user) + + cookies['cn'] = "2828,100,#{notification.id}" + + get "/t/#{topic.id}.json" + + expect(response).to be_success + expect(response.cookies['cn']).to eq(nil) + + notification.reload + expect(notification.read).to eq(true) + end + + it 'correctly clears notifications if specified via header' do + notification = Fabricate(:notification) + sign_in(notification.user) + + get "/t/#{topic.id}.json", headers: { "Discourse-Clear-Notifications" => "2828,100,#{notification.id}" } + + expect(response).to be_success + notification.reload + expect(notification.read).to eq(true) + end + end + + describe "set_locale" do + def headers(locale) + { HTTP_ACCEPT_LANGUAGE: locale } + end + + context "allow_user_locale disabled" do + context "accept-language header differs from default locale" do + before do + SiteSetting.allow_user_locale = false + SiteSetting.default_locale = "en" + end + + context "with an anonymous user" do + it "uses the default locale" do + get "/t/#{topic.id}.json", headers: headers("fr") + + expect(response).to be_success + expect(I18n.locale).to eq(:en) + end + end + + context "with a logged in user" do + it "it uses the default locale" do + user = Fabricate(:user, locale: :fr) + sign_in(user) + + get "/t/#{topic.id}.json", headers: headers("fr") + + expect(response).to be_success + expect(I18n.locale).to eq(:en) + end + end + end + end + + context "set_locale_from_accept_language_header enabled" do + context "accept-language header differs from default locale" do + before do + SiteSetting.allow_user_locale = true + SiteSetting.set_locale_from_accept_language_header = true + SiteSetting.default_locale = "en" + end + + context "with an anonymous user" do + it "uses the locale from the headers" do + get "/t/#{topic.id}.json", headers: headers("fr") + expect(response).to be_success + expect(I18n.locale).to eq(:fr) + end + end + + context "with a logged in user" do + it "uses the user's preferred locale" do + user = Fabricate(:user, locale: :fr) + sign_in(user) + + get "/t/#{topic.id}.json", headers: headers("fr") + expect(response).to be_success + expect(I18n.locale).to eq(:fr) + end + end + end + + context "the preferred locale includes a region" do + it "returns the locale and region separated by an underscore" do + SiteSetting.allow_user_locale = true + SiteSetting.set_locale_from_accept_language_header = true + SiteSetting.default_locale = "en" + + get "/t/#{topic.id}.json", headers: headers("zh-CN") + expect(response).to be_success + expect(I18n.locale).to eq(:zh_CN) + end + end + + context 'accept-language header is not set' do + it 'uses the site default locale' do + SiteSetting.allow_user_locale = true + SiteSetting.default_locale = 'en' + + get "/t/#{topic.id}.json", headers: headers("") + expect(response).to be_success + expect(I18n.locale).to eq(:en) + end + end + end + end + + describe "read only header" do + it "returns no read only header by default" do + get "/t/#{topic.id}.json" + expect(response).to be_success + expect(response.headers['Discourse-Readonly']).to eq(nil) + end + + it "returns a readonly header if the site is read only" do + Discourse.received_readonly! + get "/t/#{topic.id}.json" + expect(response).to be_success + expect(response.headers['Discourse-Readonly']).to eq('true') + end + end end describe '#posts' do From 478c86e0a41c71f4fe5751e2fe37ac3ac0b71a81 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 16:58:15 +0800 Subject: [PATCH 0043/1439] DEV: Update preview step to be more reliable. --- package.json | 2 +- test/smoke_test.js | 29 ++++++----------------------- yarn.lock | 16 ++++++++-------- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index 2668bc503a..df94fd9275 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,6 @@ "chrome-launcher": "^0.10.0", "chrome-remote-interface": "^0.25.4", "eslint": "^4.13.1", - "puppeteer": "^0.13.0" + "puppeteer": "^1.4.0" } } diff --git a/test/smoke_test.js b/test/smoke_test.js index eb7beccedc..5d190d13f0 100644 --- a/test/smoke_test.js +++ b/test/smoke_test.js @@ -15,7 +15,7 @@ const path = require('path'); (async () => { const browser = await puppeteer.launch({ // when debugging localy setting headless to "false" can be very helpful - headless: true, + headless: false, args: ["--disable-local-storage"] }); const page = await browser.newPage(); @@ -59,11 +59,11 @@ const path = require('path'); return exec(description, fn, assertion); }; - page.on('console', msg => console.log(`PAGE LOG: ${msg.text}`)); + page.on('console', msg => console.log(`PAGE LOG: ${msg.text()}`)); page.on('response', resp => { - if (resp.status !== 200) { - console.log("FAILED HTTP REQUEST TO " + resp.url + " Status is: " + resp.status); + if (resp.status() !== 200) { + console.log("FAILED HTTP REQUEST TO " + resp.url() + " Status is: " + resp.status()); } return resp; }); @@ -218,27 +218,10 @@ const path = require('path'); return page.type("#reply-control .d-editor-input", post); }); - await assert("waiting for the preview", () => { - let promise = page.waitForSelector(".d-editor-preview p", + await exec("waiting for the preview", () => { + return page.waitForXPath("//div[contains(@class, 'd-editor-preview') and contains(.//p, 'I can even write a reply')]", { visible: true } ); - - promise = promise.then(() => { - return page.evaluate(() => { - return document.querySelector(".d-editor-preview").innerText; - }); - }); - - return promise; - }, output => { - const expected = "I can even write a reply"; - const matched = output.match(expected); - - if (!matched) { - console.log(`Expected '${output}' to match '${expected}'`); - } - - return matched; }); await exec("submit the topic", () => { diff --git a/yarn.lock b/yarn.lock index e73d58eb46..2895facd2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -672,9 +672,9 @@ lru-cache@^4.0.1: pseudomap "^1.0.2" yallist "^2.1.2" -mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" +mime@^2.0.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369" mimic-fn@^1.0.0: version "1.1.0" @@ -795,14 +795,14 @@ pseudomap@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -puppeteer@^0.13.0: - version "0.13.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-0.13.0.tgz#2e6956205f2c640964c2107f620ae1eef8bde8fd" +puppeteer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.4.0.tgz#437f0f3450d76e437185c0bf06f446e80f184692" dependencies: - debug "^2.6.8" + debug "^3.1.0" extract-zip "^1.6.5" https-proxy-agent "^2.1.0" - mime "^1.3.4" + mime "^2.0.3" progress "^2.0.0" proxy-from-env "^1.0.0" rimraf "^2.6.1" From 32c0ff4831bf8f8c735c4baaddedaf56b29f5404 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 18:46:41 +0800 Subject: [PATCH 0044/1439] DEV: Install dependencies before running smoke test. --- lib/tasks/smoke_test.rake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/tasks/smoke_test.rake b/lib/tasks/smoke_test.rake index 87b526e7f6..7aa2a0286a 100644 --- a/lib/tasks/smoke_test.rake +++ b/lib/tasks/smoke_test.rake @@ -8,6 +8,8 @@ task "smoke:test" do abort "Chrome 59 or higher is required to run smoke tests in headless mode." end + system("yarn install --dev") + url = ENV["URL"] if !url require "#{Rails.root}/config/environment" From a276ffc7b344afbf92c10f17b224a52315074cf8 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 19:08:36 +0800 Subject: [PATCH 0045/1439] Run smoke test without sandbox for now. --- test/smoke_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/smoke_test.js b/test/smoke_test.js index 5d190d13f0..a7f3a71b3c 100644 --- a/test/smoke_test.js +++ b/test/smoke_test.js @@ -16,7 +16,7 @@ const path = require('path'); const browser = await puppeteer.launch({ // when debugging localy setting headless to "false" can be very helpful headless: false, - args: ["--disable-local-storage"] + args: ["--disable-local-storage", "--no-sandbox"] }); const page = await browser.newPage(); From bc7d9c61e6ae069555a4bacf95d1f12fcb225d15 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 5 Jun 2018 19:21:46 +0800 Subject: [PATCH 0046/1439] Revert smoke test accidentally default to non headless mode. --- test/smoke_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/smoke_test.js b/test/smoke_test.js index a7f3a71b3c..3bc3e7559b 100644 --- a/test/smoke_test.js +++ b/test/smoke_test.js @@ -15,7 +15,7 @@ const path = require('path'); (async () => { const browser = await puppeteer.launch({ // when debugging localy setting headless to "false" can be very helpful - headless: false, + headless: true, args: ["--disable-local-storage", "--no-sandbox"] }); const page = await browser.newPage(); From f8d82f135fac40c4c813751e0f6c0447ba23bd50 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Tue, 5 Jun 2018 16:26:51 +0530 Subject: [PATCH 0047/1439] FIX: do not verify group visibility when checking for mentionable/messageable --- app/controllers/groups_controller.rb | 9 ++++----- spec/requests/groups_controller_spec.rb | 24 ++++++++++++++++++++++-- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 40dab0ff3e..8ebbd66356 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -282,7 +282,7 @@ class GroupsController < ApplicationController end def mentionable - group = find_group(:name) + group = find_group(:name, ensure_can_see: false) if group render json: { mentionable: Group.mentionable(current_user).where(id: group.id).present? } @@ -292,7 +292,7 @@ class GroupsController < ApplicationController end def messageable - group = find_group(:name) + group = find_group(:name, ensure_can_see: false) if group render json: { messageable: Group.messageable(current_user).where(id: group.id).present? } @@ -468,12 +468,11 @@ class GroupsController < ApplicationController params.require(:group).permit(*permitted_params) end - def find_group(param_name) + def find_group(param_name, ensure_can_see: true) name = params.require(param_name) group = Group group = group.find_by("lower(name) = ?", name.downcase) - guardian.ensure_can_see!(group) + guardian.ensure_can_see!(group) if ensure_can_see group end - end diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb index b268542391..393b621716 100644 --- a/spec/requests/groups_controller_spec.rb +++ b/spec/requests/groups_controller_spec.rb @@ -383,13 +383,12 @@ describe GroupsController do group.update_attributes!(name: 'test') get "/groups/test/mentionable.json", params: { name: group.name } - expect(response).to be_success response_body = JSON.parse(response.body) expect(response_body["mentionable"]).to eq(false) - group.update_attributes!(mentionable_level: Group::ALIAS_LEVELS[:everyone]) + group.update_attributes!(mentionable_level: Group::ALIAS_LEVELS[:everyone], visibility_level: Group.visibility_levels[:staff]) get "/groups/test/mentionable.json", params: { name: group.name } expect(response).to be_success @@ -399,6 +398,27 @@ describe GroupsController do end end + describe '#messageable' do + it "should return the right response" do + sign_in(user) + group.update_attributes!(name: 'test') + + get "/groups/test/messageable.json", params: { name: group.name } + expect(response).to be_success + + response_body = JSON.parse(response.body) + expect(response_body["messageable"]).to eq(false) + + group.update_attributes!(messageable_level: Group::ALIAS_LEVELS[:everyone], visibility_level: Group.visibility_levels[:staff]) + + get "/groups/test/messageable.json", params: { name: group.name } + expect(response).to be_success + + response_body = JSON.parse(response.body) + expect(response_body["messageable"]).to eq(true) + end + end + describe '#update' do let(:group) do Fabricate(:group, From dc00089ab267e41006258dd500201acdc9791573 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Tue, 5 Jun 2018 18:17:23 +0530 Subject: [PATCH 0048/1439] allow codepen iframe by default --- config/site_settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index 6b4bd9d0a1..cdb475bc27 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1064,7 +1064,7 @@ security: default: '' type: list allowed_iframes: - default: 'https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?' + default: 'https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?|https://codepen.io/' type: list client: true whitelisted_crawler_user_agents: From 174bf985720f0aad627d81c4e97faaeea88b80fb Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Tue, 5 Jun 2018 18:21:21 +0530 Subject: [PATCH 0049/1439] Revert "allow codepen iframe by default" This reverts commit dc00089ab267e41006258dd500201acdc9791573. --- config/site_settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index cdb475bc27..6b4bd9d0a1 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1064,7 +1064,7 @@ security: default: '' type: list allowed_iframes: - default: 'https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?|https://codepen.io/' + default: 'https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?' type: list client: true whitelisted_crawler_user_agents: From f05ca02f13c3af0467cae2295fa194102fa7d7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 5 Jun 2018 15:49:21 +0200 Subject: [PATCH 0050/1439] FIX: unable to add new poll to post with a public poll --- plugins/poll/lib/polls_updater.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/poll/lib/polls_updater.rb b/plugins/poll/lib/polls_updater.rb index 8fa46c698f..50a4bb81b4 100644 --- a/plugins/poll/lib/polls_updater.rb +++ b/plugins/poll/lib/polls_updater.rb @@ -114,10 +114,10 @@ module DiscoursePoll private def self.private_to_public_poll?(post, previous_polls, current_polls, poll_name) - _previous_poll = previous_polls[poll_name] - current_poll = current_polls[poll_name] + previous_poll = previous_polls[poll_name] + current_poll = current_polls[poll_name] - if previous_polls["public"].nil? && current_poll["public"] == "true" + if previous_poll["public"].nil? && current_poll["public"] == "true" error = poll_name == DiscoursePoll::DEFAULT_POLL_NAME ? I18n.t("poll.default_cannot_be_made_public") : I18n.t("poll.named_cannot_be_made_public", name: poll_name) From dc61eaad37898212829723a453129acdca9d6ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 5 Jun 2018 17:13:00 +0200 Subject: [PATCH 0051/1439] FEATURE: new 'min ratio to crop' site setting --- config/locales/server.en.yml | 2 ++ config/site_settings.yml | 5 +++++ lib/cooked_post_processor.rb | 9 ++++----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 4d10b61b92..fd9451fa16 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1342,6 +1342,8 @@ en: strip_image_metadata: "Strip image metadata." + min_ratio_to_crop: "Ratio used to crop tall images. Enter the result of width / height." + enable_flash_video_onebox: "Enable embedding of swf and flv (Adobe Flash) links in oneboxes. WARNING: may introduce security risks." default_invitee_trust_level: "Default trust level (0-4) for invited users." diff --git a/config/site_settings.yml b/config/site_settings.yml index 6b4bd9d0a1..52aeb51cc6 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -941,6 +941,11 @@ files: default: true client: true strip_image_metadata: true + min_ratio_to_crop: + type: float + default: 0.45 # 90% of 18:9 + min: 0 + max: 1 trust: default_trust_level: diff --git a/lib/cooked_post_processor.rb b/lib/cooked_post_processor.rb index 1dc0306dfb..e1a44fa783 100644 --- a/lib/cooked_post_processor.rb +++ b/lib/cooked_post_processor.rb @@ -267,10 +267,6 @@ class CookedPostProcessor rescue URI::InvalidURIError end - # only crop when the image is taller than 18:9 - # we only use 90% of that to allow for a small margin - MIN_RATIO_TO_CROP ||= (9.0 / 18.0) * 0.9 - def convert_to_link!(img) src = img["src"] return if src.blank? || is_a_hyperlink?(img) @@ -288,7 +284,10 @@ class CookedPostProcessor return if original_width <= width && original_height <= height return if original_width <= SiteSetting.max_image_width && original_height <= SiteSetting.max_image_height - if crop = (original_width.to_f / original_height.to_f < MIN_RATIO_TO_CROP) + crop = SiteSetting.min_ratio_to_crop > 0 + crop &&= original_width.to_f / original_height.to_f < SiteSetting.min_ratio_to_crop + + if crop width, height = ImageSizer.crop(original_width, original_height) img["width"] = width img["height"] = height From 127398c68e782982ebc4f2853d7e2bd0ba2599e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 5 Jun 2018 18:22:42 +0200 Subject: [PATCH 0052/1439] FIX: import comments of 1st post in SE importer --- script/import_scripts/stack_overflow.rb | 91 ++++++++----------------- 1 file changed, 28 insertions(+), 63 deletions(-) diff --git a/script/import_scripts/stack_overflow.rb b/script/import_scripts/stack_overflow.rb index 5bef8e127d..1759f2eec8 100644 --- a/script/import_scripts/stack_overflow.rb +++ b/script/import_scripts/stack_overflow.rb @@ -22,12 +22,8 @@ class ImportScripts::StackOverflow < ImportScripts::Base # TODO: import_groups import_users - - import_topics import_posts - import_likes - mark_topics_as_solved end @@ -89,11 +85,12 @@ class ImportScripts::StackOverflow < ImportScripts::Base end end - def import_topics - puts "", "Importing topics..." + def import_posts + puts "", "Importing posts..." last_post_id = -1 - total = query("SELECT COUNT(*) count FROM Posts WHERE PostTypeId IN (1,3)").first["count"] + total = query("SELECT COUNT(*) count FROM Posts WHERE PostTypeId IN (1,2,3)").first["count"] + + query("SELECT COUNT(*) count FROM PostComments WHERE PostId IN (SELECT Id FROM Posts WHERE PostTypeId IN (1,2,3))").first["count"] batches(BATCH_SIZE) do |offset| posts = query(<<~SQL @@ -102,59 +99,15 @@ class ImportScripts::StackOverflow < ImportScripts::Base , PostTypeId , CreationDate , Body - , OwnerUserId + , OwnerUserId AS UserId , Title , Tags , DeletionDate - , CASE WHEN (ClosedDate IS NOT NULL OR LockedDate IS NOT NULL) THEN 1 ELSE 0 END AS Closed - FROM Posts - WHERE PostTypeId IN (1,3) - AND Id > #{last_post_id} - ORDER BY Id - SQL - ).to_a - - break if posts.empty? - - last_post_id = posts[-1]["Id"] - post_ids = posts.map { |p| p["Id"] } - - next if all_records_exist?(:posts, post_ids) - - create_posts(posts, total: total, offset: offset) do |p| - { - id: p["Id"], - wiki: p["PostTypeId"] == 3, - created_at: p["CreationDate"], - raw: HtmlToMarkdown.new(p["Body"]).to_markdown, - user_id: user_id_from_imported_user_id(p["OwnerUserId"]) || -1, - title: p["Title"], - tags: p["Tags"].split("|"), - deleted_at: p["DeletionDate"], - closed: p["Closed"] == 1, - } - end - end - end - - def import_posts - puts "", "Importing posts..." - - last_post_id = -1 - total = query("SELECT COUNT(*) count FROM Posts WHERE PostTypeId = 2").first["count"] + - query("SELECT COUNT(*) count FROM PostComments WHERE PostId IN (SELECT Id FROM Posts WHERE PostTypeId = 2)").first["count"] - - batches(BATCH_SIZE) do |offset| - posts = query(<<~SQL - SELECT TOP #{BATCH_SIZE} - Id - , CreationDate - , Body - , OwnerUserId AS UserId , ParentId , IsAcceptedAnswer + , CASE WHEN (ClosedDate IS NOT NULL OR LockedDate IS NOT NULL) THEN 1 ELSE 0 END AS Closed FROM Posts - WHERE PostTypeId = 2 + WHERE PostTypeId IN (1,2,3) AND Id > #{last_post_id} ORDER BY Id SQL @@ -168,7 +121,7 @@ class ImportScripts::StackOverflow < ImportScripts::Base comments = query(<<~SQL SELECT CONCAT('Comment-', Id) AS Id , PostId AS ParentId - , Text AS Body + , Text , CreationDate , UserId FROM PostComments @@ -182,19 +135,30 @@ class ImportScripts::StackOverflow < ImportScripts::Base next if all_records_exist?(:posts, post_and_comment_ids) - create_posts(posts_and_comments) do |p| - next unless t = topic_lookup_from_imported_post_id(p["ParentId"]) + create_posts(posts_and_comments, total: total, offset: offset) do |p| + raw = p["Body"].present? ? HtmlToMarkdown.new(p["Body"]).to_markdown : p["Text"] post = { id: p["Id"], created_at: p["CreationDate"], - raw: HtmlToMarkdown.new(p["Body"]).to_markdown, + raw: raw, user_id: user_id_from_imported_user_id(p["UserId"]) || -1, - topic_id: t[:topic_id], - reply_to_post_number: t[:post_number], } - post[:custom_fields] = { is_accepted_answer: true } if p["IsAcceptedAnswer"] + if p["Title"].present? + post[:wiki] = p["PostTypeId"] = 3 + post[:title] = p["Title"] + post[:tags] = p["Tags"].split("|") + post[:deleted_at] = p["DeletionDate"] + post[:closed] = p["Closed"] == 1 + elsif t = topic_lookup_from_imported_post_id(p["ParentId"]) + post[:custom_fields] = { is_accepted_answer: true } if p["IsAcceptedAnswer"] + post[:topic_id] = t[:topic_id] + post[:reply_to_post_number] = t[:post_number] + else + puts "", "", "#{p["Id"]} was not imported", "", "" + next + end post end @@ -204,10 +168,9 @@ class ImportScripts::StackOverflow < ImportScripts::Base LIKE ||= PostActionType.types[:like] def import_likes - puts "", "Importing likes..." + puts "", "Importing post likes..." last_like_id = -1 - total = query("SELECT COUNT(*) count FROM Posts2Votes WHERE VoteTypeId = 2 AND DeletionDate IS NULL").first["count"] batches(BATCH_SIZE) do |offset| likes = query(<<~SQL @@ -237,6 +200,8 @@ class ImportScripts::StackOverflow < ImportScripts::Base end end + puts "", "Importing comment likes..." + last_like_id = -1 total = query("SELECT COUNT(*) count FROM Comments2Votes WHERE VoteTypeId = 2 AND DeletionDate IS NULL").first["count"] From 9ba9ff187c69eab356cc451bd28b1ce68e169deb Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Tue, 5 Jun 2018 17:47:30 -0400 Subject: [PATCH 0053/1439] Add plugin outlet to admin plugins index --- app/assets/javascripts/admin/templates/plugins-index.hbs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/templates/plugins-index.hbs b/app/assets/javascripts/admin/templates/plugins-index.hbs index dc5405471b..176c3418b2 100644 --- a/app/assets/javascripts/admin/templates/plugins-index.hbs +++ b/app/assets/javascripts/admin/templates/plugins-index.hbs @@ -66,4 +66,6 @@

{{i18n "admin.plugins.none_installed"}}

{{/if}} -

{{i18n "admin.plugins.howto"}}

+

{{i18n "admin.plugins.howto"}}

+ +{{plugin-outlet name="admin-below-plugins-index" args=(hash model=model)}} From d069f4ecba09f1131058163681162fdc638cf5d2 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Wed, 6 Jun 2018 06:48:08 +0530 Subject: [PATCH 0054/1439] Revert "Revert "allow codepen iframe by default"" This reverts commit 174bf985720f0aad627d81c4e97faaeea88b80fb. --- config/site_settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index 52aeb51cc6..637fee437c 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1069,7 +1069,7 @@ security: default: '' type: list allowed_iframes: - default: 'https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?' + default: 'https://www.google.com/maps/embed?|https://www.openstreetmap.org/export/embed.html?|https://calendar.google.com/calendar/embed?|https://codepen.io/' type: list client: true whitelisted_crawler_user_agents: From a83ab01264da23cff2f372bddfb46d2b0667833f Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 6 Jun 2018 09:42:09 +0800 Subject: [PATCH 0055/1439] REFACTOR: Remove extra param for group mentionable and messableable route. --- .../javascripts/discourse/models/group.js.es6 | 4 ++-- app/controllers/groups_controller.rb | 4 ++-- spec/requests/groups_controller_spec.rb | 20 +++++++++++-------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/discourse/models/group.js.es6 b/app/assets/javascripts/discourse/models/group.js.es6 index 1fe9a1999f..ec49b5226d 100644 --- a/app/assets/javascripts/discourse/models/group.js.es6 +++ b/app/assets/javascripts/discourse/models/group.js.es6 @@ -262,11 +262,11 @@ Group.reopenClass({ }, mentionable(name) { - return ajax(`/groups/${name}/mentionable`, { data: { name } }); + return ajax(`/groups/${name}/mentionable`); }, messageable(name) { - return ajax(`/groups/${name}/messageable`, { data: { name } }); + return ajax(`/groups/${name}/messageable`); } }); diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 8ebbd66356..f0b6917597 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -282,7 +282,7 @@ class GroupsController < ApplicationController end def mentionable - group = find_group(:name, ensure_can_see: false) + group = find_group(:group_id, ensure_can_see: false) if group render json: { mentionable: Group.mentionable(current_user).where(id: group.id).present? } @@ -292,7 +292,7 @@ class GroupsController < ApplicationController end def messageable - group = find_group(:name, ensure_can_see: false) + group = find_group(:group_id, ensure_can_see: false) if group render json: { messageable: Group.messageable(current_user).where(id: group.id).present? } diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb index 393b621716..9e9e4d4d42 100644 --- a/spec/requests/groups_controller_spec.rb +++ b/spec/requests/groups_controller_spec.rb @@ -380,17 +380,19 @@ describe GroupsController do describe '#mentionable' do it "should return the right response" do sign_in(user) - group.update_attributes!(name: 'test') - get "/groups/test/mentionable.json", params: { name: group.name } + get "/groups/#{group.name}/mentionable.json" expect(response).to be_success response_body = JSON.parse(response.body) expect(response_body["mentionable"]).to eq(false) - group.update_attributes!(mentionable_level: Group::ALIAS_LEVELS[:everyone], visibility_level: Group.visibility_levels[:staff]) + group.update_attributes!( + mentionable_level: Group::ALIAS_LEVELS[:everyone], + visibility_level: Group.visibility_levels[:staff] + ) - get "/groups/test/mentionable.json", params: { name: group.name } + get "/groups/#{group.name}/mentionable.json" expect(response).to be_success response_body = JSON.parse(response.body) @@ -401,17 +403,19 @@ describe GroupsController do describe '#messageable' do it "should return the right response" do sign_in(user) - group.update_attributes!(name: 'test') - get "/groups/test/messageable.json", params: { name: group.name } + get "/groups/#{group.name}/messageable.json" expect(response).to be_success response_body = JSON.parse(response.body) expect(response_body["messageable"]).to eq(false) - group.update_attributes!(messageable_level: Group::ALIAS_LEVELS[:everyone], visibility_level: Group.visibility_levels[:staff]) + group.update!( + messageable_level: Group::ALIAS_LEVELS[:everyone], + visibility_level: Group.visibility_levels[:staff] + ) - get "/groups/test/messageable.json", params: { name: group.name } + get "/groups/#{group.name}/messageable.json" expect(response).to be_success response_body = JSON.parse(response.body) From aa5805e8b0823aa14d04cad5d65fb86b83244f10 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 6 Jun 2018 14:33:20 +0800 Subject: [PATCH 0056/1439] Revert "Initialize the v8 context after forking." This reverts commit 41c4e32e6428dc2a215d6b30052bef24d3a84ec0. --- lib/discourse.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/discourse.rb b/lib/discourse.rb index 92600ab61b..79e5984598 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -451,7 +451,6 @@ module Discourse # in case v8 was initialized we want to make sure it is nil PrettyText.reset_context - PrettyText.v8 Tilt::ES6ModuleTranspilerTemplate.reset_context if defined? Tilt::ES6ModuleTranspilerTemplate JsLocaleHelper.reset_context if defined? JsLocaleHelper From a4e6662833379908d728d803118e6860c494a91e Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 6 Jun 2018 14:45:05 +0800 Subject: [PATCH 0057/1439] FIX: Disconnects all connections in the pool before forking. * We were leaking connections as a result. Connections opened before the fork were never closed. --- config/unicorn.conf.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/unicorn.conf.rb b/config/unicorn.conf.rb index 01c800b198..3faf9f584b 100644 --- a/config/unicorn.conf.rb +++ b/config/unicorn.conf.rb @@ -210,7 +210,10 @@ before_fork do |server, worker| end - ActiveRecord::Base.connection.disconnect! + RailsMultisite::ConnectionManagement.each_connection do + ActiveRecord::Base.connection_pool.disconnect! + end + $redis._client.disconnect # Throttle the master from forking too quickly by sleeping. Due From a50cd8675a3c23113cff5d221a54086289767a5a Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 6 Jun 2018 14:55:22 +0800 Subject: [PATCH 0058/1439] FIX: Permalink route matcher should always be last. --- config/routes.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 8765881d63..1ee17cc3e1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -803,9 +803,9 @@ Discourse::Application.routes.draw do get "/qunit" => "qunit#index" end - get "*url", to: 'permalinks#show', constraints: PermalinkConstraint.new - post "/push_notifications/subscribe" => "push_notification#subscribe" post "/push_notifications/unsubscribe" => "push_notification#unsubscribe" + get "*url", to: 'permalinks#show', constraints: PermalinkConstraint.new + end From 3244fb8959f6b9514a03550f3b73844e69702432 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 12:07:55 +0300 Subject: [PATCH 0059/1439] REFACTOR: wizard controller specs to requests --- .../wizard_controller_spec.rb | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) rename spec/{controllers => requests}/wizard_controller_spec.rb (77%) diff --git a/spec/controllers/wizard_controller_spec.rb b/spec/requests/wizard_controller_spec.rb similarity index 77% rename from spec/controllers/wizard_controller_spec.rb rename to spec/requests/wizard_controller_spec.rb index 0875e31c26..c9736a03d5 100644 --- a/spec/controllers/wizard_controller_spec.rb +++ b/spec/requests/wizard_controller_spec.rb @@ -1,51 +1,47 @@ require 'rails_helper' describe WizardController do - context 'wizard enabled' do - render_views - before do SiteSetting.wizard_enabled = true end it 'needs you to be logged in' do - get :index, format: :json + get "/wizard.json" expect(response.status).to eq(403) end it 'needs you to be logged in' do - get :index + get "/wizard" # for whatever reason, no access is 404 # we may want to revisit this at some point and make it 403 expect(response.status).to eq(404) end it "raises an error if you aren't an admin" do - log_in(:moderator) - get :index, format: :json + sign_in(Fabricate(:moderator)) + get "/wizard.json" expect(response).to be_forbidden end it "raises an error if the wizard is disabled" do SiteSetting.wizard_enabled = false - log_in(:admin) - get :index, format: :json + sign_in(Fabricate(:admin)) + get "/wizard.json" expect(response).to be_forbidden end it "renders the wizard if you are an admin" do - log_in(:admin) - get :index, format: :json + sign_in(Fabricate(:admin)) + get "/wizard.json" expect(response).to be_success end it "returns JSON when the mime type is appropriate" do - log_in(:admin) - get :index, format: 'json' + sign_in(Fabricate(:admin)) + get "/wizard.json" expect(response).to be_success expect(::JSON.parse(response.body).has_key?('wizard')).to eq(true) end end - end From d8e641cd98e7550561d561a72065d2ee842dde3b Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Wed, 6 Jun 2018 18:27:30 +0530 Subject: [PATCH 0060/1439] FIX: avatar_url includes upload_path twice when local storage used --- app/controllers/session_controller.rb | 3 ++- spec/requests/session_controller_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 5a54591a0b..2d217ce8b1 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -63,7 +63,8 @@ class SessionController < ApplicationController sso.groups = current_user.groups.pluck(:name).join(",") if current_user.uploaded_avatar.present? - avatar_url = "#{Discourse.store.absolute_base_url}/#{Discourse.store.get_path_for_upload(current_user.uploaded_avatar)}" + base_url = Discourse.store.external? ? "#{Discourse.store.absolute_base_url}/" : Discourse.base_url + avatar_url = "#{base_url}#{Discourse.store.get_path_for_upload(current_user.uploaded_avatar)}" sso.avatar_url = UrlHelper.absolute Discourse.store.cdn_url(avatar_url) end diff --git a/spec/requests/session_controller_spec.rb b/spec/requests/session_controller_spec.rb index 3dfb07c583..408cb6a399 100644 --- a/spec/requests/session_controller_spec.rb +++ b/spec/requests/session_controller_spec.rb @@ -630,7 +630,7 @@ RSpec.describe SessionController do expect(sso2.profile_background_url.blank?).to_not eq(true) expect(sso2.card_background_url.blank?).to_not eq(true) - expect(sso2.avatar_url).to start_with(SiteSetting.s3_cdn_url) + expect(sso2.avatar_url).to start_with("#{SiteSetting.s3_cdn_url}/original") expect(sso2.profile_background_url).to start_with(SiteSetting.s3_cdn_url) expect(sso2.card_background_url).to start_with(SiteSetting.s3_cdn_url) end @@ -774,7 +774,7 @@ RSpec.describe SessionController do expect(sso2.profile_background_url.blank?).to_not eq(true) expect(sso2.card_background_url.blank?).to_not eq(true) - expect(sso2.avatar_url).to start_with(Discourse.base_url) + expect(sso2.avatar_url).to start_with("#{Discourse.store.absolute_base_url}/original") expect(sso2.profile_background_url).to start_with(Discourse.base_url) expect(sso2.card_background_url).to start_with(Discourse.base_url) end From 56dbbfbd2a4c70d1bf7b6382c61d6080b1a91141 Mon Sep 17 00:00:00 2001 From: Joe <33972521+hnb-ku@users.noreply.github.com> Date: Wed, 6 Jun 2018 21:02:35 +0800 Subject: [PATCH 0061/1439] FIX: user-fields layout in mobile create account form --- app/assets/stylesheets/mobile/login.scss | 33 +++++++++++++++++++----- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/mobile/login.scss b/app/assets/stylesheets/mobile/login.scss index 77e32ca9d8..63cf2ac41d 100644 --- a/app/assets/stylesheets/mobile/login.scss +++ b/app/assets/stylesheets/mobile/login.scss @@ -3,7 +3,6 @@ // create account modals .login-modal, .create-account { - .modal-inner-container { max-width: 350px; } @@ -19,9 +18,9 @@ width: 102%; padding-bottom: 10px; margin-left: -2%; - + button { - flex: 1 1 48%; + flex: 1 1 48%; max-width: 50%; margin: 1% 0 1% 2%; font-size: $font-up-1; @@ -39,10 +38,11 @@ form { display: flex; justify-content: center; + flex-direction: column; } table { - width: 100%; + // width: 100%; padding: 10px; } @@ -144,7 +144,7 @@ } #login-buttons + .login-form { - border-top: 1px solid $primary-low; + border-top: 1px solid $primary-low; } .login-form { margin-bottom: 0.75em; @@ -156,11 +156,32 @@ margin-top: 10px; padding-top: 15px; border-top: 1px solid $primary-low; + display: flex; + flex-direction: column; } .user-field.confirm { margin-top: 10px; - margin-bottom: 10px; + } + + .user-field { + display: flex; + flex-direction: column; + + .required { + display: none; // needs more work + } + > label { + width: auto; + font-weight: bold; + } + .controls { + margin-left: 0; + + .instructions { + margin-top: 5px; + } + } } } From a58fb817c01012517614ea6bad577016ab9d0449 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 6 Jun 2018 15:28:56 +0200 Subject: [PATCH 0062/1439] FIX: removes buggy/unnecessary local-dates margin --- .../assets/stylesheets/common/discourse-local-dates.scss | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss b/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss index 33abbd7c35..f3e846b842 100644 --- a/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss +++ b/plugins/discourse-local-dates/assets/stylesheets/common/discourse-local-dates.scss @@ -20,10 +20,6 @@ color: $primary-high; } } - - + .discourse-local-date { - margin-left: .5em; - } } .discourse-local-dates-create-modal-footer { From ab66215f5cfc189b28e650ac85b6dc385b024fa4 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 08:34:36 +0800 Subject: [PATCH 0063/1439] Upgrade Rails to 5.1.6. --- Gemfile.lock | 59 ++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 99ed6d189c..43213e7308 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,39 +1,39 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (5.1.4) - actionpack (= 5.1.4) - actionview (= 5.1.4) - activejob (= 5.1.4) + actionmailer (5.1.6) + actionpack (= 5.1.6) + actionview (= 5.1.6) + activejob (= 5.1.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.4) - actionview (= 5.1.4) - activesupport (= 5.1.4) + actionpack (5.1.6) + actionview (= 5.1.6) + activesupport (= 5.1.6) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.4) - activesupport (= 5.1.4) + actionview (5.1.6) + activesupport (= 5.1.6) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) active_model_serializers (0.8.3) activemodel (>= 3.0) - activejob (5.1.4) - activesupport (= 5.1.4) + activejob (5.1.6) + activesupport (= 5.1.6) globalid (>= 0.3.6) - activemodel (5.1.4) - activesupport (= 5.1.4) - activerecord (5.1.4) - activemodel (= 5.1.4) - activesupport (= 5.1.4) + activemodel (5.1.6) + activesupport (= 5.1.6) + activerecord (5.1.6) + activemodel (= 5.1.6) + activesupport (= 5.1.6) arel (~> 8.0) - activesupport (5.1.4) + activesupport (5.1.6) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) + i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.5.1) @@ -80,7 +80,7 @@ GEM cppjieba_rb (0.3.0) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.3) + crass (1.0.4) debug_inspector (0.0.3) diff-lcs (1.3) discourse_image_optim (0.24.5) @@ -103,7 +103,7 @@ GEM jquery-rails (>= 1.0.17) railties (>= 3.1) ember-source (2.13.3) - erubi (1.6.1) + erubi (1.7.1) erubis (2.7.0) excon (0.56.0) execjs (2.7.0) @@ -124,7 +124,7 @@ GEM thor (~> 0.19.1) fspath (3.1.0) gc_tracer (1.5.1) - globalid (0.4.0) + globalid (0.4.1) activesupport (>= 4.2.0) guess_html_encoding (0.0.11) hashdiff (0.3.4) @@ -134,7 +134,8 @@ GEM hkdf (0.3.0) htmlentities (4.3.4) http_accept_language (2.0.5) - i18n (0.8.6) + i18n (1.0.1) + concurrent-ruby (~> 1.0) image_size (1.5.0) in_threads (1.4.0) jmespath (1.3.1) @@ -175,7 +176,7 @@ GEM libv8 (~> 6.3) mini_suffix (0.3.0) ffi (~> 1.9) - minitest (5.10.3) + minitest (5.11.3) mocha (1.2.1) metaclass (~> 0.0.1) mock_redis (0.17.3) @@ -260,7 +261,7 @@ GEM ruby-openid (>= 2.1.8) rack-protection (2.0.1) rack - rack-test (0.7.0) + rack-test (1.0.0) rack (>= 1.0, < 3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) @@ -270,15 +271,15 @@ GEM rails_multisite (2.0.4) activerecord (> 4.2, < 6) railties (> 4.2, < 6) - railties (5.1.4) - actionpack (= 5.1.4) - activesupport (= 5.1.4) + railties (5.1.6) + actionpack (= 5.1.6) + activesupport (= 5.1.6) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) raindrops (0.19.0) - rake (12.3.0) + rake (12.3.1) rake-compiler (1.0.4) rake rb-fsevent (0.9.8) @@ -373,7 +374,7 @@ GEM thread_safe (0.3.6) tilt (2.0.7) trollop (2.1.2) - tzinfo (1.2.3) + tzinfo (1.2.5) thread_safe (~> 0.1) uglifier (3.2.0) execjs (>= 0.3.0, < 3) From cb9596e196ac09549becf75c5bfa609255a8b57c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 08:49:19 +0800 Subject: [PATCH 0064/1439] Remove invalid `hosted-site` plugin. --- lib/tasks/plugin.rake | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/tasks/plugin.rake b/lib/tasks/plugin.rake index 56cfb31207..4152286bd1 100644 --- a/lib/tasks/plugin.rake +++ b/lib/tasks/plugin.rake @@ -5,7 +5,6 @@ task 'plugin:install_all_official' do skip = Set.new([ 'customer-flair', 'discourse-nginx-performance-report', - 'hosted-site', 'lazyYT', 'poll', ]) From 78c705f5de2c53c14196c42f414975342c38aa45 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 08:57:01 +0800 Subject: [PATCH 0065/1439] Remove migration code that is no longer valid. --- db/migrate/20121113200844_bio_markdown_support.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/db/migrate/20121113200844_bio_markdown_support.rb b/db/migrate/20121113200844_bio_markdown_support.rb index 1737b65449..6ccd73d023 100644 --- a/db/migrate/20121113200844_bio_markdown_support.rb +++ b/db/migrate/20121113200844_bio_markdown_support.rb @@ -2,12 +2,6 @@ class BioMarkdownSupport < ActiveRecord::Migration[4.2] def up rename_column :users, :bio, :bio_raw add_column :users, :bio_cooked, :text, null: true - - User.where("bio_raw is NOT NULL").each do |u| - u.send(:cook) - u.save - end - end def down From 01f126e38fa8f35b99e3708988aef35e16795c31 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 09:03:16 +0800 Subject: [PATCH 0066/1439] Simplify unicorn config. --- config/unicorn.conf.rb | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/config/unicorn.conf.rb b/config/unicorn.conf.rb index 3faf9f584b..6d2026db61 100644 --- a/config/unicorn.conf.rb +++ b/config/unicorn.conf.rb @@ -118,16 +118,11 @@ before_fork do |server, worker| puts "Starting up #{sidekiqs} supervised sidekiqs" require 'demon/sidekiq' - if @stats_socket_dir - Demon::Sidekiq.after_fork do - start_stats_socket(server) - DiscourseEvent.trigger(:sidekiq_fork_started) - end - else - Demon::Sidekiq.after_fork do - DiscourseEvent.trigger(:sidekiq_fork_started) - end + Demon::Sidekiq.after_fork do + start_stats_socket(server) if @stats_socket_dir + DiscourseEvent.trigger(:sidekiq_fork_started) end + Demon::Sidekiq.start(sidekiqs) Signal.trap("SIGTSTP") do From 2bd905c6326a9e8c3588b5b243c50d88e0c1f313 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 09:49:38 +0800 Subject: [PATCH 0067/1439] Revert "Upgrade Rails to 5.1.6." This reverts commit ab66215f5cfc189b28e650ac85b6dc385b024fa4. --- Gemfile.lock | 59 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 43213e7308..99ed6d189c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,39 +1,39 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (5.1.6) - actionpack (= 5.1.6) - actionview (= 5.1.6) - activejob (= 5.1.6) + actionmailer (5.1.4) + actionpack (= 5.1.4) + actionview (= 5.1.4) + activejob (= 5.1.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.6) - actionview (= 5.1.6) - activesupport (= 5.1.6) + actionpack (5.1.4) + actionview (= 5.1.4) + activesupport (= 5.1.4) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.6) - activesupport (= 5.1.6) + actionview (5.1.4) + activesupport (= 5.1.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) active_model_serializers (0.8.3) activemodel (>= 3.0) - activejob (5.1.6) - activesupport (= 5.1.6) + activejob (5.1.4) + activesupport (= 5.1.4) globalid (>= 0.3.6) - activemodel (5.1.6) - activesupport (= 5.1.6) - activerecord (5.1.6) - activemodel (= 5.1.6) - activesupport (= 5.1.6) + activemodel (5.1.4) + activesupport (= 5.1.4) + activerecord (5.1.4) + activemodel (= 5.1.4) + activesupport (= 5.1.4) arel (~> 8.0) - activesupport (5.1.6) + activesupport (5.1.4) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) + i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.5.1) @@ -80,7 +80,7 @@ GEM cppjieba_rb (0.3.0) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.4) + crass (1.0.3) debug_inspector (0.0.3) diff-lcs (1.3) discourse_image_optim (0.24.5) @@ -103,7 +103,7 @@ GEM jquery-rails (>= 1.0.17) railties (>= 3.1) ember-source (2.13.3) - erubi (1.7.1) + erubi (1.6.1) erubis (2.7.0) excon (0.56.0) execjs (2.7.0) @@ -124,7 +124,7 @@ GEM thor (~> 0.19.1) fspath (3.1.0) gc_tracer (1.5.1) - globalid (0.4.1) + globalid (0.4.0) activesupport (>= 4.2.0) guess_html_encoding (0.0.11) hashdiff (0.3.4) @@ -134,8 +134,7 @@ GEM hkdf (0.3.0) htmlentities (4.3.4) http_accept_language (2.0.5) - i18n (1.0.1) - concurrent-ruby (~> 1.0) + i18n (0.8.6) image_size (1.5.0) in_threads (1.4.0) jmespath (1.3.1) @@ -176,7 +175,7 @@ GEM libv8 (~> 6.3) mini_suffix (0.3.0) ffi (~> 1.9) - minitest (5.11.3) + minitest (5.10.3) mocha (1.2.1) metaclass (~> 0.0.1) mock_redis (0.17.3) @@ -261,7 +260,7 @@ GEM ruby-openid (>= 2.1.8) rack-protection (2.0.1) rack - rack-test (1.0.0) + rack-test (0.7.0) rack (>= 1.0, < 3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) @@ -271,15 +270,15 @@ GEM rails_multisite (2.0.4) activerecord (> 4.2, < 6) railties (> 4.2, < 6) - railties (5.1.6) - actionpack (= 5.1.6) - activesupport (= 5.1.6) + railties (5.1.4) + actionpack (= 5.1.4) + activesupport (= 5.1.4) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) raindrops (0.19.0) - rake (12.3.1) + rake (12.3.0) rake-compiler (1.0.4) rake rb-fsevent (0.9.8) @@ -374,7 +373,7 @@ GEM thread_safe (0.3.6) tilt (2.0.7) trollop (2.1.2) - tzinfo (1.2.5) + tzinfo (1.2.3) thread_safe (~> 0.1) uglifier (3.2.0) execjs (>= 0.3.0, < 3) From 89ad2b590050fb9c8915d8aebcfe8f661e6012ea Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 5 Jun 2018 17:29:17 +1000 Subject: [PATCH 0068/1439] DEV: Rails 5.2 upgrade and global gem upgrade This updates tests to use latest rails 5 practice and updates ALL dependencies that could be updated Performance testing shows that performance has not regressed if anything it is marginally faster now. --- Gemfile | 14 +- Gemfile.lock | 284 +++++++++--------- app/controllers/application_controller.rb | 3 +- app/helpers/application_helper.rb | 7 +- app/models/concerns/trashable.rb | 8 +- app/models/invite.rb | 7 +- app/models/post.rb | 11 +- app/models/post_mover.rb | 2 +- app/models/topic.rb | 9 +- app/models/user.rb | 2 +- app/services/badge_granter.rb | 1 - lib/admin_user_index_query.rb | 3 +- lib/email/renderer.rb | 2 +- .../active_record_attribute_methods.rb | 18 ++ lib/freedom_patches/fast_pluck.rb | 31 +- lib/post_creator.rb | 2 +- lib/tasks/assets.rake | 1 - lib/topic_query_sql.rb | 13 +- package.json | 10 +- spec/components/file_store/base_store_spec.rb | 1 + .../components/migration/safe_migrate_spec.rb | 19 +- spec/components/post_revisor_spec.rb | 10 +- spec/components/search_spec.rb | 2 +- spec/components/topic_query_spec.rb | 6 +- .../validators/upload_validator_spec.rb | 1 + spec/controllers/admin/api_controller_spec.rb | 6 +- .../admin/backups_controller_spec.rb | 20 +- .../admin/badges_controller_spec.rb | 12 +- .../admin/color_schemes_controller_spec.rb | 12 +- .../admin/dashboard_controller_spec.rb | 4 +- .../admin/email_controller_spec.rb | 6 +- .../admin/emojis_controller_spec.rb | 2 +- .../admin/impersonate_controller_spec.rb | 4 +- .../admin/permalinks_controller_spec.rb | 6 +- .../admin/plugins_controller_spec.rb | 2 +- .../admin/reports_controller_spec.rb | 6 +- .../admin/screened_emails_controller_spec.rb | 2 +- .../screened_ip_addresses_controller_spec.rb | 8 +- .../admin/screened_urls_controller_spec.rb | 2 +- .../admin/site_settings_controller_spec.rb | 2 +- .../admin/site_texts_controller_spec.rb | 12 +- .../staff_action_logs_controller_spec.rb | 4 +- .../admin/themes_controller_spec.rb | 10 +- .../admin/user_fields_controller_spec.rb | 16 +- .../admin/users_controller_spec.rb | 58 ++-- .../admin/versions_controller_spec.rb | 2 +- .../admin/web_hooks_controller_spec.rb | 4 +- .../composer_messages_controller_spec.rb | 2 +- .../controllers/export_csv_controller_spec.rb | 10 +- .../extra_locales_controller_spec.rb | 6 +- .../finish_installation_controller_spec.rb | 12 +- .../inline_onebox_controller_spec.rb | 4 +- .../post_action_users_controller_spec.rb | 2 +- .../post_actions_controller_spec.rb | 6 +- .../queued_posts_controller_spec.rb | 14 +- spec/controllers/site_controller_spec.rb | 2 +- spec/controllers/steps_controller_spec.rb | 4 +- .../stylesheets_controller_spec.rb | 12 +- .../user_actions_controller_spec.rb | 2 +- .../user_avatars_controller_spec.rb | 2 +- spec/controllers/webhooks_controller_spec.rb | 10 +- spec/controllers/wizard_controller_spec.rb | 4 +- spec/fabricators/topic_fabricator.rb | 4 +- spec/jobs/toggle_topic_closed_spec.rb | 4 +- spec/models/post_action_spec.rb | 2 +- spec/models/tag_spec.rb | 42 +-- spec/models/topic_featured_users_spec.rb | 10 +- spec/models/topic_spec.rb | 15 +- spec/models/topic_timer_spec.rb | 4 + spec/requests/about_controller_spec.rb | 4 +- .../requests/admin/backups_controller_spec.rb | 8 +- .../admin/email_templates_controller_spec.rb | 10 +- .../admin/flagged_topics_controller_spec.rb | 2 +- spec/requests/admin/flags_controller_spec.rb | 13 +- .../moderation_history_controller_spec.rb | 14 +- spec/requests/admin/search_logs_spec.rb | 4 +- spec/requests/categories_controller_spec.rb | 8 +- .../directory_items_controller_spec.rb | 16 +- spec/requests/email_controller_spec.rb | 4 +- spec/requests/embed_controller_spec.rb | 10 +- spec/requests/groups_controller_spec.rb | 62 ++-- spec/requests/invites_controller_spec.rb | 38 +-- spec/requests/list_controller_spec.rb | 44 +-- .../requests/notifications_controller_spec.rb | 8 +- .../omniauth_callbacks_controller_spec.rb | 8 +- spec/requests/onebox_controller_spec.rb | 10 +- spec/requests/post_actions_controller_spec.rb | 6 +- spec/requests/posts_controller_spec.rb | 136 ++++----- spec/requests/search_controller_spec.rb | 32 +- spec/requests/session_controller_spec.rb | 56 ++-- spec/requests/static_controller_spec.rb | 10 +- spec/requests/tags_controller_spec.rb | 50 +-- spec/requests/topics_controller_spec.rb | 140 +++++---- spec/requests/uploads_controller_spec.rb | 4 +- spec/requests/user_badges_controller_spec.rb | 2 +- spec/requests/users_controller_spec.rb | 138 ++++----- spec/requests/users_email_controller_spec.rb | 20 +- spec/serializers/post_serializer_spec.rb | 13 +- spec/services/badge_granter_spec.rb | 3 +- spec/services/destroy_task_spec.rb | 8 +- spec/services/post_alerter_spec.rb | 13 +- spec/services/post_owner_changer_spec.rb | 26 +- spec/support/integration_helpers.rb | 4 +- 103 files changed, 900 insertions(+), 864 deletions(-) create mode 100644 lib/freedom_patches/active_record_attribute_methods.rb diff --git a/Gemfile b/Gemfile index daf906ca0d..60b197bdcd 100644 --- a/Gemfile +++ b/Gemfile @@ -13,13 +13,13 @@ if rails_master? gem 'rails', git: 'https://github.com/rails/rails.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else - gem 'actionmailer', '~> 5.1' - gem 'actionpack', '~> 5.1' - gem 'actionview', '~> 5.1' - gem 'activemodel', '~> 5.1' - gem 'activerecord', '~> 5.1' - gem 'activesupport', '~> 5.1' - gem 'railties', '~> 5.1' + gem 'actionmailer', '~> 5.2' + gem 'actionpack', '~> 5.2' + gem 'actionview', '~> 5.2' + gem 'activemodel', '~> 5.2' + gem 'activerecord', '~> 5.2' + gem 'activesupport', '~> 5.2' + gem 'railties', '~> 5.2' gem 'sprockets-rails' gem 'seed-fu' end diff --git a/Gemfile.lock b/Gemfile.lock index 99ed6d189c..3d018a3270 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,86 +1,88 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (5.1.4) - actionpack (= 5.1.4) - actionview (= 5.1.4) - activejob (= 5.1.4) + actionmailer (5.2.0) + actionpack (= 5.2.0) + actionview (= 5.2.0) + activejob (= 5.2.0) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.4) - actionview (= 5.1.4) - activesupport (= 5.1.4) + actionpack (5.2.0) + actionview (= 5.2.0) + activesupport (= 5.2.0) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.4) - activesupport (= 5.1.4) + actionview (5.2.0) + activesupport (= 5.2.0) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - active_model_serializers (0.8.3) + active_model_serializers (0.8.4) activemodel (>= 3.0) - activejob (5.1.4) - activesupport (= 5.1.4) + activejob (5.2.0) + activesupport (= 5.2.0) globalid (>= 0.3.6) - activemodel (5.1.4) - activesupport (= 5.1.4) - activerecord (5.1.4) - activemodel (= 5.1.4) - activesupport (= 5.1.4) - arel (~> 8.0) - activesupport (5.1.4) + activemodel (5.2.0) + activesupport (= 5.2.0) + activerecord (5.2.0) + activemodel (= 5.2.0) + activesupport (= 5.2.0) + arel (>= 9.0) + activesupport (5.2.0) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) + i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) - addressable (2.5.1) - public_suffix (~> 2.0, >= 2.0.2) - annotate (2.7.2) + addressable (2.5.2) + public_suffix (>= 2.0.2, < 4.0) + annotate (2.7.4) activerecord (>= 3.2, < 6.0) rake (>= 10.4, < 13.0) - arel (8.0.0) + arel (9.0.0) ast (2.4.0) - aws-partitions (1.24.0) - aws-sdk-core (3.6.0) + aws-eventstream (1.0.0) + aws-partitions (1.91.0) + aws-sdk-core (3.21.2) + aws-eventstream (~> 1.0) aws-partitions (~> 1.0) aws-sigv4 (~> 1.0) jmespath (~> 1.0) - aws-sdk-kms (1.2.0) + aws-sdk-kms (1.5.0) aws-sdk-core (~> 3) aws-sigv4 (~> 1.0) - aws-sdk-s3 (1.4.0) - aws-sdk-core (~> 3) + aws-sdk-s3 (1.13.0) + aws-sdk-core (~> 3, >= 3.21.2) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.0) aws-sigv4 (1.0.2) - barber (0.11.2) - ember-source (>= 1.0, < 3) + barber (0.12.0) + ember-source (>= 1.0, < 3.1) execjs (>= 1.2, < 3) - better_errors (2.1.1) + better_errors (2.4.0) coderay (>= 1.0.0) - erubis (>= 2.6.6) + erubi (>= 1.0.0) rack (>= 0.9.0) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) - bootsnap (1.1.8) + bootsnap (1.3.0) msgpack (~> 1.0) builder (3.2.3) - bullet (5.5.1) + bullet (5.7.5) activesupport (>= 3.0.0) - uniform_notifier (~> 1.10.0) - byebug (9.0.6) + uniform_notifier (~> 1.11.0) + byebug (10.0.2) certified (1.0.0) - chunky_png (1.3.8) + chunky_png (1.3.10) coderay (1.1.2) concurrent-ruby (1.0.5) - connection_pool (2.2.1) + connection_pool (2.2.2) cppjieba_rb (0.3.0) crack (0.4.3) safe_yaml (~> 1.0.0) - crass (1.0.3) + crass (1.0.4) debug_inspector (0.0.3) diff-lcs (1.3) discourse_image_optim (0.24.5) @@ -90,8 +92,8 @@ GEM in_threads (~> 1.3) progress (~> 3.0, >= 3.0.1) email_reply_trimmer (0.1.12) - ember-data-source (2.2.1) - ember-source (>= 1.8, < 3.0) + ember-data-source (3.0.2) + ember-source (>= 2, < 3.0) ember-handlebars-template (0.7.5) barber (>= 0.11.0) sprockets (>= 3.3, < 4) @@ -103,59 +105,60 @@ GEM jquery-rails (>= 1.0.17) railties (>= 3.1) ember-source (2.13.3) - erubi (1.6.1) - erubis (2.7.0) - excon (0.56.0) + erubi (1.7.1) + excon (0.62.0) execjs (2.7.0) - exifr (1.2.5) - fabrication (2.9.8) + exifr (1.3.4) + fabrication (2.20.1) fakeweb (1.3.0) - faraday (0.11.0) + faraday (0.12.2) multipart-post (>= 1.2, < 3) fast_blank (1.0.0) fast_xor (1.1.3) rake rake-compiler fast_xs (0.8.0) - fastimage (2.1.1) - ffi (1.9.18) + fastimage (2.1.3) + ffi (1.9.25) flamegraph (0.9.5) foreman (0.84.0) thor (~> 0.19.1) fspath (3.1.0) gc_tracer (1.5.1) - globalid (0.4.0) + globalid (0.4.1) activesupport (>= 4.2.0) guess_html_encoding (0.0.11) - hashdiff (0.3.4) - hashie (3.5.5) - highline (1.7.8) + hashdiff (0.3.7) + hashie (3.5.7) + highline (1.7.10) hiredis (0.6.1) hkdf (0.3.0) htmlentities (4.3.4) http_accept_language (2.0.5) - i18n (0.8.6) + i18n (1.0.1) + concurrent-ruby (~> 1.0) image_size (1.5.0) - in_threads (1.4.0) - jmespath (1.3.1) - jquery-rails (4.3.1) + in_threads (1.5.0) + jaro_winkler (1.5.1) + jmespath (1.4.0) + jquery-rails (4.3.3) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) jwt (1.5.6) - kgio (2.11.1) + kgio (2.11.2) libv8 (6.3.292.48.1) listen (3.1.5) rb-fsevent (~> 0.9, >= 0.9.4) rb-inotify (~> 0.9, >= 0.9.7) ruby_dep (~> 1.2) - lograge (0.7.1) - actionpack (>= 4, < 5.2) - activesupport (>= 4, < 5.2) - railties (>= 4, < 5.2) + lograge (0.10.0) + actionpack (>= 4) + activesupport (>= 4) + railties (>= 4) request_store (~> 1.0) logstash-event (1.2.02) - logstash-logger (0.25.1) + logstash-logger (0.26.1) logstash-event (~> 1.2) logster (1.2.9) loofah (2.2.2) @@ -175,10 +178,10 @@ GEM libv8 (~> 6.3) mini_suffix (0.3.0) ffi (~> 1.9) - minitest (5.10.3) - mocha (1.2.1) + minitest (5.11.3) + mocha (1.5.0) metaclass (~> 0.0.1) - mock_redis (0.17.3) + mock_redis (0.18.0) moneta (1.0.0) msgpack (1.2.4) multi_json (1.13.1) @@ -189,40 +192,39 @@ GEM mini_portile2 (~> 2.3.0) nokogumbo (1.5.0) nokogiri - oauth (0.5.1) - oauth2 (1.3.1) - faraday (>= 0.8, < 0.12) + oauth (0.5.4) + oauth2 (1.4.0) + faraday (>= 0.8, < 0.13) jwt (~> 1.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.4.0) - omniauth (1.6.1) + oj (3.6.2) + omniauth (1.8.1) hashie (>= 3.4.6, < 3.6.0) rack (>= 1.6.2, < 3) - omniauth-facebook (4.0.0) + omniauth-facebook (5.0.0) omniauth-oauth2 (~> 1.2) omniauth-github (1.3.0) omniauth (~> 1.5) omniauth-oauth2 (>= 1.4.0, < 2.0) - omniauth-google-oauth2 (0.3.1) - jwt (~> 1.0) - multi_json (~> 1.3) + omniauth-google-oauth2 (0.5.3) + jwt (>= 1.5) omniauth (>= 1.1.1) - omniauth-oauth2 (>= 1.3.1) - omniauth-instagram (1.0.2) + omniauth-oauth2 (>= 1.5) + omniauth-instagram (1.3.0) omniauth (~> 1) omniauth-oauth2 (~> 1) omniauth-oauth (1.1.0) oauth omniauth (~> 1.0) - omniauth-oauth2 (1.4.0) - oauth2 (~> 1.0) + omniauth-oauth2 (1.5.0) + oauth2 (~> 1.1) omniauth (~> 1.2) omniauth-openid (1.0.1) omniauth (~> 1.0) rack-openid (~> 1.3.1) - omniauth-twitter (1.3.0) + omniauth-twitter (1.4.0) omniauth-oauth (~> 1.1) rack onebox (1.8.48) @@ -236,31 +238,31 @@ GEM redis ruby-openid parallel (1.12.1) - parser (2.5.0.3) + parser (2.5.1.0) ast (~> 2.4.0) pg (0.21.0) powerpack (0.1.1) - progress (3.3.1) + progress (3.4.0) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) slop (~> 3.4) pry-nav (0.2.4) pry (>= 0.9.10, < 0.11.0) - pry-rails (0.3.4) - pry (>= 0.9.10) - public_suffix (2.0.5) - puma (3.9.1) - r2 (0.2.6) + pry-rails (0.3.6) + pry (>= 0.10.4) + public_suffix (3.0.2) + puma (3.11.4) + r2 (0.2.7) rack (2.0.5) rack-mini-profiler (1.0.0) rack (>= 1.2.0) rack-openid (1.3.1) rack (>= 1.1.0) ruby-openid (>= 2.1.8) - rack-protection (2.0.1) + rack-protection (2.0.2) rack - rack-test (0.7.0) + rack-test (1.0.0) rack (>= 1.0, < 3) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) @@ -270,20 +272,20 @@ GEM rails_multisite (2.0.4) activerecord (> 4.2, < 6) railties (> 4.2, < 6) - railties (5.1.4) - actionpack (= 5.1.4) - activesupport (= 5.1.4) + railties (5.2.0) + actionpack (= 5.2.0) + activesupport (= 5.2.0) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) raindrops (0.19.0) - rake (12.3.0) + rake (12.3.1) rake-compiler (1.0.4) rake - rb-fsevent (0.9.8) - rb-inotify (0.9.8) - ffi (>= 0.5.0) + rb-fsevent (0.10.3) + rb-inotify (0.9.10) + ffi (>= 0.5.0, < 2) rbtrace (0.4.10) ffi (>= 1.0.6) msgpack (>= 0.4.3) @@ -291,37 +293,39 @@ GEM redis (4.0.1) redis-namespace (1.6.0) redis (>= 3.0.4) - request_store (1.3.2) - rinku (2.0.2) - rotp (3.3.0) + request_store (1.4.1) + rack (>= 1.4) + rinku (2.0.4) + rotp (3.3.1) rqrcode (0.10.1) chunky_png (~> 1.0) - rspec (3.6.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-core (3.6.0) - rspec-support (~> 3.6.0) - rspec-expectations (3.6.0) + rspec (3.7.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-core (3.7.1) + rspec-support (~> 3.7.0) + rspec-expectations (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) + rspec-support (~> 3.7.0) rspec-html-matchers (0.9.1) nokogiri (~> 1) rspec (>= 3.0.0.a, < 4) - rspec-mocks (3.6.0) + rspec-mocks (3.7.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.6.0) - rspec-rails (3.6.1) + rspec-support (~> 3.7.0) + rspec-rails (3.7.2) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) - rspec-core (~> 3.6.0) - rspec-expectations (~> 3.6.0) - rspec-mocks (~> 3.6.0) - rspec-support (~> 3.6.0) - rspec-support (3.6.0) + rspec-core (~> 3.7.0) + rspec-expectations (~> 3.7.0) + rspec-mocks (~> 3.7.0) + rspec-support (~> 3.7.0) + rspec-support (3.7.1) rtlit (0.0.5) - rubocop (0.53.0) + rubocop (0.57.1) + jaro_winkler (~> 1.5.1) parallel (~> 1.10) parser (>= 2.5) powerpack (~> 0.1) @@ -329,23 +333,27 @@ GEM ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) ruby-openid (2.7.0) - ruby-prof (0.16.2) + ruby-prof (0.17.0) ruby-progressbar (1.9.0) ruby-readability (0.7.0) guess_html_encoding (>= 0.0.4) nokogiri (>= 1.6.0) ruby_dep (1.5.0) safe_yaml (1.0.4) - sanitize (4.6.4) + sanitize (4.6.5) crass (~> 1.0.2) nokogiri (>= 1.4.4) nokogumbo (~> 1.4) - sass (3.4.24) - sassc (1.11.2) + sass (3.5.6) + sass-listen (~> 4.0.0) + sass-listen (4.0.0) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + sassc (1.11.4) bundler ffi (~> 1.9.6) sass (>= 3.3.0) - seed-fu (2.3.7) + seed-fu (2.3.9) activerecord (>= 3.1) activesupport (>= 3.1) shoulda (3.5.0) @@ -363,29 +371,29 @@ GEM sprockets (3.7.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.2.0) + sprockets-rails (3.2.1) actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) sshkey (1.9.0) - stackprof (0.2.10) + stackprof (0.2.11) thor (0.19.4) thread_safe (0.3.6) - tilt (2.0.7) + tilt (2.0.8) trollop (2.1.2) - tzinfo (1.2.3) + tzinfo (1.2.5) thread_safe (~> 0.1) - uglifier (3.2.0) + uglifier (4.1.11) execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext - unf_ext (0.0.7.4) - unicode-display_width (1.3.0) + unf_ext (0.0.7.5) + unicode-display_width (1.4.0) unicorn (5.4.0) kgio (~> 2.6) raindrops (~> 0.7) - uniform_notifier (1.10.0) - webmock (3.0.1) + uniform_notifier (1.11.0) + webmock (3.4.2) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff @@ -397,13 +405,13 @@ PLATFORMS ruby DEPENDENCIES - actionmailer (~> 5.1) - actionpack (~> 5.1) - actionview (~> 5.1) + actionmailer (~> 5.2) + actionpack (~> 5.2) + actionview (~> 5.2) active_model_serializers (~> 0.8.3) - activemodel (~> 5.1) - activerecord (~> 5.1) - activesupport (~> 5.1) + activemodel (~> 5.2) + activerecord (~> 5.2) + activesupport (~> 5.2) annotate aws-sdk-s3 barber @@ -471,7 +479,7 @@ DEPENDENCIES rack-mini-profiler rack-protection rails_multisite - railties (~> 5.1) + railties (~> 5.2) rake rb-fsevent rb-inotify (~> 0.9) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 218e04eb46..d75e4152c8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -96,7 +96,8 @@ class ApplicationController < ActionController::Base def dont_cache_page if !response.headers["Cache-Control"] && response.cache_control.blank? - response.headers["Cache-Control"] = "no-store, must-revalidate, no-cache, private" + response.cache_control[:no_cache] = true + response.cache_control[:extras] = ["no-store"] end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 696a2a870a..f59ac7cfe6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'current_user' require 'canonical_url' require_dependency 'guardian' @@ -62,17 +63,17 @@ module ApplicationHelper if GlobalSetting.use_s3? && GlobalSetting.s3_cdn_url if GlobalSetting.cdn_url - path.gsub!(GlobalSetting.cdn_url, GlobalSetting.s3_cdn_url) + path = path.gsub(GlobalSetting.cdn_url, GlobalSetting.s3_cdn_url) else path = "#{GlobalSetting.s3_cdn_url}#{path}" end if is_brotli_req? - path.gsub!(/\.([^.]+)$/, '.br.\1') + path = path.gsub(/\.([^.]+)$/, '.br.\1') end elsif GlobalSetting.cdn_url&.start_with?("https") && is_brotli_req? - path.gsub!("#{GlobalSetting.cdn_url}/assets/", "#{GlobalSetting.cdn_url}/brotli_asset/") + path = path.gsub("#{GlobalSetting.cdn_url}/assets/", "#{GlobalSetting.cdn_url}/brotli_asset/") end if Rails.env == "development" diff --git a/app/models/concerns/trashable.rb b/app/models/concerns/trashable.rb index ffd753a805..0a8dae3f50 100644 --- a/app/models/concerns/trashable.rb +++ b/app/models/concerns/trashable.rb @@ -46,13 +46,7 @@ module Trashable private def trash_update(deleted_at, deleted_by_id) - # see: https://github.com/rails/rails/issues/8436 - # - # Fixed in Rails 4 - # - self.class.unscoped.where(id: self.id).update_all(deleted_at: deleted_at, deleted_by_id: deleted_by_id) - raw_write_attribute :deleted_at, deleted_at - raw_write_attribute :deleted_by_id, deleted_by_id + self.update_columns(deleted_at: deleted_at, deleted_by_id: deleted_by_id) end end diff --git a/app/models/invite.rb b/app/models/invite.rb index 0065d69c47..b613e22c5e 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -166,13 +166,14 @@ class Invite < ActiveRecord::Base group_ids end + INVITE_ORDER = <<~SQL + SQL + def self.find_all_invites_from(inviter, offset = 0, limit = SiteSetting.invites_per_page) Invite.where(invited_by_id: inviter.id) .where('invites.email IS NOT NULL') .includes(user: :user_stat) - .order('CASE WHEN invites.user_id IS NOT NULL THEN 0 ELSE 1 END', - 'user_stats.time_read DESC', - 'invites.redeemed_at DESC') + .order("CASE WHEN invites.user_id IS NOT NULL THEN 0 ELSE 1 END, user_stats.time_read DESC, invites.redeemed_at DESC") .limit(limit) .offset(offset) .references('user_stats') diff --git a/app/models/post.rb b/app/models/post.rb index 142066cead..57f56437dc 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -654,11 +654,18 @@ class Post < ActiveRecord::Base result = public_posts.where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date) .where(post_type: Post.types[:regular]) result = result.where('topics.category_id = ?', category_id) if category_id - result.group('date(posts.created_at)').order('date(posts.created_at)').count + result + .group('date(posts.created_at)') + .order('date(posts.created_at)') + .count end def self.private_messages_count_per_day(start_date, end_date, topic_subtype) - private_posts.with_topic_subtype(topic_subtype).where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date).group('date(posts.created_at)').order('date(posts.created_at)').count + private_posts.with_topic_subtype(topic_subtype) + .where('posts.created_at >= ? AND posts.created_at <= ?', start_date, end_date) + .group('date(posts.created_at)') + .order('date(posts.created_at)') + .count end def reply_history(max_replies = 100, guardian = nil) diff --git a/app/models/post_mover.rb b/app/models/post_mover.rb index 14a41879ec..9f7eff0d18 100644 --- a/app/models/post_mover.rb +++ b/app/models/post_mover.rb @@ -217,7 +217,7 @@ class PostMover attrs[:last_posted_at] = post.created_at attrs[:last_post_user_id] = post.user_id attrs[:bumped_at] = post.created_at unless post.no_bump - attrs[:updated_at] = 'now()' + attrs[:updated_at] = Time.now destination_topic.update_columns(attrs) end end diff --git a/app/models/topic.rb b/app/models/topic.rb index d179b12ee8..9b1c1145ea 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -278,7 +278,7 @@ class Topic < ActiveRecord::Base def ensure_topic_has_a_category if category_id.nil? && (archetype.nil? || self.regular?) - self.category_id = SiteSetting.uncategorized_category_id + self.category_id = category&.id || SiteSetting.uncategorized_category_id end end @@ -1334,7 +1334,12 @@ SQL end def self.private_message_topics_count_per_day(start_date, end_date, topic_subtype) - private_messages.with_subtype(topic_subtype).where('topics.created_at >= ? AND topics.created_at <= ?', start_date, end_date).group('date(topics.created_at)').order('date(topics.created_at)').count + private_messages + .with_subtype(topic_subtype) + .where('topics.created_at >= ? AND topics.created_at <= ?', start_date, end_date) + .group('date(topics.created_at)') + .order('date(topics.created_at)') + .count end def is_category_topic? diff --git a/app/models/user.rb b/app/models/user.rb index 90f5064c8f..c28809f26b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -844,7 +844,7 @@ class User < ActiveRecord::Base if start_date && end_date result = result.group("date(users.created_at)") result = result.where("users.created_at >= ? AND users.created_at <= ?", start_date, end_date) - result = result.order('date(users.created_at)') + result = result.order("date(users.created_at)") end if group_id diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 5e88683cff..1ac69bce48 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -43,7 +43,6 @@ class BadgeGranter end if SiteSetting.enable_badges? - unless @badge.badge_type_id == BadgeType::Bronze && user_badge.granted_at < 2.days.ago I18n.with_locale(@user.effective_locale) do notification = @user.notifications.create( diff --git a/lib/admin_user_index_query.rb b/lib/admin_user_index_query.rb index baf20275da..67cc66626e 100644 --- a/lib/admin_user_index_query.rb +++ b/lib/admin_user_index_query.rb @@ -63,7 +63,8 @@ class AdminUserIndexQuery if params[:stats].present? && params[:stats] == false klass.order(order.reject(&:blank?).join(",")) else - klass.includes(:user_stat, :user_second_factor).order(order.reject(&:blank?).join(",")) + klass.includes(:user_stat, :user_second_factor) + .order(order.reject(&:blank?).join(",")) end end diff --git a/lib/email/renderer.rb b/lib/email/renderer.rb index be802b7a99..77721ab4c5 100644 --- a/lib/email/renderer.rb +++ b/lib/email/renderer.rb @@ -10,7 +10,7 @@ module Email def text return @text if @text - @text = (@message.text_part ? @message.text_part : @message).body.to_s.force_encoding('UTF-8') + @text = (+(@message.text_part ? @message.text_part : @message).body.to_s).force_encoding('UTF-8') @text = CGI.unescapeHTML(@text) end diff --git a/lib/freedom_patches/active_record_attribute_methods.rb b/lib/freedom_patches/active_record_attribute_methods.rb new file mode 100644 index 0000000000..71fd5d44c7 --- /dev/null +++ b/lib/freedom_patches/active_record_attribute_methods.rb @@ -0,0 +1,18 @@ +# see: https://github.com/rails/rails/issues/32995 +# +# Rails 5.2 forces us to add Arel.sql to #order and #pluck +# Discourse is very SQL heavy and this makes the code much more +# verbose and confusing, especially since it is not enforced for +# #group, #join and many other relation methods +# For the time being we monkey patch this away, longer term we +# hope Rails will allow us for this to be optional + +module ActiveRecord + module AttributeMethods + module ClassMethods + def enforce_raw_sql_whitelist(*args) + return + end + end + end +end diff --git a/lib/freedom_patches/fast_pluck.rb b/lib/freedom_patches/fast_pluck.rb index 6034cf7a52..9999e5a9db 100644 --- a/lib/freedom_patches/fast_pluck.rb +++ b/lib/freedom_patches/fast_pluck.rb @@ -36,39 +36,32 @@ class ActiveRecord::Relation class ::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter def select_raw(arel, name = nil, binds = [], &block) - arel, binds = binds_from_relation arel, binds - sql = to_sql(arel, binds) + arel = arel_from_relation(arel) + sql, binds = to_sql_and_binds(arel, binds) execute_and_clear(sql, name, binds, &block) end end - def pluck(*cols) - - conn = ActiveRecord::Base.connection - relation = self - - cols.map! do |column_name| - if column_name.is_a?(Symbol) && attribute_alias?(column_name) - attribute_alias(column_name) - else - column_name.to_s - end + def pluck(*column_names) + if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty? + return records.pluck(*column_names) end - if has_include?(cols.first) - construct_relation_for_association_calculations.pluck(*cols) + if has_include?(column_names.first) + relation = apply_join_dependency + relation.pluck(*column_names) else + enforce_raw_sql_whitelist(column_names) relation = spawn - relation.select_values = cols.map { |cn| - columns_hash.key?(cn) ? arel_table[cn] : cn + relation.select_values = column_names.map { |cn| + @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn } - conn.select_raw(relation, nil, relation.bound_attributes) do |result, _| + klass.connection.select_raw(relation.arel) do |result, _| result.type_map = SqlBuilder.pg_type_map result.nfields == 1 ? result.column_values(0) : result.values end - end end end diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 62874b3627..d4198e6333 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -411,7 +411,7 @@ class PostCreator attrs[:word_count] = (@topic.word_count || 0) + @post.word_count attrs[:excerpt] = @post.excerpt_for_topic if new_topic? attrs[:bumped_at] = @post.created_at unless @post.no_bump - attrs[:updated_at] = 'now()' + attrs[:updated_at] = Time.now @topic.update_columns(attrs) end end diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake index abb83aff2b..6dcdbf88bf 100644 --- a/lib/tasks/assets.rake +++ b/lib/tasks/assets.rake @@ -94,7 +94,6 @@ def compress_ruby(from, to) data = File.read("#{assets_path}/#{from}") uglified, map = Uglifier.new(comments: :none, - screw_ie8: true, source_map: { filename: File.basename(from), output_filename: File.basename(to) diff --git a/lib/topic_query_sql.rb b/lib/topic_query_sql.rb index 2f9bbe5993..93a2b9a862 100644 --- a/lib/topic_query_sql.rb +++ b/lib/topic_query_sql.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # # SQL fragments used when querying a list of topics. # @@ -10,12 +11,12 @@ module TopicQuerySQL end def order_by_category_sql(dir) - "CASE WHEN categories.id = #{SiteSetting.uncategorized_category_id.to_i} THEN '' ELSE categories.name END #{dir}" + -"CASE WHEN categories.id = #{SiteSetting.uncategorized_category_id.to_i} THEN '' ELSE categories.name END #{dir}" end # If you've clearned the pin, use bumped_at, otherwise put it at the top def order_with_pinned_sql - "CASE + -"CASE WHEN (COALESCE(topics.pinned_at, '#{lowest_date}') > COALESCE(tu.cleared_pinned_at, '#{lowest_date}')) THEN topics.pinned_at + interval '9999 years' ELSE topics.bumped_at @@ -24,7 +25,7 @@ module TopicQuerySQL # If you've clearned the pin, use bumped_at, otherwise put it at the top def order_nocategory_with_pinned_sql - "CASE + -"CASE WHEN topics.pinned_globally AND (COALESCE(topics.pinned_at, '#{lowest_date}') > COALESCE(tu.cleared_pinned_at, '#{lowest_date}')) THEN topics.pinned_at + interval '9999 years' @@ -41,18 +42,18 @@ module TopicQuerySQL end def order_top_for(score) - "COALESCE(top_topics.#{score}, 0) DESC, topics.bumped_at DESC" + -"COALESCE(top_topics.#{score}, 0) DESC, topics.bumped_at DESC" end def order_top_with_pinned_category_for(score) # display pinned topics first - "CASE WHEN (COALESCE(topics.pinned_at, '#{lowest_date}') > COALESCE(tu.cleared_pinned_at, '#{lowest_date}')) THEN 0 ELSE 1 END, + -"CASE WHEN (COALESCE(topics.pinned_at, '#{lowest_date}') > COALESCE(tu.cleared_pinned_at, '#{lowest_date}')) THEN 0 ELSE 1 END, top_topics.#{score} DESC, topics.bumped_at DESC" end def order_top_with_notification_levels(score) - "COALESCE(topic_users.notification_level, 1) DESC, COALESCE(category_users.notification_level, 1) DESC, COALESCE(top_topics.#{score}, 0) DESC, topics.bumped_at DESC" + -"COALESCE(topic_users.notification_level, 1) DESC, COALESCE(category_users.notification_level, 1) DESC, COALESCE(top_topics.#{score}, 0) DESC, topics.bumped_at DESC" end end diff --git a/package.json b/package.json index df94fd9275..499196c42d 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,10 @@ "license": "MIT", "dependencies": {}, "devDependencies": { - "babel-eslint": "^8.0.3", - "chrome-launcher": "^0.10.0", - "chrome-remote-interface": "^0.25.4", - "eslint": "^4.13.1", - "puppeteer": "^1.4.0" + "babel-eslint": "^8.2.3", + "chrome-launcher": "^0.10.2", + "chrome-remote-interface": "^0.25.6", + "eslint": "^4.19.1", + "puppeteer": "^0.13.0" } } diff --git a/spec/components/file_store/base_store_spec.rb b/spec/components/file_store/base_store_spec.rb index 89f0a105da..20d898ee36 100644 --- a/spec/components/file_store/base_store_spec.rb +++ b/spec/components/file_store/base_store_spec.rb @@ -1,4 +1,5 @@ require 'rails_helper' +require_dependency 'file_store/base_store' RSpec.describe FileStore::BaseStore do let(:upload) { Fabricate(:upload, id: 9999, sha1: Digest::SHA1.hexdigest('9999')) } diff --git a/spec/components/migration/safe_migrate_spec.rb b/spec/components/migration/safe_migrate_spec.rb index 1be7f7c86d..15659e4b90 100644 --- a/spec/components/migration/safe_migrate_spec.rb +++ b/spec/components/migration/safe_migrate_spec.rb @@ -21,6 +21,11 @@ describe Migration::SafeMigrate do $stdout = old_stdout end + def migrate_up(path) + migrations = ActiveRecord::MigrationContext.new(path).migrations + ActiveRecord::Migrator.new(:up, migrations, migrations.first.version).run + end + it "bans all table removal" do Migration::SafeMigrate.enable! @@ -28,7 +33,7 @@ describe Migration::SafeMigrate do output = capture_stdout do expect(lambda do - ActiveRecord::Migrator.up([path]) + migrate_up(path) end).to raise_error(StandardError) end @@ -45,14 +50,14 @@ describe Migration::SafeMigrate do output = capture_stdout do expect(lambda do - ActiveRecord::Migrator.up([path]) + migrate_up(path) end).to raise_error(StandardError) end - expect(output).to include("TableDropper") - expect { User.first }.not_to raise_error expect(User.first).not_to eq(nil) + + expect(output).to include("TableDropper") end it "bans all column removal" do @@ -62,7 +67,7 @@ describe Migration::SafeMigrate do output = capture_stdout do expect(lambda do - ActiveRecord::Migrator.up([path]) + migrate_up(path) end).to raise_error(StandardError) end @@ -79,7 +84,7 @@ describe Migration::SafeMigrate do output = capture_stdout do expect(lambda do - ActiveRecord::Migrator.up([path]) + migrate_up(path) end).to raise_error(StandardError) end @@ -96,7 +101,7 @@ describe Migration::SafeMigrate do path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/drop_table" output = capture_stdout do - ActiveRecord::Migrator.up([path]) + migrate_up(path) end expect(output).to include("drop_table(:users)") diff --git a/spec/components/post_revisor_spec.rb b/spec/components/post_revisor_spec.rb index 3e6efb0a6f..4734d94cec 100644 --- a/spec/components/post_revisor_spec.rb +++ b/spec/components/post_revisor_spec.rb @@ -86,7 +86,7 @@ describe PostRevisor do let(:post) { Fabricate(:post, post_args) } let(:first_version_at) { post.last_version_at } - subject { described_class.new(post) } + subject { PostRevisor.new(post) } describe 'with the same body' do it "doesn't change version" do @@ -402,7 +402,7 @@ describe PostRevisor do describe "topic excerpt" do it "topic excerpt is updated only if first post is revised" do - revisor = described_class.new(post) + revisor = PostRevisor.new(post) first_post = topic.posts.by_post_number.first expect { revisor.revise!(first_post.user, { raw: 'Edit the first post' }, revised_at: first_post.updated_at + 10.seconds) @@ -410,7 +410,7 @@ describe PostRevisor do }.to change { topic.excerpt } second_post = Fabricate(:post, post_args.merge(post_number: 2, topic_id: topic.id)) expect { - described_class.new(second_post).revise!(second_post.user, raw: 'Edit the 2nd post') + PostRevisor.new(second_post).revise!(second_post.user, raw: 'Edit the 2nd post') topic.reload }.to_not change { topic.excerpt } end @@ -423,10 +423,10 @@ describe PostRevisor do end context "#publish_changes" do - let!(:post) { Fabricate(:post, topic_id: topic.id) } + let!(:post) { Fabricate(:post, topic: topic) } it "should publish topic changes to clients" do - revisor = described_class.new(topic.ordered_posts.first, topic) + revisor = PostRevisor.new(topic.ordered_posts.first, topic) message = MessageBus.track_publish("/topic/#{topic.id}") do revisor.revise!(newuser, title: 'this is a test topic') diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index e293a87fd2..0a70342d40 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -964,7 +964,7 @@ describe Search do context 'in:title' do it 'allows for search in title' do topic = Fabricate(:topic, title: 'I am testing a title search') - _post = Fabricate(:post, topic_id: topic.id, raw: 'this is the first post') + _post = Fabricate(:post, topic: topic, raw: 'this is the first post') results = Search.execute('title in:title') expect(results.posts.length).to eq(1) diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index fcce481252..08515a3e9d 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -17,8 +17,8 @@ describe TopicQuery do category.set_permissions(group => :full) category.save - topic = Fabricate(:topic, category: category) - topic = Fabricate(:topic, visible: false) + Fabricate(:topic, category: category) + Fabricate(:topic, visible: false) expect(TopicQuery.new(nil).list_latest.topics.count).to eq(0) expect(TopicQuery.new(user).list_latest.topics.count).to eq(0) @@ -98,7 +98,7 @@ describe TopicQuery do context 'bookmarks' do it "filters and returns bookmarks correctly" do post = Fabricate(:post) - reply = Fabricate(:post, topic_id: post.topic_id) + reply = Fabricate(:post, topic: post.topic) post2 = Fabricate(:post) diff --git a/spec/components/validators/upload_validator_spec.rb b/spec/components/validators/upload_validator_spec.rb index 77dd4a1f0c..164d0b0a8e 100644 --- a/spec/components/validators/upload_validator_spec.rb +++ b/spec/components/validators/upload_validator_spec.rb @@ -1,4 +1,5 @@ require 'rails_helper' +require_dependency 'validators/upload_validator' describe Validators::UploadValidator do subject(:validator) { described_class.new } diff --git a/spec/controllers/admin/api_controller_spec.rb b/spec/controllers/admin/api_controller_spec.rb index af72b0529a..27d73ea3ea 100644 --- a/spec/controllers/admin/api_controller_spec.rb +++ b/spec/controllers/admin/api_controller_spec.rb @@ -11,7 +11,7 @@ describe Admin::ApiController do context '.index' do it "succeeds" do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -20,7 +20,7 @@ describe Admin::ApiController do it "returns 404 when there is no key" do put :regenerate_key, params: { id: 1234 }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful expect(response.status).to eq(404) end @@ -35,7 +35,7 @@ describe Admin::ApiController do it "returns 404 when there is no key" do delete :revoke_key, params: { id: 1234 }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful expect(response.status).to eq(404) end diff --git a/spec/controllers/admin/backups_controller_spec.rb b/spec/controllers/admin/backups_controller_spec.rb index 4f7a6c7894..a4f1757a46 100644 --- a/spec/controllers/admin/backups_controller_spec.rb +++ b/spec/controllers/admin/backups_controller_spec.rb @@ -28,7 +28,7 @@ describe Admin::BackupsController do get :index, format: :html, xhr: true - expect(response).to be_success + expect(response).to be_successful end end @@ -40,7 +40,7 @@ describe Admin::BackupsController do get :index, format: :json, xhr: true - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json[0]["filename"]).to eq("backup1") @@ -58,7 +58,7 @@ describe Admin::BackupsController do get :status, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -72,7 +72,7 @@ describe Admin::BackupsController do with_uploads: false, client_id: "foo" }, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -139,14 +139,14 @@ describe Admin::BackupsController do delete :destroy, params: { id: backup_filename }, format: :json - expect(response).to be_success + expect(response).to be_successful end it "doesn't remove the backup if not found" do Backup.expects(:[]).with(backup_filename).returns(nil) b.expects(:remove).never delete :destroy, params: { id: backup_filename }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -162,7 +162,7 @@ describe Admin::BackupsController do get :logs, format: :html, xhr: true - expect(response).to be_success + expect(response).to be_successful end end @@ -175,7 +175,7 @@ describe Admin::BackupsController do post :restore, params: { id: backup_filename, client_id: "foo" }, format: :json expect(SiteSetting.disable_emails).to eq(true) - expect(response).to be_success + expect(response).to be_successful end end @@ -188,7 +188,7 @@ describe Admin::BackupsController do expect { put :readonly, params: { enable: true }, format: :json } .to change { UserHistory.count }.by(1) - expect(response).to be_success + expect(response).to be_successful user_history = UserHistory.last @@ -202,7 +202,7 @@ describe Admin::BackupsController do expect { put :readonly, params: { enable: false }, format: :json } .to change { UserHistory.count }.by(1) - expect(response).to be_success + expect(response).to be_successful user_history = UserHistory.last diff --git a/spec/controllers/admin/badges_controller_spec.rb b/spec/controllers/admin/badges_controller_spec.rb index d5995aac40..6751072d3a 100644 --- a/spec/controllers/admin/badges_controller_spec.rb +++ b/spec/controllers/admin/badges_controller_spec.rb @@ -9,7 +9,7 @@ describe Admin::BadgesController do context 'index' do it 'returns badge index' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -79,7 +79,7 @@ describe Admin::BadgesController do it 'returns JSON' do get :badge_types, format: :json - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)["badge_types"]).to be_present end end @@ -87,7 +87,7 @@ describe Admin::BadgesController do context '.destroy' do it 'deletes the badge' do delete :destroy, params: { id: badge.id }, format: :json - expect(response).to be_success + expect(response).to be_successful expect(Badge.where(id: badge.id).exists?).to eq(false) expect(UserHistory.where(acting_user_id: user.id, action: UserHistory.actions[:delete_badge]).exists?).to eq(true) end @@ -104,7 +104,7 @@ describe Admin::BadgesController do name: "123456" }, format: :json - expect(response).to be_success + expect(response).to be_successful editor_badge.reload expect(editor_badge.name).to eq(editor_badge_name) @@ -127,7 +127,7 @@ describe Admin::BadgesController do enabled: true }, format: :json - expect(response).to be_success + expect(response).to be_successful badge.reload expect(badge.name).to eq('123456') expect(badge.query).to eq('select 123') @@ -147,7 +147,7 @@ describe Admin::BadgesController do enabled: true }, format: :json - expect(response).to be_success + expect(response).to be_successful badge.reload expect(badge.name).to eq('123456') expect(badge.query).to eq(sql) diff --git a/spec/controllers/admin/color_schemes_controller_spec.rb b/spec/controllers/admin/color_schemes_controller_spec.rb index 6b11e219fb..e748d1e002 100644 --- a/spec/controllers/admin/color_schemes_controller_spec.rb +++ b/spec/controllers/admin/color_schemes_controller_spec.rb @@ -21,7 +21,7 @@ describe Admin::ColorSchemesController do Fabricate(:color_scheme) get :index, format: :json - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)).to be_present end end @@ -30,7 +30,7 @@ describe Admin::ColorSchemesController do it "returns JSON" do post :create, params: valid_params, format: :json - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['id']).to be_present end @@ -40,7 +40,7 @@ describe Admin::ColorSchemesController do post :create, params: valid_params, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful expect(::JSON.parse(response.body)['errors']).to be_present end end @@ -51,7 +51,7 @@ describe Admin::ColorSchemesController do it "returns success" do ColorSchemeRevisor.expects(:revise).returns(existing) put :update, params: valid_params.merge(id: existing.id), format: :json - expect(response).to be_success + expect(response).to be_successful end it "returns JSON" do @@ -66,7 +66,7 @@ describe Admin::ColorSchemesController do params[:color_scheme][:colors][0][:name] = color_scheme.colors.first.name params[:color_scheme][:colors][0][:hex] = 'cool color please' put :update, params: params, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful expect(::JSON.parse(response.body)['errors']).to be_present end end @@ -78,7 +78,7 @@ describe Admin::ColorSchemesController do expect { delete :destroy, params: { id: existing.id }, format: :json }.to change { ColorScheme.count }.by(-1) - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb index c190f72b7e..cfde3a4ef5 100644 --- a/spec/controllers/admin/dashboard_controller_spec.rb +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -23,7 +23,7 @@ describe Admin::DashboardController do it 'returns discourse version info' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['version_check']).to be_present end end @@ -50,7 +50,7 @@ describe Admin::DashboardController do it 'returns an empty array' do get :problems, format: :json - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json['problems'].size).to eq(0) end diff --git a/spec/controllers/admin/email_controller_spec.rb b/spec/controllers/admin/email_controller_spec.rb index 0b0c2ffca2..7f881f974f 100644 --- a/spec/controllers/admin/email_controller_spec.rb +++ b/spec/controllers/admin/email_controller_spec.rb @@ -35,7 +35,7 @@ describe Admin::EmailController do end subject { response } - it { is_expected.to be_success } + it { is_expected.to be_successful } end context '.skipped' do @@ -44,7 +44,7 @@ describe Admin::EmailController do end subject { response } - it { is_expected.to be_success } + it { is_expected.to be_successful } end context '.test' do @@ -76,7 +76,7 @@ describe Admin::EmailController do last_seen_at: 1.week.ago, username: user.username }, format: :json - expect(response).to be_success + expect(response).to be_successful end end diff --git a/spec/controllers/admin/emojis_controller_spec.rb b/spec/controllers/admin/emojis_controller_spec.rb index 1b494f0571..7a1f3618c6 100644 --- a/spec/controllers/admin/emojis_controller_spec.rb +++ b/spec/controllers/admin/emojis_controller_spec.rb @@ -23,7 +23,7 @@ describe Admin::EmojisController do it "returns a list of custom emojis" do Emoji.expects(:custom).returns([custom_emoji]) get :index, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json[0]["name"]).to eq(custom_emoji.name) expect(json[0]["url"]).to eq(custom_emoji.url) diff --git a/spec/controllers/admin/impersonate_controller_spec.rb b/spec/controllers/admin/impersonate_controller_spec.rb index 866e6898b5..b9793cc80c 100644 --- a/spec/controllers/admin/impersonate_controller_spec.rb +++ b/spec/controllers/admin/impersonate_controller_spec.rb @@ -13,7 +13,7 @@ describe Admin::ImpersonateController do context 'index' do it 'returns success' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -48,7 +48,7 @@ describe Admin::ImpersonateController do it "returns success" do post :create, params: { username_or_email: user.email }, format: :json - expect(response).to be_success + expect(response).to be_successful end it "also works with an email address" do diff --git a/spec/controllers/admin/permalinks_controller_spec.rb b/spec/controllers/admin/permalinks_controller_spec.rb index 1075150ab1..3befb17ff5 100644 --- a/spec/controllers/admin/permalinks_controller_spec.rb +++ b/spec/controllers/admin/permalinks_controller_spec.rb @@ -17,7 +17,7 @@ describe Admin::PermalinksController do get :index, params: { filter: "topic" }, format: :json - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) expect(result.length).to eq(2) end @@ -30,7 +30,7 @@ describe Admin::PermalinksController do get :index, params: { filter: "discourse" }, format: :json - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) expect(result.length).to eq(2) end @@ -43,7 +43,7 @@ describe Admin::PermalinksController do get :index, params: { filter: "discourse" }, format: :json - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) expect(result.length).to eq(3) end diff --git a/spec/controllers/admin/plugins_controller_spec.rb b/spec/controllers/admin/plugins_controller_spec.rb index 9df2c2737e..7e599c5533 100644 --- a/spec/controllers/admin/plugins_controller_spec.rb +++ b/spec/controllers/admin/plugins_controller_spec.rb @@ -11,7 +11,7 @@ describe Admin::PluginsController do it 'should return JSON' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body).has_key?('plugins')).to eq(true) end end diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb index 740df64afb..021576405e 100644 --- a/spec/controllers/admin/reports_controller_spec.rb +++ b/spec/controllers/admin/reports_controller_spec.rb @@ -45,7 +45,7 @@ describe Admin::ReportsController do end it "renders the report as JSON" do - expect(response).to be_success + expect(response).to be_successful end it "renders the report as JSON" do @@ -67,7 +67,7 @@ describe Admin::ReportsController do get :show, params: { type: 'topics', category_id: category.id }, format: :json - expect(response).to be_success + expect(response).to be_successful report = JSON.parse(response.body)["report"] @@ -87,7 +87,7 @@ describe Admin::ReportsController do get :show, params: { type: 'signups', group_id: group.id }, format: :json - expect(response).to be_success + expect(response).to be_successful report = JSON.parse(response.body)["report"] diff --git a/spec/controllers/admin/screened_emails_controller_spec.rb b/spec/controllers/admin/screened_emails_controller_spec.rb index fb4486a9b4..bd0503a60c 100644 --- a/spec/controllers/admin/screened_emails_controller_spec.rb +++ b/spec/controllers/admin/screened_emails_controller_spec.rb @@ -13,7 +13,7 @@ describe Admin::ScreenedEmailsController do end subject { response } - it { is_expected.to be_success } + it { is_expected.to be_successful } it 'returns JSON' do expect(::JSON.parse(subject.body)).to be_a(Array) diff --git a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb b/spec/controllers/admin/screened_ip_addresses_controller_spec.rb index 664fc85cdb..4176173d3b 100644 --- a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb +++ b/spec/controllers/admin/screened_ip_addresses_controller_spec.rb @@ -18,13 +18,13 @@ describe Admin::ScreenedIpAddressesController do get :index, params: { filter: "1.2.*" }, format: :json - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) expect(result.length).to eq(3) get :index, params: { filter: "4.5.6.7" }, format: :json - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) expect(result.length).to eq(1) end @@ -45,7 +45,7 @@ describe Admin::ScreenedIpAddressesController do SiteSetting.min_ban_entries_for_roll_up = 3 post :roll_up, format: :json - expect(response).to be_success + expect(response).to be_successful subnet = ScreenedIpAddress.where(ip_address: "1.2.3.0/24").first expect(subnet).to be_present @@ -65,7 +65,7 @@ describe Admin::ScreenedIpAddressesController do SiteSetting.min_ban_entries_for_roll_up = 5 post :roll_up, format: :json - expect(response).to be_success + expect(response).to be_successful subnet = ScreenedIpAddress.where(ip_address: "1.2.0.0/16").first expect(subnet).to be_present diff --git a/spec/controllers/admin/screened_urls_controller_spec.rb b/spec/controllers/admin/screened_urls_controller_spec.rb index 86d7fce0b7..e54ad12d30 100644 --- a/spec/controllers/admin/screened_urls_controller_spec.rb +++ b/spec/controllers/admin/screened_urls_controller_spec.rb @@ -13,7 +13,7 @@ describe Admin::ScreenedUrlsController do end subject { response } - it { is_expected.to be_success } + it { is_expected.to be_successful } it 'returns JSON' do expect(::JSON.parse(subject.body)).to be_a(Array) diff --git a/spec/controllers/admin/site_settings_controller_spec.rb b/spec/controllers/admin/site_settings_controller_spec.rb index 874f375602..b1f6007e93 100644 --- a/spec/controllers/admin/site_settings_controller_spec.rb +++ b/spec/controllers/admin/site_settings_controller_spec.rb @@ -14,7 +14,7 @@ describe Admin::SiteSettingsController do context 'index' do it 'returns success' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end it 'returns JSON' do diff --git a/spec/controllers/admin/site_texts_controller_spec.rb b/spec/controllers/admin/site_texts_controller_spec.rb index 7a1676a831..6acb89da03 100644 --- a/spec/controllers/admin/site_texts_controller_spec.rb +++ b/spec/controllers/admin/site_texts_controller_spec.rb @@ -14,7 +14,7 @@ describe Admin::SiteTextsController do context '.index' do it 'returns json' do get :index, params: { q: 'title' }, format: :json - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)).to be_present end end @@ -22,7 +22,7 @@ describe Admin::SiteTextsController do context '.show' do it 'returns a site text for a key that exists' do get :show, params: { id: 'title' }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -36,7 +36,7 @@ describe Admin::SiteTextsController do it 'returns not found for missing keys' do get :show, params: { id: 'made_up_no_key_exists' }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -71,7 +71,7 @@ describe Admin::SiteTextsController do orig_title = I18n.t(:title) put :update, params: { id: 'title', site_text: { value: 'hello' } }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -84,7 +84,7 @@ describe Admin::SiteTextsController do # Revert put :revert, params: { id: 'title' }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -101,7 +101,7 @@ describe Admin::SiteTextsController do id: 'made_up_no_key_exists', site_text: { value: 'hello' } }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end it 'logs the change' do diff --git a/spec/controllers/admin/staff_action_logs_controller_spec.rb b/spec/controllers/admin/staff_action_logs_controller_spec.rb index 3da6dfa158..5f12839e38 100644 --- a/spec/controllers/admin/staff_action_logs_controller_spec.rb +++ b/spec/controllers/admin/staff_action_logs_controller_spec.rb @@ -17,7 +17,7 @@ describe Admin::StaffActionLogsController do get :index, params: { action_id: UserHistory.actions[:delete_topic] }, format: :json json = JSON.parse(response.body) - expect(response).to be_success + expect(response).to be_successful expect(json["staff_action_logs"].length).to eq(1) expect(json["staff_action_logs"][0]["action_name"]).to eq("delete_topic") @@ -41,7 +41,7 @@ describe Admin::StaffActionLogsController do .log_theme_change(original_json, theme) get :diff, params: { id: record.id }, format: :json - expect(response).to be_success + expect(response).to be_successful parsed = JSON.parse(response.body) expect(parsed["side_by_side"]).to include("up") diff --git a/spec/controllers/admin/themes_controller_spec.rb b/spec/controllers/admin/themes_controller_spec.rb index c2c00b78df..e129499d4c 100644 --- a/spec/controllers/admin/themes_controller_spec.rb +++ b/spec/controllers/admin/themes_controller_spec.rb @@ -66,7 +66,7 @@ describe Admin::ThemesController do upload.destroy post :import, params: { theme: uploaded_json }, format: :json - expect(response).to be_success + expect(response).to be_successful temp.unlink theme = Theme.last @@ -79,7 +79,7 @@ describe Admin::ThemesController do it 'imports a theme' do post :import, params: { theme: theme_file }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) @@ -113,7 +113,7 @@ describe Admin::ThemesController do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) @@ -133,7 +133,7 @@ describe Admin::ThemesController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) @@ -186,7 +186,7 @@ describe Admin::ThemesController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) diff --git a/spec/controllers/admin/user_fields_controller_spec.rb b/spec/controllers/admin/user_fields_controller_spec.rb index de46a1cf0c..b885c8b389 100644 --- a/spec/controllers/admin/user_fields_controller_spec.rb +++ b/spec/controllers/admin/user_fields_controller_spec.rb @@ -16,7 +16,7 @@ describe Admin::UserFieldsController do user_field: { name: 'hello', description: 'hello desc', field_type: 'text' } }, format: :json - expect(response).to be_success + expect(response).to be_successful }.to change(UserField, :count).by(1) end @@ -31,7 +31,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful end.to change(UserField, :count).by(1) expect(UserFieldOption.count).to eq(3) @@ -43,7 +43,7 @@ describe Admin::UserFieldsController do it "returns a list of user fields" do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['user_fields']).to be_present end @@ -55,7 +55,7 @@ describe Admin::UserFieldsController do it "deletes the user field" do expect { delete :destroy, params: { id: user_field.id }, format: :json - expect(response).to be_success + expect(response).to be_successful }.to change(UserField, :count).by(-1) end end @@ -69,7 +69,7 @@ describe Admin::UserFieldsController do user_field: { name: 'fraggle', field_type: 'confirm', description: 'muppet' } }, format: :json - expect(response).to be_success + expect(response).to be_successful user_field.reload expect(user_field.name).to eq('fraggle') expect(user_field.field_type).to eq('confirm') @@ -86,7 +86,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful user_field.reload expect(user_field.name).to eq('fraggle') expect(user_field.field_type).to eq('dropdown') @@ -105,7 +105,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful user_field.reload expect(user_field.user_field_options.size).to eq(2) @@ -119,7 +119,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful user_field.reload expect(user_field.user_field_options.size).to eq(2) end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index d026d7bfb5..d82e74e06f 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -15,7 +15,7 @@ describe Admin::UsersController do context '#index' do it 'returns success' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end it 'returns JSON' do @@ -48,14 +48,14 @@ describe Admin::UsersController do context 'an existing user' do it 'returns success' do get :show, params: { id: @user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful end end context 'an existing user' do it 'returns success' do get :show, params: { id: 0 }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end end @@ -135,7 +135,7 @@ describe Admin::UsersController do format: :json } ) - expect(response).to be_success + expect(response).to be_successful user.reload expect(user).to be_suspended @@ -160,7 +160,7 @@ describe Admin::UsersController do it "can have an associated post" do put(:suspend, params: suspend_params) - expect(response).to be_success + expect(response).to be_successful log = UserHistory.where(target_user_id: user.id).order('id desc').first expect(log).to be_present @@ -171,7 +171,7 @@ describe Admin::UsersController do put(:suspend, params: suspend_params.merge(post_action: 'delete')) post.reload expect(post.deleted_at).to be_present - expect(response).to be_success + expect(response).to be_successful end it "can edit an associated post" do @@ -182,7 +182,7 @@ describe Admin::UsersController do post.reload expect(post.deleted_at).to be_blank expect(post.raw).to eq("this is the edited content") - expect(response).to be_success + expect(response).to be_successful end end @@ -205,7 +205,7 @@ describe Admin::UsersController do format: :json } ) - expect(response).to be_success + expect(response).to be_successful log = UserHistory.where(target_user_id: user.id).order('id desc').first expect(log).to be_present @@ -274,7 +274,7 @@ describe Admin::UsersController do group_id: group.id, user_id: user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful expect(GroupUser.where(user_id: user.id, group_id: group.id).exists?).to eq(true) group_history = GroupHistory.last @@ -288,7 +288,7 @@ describe Admin::UsersController do group_id: group.id, user_id: user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -358,7 +358,7 @@ describe Admin::UsersController do user_id: @another_user.id }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end it "returns a 404 if the username doesn't exist" do @@ -366,7 +366,7 @@ describe Admin::UsersController do user_id: 123123 }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end it "upgrades the user's trust level" do @@ -378,7 +378,7 @@ describe Admin::UsersController do @another_user.reload expect(@another_user.trust_level).to eq(2) - expect(response).to be_success + expect(response).to be_successful end it "raises no error when demoting a user below their current trust level (locks trust level)" do @@ -394,7 +394,7 @@ describe Admin::UsersController do level: TrustLevel[0] }, format: :json - expect(response).to be_success + expect(response).to be_successful @another_user.reload expect(@another_user.trust_level).to eq(TrustLevel[0]) expect(@another_user.manual_locked_trust_level).to eq(TrustLevel[0]) @@ -474,7 +474,7 @@ describe Admin::UsersController do users: [reject_me.id, reject_me_too.id] }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['success'].to_i).to eq(2) expect(json['failed'].to_i).to eq(0) @@ -493,7 +493,7 @@ describe Admin::UsersController do users: [reject_me.id, reject_me_too.id] }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['success'].to_i).to eq(1) expect(json['failed'].to_i).to eq(1) @@ -506,7 +506,7 @@ describe Admin::UsersController do users: [reject_me.id] }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['success'].to_i).to eq(0) expect(json['failed'].to_i).to eq(1) @@ -538,7 +538,7 @@ describe Admin::UsersController do it "doesn't return an error if delete_posts == true" do delete :destroy, params: { id: delete_me.id, delete_posts: true }, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -555,7 +555,7 @@ describe Admin::UsersController do it "returns success" do put :activate, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['success']).to eq("OK") end @@ -567,7 +567,7 @@ describe Admin::UsersController do expect(@reg_user.email_confirmed?).to eq(false) put :activate, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful @reg_user.reload expect(@reg_user.email_confirmed?).to eq(true) @@ -581,14 +581,14 @@ describe Admin::UsersController do it "returns success" do put :log_out, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['success']).to eq("OK") end it "returns 404 when user_id does not exist" do put :log_out, params: { user_id: 123123 }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -612,7 +612,7 @@ describe Admin::UsersController do it "punishes the user for spamming" do put :silence, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_success + expect(response).to be_successful @reg_user.reload expect(@reg_user).to be_silenced end @@ -626,7 +626,7 @@ describe Admin::UsersController do post_action: 'edit', post_edit: "this is the new contents for the post" }, format: :json - expect(response).to be_success + expect(response).to be_successful silence_post.reload expect(silence_post.raw).to eq("this is the new contents for the post") @@ -731,7 +731,7 @@ describe Admin::UsersController do name: 'Bill', username: 'bill22', email: 'bill@bill.com' }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end it 'should invite admin' do @@ -742,7 +742,7 @@ describe Admin::UsersController do name: 'Bill', username: 'bill22', email: 'bill@bill.com' }, format: :json - expect(response).to be_success + expect(response).to be_successful u = User.find_by_email('bill@bill.com') expect(u.name).to eq("Bill") @@ -758,7 +758,7 @@ describe Admin::UsersController do name: 'Bill', username: 'bill22', email: 'bill@bill.com', send_email: '0' }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["password_url"]).to be_present end @@ -806,7 +806,7 @@ describe Admin::UsersController do sso.email = "bob2@bob.com" post :sync_sso, params: Rack::Utils.parse_query(sso.payload), format: :json - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.email).to eq("bob2@bob.com") @@ -820,7 +820,7 @@ describe Admin::UsersController do sso.email = "dr@claw.com" sso.external_id = "2" post :sync_sso, params: Rack::Utils.parse_query(sso.payload), format: :json - expect(response).to be_success + expect(response).to be_successful user = User.find_by_email('dr@claw.com') expect(user).to be_present diff --git a/spec/controllers/admin/versions_controller_spec.rb b/spec/controllers/admin/versions_controller_spec.rb index 62c8cea39d..0d0811d70c 100644 --- a/spec/controllers/admin/versions_controller_spec.rb +++ b/spec/controllers/admin/versions_controller_spec.rb @@ -21,7 +21,7 @@ describe Admin::VersionsController do describe 'show' do subject { get :show, format: :json } - it { is_expected.to be_success } + it { is_expected.to be_successful } it 'should return the currently available version' do json = JSON.parse(subject.body) diff --git a/spec/controllers/admin/web_hooks_controller_spec.rb b/spec/controllers/admin/web_hooks_controller_spec.rb index 6b793dd0de..1d87cb43ce 100644 --- a/spec/controllers/admin/web_hooks_controller_spec.rb +++ b/spec/controllers/admin/web_hooks_controller_spec.rb @@ -28,7 +28,7 @@ describe Admin::WebHooksController do } }, format: :json - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["web_hook"]["payload_url"]).to be_present @@ -62,7 +62,7 @@ describe Admin::WebHooksController do post :ping, params: { id: web_hook.id }, format: :json - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/composer_messages_controller_spec.rb b/spec/controllers/composer_messages_controller_spec.rb index c2333fa33f..27338ed890 100644 --- a/spec/controllers/composer_messages_controller_spec.rb +++ b/spec/controllers/composer_messages_controller_spec.rb @@ -15,7 +15,7 @@ describe ComposerMessagesController do it 'redirects to your user preferences' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end it 'delegates args to the finder' do diff --git a/spec/controllers/export_csv_controller_spec.rb b/spec/controllers/export_csv_controller_spec.rb index 2e1256653c..d79c06875a 100644 --- a/spec/controllers/export_csv_controller_spec.rb +++ b/spec/controllers/export_csv_controller_spec.rb @@ -10,19 +10,19 @@ describe ExportCsvController do it "enqueues export job" do Jobs.expects(:enqueue).with(:export_csv_file, has_entries(entity: "user_archive", user_id: @user.id)) post :export_entity, params: { entity: "user_archive" }, format: :json - expect(response).to be_success + expect(response).to be_successful end it "should not enqueue export job if rate limit is reached" do Jobs::ExportCsvFile.any_instance.expects(:execute).never UserExport.create(file_name: "user-archive-codinghorror-150116-003249", user_id: @user.id) post :export_entity, params: { entity: "user_archive" }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end it "returns 404 when normal user tries to export admin entity" do post :export_entity, params: { entity: "staff_action" }, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end end @@ -34,14 +34,14 @@ describe ExportCsvController do it "enqueues export job" do Jobs.expects(:enqueue).with(:export_csv_file, has_entries(entity: "staff_action", user_id: @admin.id)) post :export_entity, params: { entity: "staff_action" }, format: :json - expect(response).to be_success + expect(response).to be_successful end it "should not rate limit export for staff" do Jobs.expects(:enqueue).with(:export_csv_file, has_entries(entity: "staff_action", user_id: @admin.id)) UserExport.create(file_name: "screened-email-150116-010145", user_id: @admin.id) post :export_entity, params: { entity: "staff_action" }, format: :json - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/extra_locales_controller_spec.rb b/spec/controllers/extra_locales_controller_spec.rb index c3aa308d51..50a4234ce3 100644 --- a/spec/controllers/extra_locales_controller_spec.rb +++ b/spec/controllers/extra_locales_controller_spec.rb @@ -16,13 +16,13 @@ describe ExtraLocalesController do it "needs a valid bundle" do get :show, params: { bundle: 'made-up-bundle' } - expect(response).to_not be_success + expect(response).to_not be_successful expect(response.body).to be_blank end it "won't work with a weird parameter" do get :show, params: { bundle: '-invalid..character!!' } - expect(response).to_not be_success + expect(response).to_not be_successful end it "includes plugin translations" do @@ -43,7 +43,7 @@ describe ExtraLocalesController do get :show, params: { bundle: "admin" } - expect(response).to be_success + expect(response).to be_successful expect(response.body.include?("github_badges")).to eq(true) end diff --git a/spec/controllers/finish_installation_controller_spec.rb b/spec/controllers/finish_installation_controller_spec.rb index e239a9af30..a7ee627ebe 100644 --- a/spec/controllers/finish_installation_controller_spec.rb +++ b/spec/controllers/finish_installation_controller_spec.rb @@ -10,7 +10,7 @@ describe FinishInstallationController do it "doesn't allow access" do get :index - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -21,7 +21,7 @@ describe FinishInstallationController do it "allows access" do get :index - expect(response).to be_success + expect(response).to be_successful end end end @@ -34,7 +34,7 @@ describe FinishInstallationController do it "doesn't allow access" do get :register - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -46,7 +46,7 @@ describe FinishInstallationController do it "allows access" do get :register - expect(response).to be_success + expect(response).to be_successful end it "raises an error when the email is not in the allowed list" do @@ -92,7 +92,7 @@ describe FinishInstallationController do it "shows the page" do get :confirm_email - expect(response).to be_success + expect(response).to be_successful end end end @@ -112,7 +112,7 @@ describe FinishInstallationController do it "resends the email" do Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup)) get :resend_email - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/inline_onebox_controller_spec.rb b/spec/controllers/inline_onebox_controller_spec.rb index e68387fa55..880c69fd98 100644 --- a/spec/controllers/inline_onebox_controller_spec.rb +++ b/spec/controllers/inline_onebox_controller_spec.rb @@ -12,7 +12,7 @@ describe InlineOneboxController do it "returns empty JSON for empty input" do get :show, params: { urls: [] }, format: :json - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json['inline-oneboxes']).to eq([]) end @@ -22,7 +22,7 @@ describe InlineOneboxController do it "returns information for a valid link" do get :show, params: { urls: [ topic.url ] }, format: :json - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) onebox = json['inline-oneboxes'][0] diff --git a/spec/controllers/post_action_users_controller_spec.rb b/spec/controllers/post_action_users_controller_spec.rb index fdd6add07c..302156f5d9 100644 --- a/spec/controllers/post_action_users_controller_spec.rb +++ b/spec/controllers/post_action_users_controller_spec.rb @@ -59,7 +59,7 @@ describe PostActionUsersController do id: post.id, post_action_type_id: PostActionType.types[:like] } - expect(response).to be_success + expect(response).to be_successful end it "paginates post actions" do diff --git a/spec/controllers/post_actions_controller_spec.rb b/spec/controllers/post_actions_controller_spec.rb index 0994fc601d..69a5bc2389 100644 --- a/spec/controllers/post_actions_controller_spec.rb +++ b/spec/controllers/post_actions_controller_spec.rb @@ -46,7 +46,7 @@ describe PostActionsController do it 'returns success' do delete :destroy, params: { id: post.id, post_action_type_id: 1 }, format: :json - expect(response).to be_success + expect(response).to be_successful end it 'deletes the action' do @@ -113,7 +113,7 @@ describe PostActionsController do id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] }, format: :json - expect(response).to be_success + expect(response).to be_successful end it "works with a deleted post" do @@ -123,7 +123,7 @@ describe PostActionsController do id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] }, format: :json - expect(response).to be_success + expect(response).to be_successful end end diff --git a/spec/controllers/queued_posts_controller_spec.rb b/spec/controllers/queued_posts_controller_spec.rb index ac88c50479..89620c116d 100644 --- a/spec/controllers/queued_posts_controller_spec.rb +++ b/spec/controllers/queued_posts_controller_spec.rb @@ -6,7 +6,7 @@ describe QueuedPostsController do context 'without authentication' do it 'fails' do get :index, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -14,7 +14,7 @@ describe QueuedPostsController do let!(:user) { log_in(:user) } it 'fails' do get :index, format: :json - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -23,7 +23,7 @@ describe QueuedPostsController do it 'returns the queued posts' do get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end end @@ -52,7 +52,7 @@ describe QueuedPostsController do id: qp.id, queued_post: { state: 'approved' } }, format: :json - expect(response).to be_success + expect(response).to be_successful qp.reload expect(qp.state).to eq(QueuedPost.states[:approved]) @@ -66,7 +66,7 @@ describe QueuedPostsController do id: qp.id, queued_post: { state: 'rejected' } }, format: :json - expect(response).to be_success + expect(response).to be_successful qp.reload expect(qp.state).to eq(QueuedPost.states[:rejected]) @@ -91,7 +91,7 @@ describe QueuedPostsController do id: queued_topic.id, queued_post: changes }, format: :json - expect(response).to be_success + expect(response).to be_successful end it 'updates raw' do @@ -119,7 +119,7 @@ describe QueuedPostsController do id: queued_reply.id, queued_post: changes }, format: :json - expect(response).to be_success + expect(response).to be_successful end it 'updates raw' do diff --git a/spec/controllers/site_controller_spec.rb b/spec/controllers/site_controller_spec.rb index c36a79589c..78d2b8d493 100644 --- a/spec/controllers/site_controller_spec.rb +++ b/spec/controllers/site_controller_spec.rb @@ -34,7 +34,7 @@ describe SiteController do get :statistics, format: :json json = JSON.parse(response.body) - expect(response).to be_success + expect(response).to be_successful expect(json["topic_count"]).to be_present expect(json["post_count"]).to be_present expect(json["user_count"]).to be_present diff --git a/spec/controllers/steps_controller_spec.rb b/spec/controllers/steps_controller_spec.rb index ec1f7fd608..2c0603ca4c 100644 --- a/spec/controllers/steps_controller_spec.rb +++ b/spec/controllers/steps_controller_spec.rb @@ -41,7 +41,7 @@ describe StepsController do id: 'contact', fields: { contact_email: "eviltrout@example.com" } }, format: :json - expect(response).to be_success + expect(response).to be_successful expect(SiteSetting.contact_email).to eq("eviltrout@example.com") end @@ -50,7 +50,7 @@ describe StepsController do id: 'contact', fields: { contact_email: "not-an-email" } }, format: :json - expect(response).to_not be_success + expect(response).to_not be_successful end end diff --git a/spec/controllers/stylesheets_controller_spec.rb b/spec/controllers/stylesheets_controller_spec.rb index a68ccc62be..67f432f95b 100644 --- a/spec/controllers/stylesheets_controller_spec.rb +++ b/spec/controllers/stylesheets_controller_spec.rb @@ -12,7 +12,7 @@ describe StylesheetsController do StylesheetCache.destroy_all get :show, params: { name: "desktop_rtl_#{digest}" }, format: :json - expect(response).to be_success + expect(response).to be_successful cached = StylesheetCache.first expect(cached.target).to eq 'desktop_rtl' @@ -22,7 +22,7 @@ describe StylesheetsController do `rm #{Stylesheet::Manager.cache_fullpath}/*` get :show, params: { name: "desktop_rtl_#{digest}" }, format: :json - expect(response).to be_success + expect(response).to be_successful # there is an edge case which is ... disk and db cache is nuked, very unlikely to happen @@ -41,13 +41,13 @@ describe StylesheetsController do name: builder.stylesheet_filename.sub(".css", "") }, format: :json - expect(response).to be_success + expect(response).to be_successful get :show, params: { name: builder.stylesheet_filename_no_digest.sub(".css", "") }, format: :json - expect(response).to be_success + expect(response).to be_successful builder = Stylesheet::Manager.new(:desktop_theme, theme.key) builder.compile @@ -58,13 +58,13 @@ describe StylesheetsController do name: builder.stylesheet_filename.sub(".css", "") }, format: :json - expect(response).to be_success + expect(response).to be_successful get :show, params: { name: builder.stylesheet_filename_no_digest.sub(".css", "") }, format: :json - expect(response).to be_success + expect(response).to be_successful end end diff --git a/spec/controllers/user_actions_controller_spec.rb b/spec/controllers/user_actions_controller_spec.rb index 79cf2ac108..d6e6ae949c 100644 --- a/spec/controllers/user_actions_controller_spec.rb +++ b/spec/controllers/user_actions_controller_spec.rb @@ -64,7 +64,7 @@ describe UserActionsController do get :index, params: { username: user.username, filter: UserAction::PENDING }, format: :json - expect(response).to_not be_success + expect(response).to_not be_successful end end diff --git a/spec/controllers/user_avatars_controller_spec.rb b/spec/controllers/user_avatars_controller_spec.rb index 7218cd8a06..9e485a091f 100644 --- a/spec/controllers/user_avatars_controller_spec.rb +++ b/spec/controllers/user_avatars_controller_spec.rb @@ -72,7 +72,7 @@ describe UserAvatarsController do size: 51, username: user.username, version: upload.id, hostname: 'default' }, format: :json - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/controllers/webhooks_controller_spec.rb b/spec/controllers/webhooks_controller_spec.rb index b5b049ca8a..cfd8c6f9de 100644 --- a/spec/controllers/webhooks_controller_spec.rb +++ b/spec/controllers/webhooks_controller_spec.rb @@ -24,7 +24,7 @@ describe WebhooksController do "Message-Id" => "<12345@il.com>" }, format: :json - expect(response).to be_success + expect(response).to be_successful email_log.reload expect(email_log.bounced).to eq(true) @@ -50,7 +50,7 @@ describe WebhooksController do ] }, format: :json - expect(response).to be_success + expect(response).to be_successful email_log.reload expect(email_log.bounced).to eq(true) @@ -72,7 +72,7 @@ describe WebhooksController do "CustomID" => message_id }, format: :json - expect(response).to be_success + expect(response).to be_successful email_log.reload expect(email_log.bounced).to eq(true) @@ -99,7 +99,7 @@ describe WebhooksController do }] }, format: :json - expect(response).to be_success + expect(response).to be_successful email_log.reload expect(email_log.bounced).to eq(true) @@ -128,7 +128,7 @@ describe WebhooksController do }] }, format: :json - expect(response).to be_success + expect(response).to be_successful email_log.reload expect(email_log.bounced).to eq(true) diff --git a/spec/controllers/wizard_controller_spec.rb b/spec/controllers/wizard_controller_spec.rb index 0875e31c26..e99e911fed 100644 --- a/spec/controllers/wizard_controller_spec.rb +++ b/spec/controllers/wizard_controller_spec.rb @@ -37,13 +37,13 @@ describe WizardController do it "renders the wizard if you are an admin" do log_in(:admin) get :index, format: :json - expect(response).to be_success + expect(response).to be_successful end it "returns JSON when the mime type is appropriate" do log_in(:admin) get :index, format: 'json' - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body).has_key?('wizard')).to eq(true) end end diff --git a/spec/fabricators/topic_fabricator.rb b/spec/fabricators/topic_fabricator.rb index b3efbb98e3..4e276237a7 100644 --- a/spec/fabricators/topic_fabricator.rb +++ b/spec/fabricators/topic_fabricator.rb @@ -1,7 +1,9 @@ Fabricator(:topic) do user title { sequence(:title) { |i| "This is a test topic #{i}" } } - category_id { SiteSetting.uncategorized_category_id } + category_id do |attrs| + attrs[:category] ? attrs[:category].id : SiteSetting.uncategorized_category_id + end end Fabricator(:deleted_topic, from: :topic) do diff --git a/spec/jobs/toggle_topic_closed_spec.rb b/spec/jobs/toggle_topic_closed_spec.rb index 77e1afbe08..8e65312eeb 100644 --- a/spec/jobs/toggle_topic_closed_spec.rb +++ b/spec/jobs/toggle_topic_closed_spec.rb @@ -10,7 +10,7 @@ describe Jobs::ToggleTopicClosed do it 'should be able to close a topic' do topic - freeze_time(1.hour.from_now) do + freeze_time(61.minutes.from_now) do described_class.new.execute( topic_timer_id: topic.public_topic_timer.id, state: true @@ -19,7 +19,7 @@ describe Jobs::ToggleTopicClosed do expect(topic.reload.closed).to eq(true) expect(Post.last.raw).to eq(I18n.t( - 'topic_statuses.autoclosed_enabled_minutes', count: 60 + 'topic_statuses.autoclosed_enabled_minutes', count: 61 )) end end diff --git a/spec/models/post_action_spec.rb b/spec/models/post_action_spec.rb index b460306d36..96fe9ea0d2 100644 --- a/spec/models/post_action_spec.rb +++ b/spec/models/post_action_spec.rb @@ -9,7 +9,7 @@ describe PostAction do let(:eviltrout) { Fabricate(:evil_trout) } let(:admin) { Fabricate(:admin) } let(:post) { Fabricate(:post) } - let(:second_post) { Fabricate(:post, topic_id: post.topic_id) } + let(:second_post) { Fabricate(:post, topic: post.topic) } let(:bookmark) { PostAction.new(user_id: post.user_id, post_action_type_id: PostActionType.types[:bookmark] , post_id: post.id) } def value_for(user_id, dt) diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb index c7cc72496b..69dd546e8d 100644 --- a/spec/models/tag_spec.rb +++ b/spec/models/tag_spec.rb @@ -48,12 +48,12 @@ describe Tag do describe '#top_tags' do it "returns nothing if nothing has been tagged" do make_some_tags(tag_a_topic: false) - expect(described_class.top_tags.sort).to be_empty + expect(Tag.top_tags.sort).to be_empty end it "can return all tags" do make_some_tags(tag_a_topic: true) - expect(described_class.top_tags.sort).to eq(@tags.map(&:name).sort) + expect(Tag.top_tags.sort).to eq(@tags.map(&:name).sort) end context "with categories" do @@ -69,27 +69,17 @@ describe Tag do @topics << Fabricate(:topic, category: @private_category, tags: [@tags[2]]) end - it "doesn't return tags that have only been used in private category to anon" do - expect(described_class.top_tags.sort).to eq([@tags[0].name, @tags[1].name].sort) - end + it "works correctly" do + expect(Tag.top_tags(category: @category1).sort).to eq([@tags[0].name].sort) + expect(Tag.top_tags(guardian: Guardian.new(Fabricate(:admin))).sort).to eq([@tags[0].name, @tags[1].name, @tags[2].name].sort) + expect(Tag.top_tags(category: @private_category, guardian: Guardian.new(Fabricate(:admin))).sort).to eq([@tags[2].name].sort) - it "returns tags used in private category to those who can see that category" do - expect(described_class.top_tags(guardian: Guardian.new(Fabricate(:admin))).sort).to eq([@tags[0].name, @tags[1].name, @tags[2].name].sort) - end + expect(Tag.top_tags.sort).to eq([@tags[0].name, @tags[1].name].sort) + expect(Tag.top_tags(category: @private_category)).to be_empty - it "returns tags scoped to a given category" do - expect(described_class.top_tags(category: @category1).sort).to eq([@tags[0].name].sort) - expect(described_class.top_tags(category: @private_category, guardian: Guardian.new(Fabricate(:admin))).sort).to eq([@tags[2].name].sort) - end - - it "returns tags from sub-categories too" do sub_category = Fabricate(:category, parent_category_id: @category1.id) Fabricate(:topic, category: sub_category, tags: [@tags[1]]) - expect(described_class.top_tags(category: @category1).sort).to eq([@tags[0].name, @tags[1].name].sort) - end - - it "returns nothing if category arg is private to you" do - expect(described_class.top_tags(category: @private_category)).to be_empty + expect(Tag.top_tags(category: @category1).sort).to eq([@tags[0].name, @tags[1].name].sort) end end @@ -105,15 +95,15 @@ describe Tag do end it "for category with restricted tags, lists those tags" do - expect(described_class.top_tags(category: @category1)).to eq([@tags[0].name]) + expect(Tag.top_tags(category: @category1)).to eq([@tags[0].name]) end it "for category without tags, lists allowed tags" do - expect(described_class.top_tags(category: @category2).sort).to eq([@tags[1].name, @tags[2].name].sort) + expect(Tag.top_tags(category: @category2).sort).to eq([@tags[1].name, @tags[2].name].sort) end it "for no category arg, lists all tags" do - expect(described_class.top_tags.sort).to eq([@tags[0].name, @tags[1].name, @tags[2].name].sort) + expect(Tag.top_tags.sort).to eq([@tags[0].name, @tags[1].name, @tags[2].name].sort) end end @@ -151,17 +141,17 @@ describe Tag do end it "returns nothing if user is not a staff" do - expect(described_class.pm_tags(guardian: Guardian.new(regular_user))).to be_empty + expect(Tag.pm_tags(guardian: Guardian.new(regular_user))).to be_empty end it "returns nothing if allow_staff_to_tag_pms setting is disabled" do SiteSetting.allow_staff_to_tag_pms = false - expect(described_class.pm_tags(guardian: Guardian.new(admin)).sort).to be_empty + expect(Tag.pm_tags(guardian: Guardian.new(admin)).sort).to be_empty end it "returns all pm tags if user is a staff and pm tagging is enabled" do SiteSetting.allow_staff_to_tag_pms = true - tags = described_class.pm_tags(guardian: Guardian.new(admin), allowed_user: regular_user) + tags = Tag.pm_tags(guardian: Guardian.new(admin), allowed_user: regular_user) expect(tags.length).to eq(2) expect(tags.map { |t| t[:id] }).to contain_exactly("tag-0", "tag-1") end @@ -171,7 +161,7 @@ describe Tag do it "should exclude private message topics" do topic Fabricate(:private_message_topic, tags: [tag]) - described_class.ensure_consistency! + Tag.ensure_consistency! tag.reload expect(tag.topic_count).to eq(1) end diff --git a/spec/models/topic_featured_users_spec.rb b/spec/models/topic_featured_users_spec.rb index 09459115ea..b874854d6b 100644 --- a/spec/models/topic_featured_users_spec.rb +++ b/spec/models/topic_featured_users_spec.rb @@ -4,11 +4,11 @@ describe TopicFeaturedUsers do it 'ensures consistency' do t = Fabricate(:topic) - Fabricate(:post, topic_id: t.id, user_id: t.user_id) - p2 = Fabricate(:post, topic_id: t.id) - p3 = Fabricate(:post, topic_id: t.id, user_id: p2.user_id) - p4 = Fabricate(:post, topic_id: t.id) - p5 = Fabricate(:post, topic_id: t.id) + Fabricate(:post, topic: t, user: t.user) + p2 = Fabricate(:post, topic: t) + p3 = Fabricate(:post, topic: t, user: p2.user) + p4 = Fabricate(:post, topic: t) + p5 = Fabricate(:post, topic: t) t.update_columns(featured_user1_id: 66, featured_user2_id: 70, diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 57ad210e34..0da4b29bd6 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -1612,8 +1612,7 @@ describe Topic do it "doesn't return topics from TL0 users" do new_user = Fabricate(:user, trust_level: 0) - Fabricate(:topic, user_id: new_user.id) - + Fabricate(:topic, user: new_user) expect(Topic.for_digest(user, 1.year.ago, top_order: true)).to be_blank end @@ -1626,7 +1625,7 @@ describe Topic do it "returns topics from TL0 users if enabled in preferences" do new_user = Fabricate(:user, trust_level: 0) - topic = Fabricate(:topic, user_id: new_user.id) + topic = Fabricate(:topic, user: new_user) u = Fabricate(:user) u.user_option.include_tl0_in_digests = true @@ -1656,7 +1655,7 @@ describe Topic do user = Fabricate(:user) muted_tag = Fabricate(:tag) TagUser.change(user.id, muted_tag.id, TagUser.notification_levels[:muted]) - topic1 = Fabricate(:topic, tags: [muted_tag]) + _topic1 = Fabricate(:topic, tags: [muted_tag]) topic2 = Fabricate(:topic, tags: [Fabricate(:tag), Fabricate(:tag)]) topic3 = Fabricate(:topic) @@ -1693,7 +1692,7 @@ describe Topic do it "excludes topics that are within the grace period" do topic1 = Fabricate(:topic, created_at: 6.minutes.ago) - topic2 = Fabricate(:topic, created_at: 4.minutes.ago) + _topic2 = Fabricate(:topic, created_at: 4.minutes.ago) expect(Topic.for_digest(user, 1.year.ago, top_order: true)).to eq([topic1]) end end @@ -2180,9 +2179,9 @@ describe Topic do end it "returns 0 with a topic with 1 reply" do - topic = Fabricate(:topic, created_at: 5.hours.ago) - post1 = Fabricate(:post, topic: topic, user: topic.user, post_number: 1, created_at: 5.hours.ago) - post1 = Fabricate(:post, topic: topic, post_number: 2, created_at: 2.hours.ago) + topic = Fabricate(:topic, created_at: 5.hours.ago) + _post1 = Fabricate(:post, topic: topic, user: topic.user, post_number: 1, created_at: 5.hours.ago) + _post2 = Fabricate(:post, topic: topic, post_number: 2, created_at: 2.hours.ago) expect(Topic.with_no_response_per_day(5.days.ago, Time.zone.now).count).to eq(0) expect(Topic.with_no_response_total).to eq(0) end diff --git a/spec/models/topic_timer_spec.rb b/spec/models/topic_timer_spec.rb index 639ef1d55e..dec05487fc 100644 --- a/spec/models/topic_timer_spec.rb +++ b/spec/models/topic_timer_spec.rb @@ -5,6 +5,10 @@ RSpec.describe TopicTimer, type: :model do let(:topic) { Fabricate(:topic) } let(:admin) { Fabricate(:admin) } + before do + freeze_time Time.new(2018) + end + context "validations" do describe '#status_type' do it 'should ensure that only one active public topic status update exists' do diff --git a/spec/requests/about_controller_spec.rb b/spec/requests/about_controller_spec.rb index e4e4b01a0a..ec4e07d4bc 100644 --- a/spec/requests/about_controller_spec.rb +++ b/spec/requests/about_controller_spec.rb @@ -8,7 +8,7 @@ describe AboutController do SiteSetting.login_required = false get "/about" - expect(response).to be_success + expect(response).to be_successful end it 'should redirect to login page for anonymous user when login_required is true' do @@ -23,7 +23,7 @@ describe AboutController do sign_in(Fabricate(:user)) get "/about" - expect(response).to be_success + expect(response).to be_successful end end end diff --git a/spec/requests/admin/backups_controller_spec.rb b/spec/requests/admin/backups_controller_spec.rb index 7504cb31c3..d4be1f1674 100644 --- a/spec/requests/admin/backups_controller_spec.rb +++ b/spec/requests/admin/backups_controller_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Admin::BackupsController do it "raises an error when backups are disabled" do SiteSetting.enable_backups = false get "/admin/backups.json" - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -21,7 +21,7 @@ RSpec.describe Admin::BackupsController do post "/admin/backups/rollback.json" - expect(response).to be_success + expect(response).to be_successful end it 'should not allow rollback via a GET request' do @@ -36,7 +36,7 @@ RSpec.describe Admin::BackupsController do delete "/admin/backups/cancel.json" - expect(response).to be_success + expect(response).to be_successful end it 'should not allow cancel via a GET request' do @@ -59,7 +59,7 @@ RSpec.describe Admin::BackupsController do put "/admin/backups/#{backup_filename}.json" - expect(response).to be_success + expect(response).to be_successful end it "returns 404 when the backup does not exist" do diff --git a/spec/requests/admin/email_templates_controller_spec.rb b/spec/requests/admin/email_templates_controller_spec.rb index 9babb31b38..8957a56717 100644 --- a/spec/requests/admin/email_templates_controller_spec.rb +++ b/spec/requests/admin/email_templates_controller_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Admin::EmailTemplatesController do sign_in(admin) get '/admin/customize/email_templates.json' - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['email_templates']).to be_present @@ -66,7 +66,7 @@ RSpec.describe Admin::EmailTemplatesController do email_template: { subject: 'Foo', body: 'Bar' } }, headers: headers - expect(response).not_to be_success + expect(response).not_to be_successful json = ::JSON.parse(response.body) expect(json['error_type']).to eq('not_found') @@ -169,7 +169,7 @@ RSpec.describe Admin::EmailTemplatesController do email_template: { subject: email_subject, body: email_body } }, headers: headers - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -237,7 +237,7 @@ RSpec.describe Admin::EmailTemplatesController do it "returns 'not found' when an unknown email template id is used" do delete '/admin/customize/email_templates/non_existent_template', headers: headers - expect(response).not_to be_success + expect(response).not_to be_successful json = ::JSON.parse(response.body) expect(json['error_type']).to eq('not_found') @@ -265,7 +265,7 @@ RSpec.describe Admin::EmailTemplatesController do it "returns the restored email template" do delete '/admin/customize/email_templates/user_notifications.admin_login', headers: headers - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present diff --git a/spec/requests/admin/flagged_topics_controller_spec.rb b/spec/requests/admin/flagged_topics_controller_spec.rb index 8f768294bc..87dfde84e3 100644 --- a/spec/requests/admin/flagged_topics_controller_spec.rb +++ b/spec/requests/admin/flagged_topics_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Admin::FlaggedTopicsController do shared_examples "successfully retrieve list of flagged topics" do it "returns a list of flagged topics" do get "/admin/flagged_topics.json" - expect(response).to be_success + expect(response).to be_successful data = ::JSON.parse(response.body) expect(data['flagged_topics']).to be_present diff --git a/spec/requests/admin/flags_controller_spec.rb b/spec/requests/admin/flags_controller_spec.rb index 98ee91c851..1d711d590b 100644 --- a/spec/requests/admin/flags_controller_spec.rb +++ b/spec/requests/admin/flags_controller_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Admin::FlagsController do it 'should return the right response when nothing is flagged' do get '/admin/flags.json' - expect(response).to be_success + expect(response).to be_successful data = ::JSON.parse(response.body) expect(data["users"]).to eq([]) @@ -25,11 +25,11 @@ RSpec.describe Admin::FlagsController do get '/admin/flags.json' - expect(response).to be_success + expect(response).to be_successful data = ::JSON.parse(response.body) - data["users"].length == 2 - data["posts"].length == 1 + expect(data["users"].length).to eq(2) + expect(data["posts"].length).to eq(1) end end @@ -49,9 +49,8 @@ RSpec.describe Admin::FlagsController do expect(post_action.agreed_by_id).to eq(admin.id) - post_1 = Post.offset(1).last - - expect(post_1.raw).to eq(I18n.with_locale(:en) { I18n.t('flags_dispositions.agreed') }) + agree_post = Topic.joins(:topic_allowed_users).where('topic_allowed_users.user_id = ?', user.id).order(:id).last.posts.last + expect(agree_post.raw).to eq(I18n.with_locale(:en) { I18n.t('flags_dispositions.agreed') }) end end end diff --git a/spec/requests/admin/moderation_history_controller_spec.rb b/spec/requests/admin/moderation_history_controller_spec.rb index f16d340fae..1b73f38668 100644 --- a/spec/requests/admin/moderation_history_controller_spec.rb +++ b/spec/requests/admin/moderation_history_controller_spec.rb @@ -10,28 +10,28 @@ RSpec.describe Admin::BackupsController do describe "parameters" do it "returns 404 without a valid filter" do get "/admin/moderation_history.json" - expect(response).not_to be_success + expect(response).not_to be_successful end it "returns 404 without a valid id" do get "/admin/moderation_history.json?filter=topic" - expect(response).not_to be_success + expect(response).not_to be_successful end end describe "for a post" do it "returns an empty array when the post doesn't exist" do get "/admin/moderation_history.json?filter=post&post_id=99999999" - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['moderation_history']).to be_blank end it "returns a history when the post exists" do p = Fabricate(:post) - p = Fabricate(:post, topic_id: p.topic_id) + p = Fabricate(:post, topic: p.topic) PostDestroyer.new(Discourse.system_user, p).destroy get "/admin/moderation_history.json?filter=post&post_id=#{p.id}" - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['moderation_history']).to be_present end @@ -40,7 +40,7 @@ RSpec.describe Admin::BackupsController do describe "for a topic" do it "returns empty history when the topic doesn't exist" do get "/admin/moderation_history.json?filter=topic&topic_id=1234" - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['moderation_history']).to be_blank end @@ -48,7 +48,7 @@ RSpec.describe Admin::BackupsController do p = Fabricate(:post) PostDestroyer.new(Discourse.system_user, p).destroy get "/admin/moderation_history.json?filter=topic&topic_id=#{p.topic_id}" - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['moderation_history']).to be_present end end diff --git a/spec/requests/admin/search_logs_spec.rb b/spec/requests/admin/search_logs_spec.rb index f811bfd44f..f872fb8700 100644 --- a/spec/requests/admin/search_logs_spec.rb +++ b/spec/requests/admin/search_logs_spec.rb @@ -28,7 +28,7 @@ RSpec.describe Admin::SearchLogsController do sign_in(admin) get '/admin/logs/search_logs.json' - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json[0]['term']).to eq('ruby') @@ -51,7 +51,7 @@ RSpec.describe Admin::SearchLogsController do sign_in(admin) get '/admin/logs/search_logs/term/ruby.json' - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['term']['type']).to eq('search_log_term') diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb index 3c1ca0ea2d..be6039564b 100644 --- a/spec/requests/categories_controller_spec.rb +++ b/spec/requests/categories_controller_spec.rb @@ -136,7 +136,7 @@ describe CategoriesController do expect do delete "/categories/#{category.slug}.json" end.to change(Category, :count).by(-1) - expect(response).to be_success + expect(response).to be_successful expect(UserHistory.count).to eq(1) end end @@ -321,14 +321,14 @@ describe CategoriesController do it 'accepts valid custom slug' do put "/category/#{category.id}/slug.json", params: { slug: 'valid-slug' } - expect(response).to be_success + expect(response).to be_successful expect(category.reload.slug).to eq('valid-slug') end it 'accepts not well formed custom slug' do put "/category/#{category.id}/slug.json", params: { slug: ' valid slug' } - expect(response).to be_success + expect(response).to be_successful expect(category.reload.slug).to eq('valid-slug') end @@ -336,7 +336,7 @@ describe CategoriesController do SiteSetting.slug_generation_method = 'none' put "/category/#{category.id}/slug.json", params: { slug: ' another !_ slug @' } - expect(response).to be_success + expect(response).to be_successful expect(category.reload.slug).to eq('another-slug') SiteSetting.slug_generation_method = 'ascii' end diff --git a/spec/requests/directory_items_controller_spec.rb b/spec/requests/directory_items_controller_spec.rb index c912634703..f9b0e08b88 100644 --- a/spec/requests/directory_items_controller_spec.rb +++ b/spec/requests/directory_items_controller_spec.rb @@ -14,7 +14,7 @@ describe DirectoryItemsController do it "requires a proper `period` param" do get '/directory_items.json', params: { period: 'eviltrout' } - expect(response).not_to be_success + expect(response).not_to be_successful end context "without data" do @@ -24,7 +24,7 @@ describe DirectoryItemsController do it "succeeds" do get '/directory_items.json', params: { period: 'all' } - expect(response).to be_success + expect(response).to be_successful end end @@ -37,7 +37,7 @@ describe DirectoryItemsController do it "succeeds with a valid value" do get '/directory_items.json', params: { period: 'all' } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -53,12 +53,12 @@ describe DirectoryItemsController do SiteSetting.enable_user_directory = false get '/directory_items.json', params: { period: 'all' } - expect(response).not_to be_success + expect(response).not_to be_successful end it "finds user by name" do get '/directory_items.json', params: { period: 'all', name: 'eviltrout' } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -69,7 +69,7 @@ describe DirectoryItemsController do it "finds staged user by name" do get '/directory_items.json', params: { period: 'all', name: 'stage_user' } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -80,7 +80,7 @@ describe DirectoryItemsController do it "excludes users by username" do get '/directory_items.json', params: { period: 'all', exclude_usernames: "stage_user,eviltrout" } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -92,7 +92,7 @@ describe DirectoryItemsController do it "filters users by group" do get '/directory_items.json', params: { period: 'all', group: group.name } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present diff --git a/spec/requests/email_controller_spec.rb b/spec/requests/email_controller_spec.rb index 188ac1807f..062c24461a 100644 --- a/spec/requests/email_controller_spec.rb +++ b/spec/requests/email_controller_spec.rb @@ -145,7 +145,7 @@ RSpec.describe EmailController do key = SecureRandom.hex $redis.set(key, user.email) get '/email/unsubscribed', params: { key: key, topic_id: topic.id } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(topic.title) end end @@ -155,7 +155,7 @@ RSpec.describe EmailController do key = SecureRandom.hex $redis.set(key, user.email) get '/email/unsubscribed', params: { key: key, topic_id: private_topic.id } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to_not include(private_topic.title) end end diff --git a/spec/requests/embed_controller_spec.rb b/spec/requests/embed_controller_spec.rb index 42b6f018d3..c62222a8cc 100644 --- a/spec/requests/embed_controller_spec.rb +++ b/spec/requests/embed_controller_spec.rb @@ -27,7 +27,7 @@ describe EmbedController do it "allows a topic to be embedded by id" do topic = Fabricate(:topic) get '/embed/comments', params: { topic_id: topic.id }, headers: headers - expect(response).to be_success + expect(response).to be_successful end end @@ -85,7 +85,7 @@ describe EmbedController do end after do - expect(response).to be_success + expect(response).to be_successful expect(response.headers['X-Frame-Options']).to eq("ALLOWALL") end @@ -139,7 +139,7 @@ describe EmbedController do params: { embed_url: embed_url }, headers: { 'REFERER' => "http://eviltrout.com/wat/1-2-3.html" } - expect(response).to be_success + expect(response).to be_successful end it "works with the second host" do @@ -147,7 +147,7 @@ describe EmbedController do params: { embed_url: embed_url }, headers: { 'REFERER' => "http://eviltrout.com/wat/1-2-3.html" } - expect(response).to be_success + expect(response).to be_successful end it "works with a host with a path" do @@ -155,7 +155,7 @@ describe EmbedController do params: { embed_url: embed_url }, headers: { 'REFERER' => "https://example.com/some-other-path" } - expect(response).to be_success + expect(response).to be_successful end it "contains custom class name" do diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb index 9e9e4d4d42..7e2b69fc77 100644 --- a/spec/requests/groups_controller_spec.rb +++ b/spec/requests/groups_controller_spec.rb @@ -152,7 +152,7 @@ describe GroupsController do staff_group get "/groups.json" - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) @@ -192,7 +192,7 @@ describe GroupsController do describe 'owner groups' do it 'should return the right response' do group2 = Fabricate(:group) - group3 = Fabricate(:group) + _group3 = Fabricate(:group) group2.add_owner(admin) expect_type_to_return_right_groups('owner', [group.id, group2.id]) @@ -219,7 +219,7 @@ describe GroupsController do describe 'close groups' do it 'should return the right response' do group2 = Fabricate(:group, public_admission: false) - group3 = Fabricate(:group, public_admission: true) + _group3 = Fabricate(:group, public_admission: true) expect_type_to_return_right_groups('close', [group.id, group2.id]) end @@ -382,7 +382,7 @@ describe GroupsController do sign_in(user) get "/groups/#{group.name}/mentionable.json" - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) expect(response_body["mentionable"]).to eq(false) @@ -393,7 +393,7 @@ describe GroupsController do ) get "/groups/#{group.name}/mentionable.json" - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) expect(response_body["mentionable"]).to eq(true) @@ -405,7 +405,7 @@ describe GroupsController do sign_in(user) get "/groups/#{group.name}/messageable.json" - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) expect(response_body["messageable"]).to eq(false) @@ -416,7 +416,7 @@ describe GroupsController do ) get "/groups/#{group.name}/messageable.json" - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) expect(response_body["messageable"]).to eq(true) @@ -645,7 +645,7 @@ describe GroupsController do order: 'last_seen_at', desc: true } - expect(response).to be_success + expect(response).to be_successful members = JSON.parse(response.body)["members"] @@ -653,7 +653,7 @@ describe GroupsController do get "/groups/#{group.name}/members.json", params: { order: 'last_seen_at' } - expect(response).to be_success + expect(response).to be_successful members = JSON.parse(response.body)["members"] @@ -663,7 +663,7 @@ describe GroupsController do order: 'last_posted_at', desc: true } - expect(response).to be_success + expect(response).to be_successful members = JSON.parse(response.body)["members"] @@ -673,7 +673,7 @@ describe GroupsController do it "should not allow members to be sorted by columns that are not allowed" do get "/groups/#{group.name}/members.json", params: { order: 'email' } - expect(response).to be_success + expect(response).to be_successful members = JSON.parse(response.body)["members"] @@ -808,7 +808,7 @@ describe GroupsController do put "/groups/#{group.id}/members.json", params: { usernames: user2.username } end.to change { group.users.count }.by(1) - expect(response).to be_success + expect(response).to be_successful group_history = GroupHistory.last @@ -834,7 +834,7 @@ describe GroupsController do params: { usernames: [user1.username, user2.username].join(",") } end.to change { group.users.count }.by(2) - expect(response).to be_success + expect(response).to be_successful end it "adds by id" do @@ -843,7 +843,7 @@ describe GroupsController do params: { user_ids: [user1.id, user2.id].join(",") } end.to change { group.users.count }.by(2) - expect(response).to be_success + expect(response).to be_successful end it "adds by email" do @@ -852,7 +852,7 @@ describe GroupsController do params: { user_emails: [user1.email, user2.email].join(",") } end.to change { group.users.count }.by(2) - expect(response).to be_success + expect(response).to be_successful end it 'fails when multiple member already exists' do @@ -920,7 +920,7 @@ describe GroupsController do params: { usernames: other_user.username } end.to change { group.users.count }.by(1) - expect(response).to be_success + expect(response).to be_successful group_history = GroupHistory.last @@ -938,7 +938,7 @@ describe GroupsController do params: { usernames: other_user.username } end.to change { group.users.count }.by(1) - expect(response).to be_success + expect(response).to be_successful end it 'should not allow an underprivilege user to add another user to a group' do @@ -971,7 +971,7 @@ describe GroupsController do delete "/groups/#{group.id}/members.json", params: { user_id: user.id } end.to change { group.users.count }.by(-1) - expect(response).to be_success + expect(response).to be_successful end it "removes by username" do @@ -979,7 +979,7 @@ describe GroupsController do delete "/groups/#{group.id}/members.json", params: { username: user.username } end.to change { group.users.count }.by(-1) - expect(response).to be_success + expect(response).to be_successful end it "removes user.primary_group_id when user is removed from group" do @@ -996,7 +996,7 @@ describe GroupsController do params: { user_email: user.email } end.to change { group.users.count }.by(-1) - expect(response).to be_success + expect(response).to be_successful end context 'public group' do @@ -1010,7 +1010,7 @@ describe GroupsController do params: { username: other_user.username } end.to change { group.users.count }.by(-1) - expect(response).to be_success + expect(response).to be_successful end end @@ -1022,7 +1022,7 @@ describe GroupsController do params: { username: other_user.username } end.to change { group.users.count }.by(-1) - expect(response).to be_success + expect(response).to be_successful end it 'should not allow a underprivilege user to leave a group for another user' do @@ -1077,7 +1077,7 @@ describe GroupsController do it 'should allow group owner to view history' do get "/groups/#{group.name}/logs.json" - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body)["logs"].last @@ -1109,7 +1109,7 @@ describe GroupsController do get "/groups/#{group.name}/logs.json" - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body)["logs"].first @@ -1132,7 +1132,7 @@ describe GroupsController do filters: { "action" => "add_user_to_group" } } - expect(response).to be_success + expect(response).to be_successful logs = JSON.parse(response.body)["logs"] @@ -1167,7 +1167,7 @@ describe GroupsController do post "/groups/#{group.name}/request_membership.json", params: { reason: 'Please add me in' } - expect(response).to be_success + expect(response).to be_successful post = Post.last topic = post.topic @@ -1217,7 +1217,7 @@ describe GroupsController do get '/groups/search.json' - expect(response).to be_success + expect(response).to be_successful groups = JSON.parse(response.body) expected_ids = Group::AUTO_GROUPS.map { |name, id| id } @@ -1229,7 +1229,7 @@ describe GroupsController do ['GO', 'nerys'].each do |term| get "/groups/search.json?term=#{term}" - expect(response).to be_success + expect(response).to be_successful groups = JSON.parse(response.body) expect(groups.length).to eq(1) @@ -1238,7 +1238,7 @@ describe GroupsController do get "/groups/search.json?term=KingOfTheNorth" - expect(response).to be_success + expect(response).to be_successful groups = JSON.parse(response.body) expect(groups).to eq([]) @@ -1255,7 +1255,7 @@ describe GroupsController do get "/groups/search.json?term=north" - expect(response).to be_success + expect(response).to be_successful groups = JSON.parse(response.body) expect(groups.length).to eq(1) @@ -1269,7 +1269,7 @@ describe GroupsController do get '/groups/search.json?ignore_automatic=true' - expect(response).to be_success + expect(response).to be_successful groups = JSON.parse(response.body) expect(groups.length).to eq(2) diff --git a/spec/requests/invites_controller_spec.rb b/spec/requests/invites_controller_spec.rb index 05deb5a832..b945453b71 100644 --- a/spec/requests/invites_controller_spec.rb +++ b/spec/requests/invites_controller_spec.rb @@ -8,7 +8,7 @@ describe InvitesController do it "returns error if invite not found" do get "/invites/nopeNOPEnope" - expect(response).to be_success + expect(response).to be_successful body = response.body expect(body).to_not have_tag(:script, with: { src: '/assets/application.js' }) @@ -18,7 +18,7 @@ describe InvitesController do it "renders the accept invite page if invite exists" do get "/invites/#{invite.invite_key}" - expect(response).to be_success + expect(response).to be_successful body = response.body expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) @@ -29,7 +29,7 @@ describe InvitesController do invite.update_attributes!(redeemed_at: 1.day.ago) get "/invites/#{invite.invite_key}" - expect(response).to be_success + expect(response).to be_successful body = response.body expect(body).to_not have_tag(:script, with: { src: '/assets/application.js' }) @@ -100,7 +100,7 @@ describe InvitesController do group = Fabricate(:group) sign_in(Fabricate(:admin)) post "/invites.json", params: { email: email, group_names: group.name } - expect(response).to be_success + expect(response).to be_successful expect(Invite.find_by(email: email).invited_groups.count).to eq(1) end @@ -112,7 +112,7 @@ describe InvitesController do post "/invites.json", params: { email: email, group_names: group.name } - expect(response).to be_success + expect(response).to be_successful expect(Invite.find_by(email: email).invited_groups.count).to eq(1) end @@ -120,7 +120,7 @@ describe InvitesController do user = sign_in(Fabricate(:admin)) invite = Invite.invite_by_email("invite@example.com", user) post "/invites.json", params: { email: invite.email } - expect(response).to be_success + expect(response).to be_successful end it "responds with error message in case of validation failure" do @@ -182,7 +182,7 @@ describe InvitesController do email: email, group_names: group.name } - expect(response).to be_success + expect(response).to be_successful expect(Invite.find_by(email: email).invited_groups.count).to eq(1) end @@ -195,7 +195,7 @@ describe InvitesController do email: email, group_names: "security,support" } - expect(response).to be_success + expect(response).to be_successful expect(Invite.find_by(email: email).invited_groups.count).to eq(2) end end @@ -205,7 +205,7 @@ describe InvitesController do context 'with an invalid invite id' do it "redirects to the root and doesn't change the session" do put "/invites/show/doesntexist.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["success"]).to eq(false) expect(json["message"]).to eq(I18n.t('invite.not_found')) @@ -223,7 +223,7 @@ describe InvitesController do it "redirects to the root" do put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["success"]).to eq(false) expect(json["message"]).to eq(I18n.t('invite.not_found')) @@ -254,7 +254,7 @@ describe InvitesController do :user_logged_in, :user_first_logged_in ) invite.reload - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(invite.user_id) expect(invite.redeemed?).to be_truthy end @@ -271,7 +271,7 @@ describe InvitesController do context 'failure' do it "doesn't log in the user if there's a validation error" do put "/invites/show/#{invite.invite_key}.json", params: { password: "password" } - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["success"]).to eq(false) expect(json["errors"]["password"]).to be_present @@ -286,13 +286,13 @@ describe InvitesController do it 'sends a welcome message if set' do user.send_welcome_message = true put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_success + expect(response).to be_successful expect(Jobs::SendSystemMessage.jobs.size).to eq(1) end it "sends password reset email if password is not set" do put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_success + expect(response).to be_successful expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(1) end @@ -300,20 +300,20 @@ describe InvitesController do SiteSetting.sso_url = "https://www.example.com/sso" SiteSetting.enable_sso = true put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_success + expect(response).to be_successful expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) end it "does not send password reset email if local login is disabled" do SiteSetting.enable_local_logins = false put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_success + expect(response).to be_successful expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) end it 'sends an activation email if password is set' do put "/invites/show/#{invite.invite_key}.json", params: { password: "verystrongpassword" } - expect(response).to be_success + expect(response).to be_successful expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) expect(Jobs::CriticalUserEmail.jobs.size).to eq(1) end @@ -381,7 +381,7 @@ describe InvitesController do it "resends the invite" do SiteSetting.queue_jobs = true post "/invites/reinvite.json", params: { email: invite.email } - expect(response).to be_success + expect(response).to be_successful expect(Jobs::InviteEmail.jobs.size).to eq(1) end end @@ -412,7 +412,7 @@ describe InvitesController do SiteSetting.queue_jobs = true sign_in(Fabricate(:admin)) post "/invites/upload_csv.json", params: { file: file, name: filename } - expect(response).to be_success + expect(response).to be_successful expect(Jobs::BulkInvite.jobs.size).to eq(1) end end diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index 5910aa3c57..f7bb4286cf 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -13,19 +13,19 @@ RSpec.describe ListController do describe '#index' do it "doesn't throw an error with a negative page" do get "/#{Discourse.anonymous_filters[1]}", params: { page: -1024 } - expect(response).to be_success + expect(response).to be_successful end it "doesn't throw an error with page params as an array" do get "/#{Discourse.anonymous_filters[1]}", params: { page: ['7'] } - expect(response).to be_success + expect(response).to be_successful end (Discourse.anonymous_filters - [:categories]).each do |filter| context "#{filter}" do it "succeeds" do get "/#{filter}" - expect(response).to be_success + expect(response).to be_successful end end end @@ -34,7 +34,7 @@ RSpec.describe ListController do p = create_post get "/latest.json", params: { topic_ids: "#{p.topic_id}" } - expect(response).to be_success + expect(response).to be_successful parsed = JSON.parse(response.body) expect(parsed["topic_list"]["topics"].length).to eq(1) end @@ -238,20 +238,20 @@ RSpec.describe ListController do describe 'RSS feeds' do it 'renders latest RSS' do get "/latest.rss" - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/rss+xml') end it 'renders top RSS' do get "/top.rss" - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/rss+xml') end TopTopic.periods.each do |period| it "renders #{period} top RSS" do get "/top/#{period}.rss" - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/rss+xml') end end @@ -312,7 +312,7 @@ RSpec.describe ListController do it 'uses the correct category' do get "/c/#{other_category.slug}/l/latest.json" - expect(response).to be_success + expect(response).to be_successful body = JSON.parse(response.body) expect(body["topic_list"]["topics"].first["category_id"]) .to eq(other_category.id) @@ -340,7 +340,7 @@ RSpec.describe ListController do describe 'feed' do it 'renders RSS' do get "/c/#{category.slug}.rss" - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/rss+xml') end end @@ -349,7 +349,7 @@ RSpec.describe ListController do it "has a top default view" do category.update_attributes!(default_view: 'top', default_top_period: 'monthly') get "/c/#{category.slug}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to eq("monthly") end @@ -357,7 +357,7 @@ RSpec.describe ListController do it "has a default view of nil" do category.update_attributes!(default_view: nil) get "/c/#{category.slug}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to be_blank end @@ -365,7 +365,7 @@ RSpec.describe ListController do it "has a default view of ''" do category.update_attributes!(default_view: '') get "/c/#{category.slug}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to be_blank end @@ -373,7 +373,7 @@ RSpec.describe ListController do it "has a default view of latest" do category.update_attributes!(default_view: 'latest') get "/c/#{category.slug}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to be_blank end @@ -382,13 +382,13 @@ RSpec.describe ListController do describe "renders canonical tag" do it 'for category default view' do get "/c/#{category.slug}" - expect(response).to be_success + expect(response).to be_successful expect(css_select("link[rel=canonical]").length).to eq(1) end it 'for category latest view' do get "/c/#{category.slug}/l/latest" - expect(response).to be_success + expect(response).to be_successful expect(css_select("link[rel=canonical]").length).to eq(1) end end @@ -403,7 +403,7 @@ RSpec.describe ListController do it "should respond with a list" do get "/topics/created-by/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -421,7 +421,7 @@ RSpec.describe ListController do pm.topic_allowed_users.create!(user: user) sign_in(user) get "/topics/private-messages/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -442,7 +442,7 @@ RSpec.describe ListController do it "succeeds when the user can see private messages" do sign_in(user) get "/topics/private-messages-sent/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -465,7 +465,7 @@ RSpec.describe ListController do it "succeeds when the user can see private messages" do sign_in(user) get "/topics/private-messages-unread/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -481,7 +481,7 @@ RSpec.describe ListController do it "succeeds" do sign_in(user) get "/read" - expect(response).to be_success + expect(response).to be_successful end end end @@ -546,7 +546,7 @@ RSpec.describe ListController do it "suppresses categories from the latest list" do get "/#{SiteSetting.homepage}.json" - expect(response).to be_success + expect(response).to be_successful topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } expect(topic_titles).not_to include(topic_in_sub_category.title, topic_in_category_two.title) @@ -554,7 +554,7 @@ RSpec.describe ListController do it "does not suppress" do get "/#{SiteSetting.homepage}.json", params: { category: category_one.id } - expect(response).to be_success + expect(response).to be_successful topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } expect(topic_titles).to include(topic_in_sub_category.title) diff --git a/spec/requests/notifications_controller_spec.rb b/spec/requests/notifications_controller_spec.rb index a55ae2e5b1..f7dede2aa5 100644 --- a/spec/requests/notifications_controller_spec.rb +++ b/spec/requests/notifications_controller_spec.rb @@ -36,12 +36,12 @@ describe NotificationsController do describe '#index' do it 'should succeed for recent' do get "/notifications", params: { recent: true } - expect(response).to be_success + expect(response).to be_successful end it 'should succeed for history' do get "/notifications" - expect(response).to be_success + expect(response).to be_successful end it 'should mark notifications as viewed' do @@ -72,14 +72,14 @@ describe NotificationsController do it 'should succeed' do put "/notifications/mark-read.json" - expect(response).to be_success + expect(response).to be_successful end it "can update a single notification" do notification = Fabricate(:notification, user: user) notification2 = Fabricate(:notification, user: user) put "/notifications/mark-read.json", params: { id: notification.id } - expect(response).to be_success + expect(response).to be_successful notification.reload notification2.reload diff --git a/spec/requests/omniauth_callbacks_controller_spec.rb b/spec/requests/omniauth_callbacks_controller_spec.rb index 5e0a18edd9..a7316c7651 100644 --- a/spec/requests/omniauth_callbacks_controller_spec.rb +++ b/spec/requests/omniauth_callbacks_controller_spec.rb @@ -80,7 +80,7 @@ RSpec.describe Users::OmniauthCallbacksController do expect(events.map { |event| event[:event_name] }).to include(:user_logged_in, :user_first_logged_in) - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) @@ -106,7 +106,7 @@ RSpec.describe Users::OmniauthCallbacksController do expect(events.map { |event| event[:event_name] }).to include(:user_logged_in, :user_first_logged_in) - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.email_confirmed?).to eq(true) @@ -125,7 +125,7 @@ RSpec.describe Users::OmniauthCallbacksController do expect(events.map { |event| event[:event_name] }).to include(:user_logged_in, :user_first_logged_in) - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.staged).to eq(false) @@ -185,7 +185,7 @@ RSpec.describe Users::OmniauthCallbacksController do it 'should return the right response' do get "/auth/google_oauth2/callback.json" - expect(response).to be_success + expect(response).to be_successful response_body = JSON.parse(response.body) diff --git a/spec/requests/onebox_controller_spec.rb b/spec/requests/onebox_controller_spec.rb index 3616c2a819..04d9da91fc 100644 --- a/spec/requests/onebox_controller_spec.rb +++ b/spec/requests/onebox_controller_spec.rb @@ -56,13 +56,13 @@ describe OneboxController do bypass_limiting Rails.cache.delete("onebox__#{url}") get "/onebox.json", params: { url: url } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include("Onebox1") bypass_limiting stub_request(:get, url).to_return(status: 200, body: html2).then.to_raise get "/onebox.json", params: { url: url, refresh: 'true' } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include("Onebox2") end @@ -75,12 +75,12 @@ describe OneboxController do get "/onebox.json", params: { url: url, refresh: "true" } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include('Onebox1') expect(response.body).to include('bodycontent') get "/onebox.json", params: { url: url } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include('Onebox1') expect(response.body).to include('bodycontent') end @@ -104,7 +104,7 @@ describe OneboxController do stub_request(:get, url).to_return(body: html).then.to_raise get "/onebox.json", params: { url: url, refresh: "true" } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include("Onebox1") end end diff --git a/spec/requests/post_actions_controller_spec.rb b/spec/requests/post_actions_controller_spec.rb index cb20f94f3a..c89d68b772 100644 --- a/spec/requests/post_actions_controller_spec.rb +++ b/spec/requests/post_actions_controller_spec.rb @@ -79,7 +79,7 @@ RSpec.describe PostActionsController do id: post_1.id, post_action_type_id: PostActionType.types[:off_topic] } - expect(response).to_not be_success + expect(response).to_not be_successful end it 'passes the message through' do @@ -133,7 +133,7 @@ RSpec.describe PostActionsController do take_action: 'true' } - expect(response).to be_success + expect(response).to be_successful post_action = PostAction.last @@ -149,7 +149,7 @@ RSpec.describe PostActionsController do post_action_type_id: PostActionType.types[:like] } - expect(response).to be_success + expect(response).to be_successful post_action = PostAction.last diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb index cd225dabf3..74d6c3ea35 100644 --- a/spec/requests/posts_controller_spec.rb +++ b/spec/requests/posts_controller_spec.rb @@ -14,7 +14,7 @@ shared_examples 'finding and showing post' do it 'succeeds' do get url - expect(response).to be_success + expect(response).to be_successful end context "deleted post" do @@ -36,13 +36,13 @@ shared_examples 'finding and showing post' do it "can find posts as a moderator" do sign_in(Fabricate(:moderator)) get url - expect(response).to be_success + expect(response).to be_successful end it "can find posts as a admin" do sign_in(Fabricate(:admin)) get url - expect(response).to be_success + expect(response).to be_successful end end end @@ -62,7 +62,7 @@ describe PostsController do let(:topicless_post) { Fabricate(:post, user: user, raw: '

Car 54, where are you?

') } let(:private_topic) do - Fabricate(:topic, archetype: Archetype.private_message, category: nil) + Fabricate(:topic, archetype: Archetype.private_message, category_id: nil) end let(:private_post) { Fabricate(:post, user: user, topic: private_topic) } @@ -127,7 +127,7 @@ describe PostsController do it 'does not allow to destroy when edit time limit expired' do SiteSetting.post_edit_time_limit = 5 - post = Fabricate(:post, topic_id: topic.id, created_at: 10.minutes.ago, user_id: user.id, post_number: 3) + post = Fabricate(:post, topic: topic, created_at: 10.minutes.ago, user: user, post_number: 3) sign_in(user) delete "/posts/#{post.id}.json" @@ -165,7 +165,7 @@ describe PostsController do describe 'when logged in' do let(:poster) { Fabricate(:moderator) } let(:post1) { Fabricate(:post, user: poster, post_number: 2) } - let(:post2) { Fabricate(:post, topic_id: post1.topic_id, user: poster, post_number: 3, reply_to_post_number: post1.post_number) } + let(:post2) { Fabricate(:post, topic: post1.topic, user: poster, post_number: 3, reply_to_post_number: post1.post_number) } it "raises invalid parameters no post_ids" do sign_in(poster) @@ -277,7 +277,7 @@ describe PostsController do it 'passes the edit reason through' do put "/posts/#{post.id}.json", params: update_params - expect(response).to be_success + expect(response).to be_successful post.reload expect(post.edit_reason).to eq("typo") expect(post.raw).to eq("edited body") @@ -307,7 +307,7 @@ describe PostsController do put "/posts/#{post.id}.json", params: param - expect(response).to be_success + expect(response).to be_successful expect(TopicLink.count).to eq(1) end @@ -316,7 +316,7 @@ describe PostsController do PostDestroyer.new(moderator, first_post).destroy put "/posts/#{first_post.id}.json", params: update_params - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -330,7 +330,7 @@ describe PostsController do PostDestroyer.new(moderator, first_post).destroy put "/posts/#{first_post.id}.json", params: update_params - expect(response).to be_success + expect(response).to be_successful post.reload expect(post.raw).to eq('edited body') @@ -373,7 +373,7 @@ describe PostsController do it 'creates a bookmark' do put "/posts/#{post.id}/bookmark.json", params: { bookmarked: "true" } - expect(response).to be_success + expect(response).to be_successful post_action = PostAction.find_by(user: user, post: post) expect(post_action.post_action_type_id).to eq(PostActionType.types[:bookmark]) @@ -435,7 +435,7 @@ describe PostsController do api_key: api_key.key } - expect(response).to be_success + expect(response).to be_successful expect(PostAction.where( post: post, user: user, @@ -460,7 +460,7 @@ describe PostsController do api_username: user.username } - expect(response).to be_success + expect(response).to be_successful expect(PostAction.where( post: post, user: user, @@ -587,7 +587,7 @@ describe PostsController do it "can rebake the post" do sign_in(Fabricate(:moderator)) put "/posts/#{post.id}/rebake.json" - expect(response).to be_success + expect(response).to be_successful end end end @@ -617,7 +617,7 @@ describe PostsController do wpid: 1 } - expect(response).to be_success + expect(response).to be_successful original = response.body post "/posts.json", params: { @@ -628,7 +628,7 @@ describe PostsController do wpid: 2 } - expect(response).to be_success + expect(response).to be_successful expect(response.body).to eq(original) end @@ -647,7 +647,7 @@ describe PostsController do reply_to_post_number: 1 } - expect(response).to be_success + expect(response).to be_successful expect(post_1.topic.user.notifications.count).to eq(1) post_1.topic.user.notifications.destroy_all @@ -660,7 +660,7 @@ describe PostsController do import_mode: true } - expect(response).to be_success + expect(response).to be_successful expect(post_1.topic.user.notifications.count).to eq(0) post "/posts.json", params: { @@ -672,7 +672,7 @@ describe PostsController do import_mode: false } - expect(response).to be_success + expect(response).to be_successful expect(post_1.topic.user.notifications.count).to eq(1) end end @@ -694,7 +694,7 @@ describe PostsController do title: 'this is the test title for the topic' } - expect(response).to be_success + expect(response).to be_successful parsed = ::JSON.parse(response.body) expect(parsed["action"]).to eq("enqueued") @@ -720,7 +720,7 @@ describe PostsController do topic_id: topic.id } - expect(response).not_to be_success + expect(response).not_to be_successful parsed = ::JSON.parse(response.body) expect(parsed["action"]).not_to eq("enqueued") end @@ -733,7 +733,7 @@ describe PostsController do title: 'this is the test title for the topic' } - expect(response).not_to be_success + expect(response).not_to be_successful parsed = ::JSON.parse(response.body) expect(parsed["action"]).not_to eq("enqueued") end @@ -747,7 +747,7 @@ describe PostsController do title: 'when I eat s3 sometimes when not looking' } - expect(response).to be_success + expect(response).to be_successful parsed = ::JSON.parse(response.body) expect(parsed["action"]).to eq("enqueued") @@ -768,7 +768,7 @@ describe PostsController do archetype: Archetype.private_message } - expect(response).not_to be_success + expect(response).not_to be_successful # allow pm to this group group.update_columns(messageable_level: Group::ALIAS_LEVELS[:everyone]) @@ -780,7 +780,7 @@ describe PostsController do archetype: Archetype.private_message } - expect(response).to be_success + expect(response).to be_successful parsed = ::JSON.parse(response.body) post = Post.find(parsed['id']) @@ -796,7 +796,7 @@ describe PostsController do nested_post: true } - expect(response).to be_success + expect(response).to be_successful parsed = ::JSON.parse(response.body) expect(parsed['post']).to be_present expect(parsed['post']['cooked']).to be_present @@ -807,10 +807,10 @@ describe PostsController do title = "this is a title #{SecureRandom.hash}" post "/posts.json", params: { raw: raw, title: title, wpid: 1 } - expect(response).to be_success + expect(response).to be_successful post "/posts.json", params: { raw: raw, title: title, wpid: 2 } - expect(response).not_to be_success + expect(response).not_to be_successful end it 'can not create a post in a disallowed category' do @@ -835,7 +835,7 @@ describe PostsController do meta_data: { xyz: 'abc' } } - expect(response).to be_success + expect(response).to be_successful new_post = Post.last topic = new_post.topic @@ -858,7 +858,7 @@ describe PostsController do image_sizes: { width: '100', height: '200' } } - expect(response).to be_success + expect(response).to be_successful new_post = Post.last topic = new_post.topic @@ -883,7 +883,7 @@ describe PostsController do target_usernames: "#{user_2.username},#{user_3.username}" } - expect(response).to be_success + expect(response).to be_successful new_post = Post.last new_topic = Topic.last @@ -896,7 +896,7 @@ describe PostsController do context "errors" do it "does not succeed" do post "/posts.json", params: { raw: 'test' } - expect(response).not_to be_success + expect(response).not_to be_successful expect(response.status).to eq(422) end @@ -925,7 +925,7 @@ describe PostsController do category: destination_category.id, shared_draft: 'true' } - expect(response).not_to be_success + expect(response).not_to be_successful end describe "as a staff user" do @@ -940,7 +940,7 @@ describe PostsController do category: destination_category.id, shared_draft: 'true' } - expect(response).not_to be_success + expect(response).not_to be_successful end context "with a shared category" do @@ -956,7 +956,7 @@ describe PostsController do category: destination_category.id, shared_draft: 'true' } - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) topic = Topic.find(result['topic_id']) expect(topic.category_id).to eq(shared_category.id) @@ -983,7 +983,7 @@ describe PostsController do is_warning: true } - expect(response).to be_success + expect(response).to be_successful new_topic = Topic.last @@ -1000,7 +1000,7 @@ describe PostsController do is_warning: false } - expect(response).to be_success + expect(response).to be_successful new_topic = Topic.last @@ -1020,7 +1020,7 @@ describe PostsController do is_warning: true } - expect(response).to be_success + expect(response).to be_successful new_topic = Topic.last @@ -1058,7 +1058,7 @@ describe PostsController do it "ensures staff can see the revisions" do sign_in(Fabricate(:admin)) get "/posts/#{post.id}/revisions/#{post_revision.number}.json" - expect(response).to be_success + expect(response).to be_successful end it "ensures poster can see the revisions" do @@ -1069,13 +1069,13 @@ describe PostsController do pr = Fabricate(:post_revision, user: user, post: post) get "/posts/#{pr.post_id}/revisions/#{pr.number}.json" - expect(response).to be_success + expect(response).to be_successful end it "ensures trust level 4 can see the revisions" do sign_in(Fabricate(:user, trust_level: 4)) get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response).to be_success + expect(response).to be_successful end end @@ -1085,7 +1085,7 @@ describe PostsController do it "ensures anyone can see the revisions" do get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response).to be_success + expect(response).to be_successful end end @@ -1099,7 +1099,7 @@ describe PostsController do it "also work on deleted post" do sign_in(admin) get "/posts/#{deleted_post_revision.post_id}/revisions/#{deleted_post_revision.number}.json" - expect(response).to be_success + expect(response).to be_successful end end @@ -1114,7 +1114,7 @@ describe PostsController do it "also work on deleted topic" do sign_in(admin) get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response).to be_success + expect(response).to be_successful end end end @@ -1135,7 +1135,7 @@ describe PostsController do it "does not work" do sign_in(Fabricate(:user)) put "/posts/#{post_id}/revisions/#{revision_id}/revert.json" - expect(response).to_not be_success + expect(response).to_not be_successful end end @@ -1151,12 +1151,12 @@ describe PostsController do it "fails when post_revision record is not found" do put "/posts/#{post_id}/revisions/#{revision_id + 1}/revert.json" - expect(response).to_not be_success + expect(response).to_not be_successful end it "fails when post record is not found" do put "/posts/#{post_id + 1}/revisions/#{revision_id}/revert.json" - expect(response).to_not be_success + expect(response).to_not be_successful end it "fails when revision is blank" do @@ -1173,7 +1173,7 @@ describe PostsController do it "works!" do put "/posts/#{post_id}/revisions/#{revision_id}/revert.json" - expect(response).to be_success + expect(response).to be_successful end it "supports reverting posts in deleted topics" do @@ -1181,7 +1181,7 @@ describe PostsController do PostDestroyer.new(moderator, first_post).destroy put "/posts/#{post_id}/revisions/#{revision_id}/revert.json" - expect(response).to be_success + expect(response).to be_successful end end end @@ -1196,13 +1196,13 @@ describe PostsController do it "raises an error when you can't see the post" do post = Fabricate(:private_message_post) get "/posts/#{post.id}/expand-embed.json" - expect(response).not_to be_success + expect(response).not_to be_successful end it "retrieves the body when you can see the post" do TopicEmbed.expects(:expanded_for).with(post).returns("full content") get "/posts/#{post.id}/expand-embed.json" - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['cooked']).to eq("full content") end end @@ -1220,7 +1220,7 @@ describe PostsController do it "can see the flagged posts when authorized" do sign_in(Fabricate(:moderator)) get "/posts/system/flagged.json" - expect(response).to be_success + expect(response).to be_successful end it "only shows agreed and deferred flags" do @@ -1241,7 +1241,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{user.username}/flagged.json" - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body).length).to eq(2) end @@ -1261,7 +1261,7 @@ describe PostsController do it "can see the deleted posts when authorized" do sign_in(Fabricate(:moderator)) get "/posts/system/deleted.json" - expect(response).to be_success + expect(response).to be_successful end it "doesn't return secured categories for moderators if they don't have access" do @@ -1278,7 +1278,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{user.username}/deleted.json" - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data.length).to eq(0) @@ -1294,7 +1294,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{user.username}/deleted.json" - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data.length).to eq(0) @@ -1313,7 +1313,7 @@ describe PostsController do sign_in(Fabricate(:admin)) get "/posts/#{user.username}/deleted.json" - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data.length).to eq(1) @@ -1327,7 +1327,7 @@ describe PostsController do it "can be viewed by anonymous" do post = Fabricate(:post, raw: "123456789") get "/posts/#{post.id}/raw.json" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to eq("123456789") end end @@ -1338,7 +1338,7 @@ describe PostsController do post = Fabricate(:post, topic: topic, post_number: 1, raw: "123456789") post.save get "/raw/#{topic.id}/1.json" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to eq("123456789") end end @@ -1366,7 +1366,7 @@ describe PostsController do get "/u/#{user.username}/activity.rss" - expect(response).to be_success + expect(response).to be_successful body = response.body @@ -1384,7 +1384,7 @@ describe PostsController do private_post get "/private-posts.rss" - expect(response).to be_success + expect(response).to be_successful body = response.body @@ -1398,7 +1398,7 @@ describe PostsController do public_post private_post get "/private-posts.json" - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) post_ids = json['private_posts'].map { |p| p['id'] } @@ -1415,7 +1415,7 @@ describe PostsController do get "/posts.rss" - expect(response).to be_success + expect(response).to be_successful body = response.body @@ -1431,7 +1431,7 @@ describe PostsController do topicless_post get "/posts.json" - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) post_ids = json['latest_posts'].map { |p| p['id'] } @@ -1448,7 +1448,7 @@ describe PostsController do post = Fabricate(:post, cooked: "WAt") get "/posts/#{post.id}/cooked.json" - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json).to be_present @@ -1473,7 +1473,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{post.id}/raw-email.json" - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['raw_email']).to eq('email_content') @@ -1488,12 +1488,12 @@ describe PostsController do it 'can lock and unlock the post' do put "/posts/#{public_post.id}/locked.json", params: { locked: "true" } - expect(response).to be_success + expect(response).to be_successful public_post.reload expect(public_post).to be_locked put "/posts/#{public_post.id}/locked.json", params: { locked: "false" } - expect(response).to be_success + expect(response).to be_successful public_post.reload expect(public_post).not_to be_locked end diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb index 7c8de16e56..1a5ab80d24 100644 --- a/spec/requests/search_controller_spec.rb +++ b/spec/requests/search_controller_spec.rb @@ -17,7 +17,7 @@ describe SearchController do term: 'awesome', include_blurb: true } - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data['posts'][0]['id']).to eq(my_post.id) expect(data['posts'][0]['blurb']).to eq('this is my really awesome post') @@ -32,7 +32,7 @@ describe SearchController do term: user.username, type_filter: 'topic' } - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data['posts'][0]['id']).to eq(my_post.id) @@ -42,7 +42,7 @@ describe SearchController do term: user.username, type_filter: 'user' } - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data['posts']).to be_blank @@ -61,7 +61,7 @@ describe SearchController do search_for_id: true } - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data['topics'][0]['id']).to eq(post.topic_id) @@ -77,7 +77,7 @@ describe SearchController do search_for_id: true } - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data['topics'][0]['id']).to eq(my_post.topic_id) @@ -90,7 +90,7 @@ describe SearchController do SiteSetting.log_search_queries = true get "/search/query.json", params: { term: 'wookie' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.where(term: 'wookie')).to be_present json = JSON.parse(response.body) @@ -105,7 +105,7 @@ describe SearchController do it "doesn't log when disabled" do SiteSetting.log_search_queries = false get "/search/query.json", params: { term: 'wookie' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.where(term: 'wookie')).to be_blank end end @@ -114,14 +114,14 @@ describe SearchController do it "logs the search term" do SiteSetting.log_search_queries = true get "/search.json", params: { q: 'bantha' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.where(term: 'bantha')).to be_present end it "doesn't log when disabled" do SiteSetting.log_search_queries = false get "/search.json", params: { q: 'bantha' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.where(term: 'bantha')).to be_blank end end @@ -155,7 +155,7 @@ describe SearchController do term: 'test', search_context: { type: 'user', id: user.username } } - expect(response).to be_success + expect(response).to be_successful end end @@ -187,7 +187,7 @@ describe SearchController do search_result_type: 'topic' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.find(search_log_id).search_result_id).to be_blank end @@ -207,7 +207,7 @@ describe SearchController do search_result_type: 'user' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.find(search_log_id).search_result_id).to eq(12345) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:user]) end @@ -228,7 +228,7 @@ describe SearchController do search_result_type: 'topic' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.find(search_log_id).search_result_id).to eq(22222) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:topic]) end @@ -246,7 +246,7 @@ describe SearchController do search_result_type: 'topic' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.find(search_log_id).search_result_id).to be_blank end @@ -266,7 +266,7 @@ describe SearchController do search_result_type: 'category' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.find(search_log_id).search_result_id).to eq(23456) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:category]) end @@ -288,7 +288,7 @@ describe SearchController do search_result_type: 'tag' } - expect(response).to be_success + expect(response).to be_successful expect(SearchLog.find(search_log_id).search_result_id).to eq(tag.id) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:tag]) end diff --git a/spec/requests/session_controller_spec.rb b/spec/requests/session_controller_spec.rb index 408cb6a399..51bff909d0 100644 --- a/spec/requests/session_controller_spec.rb +++ b/spec/requests/session_controller_spec.rb @@ -7,7 +7,7 @@ RSpec.describe SessionController do shared_examples 'failed to continue local login' do it 'should return the right response' do - expect(response).not_to be_success + expect(response).not_to be_successful expect(response.status).to eq(500) end end @@ -28,7 +28,7 @@ RSpec.describe SessionController do it 'returns the right response' do get "/session/email-login/adasdad" - expect(response).to be_success + expect(response).to be_successful expect(CGI.unescapeHTML(response.body)).to match( I18n.t('email_login.invalid_token') @@ -41,7 +41,7 @@ RSpec.describe SessionController do get "/session/email-login/#{email_token.token}" - expect(response).to be_success + expect(response).to be_successful expect(CGI.unescapeHTML(response.body)).to match( I18n.t('email_login.invalid_token') @@ -823,7 +823,7 @@ RSpec.describe SessionController do login: user.username, password: 'sssss' } - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['error']).to eq( I18n.t("login.incorrect_username_email_or_password") ) @@ -837,7 +837,7 @@ RSpec.describe SessionController do login: user.username, password: ('s' * (User.max_password_length + 1)) } - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['error']).to eq( I18n.t("login.incorrect_username_email_or_password") ) @@ -855,7 +855,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq(I18n.t('login.suspended_with_reason', date: I18n.l(user.suspended_till, format: :date_only), reason: Rack::Utils.escape_html(user.suspend_reason) @@ -872,7 +872,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq(I18n.t('login.not_activated')) end end @@ -885,7 +885,7 @@ RSpec.describe SessionController do } end - expect(response).to be_success + expect(response).to be_successful expect(events.map { |event| event[:event_name] }).to contain_exactly( :user_logged_in, :user_first_logged_in ) @@ -908,7 +908,7 @@ RSpec.describe SessionController do password: 'myawesomepassword', } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq(I18n.t( 'login.invalid_second_factor_code' )) @@ -923,7 +923,7 @@ RSpec.describe SessionController do second_factor_token: '00000000' } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq(I18n.t( 'login.invalid_second_factor_code' )) @@ -937,7 +937,7 @@ RSpec.describe SessionController do password: 'myawesomepassword', second_factor_token: ROTP::TOTP.new(user_second_factor.data).now } - expect(response).to be_success + expect(response).to be_successful user.reload expect(session[:current_user_id]).to eq(user.id) @@ -957,7 +957,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: "@" + user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful user.reload expect(session[:current_user_id]).to be_nil @@ -969,7 +969,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: "@" + user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful user.reload expect(session[:current_user_id]).to eq(user.id) @@ -981,7 +981,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: user.email, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(user.id) end end @@ -994,7 +994,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['error']).not_to be_present end @@ -1002,7 +1002,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: email, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(::JSON.parse(response.body)['error']).not_to be_present end end @@ -1020,12 +1020,12 @@ RSpec.describe SessionController do end it "doesn't log in the user" do - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to be_blank end it "shows the 'not approved' error message" do - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq( I18n.t('login.not_approved') ) @@ -1040,7 +1040,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: user.email, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(user.id) end end @@ -1063,7 +1063,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(user.id) end @@ -1076,7 +1076,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to be_present expect(session[:current_user_id]).not_to eq(user.id) end @@ -1090,7 +1090,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(user.id) end end @@ -1105,13 +1105,13 @@ RSpec.describe SessionController do it "doesn't log in the user" do post_login - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to be_blank end it "shows the 'not activated' error message" do post_login - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq( I18n.t 'login.not_activated' ) @@ -1122,7 +1122,7 @@ RSpec.describe SessionController do it "shows the 'not approved' error message" do post_login - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)['error']).to eq( I18n.t 'login.not_approved' ) @@ -1141,7 +1141,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_success + expect(response).to be_successful end post "/session.json", params: { @@ -1164,7 +1164,7 @@ RSpec.describe SessionController do second_factor_token: '000000' } - expect(response).to be_success + expect(response).to be_successful end post "/session.json", params: { @@ -1285,7 +1285,7 @@ RSpec.describe SessionController do it "returns the JSON for the user" do get "/session/current.json" - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['current_user']).to be_present expect(json['current_user']['id']).to eq(user.id) diff --git a/spec/requests/static_controller_spec.rb b/spec/requests/static_controller_spec.rb index 624bdadb2c..994167fad7 100644 --- a/spec/requests/static_controller_spec.rb +++ b/spec/requests/static_controller_spec.rb @@ -98,7 +98,7 @@ describe StaticController do it "should return the right response" do get "/faq" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(I18n.t('js.faq')) end end @@ -113,7 +113,7 @@ describe StaticController do it "renders the #{id} page" do get "/#{id}" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(text) end end @@ -150,7 +150,7 @@ describe StaticController do get "/login" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(PrettyText.cook(I18n.t( 'login_required.welcome_message', title: SiteSetting.title @@ -177,7 +177,7 @@ describe StaticController do get '/faq' - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(I18n.t('js.faq')) end @@ -186,7 +186,7 @@ describe StaticController do get '/guidelines' - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(I18n.t('guidelines')) end end diff --git a/spec/requests/tags_controller_spec.rb b/spec/requests/tags_controller_spec.rb index 107655ac6e..3b58b6e89a 100644 --- a/spec/requests/tags_controller_spec.rb +++ b/spec/requests/tags_controller_spec.rb @@ -16,7 +16,7 @@ describe TagsController do it "should return the right response" do get "/tags.json" - expect(response).to be_success + expect(response).to be_successful tags = JSON.parse(response.body)["tags"] expect(tags.length).to eq(1) @@ -41,7 +41,7 @@ describe TagsController do get "/tags.json" - expect(response).to be_success + expect(response).to be_successful tags = JSON.parse(response.body)["tags"] expect(tags.length).to eq(2) @@ -57,7 +57,7 @@ describe TagsController do it "should return the right response" do get "/tags/test" - expect(response).to be_success + expect(response).to be_successful end it "should handle invalid tags" do @@ -72,7 +72,7 @@ describe TagsController do it "should return the right response" do get "/tags/check.json", params: { tag_values: [tag.name] } - expect(response).to be_success + expect(response).to be_successful tag = JSON.parse(response.body)["valid"].first expect(tag["value"]).to eq('test') @@ -123,7 +123,7 @@ describe TagsController do it "can't see pm tags" do get "/tags/personal_messages/#{regular_user.username}.json" - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -135,13 +135,13 @@ describe TagsController do it "can't see pm tags for regular user" do get "/tags/personal_messages/#{regular_user.username}.json" - expect(response).not_to be_success + expect(response).not_to be_successful end it "can see their own pm tags" do get "/tags/personal_messages/#{moderator.username}.json" - expect(response).to be_success + expect(response).to be_successful tag = JSON.parse(response.body)['tags'] expect(tag[0]["id"]).to eq('test') @@ -156,7 +156,7 @@ describe TagsController do it "can see pm tags for regular user" do get "/tags/personal_messages/#{regular_user.username}.json" - expect(response).to be_success + expect(response).to be_successful tag = JSON.parse(response.body)['tags'] expect(tag[0]["id"]).to eq('test') @@ -165,7 +165,7 @@ describe TagsController do it "can see their own pm tags" do get "/tags/personal_messages/#{admin.username}.json" - expect(response).to be_success + expect(response).to be_successful tag = JSON.parse(response.body)['tags'] expect(tag[0]["id"]).to eq('test') @@ -195,7 +195,7 @@ describe TagsController do context 'tagging enabled' do it "can filter by tag" do get "/tags/#{tag.name}/l/latest.json" - expect(response).to be_success + expect(response).to be_successful end it "can filter by two tags" do @@ -205,7 +205,7 @@ describe TagsController do additional_tag_ids: other_tag.name } - expect(response).to be_success + expect(response).to be_successful topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -222,7 +222,7 @@ describe TagsController do additional_tag_ids: "#{other_tag.name}/#{third_tag.name}" } - expect(response).to be_success + expect(response).to be_successful topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -239,7 +239,7 @@ describe TagsController do additional_tag_ids: "notatag" } - expect(response).to be_success + expect(response).to be_successful topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -249,17 +249,17 @@ describe TagsController do it "can filter by category and tag" do get "/tags/c/#{category.slug}/#{tag.name}/l/latest.json" - expect(response).to be_success + expect(response).to be_successful end it "can filter by category, sub-category, and tag" do get "/tags/c/#{category.slug}/#{subcategory.slug}/#{tag.name}/l/latest.json" - expect(response).to be_success + expect(response).to be_successful end it "can filter by category, no sub-category, and tag" do get "/tags/c/#{category.slug}/none/#{tag.name}/l/latest.json" - expect(response).to be_success + expect(response).to be_successful end it "can handle subcategories with the same name" do @@ -272,7 +272,7 @@ describe TagsController do t = Fabricate(:topic, category_id: subcategory2.id, tags: [other_tag]) get "/tags/c/#{category2.slug}/#{subcategory2.slug}/#{other_tag.name}/l/latest.json" - expect(response).to be_success + expect(response).to be_successful topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -284,7 +284,7 @@ describe TagsController do sign_in(Fabricate(:user)) get "/tags/#{tag.name}/l/bookmarks.json" - expect(response).to be_success + expect(response).to be_successful end end end @@ -303,7 +303,7 @@ describe TagsController do tag_names = ['stuff', 'stinky', 'stumped'] tag_names.each { |name| Fabricate(:tag, name: name) } get "/tags/filter/search.json", params: { q: 'stu' } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }.sort).to eq(['stuff', 'stumped']) end @@ -312,7 +312,7 @@ describe TagsController do yup, nope = Fabricate(:tag, name: 'yup'), Fabricate(:tag, name: 'nope') category = Fabricate(:category, tags: [yup]) get "/tags/filter/search.json", params: { q: 'nope', categoryId: category.id } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }.sort).to eq([]) expect(json["forbidden"]).to be_present @@ -322,7 +322,7 @@ describe TagsController do c = Fabricate(:private_category, group: Fabricate(:group)) Fabricate(:topic, category: c, tags: [Fabricate(:tag, name: "cooltag")]) get "/tags/filter/search.json", params: { q: "cool" } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }).to eq(['cooltag']) end @@ -332,12 +332,12 @@ describe TagsController do tag_names.each { |name| Fabricate(:tag, name: name) } get "/tags/filter/search.json", params: { q: '房' } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }).to eq(['房地产']) get "/tags/filter/search.json", params: { q: 'тема' } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }).to eq(['тема-в-разработке']) end @@ -354,7 +354,7 @@ describe TagsController do it 'deletes the tag' do tag = Fabricate(:tag) delete "/tags/#{tag.name}.json" - expect(response).to be_success + expect(response).to be_successful expect(Tag.where(id: tag.id)).to be_empty end end @@ -362,7 +362,7 @@ describe TagsController do context 'with a nonexistent tag name' do it 'returns a tag not found message' do delete "/tags/doesntexists.json" - expect(response).not_to be_success + expect(response).not_to be_successful json = ::JSON.parse(response.body) expect(json['error_type']).to eq('not_found') end diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index 9c471ee1ee..f23881b74c 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}/wordpress.json", params: { best: 3 } - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) # The JSON has the data the wordpress plugin needs @@ -105,7 +105,7 @@ RSpec.describe TopicsController do } end.to change { Topic.count }.by(1) - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) @@ -127,7 +127,7 @@ RSpec.describe TopicsController do } end.to change { Topic.count }.by(1) - expect(response).to be_success + expect(response).to be_successful result = JSON.parse(response.body) @@ -143,7 +143,7 @@ RSpec.describe TopicsController do post "/t/#{topic.id}/move-posts.json", params: { post_ids: [p2.id] } - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) expect(result['success']).to eq(false) expect(result['url']).to be_blank @@ -193,7 +193,7 @@ RSpec.describe TopicsController do destination_topic_id: dest_topic.id } - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) expect(result['success']).to eq(true) expect(result['url']).to be_present @@ -207,7 +207,7 @@ RSpec.describe TopicsController do post_ids: [p2.id] } - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) expect(result['success']).to eq(false) expect(result['url']).to be_blank @@ -251,7 +251,7 @@ RSpec.describe TopicsController do destination_topic_id: dest_topic.id } - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) expect(result['success']).to eq(true) expect(result['url']).to be_present @@ -298,8 +298,8 @@ RSpec.describe TopicsController do let!(:editor) { sign_in(Fabricate(:admin)) } let(:topic) { Fabricate(:topic) } let(:user_a) { Fabricate(:user) } - let(:p1) { Fabricate(:post, topic_id: topic.id) } - let(:p2) { Fabricate(:post, topic_id: topic.id) } + let(:p1) { Fabricate(:post, topic: topic) } + let(:p2) { Fabricate(:post, topic: topic) } it "raises an error with a parameter missing" do [ @@ -317,7 +317,7 @@ RSpec.describe TopicsController do } topic.reload p1.reload - expect(response).to be_success + expect(response).to be_successful expect(topic.user.username).to eq(user_a.username) expect(p1.user.username).to eq(user_a.username) end @@ -327,7 +327,7 @@ RSpec.describe TopicsController do username: user_a.username_lower, post_ids: [p1.id, p2.id] } - expect(response).to be_success + expect(response).to be_successful p1.reload p2.reload @@ -339,7 +339,7 @@ RSpec.describe TopicsController do it "works with deleted users" do deleted_user = Fabricate(:user) t2 = Fabricate(:topic, user: deleted_user) - p3 = Fabricate(:post, topic_id: t2.id, user: deleted_user) + p3 = Fabricate(:post, topic: t2, user: deleted_user) UserDestroyer.new(editor).destroy(deleted_user, delete_posts: true, context: 'test', delete_as_spammer: true) @@ -347,7 +347,7 @@ RSpec.describe TopicsController do username: user_a.username_lower, post_ids: [p3.id] } - expect(response).to be_success + expect(response).to be_successful t2.reload p3.reload expect(t2.deleted_at).to be_nil @@ -380,20 +380,19 @@ RSpec.describe TopicsController do let(:old_timestamp) { Time.zone.now } let(:new_timestamp) { old_timestamp - 1.day } let!(:topic) { Fabricate(:topic, created_at: old_timestamp) } - let!(:p1) { Fabricate(:post, topic_id: topic.id, created_at: old_timestamp) } - let!(:p2) { Fabricate(:post, topic_id: topic.id, created_at: old_timestamp + 1.day) } - - it 'raises an error with a missing parameter' do - put "/t/1/change-timestamp.json" - expect(response.status).to eq(400) - end + let!(:p1) { Fabricate(:post, topic: topic, created_at: old_timestamp) } + let!(:p2) { Fabricate(:post, topic: topic, created_at: old_timestamp + 1.day) } it 'should update the timestamps of selected posts' do + # try to see if we fail with invalid first + put "/t/1/change-timestamp.json" + expect(response.status).to eq(400) + put "/t/#{topic.id}/change-timestamp.json", params: { timestamp: new_timestamp.to_f } - expect(response).to be_success + expect(response).to be_successful expect(topic.reload.created_at).to be_within_one_second_of(new_timestamp) expect(p1.reload.created_at).to be_within_one_second_of(new_timestamp) expect(p2.reload.created_at).to be_within_one_second_of(old_timestamp) @@ -425,7 +424,7 @@ RSpec.describe TopicsController do expect do put "/t/#{topic.id}/clear-pin.json" end.to change { TopicUser.where(topic_id: topic.id, user_id: user.id).count }.by(1) - expect(response).to be_success + expect(response).to be_successful end end end @@ -473,15 +472,14 @@ RSpec.describe TopicsController do end it 'should update the status of the topic correctly' do - topic = Fabricate(:topic, user: user, closed: true, topic_timers: [ - Fabricate(:topic_timer, status_type: TopicTimer.types[:open]) - ]) + topic = Fabricate(:topic, user: user, closed: true) + Fabricate(:topic_timer, topic: topic, status_type: TopicTimer.types[:open]) put "/t/#{topic.id}/status.json", params: { status: 'closed', enabled: 'false' } - expect(response).to be_success + expect(response).to be_successful expect(topic.reload.closed).to eq(false) expect(topic.topic_timers).to eq([]) @@ -562,7 +560,7 @@ RSpec.describe TopicsController do put "/t/#{topic.id}/recover.json" topic.reload post.reload - expect(response).to be_success + expect(response).to be_successful expect(topic.trashed?).to be_falsey expect(post.trashed?).to be_falsey end @@ -597,7 +595,7 @@ RSpec.describe TopicsController do it 'succeeds' do delete "/t/#{topic.id}.json" - expect(response).to be_success + expect(response).to be_successful topic.reload expect(topic.trashed?).to be_truthy end @@ -611,7 +609,7 @@ RSpec.describe TopicsController do it "returns JSON for the slug" do get "/t/id_for/#{topic.slug}.json" - expect(response).to be_success + expect(response).to be_successful json = ::JSON.parse(response.body) expect(json['topic_id']).to eq(topic.id) expect(json['url']).to eq(topic.url) @@ -787,9 +785,9 @@ RSpec.describe TopicsController do it 'correctly renders canoicals' do get "/t/#{topic.id}", params: { slug: topic.slug } - expect(response).to be_success + expect(response).to be_successful expect(css_select("link[rel=canonical]").length).to eq(1) - expect(response.headers["Cache-Control"]).to eq("no-store, must-revalidate, no-cache, private") + expect(response.headers["Cache-Control"]).to eq("no-cache, no-store") end it 'returns 301 even if slug does not match URL' do @@ -804,7 +802,7 @@ RSpec.describe TopicsController do Fabricate(:post, topic: topic) get "/t/#{topic.id}.json", params: { slug: topic.slug } - expect(response).to be_success + expect(response).to be_successful get "/t/#{topic.id}.json", params: { slug: "just-guessing" } expect(response.status).to eq(301) @@ -815,7 +813,7 @@ RSpec.describe TopicsController do it 'shows a topic correctly' do get "/t/#{topic.slug}/#{topic.id}.json" - expect(response).to be_success + expect(response).to be_successful end it 'return 404 for an invalid page' do @@ -1110,20 +1108,20 @@ RSpec.describe TopicsController do it 'grabs the correct set of posts' do get "/t/#{topic.slug}/#{topic.id}.json" - expect(response).to be_success + expect(response).to be_successful expect(extract_post_stream).to eq(@post_ids[0..1]) get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 1 } - expect(response).to be_success + expect(response).to be_successful expect(extract_post_stream).to eq(@post_ids[0..1]) get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 2 } - expect(response).to be_success + expect(response).to be_successful 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).to be_success + expect(response).to be_successful expect(extract_post_stream).to eq(@post_ids[-2..-1]) end end @@ -1228,7 +1226,7 @@ RSpec.describe TopicsController do expect { get "/t/#{topic.id}.json" }.not_to change(IncomingLink, :count) - expect(response).to be_success + expect(response).to be_successful end it "doesn't raise an error on a very long link" do @@ -1247,7 +1245,7 @@ RSpec.describe TopicsController do body = response.body - expect(response).to be_success + expect(response).to be_successful expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) end @@ -1274,7 +1272,7 @@ RSpec.describe TopicsController do body = response.body - expect(response).to be_success + expect(response).to be_successful expect(body).to have_tag(:body, with: { class: 'crawler' }) expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) end @@ -1290,7 +1288,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}.json" - expect(response).to be_success + expect(response).to be_successful expect(response.cookies['cn']).to eq(nil) notification.reload @@ -1303,7 +1301,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}.json", headers: { "Discourse-Clear-Notifications" => "2828,100,#{notification.id}" } - expect(response).to be_success + expect(response).to be_successful notification.reload expect(notification.read).to eq(true) end @@ -1325,7 +1323,7 @@ RSpec.describe TopicsController do it "uses the default locale" do get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_success + expect(response).to be_successful expect(I18n.locale).to eq(:en) end end @@ -1337,7 +1335,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_success + expect(response).to be_successful expect(I18n.locale).to eq(:en) end end @@ -1355,7 +1353,7 @@ RSpec.describe TopicsController do context "with an anonymous user" do it "uses the locale from the headers" do get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_success + expect(response).to be_successful expect(I18n.locale).to eq(:fr) end end @@ -1366,7 +1364,7 @@ RSpec.describe TopicsController do sign_in(user) get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_success + expect(response).to be_successful expect(I18n.locale).to eq(:fr) end end @@ -1379,7 +1377,7 @@ RSpec.describe TopicsController do SiteSetting.default_locale = "en" get "/t/#{topic.id}.json", headers: headers("zh-CN") - expect(response).to be_success + expect(response).to be_successful expect(I18n.locale).to eq(:zh_CN) end end @@ -1390,7 +1388,7 @@ RSpec.describe TopicsController do SiteSetting.default_locale = 'en' get "/t/#{topic.id}.json", headers: headers("") - expect(response).to be_success + expect(response).to be_successful expect(I18n.locale).to eq(:en) end end @@ -1400,14 +1398,14 @@ RSpec.describe TopicsController do describe "read only header" do it "returns no read only header by default" do get "/t/#{topic.id}.json" - expect(response).to be_success + expect(response).to be_successful expect(response.headers['Discourse-Readonly']).to eq(nil) end it "returns a readonly header if the site is read only" do Discourse.received_readonly! get "/t/#{topic.id}.json" - expect(response).to be_success + expect(response).to be_successful expect(response.headers['Discourse-Readonly']).to eq('true') end end @@ -1418,7 +1416,7 @@ RSpec.describe TopicsController do it 'returns first posts of the topic' do get "/t/#{topic.id}/posts.json" - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/json') end end @@ -1428,7 +1426,7 @@ RSpec.describe TopicsController do it 'renders rss of the topic' do get "/t/foo/#{topic.id}.rss" - expect(response).to be_success + expect(response).to be_successful expect(response.content_type).to eq('application/rss+xml') end end @@ -1475,7 +1473,7 @@ RSpec.describe TopicsController do topic = Fabricate(:topic, user: sign_in(Fabricate(:admin))) put "/t/#{topic.id}/make-banner.json" - expect(response).to be_success + expect(response).to be_successful topic.reload expect(topic.archetype).to eq(Archetype.banner) end @@ -1494,7 +1492,7 @@ RSpec.describe TopicsController do topic = Fabricate(:topic, user: sign_in(Fabricate(:admin)), archetype: Archetype.banner) put "/t/#{topic.id}/remove-banner.json" - expect(response).to be_success + expect(response).to be_successful topic.reload expect(topic.archetype).to eq(Archetype.default) end @@ -1603,7 +1601,7 @@ RSpec.describe TopicsController do user.user_stat.update_column(:new_since, old_date) put "/topics/reset-new.json" - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.user_stat.new_since.to_date).not_to eq(old_date.to_date) end @@ -1613,7 +1611,7 @@ RSpec.describe TopicsController do it "works" do get "/topics/feature_stats.json", params: { category_id: 1 } - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["pinned_in_category_count"]).to eq(0) expect(json["pinned_globally_count"]).to eq(0) @@ -1673,12 +1671,12 @@ RSpec.describe TopicsController do context "success" do it "returns success" do - admin = sign_in(Fabricate(:admin)) + sign_in(Fabricate(:admin)) put "/t/#{topic.id}/convert-topic/private.json" topic.reload expect(topic.archetype).to eq(Archetype.private_message) - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) expect(result['success']).to eq(true) @@ -1699,12 +1697,12 @@ RSpec.describe TopicsController do context "success" do it "returns success" do - admin = sign_in(Fabricate(:admin)) + sign_in(Fabricate(:admin)) put "/t/#{topic.id}/convert-topic/public.json" topic.reload expect(topic.archetype).to eq(Archetype.default) - expect(response).to be_success + expect(response).to be_successful result = ::JSON.parse(response.body) expect(result['success']).to eq(true) @@ -1726,7 +1724,7 @@ RSpec.describe TopicsController do timings: { post_1.post_number => 2 } } - expect(response).to be_success + expect(response).to be_successful post_timing = PostTiming.first @@ -1774,7 +1772,7 @@ RSpec.describe TopicsController do status_type: TopicTimer.types[1] } - expect(response).to be_success + expect(response).to be_successful topic_status_update = TopicTimer.last @@ -1800,7 +1798,7 @@ RSpec.describe TopicsController do status_type: TopicTimer.types[1] } - expect(response).to be_success + expect(response).to be_successful expect(topic.reload.public_topic_timer).to eq(nil) json = JSON.parse(response.body) @@ -1818,7 +1816,7 @@ RSpec.describe TopicsController do category_id: topic.category_id } - expect(response).to be_success + expect(response).to be_successful topic_status_update = TopicTimer.last @@ -2038,7 +2036,7 @@ RSpec.describe TopicsController do let!(:shared_draft) { Fabricate(:shared_draft, topic: topic, category: category) } it "allows staff to update the category id" do put "/t/#{topic.id}/shared-draft.json", params: { category_id: other_cat.id } - expect(response).to be_success + expect(response).to be_successful topic.reload expect(topic.shared_draft.category_id).to eq(other_cat.id) end @@ -2047,7 +2045,7 @@ RSpec.describe TopicsController do context "without a shared draft" do it "allows staff to update the category id" do put "/t/#{topic.id}/shared-draft.json", params: { category_id: other_cat.id } - expect(response).to be_success + expect(response).to be_successful topic.reload expect(topic.shared_draft.category_id).to eq(other_cat.id) end @@ -2113,15 +2111,15 @@ RSpec.describe TopicsController do freeze_time page1_time topic = Fabricate(:topic) - Fabricate(:post, topic_id: topic.id) - Fabricate(:post, topic_id: topic.id) + Fabricate(:post, topic: topic) + Fabricate(:post, topic: topic) freeze_time page2_time - Fabricate(:post, topic_id: topic.id) - Fabricate(:post, topic_id: topic.id) + Fabricate(:post, topic: topic) + Fabricate(:post, topic: topic) freeze_time page3_time - Fabricate(:post, topic_id: topic.id) + Fabricate(:post, topic: topic) # ugly, but no inteface to set this and we don't want to create # 100 posts to test this thing diff --git a/spec/requests/uploads_controller_spec.rb b/spec/requests/uploads_controller_spec.rb index 31130e15c0..9fa184f0e5 100644 --- a/spec/requests/uploads_controller_spec.rb +++ b/spec/requests/uploads_controller_spec.rb @@ -122,7 +122,7 @@ describe UploadsController do for_private_message: "true", } - expect(response).to be_success + expect(response).to be_successful id = JSON.parse(response.body)["id"] expect(id).to be_present end @@ -137,7 +137,7 @@ describe UploadsController do type: "composer", } - expect(response).to be_success + expect(response).to be_successful data = JSON.parse(response.body) expect(data["id"]).to be_present end diff --git a/spec/requests/user_badges_controller_spec.rb b/spec/requests/user_badges_controller_spec.rb index 20fd5d3b63..84b1b2ebbb 100644 --- a/spec/requests/user_badges_controller_spec.rb +++ b/spec/requests/user_badges_controller_spec.rb @@ -11,7 +11,7 @@ describe UserBadgesController do UserBadge.create!(badge: badge, user: user, post_id: p.id, granted_by_id: -1, granted_at: Time.now) get "/user_badges.json", params: { badge_id: badge.id } - expect(response).to be_success + expect(response).to be_successful parsed = JSON.parse(response.body) expect(parsed["topics"]).to eq(nil) diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 5b7e588c52..1714816a00 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -64,7 +64,7 @@ describe UsersController do :user_logged_in, :user_first_logged_in ) - expect(response).to be_success + expect(response).to be_successful expect(flash[:error]).to be_blank expect(session[:current_user_id]).to be_present @@ -81,7 +81,7 @@ describe UsersController do end it 'should return the right response' do - expect(response).to be_success + expect(response).to be_successful expect(CGI.unescapeHTML(response.body)) .to include(I18n.t('activation.approval_required')) @@ -116,7 +116,7 @@ describe UsersController do it "returns success" do SiteSetting.login_required = true get "/u/password-reset/#{token}" - expect(response).to be_success + expect(response).to be_successful expect(CGI.unescapeHTML(response.body)).to include(I18n.t('password_reset.no_token')) end end @@ -127,7 +127,7 @@ describe UsersController do end it 'disallows login' do - expect(response).to be_success + expect(response).to be_successful expect(CGI.unescapeHTML(response.body)) .to include(I18n.t('password_reset.no_token')) @@ -144,7 +144,7 @@ describe UsersController do it 'disallows login' do get "/u/password-reset/ev!l_trout@!" - expect(response).to be_success + expect(response).to be_successful expect(CGI.unescapeHTML(response.body)) .to include(I18n.t('password_reset.no_token')) @@ -159,7 +159,7 @@ describe UsersController do it "responds with proper error message" do put "/u/password-reset/evil_trout!.json", params: { password: "awesomeSecretPassword" } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)["message"]).to eq(I18n.t('password_reset.no_token')) expect(session[:current_user_id]).to be_blank end @@ -189,7 +189,7 @@ describe UsersController do :user_logged_in, :user_first_logged_in ) - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include('{"is_developer":false,"admin":false,"second_factor_required":false}') expect(session["password-#{token}"]).to be_blank @@ -294,7 +294,7 @@ describe UsersController do it "fails when the password is blank" do put "/u/password-reset/#{token}.json", params: { password: '' } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)["errors"]).to be_present expect(session[:current_user_id]).to be_blank end @@ -302,7 +302,7 @@ describe UsersController do it "fails when the password is too long" do put "/u/password-reset/#{token}.json", params: { password: ('x' * (User.max_password_length + 1)) } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)["errors"]).to be_present expect(session[:current_user_id]).to be_blank end @@ -310,7 +310,7 @@ describe UsersController do it "logs in the user" do put "/u/password-reset/#{token}.json", params: { password: 'ksjafh928r' } - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)["errors"]).to be_blank expect(session[:current_user_id]).to be_present end @@ -331,14 +331,14 @@ describe UsersController do it "token doesn't match any records" do email_token = user.email_tokens.create(email: user.email) get "/u/confirm-email-token/#{SecureRandom.hex}.json" - expect(response).to be_success + expect(response).to be_successful expect(email_token.reload.confirmed).to eq(false) end it "token matches" do email_token = user.email_tokens.create(email: user.email) get "/u/confirm-email-token/#{email_token.token}.json" - expect(response).to be_success + expect(response).to be_successful expect(email_token.reload.confirmed).to eq(true) end end @@ -442,11 +442,11 @@ describe UsersController do user.save! post "/u/toggle-anon.json" - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(AnonymousShadowCreator.get(user).id) post "/u/toggle-anon.json" - expect(response).to be_success + expect(response).to be_successful expect(session[:current_user_id]).to eq(user.id) end end @@ -934,7 +934,7 @@ describe UsersController do it "should succeed without the optional field" do post "/u.json", params: create_params - expect(response).to be_success + expect(response).to be_successful inserted = User.find_by_email(@user.email) expect(inserted).to be_present expect(inserted.custom_fields).to be_present @@ -946,7 +946,7 @@ describe UsersController do it "should succeed with the optional field" do create_params[:user_fields][optional_field.id.to_s] = 'value3' post "/u.json", params: create_params.merge(create_params) - expect(response).to be_success + expect(response).to be_successful inserted = User.find_by_email(@user.email) expect(inserted).to be_present expect(inserted.custom_fields).to be_present @@ -958,7 +958,7 @@ describe UsersController do it "trims excessively long fields" do create_params[:user_fields][optional_field.id.to_s] = ('x' * 3000) post "/u.json", params: create_params.merge(create_params) - expect(response).to be_success + expect(response).to be_successful inserted = User.find_by_email(@user.email) val = inserted.custom_fields["user_field_#{optional_field.id}"] @@ -980,7 +980,7 @@ describe UsersController do it "should succeed" do post "/u.json", params: create_params - expect(response).to be_success + expect(response).to be_successful inserted = User.find_by_email(@user.email) expect(inserted).to be_present expect(inserted.custom_fields).not_to be_present @@ -1073,7 +1073,7 @@ describe UsersController do it 'should succeed in normal circumstances' do put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username } - expect(response).to be_success + expect(response).to be_successful expect(user.reload.username).to eq(new_username) end @@ -1097,7 +1097,7 @@ describe UsersController do put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username } - expect(response).to be_success + expect(response).to be_successful expect(UserHistory.where(action: UserHistory.actions[:change_username], target_user_id: user.id, acting_user_id: acting_user.id)).to be_present expect(user.reload.username).to eq(new_username) end @@ -1221,7 +1221,7 @@ describe UsersController do user = Fabricate(:user) get "/u/#{user.username}/invited.json", params: { username: user.username } - expect(response).to be_success + expect(response).to be_successful end it 'filters by email' do @@ -1366,14 +1366,14 @@ describe UsersController do it "should be able to update a user" do put "/u/#{user.username}.json", params: { name: 'test.test' } - expect(response).to be_success + expect(response).to be_successful expect(user.reload.name).to eq('test.test') end it "should be able to update a user" do put "/u/#{user.username}.json", params: { name: 'testing123' } - expect(response).to be_success + expect(response).to be_successful expect(user.reload.name).to eq('testing123') end end @@ -1391,7 +1391,7 @@ describe UsersController do user_fields: { user_field.id.to_s => 'happy' } } - expect(response).to be_success + expect(response).to be_successful user.reload @@ -1417,7 +1417,7 @@ describe UsersController do watched_tags: "#{tags[0].name},#{tags[1].name}" } - expect(response).to be_success + expect(response).to be_successful user.reload @@ -1460,7 +1460,7 @@ describe UsersController do it "should update the user field" do put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' } } - expect(response).to be_success + expect(response).to be_successful expect(user.user_fields[user_field.id.to_s]).to eq 'happy' end @@ -1480,13 +1480,13 @@ describe UsersController do it "should retain existing user fields" do put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy', optional_field.id.to_s => 'feet' } } - expect(response).to be_success + expect(response).to be_successful expect(user.user_fields[user_field.id.to_s]).to eq('happy') expect(user.user_fields[optional_field.id.to_s]).to eq('feet') put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'sad' } } - expect(response).to be_success + expect(response).to be_successful user.reload @@ -1501,7 +1501,7 @@ describe UsersController do it "does not update the user field" do put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' } } - expect(response).to be_success + expect(response).to be_successful expect(user.user_fields[user_field.id.to_s]).to be_blank end end @@ -1748,7 +1748,7 @@ describe UsersController do it 'can successfully pick the system avatar' do put "/u/#{user.username}/preferences/avatar/pick.json" - expect(response).to be_success + expect(response).to be_successful expect(user.reload.uploaded_avatar_id).to eq(nil) end @@ -1757,7 +1757,7 @@ describe UsersController do upload_id: upload.id, type: "gravatar" } - expect(response).to be_success + expect(response).to be_successful expect(user.reload.uploaded_avatar_id).to eq(upload.id) expect(user.user_avatar.reload.gravatar_upload_id).to eq(upload.id) end @@ -1767,7 +1767,7 @@ describe UsersController do upload_id: upload.id, type: "custom" } - expect(response).to be_success + expect(response).to be_successful expect(user.reload.uploaded_avatar_id).to eq(upload.id) expect(user.user_avatar.reload.custom_upload_id).to eq(upload.id) end @@ -1807,7 +1807,7 @@ describe UsersController do delete "/u/#{user.username}/preferences/user_image.json", params: { type: 'profile_background' } expect(user.reload.user_profile.profile_background).to eq("") - expect(response).to be_success + expect(response).to be_successful end end end @@ -1843,7 +1843,7 @@ describe UsersController do it "deletes your account when you're allowed to" do UserDestroyer.any_instance.expects(:destroy).with(user, anything).returns(user) delete "/u/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful end end end @@ -1894,7 +1894,7 @@ describe UsersController do get "/u/#{Fabricate(:user).username}/emails.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["email"]).to be_present expect(json["associated_accounts"]).to be_present @@ -1906,7 +1906,7 @@ describe UsersController do get "/u/#{inactive_user.username}/emails.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["email"]).to be_present expect(json["associated_accounts"]).to be_present @@ -2034,7 +2034,7 @@ describe UsersController do create_post(user: user) get "/u/#{user.username_lower}/summary.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["user_summary"]["topic_count"]).to eq(1) @@ -2045,12 +2045,12 @@ describe UsersController do describe '#confirm_admin' do it "fails without a valid token" do get "/u/confirm-admin/invalid-token.josn" - expect(response).not_to be_success + expect(response).not_to be_successful end it "fails with a missing token" do get "/u/confirm-admin/a0a0a0a0a0.josn" - expect(response).to_not be_success + expect(response).to_not be_successful end it "succeeds with a valid code as anonymous" do @@ -2058,7 +2058,7 @@ describe UsersController do ac = AdminConfirmation.new(user, Fabricate(:admin)) ac.create_confirmation get "/u/confirm-admin/#{ac.token}.josn" - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.admin?).to eq(false) @@ -2071,7 +2071,7 @@ describe UsersController do ac = AdminConfirmation.new(user, admin) ac.create_confirmation get "/u/confirm-admin/#{ac.token}.josn", params: { token: ac.token } - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.admin?).to eq(false) @@ -2084,7 +2084,7 @@ describe UsersController do ac = AdminConfirmation.new(user, Fabricate(:admin)) ac.create_confirmation get "/u/confirm-admin/#{ac.token}.josn" - expect(response).to_not be_success + expect(response).to_not be_successful user.reload expect(user.admin?).to eq(false) @@ -2096,7 +2096,7 @@ describe UsersController do ac = AdminConfirmation.new(user, Fabricate(:admin)) ac.create_confirmation post "/u/confirm-admin/#{ac.token}.josn" - expect(response).to be_success + expect(response).to be_successful user.reload expect(user.admin?).to eq(true) @@ -2285,7 +2285,7 @@ describe UsersController do it "returns success" do get "/u/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)["user"]["username"]).to eq(user.username) end @@ -2320,7 +2320,7 @@ describe UsersController do it 'returns success' do get "/u/#{user.username}.json" - expect(response).to be_success + expect(response).to be_successful json = JSON.parse(response.body) expect(json["user"]["has_title_badges"]).to eq(false) @@ -2328,20 +2328,20 @@ describe UsersController do it "returns not found when the username doesn't exist" do get "/u/madeuppity.json" - expect(response).not_to be_success + expect(response).not_to be_successful end it 'returns not found when the user is inactive' do inactive = Fabricate(:user, active: false) get "/u/#{inactive.username}.json" - expect(response).not_to be_success + expect(response).not_to be_successful end it 'returns success when show_inactive_accounts is true and user is logged in' do SiteSetting.show_inactive_accounts = true inactive = Fabricate(:user, active: false) get "/u/#{inactive.username}.json" - expect(response).to be_success + expect(response).to be_successful end it "raises an error on invalid access" do @@ -2374,13 +2374,13 @@ describe UsersController do it "returns fetch for a matching external_id" do get "/u/by-external/997.json" - expect(response).to be_success + expect(response).to be_successful expect(JSON.parse(response.body)["user"]["username"]).to eq(user.username) end it "returns not found when external_id doesn't match" do get "/u/by-external/99.json" - expect(response).not_to be_success + expect(response).not_to be_successful end end @@ -2414,7 +2414,7 @@ describe UsersController do it "should be able to view a user" do get "/u/#{user.username}" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(user.username) end @@ -2426,7 +2426,7 @@ describe UsersController do it "should be able to view a user" do get "/u/#{user.username}" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include(user.username) end end @@ -2435,7 +2435,7 @@ describe UsersController do describe '#badges' do it "renders fine by default" do get "/u/#{user.username}/badges" - expect(response).to be_success + expect(response).to be_successful end it "fails if badges are disabled" do @@ -2449,7 +2449,7 @@ describe UsersController do it "returns a message when no session is present" do get "/u/account-created" - expect(response).to be_success + expect(response).to be_successful body = response.body @@ -2470,7 +2470,7 @@ describe UsersController do user = create_user get "/u/account-created" - expect(response).to be_success + expect(response).to be_successful expect(response.body).to include( "{\"message\":\"#{I18n.t("login.activate_email", email: user.email).gsub!(" Date: Thu, 7 Jun 2018 07:24:05 +0300 Subject: [PATCH 0069/1439] REFACTOR: offline controller spec to requests (#5943) --- spec/{controllers => requests}/offline_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename spec/{controllers => requests}/offline_controller_spec.rb (84%) diff --git a/spec/controllers/offline_controller_spec.rb b/spec/requests/offline_controller_spec.rb similarity index 84% rename from spec/controllers/offline_controller_spec.rb rename to spec/requests/offline_controller_spec.rb index b583747b7d..3bbea35374 100644 --- a/spec/controllers/offline_controller_spec.rb +++ b/spec/requests/offline_controller_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe OfflineController do it "can hit index" do - get :index + get "/offline.html" expect(response.status).to eq(200) end end From 600ff85ecdb4aa13bcce59aa5d2ffb328f451fc5 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 07:24:20 +0300 Subject: [PATCH 0070/1439] REFACTOR: draft controller specs to requests (#5942) --- .../draft_controller_spec.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename spec/{controllers => requests}/draft_controller_spec.rb (53%) diff --git a/spec/controllers/draft_controller_spec.rb b/spec/requests/draft_controller_spec.rb similarity index 53% rename from spec/controllers/draft_controller_spec.rb rename to spec/requests/draft_controller_spec.rb index d7e63615f2..55f471a44d 100644 --- a/spec/controllers/draft_controller_spec.rb +++ b/spec/requests/draft_controller_spec.rb @@ -1,23 +1,23 @@ require 'rails_helper' describe DraftController do - it 'requires you to be logged in' do - post :update + post "/draft" expect(response.status).to eq(403) end it 'saves a draft on update' do - user = log_in - post :update, params: { draft_key: 'xyz', data: 'my data', sequence: 0 }, format: :json + user = sign_in(Fabricate(:user)) + post "/draft.json", params: { draft_key: 'xyz', data: 'my data', sequence: 0 } + expect(response.status).to eq(200) expect(Draft.get(user, 'xyz', 0)).to eq('my data') end it 'destroys drafts when required' do - user = log_in + user = sign_in(Fabricate(:user)) Draft.set(user, 'xxx', 0, 'hi') - delete :destroy, params: { draft_key: 'xxx', sequence: 0 }, format: :json + delete "/draft.json", params: { draft_key: 'xxx', sequence: 0 } + expect(response.status).to eq(200) expect(Draft.get(user, 'xxx', 0)).to eq(nil) end - end From d2880246cdad46ba97629db7582992ac9d798559 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 12:49:43 +0300 Subject: [PATCH 0071/1439] REFACTOR: steps controller specs to requests --- .../steps_controller_spec.rb | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) rename spec/{controllers => requests}/steps_controller_spec.rb (51%) diff --git a/spec/controllers/steps_controller_spec.rb b/spec/requests/steps_controller_spec.rb similarity index 51% rename from spec/controllers/steps_controller_spec.rb rename to spec/requests/steps_controller_spec.rb index 2c0603ca4c..44a6c9bdff 100644 --- a/spec/controllers/steps_controller_spec.rb +++ b/spec/requests/steps_controller_spec.rb @@ -1,57 +1,55 @@ require 'rails_helper' describe StepsController do - before do SiteSetting.wizard_enabled = true end it 'needs you to be logged in' do - put :update, params: { - id: 'made-up-id', fields: { forum_title: "updated title" } - }, format: :json + put "/wizard/steps/made-up-id.json", params: { + fields: { forum_title: "updated title" } + } expect(response.status).to eq(403) end it "raises an error if you aren't an admin" do - log_in(:moderator) + sign_in(Fabricate(:moderator)) - put :update, params: { - id: 'made-up-id', fields: { forum_title: "updated title" } - }, format: :json + put "/wizard/steps/made-up-id.json", params: { + fields: { forum_title: "updated title" } + } expect(response).to be_forbidden end context "as an admin" do before do - log_in(:admin) + sign_in(Fabricate(:admin)) end it "raises an error if the wizard is disabled" do SiteSetting.wizard_enabled = false - put :update, params: { - id: 'contact', fields: { contact_email: "eviltrout@example.com" } - }, format: :json + put "/wizard/steps/contact.json", params: { + fields: { contact_email: "eviltrout@example.com" } + } expect(response).to be_forbidden end it "updates properly if you are staff" do - put :update, params: { - id: 'contact', fields: { contact_email: "eviltrout@example.com" } - }, format: :json + put "/wizard/steps/contact.json", params: { + fields: { contact_email: "eviltrout@example.com" } + } expect(response).to be_successful expect(SiteSetting.contact_email).to eq("eviltrout@example.com") end it "returns errors if the field has them" do - put :update, params: { - id: 'contact', fields: { contact_email: "not-an-email" } - }, format: :json + put "/wizard/steps/contact.json", params: { + fields: { contact_email: "not-an-email" } + } - expect(response).to_not be_successful + expect(response.status).to eq(422) end end - end From f331d2603d2f7690c48b974d3aa3df1f398d7571 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 1 Jun 2018 12:22:47 +1000 Subject: [PATCH 0072/1439] DEV: improve design of site setting default provider This refactors it so "Defaults provider" is only responsible for "defaults" Locale handling and management of locale settings is moved back into SiteSettingExtension This eliminates complex state management using DistributedCache and makes it way easier to test SiteSettingExtension --- lib/site_setting_extension.rb | 90 ++++++++-- lib/site_settings/defaults_provider.rb | 100 +++-------- .../components/site_setting_extension_spec.rb | 9 + .../site_settings/defaults_provider_spec.rb | 165 +----------------- .../admin/site_settings_controller_spec.rb | 16 +- spec/multisite/jobs_spec.rb | 1 - spec/rails_helper.rb | 1 - 7 files changed, 122 insertions(+), 260 deletions(-) diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index 8efee07032..4e525ff72a 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_dependency 'site_settings/deprecated_settings' require_dependency 'site_settings/type_supervisor' require_dependency 'site_settings/defaults_provider' @@ -5,12 +7,54 @@ require_dependency 'site_settings/db_provider' module SiteSettingExtension include SiteSettings::DeprecatedSettings - extend Forwardable - def_delegator :defaults, :site_locale, :default_locale - def_delegator :defaults, :site_locale=, :default_locale= - def_delegator :defaults, :has_setting? - def_delegators 'SiteSettings::TypeSupervisor', :types, :supported_types + # support default_locale being set via global settings + # this also adds support for testing the extension and global settings + # for site locale + def self.extended(klass) + if GlobalSetting.respond_to?(:default_locale) && GlobalSetting.default_locale.present? + klass.send :setup_shadowed_methods, :default_locale, GlobalSetting.default_locale + end + end + + # we need a default here to support defaults per locale + def default_locale=(val) + val = val.to_s + raise Discourse::InvalidParameters.new(:value) unless LocaleSiteSetting.valid_value?(val) + if val != self.default_locale + add_override!(:default_locale, val) + refresh! + Discourse.request_refresh! + end + end + + def default_locale? + true + end + + # set up some sort of default so we can look stuff up + def default_locale + # note optimised cause this is called a lot so avoiding .presence which + # adds 2 method calls + locale = current[:default_locale] + if locale && !locale.blank? + locale + else + SiteSettings::DefaultsProvider::DEFAULT_LOCALE + end + end + + def has_setting?(v) + defaults.has_setting?(v) + end + + def supported_types + SiteSettings::TypeSupervisor.supported_types + end + + def types + SiteSettings::TypeSupervisor.types + end def listen_for_changes=(val) @listen_for_changes = val @@ -55,11 +99,11 @@ module SiteSettingExtension end def refresh_settings - @refresh_settings ||= [] + @refresh_settings ||= [:default_locale] end def client_settings - @client_settings ||= [] + @client_settings ||= [:default_locale] end def previews @@ -73,13 +117,17 @@ module SiteSettingExtension def setting(name_arg, default = nil, opts = {}) name = name_arg.to_sym + if name == :default_locale + raise ArgumentError.new("Other settings depend on default locale, you can not configure it like this") + end + shadowed_val = nil mutex.synchronize do defaults.load_setting( name, default, - opts.extract!(*SiteSettings::DefaultsProvider::CONSUMED_OPTS) + opts.delete(:locale_default) ) categories[name] = opts[:category] || :uncategorized @@ -129,7 +177,7 @@ module SiteSettingExtension def settings_hash result = {} - defaults.each_key do |s| + defaults.all.keys.each do |s| result[s] = send(s).to_s end result @@ -147,14 +195,28 @@ module SiteSettingExtension # Retrieve all settings def all_settings(include_hidden = false) - defaults + + locale_setting_hash = + { + setting: 'default_locale', + default: SiteSettings::DefaultsProvider::DEFAULT_LOCALE, + category: 'required', + description: description('default_locale'), + type: SiteSetting.types[SiteSetting.types[:enum]], + preview: nil, + value: self.default_locale, + valid_values: LocaleSiteSetting.values, + translate_names: LocaleSiteSetting.translate_names? + } + + defaults.all(default_locale) .reject { |s, _| !include_hidden && hidden_settings.include?(s) } .map do |s, v| value = send(s) opts = { setting: s, description: description(s), - default: defaults[s].to_s, + default: defaults.get(s, default_locale).to_s, value: value.to_s, category: categories[s], preview: previews[s], @@ -162,7 +224,7 @@ module SiteSettingExtension }.merge(type_supervisor.type_hash(s)) opts - end.unshift(defaults.locale_setting_hash) + end.unshift(locale_setting_hash) end def description(setting) @@ -185,7 +247,7 @@ module SiteSettingExtension [s.name.to_sym, type_supervisor.to_rb_value(s.name, s.value, s.data_type)] }.to_a.flatten)] - defaults_view = defaults.all + defaults_view = defaults.all(new_hash[:default_locale]) # add locale default and defaults based on default_locale, cause they are cached new_hash = defaults_view.merge!(new_hash) @@ -242,7 +304,7 @@ module SiteSettingExtension def remove_override!(name) provider.destroy(name) - current[name] = defaults[name] + current[name] = defaults.get(name, default_locale) clear_cache! end diff --git a/lib/site_settings/defaults_provider.rb b/lib/site_settings/defaults_provider.rb index 7b1467a653..6340ff91b9 100644 --- a/lib/site_settings/defaults_provider.rb +++ b/lib/site_settings/defaults_provider.rb @@ -1,31 +1,23 @@ +# frozen_string_literal: true + module SiteSettings; end # A cache for providing default value based on site locale class SiteSettings::DefaultsProvider - include Enumerable - - CONSUMED_OPTS = %i[default locale_default].freeze - DEFAULT_LOCALE_KEY = :default_locale - DEFAULT_LOCALE = 'en'.freeze - DEFAULT_CATEGORY = 'required'.freeze - - @@site_locales ||= DistributedCache.new('site_locales') + DEFAULT_LOCALE = 'en' def initialize(site_setting) @site_setting = site_setting - @site_setting.refresh_settings << DEFAULT_LOCALE_KEY @defaults = {} @defaults[DEFAULT_LOCALE.to_sym] = {} - - refresh_site_locale! end - def load_setting(name_arg, value, opts = {}) + def load_setting(name_arg, value, locale_defaults) name = name_arg.to_sym @defaults[DEFAULT_LOCALE.to_sym][name] = value - if (locale_default = opts[:locale_default]) - locale_default.each do |locale, v| + if (locale_defaults) + locale_defaults.each do |locale, v| locale = locale.to_sym @defaults[locale] ||= {} @defaults[locale][name] = v @@ -34,15 +26,19 @@ class SiteSettings::DefaultsProvider end def db_all - @site_setting.provider.all.delete_if { |s| s.name.to_sym == DEFAULT_LOCALE_KEY } + @site_setting.provider.all end - def all - @defaults[DEFAULT_LOCALE.to_sym].merge(@defaults[self.site_locale.to_sym] || {}) + def all(locale = nil) + if locale + @defaults[DEFAULT_LOCALE.to_sym].merge(@defaults[locale.to_sym] || {}) + else + @defaults[DEFAULT_LOCALE.to_sym].dup + end end - def get(name) - @defaults.dig(self.site_locale.to_sym, name.to_sym) || + def get(name, locale = DEFAULT_LOCALE) + @defaults.dig(locale.to_sym, name.to_sym) || @defaults.dig(DEFAULT_LOCALE.to_sym, name.to_sym) end alias [] get @@ -50,81 +46,25 @@ class SiteSettings::DefaultsProvider # Used to override site settings in dev/test env def set_regardless_of_locale(name, value) name = name.to_sym - if @site_setting.has_setting?(name) + if name == :default_locale || @site_setting.has_setting?(name) @defaults.each { |_, hash| hash.delete(name) } @defaults[DEFAULT_LOCALE.to_sym][name] = value value, type = @site_setting.type_supervisor.to_db_value(name, value) - @defaults[self.site_locale.to_sym] ||= {} - @defaults[self.site_locale.to_sym][name] = @site_setting.type_supervisor.to_rb_value(name, value, type) + @defaults[SiteSetting.default_locale.to_sym] ||= {} + @defaults[SiteSetting.default_locale.to_sym][name] = @site_setting.type_supervisor.to_rb_value(name, value, type) else raise ArgumentError.new("No setting named '#{name}' exists") end end - def site_locale - @@site_locales[current_db] - end - - def site_locale=(val) - val = val.to_s - raise Discourse::InvalidParameters.new(:value) unless LocaleSiteSetting.valid_value?(val) - - if val != @@site_locales[current_db] - @site_setting.provider.save(DEFAULT_LOCALE_KEY, val, SiteSetting.types[:string]) - refresh_site_locale! - @site_setting.refresh! - Discourse.request_refresh! - end - - @@site_locales[current_db] - end - - def each(&block) - self.all.each do |key, value| - block.call(key.to_sym, value) - end - end - - def locale_setting_hash - { - setting: DEFAULT_LOCALE_KEY, - default: DEFAULT_LOCALE, - category: DEFAULT_CATEGORY, - description: @site_setting.description(DEFAULT_LOCALE_KEY), - type: SiteSetting.types[SiteSetting.types[:enum]], - preview: nil, - value: @@site_locales[current_db], - valid_values: LocaleSiteSetting.values, - translate_names: LocaleSiteSetting.translate_names? - } - end - - def refresh_site_locale! - RailsMultisite::ConnectionManagement.each_connection do |db| - @@site_locales[db] = - if GlobalSetting.respond_to?(DEFAULT_LOCALE_KEY) && - (global_val = GlobalSetting.send(DEFAULT_LOCALE_KEY)) && - !global_val.blank? - global_val - elsif (db_val = @site_setting.provider.find(DEFAULT_LOCALE_KEY)) - db_val.value.to_s - else - DEFAULT_LOCALE - end - - @@site_locales[db] - end - end - def has_setting?(name) - has_key?(name.to_sym) || has_key?("#{name.to_s}?".to_sym) + has_key?(name.to_sym) || has_key?("#{name.to_s}?".to_sym) || name.to_sym == :default_locale end private def has_key?(name) - @defaults[self.site_locale.to_sym]&.key?(name) || - @defaults[DEFAULT_LOCALE.to_sym].key?(name) || name == DEFAULT_LOCALE_KEY + @defaults[DEFAULT_LOCALE.to_sym].key?(name) end def current_db diff --git a/spec/components/site_setting_extension_spec.rb b/spec/components/site_setting_extension_spec.rb index 1c8491c009..f246a5588b 100644 --- a/spec/components/site_setting_extension_spec.rb +++ b/spec/components/site_setting_extension_spec.rb @@ -505,6 +505,15 @@ describe SiteSettingExtension do end describe "shadowed_by_global" do + + context "default_locale" do + it "supports adding a default locale via a global" do + global_setting :default_locale, 'zh_CN' + settings.default_locale = 'en' + expect(settings.default_locale).to eq('zh_CN') + end + end + context "without global setting" do before do settings.setting(:trout_api_key, 'evil', shadowed_by_global: true) diff --git a/spec/components/site_settings/defaults_provider_spec.rb b/spec/components/site_settings/defaults_provider_spec.rb index e19b369f2b..e4ca9a9109 100644 --- a/spec/components/site_settings/defaults_provider_spec.rb +++ b/spec/components/site_settings/defaults_provider_spec.rb @@ -26,20 +26,7 @@ describe SiteSettings::DefaultsProvider do new_settings(provider_local) end - describe 'inserts default_locale into refresh' do - it 'when initialize' do - expect(settings.refresh_settings.include?(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY)).to be_truthy - end - end - describe '.db_all' do - it 'collects values from db except default locale' do - settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY, - 'en', - SiteSetting.types[:string]) - expect(settings.defaults.db_all).to eq([]) - end - it 'can collect values from db' do settings.provider.save('try_a', 1, SiteSetting.types[:integer]) settings.provider.save('try_b', 2, SiteSetting.types[:integer]) @@ -55,11 +42,9 @@ describe SiteSettings::DefaultsProvider do end describe '.all' do - it 'returns all values according to the current locale' do + it 'returns all values according to locale' do expect(settings.defaults.all).to eq(test_override: 'default', test_default: 'test') - settings.defaults.site_locale = 'zh_CN' - settings.defaults.refresh_site_locale! - expect(settings.defaults.all).to eq(test_override: 'cn', test_default: 'test') + expect(settings.defaults.all('zh_CN')).to eq(test_override: 'cn', test_default: 'test') end end @@ -72,11 +57,6 @@ describe SiteSettings::DefaultsProvider do expect(settings.defaults.get('test_override')).to eq 'default' end - it 'returns the default value according to current locale' do - expect(settings.defaults.get(:test_override)).to eq 'default' - settings.defaults.site_locale = 'zh_CN' - expect(settings.defaults.get(:test_override)).to eq 'cn' - end end describe '.set_regardless_of_locale' do @@ -85,8 +65,7 @@ describe SiteSettings::DefaultsProvider do it 'sets the default value to a site setting regardless the locale' do settings.defaults.set_regardless_of_locale(:test_override, val) expect(settings.defaults.get(:test_override)).to eq val - settings.defaults.site_locale = 'zh_CN' - expect(settings.defaults.get(:test_override)).to eq val + expect(settings.defaults.get(:test_override, 'zh_CN')).to eq val end it 'handles the string' do @@ -111,143 +90,13 @@ describe SiteSettings::DefaultsProvider do }.to raise_error(Discourse::InvalidParameters) end end - - describe '.each' do - it 'yields the pair of site settings' do - expect { |b| settings.defaults.each(&b) }.to yield_successive_args([:test_override, 'default'], [:test_default, 'test']) - settings.defaults.site_locale = 'zh_CN' - expect { |b| settings.defaults.each(&b) }.to yield_successive_args([:test_override, 'cn'], [:test_default, 'test']) - end - end - end - - describe '.site_locale' do - it 'returns the current site locale' do - expect(settings.defaults.site_locale).to eq 'en' - end - - context 'when locale is set in the db' do - let(:db_val) { 'zr' } - let(:global_val) { 'gr' } - - before do - settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY, - db_val, - SiteSetting.types[:string]) - settings.defaults.refresh_site_locale! - end - - it 'should load from database' do - expect(settings.defaults.site_locale).to eq db_val - end - - it 'prioritizes GlobalSetting than value from db' do - GlobalSetting.stubs(:default_locale).returns(global_val) - settings.defaults.refresh_site_locale! - expect(settings.defaults.site_locale).to eq global_val - end - - it 'ignores blank GlobalSetting' do - GlobalSetting.stubs(:default_locale).returns('') - settings.defaults.refresh_site_locale! - expect(settings.defaults.site_locale).to eq db_val - end - end - - end - - describe '.site_locale=' do - it 'should store site locale in a distributed cache' do - expect(settings.defaults.class.class_variable_get(:@@site_locales)) - .to be_a(DistributedCache) - end - - it 'changes and store the current site locale' do - settings.defaults.site_locale = 'zh_CN' - - expect(settings.defaults.site_locale).to eq('zh_CN') - end - - it 'changes and store the current site locale' do - expect { settings.defaults.site_locale = 'random' }.to raise_error(Discourse::InvalidParameters) - expect(settings.defaults.site_locale).to eq 'en' - end - - it "don't change when it's shadowed" do - GlobalSetting.stubs(:default_locale).returns('shadowed') - settings.defaults.site_locale = 'zh_CN' - expect(settings.defaults.site_locale).to eq 'shadowed' - end - - it 'refresh_site_locale! when called' do - settings.defaults.expects(:refresh_site_locale!) - settings.defaults.site_locale = 'zh_CN' - end - - it 'refreshes the client when changed' do - Discourse.expects(:request_refresh!).once - settings.defaults.site_locale = 'zh_CN' - end - - it "doesn't refresh the client when changed" do - Discourse.expects(:request_refresh!).never - settings.defaults.site_locale = 'en' - end - end - - describe '.locale_setting_hash' do - it 'returns the hash for client display' do - result = settings.defaults.locale_setting_hash - - expect(result[:setting]).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY) - expect(result[:default]).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE) - expect(result[:type]).to eq(SiteSetting.types[SiteSetting.types[:enum]]) - expect(result[:preview]).to be_nil - expect(result[:value]).to eq(SiteSettings::DefaultsProvider::DEFAULT_LOCALE) - expect(result[:category]).to eq(SiteSettings::DefaultsProvider::DEFAULT_CATEGORY) - expect(result[:valid_values]).to eq(LocaleSiteSetting.values) - expect(result[:translate_names]).to eq(LocaleSiteSetting.translate_names?) - expect(result[:description]).not_to be_nil - end end describe '.load_setting' do - it 'adds a setting to the cache' do - settings.defaults.load_setting('new_a', 1) + it 'adds a setting to the cache correctly' do + settings.defaults.load_setting('new_a', 1, zh_CN: 7) expect(settings.defaults[:new_a]).to eq 1 - end - - it 'takes care of locale default' do - settings.defaults.load_setting(:new_b, 1, locale_default: { zh_CN: 2, zh_TW: 2 }) - expect(settings.defaults[:new_b]).to eq 1 - end - end - - describe '.refresh_site_locale!' do - it 'loads the change to locale' do - expect(settings.defaults.site_locale).to eq 'en' - settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY, - 'zh_CN', - SiteSetting.types[:string]) - settings.defaults.refresh_site_locale! - expect(settings.defaults.site_locale).to eq 'zh_CN' - end - - it 'loads from GlobalSettings' do - expect(settings.defaults.site_locale).to eq 'en' - GlobalSetting.stubs(:default_locale).returns('fr') - settings.defaults.refresh_site_locale! - expect(settings.defaults.site_locale).to eq 'fr' - end - - it 'prioritized GlobalSettings than db' do - expect(settings.defaults.site_locale).to eq 'en' - settings.provider.save(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY, - 'zh_CN', - SiteSetting.types[:string]) - GlobalSetting.stubs(:default_locale).returns('fr') - settings.defaults.refresh_site_locale! - expect(settings.defaults.site_locale).to eq 'fr' + expect(settings.defaults.get(:new_a, 'zh_CN')).to eq 7 end end @@ -266,7 +115,7 @@ describe SiteSettings::DefaultsProvider do end it 'default_locale always exists' do - expect(settings.defaults.has_setting?(SiteSettings::DefaultsProvider::DEFAULT_LOCALE_KEY)).to be_truthy + expect(settings.defaults.has_setting?(:default_locale)).to be_truthy end it 'returns false when the key is not exist' do diff --git a/spec/controllers/admin/site_settings_controller_spec.rb b/spec/controllers/admin/site_settings_controller_spec.rb index b1f6007e93..c65247044c 100644 --- a/spec/controllers/admin/site_settings_controller_spec.rb +++ b/spec/controllers/admin/site_settings_controller_spec.rb @@ -12,14 +12,18 @@ describe Admin::SiteSettingsController do end context 'index' do - it 'returns success' do + it 'returns valid info' do get :index, format: :json - expect(response).to be_successful - end + json = ::JSON.parse(response.body) + expect(json).to be_present + expect(response.status).to eq(200) + expect(json["site_settings"].length).to be > 100 - it 'returns JSON' do - get :index, format: :json - expect(::JSON.parse(response.body)).to be_present + locale = json["site_settings"].select do |s| + s["setting"] == "default_locale" + end + + expect(locale.length).to eq(1) end end diff --git a/spec/multisite/jobs_spec.rb b/spec/multisite/jobs_spec.rb index 076f6cea54..2434bda3d4 100644 --- a/spec/multisite/jobs_spec.rb +++ b/spec/multisite/jobs_spec.rb @@ -5,7 +5,6 @@ RSpec.describe "Running Sidekiq Jobs in Multisite" do before do conn.config_filename = "spec/fixtures/multisite/two_dbs.yml" - SiteSetting.defaults.refresh_site_locale! end after do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index fd977925cd..e222e65e23 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -153,7 +153,6 @@ RSpec.configure do |config| SiteSetting.provider.all.each do |setting| SiteSetting.remove_override!(setting.name) end - SiteSetting.defaults.site_locale = SiteSettings::DefaultsProvider::DEFAULT_LOCALE # very expensive IO operations SiteSetting.automatically_download_gravatars = false From f75d1e958d7292f9cd02ac7e9ff7ff1937e293bd Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 12:45:29 +0300 Subject: [PATCH 0073/1439] REFACTOR: extra locales controller specs to requests --- .../extra_locales_controller_spec.rb | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) rename spec/{controllers => requests}/extra_locales_controller_spec.rb (72%) diff --git a/spec/controllers/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb similarity index 72% rename from spec/controllers/extra_locales_controller_spec.rb rename to spec/requests/extra_locales_controller_spec.rb index 50a4234ce3..3093d9f38f 100644 --- a/spec/controllers/extra_locales_controller_spec.rb +++ b/spec/requests/extra_locales_controller_spec.rb @@ -1,28 +1,27 @@ require 'rails_helper' describe ExtraLocalesController do - context 'show' do - it "caches for 24 hours if version is provided and it matches current hash" do - get :show, params: { bundle: 'admin', v: ExtraLocalesController.bundle_js_hash('admin') } + get "/extra-locales/admin", params: { v: ExtraLocalesController.bundle_js_hash('admin') } + expect(response.status).to eq(200) expect(response.headers["Cache-Control"]).to eq("max-age=86400, public, immutable") end it "does not cache at all if version is invalid" do - get :show, params: { bundle: 'admin', v: 'a' * 32 } + get "/extra-locales/admin", params: { v: 'a' * 32 } + expect(response.status).to eq(200) expect(response.headers["Cache-Control"]).not_to eq("max-age=86400, public, immutable") end it "needs a valid bundle" do - get :show, params: { bundle: 'made-up-bundle' } - expect(response).to_not be_successful - expect(response.body).to be_blank + get "/extra-locales/made-up-bundle" + expect(response.status).to eq(403) end it "won't work with a weird parameter" do - get :show, params: { bundle: '-invalid..character!!' } - expect(response).to_not be_successful + get "/extra-locales/-invalid..character!!" + expect(response.status).to eq(404) end it "includes plugin translations" do @@ -41,12 +40,10 @@ describe ExtraLocalesController do } }).at_least_once - get :show, params: { bundle: "admin" } + get "/extra-locales/admin" expect(response).to be_successful expect(response.body.include?("github_badges")).to eq(true) end - end - end From 1b7d46c054b9e2c8703801771ebdecf99ae6462c Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 06:28:27 +0300 Subject: [PATCH 0074/1439] REFACTOR: post actions controller specs to requests --- spec/requests/post_actions_controller_spec.rb | 153 +++++++++++++++++- 1 file changed, 148 insertions(+), 5 deletions(-) diff --git a/spec/requests/post_actions_controller_spec.rb b/spec/requests/post_actions_controller_spec.rb index c89d68b772..f3e8a38557 100644 --- a/spec/requests/post_actions_controller_spec.rb +++ b/spec/requests/post_actions_controller_spec.rb @@ -5,18 +5,91 @@ RSpec.describe PostActionsController do let(:post) { Fabricate(:post, user: Fabricate(:coding_horror)) } it 'requires you to be logged in' do - delete '/post_action.json', params: { id: post.id } - expect(response.status).to eq(404) + delete "/post_actions/#{post.id}.json" + expect(response.status).to eq(403) + end + + context 'logged in' do + let(:user) { Fabricate(:user) } + + before do + sign_in(user) + end + + it 'raises an error when the post_action_type_id is missing' do + delete "/post_actions/#{post.id}.json" + expect(response.status).to eq(400) + end + + it "returns 404 when the post action type doesn't exist for that user" do + delete "/post_actions/#{post.id}.json", params: { post_action_type_id: PostActionType.types[:bookmark] } + expect(response.status).to eq(404) + end + + context 'with a post_action record ' do + let!(:post_action) do + PostAction.create!( + user_id: user.id, + post_id: post.id, + post_action_type_id: PostActionType.types[:bookmark] + ) + end + + it 'returns success' do + delete "/post_actions/#{post.id}.json", params: { post_action_type_id: PostActionType.types[:bookmark] } + expect(response).to be_success + end + + it 'deletes the action' do + delete "/post_actions/#{post.id}.json", params: { + post_action_type_id: PostActionType.types[:bookmark] + } + + expect(response).to be_success + expect(PostAction.exists?( + user_id: user.id, + post_id: post.id, + post_action_type_id: PostActionType.types[:bookmark], + deleted_at: nil + )).to eq(false) + end + + it "isn't deleted when the user doesn't have permission" do + pa = PostAction.create!( + post: post, + user: user, + post_action_type_id: PostActionType.types[:like], + created_at: 1.day.ago + ) + + delete "/post_actions/#{post.id}.json", params: { + post_action_type_id: PostActionType.types[:like] + } + + expect(response).to be_forbidden + end + end end end describe '#create' do - it 'requires you to be logged in' do post '/post_actions.json' expect(response.status).to eq(403) end + it 'fails when the user does not have permission to see the post' do + sign_in(Fabricate(:user)) + pm = Fabricate(:private_message_post, user: Fabricate(:coding_horror)) + + post "/post_actions.json", params: { + id: pm.id, + post_action_type_id: PostActionType.types[:bookmark] + } + + expect(response).to be_forbidden + end + describe 'as a moderator' do let(:user) { Fabricate(:moderator) } let(:post_1) { Fabricate(:post, user: Fabricate(:coding_horror)) } @@ -64,12 +137,13 @@ RSpec.describe PostActionsController do post_action = PostAction.last + expect(response).to be_success expect(post_action.post_id).to eq(post_1.id) expect(post_action.post_action_type_id).to eq(PostActionType.types[:like]) end it "passes a list of taken actions through" do - PostAction.create( + PostAction.create!( post_id: post_1.id, user_id: user.id, post_action_type_id: PostActionType.types[:inappropriate] @@ -79,7 +153,7 @@ RSpec.describe PostActionsController do id: post_1.id, post_action_type_id: PostActionType.types[:off_topic] } - expect(response).to_not be_successful + expect(response).to be_forbidden end it 'passes the message through' do @@ -91,6 +165,7 @@ RSpec.describe PostActionsController do message: message } + expect(response).to be_success expect(PostAction.last.post_id).to eq(post_1.id) expect(Post.last.raw).to include(message) end @@ -105,6 +180,7 @@ RSpec.describe PostActionsController do is_warning: true } + expect(response).to be_success expect(PostAction.last.post_id).to eq(post_1.id) post = Post.last @@ -158,4 +234,71 @@ RSpec.describe PostActionsController do end end end + + describe '#defer_flags' do + let!(:flag) do + PostAction.create!( + post_id: flagged_post.id, + user_id: Fabricate(:user).id, + post_action_type_id: PostActionType.types[:spam] + ) + end + let(:flagged_post) { Fabricate(:post, user: Fabricate(:coding_horror)) } + + context "not logged in" do + it "should not allow them to clear flags" do + post "/post_actions/defer_flags.json", params: { id: flagged_post.id } + expect(response.status).to eq(403) + flag.reload + expect(flag.deferred_at).to be_nil + end + end + + context 'logged in' do + let!(:user) { sign_in(Fabricate(:moderator)) } + + it "raises an error without a post_action_type_id" do + post "/post_actions/defer_flags.json", params: { id: flagged_post.id } + expect(response.status).to eq(400) + flag.reload + expect(flag.deferred_at).to be_nil + end + + it "raises an error when the user doesn't have access" do + sign_in(Fabricate(:user)) + + post "/post_actions/defer_flags.json", params: { + id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] + } + + expect(response).to be_forbidden + flag.reload + expect(flag.deferred_at).to be_nil + end + + context "success" do + it "delegates to defer_flags" do + post "/post_actions/defer_flags.json", params: { + id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] + } + + expect(response).to be_success + flag.reload + expect(flag.deferred_at).to be_present + end + + it "works with a deleted post" do + flagged_post.trash!(user) + + post "/post_actions/defer_flags.json", params: { + id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] + } + + expect(response).to be_success + flag.reload + expect(flag.deferred_at).to be_present + end + end + end + end end From cc82fb33b5cef071a66e7398e3f25789edcb2207 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 07:43:05 +0300 Subject: [PATCH 0075/1439] REFACTOR: queued posts controller specs to requests --- .../queued_posts_controller_spec.rb | 144 ------------------ spec/requests/queued_posts_controller_spec.rb | 125 +++++++++++++++ 2 files changed, 125 insertions(+), 144 deletions(-) delete mode 100644 spec/controllers/queued_posts_controller_spec.rb create mode 100644 spec/requests/queued_posts_controller_spec.rb diff --git a/spec/controllers/queued_posts_controller_spec.rb b/spec/controllers/queued_posts_controller_spec.rb deleted file mode 100644 index 89620c116d..0000000000 --- a/spec/controllers/queued_posts_controller_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -require 'rails_helper' -require_dependency 'queued_posts_controller' -require_dependency 'queued_post' - -describe QueuedPostsController do - context 'without authentication' do - it 'fails' do - get :index, format: :json - expect(response).not_to be_successful - end - end - - context 'as a regular user' do - let!(:user) { log_in(:user) } - it 'fails' do - get :index, format: :json - expect(response).not_to be_successful - end - end - - context 'as an admin' do - let!(:user) { log_in(:moderator) } - - it 'returns the queued posts' do - get :index, format: :json - expect(response).to be_successful - end - end - - describe '#update' do - let!(:user) { log_in(:moderator) } - let(:qp) { Fabricate(:queued_post) } - - context 'not found' do - it 'returns json error' do - qp.destroy! - - put :update, params: { - id: qp.id, queued_post: { state: 'approved' } - }, format: :json - - expect(response.status).to eq(422) - - expect(eval(response.body)).to eq(described_class.new.create_errors_json(I18n.t('queue.not_found'))) - end - end - - context 'approved' do - it 'updates the post to approved' do - - put :update, params: { - id: qp.id, queued_post: { state: 'approved' } - }, format: :json - - expect(response).to be_successful - - qp.reload - expect(qp.state).to eq(QueuedPost.states[:approved]) - end - end - - context 'rejected' do - it 'updates the post to rejected' do - - put :update, params: { - id: qp.id, queued_post: { state: 'rejected' } - }, format: :json - - expect(response).to be_successful - - qp.reload - expect(qp.state).to eq(QueuedPost.states[:rejected]) - end - end - - context 'editing content' do - let(:changes) do - { - raw: 'new raw', - title: 'new title', - category_id: 10, - tags: ['new_tag'] - } - end - - context 'when it is a topic' do - let(:queued_topic) { Fabricate(:queued_topic) } - - before do - put :update, params: { - id: queued_topic.id, queued_post: changes - }, format: :json - - expect(response).to be_successful - end - - it 'updates raw' do - expect(queued_topic.reload.raw).to eq(changes[:raw]) - end - - it 'updates the title' do - expect(queued_topic.reload.post_options['title']).to eq(changes[:title]) - end - - it 'updates the category' do - expect(queued_topic.reload.post_options['category']).to eq(changes[:category_id]) - end - - it 'updates the tags' do - expect(queued_topic.reload.post_options['tags']).to eq(changes[:tags]) - end - end - - context 'when it is a reply' do - let(:queued_reply) { Fabricate(:queued_post) } - - before do - put :update, params: { - id: queued_reply.id, queued_post: changes - }, format: :json - - expect(response).to be_successful - end - - it 'updates raw' do - expect(queued_reply.reload.raw).to eq(changes[:raw]) - end - - it 'does not update the title' do - expect(queued_reply.reload.post_options['title']).to be_nil - end - - it 'does not update the category' do - original_category = queued_reply.post_options['category'] - expect(queued_reply.reload.post_options['category']).to eq(original_category) - end - - it 'does not update the tags' do - expect(queued_reply.reload.post_options['tags']).to be_nil - end - end - end - end -end diff --git a/spec/requests/queued_posts_controller_spec.rb b/spec/requests/queued_posts_controller_spec.rb new file mode 100644 index 0000000000..421c0d9bc7 --- /dev/null +++ b/spec/requests/queued_posts_controller_spec.rb @@ -0,0 +1,125 @@ +require 'rails_helper' +require_dependency 'queued_posts_controller' +require_dependency 'queued_post' + +describe QueuedPostsController do + context 'without authentication' do + it 'fails' do + get "/queued-posts.json" + expect(response).to be_forbidden + end + end + + context 'as a regular user' do + before { sign_in(Fabricate(:user)) } + + it 'fails' do + get "/queued-posts.json" + expect(response).to be_forbidden + end + end + + context 'as an admin' do + before { sign_in(Fabricate(:moderator)) } + + it 'returns the queued posts' do + get "/queued-posts.json" + expect(response).to be_success + end + end + + describe '#update' do + before { sign_in(Fabricate(:moderator)) } + let(:qp) { Fabricate(:queued_post) } + + context 'not found' do + it 'returns json error' do + qp.destroy! + + put "/queued_posts/#{qp.id}.json", params: { + queued_post: { state: 'approved' } + } + + expect(response.status).to eq(422) + + expect(JSON.parse(response.body)["errors"].first).to eq(I18n.t('queue.not_found')) + end + end + + context 'approved' do + it 'updates the post to approved' do + + put "/queued_posts/#{qp.id}.json", params: { + queued_post: { state: 'approved' } + } + + expect(response).to be_success + + qp.reload + expect(qp.state).to eq(QueuedPost.states[:approved]) + end + end + + context 'rejected' do + it 'updates the post to rejected' do + + put "/queued_posts/#{qp.id}.json", params: { + queued_post: { state: 'rejected' } + } + + expect(response).to be_success + + qp.reload + expect(qp.state).to eq(QueuedPost.states[:rejected]) + end + end + + context 'editing content' do + let(:changes) do + { + raw: 'new raw', + title: 'new title', + category_id: 10, + tags: ['new_tag'] + } + end + + context 'when it is a topic' do + let(:queued_topic) { Fabricate(:queued_topic) } + + it 'updates the topic attributes' do + put "/queued_posts/#{queued_topic.id}.json", params: { + queued_post: changes + } + + expect(response).to be_success + queued_topic.reload + + expect(queued_topic.raw).to eq(changes[:raw]) + expect(queued_topic.post_options['title']).to eq(changes[:title]) + expect(queued_topic.post_options['category']).to eq(changes[:category_id]) + expect(queued_topic.post_options['tags']).to eq(changes[:tags]) + end + end + + context 'when it is a reply' do + let(:queued_reply) { Fabricate(:queued_post) } + + it 'updates the reply attributes' do + put "/queued_posts/#{queued_reply.id}.json", params: { + queued_post: changes + } + + original_category = queued_reply.post_options['category'] + expect(response).to be_success + queued_reply.reload + + expect(queued_reply.raw).to eq(changes[:raw]) + expect(queued_reply.post_options['title']).to be_nil + expect(queued_reply.post_options['category']).to eq(original_category) + expect(queued_reply.post_options['tags']).to be_nil + end + end + end + end +end From 4782f6cd017302671b6fee82bec19850f2fd58fe Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 12:45:38 +0800 Subject: [PATCH 0076/1439] Remove controller type spec for post actions. --- .../post_actions_controller_spec.rb | 135 ------------------ 1 file changed, 135 deletions(-) delete mode 100644 spec/controllers/post_actions_controller_spec.rb diff --git a/spec/controllers/post_actions_controller_spec.rb b/spec/controllers/post_actions_controller_spec.rb deleted file mode 100644 index 69a5bc2389..0000000000 --- a/spec/controllers/post_actions_controller_spec.rb +++ /dev/null @@ -1,135 +0,0 @@ -require 'rails_helper' - -describe PostActionsController do - - describe 'create' do - - context 'logged in as user' do - let(:user) { Fabricate(:user) } - let(:private_message) { Fabricate(:private_message_post, user: Fabricate(:coding_horror)) } - - before do - log_in_user(user) - end - - it 'fails when the user does not have permission to see the post' do - post :create, params: { - id: private_message.id, - post_action_type_id: PostActionType.types[:bookmark] - }, format: :json - - expect(response).to be_forbidden - end - end - end - - context 'destroy' do - - let(:post) { Fabricate(:post, user: Fabricate(:coding_horror)) } - - context 'logged in' do - let!(:user) { log_in } - - it 'raises an error when the post_action_type_id is missing' do - expect do - delete :destroy, params: { id: post.id }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "returns 404 when the post action type doesn't exist for that user" do - delete :destroy, params: { id: post.id, post_action_type_id: 1 }, format: :json - expect(response.code).to eq('404') - end - - context 'with a post_action record ' do - let!(:post_action) { PostAction.create(user_id: user.id, post_id: post.id, post_action_type_id: 1) } - - it 'returns success' do - delete :destroy, params: { id: post.id, post_action_type_id: 1 }, format: :json - expect(response).to be_successful - end - - it 'deletes the action' do - delete :destroy, params: { - id: post.id, post_action_type_id: 1 - }, format: :json - - expect(PostAction.exists?(user_id: user.id, post_id: post.id, post_action_type_id: 1, deleted_at: nil)).to eq(false) - end - - it 'ensures it can be deleted' do - Guardian.any_instance.expects(:can_delete?).with(post_action).returns(false) - - delete :destroy, params: { - id: post.id, post_action_type_id: 1 - }, format: :json - - expect(response).to be_forbidden - end - end - - end - - end - - context 'defer_flags' do - - let(:flagged_post) { Fabricate(:post, user: Fabricate(:coding_horror)) } - - context "not logged in" do - it "should not allow them to clear flags" do - post :defer_flags, format: :json - expect(response.status).to eq(403) - end - end - - context 'logged in' do - let!(:user) { log_in(:moderator) } - - it "raises an error without a post_action_type_id" do - expect do - post :defer_flags, params: { id: flagged_post.id }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "raises an error when the user doesn't have access" do - Guardian.any_instance.expects(:can_defer_flags?).returns(false) - - post :defer_flags, params: { - id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] - }, format: :json - - expect(response).to be_forbidden - end - - context "success" do - before do - Guardian.any_instance.expects(:can_defer_flags?).returns(true) - PostAction.expects(:defer_flags!).with(flagged_post, user) - end - - it "delegates to defer_flags" do - post :defer_flags, params: { - id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] - }, format: :json - - expect(response).to be_successful - end - - it "works with a deleted post" do - flagged_post.trash!(user) - - post :defer_flags, params: { - id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] - }, format: :json - - expect(response).to be_successful - end - - end - - end - - end - -end From 5ecaa55e5059e77cad407c74fbedfd81fa33932f Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 08:17:33 +0300 Subject: [PATCH 0077/1439] REFACTOR: webhooks controller specs to requests --- .../webhooks_controller_spec.rb | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) rename spec/{controllers => requests}/webhooks_controller_spec.rb (81%) diff --git a/spec/controllers/webhooks_controller_spec.rb b/spec/requests/webhooks_controller_spec.rb similarity index 81% rename from spec/controllers/webhooks_controller_spec.rb rename to spec/requests/webhooks_controller_spec.rb index cfd8c6f9de..e0ed4db5cf 100644 --- a/spec/controllers/webhooks_controller_spec.rb +++ b/spec/requests/webhooks_controller_spec.rb @@ -7,22 +7,25 @@ describe WebhooksController do let(:message_id) { "12345@il.com" } context "mailgun" do - it "works" do SiteSetting.mailgun_api_key = "key-8221462f0c915af3f6f2e2df7aa5a493" user = Fabricate(:user, email: email) email_log = Fabricate(:email_log, user: user, message_id: message_id, to_address: email) - WebhooksController.any_instance.expects(:mailgun_verify).returns(true) + token = "705a8ccd2ce932be8e98c221fe701c1b4a0afcb8bbd57726de" + timestamp = Time.now.to_i + data = "#{timestamp}#{token}" + signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, SiteSetting.mailgun_api_key, data) - post :mailgun, params: { - "token" => "705a8ccd2ce932be8e98c221fe701c1b4a0afcb8bbd57726de", - "timestamp" => Time.now.to_i, + post "/webhooks/mailgun.json", params: { + "token" => token, + "timestamp" => timestamp, "event" => "dropped", "recipient" => email, - "Message-Id" => "<12345@il.com>" - }, format: :json + "Message-Id" => "<12345@il.com>", + "signature" => signature + } expect(response).to be_successful @@ -30,16 +33,14 @@ describe WebhooksController do expect(email_log.bounced).to eq(true) expect(email_log.user.user_stat.bounce_score).to eq(2) end - end context "sendgrid" do - it "works" do user = Fabricate(:user, email: email) email_log = Fabricate(:email_log, user: user, message_id: message_id, to_address: email) - post :sendgrid, params: { + post "/webhooks/sendgrid.json", params: { "_json" => [ { "email" => email, @@ -48,7 +49,7 @@ describe WebhooksController do "status" => "5.0.0" } ] - }, format: :json + } expect(response).to be_successful @@ -56,21 +57,19 @@ describe WebhooksController do expect(email_log.bounced).to eq(true) expect(email_log.user.user_stat.bounce_score).to eq(2) end - end context "mailjet" do - it "works" do user = Fabricate(:user, email: email) email_log = Fabricate(:email_log, user: user, message_id: message_id, to_address: email) - post :mailjet, params: { + post "/webhooks/mailjet.json", params: { "event" => "bounce", "email" => email, "hard_bounce" => true, "CustomID" => message_id - }, format: :json + } expect(response).to be_successful @@ -78,16 +77,14 @@ describe WebhooksController do expect(email_log.bounced).to eq(true) expect(email_log.user.user_stat.bounce_score).to eq(2) end - end context "mandrill" do - it "works" do user = Fabricate(:user, email: email) email_log = Fabricate(:email_log, user: user, message_id: message_id, to_address: email) - post :mandrill, params: { + post "/webhooks/mandrill.json", params: { mandrill_events: [{ "event" => "hard_bounce", "msg" => { @@ -97,7 +94,7 @@ describe WebhooksController do } } }] - }, format: :json + } expect(response).to be_successful @@ -105,16 +102,14 @@ describe WebhooksController do expect(email_log.bounced).to eq(true) expect(email_log.user.user_stat.bounce_score).to eq(2) end - end context "sparkpost" do - it "works" do user = Fabricate(:user, email: email) email_log = Fabricate(:email_log, user: user, message_id: message_id, to_address: email) - post :sparkpost, params: { + post "/webhooks/sparkpost.json", params: { "_json" => [{ "msys" => { "message_event" => { @@ -126,7 +121,7 @@ describe WebhooksController do } } }] - }, format: :json + } expect(response).to be_successful @@ -134,7 +129,5 @@ describe WebhooksController do expect(email_log.bounced).to eq(true) expect(email_log.user.user_stat.bounce_score).to eq(2) end - end - end From 7f21892ad0619be15a13c71785992eed91c1cda7 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 08:39:23 +0300 Subject: [PATCH 0078/1439] REFACTOR: finish installation controller specs to requests --- .../finish_installation_controller_spec.rb | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) rename spec/{controllers => requests}/finish_installation_controller_spec.rb (62%) diff --git a/spec/controllers/finish_installation_controller_spec.rb b/spec/requests/finish_installation_controller_spec.rb similarity index 62% rename from spec/controllers/finish_installation_controller_spec.rb rename to spec/requests/finish_installation_controller_spec.rb index a7ee627ebe..0703a2d9c0 100644 --- a/spec/controllers/finish_installation_controller_spec.rb +++ b/spec/requests/finish_installation_controller_spec.rb @@ -2,15 +2,15 @@ require 'rails_helper' describe FinishInstallationController do - describe '.index' do + describe '#index' do context "has_login_hint is false" do before do SiteSetting.has_login_hint = false end it "doesn't allow access" do - get :index - expect(response).not_to be_successful + get "/finish-installation" + expect(response).to be_forbidden end end @@ -20,21 +20,21 @@ describe FinishInstallationController do end it "allows access" do - get :index - expect(response).to be_successful + get "/finish-installation" + expect(response.status).to eq(200) end end end - describe '.register' do + describe '#register' do context "has_login_hint is false" do before do SiteSetting.has_login_hint = false end it "doesn't allow access" do - get :register - expect(response).not_to be_successful + get "/finish-installation/register" + expect(response).to be_forbidden end end @@ -45,21 +45,21 @@ describe FinishInstallationController do end it "allows access" do - get :register - expect(response).to be_successful + get "/finish-installation/register" + expect(response.status).to eq(200) end it "raises an error when the email is not in the allowed list" do - post :register, params: { + post "/finish-installation/register.json", params: { email: 'notrobin@example.com', username: 'eviltrout', password: 'disismypasswordokay' - }, format: :json + } expect(response.status).to eq(400) end it "doesn't redirect when fields are wrong" do - post :register, params: { + post "/finish-installation/register", params: { email: 'robin@example.com', username: '', password: 'disismypasswordokay' @@ -69,40 +69,39 @@ describe FinishInstallationController do end it "registers the admin when the email is in the list" do - Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup)) - - post :register, params: { - email: 'robin@example.com', - username: 'eviltrout', - password: 'disismypasswordokay' - }, format: :json + expect do + post "/finish-installation/register.json", params: { + email: 'robin@example.com', + username: 'eviltrout', + password: 'disismypasswordokay' + } + end.to change { Jobs::CriticalUserEmail.jobs.size }.by(1) expect(response).to be_redirect expect(User.where(username: 'eviltrout').exists?).to eq(true) end - end end - describe '.confirm_email' do + describe '#confirm_email' do context "has_login_hint is false" do before do SiteSetting.has_login_hint = false end it "shows the page" do - get :confirm_email - expect(response).to be_successful + get "/finish-installation/confirm-email" + expect(response.status).to eq(200) end end end - describe '.resend_email' do + describe '#resend_email' do before do SiteSetting.has_login_hint = true GlobalSetting.stubs(:developer_emails).returns("robin@example.com") - post :register, params: { + post "/finish-installation/register", params: { email: 'robin@example.com', username: 'eviltrout', password: 'disismypasswordokay' @@ -110,9 +109,11 @@ describe FinishInstallationController do end it "resends the email" do - Jobs.expects(:enqueue).with(:critical_user_email, has_entries(type: :signup)) - get :resend_email - expect(response).to be_successful + expect do + put "/finish-installation/resend-email" + end.to change { Jobs::CriticalUserEmail.jobs.size }.by(1) + + expect(response.status).to eq(200) end end end From 54c0aa788cc365909dc507e6c5e0a454c8179dfc Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 14:51:00 +1000 Subject: [PATCH 0079/1439] FIX: db:create was failing due to site settings --- lib/site_settings/db_provider.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/site_settings/db_provider.rb b/lib/site_settings/db_provider.rb index 3ad32164e9..0887e0edc4 100644 --- a/lib/site_settings/db_provider.rb +++ b/lib/site_settings/db_provider.rb @@ -57,12 +57,12 @@ class SiteSettings::DbProvider # table is not in the db yet, initial migration, etc def table_exists? @table_exists ||= {} - - unless @table_exists[current_site] - @table_exists[current_site] = ActiveRecord::Base.connection.table_exists?(@model.table_name) + begin + @table_exists[current_site] ||= ActiveRecord::Base.connection.table_exists?(@model.table_name) + rescue + STDERR.puts "No connection to db, unable to retrieve site settings! (normal when running db:create)" + @table_exists[current_site] = false end - - @table_exists[current_site] end end From 05c1fe5c8facc2ae7154820a2d5cfb41d9eae655 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 16:02:59 +0300 Subject: [PATCH 0080/1439] REFACTOR: user actions controller specs to requests --- .../user_actions_controller_spec.rb | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) rename spec/{controllers => requests}/user_actions_controller_spec.rb (81%) diff --git a/spec/controllers/user_actions_controller_spec.rb b/spec/requests/user_actions_controller_spec.rb similarity index 81% rename from spec/controllers/user_actions_controller_spec.rb rename to spec/requests/user_actions_controller_spec.rb index d6e6ae949c..3bae24ecfa 100644 --- a/spec/controllers/user_actions_controller_spec.rb +++ b/spec/requests/user_actions_controller_spec.rb @@ -5,16 +5,15 @@ describe UserActionsController do context 'index' do it 'fails if username is not specified' do - expect do - get :index, format: :json - end.to raise_error(ActionController::ParameterMissing) + get "/user_actions.json" + expect(response.status).to eq(400) end it 'renders list correctly' do UserActionCreator.enable post = Fabricate(:post) - get :index, params: { username: post.user.username }, format: :json + get "/user_actions.json", params: { username: post.user.username } expect(response.status).to eq(200) parsed = JSON.parse(response.body) @@ -27,29 +26,28 @@ describe UserActionsController do end it 'renders help text if provided for self' do - logged_in = log_in + logged_in = sign_in(Fabricate(:user)) - get :index, params: { + get "/user_actions.json", params: { filter: UserAction::LIKE, username: logged_in.username, no_results_help_key: "user_activity.no_bookmarks" - }, format: :json + } expect(response.status).to eq(200) parsed = JSON.parse(response.body) expect(parsed["no_results_help"]).to eq(I18n.t("user_activity.no_bookmarks.self")) - end it 'renders help text for others' do user = Fabricate(:user) - get :index, params: { + get "/user_actions.json", params: { filter: UserAction::LIKE, username: user.username, no_results_help_key: "user_activity.no_bookmarks" - }, format: :json + } expect(response.status).to eq(200) parsed = JSON.parse(response.body) @@ -61,23 +59,22 @@ describe UserActionsController do context "without access" do let(:user) { Fabricate(:user) } it "raises an exception" do - get :index, params: { + get "/user_actions.json", params: { username: user.username, filter: UserAction::PENDING - }, format: :json - expect(response).to_not be_successful - + } + expect(response).to be_forbidden end end context "with access" do - let(:user) { log_in } + let(:user) { sign_in(Fabricate(:user)) } it 'finds queued posts' do queued_post = PostEnqueuer.new(user, 'default').enqueue(raw: 'this is the raw enqueued content') - get :index, params: { + get "/user_actions.json", params: { username: user.username, filter: UserAction::PENDING - }, format: :json + } expect(response.status).to eq(200) parsed = JSON.parse(response.body) From e2e566214d8fc42112f1717407d23e543cd9fac8 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 16:21:25 +0300 Subject: [PATCH 0081/1439] REFACTOR: user avatars controller spec to requests --- .../user_avatars_controller_spec.rb | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) rename spec/{controllers => requests}/user_avatars_controller_spec.rb (74%) diff --git a/spec/controllers/user_avatars_controller_spec.rb b/spec/requests/user_avatars_controller_spec.rb similarity index 74% rename from spec/controllers/user_avatars_controller_spec.rb rename to spec/requests/user_avatars_controller_spec.rb index 9e485a091f..0d86117abc 100644 --- a/spec/controllers/user_avatars_controller_spec.rb +++ b/spec/requests/user_avatars_controller_spec.rb @@ -5,19 +5,12 @@ describe UserAvatarsController do context 'show_proxy_letter' do it 'returns not found if external avatar is set somewhere else' do SiteSetting.external_system_avatars_url = "https://somewhere.else.com/avatar.png" - - get :show_proxy_letter, params: { - version: 'v2', letter: 'a', color: 'aaaaaa', size: 20 - }, format: :json - + get "/letter_avatar_proxy/v2/letter/a/aaaaaa/20.png" expect(response.status).to eq(404) end it 'returns an avatar if we are allowing the proxy' do - get :show_proxy_letter, params: { - version: 'v2', letter: 'a', color: 'aaaaaa', size: 360 - }, format: :json - + get "/letter_avatar_proxy/v2/letter/a/aaaaaa/360.png" expect(response.status).to eq(200) end end @@ -47,16 +40,12 @@ describe UserAvatarsController do user = Fabricate(:user, uploaded_avatar_id: upload.id) - get :show, params: { - size: 97, username: user.username, version: upload.id, hostname: 'default' - }, format: :json + get "/user_avatar/default/#{user.username}/97/#{upload.id}.png" # 98 is closest which is 49 * 2 for retina expect(response).to redirect_to("http://awesome.com/boom/user_avatar/default/#{user.username_lower}/98/#{upload.id}_#{OptimizedImage::VERSION}.png") - get :show, params: { - size: 98, username: user.username, version: upload.id, hostname: 'default' - }, format: :json + get "/user_avatar/default/#{user.username}/98/#{upload.id}.png" expect(response.body).to eq("image") expect(response.headers["Cache-Control"]).to eq('max-age=31556952, public, immutable') @@ -68,9 +57,7 @@ describe UserAvatarsController do upload = Fabricate(:upload) user = Fabricate(:user, uploaded_avatar_id: upload.id) - get :show, params: { - size: 51, username: user.username, version: upload.id, hostname: 'default' - }, format: :json + get "/user_avatar/default/#{user.username}/51/#{upload.id}.png" expect(response).to be_successful end From 2688cc624104164f1ea675554cc88deac8b4a3f5 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Tue, 5 Jun 2018 16:35:54 +0300 Subject: [PATCH 0082/1439] REFACTOR: post action users controller specs to requests --- .../post_action_users_controller_spec.rb | 33 ++++++++----------- 1 file changed, 14 insertions(+), 19 deletions(-) rename spec/{controllers => requests}/post_action_users_controller_spec.rb (68%) diff --git a/spec/controllers/post_action_users_controller_spec.rb b/spec/requests/post_action_users_controller_spec.rb similarity index 68% rename from spec/controllers/post_action_users_controller_spec.rb rename to spec/requests/post_action_users_controller_spec.rb index 302156f5d9..04d40eb866 100644 --- a/spec/controllers/post_action_users_controller_spec.rb +++ b/spec/requests/post_action_users_controller_spec.rb @@ -1,17 +1,16 @@ require 'rails_helper' describe PostActionUsersController do - let(:post) { Fabricate(:post, user: log_in) } + let(:post) { Fabricate(:post, user: sign_in(Fabricate(:user))) } context 'with render' do - render_views it 'always allows you to see your own actions' do notify_mod = PostActionType.types[:notify_moderators] PostAction.act(post.user, post, notify_mod, message: 'well something is wrong here!') PostAction.act(Fabricate(:user), post, notify_mod, message: 'well something is not wrong here!') - get :index, params: { id: post.id, post_action_type_id: notify_mod }, format: :json + get "/post_action_users.json", params: { id: post.id, post_action_type_id: notify_mod } expect(response.status).to eq(200) json = JSON.parse(response.body) users = json["post_action_users"] @@ -22,40 +21,35 @@ describe PostActionUsersController do end it 'raises an error without an id' do - expect do - get :index, - params: { post_action_type_id: PostActionType.types[:like] }, - format: :json - end.to raise_error(ActionController::ParameterMissing) + get "/post_action_users.json", params: { post_action_type_id: PostActionType.types[:like] } + expect(response.status).to eq(400) end it 'raises an error without a post action type' do - expect do - get :index, params: { id: post.id }, format: :json - end.to raise_error(ActionController::ParameterMissing) + get "/post_action_users.json", params: { id: post.id } + expect(response.status).to eq(400) end it "fails when the user doesn't have permission to see the post" do - Guardian.any_instance.expects(:can_see?).with(post).returns(false) - - get :index, params: { + post.trash! + get "/post_action_users.json", params: { id: post.id, post_action_type_id: PostActionType.types[:like] - }, format: :json + } expect(response).to be_forbidden end it 'raises an error when anon tries to look at an invalid action' do - get :index, params: { + get "/post_action_users.json", params: { id: Fabricate(:post).id, post_action_type_id: PostActionType.types[:notify_moderators] - }, format: :json + } expect(response).to be_forbidden end it 'succeeds' do - get :index, params: { + get "/post_action_users.json", params: { id: post.id, post_action_type_id: PostActionType.types[:like] } @@ -70,7 +64,8 @@ describe PostActionUsersController do PostAction.act(user, post, PostActionType.types[:like]) end - get :index, params: { id: post.id, post_action_type_id: PostActionType.types[:like], page: 1, limit: 2 }, format: :json + get "/post_action_users.json", + params: { id: post.id, post_action_type_id: PostActionType.types[:like], page: 1, limit: 2 } json = JSON.parse(response.body) users = json["post_action_users"] From 3c96ee4b6f081d655b481955ae5f5ac958bad016 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 07:57:29 +0300 Subject: [PATCH 0083/1439] REFACTOR: clicks controller specs to requests (#5929) --- spec/controllers/clicks_controller_spec.rb | 88 ---------------------- spec/requests/clicks_controller_spec.rb | 61 +++++++++++++++ 2 files changed, 61 insertions(+), 88 deletions(-) delete mode 100644 spec/controllers/clicks_controller_spec.rb create mode 100644 spec/requests/clicks_controller_spec.rb diff --git a/spec/controllers/clicks_controller_spec.rb b/spec/controllers/clicks_controller_spec.rb deleted file mode 100644 index 67650b2eb8..0000000000 --- a/spec/controllers/clicks_controller_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -require 'rails_helper' - -describe ClicksController do - - context 'create' do - - context 'missing params' do - - it 'raises a 404 without a url' do - get :track, params: { post_id: 123 } - - expect(response).to be_not_found - end - - end - - context 'correct params' do - let(:url) { "http://discourse.org" } - - before do - request.headers.merge!('REMOTE_ADDR' => '192.168.0.1') - end - - context "with a made up url" do - render_views - - it "doesn't redirect" do - TopicLinkClick.expects(:create_from).returns(nil) - - get :track, params: { url: 'http://discourse.org', post_id: 123 } - - expect(response).not_to be_redirect - expect(response.body).to include(I18n.t("redirect_warning")) - end - end - - context "with a valid url" do - it "redirects" do - TopicLinkClick.expects(:create_from).with(has_entries('url' => 'http://discourse.org/?hello=123')).returns(url) - - get :track, params: { url: 'http://discourse.org/?hello=123', post_id: 123 } - - expect(response).to redirect_to(url) - end - end - - context 'with a post_id' do - it 'redirects' do - TopicLinkClick.expects(:create_from).with('url' => url, 'post_id' => '123', 'ip' => '192.168.0.1').returns(url) - - get :track, params: { url: url, post_id: 123 } - - expect(response).to redirect_to(url) - end - - it "redirects links in whispers to staff members" do - log_in(:admin) - whisper = Fabricate(:post, post_type: Post.types[:whisper]) - - get :track, params: { url: url, post_id: whisper.id } - - expect(response).to redirect_to(url) - end - - it "doesn't redirect with the redirect=false param" do - TopicLinkClick.expects(:create_from).with('url' => url, 'post_id' => '123', 'ip' => '192.168.0.1', 'redirect' => 'false').returns(url) - - get :track, params: { url: url, post_id: 123, redirect: 'false' } - - expect(response).not_to be_redirect - end - end - - context 'with a topic_id' do - it 'redirects' do - TopicLinkClick.expects(:create_from).with('url' => url, 'topic_id' => '789', 'ip' => '192.168.0.1').returns(url) - - get :track, params: { url: url, topic_id: 789 } - - expect(response).to redirect_to(url) - end - end - - end - - end - -end diff --git a/spec/requests/clicks_controller_spec.rb b/spec/requests/clicks_controller_spec.rb new file mode 100644 index 0000000000..293b07bdf7 --- /dev/null +++ b/spec/requests/clicks_controller_spec.rb @@ -0,0 +1,61 @@ +require 'rails_helper' + +describe ClicksController do + context 'create' do + context 'missing params' do + it 'raises a 404 without a url' do + get "/clicks/track", params: { post_id: 123 } + expect(response).to be_not_found + end + end + + context 'correct params' do + let(:url) { "https://discourse.org/" } + let(:headers) { { REMOTE_ADDR: "192.168.0.1" } } + let(:post) { create_post(raw: "this is a post with a link #{url}") } + + context "with a made up url" do + it "doesn't redirect" do + get "/clicks/track", params: { url: 'https://fakewebsite.com', post_id: post.id }, headers: headers + expect(response).not_to be_redirect + expect(response.body).to include(I18n.t("redirect_warning")) + end + end + + context "with a valid url" do + it "redirects" do + get "/clicks/track", params: { url: 'https://discourse.org/?hello=123', post_id: post.id }, headers: headers + expect(response).to redirect_to("https://discourse.org/?hello=123") + end + end + + context 'with a post_id' do + it 'redirects' do + get "/clicks/track", params: { url: url, post_id: post.id }, headers: headers + expect(response).to redirect_to(url) + end + + it "redirects links in whispers to staff members" do + sign_in(Fabricate(:admin)) + whisper = Fabricate(:post, post_type: Post.types[:whisper]) + + get "/clicks/track", params: { url: url, post_id: whisper.id }, headers: headers + + expect(response).to redirect_to(url) + end + + it "doesn't redirect with the redirect=false param" do + get "/clicks/track", params: { url: url, post_id: post.id, redirect: 'false' }, headers: headers + expect(response).not_to be_redirect + end + end + + context 'with a topic_id' do + it 'redirects' do + get "/clicks/track", params: { url: url, topic_id: post.topic.id }, headers: headers + expect(response).to redirect_to(url) + end + end + end + end +end From 0124209a96df4d72c0d64c8799ef92a9f2745533 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 06:32:03 +0300 Subject: [PATCH 0084/1439] REFACTOR: site controller specs to requests --- spec/{controllers => requests}/site_controller_spec.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) rename spec/{controllers => requests}/site_controller_spec.rb (95%) diff --git a/spec/controllers/site_controller_spec.rb b/spec/requests/site_controller_spec.rb similarity index 95% rename from spec/controllers/site_controller_spec.rb rename to spec/requests/site_controller_spec.rb index 78d2b8d493..d57ca36da8 100644 --- a/spec/controllers/site_controller_spec.rb +++ b/spec/requests/site_controller_spec.rb @@ -2,7 +2,6 @@ require 'rails_helper' describe SiteController do describe '.basic_info' do - it 'is visible always even for sites requiring login' do SiteSetting.login_required = true @@ -13,7 +12,7 @@ describe SiteController do SiteSetting.apple_touch_icon_url = "https://boom.com/apple/logo.png" SiteSetting.mobile_logo_url = "https://a.a/a.png" - get :basic_info, format: :json + get "/site/basic-info.json" json = JSON.parse(response.body) expect(json["title"]).to eq("Hammer Time") @@ -26,12 +25,11 @@ describe SiteController do end describe '.statistics' do - it 'is visible for sites requiring login' do SiteSetting.login_required = true SiteSetting.share_anonymized_statistics = true - get :statistics, format: :json + get "/site/statistics.json" json = JSON.parse(response.body) expect(response).to be_successful @@ -54,7 +52,7 @@ describe SiteController do it 'is not visible if site setting share_anonymized_statistics is disabled' do SiteSetting.share_anonymized_statistics = false - get :statistics, format: :json + get "/site/statistics.json" expect(response).to redirect_to '/' end end From a8d33603f9f34de9d001cbe3156fb2a6b4725bc9 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 06:46:04 +0300 Subject: [PATCH 0085/1439] REFACTOR: export CSV controller specs to requests --- .../controllers/export_csv_controller_spec.rb | 48 -------------- spec/requests/export_csv_controller_spec.rb | 63 +++++++++++++++++++ 2 files changed, 63 insertions(+), 48 deletions(-) delete mode 100644 spec/controllers/export_csv_controller_spec.rb create mode 100644 spec/requests/export_csv_controller_spec.rb diff --git a/spec/controllers/export_csv_controller_spec.rb b/spec/controllers/export_csv_controller_spec.rb deleted file mode 100644 index d79c06875a..0000000000 --- a/spec/controllers/export_csv_controller_spec.rb +++ /dev/null @@ -1,48 +0,0 @@ -require "rails_helper" - -describe ExportCsvController do - let(:export_filename) { "user-archive-codinghorror-150115-234817-999.csv.gz" } - - context "while logged in as normal user" do - before { @user = log_in(:user) } - - describe ".export_entity" do - it "enqueues export job" do - Jobs.expects(:enqueue).with(:export_csv_file, has_entries(entity: "user_archive", user_id: @user.id)) - post :export_entity, params: { entity: "user_archive" }, format: :json - expect(response).to be_successful - end - - it "should not enqueue export job if rate limit is reached" do - Jobs::ExportCsvFile.any_instance.expects(:execute).never - UserExport.create(file_name: "user-archive-codinghorror-150116-003249", user_id: @user.id) - post :export_entity, params: { entity: "user_archive" }, format: :json - expect(response).not_to be_successful - end - - it "returns 404 when normal user tries to export admin entity" do - post :export_entity, params: { entity: "staff_action" }, format: :json - expect(response).not_to be_successful - end - end - end - - context "while logged in as an admin" do - before { @admin = log_in(:admin) } - - describe ".export_entity" do - it "enqueues export job" do - Jobs.expects(:enqueue).with(:export_csv_file, has_entries(entity: "staff_action", user_id: @admin.id)) - post :export_entity, params: { entity: "staff_action" }, format: :json - expect(response).to be_successful - end - - it "should not rate limit export for staff" do - Jobs.expects(:enqueue).with(:export_csv_file, has_entries(entity: "staff_action", user_id: @admin.id)) - UserExport.create(file_name: "screened-email-150116-010145", user_id: @admin.id) - post :export_entity, params: { entity: "staff_action" }, format: :json - expect(response).to be_successful - end - end - end -end diff --git a/spec/requests/export_csv_controller_spec.rb b/spec/requests/export_csv_controller_spec.rb new file mode 100644 index 0000000000..cc84bd0403 --- /dev/null +++ b/spec/requests/export_csv_controller_spec.rb @@ -0,0 +1,63 @@ +require "rails_helper" + +describe ExportCsvController do + let(:export_filename) { "user-archive-codinghorror-150115-234817-999.csv.gz" } + + context "while logged in as normal user" do + let(:user) { Fabricate(:user) } + before { sign_in(user) } + + describe ".export_entity" do + it "enqueues export job" do + post "/export_csv/export_entity.json", params: { entity: "user_archive" } + expect(response).to be_success + expect(Jobs::ExportCsvFile.jobs.size).to eq(1) + + job_data = Jobs::ExportCsvFile.jobs.first["args"].first + expect(job_data["entity"]).to eq("user_archive") + expect(job_data["user_id"]).to eq(user.id) + end + + it "should not enqueue export job if rate limit is reached" do + UserExport.create(file_name: "user-archive-codinghorror-150116-003249", user_id: user.id) + post "/export_csv/export_entity.json", params: { entity: "user_archive" } + expect(response).to be_forbidden + expect(Jobs::ExportCsvFile.jobs.size).to eq(0) + end + + it "returns 404 when normal user tries to export admin entity" do + post "/export_csv/export_entity.json", params: { entity: "staff_action" } + expect(response).to be_forbidden + expect(Jobs::ExportCsvFile.jobs.size).to eq(0) + end + end + end + + context "while logged in as an admin" do + let(:admin) { Fabricate(:admin) } + before { sign_in(admin) } + + describe ".export_entity" do + it "enqueues export job" do + post "/export_csv/export_entity.json", params: { entity: "staff_action" } + expect(response).to be_success + expect(Jobs::ExportCsvFile.jobs.size).to eq(1) + + job_data = Jobs::ExportCsvFile.jobs.first["args"].first + expect(job_data["entity"]).to eq("staff_action") + expect(job_data["user_id"]).to eq(admin.id) + end + + it "should not rate limit export for staff" do + UserExport.create(file_name: "screened-email-150116-010145", user_id: admin.id) + post "/export_csv/export_entity.json", params: { entity: "staff_action" } + expect(response).to be_success + expect(Jobs::ExportCsvFile.jobs.size).to eq(1) + + job_data = Jobs::ExportCsvFile.jobs.first["args"].first + expect(job_data["entity"]).to eq("staff_action") + expect(job_data["user_id"]).to eq(admin.id) + end + end + end +end From 37829a521a21bace42cd079044871a316e65bf0d Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 06:53:53 +0300 Subject: [PATCH 0086/1439] REFACTOR: stylesheets controller specs to requests --- .../stylesheets_controller_spec.rb | 36 +++++++------------ 1 file changed, 12 insertions(+), 24 deletions(-) rename spec/{controllers => requests}/stylesheets_controller_spec.rb (57%) diff --git a/spec/controllers/stylesheets_controller_spec.rb b/spec/requests/stylesheets_controller_spec.rb similarity index 57% rename from spec/controllers/stylesheets_controller_spec.rb rename to spec/requests/stylesheets_controller_spec.rb index 67f432f95b..d33961fa75 100644 --- a/spec/controllers/stylesheets_controller_spec.rb +++ b/spec/requests/stylesheets_controller_spec.rb @@ -1,9 +1,7 @@ require 'rails_helper' describe StylesheetsController do - it 'can survive cache miss' do - StylesheetCache.destroy_all builder = Stylesheet::Manager.new('desktop_rtl', nil) builder.compile @@ -11,8 +9,8 @@ describe StylesheetsController do digest = StylesheetCache.first.digest StylesheetCache.destroy_all - get :show, params: { name: "desktop_rtl_#{digest}" }, format: :json - expect(response).to be_successful + get "/stylesheets/desktop_rtl_#{digest}.css" + expect(response.status).to eq(200) cached = StylesheetCache.first expect(cached.target).to eq 'desktop_rtl' @@ -21,11 +19,10 @@ describe StylesheetsController do # tmp folder destruction and cached `rm #{Stylesheet::Manager.cache_fullpath}/*` - get :show, params: { name: "desktop_rtl_#{digest}" }, format: :json - expect(response).to be_successful + get "/stylesheets/desktop_rtl_#{digest}.css" + expect(response.status).to eq(200) # there is an edge case which is ... disk and db cache is nuked, very unlikely to happen - end it 'can lookup theme specific css' do @@ -37,34 +34,25 @@ describe StylesheetsController do `rm #{Stylesheet::Manager.cache_fullpath}/*` - get :show, params: { - name: builder.stylesheet_filename.sub(".css", "") - }, format: :json + get "/stylesheets/#{builder.stylesheet_filename.sub(".css", "")}.css" - expect(response).to be_successful + expect(response.status).to eq(200) - get :show, params: { - name: builder.stylesheet_filename_no_digest.sub(".css", "") - }, format: :json + get "/stylesheets/#{builder.stylesheet_filename_no_digest.sub(".css", "")}.css" - expect(response).to be_successful + expect(response.status).to eq(200) builder = Stylesheet::Manager.new(:desktop_theme, theme.key) builder.compile `rm #{Stylesheet::Manager.cache_fullpath}/*` - get :show, params: { - name: builder.stylesheet_filename.sub(".css", "") - }, format: :json + get "/stylesheets/#{builder.stylesheet_filename.sub(".css", "")}.css" - expect(response).to be_successful + expect(response.status).to eq(200) - get :show, params: { - name: builder.stylesheet_filename_no_digest.sub(".css", "") - }, format: :json + get "/stylesheets/#{builder.stylesheet_filename_no_digest.sub(".css", "")}.css" - expect(response).to be_successful + expect(response.status).to eq(200) end - end From f2a5a84f0bdae32a52e7a225d5edc26abd02c5b5 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 08:07:53 +0300 Subject: [PATCH 0087/1439] REFACTOR: similar topics controller specs to requests (#5933) --- .../similar_topics_controller_spec.rb | 61 ------------- .../similar_topics_controller_spec.rb | 91 +++++++++++++++++++ 2 files changed, 91 insertions(+), 61 deletions(-) delete mode 100644 spec/controllers/similar_topics_controller_spec.rb create mode 100644 spec/requests/similar_topics_controller_spec.rb diff --git a/spec/controllers/similar_topics_controller_spec.rb b/spec/controllers/similar_topics_controller_spec.rb deleted file mode 100644 index f7dad39562..0000000000 --- a/spec/controllers/similar_topics_controller_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'rails_helper' - -describe SimilarTopicsController do - context 'similar_to' do - - let(:title) { 'this title is long enough to search for' } - let(:raw) { 'this body is long enough to search for' } - - it "requires a title" do - expect do - get :index, params: { raw: raw }, format: :json - end.to raise_error(ActionController::ParameterMissing) - end - - it "returns no results if the title length is below the minimum" do - Topic.expects(:similar_to).never - SiteSetting.min_title_similar_length = 100 - get :index, params: { title: title, raw: raw }, format: :json - json = ::JSON.parse(response.body) - expect(json["similar_topics"].size).to eq(0) - end - - describe "minimum_topics_similar" do - - before do - SiteSetting.minimum_topics_similar = 30 - end - - after do - get :index, params: { title: title, raw: raw }, format: :json - end - - describe "With enough topics" do - before do - Topic.stubs(:count).returns(50) - end - - it "deletes to Topic.similar_to if there are more topics than `minimum_topics_similar`" do - Topic.expects(:similar_to).with(title, raw, nil).returns([Fabricate(:topic)]) - end - - describe "with a logged in user" do - let(:user) { log_in } - - it "passes a user through if logged in" do - Topic.expects(:similar_to).with(title, raw, user).returns([Fabricate(:topic)]) - end - end - - end - - it "does not call Topic.similar_to if there are fewer topics than `minimum_topics_similar`" do - Topic.stubs(:count).returns(10) - Topic.expects(:similar_to).never - end - - end - - end - -end diff --git a/spec/requests/similar_topics_controller_spec.rb b/spec/requests/similar_topics_controller_spec.rb new file mode 100644 index 0000000000..d6692bab3f --- /dev/null +++ b/spec/requests/similar_topics_controller_spec.rb @@ -0,0 +1,91 @@ +require 'rails_helper' + +describe SimilarTopicsController do + context 'similar_to' do + let(:title) { 'this title is long enough to search for' } + let(:raw) { 'this body is long enough to search for' } + + let(:topic) { Fabricate(:topic, title: title) } + let(:post) { Fabricate(:post, topic: topic, raw: raw, post_number: 1) } + + let(:private_post) { Fabricate(:post, raw: raw, topic: private_topic, post_number: 1) } + let(:private_topic) do + Fabricate(:topic, title: "#{title} 02", category: Fabricate(:private_category, group: Group[:staff])) + end + + def reindex_posts + SearchIndexer.enable + Jobs::ReindexSearch.new.rebuild_problem_posts + end + + it "requires a title param" do + get "/topics/similar_to.json", params: { raw: raw } + expect(response.status).to eq(400) + end + + it "returns no results if the title length is below the minimum" do + SiteSetting.minimum_topics_similar = 0 + SiteSetting.min_title_similar_length = 100 + post + reindex_posts + + get "/topics/similar_to.json", params: { title: title, raw: raw } + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["similar_topics"].size).to eq(0) + end + + describe "minimum_topics_similar" do + before do + SiteSetting.minimum_topics_similar = 30 + end + + describe "With enough topics" do + it "deletes to Topic.similar_to if there are more topics than `minimum_topics_similar`" do + Topic.stubs(:count).returns(50) + post + reindex_posts + + get "/topics/similar_to.json", params: { title: title, raw: raw } + + expect(response).to be_success + similar_topics = ::JSON.parse(response.body)["similar_topics"] + expect(similar_topics.size).to eq(1) + expect(similar_topics.first["topic_id"]).to eq(topic.id) + end + + describe "with a logged in user" do + before do + private_post; post + reindex_posts + Topic.stubs(:count).returns(50) + sign_in(Fabricate(:moderator)) + Group.refresh_automatic_groups! + end + + it "passes a user through if logged in" do + get "/topics/similar_to.json", params: { title: title, raw: raw } + + expect(response).to be_success + similar_topics = ::JSON.parse(response.body)["similar_topics"].map { |topic| topic["topic_id"] } + expect(similar_topics.size).to eq(2) + expect(similar_topics).to include(topic.id) + expect(similar_topics).to include(private_topic.id) + end + end + end + + it "does not call Topic.similar_to if there are fewer topics than `minimum_topics_similar`" do + Topic.stubs(:count).returns(10) + post + reindex_posts + + get "/topics/similar_to.json", params: { title: title, raw: raw } + + expect(response).to be_success + json = ::JSON.parse(response.body) + expect(json["similar_topics"].size).to eq(0) + end + end + end +end From 1957cb541bee591ec86d846ed6e6fad182057ea7 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 08:08:13 +0300 Subject: [PATCH 0088/1439] REFACTOR: permalinks controller specs to requests (#5934) --- .../permalinks_controller_spec.rb | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) rename spec/{controllers => requests}/permalinks_controller_spec.rb (53%) diff --git a/spec/controllers/permalinks_controller_spec.rb b/spec/requests/permalinks_controller_spec.rb similarity index 53% rename from spec/controllers/permalinks_controller_spec.rb rename to spec/requests/permalinks_controller_spec.rb index 595571f9bd..b172315c63 100644 --- a/spec/controllers/permalinks_controller_spec.rb +++ b/spec/requests/permalinks_controller_spec.rb @@ -1,46 +1,49 @@ require 'rails_helper' describe PermalinksController do + let(:topic) { Fabricate(:topic) } + let(:permalink) { Fabricate(:permalink, url: "deadroutee/topic/546") } + describe 'show' do it "should redirect to a permalink's target_url with status 301" do - permalink = Fabricate(:permalink) - Permalink.any_instance.stubs(:target_url).returns('/t/the-topic-slug/42') - get :show, params: { url: permalink.url } - expect(response).to redirect_to('/t/the-topic-slug/42') + permalink.update!(topic_id: topic.id) + + get "/#{permalink.url}" + + expect(response).to redirect_to(topic.relative_url) expect(response.status).to eq(301) end it "should work for subfolder installs too" do + permalink.update!(topic_id: topic.id) GlobalSetting.stubs(:relative_url_root).returns('/forum') Discourse.stubs(:base_uri).returns("/forum") - permalink = Fabricate(:permalink) - Permalink.any_instance.stubs(:target_url).returns('/forum/t/the-topic-slug/42') - get :show, params: { url: permalink.url } - expect(response).to redirect_to('/forum/t/the-topic-slug/42') + + get "/#{permalink.url}" + + expect(response).to redirect_to(topic.relative_url) expect(response.status).to eq(301) end it "should apply normalizations" do + permalink.update!(external_url: '/topic/100') SiteSetting.permalink_normalizations = "/(.*)\\?.*/\\1" - permalink = Fabricate(:permalink, url: '/topic/bla', external_url: '/topic/100') - - get :show, params: { url: permalink.url, test: "hello" } + get "/#{permalink.url}", params: { test: "hello" } expect(response).to redirect_to('/topic/100') expect(response.status).to eq(301) SiteSetting.permalink_normalizations = "/(.*)\\?.*/\\1X" - get :show, params: { url: permalink.url, test: "hello" } + get "/#{permalink.url}", params: { test: "hello" } expect(response.status).to eq(404) end it 'return 404 if permalink record does not exist' do - get :show, params: { url: '/not/a/valid/url' } + get '/not/a/valid/url' expect(response.status).to eq(404) end end - end From 9975f9751e01d58dfb940e738bb7eb6ace1aa63d Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 08:08:28 +0300 Subject: [PATCH 0089/1439] REFACTOR: metadata controller specs to requests (#5935) --- .../metadata_controller_spec.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) rename spec/{controllers => requests}/metadata_controller_spec.rb (83%) diff --git a/spec/controllers/metadata_controller_spec.rb b/spec/requests/metadata_controller_spec.rb similarity index 83% rename from spec/controllers/metadata_controller_spec.rb rename to spec/requests/metadata_controller_spec.rb index 96558ec0c7..7018e09c20 100644 --- a/spec/controllers/metadata_controller_spec.rb +++ b/spec/requests/metadata_controller_spec.rb @@ -3,12 +3,12 @@ require 'rails_helper' RSpec.describe MetadataController do describe 'manifest.json' do it 'returns the right output' do - title = 'MyApp' SiteSetting.title = title SiteSetting.large_icon_url = "http://big.square/png" - get :manifest + get "/manifest.json" + expect(response.status).to eq(200) expect(response.content_type).to eq('application/json') manifest = JSON.parse(response.body) @@ -18,14 +18,16 @@ RSpec.describe MetadataController do it 'can guess mime types' do SiteSetting.large_icon_url = "http://big.square/ico.jpg" - get :manifest + get "/manifest.json" + expect(response.status).to eq(200) manifest = JSON.parse(response.body) expect(manifest["icons"].first["type"]).to eq("image/jpeg") end it 'defaults to png' do SiteSetting.large_icon_url = "http://big.square/noidea.bogus" - get :manifest + get "/manifest.json" + expect(response.status).to eq(200) manifest = JSON.parse(response.body) expect(manifest["icons"].first["type"]).to eq("image/png") end @@ -37,7 +39,8 @@ RSpec.describe MetadataController do favicon_path = '/uploads/something/23432.png' SiteSetting.title = title SiteSetting.favicon_url = favicon_path - get :opensearch, format: :xml + get "/opensearch.xml" + expect(response.status).to eq(200) expect(response.body).to include(title) expect(response.body).to include("/search?q={searchTerms}") expect(response.body).to include('image/png') From 30be1b0d2bb17287efd0d2e52bd2036c7e4089b4 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 08:09:23 +0300 Subject: [PATCH 0090/1439] REFACTOR: category hashtags controller specs to requests (#5936) --- .../category_hashtags_controller_spec.rb | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) rename spec/{controllers => requests}/category_hashtags_controller_spec.rb (66%) diff --git a/spec/controllers/category_hashtags_controller_spec.rb b/spec/requests/category_hashtags_controller_spec.rb similarity index 66% rename from spec/controllers/category_hashtags_controller_spec.rb rename to spec/requests/category_hashtags_controller_spec.rb index f177811df2..c638d82ede 100644 --- a/spec/controllers/category_hashtags_controller_spec.rb +++ b/spec/requests/category_hashtags_controller_spec.rb @@ -4,14 +4,15 @@ describe CategoryHashtagsController do describe "check" do describe "logged in" do before do - log_in(:user) + sign_in(Fabricate(:user)) end it 'only returns the categories that are valid' do category = Fabricate(:category) - get :check, params: { category_slugs: [category.slug, 'none'] }, format: :json + get "/category_hashtags/check.json", params: { category_slugs: [category.slug, 'none'] } + expect(response.status).to eq(200) expect(JSON.parse(response.body)).to eq( "valid" => [{ "slug" => category.hashtag_slug, "url" => category.url_with_id }] ) @@ -21,21 +22,22 @@ describe CategoryHashtagsController do group = Fabricate(:group) private_category = Fabricate(:private_category, group: group) - get :check, params: { category_slugs: [private_category.slug] }, format: :json + get "/category_hashtags/check.json", params: { category_slugs: [private_category.slug] } + expect(response.status).to eq(200) expect(JSON.parse(response.body)).to eq("valid" => []) end it 'returns restricted categories for an admin' do - admin = log_in(:admin) + admin = sign_in(Fabricate(:admin)) group = Fabricate(:group) group.add(admin) private_category = Fabricate(:private_category, group: group) - get :check, - params: { category_slugs: [private_category.slug] }, - format: :json + get "/category_hashtags/check.json", + params: { category_slugs: [private_category.slug] } + expect(response.status).to eq(200) expect(JSON.parse(response.body)).to eq( "valid" => [{ "slug" => private_category.hashtag_slug, "url" => private_category.url_with_id }] ) @@ -44,7 +46,7 @@ describe CategoryHashtagsController do describe "not logged in" do it 'raises an exception' do - get :check, params: { category_slugs: [] }, format: :json + get "/category_hashtags/check.json", params: { category_slugs: [] } expect(response.status).to eq(403) end end From c6c1ef71c113f483e4c60bb44cac22d6e429f171 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Wed, 6 Jun 2018 12:10:59 +0300 Subject: [PATCH 0091/1439] REFACTOR: inline onebox controller specs to requests --- .../inline_onebox_controller_spec.rb | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) rename spec/{controllers => requests}/inline_onebox_controller_spec.rb (69%) diff --git a/spec/controllers/inline_onebox_controller_spec.rb b/spec/requests/inline_onebox_controller_spec.rb similarity index 69% rename from spec/controllers/inline_onebox_controller_spec.rb rename to spec/requests/inline_onebox_controller_spec.rb index 880c69fd98..c46835c82c 100644 --- a/spec/controllers/inline_onebox_controller_spec.rb +++ b/spec/requests/inline_onebox_controller_spec.rb @@ -3,16 +3,16 @@ require 'rails_helper' describe InlineOneboxController do it "requires the user to be logged in" do - get :show, params: { urls: [] }, format: :json + get "/inline-onebox.json", params: { urls: [] } expect(response.status).to eq(403) end context "logged in" do - let!(:user) { log_in(:user) } + let!(:user) { sign_in(Fabricate(:user)) } it "returns empty JSON for empty input" do - get :show, params: { urls: [] }, format: :json - expect(response).to be_successful + get "/inline-onebox.json", params: { urls: [] } + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json['inline-oneboxes']).to eq([]) end @@ -21,8 +21,8 @@ describe InlineOneboxController do let(:topic) { Fabricate(:topic) } it "returns information for a valid link" do - get :show, params: { urls: [ topic.url ] }, format: :json - expect(response).to be_successful + get "/inline-onebox.json", params: { urls: [ topic.url ] } + expect(response.status).to eq(200) json = JSON.parse(response.body) onebox = json['inline-oneboxes'][0] @@ -31,7 +31,5 @@ describe InlineOneboxController do expect(onebox['title']).to eq(topic.title) end end - end - end From ad5082d969ab1f60b5c5b1e89a616117906289f8 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 13:28:18 +0800 Subject: [PATCH 0092/1439] Make rubocop happy again. --- app/controllers/admin/badges_controller.rb | 68 +- .../admin/embeddable_hosts_controller.rb | 22 +- app/controllers/admin/embedding_controller.rb | 6 +- .../admin/screened_ip_addresses_controller.rb | 14 +- .../admin/site_texts_controller.rb | 24 +- app/controllers/admin/themes_controller.rb | 86 +- .../admin/user_fields_controller.rb | 12 +- app/controllers/admin/users_controller.rb | 46 +- app/controllers/application_controller.rb | 440 ++++----- app/controllers/categories_controller.rb | 184 ++-- app/controllers/clicks_controller.rb | 8 +- app/controllers/embed_controller.rb | 36 +- app/controllers/exceptions_controller.rb | 6 +- app/controllers/export_csv_controller.rb | 10 +- .../finish_installation_controller.rb | 24 +- app/controllers/invites_controller.rb | 16 +- app/controllers/notifications_controller.rb | 18 +- app/controllers/post_actions_controller.rb | 46 +- app/controllers/queued_posts_controller.rb | 22 +- app/controllers/stylesheets_controller.rb | 10 +- app/controllers/tag_groups_controller.rb | 42 +- app/controllers/tags_controller.rb | 222 ++--- app/controllers/user_badges_controller.rb | 40 +- app/controllers/users_controller.rb | 186 ++-- app/controllers/webhooks_controller.rb | 38 +- app/jobs/regular/export_csv_file.rb | 298 +++--- app/jobs/regular/pull_hotlinked_images.rb | 6 +- app/models/badge.rb | 12 +- app/models/category_list.rb | 192 ++-- app/models/concerns/trashable.rb | 6 +- app/models/embeddable_host.rb | 12 +- app/models/group.rb | 172 ++-- app/models/group_archived_message.rb | 10 +- app/models/post_analyzer.rb | 24 +- app/models/queued_post.rb | 38 +- app/models/topic_featured_users.rb | 8 +- app/models/topic_timer.rb | 94 +- app/models/unsubscribe_key.rb | 6 +- app/models/user_archived_message.rb | 10 +- app/models/user_badge.rb | 6 +- app/models/user_option.rb | 8 +- app/models/web_hook.rb | 6 +- .../admin_user_action_serializer.rb | 14 +- app/serializers/basic_group_serializer.rb | 18 +- app/serializers/listable_topic_serializer.rb | 6 +- .../post_action_type_serializer.rb | 8 +- app/serializers/post_revision_serializer.rb | 152 ++-- app/serializers/post_serializer.rb | 34 +- app/serializers/topic_flag_type_serializer.rb | 8 +- app/serializers/topic_view_serializer.rb | 6 +- app/services/group_action_logger.rb | 28 +- app/services/staff_action_logger.rb | 14 +- app/services/user_anonymizer.rb | 12 +- lib/auth/facebook_authenticator.rb | 90 +- lib/auth/twitter_authenticator.rb | 34 +- lib/common_passwords/common_passwords.rb | 42 +- lib/composer_messages_finder.rb | 26 +- lib/email_updater.rb | 26 +- lib/file_helper.rb | 12 +- lib/flag_query.rb | 16 +- lib/freedom_patches/rack_patches.rb | 54 +- lib/i18n/backend/discourse_i18n.rb | 70 +- lib/i18n/duplicate_key_finder.rb | 8 +- lib/inline_oneboxer.rb | 26 +- .../engine/whitelisted_generic_onebox.rb | 24 +- lib/oneboxer.rb | 258 +++--- lib/retrieve_title.rb | 48 +- lib/search.rb | 730 +++++++-------- lib/topic_query.rb | 852 +++++++++--------- lib/topic_retriever.rb | 68 +- lib/topics_bulk_action.rb | 254 +++--- lib/validators/censored_words_validator.rb | 34 +- .../pop3_polling_enabled_setting_validator.rb | 20 +- .../topic_title_length_validator.rb | 22 +- .../certificate_generator.rb | 62 +- .../quandora/quandora_question.rb | 176 ++-- .../socialcast/socialcast_message.rb | 132 +-- .../socialcast/socialcast_user.rb | 22 +- script/import_scripts/vanilla.rb | 370 ++++---- 79 files changed, 3155 insertions(+), 3155 deletions(-) diff --git a/app/controllers/admin/badges_controller.rb b/app/controllers/admin/badges_controller.rb index 53089c8e51..e54860d085 100644 --- a/app/controllers/admin/badges_controller.rb +++ b/app/controllers/admin/badges_controller.rb @@ -88,44 +88,44 @@ class Admin::BadgesController < Admin::AdminController end private - def find_badge - params.require(:id) - Badge.find(params[:id]) - end + def find_badge + params.require(:id) + Badge.find(params[:id]) + end - # Options: - # :new - reset the badge id to nil before saving - def update_badge_from_params(badge, opts = {}) - errors = [] - Badge.transaction do - allowed = Badge.column_names.map(&:to_sym) - allowed -= [:id, :created_at, :updated_at, :grant_count] - allowed -= Badge.protected_system_fields if badge.system? - allowed -= [:query] unless SiteSetting.enable_badge_sql + # Options: + # :new - reset the badge id to nil before saving + def update_badge_from_params(badge, opts = {}) + errors = [] + Badge.transaction do + allowed = Badge.column_names.map(&:to_sym) + allowed -= [:id, :created_at, :updated_at, :grant_count] + allowed -= Badge.protected_system_fields if badge.system? + allowed -= [:query] unless SiteSetting.enable_badge_sql - params.permit(*allowed) + params.permit(*allowed) - allowed.each do |key| - badge.send("#{key}=" , params[key]) if params[key] - end - - # Badge query contract checks - begin - if SiteSetting.enable_badge_sql - BadgeGranter.contract_checks!(badge.query, target_posts: badge.target_posts, trigger: badge.trigger) - end - rescue => e - errors << e.message - raise ActiveRecord::Rollback - end - - badge.id = nil if opts[:new] - badge.save! + allowed.each do |key| + badge.send("#{key}=" , params[key]) if params[key] end - errors - rescue ActiveRecord::RecordInvalid - errors.push(*badge.errors.full_messages) - errors + # Badge query contract checks + begin + if SiteSetting.enable_badge_sql + BadgeGranter.contract_checks!(badge.query, target_posts: badge.target_posts, trigger: badge.trigger) + end + rescue => e + errors << e.message + raise ActiveRecord::Rollback + end + + badge.id = nil if opts[:new] + badge.save! end + + errors + rescue ActiveRecord::RecordInvalid + errors.push(*badge.errors.full_messages) + errors + end end diff --git a/app/controllers/admin/embeddable_hosts_controller.rb b/app/controllers/admin/embeddable_hosts_controller.rb index 667db524fe..e70061f0c2 100644 --- a/app/controllers/admin/embeddable_hosts_controller.rb +++ b/app/controllers/admin/embeddable_hosts_controller.rb @@ -17,18 +17,18 @@ class Admin::EmbeddableHostsController < Admin::AdminController protected - def save_host(host) - host.host = params[:embeddable_host][:host] - host.path_whitelist = params[:embeddable_host][:path_whitelist] - host.class_name = params[:embeddable_host][:class_name] - host.category_id = params[:embeddable_host][:category_id] - host.category_id = SiteSetting.uncategorized_category_id if host.category_id.blank? + def save_host(host) + host.host = params[:embeddable_host][:host] + host.path_whitelist = params[:embeddable_host][:path_whitelist] + host.class_name = params[:embeddable_host][:class_name] + host.category_id = params[:embeddable_host][:category_id] + host.category_id = SiteSetting.uncategorized_category_id if host.category_id.blank? - if host.save - render_serialized(host, EmbeddableHostSerializer, root: 'embeddable_host', rest_serializer: true) - else - render_json_error(host) - end + if host.save + render_serialized(host, EmbeddableHostSerializer, root: 'embeddable_host', rest_serializer: true) + else + render_json_error(host) end + end end diff --git a/app/controllers/admin/embedding_controller.rb b/app/controllers/admin/embedding_controller.rb index ebac31e576..8f86a9a22d 100644 --- a/app/controllers/admin/embedding_controller.rb +++ b/app/controllers/admin/embedding_controller.rb @@ -27,7 +27,7 @@ class Admin::EmbeddingController < Admin::AdminController protected - def fetch_embedding - @embedding = Embedding.find - end + def fetch_embedding + @embedding = Embedding.find + end end diff --git a/app/controllers/admin/screened_ip_addresses_controller.rb b/app/controllers/admin/screened_ip_addresses_controller.rb index 775f115195..6e92777233 100644 --- a/app/controllers/admin/screened_ip_addresses_controller.rb +++ b/app/controllers/admin/screened_ip_addresses_controller.rb @@ -51,13 +51,13 @@ class Admin::ScreenedIpAddressesController < Admin::AdminController private - def allowed_params - params.require(:ip_address) - params.permit(:ip_address, :action_name) - end + def allowed_params + params.require(:ip_address) + params.permit(:ip_address, :action_name) + end - def fetch_screened_ip_address - @screened_ip_address = ScreenedIpAddress.find(params[:id]) - end + def fetch_screened_ip_address + @screened_ip_address = ScreenedIpAddress.find(params[:id]) + end end diff --git a/app/controllers/admin/site_texts_controller.rb b/app/controllers/admin/site_texts_controller.rb index 33e636926d..ffc3633203 100644 --- a/app/controllers/admin/site_texts_controller.rb +++ b/app/controllers/admin/site_texts_controller.rb @@ -75,19 +75,19 @@ class Admin::SiteTextsController < Admin::AdminController protected - def record_for(k, value = nil) - if k.ends_with?("_MF") - ovr = TranslationOverride.where(translation_key: k, locale: I18n.locale).pluck(:value) - value = ovr[0] if ovr.present? - end - - value ||= I18n.t(k) - { id: k, value: value } + def record_for(k, value = nil) + if k.ends_with?("_MF") + ovr = TranslationOverride.where(translation_key: k, locale: I18n.locale).pluck(:value) + value = ovr[0] if ovr.present? end - def find_site_text - raise Discourse::NotFound unless I18n.exists?(params[:id]) && !self.class.restricted_keys.include?(params[:id]) - record_for(params[:id]) - end + value ||= I18n.t(k) + { id: k, value: value } + end + + def find_site_text + raise Discourse::NotFound unless I18n.exists?(params[:id]) && !self.class.restricted_keys.include?(params[:id]) + record_for(params[:id]) + end end diff --git a/app/controllers/admin/themes_controller.rb b/app/controllers/admin/themes_controller.rb index a40ec46998..ebc74980e0 100644 --- a/app/controllers/admin/themes_controller.rb +++ b/app/controllers/admin/themes_controller.rb @@ -223,59 +223,59 @@ class Admin::ThemesController < Admin::AdminController private - def update_default_theme - if theme_params.key?(:default) - is_default = theme_params[:default].to_s == "true" - if @theme.key == SiteSetting.default_theme_key && !is_default - Theme.clear_default! - elsif is_default - @theme.set_default! - end + def update_default_theme + if theme_params.key?(:default) + is_default = theme_params[:default].to_s == "true" + if @theme.key == SiteSetting.default_theme_key && !is_default + Theme.clear_default! + elsif is_default + @theme.set_default! end end + end - def theme_params - @theme_params ||= - begin - # deep munge is a train wreck, work around it for now - params[:theme][:child_theme_ids] ||= [] if params[:theme].key?(:child_theme_ids) + def theme_params + @theme_params ||= + begin + # deep munge is a train wreck, work around it for now + params[:theme][:child_theme_ids] ||= [] if params[:theme].key?(:child_theme_ids) - params.require(:theme).permit( - :name, - :color_scheme_id, - :default, - :user_selectable, - settings: {}, - theme_fields: [:name, :target, :value, :upload_id, :type_id], - child_theme_ids: [] - ) - end - end - - def set_fields - return unless fields = theme_params[:theme_fields] - - fields.each do |field| - @theme.set_field( - target: field[:target], - name: field[:name], - value: field[:value], - type_id: field[:type_id], - upload_id: field[:upload_id] + params.require(:theme).permit( + :name, + :color_scheme_id, + :default, + :user_selectable, + settings: {}, + theme_fields: [:name, :target, :value, :upload_id, :type_id], + child_theme_ids: [] ) end - end + end - def update_settings - return unless target_settings = theme_params[:settings] + def set_fields + return unless fields = theme_params[:theme_fields] - target_settings.each_pair do |setting_name, new_value| - @theme.update_setting(setting_name.to_sym, new_value) - end + fields.each do |field| + @theme.set_field( + target: field[:target], + name: field[:name], + value: field[:value], + type_id: field[:type_id], + upload_id: field[:upload_id] + ) end + end - def log_theme_change(old_record, new_record) - StaffActionLogger.new(current_user).log_theme_change(old_record, new_record) + def update_settings + return unless target_settings = theme_params[:settings] + + target_settings.each_pair do |setting_name, new_value| + @theme.update_setting(setting_name.to_sym, new_value) end + end + + def log_theme_change(old_record, new_record) + StaffActionLogger.new(current_user).log_theme_change(old_record, new_record) + end end diff --git a/app/controllers/admin/user_fields_controller.rb b/app/controllers/admin/user_fields_controller.rb index 2af8832e33..4ac32bb911 100644 --- a/app/controllers/admin/user_fields_controller.rb +++ b/app/controllers/admin/user_fields_controller.rb @@ -47,11 +47,11 @@ class Admin::UserFieldsController < Admin::AdminController protected - def update_options(field) - options = params[:user_field][:options] - if options.present? - UserFieldOption.where(user_field_id: field.id).delete_all - field.user_field_options_attributes = options.map { |o| { value: o } }.uniq - end + def update_options(field) + options = params[:user_field][:options] + if options.present? + UserFieldOption.where(user_field_id: field.id).delete_all + field.user_field_options_attributes = options.map { |o| { value: o } }.uniq end + end end diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 7b7f42096c..66b5daf926 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -544,34 +544,34 @@ class Admin::UsersController < Admin::AdminController private - def perform_post_action - return unless params[:post_id].present? && - params[:post_action].present? + def perform_post_action + return unless params[:post_id].present? && + params[:post_action].present? - if post = Post.where(id: params[:post_id]).first - case params[:post_action] - when 'delete' - PostDestroyer.new(current_user, post).destroy - when 'edit' - revisor = PostRevisor.new(post) + if post = Post.where(id: params[:post_id]).first + case params[:post_action] + when 'delete' + PostDestroyer.new(current_user, post).destroy + when 'edit' + revisor = PostRevisor.new(post) - # Take what the moderator edited in as gospel - revisor.revise!( - current_user, - { raw: params[:post_edit] }, - skip_validations: true, - skip_revision: true - ) - end + # Take what the moderator edited in as gospel + revisor.revise!( + current_user, + { raw: params[:post_edit] }, + skip_validations: true, + skip_revision: true + ) end end + end - def fetch_user - @user = User.find_by(id: params[:user_id]) - end + def fetch_user + @user = User.find_by(id: params[:user_id]) + end - def refresh_browser(user) - MessageBus.publish "/file-change", ["refresh"], user_ids: [user.id] - end + def refresh_browser(user) + MessageBus.publish "/file-change", ["refresh"], user_ids: [user.id] + end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d75e4152c8..b9929a9e28 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -462,255 +462,255 @@ class ApplicationController < ActionController::Base private - def check_readonly_mode - @readonly_mode = Discourse.readonly_mode? + def check_readonly_mode + @readonly_mode = Discourse.readonly_mode? + end + + def locale_from_header + begin + # Rails I18n uses underscores between the locale and the region; the request + # headers use hyphens. + require 'http_accept_language' unless defined? HttpAcceptLanguage + available_locales = I18n.available_locales.map { |locale| locale.to_s.tr('_', '-') } + parser = HttpAcceptLanguage::Parser.new(request.env["HTTP_ACCEPT_LANGUAGE"]) + parser.language_region_compatible_from(available_locales).tr('-', '_') + rescue + # If Accept-Language headers are not set. + I18n.default_locale end + end - def locale_from_header - begin - # Rails I18n uses underscores between the locale and the region; the request - # headers use hyphens. - require 'http_accept_language' unless defined? HttpAcceptLanguage - available_locales = I18n.available_locales.map { |locale| locale.to_s.tr('_', '-') } - parser = HttpAcceptLanguage::Parser.new(request.env["HTTP_ACCEPT_LANGUAGE"]) - parser.language_region_compatible_from(available_locales).tr('-', '_') - rescue - # If Accept-Language headers are not set. - I18n.default_locale - end - end + def preload_anonymous_data + store_preloaded("site", Site.json_for(guardian)) + store_preloaded("siteSettings", SiteSetting.client_settings_json) + store_preloaded("themeSettings", Theme.settings_for_client(@theme_key)) + store_preloaded("customHTML", custom_html_json) + store_preloaded("banner", banner_json) + store_preloaded("customEmoji", custom_emoji) + store_preloaded("translationOverrides", I18n.client_overrides_json(I18n.locale)) + end - def preload_anonymous_data - store_preloaded("site", Site.json_for(guardian)) - store_preloaded("siteSettings", SiteSetting.client_settings_json) - store_preloaded("themeSettings", Theme.settings_for_client(@theme_key)) - store_preloaded("customHTML", custom_html_json) - store_preloaded("banner", banner_json) - store_preloaded("customEmoji", custom_emoji) - store_preloaded("translationOverrides", I18n.client_overrides_json(I18n.locale)) - end + def preload_current_user_data + store_preloaded("currentUser", MultiJson.dump(CurrentUserSerializer.new(current_user, scope: guardian, root: false))) + report = TopicTrackingState.report(current_user) + serializer = ActiveModel::ArraySerializer.new(report, each_serializer: TopicTrackingStateSerializer) + store_preloaded("topicTrackingStates", MultiJson.dump(serializer)) + end - def preload_current_user_data - store_preloaded("currentUser", MultiJson.dump(CurrentUserSerializer.new(current_user, scope: guardian, root: false))) - report = TopicTrackingState.report(current_user) - serializer = ActiveModel::ArraySerializer.new(report, each_serializer: TopicTrackingStateSerializer) - store_preloaded("topicTrackingStates", MultiJson.dump(serializer)) - end + def custom_html_json + target = view_context.mobile_view? ? :mobile : :desktop - def custom_html_json - target = view_context.mobile_view? ? :mobile : :desktop - - data = - if @theme_key - { - top: Theme.lookup_field(@theme_key, target, "after_header"), - footer: Theme.lookup_field(@theme_key, target, "footer") - } - else - {} - end - - if DiscoursePluginRegistry.custom_html - data.merge! DiscoursePluginRegistry.custom_html - end - - DiscoursePluginRegistry.html_builders.each do |name, _| - if name.start_with?("client:") - data[name.sub(/^client:/, '')] = DiscoursePluginRegistry.build_html(name, self) - end - end - - MultiJson.dump(data) - end - - def self.banner_json_cache - @banner_json_cache ||= DistributedCache.new("banner_json") - end - - def banner_json - json = ApplicationController.banner_json_cache["json"] - - unless json - topic = Topic.where(archetype: Archetype.banner).first - banner = topic.present? ? topic.banner : {} - ApplicationController.banner_json_cache["json"] = json = MultiJson.dump(banner) - end - - json - end - - def custom_emoji - serializer = ActiveModel::ArraySerializer.new(Emoji.custom, each_serializer: EmojiSerializer) - MultiJson.dump(serializer) - end - - # Render action for a JSON error. - # - # obj - a translated string, an ActiveRecord model, or an array of translated strings - # opts: - # type - a machine-readable description of the error - # status - HTTP status code to return - # headers - extra headers for the response - def render_json_error(obj, opts = {}) - opts = { status: opts } if opts.is_a?(Integer) - opts.fetch(:headers, {}).each { |name, value| headers[name.to_s] = value } - - render json: MultiJson.dump(create_errors_json(obj, opts)), status: opts[:status] || 422 - end - - def success_json - { success: 'OK' } - end - - def failed_json - { failed: 'FAILED' } - end - - def json_result(obj, opts = {}) - if yield(obj) - json = success_json - - # If we were given a serializer, add the class to the json that comes back - if opts[:serializer].present? - json[obj.class.name.underscore] = opts[:serializer].new(obj, scope: guardian).serializable_hash - end - - render json: MultiJson.dump(json) + data = + if @theme_key + { + top: Theme.lookup_field(@theme_key, target, "after_header"), + footer: Theme.lookup_field(@theme_key, target, "footer") + } else - error_obj = nil - if opts[:additional_errors] - error_target = opts[:additional_errors].find do |o| - target = obj.send(o) - target && target.errors.present? - end - error_obj = obj.send(error_target) if error_target + {} + end + + if DiscoursePluginRegistry.custom_html + data.merge! DiscoursePluginRegistry.custom_html + end + + DiscoursePluginRegistry.html_builders.each do |name, _| + if name.start_with?("client:") + data[name.sub(/^client:/, '')] = DiscoursePluginRegistry.build_html(name, self) + end + end + + MultiJson.dump(data) + end + + def self.banner_json_cache + @banner_json_cache ||= DistributedCache.new("banner_json") + end + + def banner_json + json = ApplicationController.banner_json_cache["json"] + + unless json + topic = Topic.where(archetype: Archetype.banner).first + banner = topic.present? ? topic.banner : {} + ApplicationController.banner_json_cache["json"] = json = MultiJson.dump(banner) + end + + json + end + + def custom_emoji + serializer = ActiveModel::ArraySerializer.new(Emoji.custom, each_serializer: EmojiSerializer) + MultiJson.dump(serializer) + end + + # Render action for a JSON error. + # + # obj - a translated string, an ActiveRecord model, or an array of translated strings + # opts: + # type - a machine-readable description of the error + # status - HTTP status code to return + # headers - extra headers for the response + def render_json_error(obj, opts = {}) + opts = { status: opts } if opts.is_a?(Integer) + opts.fetch(:headers, {}).each { |name, value| headers[name.to_s] = value } + + render json: MultiJson.dump(create_errors_json(obj, opts)), status: opts[:status] || 422 + end + + def success_json + { success: 'OK' } + end + + def failed_json + { failed: 'FAILED' } + end + + def json_result(obj, opts = {}) + if yield(obj) + json = success_json + + # If we were given a serializer, add the class to the json that comes back + if opts[:serializer].present? + json[obj.class.name.underscore] = opts[:serializer].new(obj, scope: guardian).serializable_hash + end + + render json: MultiJson.dump(json) + else + error_obj = nil + if opts[:additional_errors] + error_target = opts[:additional_errors].find do |o| + target = obj.send(o) + target && target.errors.present? end - render_json_error(error_obj || obj) + error_obj = obj.send(error_target) if error_target end + render_json_error(error_obj || obj) end + end - def mini_profiler_enabled? - defined?(Rack::MiniProfiler) && (guardian.is_developer? || Rails.env.development?) - end + def mini_profiler_enabled? + defined?(Rack::MiniProfiler) && (guardian.is_developer? || Rails.env.development?) + end - def authorize_mini_profiler - return unless mini_profiler_enabled? - Rack::MiniProfiler.authorize_request - end + def authorize_mini_profiler + return unless mini_profiler_enabled? + Rack::MiniProfiler.authorize_request + end - def check_xhr - # bypass xhr check on PUT / POST / DELETE provided api key is there, otherwise calling api is annoying - return if !request.get? && (is_api? || is_user_api?) - raise RenderEmpty.new unless ((request.format && request.format.json?) || request.xhr?) - end + def check_xhr + # bypass xhr check on PUT / POST / DELETE provided api key is there, otherwise calling api is annoying + return if !request.get? && (is_api? || is_user_api?) + raise RenderEmpty.new unless ((request.format && request.format.json?) || request.xhr?) + end - def self.requires_login(arg = {}) - @requires_login_arg = arg - end + def self.requires_login(arg = {}) + @requires_login_arg = arg + end - def self.requires_login_arg - @requires_login_arg - end + def self.requires_login_arg + @requires_login_arg + end - def block_if_requires_login - if arg = self.class.requires_login_arg - check = - if except = arg[:except] - !except.include?(action_name.to_sym) - elsif only = arg[:only] - only.include?(action_name.to_sym) - else - true - end - ensure_logged_in if check - end - end - - def ensure_logged_in - raise Discourse::NotLoggedIn.new unless current_user.present? - end - - def ensure_staff - raise Discourse::InvalidAccess.new unless current_user && current_user.staff? - end - - def ensure_admin - raise Discourse::InvalidAccess.new unless current_user && current_user.admin? - end - - def ensure_wizard_enabled - raise Discourse::InvalidAccess.new unless SiteSetting.wizard_enabled? - end - - def destination_url - request.original_url unless request.original_url =~ /uploads/ - end - - def redirect_to_login_if_required - return if current_user || (request.format.json? && is_api?) - - if SiteSetting.login_required? - flash.keep - - if SiteSetting.enable_sso? - # save original URL in a session so we can redirect after login - session[:destination_url] = destination_url - redirect_to path('/session/sso') - elsif params[:authComplete].present? - redirect_to path("/login?authComplete=true") + def block_if_requires_login + if arg = self.class.requires_login_arg + check = + if except = arg[:except] + !except.include?(action_name.to_sym) + elsif only = arg[:only] + only.include?(action_name.to_sym) else - # save original URL in a cookie (javascript redirects after login in this case) - cookies[:destination_url] = destination_url - redirect_to path("/login") + true end + ensure_logged_in if check + end + end + + def ensure_logged_in + raise Discourse::NotLoggedIn.new unless current_user.present? + end + + def ensure_staff + raise Discourse::InvalidAccess.new unless current_user && current_user.staff? + end + + def ensure_admin + raise Discourse::InvalidAccess.new unless current_user && current_user.admin? + end + + def ensure_wizard_enabled + raise Discourse::InvalidAccess.new unless SiteSetting.wizard_enabled? + end + + def destination_url + request.original_url unless request.original_url =~ /uploads/ + end + + def redirect_to_login_if_required + return if current_user || (request.format.json? && is_api?) + + if SiteSetting.login_required? + flash.keep + + if SiteSetting.enable_sso? + # save original URL in a session so we can redirect after login + session[:destination_url] = destination_url + redirect_to path('/session/sso') + elsif params[:authComplete].present? + redirect_to path("/login?authComplete=true") + else + # save original URL in a cookie (javascript redirects after login in this case) + cookies[:destination_url] = destination_url + redirect_to path("/login") end end + end - def block_if_readonly_mode - return if request.fullpath.start_with?(path "/admin/backups") - raise Discourse::ReadOnly.new if !(request.get? || request.head?) && @readonly_mode + def block_if_readonly_mode + return if request.fullpath.start_with?(path "/admin/backups") + raise Discourse::ReadOnly.new if !(request.get? || request.head?) && @readonly_mode + end + + def build_not_found_page(status = 404, layout = false) + if SiteSetting.bootstrap_error_pages? + preload_json + layout = 'application' if layout == 'no_ember' end - def build_not_found_page(status = 404, layout = false) - if SiteSetting.bootstrap_error_pages? - preload_json - layout = 'application' if layout == 'no_ember' - end + category_topic_ids = Category.pluck(:topic_id).compact + @container_class = "wrap not-found-container" + @top_viewed = TopicQuery.new(nil, except_topic_ids: category_topic_ids).list_top_for("monthly").topics.first(10) + @recent = Topic.includes(:category).where.not(id: category_topic_ids).recent(10) + @slug = params[:slug].class == String ? params[:slug] : '' + @slug = (params[:id].class == String ? params[:id] : '') if @slug.blank? + @slug.tr!('-', ' ') + @hide_google = true if SiteSetting.login_required + render_to_string status: status, layout: layout, formats: [:html], template: '/exceptions/not_found' + end - category_topic_ids = Category.pluck(:topic_id).compact - @container_class = "wrap not-found-container" - @top_viewed = TopicQuery.new(nil, except_topic_ids: category_topic_ids).list_top_for("monthly").topics.first(10) - @recent = Topic.includes(:category).where.not(id: category_topic_ids).recent(10) - @slug = params[:slug].class == String ? params[:slug] : '' - @slug = (params[:id].class == String ? params[:id] : '') if @slug.blank? - @slug.tr!('-', ' ') - @hide_google = true if SiteSetting.login_required - render_to_string status: status, layout: layout, formats: [:html], template: '/exceptions/not_found' - end - - def is_asset_path - request.env['DISCOURSE_IS_ASSET_PATH'] = 1 - end + def is_asset_path + request.env['DISCOURSE_IS_ASSET_PATH'] = 1 + end protected - def render_post_json(post, add_raw = true) - post_serializer = PostSerializer.new(post, scope: guardian, root: false) - post_serializer.add_raw = add_raw + def render_post_json(post, add_raw = true) + post_serializer = PostSerializer.new(post, scope: guardian, root: false) + post_serializer.add_raw = add_raw - counts = PostAction.counts_for([post], current_user) - if counts && counts = counts[post.id] - post_serializer.post_actions = counts - end - render_json_dump(post_serializer) + counts = PostAction.counts_for([post], current_user) + if counts && counts = counts[post.id] + post_serializer.post_actions = counts end + render_json_dump(post_serializer) + end - # returns an array of integers given a param key - # returns nil if key is not found - def param_to_integer_list(key, delimiter = ',') - if params[key] - params[key].split(delimiter).map(&:to_i) - end + # returns an array of integers given a param key + # returns nil if key is not found + def param_to_integer_list(key, delimiter = ',') + if params[key] + params[key].split(delimiter).map(&:to_i) end + end end diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index f9216fc56b..b9e86e7276 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -201,109 +201,109 @@ class CategoriesController < ApplicationController end private - def categories_and_topics(topics_filter) - discourse_expires_in 1.minute + def categories_and_topics(topics_filter) + discourse_expires_in 1.minute - category_options = { - is_homepage: current_homepage == "categories".freeze, - parent_category_id: params[:parent_category_id], - include_topics: false - } + category_options = { + is_homepage: current_homepage == "categories".freeze, + parent_category_id: params[:parent_category_id], + include_topics: false + } - topic_options = { - per_page: SiteSetting.categories_topics, - no_definitions: true, - exclude_category_ids: Category.where(suppress_from_latest: true).pluck(:id) - } + topic_options = { + per_page: SiteSetting.categories_topics, + no_definitions: true, + exclude_category_ids: Category.where(suppress_from_latest: true).pluck(:id) + } - result = CategoryAndTopicLists.new - result.category_list = CategoryList.new(guardian, category_options) + result = CategoryAndTopicLists.new + result.category_list = CategoryList.new(guardian, category_options) - if topics_filter == :latest - result.topic_list = TopicQuery.new(current_user, topic_options).list_latest - elsif topics_filter == :top - result.topic_list = TopicQuery.new(nil, topic_options).list_top_for(SiteSetting.top_page_default_timeframe.to_sym) + if topics_filter == :latest + result.topic_list = TopicQuery.new(current_user, topic_options).list_latest + elsif topics_filter == :top + result.topic_list = TopicQuery.new(nil, topic_options).list_top_for(SiteSetting.top_page_default_timeframe.to_sym) + end + + draft_key = Draft::NEW_TOPIC + draft_sequence = DraftSequence.current(current_user, draft_key) + draft = Draft.get(current_user, draft_key, draft_sequence) if current_user + + %w{category topic}.each do |type| + result.send(:"#{type}_list").draft = draft + result.send(:"#{type}_list").draft_key = draft_key + result.send(:"#{type}_list").draft_sequence = draft_sequence + end + + render_serialized(result, CategoryAndTopicListsSerializer, root: false) + end + + def required_param_keys + [:name, :color, :text_color] + end + + def category_params + @category_params ||= begin + required_param_keys.each do |key| + params.require(key) end - draft_key = Draft::NEW_TOPIC - draft_sequence = DraftSequence.current(current_user, draft_key) - draft = Draft.get(current_user, draft_key, draft_sequence) if current_user - - %w{category topic}.each do |type| - result.send(:"#{type}_list").draft = draft - result.send(:"#{type}_list").draft_key = draft_key - result.send(:"#{type}_list").draft_sequence = draft_sequence + if p = params[:permissions] + p.each do |k, v| + p[k] = v.to_i + end end - render_serialized(result, CategoryAndTopicListsSerializer, root: false) - end - - def required_param_keys - [:name, :color, :text_color] - end - - def category_params - @category_params ||= begin - required_param_keys.each do |key| - params.require(key) - end - - if p = params[:permissions] - p.each do |k, v| - p[k] = v.to_i - end - end - - if SiteSetting.tagging_enabled - params[:allowed_tags] ||= [] - params[:allowed_tag_groups] ||= [] - end - - params.permit(*required_param_keys, - :position, - :email_in, - :email_in_allow_strangers, - :mailinglist_mirror, - :suppress_from_latest, - :all_topics_wiki, - :parent_category_id, - :auto_close_hours, - :auto_close_based_on_last_post, - :uploaded_logo_id, - :uploaded_background_id, - :slug, - :allow_badges, - :topic_template, - :sort_order, - :sort_ascending, - :topic_featured_link_allowed, - :show_subcategory_list, - :num_featured_topics, - :default_view, - :subcategory_list_style, - :default_top_period, - :minimum_required_tags, - custom_fields: [params[:custom_fields].try(:keys)], - permissions: [*p.try(:keys)], - allowed_tags: [], - allowed_tag_groups: []) + if SiteSetting.tagging_enabled + params[:allowed_tags] ||= [] + params[:allowed_tag_groups] ||= [] end - end - def fetch_category - @category = Category.find_by(slug: params[:id]) || Category.find_by(id: params[:id].to_i) + params.permit(*required_param_keys, + :position, + :email_in, + :email_in_allow_strangers, + :mailinglist_mirror, + :suppress_from_latest, + :all_topics_wiki, + :parent_category_id, + :auto_close_hours, + :auto_close_based_on_last_post, + :uploaded_logo_id, + :uploaded_background_id, + :slug, + :allow_badges, + :topic_template, + :sort_order, + :sort_ascending, + :topic_featured_link_allowed, + :show_subcategory_list, + :num_featured_topics, + :default_view, + :subcategory_list_style, + :default_top_period, + :minimum_required_tags, + custom_fields: [params[:custom_fields].try(:keys)], + permissions: [*p.try(:keys)], + allowed_tags: [], + allowed_tag_groups: []) end + end - def initialize_staff_action_logger - @staff_action_logger = StaffActionLogger.new(current_user) - end + def fetch_category + @category = Category.find_by(slug: params[:id]) || Category.find_by(id: params[:id].to_i) + end - def include_topics(parent_category = nil) - style = SiteSetting.desktop_category_page_style - view_context.mobile_view? || - params[:include_topics] || - (parent_category && parent_category.subcategory_list_includes_topics?) || - style == "categories_with_featured_topics".freeze || - style == "categories_with_top_topics".freeze - end + def initialize_staff_action_logger + @staff_action_logger = StaffActionLogger.new(current_user) + end + + def include_topics(parent_category = nil) + style = SiteSetting.desktop_category_page_style + view_context.mobile_view? || + params[:include_topics] || + (parent_category && parent_category.subcategory_list_includes_topics?) || + style == "categories_with_featured_topics".freeze || + style == "categories_with_top_topics".freeze + end end diff --git a/app/controllers/clicks_controller.rb b/app/controllers/clicks_controller.rb index 9602a48625..1aa3a29289 100644 --- a/app/controllers/clicks_controller.rb +++ b/app/controllers/clicks_controller.rb @@ -31,9 +31,9 @@ class ClicksController < ApplicationController private - def track_params - params.require(:url) - params.permit(:url, :post_id, :topic_id, :redirect) - end + def track_params + params.require(:url) + params.permit(:url, :post_id, :topic_id, :redirect) + end end diff --git a/app/controllers/embed_controller.rb b/app/controllers/embed_controller.rb index 686019e850..d43754709b 100644 --- a/app/controllers/embed_controller.rb +++ b/app/controllers/embed_controller.rb @@ -92,28 +92,28 @@ class EmbedController < ApplicationController private - def get_embeddable_css_class - @embeddable_css_class = "" - embeddable_host = EmbeddableHost.record_for_url(request.referer) - @embeddable_css_class = " class=\"#{embeddable_host.class_name}\"" if embeddable_host.present? && embeddable_host.class_name.present? - end + def get_embeddable_css_class + @embeddable_css_class = "" + embeddable_host = EmbeddableHost.record_for_url(request.referer) + @embeddable_css_class = " class=\"#{embeddable_host.class_name}\"" if embeddable_host.present? && embeddable_host.class_name.present? + end - def ensure_api_request - raise Discourse::InvalidAccess.new('api key not set') if !is_api? - end + def ensure_api_request + raise Discourse::InvalidAccess.new('api key not set') if !is_api? + end - def ensure_embeddable - if !(Rails.env.development? && current_user&.admin?) - referer = request.referer + def ensure_embeddable + if !(Rails.env.development? && current_user&.admin?) + referer = request.referer - unless referer && EmbeddableHost.url_allowed?(referer) - raise Discourse::InvalidAccess.new('invalid referer host') - end + unless referer && EmbeddableHost.url_allowed?(referer) + raise Discourse::InvalidAccess.new('invalid referer host') end - - response.headers['X-Frame-Options'] = "ALLOWALL" - rescue URI::InvalidURIError - raise Discourse::InvalidAccess.new('invalid referer host') end + response.headers['X-Frame-Options'] = "ALLOWALL" + rescue URI::InvalidURIError + raise Discourse::InvalidAccess.new('invalid referer host') + end + end diff --git a/app/controllers/exceptions_controller.rb b/app/controllers/exceptions_controller.rb index 33cbad301b..540add85c4 100644 --- a/app/controllers/exceptions_controller.rb +++ b/app/controllers/exceptions_controller.rb @@ -14,8 +14,8 @@ class ExceptionsController < ApplicationController private - def hide_google - @hide_google = true if SiteSetting.login_required - end + def hide_google + @hide_google = true if SiteSetting.login_required + end end diff --git a/app/controllers/export_csv_controller.rb b/app/controllers/export_csv_controller.rb index 836ad48d70..851d164368 100644 --- a/app/controllers/export_csv_controller.rb +++ b/app/controllers/export_csv_controller.rb @@ -9,10 +9,10 @@ class ExportCsvController < ApplicationController end private - def export_params - @_export_params ||= begin - params.require(:entity) - params.permit(:entity, args: [:name, :start_date, :end_date, :category_id, :group_id, :trust_level]).to_h - end + def export_params + @_export_params ||= begin + params.require(:entity) + params.permit(:entity, args: [:name, :start_date, :end_date, :category_id, :group_id, :trust_level]).to_h end + end end diff --git a/app/controllers/finish_installation_controller.rb b/app/controllers/finish_installation_controller.rb index 4640677ebc..c896724a49 100644 --- a/app/controllers/finish_installation_controller.rb +++ b/app/controllers/finish_installation_controller.rb @@ -48,18 +48,18 @@ class FinishInstallationController < ApplicationController protected - def redirect_confirm(email) - session[:registered_email] = email - redirect_to(finish_installation_confirm_email_path) - end + def redirect_confirm(email) + session[:registered_email] = email + redirect_to(finish_installation_confirm_email_path) + end - def find_allowed_emails - return [] unless GlobalSetting.respond_to?(:developer_emails) && GlobalSetting.developer_emails.present? - GlobalSetting.developer_emails.split(",").map(&:strip) - end + def find_allowed_emails + return [] unless GlobalSetting.respond_to?(:developer_emails) && GlobalSetting.developer_emails.present? + GlobalSetting.developer_emails.split(",").map(&:strip) + end - def ensure_no_admins - preload_anonymous_data - raise Discourse::InvalidAccess.new unless SiteSetting.has_login_hint? - end + def ensure_no_admins + preload_anonymous_data + raise Discourse::InvalidAccess.new unless SiteSetting.has_login_hint? + end end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index 10933affcf..c2c51ddf1e 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -211,14 +211,14 @@ class InvitesController < ApplicationController private - def post_process_invite(user) - user.enqueue_welcome_message('welcome_invite') if user.send_welcome_message - if user.has_password? - email_token = user.email_tokens.create(email: user.email) - Jobs.enqueue(:critical_user_email, type: :signup, user_id: user.id, email_token: email_token.token) - elsif !SiteSetting.enable_sso && SiteSetting.enable_local_logins - Jobs.enqueue(:invite_password_instructions_email, username: user.username) - end + def post_process_invite(user) + user.enqueue_welcome_message('welcome_invite') if user.send_welcome_message + if user.has_password? + email_token = user.email_tokens.create(email: user.email) + Jobs.enqueue(:critical_user_email, type: :signup, user_id: user.id, email_token: email_token.token) + elsif !SiteSetting.enable_sso && SiteSetting.enable_local_logins + Jobs.enqueue(:invite_password_instructions_email, username: user.username) end + end end diff --git a/app/controllers/notifications_controller.rb b/app/controllers/notifications_controller.rb index 7fbc06a2b0..50d715933b 100644 --- a/app/controllers/notifications_controller.rb +++ b/app/controllers/notifications_controller.rb @@ -84,16 +84,16 @@ class NotificationsController < ApplicationController private - def set_notification - @notification = Notification.find(params[:id]) - end + def set_notification + @notification = Notification.find(params[:id]) + end - def notification_params - params.permit(:notification_type, :user_id, :data, :read, :topic_id, :post_number, :post_action_id) - end + def notification_params + params.permit(:notification_type, :user_id, :data, :read, :topic_id, :post_number, :post_action_id) + end - def render_notification - render_json_dump(NotificationSerializer.new(@notification, scope: guardian, root: false)) - end + def render_notification + render_json_dump(NotificationSerializer.new(@notification, scope: guardian, root: false)) + end end diff --git a/app/controllers/post_actions_controller.rb b/app/controllers/post_actions_controller.rb index fa0314b999..3e5b0c8e84 100644 --- a/app/controllers/post_actions_controller.rb +++ b/app/controllers/post_actions_controller.rb @@ -65,32 +65,32 @@ class PostActionsController < ApplicationController private - def fetch_post_from_params - params.require(:id) + def fetch_post_from_params + params.require(:id) - flag_topic = params[:flag_topic] - flag_topic = flag_topic && (flag_topic == true || flag_topic == "true") + flag_topic = params[:flag_topic] + flag_topic = flag_topic && (flag_topic == true || flag_topic == "true") - post_id = if flag_topic - begin - Topic.find(params[:id]).posts.first.id - rescue - raise Discourse::NotFound - end - else - params[:id] + post_id = if flag_topic + begin + Topic.find(params[:id]).posts.first.id + rescue + raise Discourse::NotFound end - - finder = Post.where(id: post_id) - - # Include deleted posts if the user is a staff - finder = finder.with_deleted if guardian.is_staff? - - @post = finder.first + else + params[:id] end - def fetch_post_action_type_id_from_params - params.require(:post_action_type_id) - @post_action_type_id = params[:post_action_type_id].to_i - end + finder = Post.where(id: post_id) + + # Include deleted posts if the user is a staff + finder = finder.with_deleted if guardian.is_staff? + + @post = finder.first + end + + def fetch_post_action_type_id_from_params + params.require(:post_action_type_id) + @post_action_type_id = params[:post_action_type_id].to_i + end end diff --git a/app/controllers/queued_posts_controller.rb b/app/controllers/queued_posts_controller.rb index 3360b41f7b..7db439e929 100644 --- a/app/controllers/queued_posts_controller.rb +++ b/app/controllers/queued_posts_controller.rb @@ -52,18 +52,18 @@ class QueuedPostsController < ApplicationController private - def user_deletion_opts - base = { - context: I18n.t('queue.delete_reason', performed_by: current_user.username), - delete_posts: true, - delete_as_spammer: true - } + def user_deletion_opts + base = { + context: I18n.t('queue.delete_reason', performed_by: current_user.username), + delete_posts: true, + delete_as_spammer: true + } - if Rails.env.production? && ENV["Staging"].nil? - base.merge!(block_email: true, block_ip: true) - end - - base + if Rails.env.production? && ENV["Staging"].nil? + base.merge!(block_email: true, block_ip: true) end + base + end + end diff --git a/app/controllers/stylesheets_controller.rb b/app/controllers/stylesheets_controller.rb index 7377d47989..f7344a3393 100644 --- a/app/controllers/stylesheets_controller.rb +++ b/app/controllers/stylesheets_controller.rb @@ -98,11 +98,11 @@ class StylesheetsController < ApplicationController private - def read_file(location) - begin - File.read(location) - rescue Errno::ENOENT - end + def read_file(location) + begin + File.read(location) + rescue Errno::ENOENT end + end end diff --git a/app/controllers/tag_groups_controller.rb b/app/controllers/tag_groups_controller.rb index 65748f8378..4fd4f0f6e0 100644 --- a/app/controllers/tag_groups_controller.rb +++ b/app/controllers/tag_groups_controller.rb @@ -64,28 +64,28 @@ class TagGroupsController < ApplicationController private - def fetch_tag_group - @tag_group = TagGroup.find(params[:id]) - end + def fetch_tag_group + @tag_group = TagGroup.find(params[:id]) + end - def tag_groups_params - if permissions = params[:permissions] - permissions.each do |k, v| - permissions[k] = v.to_i - end + def tag_groups_params + if permissions = params[:permissions] + permissions.each do |k, v| + permissions[k] = v.to_i end - - result = params.permit( - :id, - :name, - :one_per_topic, - tag_names: [], - parent_tag_name: [], - permissions: permissions&.keys, - ) - result[:tag_names] ||= [] - result[:parent_tag_name] ||= [] - result[:one_per_topic] = (params[:one_per_topic] == "true") - result end + + result = params.permit( + :id, + :name, + :one_per_topic, + tag_names: [], + parent_tag_name: [], + permissions: permissions&.keys, + ) + result[:tag_names] ||= [] + result[:parent_tag_name] ||= [] + result[:one_per_topic] = (params[:one_per_topic] == "true") + result + end end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index a673bb06d0..b2916e8c9d 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -207,130 +207,130 @@ class TagsController < ::ApplicationController private - def ensure_tags_enabled - raise Discourse::NotFound unless SiteSetting.tagging_enabled? - end + def ensure_tags_enabled + raise Discourse::NotFound unless SiteSetting.tagging_enabled? + end - def self.tag_counts_json(tags) - tags.map { |t| { id: t.name, text: t.name, count: t.topic_count, pm_count: t.pm_topic_count } } - end + def self.tag_counts_json(tags) + tags.map { |t| { id: t.name, text: t.name, count: t.topic_count, pm_count: t.pm_topic_count } } + end - def set_category_from_params - slug_or_id = params[:category] - return true if slug_or_id.nil? + def set_category_from_params + slug_or_id = params[:category] + return true if slug_or_id.nil? - if slug_or_id == 'none' && params[:parent_category] - @filter_on_category = Category.query_category(params[:parent_category], nil) - params[:no_subcategories] = 'true' - else - parent_slug_or_id = params[:parent_category] + if slug_or_id == 'none' && params[:parent_category] + @filter_on_category = Category.query_category(params[:parent_category], nil) + params[:no_subcategories] = 'true' + else + parent_slug_or_id = params[:parent_category] - parent_category_id = nil - if parent_slug_or_id.present? - parent_category_id = Category.query_parent_category(parent_slug_or_id) - category_redirect_or_not_found && (return) if parent_category_id.blank? - end - - @filter_on_category = Category.query_category(slug_or_id, parent_category_id) + parent_category_id = nil + if parent_slug_or_id.present? + parent_category_id = Category.query_parent_category(parent_slug_or_id) + category_redirect_or_not_found && (return) if parent_category_id.blank? end - category_redirect_or_not_found && (return) if !@filter_on_category - - guardian.ensure_can_see!(@filter_on_category) + @filter_on_category = Category.query_category(slug_or_id, parent_category_id) end - # TODO: this is duplication of ListController - def page_params(opts = nil) - opts ||= {} - route_params = { format: 'json' } - route_params[:category] = @filter_on_category.slug_for_url if @filter_on_category - route_params[:parent_category] = @filter_on_category.parent_category.slug_for_url if @filter_on_category && @filter_on_category.parent_category - route_params[:order] = opts[:order] if opts[:order].present? - route_params[:ascending] = opts[:ascending] if opts[:ascending].present? - route_params - end + category_redirect_or_not_found && (return) if !@filter_on_category - def next_page_params(opts = nil) - page_params(opts).merge(page: params[:page].to_i + 1) - end + guardian.ensure_can_see!(@filter_on_category) + end - def prev_page_params(opts = nil) - pg = params[:page].to_i - if pg > 1 - page_params(opts).merge(page: pg - 1) - else - page_params(opts).merge(page: nil) + # TODO: this is duplication of ListController + def page_params(opts = nil) + opts ||= {} + route_params = { format: 'json' } + route_params[:category] = @filter_on_category.slug_for_url if @filter_on_category + route_params[:parent_category] = @filter_on_category.parent_category.slug_for_url if @filter_on_category && @filter_on_category.parent_category + route_params[:order] = opts[:order] if opts[:order].present? + route_params[:ascending] = opts[:ascending] if opts[:ascending].present? + route_params + end + + def next_page_params(opts = nil) + page_params(opts).merge(page: params[:page].to_i + 1) + end + + def prev_page_params(opts = nil) + pg = params[:page].to_i + if pg > 1 + page_params(opts).merge(page: pg - 1) + else + page_params(opts).merge(page: nil) + end + end + + def url_method(opts = {}) + if opts[:parent_category] && opts[:category] + "tag_parent_category_category_#{action_name}_path" + elsif opts[:category] + "tag_category_#{action_name}_path" + else + "tag_#{action_name}_path" + end + end + + def construct_url_with(action, opts) + method = url_method(opts) + + begin + url = if action == :prev + public_send(method, opts.merge(prev_page_params(opts))) + else # :next + public_send(method, opts.merge(next_page_params(opts))) end + rescue ActionController::UrlGenerationError + raise Discourse::NotFound + end + url.sub('.json?', '?') + end + + def build_topic_list_options + options = { + page: params[:page], + topic_ids: param_to_integer_list(:topic_ids), + exclude_category_ids: params[:exclude_category_ids], + category: @filter_on_category ? @filter_on_category.id : params[:category], + order: params[:order], + ascending: params[:ascending], + min_posts: params[:min_posts], + max_posts: params[:max_posts], + status: params[:status], + filter: params[:filter], + state: params[:state], + search: params[:search], + q: params[:q] + } + options[:no_subcategories] = true if params[:no_subcategories] == 'true' + options[:slow_platform] = true if slow_platform? + + if params[:tag_id] == 'none' + options[:no_tags] = true + else + options[:tags] = tag_params + options[:match_all_tags] = true end - def url_method(opts = {}) - if opts[:parent_category] && opts[:category] - "tag_parent_category_category_#{action_name}_path" - elsif opts[:category] - "tag_category_#{action_name}_path" - else - "tag_#{action_name}_path" - end + options + end + + def category_redirect_or_not_found + # automatic redirects for renamed categories + url = params[:parent_category] ? "c/#{params[:parent_category]}/#{params[:category]}" : "c/#{params[:category]}" + permalink = Permalink.find_by_url(url) + + if permalink.present? && permalink.category_id + redirect_to "#{Discourse::base_uri}/tags#{permalink.target_url}/#{params[:tag_id]}", status: :moved_permanently + else + # redirect to 404 + raise Discourse::NotFound end + end - def construct_url_with(action, opts) - method = url_method(opts) - - begin - url = if action == :prev - public_send(method, opts.merge(prev_page_params(opts))) - else # :next - public_send(method, opts.merge(next_page_params(opts))) - end - rescue ActionController::UrlGenerationError - raise Discourse::NotFound - end - url.sub('.json?', '?') - end - - def build_topic_list_options - options = { - page: params[:page], - topic_ids: param_to_integer_list(:topic_ids), - exclude_category_ids: params[:exclude_category_ids], - category: @filter_on_category ? @filter_on_category.id : params[:category], - order: params[:order], - ascending: params[:ascending], - min_posts: params[:min_posts], - max_posts: params[:max_posts], - status: params[:status], - filter: params[:filter], - state: params[:state], - search: params[:search], - q: params[:q] - } - options[:no_subcategories] = true if params[:no_subcategories] == 'true' - options[:slow_platform] = true if slow_platform? - - if params[:tag_id] == 'none' - options[:no_tags] = true - else - options[:tags] = tag_params - options[:match_all_tags] = true - end - - options - end - - def category_redirect_or_not_found - # automatic redirects for renamed categories - url = params[:parent_category] ? "c/#{params[:parent_category]}/#{params[:category]}" : "c/#{params[:category]}" - permalink = Permalink.find_by_url(url) - - if permalink.present? && permalink.category_id - redirect_to "#{Discourse::base_uri}/tags#{permalink.target_url}/#{params[:tag_id]}", status: :moved_permanently - else - # redirect to 404 - raise Discourse::NotFound - end - end - - def tag_params - [@tag_id].concat(Array(@additional_tags)) - end + def tag_params + [@tag_id].concat(Array(@additional_tags)) + end end diff --git a/app/controllers/user_badges_controller.rb b/app/controllers/user_badges_controller.rb index b6b415d69a..999c987647 100644 --- a/app/controllers/user_badges_controller.rb +++ b/app/controllers/user_badges_controller.rb @@ -92,28 +92,28 @@ class UserBadgesController < ApplicationController private - # Get the badge from either the badge name or id specified in the params. - def fetch_badge_from_params - badge = nil + # Get the badge from either the badge name or id specified in the params. + def fetch_badge_from_params + badge = nil - params.permit(:badge_name) - if params[:badge_name].nil? - params.require(:badge_id) - badge = Badge.find_by(id: params[:badge_id], enabled: true) - else - badge = Badge.find_by(name: params[:badge_name], enabled: true) - end - raise Discourse::NotFound if badge.blank? - - badge + params.permit(:badge_name) + if params[:badge_name].nil? + params.require(:badge_id) + badge = Badge.find_by(id: params[:badge_id], enabled: true) + else + badge = Badge.find_by(name: params[:badge_name], enabled: true) end + raise Discourse::NotFound if badge.blank? - def can_assign_badge_to_user?(user) - master_api_call = current_user.nil? && is_api? - master_api_call || guardian.can_grant_badges?(user) - end + badge + end - def ensure_badges_enabled - raise Discourse::NotFound unless SiteSetting.enable_badges? - end + def can_assign_badge_to_user?(user) + master_api_call = current_user.nil? && is_api? + master_api_call || guardian.can_grant_badges?(user) + end + + def ensure_badges_enabled + raise Discourse::NotFound unless SiteSetting.enable_badges? + end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 548ce754c6..3c97ce94d7 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -994,104 +994,104 @@ class UsersController < ApplicationController private - def honeypot_value - Digest::SHA1::hexdigest("#{Discourse.current_hostname}:#{GlobalSetting.safe_secret_key_base}")[0, 15] + def honeypot_value + Digest::SHA1::hexdigest("#{Discourse.current_hostname}:#{GlobalSetting.safe_secret_key_base}")[0, 15] + end + + def challenge_value + challenge = $redis.get('SECRET_CHALLENGE') + unless challenge && challenge.length == 16 * 2 + challenge = SecureRandom.hex(16) + $redis.set('SECRET_CHALLENGE', challenge) end - def challenge_value - challenge = $redis.get('SECRET_CHALLENGE') - unless challenge && challenge.length == 16 * 2 - challenge = SecureRandom.hex(16) - $redis.set('SECRET_CHALLENGE', challenge) - end + challenge + end - challenge + def respond_to_suspicious_request + if suspicious?(params) + render json: { + success: true, + active: false, + message: I18n.t("login.activate_email", email: params[:email]) + } + end + end + + def suspicious?(params) + return false if current_user && is_api? && current_user.admin? + honeypot_or_challenge_fails?(params) || SiteSetting.invite_only? + end + + def honeypot_or_challenge_fails?(params) + return false if is_api? + params[:password_confirmation] != honeypot_value || + params[:challenge] != challenge_value.try(:reverse) + end + + def user_params + permitted = [ + :name, + :email, + :password, + :username, + :title, + :date_of_birth, + :muted_usernames, + :theme_key, + :locale, + :bio_raw, + :location, + :website, + :dismissed_banner_key, + :profile_background, + :card_background + ] + + permitted.concat UserUpdater::OPTION_ATTR + permitted.concat UserUpdater::CATEGORY_IDS.keys.map { |k| { k => [] } } + permitted.concat UserUpdater::TAG_NAMES.keys + + result = params + .permit(permitted) + .reverse_merge( + ip_address: request.remote_ip, + registration_ip_address: request.remote_ip, + locale: user_locale + ) + + if !UsernameCheckerService.is_developer?(result['email']) && + is_api? && + current_user.present? && + current_user.admin? + + result.merge!(params.permit(:active, :staged, :approved)) end - def respond_to_suspicious_request - if suspicious?(params) - render json: { - success: true, - active: false, - message: I18n.t("login.activate_email", email: params[:email]) - } - end - end - - def suspicious?(params) - return false if current_user && is_api? && current_user.admin? - honeypot_or_challenge_fails?(params) || SiteSetting.invite_only? - end - - def honeypot_or_challenge_fails?(params) - return false if is_api? - params[:password_confirmation] != honeypot_value || - params[:challenge] != challenge_value.try(:reverse) - end - - def user_params - permitted = [ - :name, - :email, - :password, - :username, - :title, - :date_of_birth, - :muted_usernames, - :theme_key, - :locale, - :bio_raw, - :location, - :website, - :dismissed_banner_key, - :profile_background, - :card_background - ] - - permitted.concat UserUpdater::OPTION_ATTR - permitted.concat UserUpdater::CATEGORY_IDS.keys.map { |k| { k => [] } } - permitted.concat UserUpdater::TAG_NAMES.keys - - result = params - .permit(permitted) - .reverse_merge( - ip_address: request.remote_ip, - registration_ip_address: request.remote_ip, - locale: user_locale - ) - - if !UsernameCheckerService.is_developer?(result['email']) && - is_api? && - current_user.present? && - current_user.admin? - - result.merge!(params.permit(:active, :staged, :approved)) - end - - modify_user_params(result) - end - - # Plugins can use this to modify user parameters - def modify_user_params(attrs) - attrs - end - - def user_locale - I18n.locale - end - - def fail_with(key) - render json: { success: false, message: I18n.t(key) } - end - - def track_visit_to_user_profile - user_profile_id = @user.user_profile.id - ip = request.remote_ip - user_id = (current_user.id if current_user) - - Scheduler::Defer.later 'Track profile view visit' do - UserProfileView.add(user_profile_id, ip, user_id) - end + modify_user_params(result) + end + + # Plugins can use this to modify user parameters + def modify_user_params(attrs) + attrs + end + + def user_locale + I18n.locale + end + + def fail_with(key) + render json: { success: false, message: I18n.t(key) } + end + + def track_visit_to_user_profile + user_profile_id = @user.user_profile.id + ip = request.remote_ip + user_id = (current_user.id if current_user) + + Scheduler::Defer.later 'Track profile view visit' do + UserProfileView.add(user_profile_id, ip, user_id) end + end end diff --git a/app/controllers/webhooks_controller.rb b/app/controllers/webhooks_controller.rb index b6e1ad2093..5480fe3368 100644 --- a/app/controllers/webhooks_controller.rb +++ b/app/controllers/webhooks_controller.rb @@ -119,30 +119,30 @@ class WebhooksController < ActionController::Base private - def mailgun_failure - render body: nil, status: 406 - end + def mailgun_failure + render body: nil, status: 406 + end - def mailgun_success - render body: nil, status: 200 - end + def mailgun_success + render body: nil, status: 200 + end - def mailgun_verify(timestamp, token, signature) - digest = OpenSSL::Digest::SHA256.new - data = "#{timestamp}#{token}" - signature == OpenSSL::HMAC.hexdigest(digest, SiteSetting.mailgun_api_key, data) - end + def mailgun_verify(timestamp, token, signature) + digest = OpenSSL::Digest::SHA256.new + data = "#{timestamp}#{token}" + signature == OpenSSL::HMAC.hexdigest(digest, SiteSetting.mailgun_api_key, data) + end - def process_bounce(message_id, to_address, bounce_score) - return if message_id.blank? || to_address.blank? + def process_bounce(message_id, to_address, bounce_score) + return if message_id.blank? || to_address.blank? - email_log = EmailLog.find_by(message_id: message_id, to_address: to_address) - return if email_log.nil? + email_log = EmailLog.find_by(message_id: message_id, to_address: to_address) + return if email_log.nil? - email_log.update_columns(bounced: true) - return if email_log.user.nil? || email_log.user.email.blank? + email_log.update_columns(bounced: true) + return if email_log.user.nil? || email_log.user.email.blank? - Email::Receiver.update_bounce_score(email_log.user.email, bounce_score) - end + Email::Receiver.update_bounce_score(email_log.user.email, bounce_score) + end end diff --git a/app/jobs/regular/export_csv_file.rb b/app/jobs/regular/export_csv_file.rb index 2ebfb75df7..d32e2b822c 100644 --- a/app/jobs/regular/export_csv_file.rb +++ b/app/jobs/regular/export_csv_file.rb @@ -211,169 +211,169 @@ module Jobs private - def escape_comma(string) - if string && string =~ /,/ - return "#{string}" - else - return string + def escape_comma(string) + if string && string =~ /,/ + return "#{string}" + else + return string + end + end + + def get_base_user_array(user) + user_array = [] + user_array.push(user.id, escape_comma(user.name), user.username, user.email, escape_comma(user.title), user.created_at, user.last_seen_at, user.last_posted_at, user.last_emailed_at, user.trust_level, user.approved, user.suspended_at, user.suspended_till, user.silenced_till, user.active, user.admin, user.moderator, user.ip_address, user.staged, user.user_stat.topics_entered, user.user_stat.posts_read_count, user.user_stat.time_read, user.user_stat.topic_count, user.user_stat.post_count, user.user_stat.likes_given, user.user_stat.likes_received, escape_comma(user.user_profile.location), user.user_profile.website, user.user_profile.views) + end + + def add_single_sign_on(user, user_info_array) + if user.single_sign_on_record + user_info_array.push(user.single_sign_on_record.external_id, user.single_sign_on_record.external_email, user.single_sign_on_record.external_username, escape_comma(user.single_sign_on_record.external_name), user.single_sign_on_record.external_avatar_url) + else + user_info_array.push(nil, nil, nil, nil, nil) + end + user_info_array + end + + def add_custom_fields(user, user_info_array, user_field_ids) + if user_field_ids.present? + user.user_fields.each do |custom_field| + user_info_array << escape_comma(custom_field[1]) end end + user_info_array + end - def get_base_user_array(user) - user_array = [] - user_array.push(user.id, escape_comma(user.name), user.username, user.email, escape_comma(user.title), user.created_at, user.last_seen_at, user.last_posted_at, user.last_emailed_at, user.trust_level, user.approved, user.suspended_at, user.suspended_till, user.silenced_till, user.active, user.admin, user.moderator, user.ip_address, user.staged, user.user_stat.topics_entered, user.user_stat.posts_read_count, user.user_stat.time_read, user.user_stat.topic_count, user.user_stat.post_count, user.user_stat.likes_given, user.user_stat.likes_received, escape_comma(user.user_profile.location), user.user_profile.website, user.user_profile.views) + def add_group_names(user, user_info_array) + group_names = user.groups.each_with_object("") do |group, names| + names << "#{group.name};" end + user_info_array << group_names[0..-2] unless group_names.blank? + group_names = nil + user_info_array + end - def add_single_sign_on(user, user_info_array) - if user.single_sign_on_record - user_info_array.push(user.single_sign_on_record.external_id, user.single_sign_on_record.external_email, user.single_sign_on_record.external_username, escape_comma(user.single_sign_on_record.external_name), user.single_sign_on_record.external_avatar_url) - else - user_info_array.push(nil, nil, nil, nil, nil) - end - user_info_array - end - - def add_custom_fields(user, user_info_array, user_field_ids) - if user_field_ids.present? - user.user_fields.each do |custom_field| - user_info_array << escape_comma(custom_field[1]) + def get_user_archive_fields(user_archive) + user_archive_array = [] + topic_data = user_archive.topic + user_archive = user_archive.as_json + topic_data = Topic.with_deleted.find_by(id: user_archive['topic_id']) if topic_data.nil? + return user_archive_array if topic_data.nil? + category = topic_data.category + sub_category_name = "-" + if category + category_name = category.name + if category.parent_category_id.present? + # sub category + if parent_category = Category.find_by(id: category.parent_category_id) + category_name = parent_category.name + sub_category_name = category.name end end - user_info_array + else + # PM + category_name = "-" + end + is_pm = topic_data.archetype == "private_message" ? I18n.t("csv_export.boolean_yes") : I18n.t("csv_export.boolean_no") + url = "#{Discourse.base_url}/t/#{topic_data.slug}/#{topic_data.id}/#{user_archive['post_number']}" + + topic_hash = { "post" => user_archive['raw'], "topic_title" => topic_data.title, "category" => category_name, "sub_category" => sub_category_name, "is_pm" => is_pm, "url" => url } + user_archive.merge!(topic_hash) + + HEADER_ATTRS_FOR['user_archive'].each do |attr| + user_archive_array.push(user_archive[attr]) end - def add_group_names(user, user_info_array) - group_names = user.groups.each_with_object("") do |group, names| - names << "#{group.name};" - end - user_info_array << group_names[0..-2] unless group_names.blank? - group_names = nil - user_info_array - end + user_archive_array + end - def get_user_archive_fields(user_archive) - user_archive_array = [] - topic_data = user_archive.topic - user_archive = user_archive.as_json - topic_data = Topic.with_deleted.find_by(id: user_archive['topic_id']) if topic_data.nil? - return user_archive_array if topic_data.nil? - category = topic_data.category - sub_category_name = "-" - if category - category_name = category.name - if category.parent_category_id.present? - # sub category - if parent_category = Category.find_by(id: category.parent_category_id) - category_name = parent_category.name - sub_category_name = category.name - end - end - else - # PM - category_name = "-" - end - is_pm = topic_data.archetype == "private_message" ? I18n.t("csv_export.boolean_yes") : I18n.t("csv_export.boolean_no") - url = "#{Discourse.base_url}/t/#{topic_data.slug}/#{topic_data.id}/#{user_archive['post_number']}" + def get_staff_action_fields(staff_action) + staff_action_array = [] - topic_hash = { "post" => user_archive['raw'], "topic_title" => topic_data.title, "category" => category_name, "sub_category" => sub_category_name, "is_pm" => is_pm, "url" => url } - user_archive.merge!(topic_hash) - - HEADER_ATTRS_FOR['user_archive'].each do |attr| - user_archive_array.push(user_archive[attr]) - end - - user_archive_array - end - - def get_staff_action_fields(staff_action) - staff_action_array = [] - - HEADER_ATTRS_FOR['staff_action'].each do |attr| - data = - if attr == 'action' - UserHistory.actions.key(staff_action.attributes[attr]).to_s - elsif attr == 'staff_user' - user = User.find_by(id: staff_action.attributes['acting_user_id']) - user.username if !user.nil? - elsif attr == 'subject' - user = User.find_by(id: staff_action.attributes['target_user_id']) - user.nil? ? staff_action.attributes[attr] : "#{user.username} #{staff_action.attributes[attr]}" - else - staff_action.attributes[attr] - end - - staff_action_array.push(data) - end - staff_action_array - end - - def get_screened_email_fields(screened_email) - screened_email_array = [] - - HEADER_ATTRS_FOR['screened_email'].each do |attr| - data = - if attr == 'action' - ScreenedEmail.actions.key(screened_email.attributes['action_type']).to_s - else - screened_email.attributes[attr] - end - - screened_email_array.push(data) - end - - screened_email_array - end - - def get_screened_ip_fields(screened_ip) - screened_ip_array = [] - - HEADER_ATTRS_FOR['screened_ip'].each do |attr| - data = - if attr == 'action' - ScreenedIpAddress.actions.key(screened_ip.attributes['action_type']).to_s - else - screened_ip.attributes[attr] - end - - screened_ip_array.push(data) - end - - screened_ip_array - end - - def get_screened_url_fields(screened_url) - screened_url_array = [] - - HEADER_ATTRS_FOR['screened_url'].each do |attr| - data = - if attr == 'action' - action = ScreenedUrl.actions.key(screened_url.attributes['action_type']).to_s - action = "do nothing" if action.blank? - else - screened_url.attributes[attr] - end - - screened_url_array.push(data) - end - - screened_url_array - end - - def notify_user(download_link, file_name, file_size, export_title) - if @current_user - if download_link.present? - SystemMessage.create_from_system_user( - @current_user, - :csv_export_succeeded, - download_link: download_link, - file_name: "#{file_name}.gz", - file_size: file_size, - export_title: export_title - ) + HEADER_ATTRS_FOR['staff_action'].each do |attr| + data = + if attr == 'action' + UserHistory.actions.key(staff_action.attributes[attr]).to_s + elsif attr == 'staff_user' + user = User.find_by(id: staff_action.attributes['acting_user_id']) + user.username if !user.nil? + elsif attr == 'subject' + user = User.find_by(id: staff_action.attributes['target_user_id']) + user.nil? ? staff_action.attributes[attr] : "#{user.username} #{staff_action.attributes[attr]}" else - SystemMessage.create_from_system_user(@current_user, :csv_export_failed) + staff_action.attributes[attr] end + + staff_action_array.push(data) + end + staff_action_array + end + + def get_screened_email_fields(screened_email) + screened_email_array = [] + + HEADER_ATTRS_FOR['screened_email'].each do |attr| + data = + if attr == 'action' + ScreenedEmail.actions.key(screened_email.attributes['action_type']).to_s + else + screened_email.attributes[attr] + end + + screened_email_array.push(data) + end + + screened_email_array + end + + def get_screened_ip_fields(screened_ip) + screened_ip_array = [] + + HEADER_ATTRS_FOR['screened_ip'].each do |attr| + data = + if attr == 'action' + ScreenedIpAddress.actions.key(screened_ip.attributes['action_type']).to_s + else + screened_ip.attributes[attr] + end + + screened_ip_array.push(data) + end + + screened_ip_array + end + + def get_screened_url_fields(screened_url) + screened_url_array = [] + + HEADER_ATTRS_FOR['screened_url'].each do |attr| + data = + if attr == 'action' + action = ScreenedUrl.actions.key(screened_url.attributes['action_type']).to_s + action = "do nothing" if action.blank? + else + screened_url.attributes[attr] + end + + screened_url_array.push(data) + end + + screened_url_array + end + + def notify_user(download_link, file_name, file_size, export_title) + if @current_user + if download_link.present? + SystemMessage.create_from_system_user( + @current_user, + :csv_export_succeeded, + download_link: download_link, + file_name: "#{file_name}.gz", + file_size: file_size, + export_title: export_title + ) + else + SystemMessage.create_from_system_user(@current_user, :csv_export_failed) end end + end end end diff --git a/app/jobs/regular/pull_hotlinked_images.rb b/app/jobs/regular/pull_hotlinked_images.rb index ce88cd6546..d6e03f782d 100644 --- a/app/jobs/regular/pull_hotlinked_images.rb +++ b/app/jobs/regular/pull_hotlinked_images.rb @@ -174,9 +174,9 @@ module Jobs private - def remove_scheme(src) - src.sub(/^https?:/i, "") - end + def remove_scheme(src) + src.sub(/^https?:/i, "") + end end end diff --git a/app/models/badge.rb b/app/models/badge.rb index 60da562949..9a64949980 100644 --- a/app/models/badge.rb +++ b/app/models/badge.rb @@ -225,13 +225,13 @@ class Badge < ActiveRecord::Base protected - def ensure_not_system - self.id = [Badge.maximum(:id) + 1, 100].max unless id - end + def ensure_not_system + self.id = [Badge.maximum(:id) + 1, 100].max unless id + end - def i18n_name - self.name.downcase.tr(' ', '_') - end + def i18n_name + self.name.downcase.tr(' ', '_') + end end diff --git a/app/models/category_list.rb b/app/models/category_list.rb index 76511d5b8b..e8bf8aefab 100644 --- a/app/models/category_list.rb +++ b/app/models/category_list.rb @@ -44,127 +44,127 @@ class CategoryList private - def find_relevant_topics - @topics_by_id = {} - @topics_by_category_id = {} + def find_relevant_topics + @topics_by_id = {} + @topics_by_category_id = {} - category_featured_topics = CategoryFeaturedTopic.select([:category_id, :topic_id]).order(:rank) + category_featured_topics = CategoryFeaturedTopic.select([:category_id, :topic_id]).order(:rank) - @all_topics = Topic.where(id: category_featured_topics.map(&:topic_id)) - @all_topics = @all_topics.includes(:last_poster) if @options[:include_topics] - @all_topics.each do |t| - # hint for the serializer - t.include_last_poster = true if @options[:include_topics] - @topics_by_id[t.id] = t - end - - category_featured_topics.each do |cft| - @topics_by_category_id[cft.category_id] ||= [] - @topics_by_category_id[cft.category_id] << cft.topic_id - end + @all_topics = Topic.where(id: category_featured_topics.map(&:topic_id)) + @all_topics = @all_topics.includes(:last_poster) if @options[:include_topics] + @all_topics.each do |t| + # hint for the serializer + t.include_last_poster = true if @options[:include_topics] + @topics_by_id[t.id] = t end - def find_categories - @categories = Category.includes( - :uploaded_background, - :uploaded_logo, - :topic_only_relative_url, - subcategories: [:topic_only_relative_url] - ).secured(@guardian) + category_featured_topics.each do |cft| + @topics_by_category_id[cft.category_id] ||= [] + @topics_by_category_id[cft.category_id] << cft.topic_id + end + end - @categories = @categories.where("categories.parent_category_id = ?", @options[:parent_category_id].to_i) if @options[:parent_category_id].present? + def find_categories + @categories = Category.includes( + :uploaded_background, + :uploaded_logo, + :topic_only_relative_url, + subcategories: [:topic_only_relative_url] + ).secured(@guardian) - if SiteSetting.fixed_category_positions - @categories = @categories.order(:position, :id) - else - @categories = @categories.order('COALESCE(categories.posts_week, 0) DESC') - .order('COALESCE(categories.posts_month, 0) DESC') - .order('COALESCE(categories.posts_year, 0) DESC') - .order('id ASC') - end + @categories = @categories.where("categories.parent_category_id = ?", @options[:parent_category_id].to_i) if @options[:parent_category_id].present? - @categories = @categories.to_a + if SiteSetting.fixed_category_positions + @categories = @categories.order(:position, :id) + else + @categories = @categories.order('COALESCE(categories.posts_week, 0) DESC') + .order('COALESCE(categories.posts_month, 0) DESC') + .order('COALESCE(categories.posts_year, 0) DESC') + .order('id ASC') + end - category_user = {} - default_notification_level = nil - unless @guardian.anonymous? - category_user = Hash[*CategoryUser.where(user: @guardian.user).pluck(:category_id, :notification_level).flatten] - default_notification_level = CategoryUser.notification_levels[:regular] - end + @categories = @categories.to_a - allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id)) - @categories.each do |category| - category.notification_level = category_user[category.id] || default_notification_level - category.permission = CategoryGroup.permission_types[:full] if allowed_topic_create.include?(category.id) - category.has_children = category.subcategories.present? - end + category_user = {} + default_notification_level = nil + unless @guardian.anonymous? + category_user = Hash[*CategoryUser.where(user: @guardian.user).pluck(:category_id, :notification_level).flatten] + default_notification_level = CategoryUser.notification_levels[:regular] + end - if @options[:parent_category_id].blank? - subcategories = {} - to_delete = Set.new - @categories.each do |c| - if c.parent_category_id.present? - subcategories[c.parent_category_id] ||= [] - subcategories[c.parent_category_id] << c.id - to_delete << c - end + allowed_topic_create = Set.new(Category.topic_create_allowed(@guardian).pluck(:id)) + @categories.each do |category| + category.notification_level = category_user[category.id] || default_notification_level + category.permission = CategoryGroup.permission_types[:full] if allowed_topic_create.include?(category.id) + category.has_children = category.subcategories.present? + end + + if @options[:parent_category_id].blank? + subcategories = {} + to_delete = Set.new + @categories.each do |c| + if c.parent_category_id.present? + subcategories[c.parent_category_id] ||= [] + subcategories[c.parent_category_id] << c.id + to_delete << c end - @categories.each { |c| c.subcategory_ids = subcategories[c.id] } - @categories.delete_if { |c| to_delete.include?(c) } end + @categories.each { |c| c.subcategory_ids = subcategories[c.id] } + @categories.delete_if { |c| to_delete.include?(c) } + end - if @topics_by_category_id - @categories.each do |c| - topics_in_cat = @topics_by_category_id[c.id] - if topics_in_cat.present? - c.displayable_topics = [] - topics_in_cat.each do |topic_id| - topic = @topics_by_id[topic_id] - if topic.present? && @guardian.can_see?(topic) - # topic.category is very slow under rails 4.2 - topic.association(:category).target = c - c.displayable_topics << topic - end + if @topics_by_category_id + @categories.each do |c| + topics_in_cat = @topics_by_category_id[c.id] + if topics_in_cat.present? + c.displayable_topics = [] + topics_in_cat.each do |topic_id| + topic = @topics_by_id[topic_id] + if topic.present? && @guardian.can_see?(topic) + # topic.category is very slow under rails 4.2 + topic.association(:category).target = c + c.displayable_topics << topic end end end end end + end - def prune_empty - return if SiteSetting.allow_uncategorized_topics - @categories.delete_if { |c| c.uncategorized? && c.displayable_topics.blank? } + def prune_empty + return if SiteSetting.allow_uncategorized_topics + @categories.delete_if { |c| c.uncategorized? && c.displayable_topics.blank? } + end + + # Attach some data for serialization to each topic + def find_user_data + if @guardian.current_user && @all_topics.present? + topic_lookup = TopicUser.lookup_for(@guardian.current_user, @all_topics) + @all_topics.each { |ft| ft.user_data = topic_lookup[ft.id] } end + end - # Attach some data for serialization to each topic - def find_user_data - if @guardian.current_user && @all_topics.present? - topic_lookup = TopicUser.lookup_for(@guardian.current_user, @all_topics) - @all_topics.each { |ft| ft.user_data = topic_lookup[ft.id] } - end - end - - # Put unpinned topics at the end of the list - def sort_unpinned - if @guardian.current_user && @all_topics.present? - @categories.each do |c| - next if c.displayable_topics.blank? || c.displayable_topics.size <= c.num_featured_topics - unpinned = [] - c.displayable_topics.each do |t| - unpinned << t if t.pinned_at && PinnedCheck.unpinned?(t, t.user_data) - end - unless unpinned.empty? - c.displayable_topics = (c.displayable_topics - unpinned) + unpinned - end + # Put unpinned topics at the end of the list + def sort_unpinned + if @guardian.current_user && @all_topics.present? + @categories.each do |c| + next if c.displayable_topics.blank? || c.displayable_topics.size <= c.num_featured_topics + unpinned = [] + c.displayable_topics.each do |t| + unpinned << t if t.pinned_at && PinnedCheck.unpinned?(t, t.user_data) + end + unless unpinned.empty? + c.displayable_topics = (c.displayable_topics - unpinned) + unpinned end end end + end - def trim_results - @categories.each do |c| - next if c.displayable_topics.blank? - c.displayable_topics = c.displayable_topics[0, c.num_featured_topics] - end + def trim_results + @categories.each do |c| + next if c.displayable_topics.blank? + c.displayable_topics = c.displayable_topics[0, c.num_featured_topics] end + end end diff --git a/app/models/concerns/trashable.rb b/app/models/concerns/trashable.rb index 0a8dae3f50..3d79754980 100644 --- a/app/models/concerns/trashable.rb +++ b/app/models/concerns/trashable.rb @@ -45,8 +45,8 @@ module Trashable private - def trash_update(deleted_at, deleted_by_id) - self.update_columns(deleted_at: deleted_at, deleted_by_id: deleted_by_id) - end + def trash_update(deleted_at, deleted_by_id) + self.update_columns(deleted_at: deleted_at, deleted_by_id: deleted_by_id) + end end diff --git a/app/models/embeddable_host.rb b/app/models/embeddable_host.rb index c6f0effbbe..aed2a25362 100644 --- a/app/models/embeddable_host.rb +++ b/app/models/embeddable_host.rb @@ -53,13 +53,13 @@ class EmbeddableHost < ActiveRecord::Base private - def host_must_be_valid - if host !~ /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,10}(:[0-9]{1,5})?(\/.*)?\Z/i && - host !~ /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(:[0-9]{1,5})?(\/.*)?\Z/ && - host !~ /\A([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.)?localhost(\:[0-9]{1,5})?(\/.*)?\Z/i - errors.add(:host, I18n.t('errors.messages.invalid')) - end + def host_must_be_valid + if host !~ /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,10}(:[0-9]{1,5})?(\/.*)?\Z/i && + host !~ /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})(:[0-9]{1,5})?(\/.*)?\Z/ && + host !~ /\A([a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.)?localhost(\:[0-9]{1,5})?(\/.*)?\Z/i + errors.add(:host, I18n.t('errors.messages.invalid')) end + end end # == Schema Information diff --git a/app/models/group.rb b/app/models/group.rb index 1a895775de..fe0c647e39 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -598,58 +598,58 @@ class Group < ActiveRecord::Base protected - def name_format_validator - self.name.strip! + def name_format_validator + self.name.strip! - UsernameValidator.perform_validation(self, 'name') || begin - name_lower = self.name.downcase + UsernameValidator.perform_validation(self, 'name') || begin + name_lower = self.name.downcase - if self.will_save_change_to_name? && self.name_was&.downcase != name_lower - existing = Group.exec_sql( - User::USERNAME_EXISTS_SQL, username: name_lower - ).values.present? + if self.will_save_change_to_name? && self.name_was&.downcase != name_lower + existing = Group.exec_sql( + User::USERNAME_EXISTS_SQL, username: name_lower + ).values.present? - if existing - errors.add(:name, I18n.t("activerecord.errors.messages.taken")) - end + if existing + errors.add(:name, I18n.t("activerecord.errors.messages.taken")) end end end + end - def automatic_membership_email_domains_format_validator - return if self.automatic_membership_email_domains.blank? + def automatic_membership_email_domains_format_validator + return if self.automatic_membership_email_domains.blank? - domains = self.automatic_membership_email_domains.split("|") - domains.each do |domain| - domain.sub!(/^https?:\/\//, '') - domain.sub!(/\/.*$/, '') - self.errors.add :base, (I18n.t('groups.errors.invalid_domain', domain: domain)) unless domain =~ /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,24}(:[0-9]{1,5})?(\/.*)?\Z/i - end - self.automatic_membership_email_domains = domains.join("|") + domains = self.automatic_membership_email_domains.split("|") + domains.each do |domain| + domain.sub!(/^https?:\/\//, '') + domain.sub!(/\/.*$/, '') + self.errors.add :base, (I18n.t('groups.errors.invalid_domain', domain: domain)) unless domain =~ /\A[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,24}(:[0-9]{1,5})?(\/.*)?\Z/i end + self.automatic_membership_email_domains = domains.join("|") + end - # hack around AR - def destroy_deletions - if @deletions - @deletions.each do |gu| - gu.destroy - User.where('id = ? AND primary_group_id = ?', gu.user_id, gu.group_id).update_all 'primary_group_id = NULL' - end - end - @deletions = nil - end - - def automatic_group_membership - if self.automatic_membership_retroactive - Jobs.enqueue(:automatic_group_membership, group_id: self.id) + # hack around AR + def destroy_deletions + if @deletions + @deletions.each do |gu| + gu.destroy + User.where('id = ? AND primary_group_id = ?', gu.user_id, gu.group_id).update_all 'primary_group_id = NULL' end end + @deletions = nil + end - def update_title - return if new_record? && !self.title.present? + def automatic_group_membership + if self.automatic_membership_retroactive + Jobs.enqueue(:automatic_group_membership, group_id: self.id) + end + end - if self.saved_change_to_title? - sql = <<-SQL.squish + def update_title + return if new_record? && !self.title.present? + + if self.saved_change_to_title? + sql = <<-SQL.squish UPDATE users SET title = :title WHERE (title = :title_was OR title = '' OR title IS NULL) @@ -657,71 +657,71 @@ class Group < ActiveRecord::Base AND id IN (SELECT user_id FROM group_users WHERE group_id = :id) SQL - self.class.exec_sql(sql, title: title, title_was: title_before_last_save, id: id) - end + self.class.exec_sql(sql, title: title, title_was: title_before_last_save, id: id) end + end - def update_primary_group - return if new_record? && !self.primary_group? + def update_primary_group + return if new_record? && !self.primary_group? - if self.saved_change_to_primary_group? - sql = <<~SQL + if self.saved_change_to_primary_group? + sql = <<~SQL UPDATE users /*set*/ /*where*/ SQL - builder = SqlBuilder.new(sql) - builder.where(" - id IN ( - SELECT user_id - FROM group_users - WHERE group_id = :id - )", id: id) + builder = SqlBuilder.new(sql) + builder.where(" + id IN ( + SELECT user_id + FROM group_users + WHERE group_id = :id + )", id: id) - if primary_group - builder.set("primary_group_id = :id") - else - builder.set("primary_group_id = NULL") - builder.where("primary_group_id = :id") - end - - builder.exec + if primary_group + builder.set("primary_group_id = :id") + else + builder.set("primary_group_id = NULL") + builder.where("primary_group_id = :id") end + + builder.exec end + end private - def validate_grant_trust_level - unless TrustLevel.valid?(self.grant_trust_level) - self.errors.add(:base, I18n.t( - 'groups.errors.grant_trust_level_not_valid', - trust_level: self.grant_trust_level - )) + def validate_grant_trust_level + unless TrustLevel.valid?(self.grant_trust_level) + self.errors.add(:base, I18n.t( + 'groups.errors.grant_trust_level_not_valid', + trust_level: self.grant_trust_level + )) + end + end + + def can_allow_membership_requests + valid = true + + valid = + if self.persisted? + self.group_users.where(owner: true).exists? + else + self.group_users.any?(&:owner) end + + if !valid + self.errors.add(:base, I18n.t('groups.errors.cant_allow_membership_requests')) end + end - def can_allow_membership_requests - valid = true - - valid = - if self.persisted? - self.group_users.where(owner: true).exists? - else - self.group_users.any?(&:owner) - end - - if !valid - self.errors.add(:base, I18n.t('groups.errors.cant_allow_membership_requests')) - end - end - - def enqueue_update_mentions_job - Jobs.enqueue(:update_group_mentions, - previous_name: self.name_before_last_save, - group_id: self.id - ) - end + def enqueue_update_mentions_job + Jobs.enqueue(:update_group_mentions, + previous_name: self.name_before_last_save, + group_id: self.id + ) + end end # == Schema Information diff --git a/app/models/group_archived_message.rb b/app/models/group_archived_message.rb index 778a3944c1..729ad8b82a 100644 --- a/app/models/group_archived_message.rb +++ b/app/models/group_archived_message.rb @@ -29,11 +29,11 @@ class GroupArchivedMessage < ActiveRecord::Base private - def self.publish_topic_tracking_state(topic) - TopicTrackingState.publish_private_message( - topic, group_archive: true - ) - end + def self.publish_topic_tracking_state(topic) + TopicTrackingState.publish_private_message( + topic, group_archive: true + ) + end end # == Schema Information diff --git a/app/models/post_analyzer.rb b/app/models/post_analyzer.rb index 5d069c72eb..5de5a83f8e 100644 --- a/app/models/post_analyzer.rb +++ b/app/models/post_analyzer.rb @@ -127,19 +127,19 @@ class PostAnalyzer private - def cooked_stripped - @cooked_stripped ||= begin - doc = Nokogiri::HTML.fragment(cook(@raw, topic_id: @topic_id)) - doc.css("pre .mention, aside.quote > .title, aside.quote .mention, .onebox, .elided").remove - doc - end + def cooked_stripped + @cooked_stripped ||= begin + doc = Nokogiri::HTML.fragment(cook(@raw, topic_id: @topic_id)) + doc.css("pre .mention, aside.quote > .title, aside.quote .mention, .onebox, .elided").remove + doc end + end - def link_is_a_mention?(l) - html_class = l['class'] - return false if html_class.blank? - href = l['href'].to_s - html_class.to_s['mention'] && href[/^\/u\//] || href[/^\/users\//] - end + def link_is_a_mention?(l) + html_class = l['class'] + return false if html_class.blank? + href = l['href'].to_s + html_class.to_s['mention'] && href[/^\/u\//] || href[/^\/users\//] + end end diff --git a/app/models/queued_post.rb b/app/models/queued_post.rb index fb4a390f7f..1f2afa75fe 100644 --- a/app/models/queued_post.rb +++ b/app/models/queued_post.rb @@ -94,30 +94,30 @@ class QueuedPost < ActiveRecord::Base private - def change_to!(state, changed_by) - state_val = QueuedPost.states[state] + def change_to!(state, changed_by) + state_val = QueuedPost.states[state] - updates = { state: state_val, - "#{state}_by_id" => changed_by.id, - "#{state}_at" => Time.now } + updates = { state: state_val, + "#{state}_by_id" => changed_by.id, + "#{state}_at" => Time.now } - # We use an update with `row_count` trick here to avoid stampeding requests to - # update the same row simultaneously. Only one state change should go through and - # we can use the DB to enforce this - row_count = QueuedPost.where('id = ? AND state <> ?', id, state_val).update_all(updates) - raise InvalidStateTransition.new if row_count == 0 + # We use an update with `row_count` trick here to avoid stampeding requests to + # update the same row simultaneously. Only one state change should go through and + # we can use the DB to enforce this + row_count = QueuedPost.where('id = ? AND state <> ?', id, state_val).update_all(updates) + raise InvalidStateTransition.new if row_count == 0 - if [:rejected, :approved].include?(state) - UserAction.where(queued_post_id: id).destroy_all - end - - # Update the record in memory too, and clear the dirty flag - updates.each { |k, v| send("#{k}=", v) } - changes_applied - - QueuedPost.broadcast_new! if visible? + if [:rejected, :approved].include?(state) + UserAction.where(queued_post_id: id).destroy_all end + # Update the record in memory too, and clear the dirty flag + updates.each { |k, v| send("#{k}=", v) } + changes_applied + + QueuedPost.broadcast_new! if visible? + end + end # == Schema Information diff --git a/app/models/topic_featured_users.rb b/app/models/topic_featured_users.rb index d3f705149b..d8a8a406cb 100644 --- a/app/models/topic_featured_users.rb +++ b/app/models/topic_featured_users.rb @@ -84,8 +84,8 @@ SQL private - def update_participant_count - count = topic.posts.where('NOT hidden AND post_type in (?)', Topic.visible_post_types).count('distinct user_id') - topic.update_columns(participant_count: count) - end + def update_participant_count + count = topic.posts.where('NOT hidden AND post_type in (?)', Topic.visible_post_types).count('distinct user_id') + topic.update_columns(participant_count: count) + end end diff --git a/app/models/topic_timer.rb b/app/models/topic_timer.rb index 39f882dbaf..e481ec1b26 100644 --- a/app/models/topic_timer.rb +++ b/app/models/topic_timer.rb @@ -83,66 +83,66 @@ class TopicTimer < ActiveRecord::Base private - def ensure_update_will_happen - if created_at && (execute_at < created_at) - errors.add(:execute_at, I18n.t( - 'activerecord.errors.models.topic_timer.attributes.execute_at.in_the_past' - )) - end + def ensure_update_will_happen + if created_at && (execute_at < created_at) + errors.add(:execute_at, I18n.t( + 'activerecord.errors.models.topic_timer.attributes.execute_at.in_the_past' + )) end + end - def cancel_auto_close_job - Jobs.cancel_scheduled_job(:toggle_topic_closed, topic_timer_id: id) - end - alias_method :cancel_auto_open_job, :cancel_auto_close_job + def cancel_auto_close_job + Jobs.cancel_scheduled_job(:toggle_topic_closed, topic_timer_id: id) + end + alias_method :cancel_auto_open_job, :cancel_auto_close_job - def cancel_auto_publish_to_category_job - Jobs.cancel_scheduled_job(:publish_topic_to_category, topic_timer_id: id) - end + def cancel_auto_publish_to_category_job + Jobs.cancel_scheduled_job(:publish_topic_to_category, topic_timer_id: id) + end - def cancel_auto_delete_job - Jobs.cancel_scheduled_job(:delete_topic, topic_timer_id: id) - end + def cancel_auto_delete_job + Jobs.cancel_scheduled_job(:delete_topic, topic_timer_id: id) + end - def cancel_auto_reminder_job - Jobs.cancel_scheduled_job(:topic_reminder, topic_timer_id: id) - end + def cancel_auto_reminder_job + Jobs.cancel_scheduled_job(:topic_reminder, topic_timer_id: id) + end - def schedule_auto_open_job(time) - return unless topic - topic.update_status('closed', true, user) if !topic.closed + def schedule_auto_open_job(time) + return unless topic + topic.update_status('closed', true, user) if !topic.closed - Jobs.enqueue_at(time, :toggle_topic_closed, - topic_timer_id: id, - state: false - ) - end + Jobs.enqueue_at(time, :toggle_topic_closed, + topic_timer_id: id, + state: false + ) + end - def schedule_auto_close_job(time) - return unless topic - topic.update_status('closed', false, user) if topic.closed + def schedule_auto_close_job(time) + return unless topic + topic.update_status('closed', false, user) if topic.closed - Jobs.enqueue_at(time, :toggle_topic_closed, - topic_timer_id: id, - state: true - ) - end + Jobs.enqueue_at(time, :toggle_topic_closed, + topic_timer_id: id, + state: true + ) + end - def schedule_auto_publish_to_category_job(time) - Jobs.enqueue_at(time, :publish_topic_to_category, topic_timer_id: id) - end + def schedule_auto_publish_to_category_job(time) + Jobs.enqueue_at(time, :publish_topic_to_category, topic_timer_id: id) + end - def publishing_to_category? - self.status_type.to_i == TopicTimer.types[:publish_to_category] - end + def publishing_to_category? + self.status_type.to_i == TopicTimer.types[:publish_to_category] + end - def schedule_auto_delete_job(time) - Jobs.enqueue_at(time, :delete_topic, topic_timer_id: id) - end + def schedule_auto_delete_job(time) + Jobs.enqueue_at(time, :delete_topic, topic_timer_id: id) + end - def schedule_auto_reminder_job(time) - Jobs.enqueue_at(time, :topic_reminder, topic_timer_id: id) - end + def schedule_auto_reminder_job(time) + Jobs.enqueue_at(time, :topic_reminder, topic_timer_id: id) + end end # == Schema Information diff --git a/app/models/unsubscribe_key.rb b/app/models/unsubscribe_key.rb index 967d8f34a1..7f5ee933cb 100644 --- a/app/models/unsubscribe_key.rb +++ b/app/models/unsubscribe_key.rb @@ -19,9 +19,9 @@ class UnsubscribeKey < ActiveRecord::Base private - def generate_random_key - self.key = SecureRandom.hex(32) - end + def generate_random_key + self.key = SecureRandom.hex(32) + end end # == Schema Information diff --git a/app/models/user_archived_message.rb b/app/models/user_archived_message.rb index 1edd3863c4..6c2c604042 100644 --- a/app/models/user_archived_message.rb +++ b/app/models/user_archived_message.rb @@ -36,11 +36,11 @@ class UserArchivedMessage < ActiveRecord::Base private - def self.publish_topic_tracking_state(topic, user_id) - TopicTrackingState.publish_private_message( - topic, archive_user_id: user_id - ) - end + def self.publish_topic_tracking_state(topic, user_id) + TopicTrackingState.publish_private_message( + topic, archive_user_id: user_id + ) + end end # == Schema Information diff --git a/app/models/user_badge.rb b/app/models/user_badge.rb index 53979ec9cf..b0b4ce354c 100644 --- a/app/models/user_badge.rb +++ b/app/models/user_badge.rb @@ -26,9 +26,9 @@ class UserBadge < ActiveRecord::Base private - def single_grant_badge? - self.badge.single_grant? - end + def single_grant_badge? + self.badge.single_grant? + end end # == Schema Information diff --git a/app/models/user_option.rb b/app/models/user_option.rb index 828ac58c60..5077d8dc36 100644 --- a/app/models/user_option.rb +++ b/app/models/user_option.rb @@ -141,10 +141,10 @@ class UserOption < ActiveRecord::Base private - def update_tracked_topics - return unless saved_change_to_auto_track_topics_after_msecs? - TrackedTopicsUpdater.new(id, auto_track_topics_after_msecs).call - end + def update_tracked_topics + return unless saved_change_to_auto_track_topics_after_msecs? + TrackedTopicsUpdater.new(id, auto_track_topics_after_msecs).call + end end diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb index c2c016741e..8bea527b71 100644 --- a/app/models/web_hook.rb +++ b/app/models/web_hook.rb @@ -93,9 +93,9 @@ class WebHook < ActiveRecord::Base private - def self.guardian - @guardian ||= Guardian.new(Discourse.system_user) - end + def self.guardian + @guardian ||= Guardian.new(Discourse.system_user) + end end # == Schema Information diff --git a/app/serializers/admin_user_action_serializer.rb b/app/serializers/admin_user_action_serializer.rb index dfe2cbc631..4bc1db5f5a 100644 --- a/app/serializers/admin_user_action_serializer.rb +++ b/app/serializers/admin_user_action_serializer.rb @@ -81,12 +81,12 @@ class AdminUserActionSerializer < ApplicationSerializer private - # we need this to handle deleted topics which aren't loaded via the .includes(:topic) - # because Rails 4 "unscoped" support is bugged (cf. https://github.com/rails/rails/issues/13775) - def topic - return @topic if @topic - @topic = object.topic || Topic.with_deleted.find(object.topic_id) - @topic - end + # we need this to handle deleted topics which aren't loaded via the .includes(:topic) + # because Rails 4 "unscoped" support is bugged (cf. https://github.com/rails/rails/issues/13775) + def topic + return @topic if @topic + @topic = object.topic || Topic.with_deleted.find(object.topic_id) + @topic + end end diff --git a/app/serializers/basic_group_serializer.rb b/app/serializers/basic_group_serializer.rb index 26fb3ea2de..6ac6f23b49 100644 --- a/app/serializers/basic_group_serializer.rb +++ b/app/serializers/basic_group_serializer.rb @@ -68,15 +68,15 @@ class BasicGroupSerializer < ApplicationSerializer private - def staff? - @staff ||= scope.is_staff? - end + def staff? + @staff ||= scope.is_staff? + end - def user_group_ids - @options[:user_group_ids] - end + def user_group_ids + @options[:user_group_ids] + end - def owner_group_ids - @options[:owner_group_ids] - end + def owner_group_ids + @options[:owner_group_ids] + end end diff --git a/app/serializers/listable_topic_serializer.rb b/app/serializers/listable_topic_serializer.rb index aeecddbeae..40b29f6383 100644 --- a/app/serializers/listable_topic_serializer.rb +++ b/app/serializers/listable_topic_serializer.rb @@ -121,8 +121,8 @@ class ListableTopicSerializer < BasicTopicSerializer protected - def unread_helper - @unread_helper ||= Unread.new(object, object.user_data, scope) - end + def unread_helper + @unread_helper ||= Unread.new(object, object.user_data, scope) + end end diff --git a/app/serializers/post_action_type_serializer.rb b/app/serializers/post_action_type_serializer.rb index 718c84a5b7..9ea2847e9a 100644 --- a/app/serializers/post_action_type_serializer.rb +++ b/app/serializers/post_action_type_serializer.rb @@ -45,9 +45,9 @@ class PostActionTypeSerializer < ApplicationSerializer protected - def i18n(field, vars = nil) - key = "post_action_types.#{name_key}.#{field}" - vars ? I18n.t(key, vars) : I18n.t(key) - end + def i18n(field, vars = nil) + key = "post_action_types.#{name_key}.#{field}" + vars ? I18n.t(key, vars) : I18n.t(key) + end end diff --git a/app/serializers/post_revision_serializer.rb b/app/serializers/post_revision_serializer.rb index e8c7e9f16e..6bfb7dbb03 100644 --- a/app/serializers/post_revision_serializer.rb +++ b/app/serializers/post_revision_serializer.rb @@ -173,94 +173,94 @@ class PostRevisionSerializer < ApplicationSerializer protected - def post - @post ||= object.post + def post + @post ||= object.post + end + + def topic + @topic ||= object.post.topic + end + + def revisions + @revisions ||= all_revisions.select { |r| scope.can_view_hidden_post_revisions? || !r["hidden"] } + end + + def all_revisions + return @all_revisions if @all_revisions + + post_revisions = PostRevision.where(post_id: object.post_id).order(:number).to_a + + latest_modifications = { + "raw" => [post.raw], + "cooked" => [post.cooked], + "edit_reason" => [post.edit_reason], + "wiki" => [post.wiki], + "post_type" => [post.post_type], + "user_id" => [post.user_id] + } + + # Retrieve any `tracked_topic_fields` + PostRevisor.tracked_topic_fields.each_key do |field| + latest_modifications[field.to_s] = [topic.send(field)] if topic.respond_to?(field) end - def topic - @topic ||= object.post.topic - end + latest_modifications["featured_link"] = [post.topic.featured_link] if SiteSetting.topic_featured_link_enabled + latest_modifications["tags"] = [topic.tags.pluck(:name)] if scope.can_see_tags?(topic) - def revisions - @revisions ||= all_revisions.select { |r| scope.can_view_hidden_post_revisions? || !r["hidden"] } - end + post_revisions << PostRevision.new( + number: post_revisions.last.number + 1, + hidden: post.hidden, + modifications: latest_modifications + ) - def all_revisions - return @all_revisions if @all_revisions + @all_revisions = [] - post_revisions = PostRevision.where(post_id: object.post_id).order(:number).to_a + # backtrack + post_revisions.each do |pr| + revision = HashWithIndifferentAccess.new + revision[:revision] = pr.number + revision[:hidden] = pr.hidden - latest_modifications = { - "raw" => [post.raw], - "cooked" => [post.cooked], - "edit_reason" => [post.edit_reason], - "wiki" => [post.wiki], - "post_type" => [post.post_type], - "user_id" => [post.user_id] - } - - # Retrieve any `tracked_topic_fields` - PostRevisor.tracked_topic_fields.each_key do |field| - latest_modifications[field.to_s] = [topic.send(field)] if topic.respond_to?(field) + pr.modifications.each_key do |field| + revision[field] = pr.modifications[field][0] end - latest_modifications["featured_link"] = [post.topic.featured_link] if SiteSetting.topic_featured_link_enabled - latest_modifications["tags"] = [topic.tags.pluck(:name)] if scope.can_see_tags?(topic) - - post_revisions << PostRevision.new( - number: post_revisions.last.number + 1, - hidden: post.hidden, - modifications: latest_modifications - ) - - @all_revisions = [] - - # backtrack - post_revisions.each do |pr| - revision = HashWithIndifferentAccess.new - revision[:revision] = pr.number - revision[:hidden] = pr.hidden - - pr.modifications.each_key do |field| - revision[field] = pr.modifications[field][0] - end - - @all_revisions << revision - end - - # waterfall - (@all_revisions.count - 1).downto(1).each do |r| - cur = @all_revisions[r] - prev = @all_revisions[r - 1] - - cur.each_key do |field| - prev[field] = prev.has_key?(field) ? prev[field] : cur[field] - end - end - - @all_revisions + @all_revisions << revision end - def previous - @previous ||= revisions.select { |r| r["revision"] <= current_revision }.last - end + # waterfall + (@all_revisions.count - 1).downto(1).each do |r| + cur = @all_revisions[r] + prev = @all_revisions[r - 1] - def current - @current ||= revisions.select { |r| r["revision"] > current_revision }.first - end - - def user - # if stuff goes pear shape attribute to system - object.user || Discourse.system_user - end - - def filter_visible_tags(tags) - if tags.is_a?(Array) && tags.size > 0 - @hidden_tag_names ||= DiscourseTagging.hidden_tag_names(scope) - tags - @hidden_tag_names - else - tags + cur.each_key do |field| + prev[field] = prev.has_key?(field) ? prev[field] : cur[field] end end + @all_revisions + end + + def previous + @previous ||= revisions.select { |r| r["revision"] <= current_revision }.last + end + + def current + @current ||= revisions.select { |r| r["revision"] > current_revision }.first + end + + def user + # if stuff goes pear shape attribute to system + object.user || Discourse.system_user + end + + def filter_visible_tags(tags) + if tags.is_a?(Array) && tags.size > 0 + @hidden_tag_names ||= DiscourseTagging.hidden_tag_names(scope) + tags - @hidden_tag_names + else + tags + end + end + end diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb index e66fa720fd..d389cecafe 100644 --- a/app/serializers/post_serializer.rb +++ b/app/serializers/post_serializer.rb @@ -380,26 +380,26 @@ class PostSerializer < BasicPostSerializer private - def topic - @topic = object.topic - @topic ||= Topic.with_deleted.find(object.topic_id) if scope.is_staff? - @topic - end + def topic + @topic = object.topic + @topic ||= Topic.with_deleted.find(object.topic_id) if scope.is_staff? + @topic + end - def post_actions - @post_actions ||= (@topic_view&.all_post_actions || {})[object.id] - end + def post_actions + @post_actions ||= (@topic_view&.all_post_actions || {})[object.id] + end - def active_flags - @active_flags ||= (@topic_view&.all_active_flags || {})[object.id] - end + def active_flags + @active_flags ||= (@topic_view&.all_active_flags || {})[object.id] + end - def post_custom_fields - @post_custom_fields ||= if @topic_view - (@topic_view.post_custom_fields || {})[object.id] || {} - else - object.custom_fields - end + def post_custom_fields + @post_custom_fields ||= if @topic_view + (@topic_view.post_custom_fields || {})[object.id] || {} + else + object.custom_fields end + end end diff --git a/app/serializers/topic_flag_type_serializer.rb b/app/serializers/topic_flag_type_serializer.rb index c0ac6951bd..4caa98a698 100644 --- a/app/serializers/topic_flag_type_serializer.rb +++ b/app/serializers/topic_flag_type_serializer.rb @@ -2,9 +2,9 @@ class TopicFlagTypeSerializer < PostActionTypeSerializer protected - def i18n(field, vars = nil) - key = "topic_flag_types.#{name_key}.#{field}" - vars ? I18n.t(key, vars) : I18n.t(key) - end + def i18n(field, vars = nil) + key = "topic_flag_types.#{name_key}.#{field}" + vars ? I18n.t(key, vars) : I18n.t(key) + end end diff --git a/app/serializers/topic_view_serializer.rb b/app/serializers/topic_view_serializer.rb index 44479aa7e0..9475da548a 100644 --- a/app/serializers/topic_view_serializer.rb +++ b/app/serializers/topic_view_serializer.rb @@ -301,8 +301,8 @@ class TopicViewSerializer < ApplicationSerializer private - def private_message?(topic) - @private_message ||= topic.private_message? - end + def private_message?(topic) + @private_message ||= topic.private_message? + end end diff --git a/app/services/group_action_logger.rb b/app/services/group_action_logger.rb index 58674016c3..bcd5e56908 100644 --- a/app/services/group_action_logger.rb +++ b/app/services/group_action_logger.rb @@ -58,21 +58,21 @@ class GroupActionLogger private - def excluded_attributes - [ - :bio_cooked, - :updated_at, - :created_at, - :user_count - ] - end + def excluded_attributes + [ + :bio_cooked, + :updated_at, + :created_at, + :user_count + ] + end - def default_params - { group: @group, acting_user: @acting_user } - end + def default_params + { group: @group, acting_user: @acting_user } + end - def can_edit? - raise Discourse::InvalidParameters.new unless Guardian.new(@acting_user).can_log_group_changes?(@group) - end + def can_edit? + raise Discourse::InvalidParameters.new unless Guardian.new(@acting_user).can_log_group_changes?(@group) + end end diff --git a/app/services/staff_action_logger.rb b/app/services/staff_action_logger.rb index f9205e075e..d836073580 100644 --- a/app/services/staff_action_logger.rb +++ b/app/services/staff_action_logger.rb @@ -550,13 +550,13 @@ class StaffActionLogger private - def params(opts = nil) - opts ||= {} - { acting_user_id: @admin.id, context: opts[:context] } - end + def params(opts = nil) + opts ||= {} + { acting_user_id: @admin.id, context: opts[:context] } + end - def validate_category(category) - raise Discourse::InvalidParameters.new(:category) unless category && category.is_a?(Category) - end + def validate_category(category) + raise Discourse::InvalidParameters.new(:category) unless category && category.is_a?(Category) + end end diff --git a/app/services/user_anonymizer.rb b/app/services/user_anonymizer.rb index 7184f1ac87..45fd0f341d 100644 --- a/app/services/user_anonymizer.rb +++ b/app/services/user_anonymizer.rb @@ -77,13 +77,13 @@ class UserAnonymizer private - def make_anon_username - 100.times do - new_username = "anon#{(SecureRandom.random_number * 100000000).to_i}" - return new_username unless User.where(username_lower: new_username).exists? - end - raise "Failed to generate an anon username" + def make_anon_username + 100.times do + new_username = "anon#{(SecureRandom.random_number * 100000000).to_i}" + return new_username unless User.where(username_lower: new_username).exists? end + raise "Failed to generate an anon username" + end def ip_where(column = 'user_id') ["#{column} = :user_id AND ip_address IS NOT NULL", user_id: @user.id] diff --git a/lib/auth/facebook_authenticator.rb b/lib/auth/facebook_authenticator.rb index 50e717d739..f4ea2f1b85 100644 --- a/lib/auth/facebook_authenticator.rb +++ b/lib/auth/facebook_authenticator.rb @@ -63,58 +63,58 @@ class Auth::FacebookAuthenticator < Auth::Authenticator protected - def parse_auth_token(auth_token) - raw_info = auth_token["extra"]["raw_info"] - info = auth_token["info"] + def parse_auth_token(auth_token) + raw_info = auth_token["extra"]["raw_info"] + info = auth_token["info"] - email = auth_token["info"][:email] + email = auth_token["info"][:email] - website = (info["urls"] && info["urls"]["Website"]) || nil + website = (info["urls"] && info["urls"]["Website"]) || nil - { - facebook: { - facebook_user_id: auth_token["uid"], - link: raw_info["link"], - username: raw_info["username"], - first_name: raw_info["first_name"], - last_name: raw_info["last_name"], - email: email, - gender: raw_info["gender"], - name: raw_info["name"], - avatar_url: info["image"], - location: info["location"], - website: website, - about_me: info["description"] - }, + { + facebook: { + facebook_user_id: auth_token["uid"], + link: raw_info["link"], + username: raw_info["username"], + first_name: raw_info["first_name"], + last_name: raw_info["last_name"], email: email, - email_valid: true - } + gender: raw_info["gender"], + name: raw_info["name"], + avatar_url: info["image"], + location: info["location"], + website: website, + about_me: info["description"] + }, + email: email, + email_valid: true + } + end + + def retrieve_avatar(user, data) + return unless user + return if user.user_avatar.try(:custom_upload_id).present? + + if (avatar_url = data[:avatar_url]).present? + url = "#{avatar_url}?height=#{AVATAR_SIZE}&width=#{AVATAR_SIZE}" + Jobs.enqueue(:download_avatar_from_url, url: url, user_id: user.id, override_gravatar: false) end + end - def retrieve_avatar(user, data) - return unless user - return if user.user_avatar.try(:custom_upload_id).present? + def retrieve_profile(user, data) + return unless user - if (avatar_url = data[:avatar_url]).present? - url = "#{avatar_url}?height=#{AVATAR_SIZE}&width=#{AVATAR_SIZE}" - Jobs.enqueue(:download_avatar_from_url, url: url, user_id: user.id, override_gravatar: false) - end - end - - def retrieve_profile(user, data) - return unless user - - bio = data[:about_me] || data[:about] - location = data[:location] - website = data[:website] - - if bio || location || website - profile = user.user_profile - profile.bio_raw = bio unless profile.bio_raw.present? - profile.location = location unless profile.location.present? - profile.website = website unless profile.website.present? - profile.save - end + bio = data[:about_me] || data[:about] + location = data[:location] + website = data[:website] + + if bio || location || website + profile = user.user_profile + profile.bio_raw = bio unless profile.bio_raw.present? + profile.location = location unless profile.location.present? + profile.website = website unless profile.website.present? + profile.save end + end end diff --git a/lib/auth/twitter_authenticator.rb b/lib/auth/twitter_authenticator.rb index 36a16b1cf9..b4ef82d9eb 100644 --- a/lib/auth/twitter_authenticator.rb +++ b/lib/auth/twitter_authenticator.rb @@ -69,28 +69,28 @@ class Auth::TwitterAuthenticator < Auth::Authenticator protected - def retrieve_avatar(user, data) - return unless user - return if user.user_avatar.try(:custom_upload_id).present? + def retrieve_avatar(user, data) + return unless user + return if user.user_avatar.try(:custom_upload_id).present? - if (avatar_url = data[:twitter_image]).present? - url = avatar_url.sub("_normal", "") - Jobs.enqueue(:download_avatar_from_url, url: url, user_id: user.id, override_gravatar: false) - end + if (avatar_url = data[:twitter_image]).present? + url = avatar_url.sub("_normal", "") + Jobs.enqueue(:download_avatar_from_url, url: url, user_id: user.id, override_gravatar: false) end + end - def retrieve_profile(user, data) - return unless user + def retrieve_profile(user, data) + return unless user - bio = data[:twitter_description] - location = data[:twitter_location] + bio = data[:twitter_description] + location = data[:twitter_location] - if bio || location - profile = user.user_profile - profile.bio_raw = bio unless profile.bio_raw.present? - profile.location = location unless profile.location.present? - profile.save - end + if bio || location + profile = user.user_profile + profile.bio_raw = bio unless profile.bio_raw.present? + profile.location = location unless profile.location.present? + profile.save end + end end diff --git a/lib/common_passwords/common_passwords.rb b/lib/common_passwords/common_passwords.rb index 0045cc8a36..bec6fca43f 100644 --- a/lib/common_passwords/common_passwords.rb +++ b/lib/common_passwords/common_passwords.rb @@ -23,32 +23,32 @@ class CommonPasswords private - class RedisPasswordList - def include?(password) - CommonPasswords.redis.sismember CommonPasswords::LIST_KEY, password - end + class RedisPasswordList + def include?(password) + CommonPasswords.redis.sismember CommonPasswords::LIST_KEY, password end + end - def self.password_list - @mutex.synchronize do - load_passwords unless redis.scard(LIST_KEY) > 0 - end - RedisPasswordList.new + def self.password_list + @mutex.synchronize do + load_passwords unless redis.scard(LIST_KEY) > 0 end + RedisPasswordList.new + end - def self.redis - $redis.without_namespace - end + def self.redis + $redis.without_namespace + end - def self.load_passwords - passwords = File.readlines(PASSWORD_FILE) - passwords.map!(&:chomp).each do |pwd| - # slower, but a tad more compatible - redis.sadd LIST_KEY, pwd - end - rescue Errno::ENOENT - # tolerate this so we don't block signups - Rails.logger.error "Common passwords file #{PASSWORD_FILE} is not found! Common password checking is skipped." + def self.load_passwords + passwords = File.readlines(PASSWORD_FILE) + passwords.map!(&:chomp).each do |pwd| + # slower, but a tad more compatible + redis.sadd LIST_KEY, pwd end + rescue Errno::ENOENT + # tolerate this so we don't block signups + Rails.logger.error "Common passwords file #{PASSWORD_FILE} is not found! Common password checking is skipped." + end end diff --git a/lib/composer_messages_finder.rb b/lib/composer_messages_finder.rb index 76c582dd57..a539df7065 100644 --- a/lib/composer_messages_finder.rb +++ b/lib/composer_messages_finder.rb @@ -193,20 +193,20 @@ class ComposerMessagesFinder private - def educate_reply?(type) - replying? && - @details[:topic_id] && - (@topic.present? && !@topic.private_message?) && - (@user.post_count >= SiteSetting.educate_until_posts) && - !UserHistory.exists_for_user?(@user, type, topic_id: @details[:topic_id]) - end + def educate_reply?(type) + replying? && + @details[:topic_id] && + (@topic.present? && !@topic.private_message?) && + (@user.post_count >= SiteSetting.educate_until_posts) && + !UserHistory.exists_for_user?(@user, type, topic_id: @details[:topic_id]) + end - def creating_topic? - @details[:composer_action] == "createTopic" - end + def creating_topic? + @details[:composer_action] == "createTopic" + end - def replying? - @details[:composer_action] == "reply" - end + def replying? + @details[:composer_action] == "reply" + end end diff --git a/lib/email_updater.rb b/lib/email_updater.rb index d3d8eaf339..dd7670f75b 100644 --- a/lib/email_updater.rb +++ b/lib/email_updater.rb @@ -104,19 +104,19 @@ class EmailUpdater protected - def notify_old(old_email, new_email) - Jobs.enqueue :critical_user_email, - to_address: old_email, - type: :notify_old_email, - user_id: @user.id - end + def notify_old(old_email, new_email) + Jobs.enqueue :critical_user_email, + to_address: old_email, + type: :notify_old_email, + user_id: @user.id + end - def send_email(type, email_token) - Jobs.enqueue :critical_user_email, - to_address: email_token.email, - type: type, - user_id: @user.id, - email_token: email_token.token - end + def send_email(type, email_token) + Jobs.enqueue :critical_user_email, + to_address: email_token.email, + type: type, + user_id: @user.id, + email_token: email_token.token + end end diff --git a/lib/file_helper.rb b/lib/file_helper.rb index 7ef5952390..4fc4df68e4 100644 --- a/lib/file_helper.rb +++ b/lib/file_helper.rb @@ -96,12 +96,12 @@ class FileHelper private - def self.images - @@images ||= Set.new %w{jpg jpeg png gif tif tiff bmp svg webp ico} - end + def self.images + @@images ||= Set.new %w{jpg jpeg png gif tif tiff bmp svg webp ico} + end - def self.images_regexp - @@images_regexp ||= /\.(#{images.to_a.join("|")})$/i - end + def self.images_regexp + @@images_regexp ||= /\.(#{images.to_a.join("|")})$/i + end end diff --git a/lib/flag_query.rb b/lib/flag_query.rb index 11db2aa887..1d833200d8 100644 --- a/lib/flag_query.rb +++ b/lib/flag_query.rb @@ -224,14 +224,14 @@ module FlagQuery private - def self.excerpt(cooked) - excerpt = Post.excerpt(cooked, 200, keep_emoji_images: true) - # remove the first link if it's the first node - fragment = Nokogiri::HTML.fragment(excerpt) - if fragment.children.first == fragment.css("a:first").first && fragment.children.first - fragment.children.first.remove - end - fragment.to_html.strip + def self.excerpt(cooked) + excerpt = Post.excerpt(cooked, 200, keep_emoji_images: true) + # remove the first link if it's the first node + fragment = Nokogiri::HTML.fragment(excerpt) + if fragment.children.first == fragment.css("a:first").first && fragment.children.first + fragment.children.first.remove end + fragment.to_html.strip + end end diff --git a/lib/freedom_patches/rack_patches.rb b/lib/freedom_patches/rack_patches.rb index 890435d9b9..4cdc2dce11 100644 --- a/lib/freedom_patches/rack_patches.rb +++ b/lib/freedom_patches/rack_patches.rb @@ -3,40 +3,40 @@ class Rack::ETag private - def digest_body(body) - parts = [] - has_body = false + def digest_body(body) + parts = [] + has_body = false - body.each do |part| - parts << part - has_body ||= part.length > 0 - end + body.each do |part| + parts << part + has_body ||= part.length > 0 + end - hexdigest = - if has_body - digest = Digest::MD5.new - parts.each { |part| digest << part } - digest.hexdigest - end + hexdigest = + if has_body + digest = Digest::MD5.new + parts.each { |part| digest << part } + digest.hexdigest + end - [hexdigest, parts] - end + [hexdigest, parts] + end end # patch https://github.com/rack/rack/pull/596 # class Rack::ConditionalGet private - def to_rfc2822(since) - # shortest possible valid date is the obsolete: 1 Nov 97 09:55 A - # anything shorter is invalid, this avoids exceptions for common cases - # most common being the empty string - if since && since.length >= 16 - # NOTE: there is no trivial way to write this in a non execption way - # _rfc2822 returns a hash but is not that usable - Time.rfc2822(since) rescue nil - else - nil - end - end + def to_rfc2822(since) + # shortest possible valid date is the obsolete: 1 Nov 97 09:55 A + # anything shorter is invalid, this avoids exceptions for common cases + # most common being the empty string + if since && since.length >= 16 + # NOTE: there is no trivial way to write this in a non execption way + # _rfc2822 returns a hash but is not that usable + Time.rfc2822(since) rescue nil + else + nil + end + end end diff --git a/lib/i18n/backend/discourse_i18n.rb b/lib/i18n/backend/discourse_i18n.rb index 1f33dd60e0..fec8150c79 100644 --- a/lib/i18n/backend/discourse_i18n.rb +++ b/lib/i18n/backend/discourse_i18n.rb @@ -52,54 +52,54 @@ module I18n protected - def find_results(regexp, results, translations, path = nil) - return results if translations.blank? + def find_results(regexp, results, translations, path = nil) + return results if translations.blank? - translations.each do |k_sym, v| - k = k_sym.to_s - key_path = path ? "#{path}.#{k}" : k - if v.is_a?(String) - unless results.has_key?(key_path) - results[key_path] = v if key_path =~ regexp || v =~ regexp - end - elsif v.is_a?(Hash) - find_results(regexp, results, v, key_path) + translations.each do |k_sym, v| + k = k_sym.to_s + key_path = path ? "#{path}.#{k}" : k + if v.is_a?(String) + unless results.has_key?(key_path) + results[key_path] = v if key_path =~ regexp || v =~ regexp end + elsif v.is_a?(Hash) + find_results(regexp, results, v, key_path) end - results end + results + end - # Support interpolation and pluralization of overrides by first looking up - # the original translations before applying our overrides. - def lookup(locale, key, scope = [], options = {}) - existing_translations = super(locale, key, scope, options) - return existing_translations if scope.is_a?(Array) && scope.include?(:models) + # Support interpolation and pluralization of overrides by first looking up + # the original translations before applying our overrides. + def lookup(locale, key, scope = [], options = {}) + existing_translations = super(locale, key, scope, options) + return existing_translations if scope.is_a?(Array) && scope.include?(:models) - overrides = options.dig(:overrides, locale) + overrides = options.dig(:overrides, locale) - if overrides - if existing_translations && options[:count] - remapped_translations = - if existing_translations.is_a?(Hash) - Hash[existing_translations.map { |k, v| ["#{key}.#{k}", v] }] - elsif existing_translations.is_a?(String) - Hash[[[key, existing_translations]]] - end - - result = {} - - remapped_translations.merge(overrides).each do |k, v| - result[k.split('.').last.to_sym] = v if k != key && k.start_with?(key.to_s) + if overrides + if existing_translations && options[:count] + remapped_translations = + if existing_translations.is_a?(Hash) + Hash[existing_translations.map { |k, v| ["#{key}.#{k}", v] }] + elsif existing_translations.is_a?(String) + Hash[[[key, existing_translations]]] end - return result if result.size > 0 - end - return overrides[key] if overrides[key] + result = {} + + remapped_translations.merge(overrides).each do |k, v| + result[k.split('.').last.to_sym] = v if k != key && k.start_with?(key.to_s) + end + return result if result.size > 0 end - existing_translations + return overrides[key] if overrides[key] end + existing_translations + end + end end end diff --git a/lib/i18n/duplicate_key_finder.rb b/lib/i18n/duplicate_key_finder.rb index 745b5ce293..f23221d13e 100644 --- a/lib/i18n/duplicate_key_finder.rb +++ b/lib/i18n/duplicate_key_finder.rb @@ -10,8 +10,8 @@ class DuplicateKeyFinder < LocaleFileWalker protected - def handle_scalar(node, depth, parents) - super - @keys_with_count[parents.join('.')] += 1 - end + def handle_scalar(node, depth, parents) + super + @keys_with_count[parents.join('.')] += 1 + end end diff --git a/lib/inline_oneboxer.rb b/lib/inline_oneboxer.rb index aafe3b338c..7e1ccfa29f 100644 --- a/lib/inline_oneboxer.rb +++ b/lib/inline_oneboxer.rb @@ -63,20 +63,20 @@ class InlineOneboxer private - def self.onebox_for(url, title, opts) - onebox = { - url: url, - title: title && Emoji.gsub_emoji_to_unicode(title) - } - unless opts[:skip_cache] - Rails.cache.write(cache_key(url), onebox, expires_in: 1.day) - end - - onebox + def self.onebox_for(url, title, opts) + onebox = { + url: url, + title: title && Emoji.gsub_emoji_to_unicode(title) + } + unless opts[:skip_cache] + Rails.cache.write(cache_key(url), onebox, expires_in: 1.day) end - def self.cache_key(url) - "inline_onebox:#{url}" - end + onebox + end + + def self.cache_key(url) + "inline_onebox:#{url}" + end end diff --git a/lib/onebox/engine/whitelisted_generic_onebox.rb b/lib/onebox/engine/whitelisted_generic_onebox.rb index f48ad2f214..64b22dae9c 100644 --- a/lib/onebox/engine/whitelisted_generic_onebox.rb +++ b/lib/onebox/engine/whitelisted_generic_onebox.rb @@ -16,22 +16,22 @@ module Onebox private - # overwrite to whitelist iframes - def is_embedded? - return false unless data[:html] && data[:height] - return true if WhitelistedGenericOnebox.html_providers.include?(data[:provider_name]) + # overwrite to whitelist iframes + def is_embedded? + return false unless data[:html] && data[:height] + return true if WhitelistedGenericOnebox.html_providers.include?(data[:provider_name]) - if data[:html]["iframe"] - fragment = Nokogiri::HTML::fragment(data[:html]) - if iframe = fragment.at_css("iframe") - src = iframe["src"] - return src.present? && SiteSetting.allowed_iframes.split("|").any? { |url| src.start_with?(url) } - end + if data[:html]["iframe"] + fragment = Nokogiri::HTML::fragment(data[:html]) + if iframe = fragment.at_css("iframe") + src = iframe["src"] + return src.present? && SiteSetting.allowed_iframes.split("|").any? { |url| src.start_with?(url) } end - - false end + false + end + end end end diff --git a/lib/oneboxer.rb b/lib/oneboxer.rb index dc5b649157..2f99c0f814 100644 --- a/lib/oneboxer.rb +++ b/lib/oneboxer.rb @@ -125,151 +125,151 @@ module Oneboxer private - def self.preview_key(user_id) - "onebox:preview:#{user_id}" - end + def self.preview_key(user_id) + "onebox:preview:#{user_id}" + end - def self.blank_onebox - { preview: "", onebox: "" } - end + def self.blank_onebox + { preview: "", onebox: "" } + end - def self.onebox_cache_key(url) - "onebox__#{url}" - end + def self.onebox_cache_key(url) + "onebox__#{url}" + end - def self.onebox_raw(url, opts = {}) - url = URI(url).to_s - local_onebox(url, opts) || external_onebox(url) - rescue => e - # no point warning here, just cause we have an issue oneboxing a url - # we can later hunt for failed oneboxes by searching logs if needed - Rails.logger.info("Failed to onebox #{url} #{e} #{e.backtrace}") - # return a blank hash, so rest of the code works - blank_onebox - end + def self.onebox_raw(url, opts = {}) + url = URI(url).to_s + local_onebox(url, opts) || external_onebox(url) + rescue => e + # no point warning here, just cause we have an issue oneboxing a url + # we can later hunt for failed oneboxes by searching logs if needed + Rails.logger.info("Failed to onebox #{url} #{e} #{e.backtrace}") + # return a blank hash, so rest of the code works + blank_onebox + end - def self.local_onebox(url, opts = {}) - return unless route = Discourse.route_for(url) + def self.local_onebox(url, opts = {}) + return unless route = Discourse.route_for(url) - html = - case route[:controller] - when "uploads" then local_upload_html(url) - when "topics" then local_topic_html(url, route, opts) - when "users" then local_user_html(url, route) - end - - html = html.presence || "#{url}" - { onebox: html, preview: html } - end - - def self.local_upload_html(url) - case File.extname(URI(url).path || "") - when /^\.(mov|mp4|webm|ogv)$/i - "" - when /^\.(mp3|ogg|wav|m4a)$/i - "" - end - end - - def self.local_topic_html(url, route, opts) - return unless current_user = User.find_by(id: opts[:user_id]) - - if current_category = Category.find_by(id: opts[:category_id]) - return unless Guardian.new(current_user).can_see_category?(current_category) + html = + case route[:controller] + when "uploads" then local_upload_html(url) + when "topics" then local_topic_html(url, route, opts) + when "users" then local_user_html(url, route) end - if current_topic = Topic.find_by(id: opts[:topic_id]) - return unless Guardian.new(current_user).can_see_topic?(current_topic) - end + html = html.presence || "#{url}" + { onebox: html, preview: html } + end - topic = Topic.find_by(id: route[:topic_id]) + def self.local_upload_html(url) + case File.extname(URI(url).path || "") + when /^\.(mov|mp4|webm|ogv)$/i + "" + when /^\.(mp3|ogg|wav|m4a)$/i + "" + end + end - return unless topic - return if topic.private_message? + def self.local_topic_html(url, route, opts) + return unless current_user = User.find_by(id: opts[:user_id]) - if current_category&.id != topic.category_id - return unless Guardian.new.can_see_topic?(topic) - end - - post_number = route[:post_number].to_i - - post = post_number > 1 ? - topic.posts.where(post_number: post_number).first : - topic.ordered_posts.first - - return if !post || post.hidden || post.post_type != Post.types[:regular] - - if post_number > 1 && current_topic&.id == topic.id - excerpt = post.excerpt(SiteSetting.post_onebox_maxlength) - excerpt.gsub!(/[\r\n]+/, " ") - excerpt.gsub!("[/quote]", "[quote]") # don't break my quote - - quote = "[quote=\"#{post.user.username}, topic:#{topic.id}, post:#{post.post_number}\"]\n#{excerpt}\n[/quote]" - - PrettyText.cook(quote) - else - args = { - topic_id: topic.id, - post_number: post.post_number, - avatar: PrettyText.avatar_img(post.user.avatar_template, "tiny"), - original_url: url, - title: PrettyText.unescape_emoji(CGI::escapeHTML(topic.title)), - category_html: CategoryBadge.html_for(topic.category), - quote: PrettyText.unescape_emoji(post.excerpt(SiteSetting.post_onebox_maxlength)), - } - - template = File.read("#{Rails.root}/lib/onebox/templates/discourse_topic_onebox.hbs") - Mustache.render(template, args) - end + if current_category = Category.find_by(id: opts[:category_id]) + return unless Guardian.new(current_user).can_see_category?(current_category) end - def self.local_user_html(url, route) - username = route[:username] || "" - - if user = User.find_by(username_lower: username.downcase) - args = { - user_id: user.id, - username: user.username, - avatar: PrettyText.avatar_img(user.avatar_template, "extra_large"), - name: user.name, - bio: user.user_profile.bio_excerpt(230), - location: user.user_profile.location, - joined: I18n.t('joined'), - created_at: user.created_at.strftime(I18n.t('datetime_formats.formats.date_only')), - website: user.user_profile.website, - website_name: UserSerializer.new(user).website_name, - original_url: url - } - - template = File.read("#{Rails.root}/lib/onebox/templates/discourse_user_onebox.hbs") - Mustache.render(template, args) - else - nil - end + if current_topic = Topic.find_by(id: opts[:topic_id]) + return unless Guardian.new(current_user).can_see_topic?(current_topic) end - def self.external_onebox(url) - Rails.cache.fetch(onebox_cache_key(url), expires_in: 1.day) do - fd = FinalDestination.new(url, ignore_redirects: ignore_redirects, force_get_hosts: force_get_hosts) - uri = fd.resolve - return blank_onebox if uri.blank? || SiteSetting.onebox_domains_blacklist.include?(uri.hostname) + topic = Topic.find_by(id: route[:topic_id]) - options = { - cache: {}, - max_width: 695, - sanitize_config: Sanitize::Config::DISCOURSE_ONEBOX - } + return unless topic + return if topic.private_message? - options[:cookie] = fd.cookie if fd.cookie - - if Rails.env.development? && SiteSetting.port.to_i > 0 - Onebox.options = { allowed_ports: [80, 443, SiteSetting.port.to_i] } - end - - r = Onebox.preview(uri.to_s, options) - - { onebox: r.to_s, preview: r&.placeholder_html.to_s } - end + if current_category&.id != topic.category_id + return unless Guardian.new.can_see_topic?(topic) end + post_number = route[:post_number].to_i + + post = post_number > 1 ? + topic.posts.where(post_number: post_number).first : + topic.ordered_posts.first + + return if !post || post.hidden || post.post_type != Post.types[:regular] + + if post_number > 1 && current_topic&.id == topic.id + excerpt = post.excerpt(SiteSetting.post_onebox_maxlength) + excerpt.gsub!(/[\r\n]+/, " ") + excerpt.gsub!("[/quote]", "[quote]") # don't break my quote + + quote = "[quote=\"#{post.user.username}, topic:#{topic.id}, post:#{post.post_number}\"]\n#{excerpt}\n[/quote]" + + PrettyText.cook(quote) + else + args = { + topic_id: topic.id, + post_number: post.post_number, + avatar: PrettyText.avatar_img(post.user.avatar_template, "tiny"), + original_url: url, + title: PrettyText.unescape_emoji(CGI::escapeHTML(topic.title)), + category_html: CategoryBadge.html_for(topic.category), + quote: PrettyText.unescape_emoji(post.excerpt(SiteSetting.post_onebox_maxlength)), + } + + template = File.read("#{Rails.root}/lib/onebox/templates/discourse_topic_onebox.hbs") + Mustache.render(template, args) + end + end + + def self.local_user_html(url, route) + username = route[:username] || "" + + if user = User.find_by(username_lower: username.downcase) + args = { + user_id: user.id, + username: user.username, + avatar: PrettyText.avatar_img(user.avatar_template, "extra_large"), + name: user.name, + bio: user.user_profile.bio_excerpt(230), + location: user.user_profile.location, + joined: I18n.t('joined'), + created_at: user.created_at.strftime(I18n.t('datetime_formats.formats.date_only')), + website: user.user_profile.website, + website_name: UserSerializer.new(user).website_name, + original_url: url + } + + template = File.read("#{Rails.root}/lib/onebox/templates/discourse_user_onebox.hbs") + Mustache.render(template, args) + else + nil + end + end + + def self.external_onebox(url) + Rails.cache.fetch(onebox_cache_key(url), expires_in: 1.day) do + fd = FinalDestination.new(url, ignore_redirects: ignore_redirects, force_get_hosts: force_get_hosts) + uri = fd.resolve + return blank_onebox if uri.blank? || SiteSetting.onebox_domains_blacklist.include?(uri.hostname) + + options = { + cache: {}, + max_width: 695, + sanitize_config: Sanitize::Config::DISCOURSE_ONEBOX + } + + options[:cookie] = fd.cookie if fd.cookie + + if Rails.env.development? && SiteSetting.port.to_i > 0 + Onebox.options = { allowed_ports: [80, 443, SiteSetting.port.to_i] } + end + + r = Onebox.preview(uri.to_s, options) + + { onebox: r.to_s, preview: r&.placeholder_html.to_s } + end + end + end diff --git a/lib/retrieve_title.rb b/lib/retrieve_title.rb index c8e5f8a7ed..62c4a4022d 100644 --- a/lib/retrieve_title.rb +++ b/lib/retrieve_title.rb @@ -37,36 +37,36 @@ module RetrieveTitle private - def self.max_chunk_size(uri) + def self.max_chunk_size(uri) - # Amazon and YouTube leave the title until very late. Exceptions are bad - # but these are large sites. - return 500 if uri.host =~ /amazon\.(com|ca|co\.uk|es|fr|de|it|com\.au|com\.br|cn|in|co\.jp|com\.mx)$/ - return 300 if uri.host =~ /youtube\.com$/ || uri.host =~ /youtu.be/ + # Amazon and YouTube leave the title until very late. Exceptions are bad + # but these are large sites. + return 500 if uri.host =~ /amazon\.(com|ca|co\.uk|es|fr|de|it|com\.au|com\.br|cn|in|co\.jp|com\.mx)$/ + return 300 if uri.host =~ /youtube\.com$/ || uri.host =~ /youtu.be/ - # default is 10k - 10 - end + # default is 10k + 10 + end - # Fetch the beginning of a HTML document at a url - def self.fetch_title(url) - fd = FinalDestination.new(url, timeout: CRAWL_TIMEOUT) + # Fetch the beginning of a HTML document at a url + def self.fetch_title(url) + fd = FinalDestination.new(url, timeout: CRAWL_TIMEOUT) - current = nil - title = nil + current = nil + title = nil - fd.get do |_response, chunk, uri| + fd.get do |_response, chunk, uri| - if current - current << chunk - else - current = chunk - end - - max_size = max_chunk_size(uri) * 1024 - title = extract_title(current) - throw :done if title || max_size < current.length + if current + current << chunk + else + current = chunk end - return title + + max_size = max_chunk_size(uri) * 1024 + title = extract_title(current) + throw :done if title || max_size < current.length end + return title + end end diff --git a/lib/search.rb b/lib/search.rb index 40f80a245c..054f7e5fd0 100644 --- a/lib/search.rb +++ b/lib/search.rb @@ -503,399 +503,399 @@ class Search private - def process_advanced_search!(term) + def process_advanced_search!(term) - term.to_s.scan(/(([^" \t\n\x0B\f\r]+)?(("[^"]+")?))/).to_a.map do |(word, _)| - next if word.blank? + term.to_s.scan(/(([^" \t\n\x0B\f\r]+)?(("[^"]+")?))/).to_a.map do |(word, _)| + next if word.blank? - found = false + found = false - Search.advanced_filters.each do |matcher, block| - cleaned = word.gsub(/["']/, "") - if cleaned =~ matcher - (@filters ||= []) << [block, $1] - found = true + Search.advanced_filters.each do |matcher, block| + cleaned = word.gsub(/["']/, "") + if cleaned =~ matcher + (@filters ||= []) << [block, $1] + found = true + end + end + + @in_title = false + + if word == 'order:latest' || word == 'l' + @order = :latest + nil + elsif word == 'order:latest_topic' + @order = :latest_topic + nil + elsif word == 'in:title' + @in_title = true + nil + elsif word =~ /topic:(\d+)/ + topic_id = $1.to_i + if topic_id > 1 + topic = Topic.find_by(id: topic_id) + if @guardian.can_see?(topic) + @search_context = topic end end - - @in_title = false - - if word == 'order:latest' || word == 'l' - @order = :latest - nil - elsif word == 'order:latest_topic' - @order = :latest_topic - nil - elsif word == 'in:title' - @in_title = true - nil - elsif word =~ /topic:(\d+)/ - topic_id = $1.to_i - if topic_id > 1 - topic = Topic.find_by(id: topic_id) - if @guardian.can_see?(topic) - @search_context = topic - end - end - nil - elsif word == 'order:views' - @order = :views - nil - elsif word == 'order:likes' - @order = :likes - nil - elsif word == 'in:private' - @search_pms = true - nil - elsif word =~ /^private_messages:(.+)$/ - @search_pms = true - nil - else - found ? nil : word - end - end.compact.join(' ') - end - - def find_grouped_results - - if @results.type_filter.present? - raise Discourse::InvalidAccess.new("invalid type filter") unless Search.facets.include?(@results.type_filter) - send("#{@results.type_filter}_search") + nil + elsif word == 'order:views' + @order = :views + nil + elsif word == 'order:likes' + @order = :likes + nil + elsif word == 'in:private' + @search_pms = true + nil + elsif word =~ /^private_messages:(.+)$/ + @search_pms = true + nil else - unless @search_context - user_search if @term.present? - category_search if @term.present? - tags_search if @term.present? + found ? nil : word + end + end.compact.join(' ') + end + + def find_grouped_results + + if @results.type_filter.present? + raise Discourse::InvalidAccess.new("invalid type filter") unless Search.facets.include?(@results.type_filter) + send("#{@results.type_filter}_search") + else + unless @search_context + user_search if @term.present? + category_search if @term.present? + tags_search if @term.present? + end + topic_search + end + + add_more_topics_if_expected + @results + rescue ActiveRecord::StatementInvalid + # In the event of a PG:Error return nothing, it is likely they used a foreign language whose + # locale is not supported by postgres + end + + # Add more topics if we expected them + def add_more_topics_if_expected + expected_topics = 0 + expected_topics = Search.facets.size unless @results.type_filter.present? + expected_topics = Search.per_facet * Search.facets.size if @results.type_filter == 'topic' + expected_topics -= @results.posts.length + if expected_topics > 0 + extra_posts = posts_query(expected_topics * Search.burst_factor) + extra_posts = extra_posts.where("posts.topic_id NOT in (?)", @results.posts.map(&:topic_id)) if @results.posts.present? + extra_posts.each do |post| + @results.add(post) + expected_topics -= 1 + break if expected_topics == 0 + end + end + end + + # If we're searching for a single topic + def single_topic(id) + post = Post.find_by(topic_id: id, post_number: 1) + return nil unless @guardian.can_see?(post) + + @results.add(post) + @results + end + + def secure_category_ids + return @secure_category_ids unless @secure_category_ids.nil? + @secure_category_ids = @guardian.secure_category_ids + end + + def category_search + # scope is leaking onto Category, this is not good and probably a bug in Rails + # the secure_category_ids will invoke the same method on User, it calls Category.where + # however the scope from the query below is leaking in to Category, this works around + # the issue while we figure out what is up in Rails + secure_category_ids + + categories = Category.includes(:category_search_data) + .where("category_search_data.search_data @@ #{ts_query}") + .references(:category_search_data) + .order("topics_month DESC") + .secured(@guardian) + .limit(limit) + + categories.each do |category| + @results.add(category) + end + end + + def user_search + return if SiteSetting.hide_user_profiles_from_public && !@guardian.user + + users = User.includes(:user_search_data) + .references(:user_search_data) + .where(active: true) + .where(staged: false) + .where("user_search_data.search_data @@ #{ts_query("simple")}") + .order("CASE WHEN username_lower = '#{@original_term.downcase}' THEN 0 ELSE 1 END") + .order("last_posted_at DESC") + .limit(limit) + + users.each do |user| + @results.add(user) + end + end + + def tags_search + return unless SiteSetting.tagging_enabled + + tags = Tag.includes(:tag_search_data) + .where("tag_search_data.search_data @@ #{ts_query}") + .references(:tag_search_data) + .order("name asc") + .limit(limit) + + tags.each do |tag| + @results.add(tag) + end + end + + def posts_query(limit, opts = nil) + opts ||= {} + posts = Post.where(post_type: Topic.visible_post_types(@guardian.user)) + .joins(:post_search_data, :topic) + .joins("LEFT JOIN categories ON categories.id = topics.category_id") + .where("topics.deleted_at" => nil) + + is_topic_search = @search_context.present? && @search_context.is_a?(Topic) + + posts = posts.where("topics.visible") unless is_topic_search + + if opts[:private_messages] || (is_topic_search && @search_context.private_message?) + posts = posts.where("topics.archetype = ?", Archetype.private_message) + + unless @guardian.is_admin? + posts = posts.private_posts_for_user(@guardian.user) + end + else + posts = posts.where("topics.archetype <> ?", Archetype.private_message) + end + + if @term.present? + if is_topic_search + + term_without_quote = @term + if @term =~ /"(.+)"/ + term_without_quote = $1 end - topic_search - end - add_more_topics_if_expected - @results - rescue ActiveRecord::StatementInvalid - # In the event of a PG:Error return nothing, it is likely they used a foreign language whose - # locale is not supported by postgres - end - - # Add more topics if we expected them - def add_more_topics_if_expected - expected_topics = 0 - expected_topics = Search.facets.size unless @results.type_filter.present? - expected_topics = Search.per_facet * Search.facets.size if @results.type_filter == 'topic' - expected_topics -= @results.posts.length - if expected_topics > 0 - extra_posts = posts_query(expected_topics * Search.burst_factor) - extra_posts = extra_posts.where("posts.topic_id NOT in (?)", @results.posts.map(&:topic_id)) if @results.posts.present? - extra_posts.each do |post| - @results.add(post) - expected_topics -= 1 - break if expected_topics == 0 + if @term =~ /'(.+)'/ + term_without_quote = $1 end - end - end - # If we're searching for a single topic - def single_topic(id) - post = Post.find_by(topic_id: id, post_number: 1) - return nil unless @guardian.can_see?(post) - - @results.add(post) - @results - end - - def secure_category_ids - return @secure_category_ids unless @secure_category_ids.nil? - @secure_category_ids = @guardian.secure_category_ids - end - - def category_search - # scope is leaking onto Category, this is not good and probably a bug in Rails - # the secure_category_ids will invoke the same method on User, it calls Category.where - # however the scope from the query below is leaking in to Category, this works around - # the issue while we figure out what is up in Rails - secure_category_ids - - categories = Category.includes(:category_search_data) - .where("category_search_data.search_data @@ #{ts_query}") - .references(:category_search_data) - .order("topics_month DESC") - .secured(@guardian) - .limit(limit) - - categories.each do |category| - @results.add(category) - end - end - - def user_search - return if SiteSetting.hide_user_profiles_from_public && !@guardian.user - - users = User.includes(:user_search_data) - .references(:user_search_data) - .where(active: true) - .where(staged: false) - .where("user_search_data.search_data @@ #{ts_query("simple")}") - .order("CASE WHEN username_lower = '#{@original_term.downcase}' THEN 0 ELSE 1 END") - .order("last_posted_at DESC") - .limit(limit) - - users.each do |user| - @results.add(user) - end - end - - def tags_search - return unless SiteSetting.tagging_enabled - - tags = Tag.includes(:tag_search_data) - .where("tag_search_data.search_data @@ #{ts_query}") - .references(:tag_search_data) - .order("name asc") - .limit(limit) - - tags.each do |tag| - @results.add(tag) - end - end - - def posts_query(limit, opts = nil) - opts ||= {} - posts = Post.where(post_type: Topic.visible_post_types(@guardian.user)) - .joins(:post_search_data, :topic) - .joins("LEFT JOIN categories ON categories.id = topics.category_id") - .where("topics.deleted_at" => nil) - - is_topic_search = @search_context.present? && @search_context.is_a?(Topic) - - posts = posts.where("topics.visible") unless is_topic_search - - if opts[:private_messages] || (is_topic_search && @search_context.private_message?) - posts = posts.where("topics.archetype = ?", Archetype.private_message) - - unless @guardian.is_admin? - posts = posts.private_posts_for_user(@guardian.user) - end + posts = posts.joins('JOIN users u ON u.id = posts.user_id') + posts = posts.where("posts.raw || ' ' || u.username || ' ' || COALESCE(u.name, '') ilike ?", "%#{term_without_quote}%") else - posts = posts.where("topics.archetype <> ?", Archetype.private_message) - end - - if @term.present? - if is_topic_search - - term_without_quote = @term - if @term =~ /"(.+)"/ - term_without_quote = $1 - end - - if @term =~ /'(.+)'/ - term_without_quote = $1 - end - - posts = posts.joins('JOIN users u ON u.id = posts.user_id') - posts = posts.where("posts.raw || ' ' || u.username || ' ' || COALESCE(u.name, '') ilike ?", "%#{term_without_quote}%") - else - # A is for title - # B is for category - # C is for tags - # D is for cooked - weights = @in_title ? 'A' : (SiteSetting.tagging_enabled ? 'ABCD' : 'ABD') - posts = posts.where("post_search_data.search_data @@ #{ts_query(weight_filter: weights)}") - exact_terms = @term.scan(/"([^"]+)"/).flatten - exact_terms.each do |exact| - posts = posts.where("posts.raw ilike :exact OR topics.title ilike :exact", exact: "%#{exact}%") - end + # A is for title + # B is for category + # C is for tags + # D is for cooked + weights = @in_title ? 'A' : (SiteSetting.tagging_enabled ? 'ABCD' : 'ABD') + posts = posts.where("post_search_data.search_data @@ #{ts_query(weight_filter: weights)}") + exact_terms = @term.scan(/"([^"]+)"/).flatten + exact_terms.each do |exact| + posts = posts.where("posts.raw ilike :exact OR topics.title ilike :exact", exact: "%#{exact}%") end end + end - @filters.each do |block, match| - if block.arity == 1 - posts = instance_exec(posts, &block) || posts - else - posts = instance_exec(posts, match, &block) || posts - end - end if @filters - - # If we have a search context, prioritize those posts first - if @search_context.present? - - if @search_context.is_a?(User) - - if opts[:private_messages] - posts = posts.private_posts_for_user(@search_context) - else - posts = posts.where("posts.user_id = #{@search_context.id}") - end - - elsif @search_context.is_a?(Category) - category_ids = [@search_context.id] + Category.where(parent_category_id: @search_context.id).pluck(:id) - posts = posts.where("topics.category_id in (?)", category_ids) - elsif @search_context.is_a?(Topic) - posts = posts.where("topics.id = #{@search_context.id}") - .order("posts.post_number #{@order == :latest ? "DESC" : ""}") - end - - end - - if @order == :latest || (@term.blank? && !@order) - if opts[:aggregate_search] - posts = posts.order("MAX(posts.created_at) DESC") - else - posts = posts.reorder("posts.created_at DESC") - end - elsif @order == :latest_topic - if opts[:aggregate_search] - posts = posts.order("MAX(topics.created_at) DESC") - else - posts = posts.order("topics.created_at DESC") - end - elsif @order == :views - if opts[:aggregate_search] - posts = posts.order("MAX(topics.views) DESC") - else - posts = posts.order("topics.views DESC") - end - elsif @order == :likes - if opts[:aggregate_search] - posts = posts.order("MAX(posts.like_count) DESC") - else - posts = posts.order("posts.like_count DESC") - end + @filters.each do |block, match| + if block.arity == 1 + posts = instance_exec(posts, &block) || posts else - data_ranking = "TS_RANK_CD(post_search_data.search_data, #{ts_query})" - if opts[:aggregate_search] - posts = posts.order("MAX(#{data_ranking}) DESC") + posts = instance_exec(posts, match, &block) || posts + end + end if @filters + + # If we have a search context, prioritize those posts first + if @search_context.present? + + if @search_context.is_a?(User) + + if opts[:private_messages] + posts = posts.private_posts_for_user(@search_context) else - posts = posts.order("#{data_ranking} DESC") + posts = posts.where("posts.user_id = #{@search_context.id}") end - posts = posts.order("topics.bumped_at DESC") + + elsif @search_context.is_a?(Category) + category_ids = [@search_context.id] + Category.where(parent_category_id: @search_context.id).pluck(:id) + posts = posts.where("topics.category_id in (?)", category_ids) + elsif @search_context.is_a?(Topic) + posts = posts.where("topics.id = #{@search_context.id}") + .order("posts.post_number #{@order == :latest ? "DESC" : ""}") end - if secure_category_ids.present? - posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted) OR (categories.id IN (?))", secure_category_ids).references(:categories) + end + + if @order == :latest || (@term.blank? && !@order) + if opts[:aggregate_search] + posts = posts.order("MAX(posts.created_at) DESC") else - posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted)").references(:categories) + posts = posts.reorder("posts.created_at DESC") end - - posts = posts.offset(offset) - posts.limit(limit) - end - - def self.default_ts_config - "'#{Search.ts_config}'" - end - - def default_ts_config - self.class.default_ts_config - end - - def self.ts_query(term: , ts_config: nil, joiner: "&", weight_filter: nil) - - data = Post.exec_sql("SELECT TO_TSVECTOR(:config, :term)", - config: 'simple', - term: term).values[0][0] - - ts_config = ActiveRecord::Base.connection.quote(ts_config) if ts_config - all_terms = data.scan(/'([^']+)'\:\d+/).flatten - all_terms.map! do |t| - t.split(/[\)\(&']/)[0] - end.compact! - - query = ActiveRecord::Base.connection.quote( - all_terms - .map { |t| "'#{PG::Connection.escape_string(t)}':*#{weight_filter}" } - .join(" #{joiner} ") - ) - - "TO_TSQUERY(#{ts_config || default_ts_config}, #{query})" - end - - def ts_query(ts_config = nil, weight_filter: nil) - @ts_query_cache ||= {} - @ts_query_cache["#{ts_config || default_ts_config} #{@term} #{weight_filter}"] ||= - Search.ts_query(term: @term, ts_config: ts_config, weight_filter: weight_filter) - end - - def wrap_rows(query) - "SELECT *, row_number() over() row_number FROM (#{query.to_sql}) xxx" - end - - def aggregate_post_sql(opts) - min_or_max = @order == :latest ? "max" : "min" - - query = - if @order == :likes - # likes are a pain to aggregate so skip - posts_query(limit, private_messages: opts[:private_messages]) - .select('topics.id', "posts.post_number") - else - posts_query(limit, aggregate_search: true, private_messages: opts[:private_messages]) - .select('topics.id', "#{min_or_max}(posts.post_number) post_number") - .group('topics.id') - end - - min_id = Search.min_post_id - if min_id > 0 - low_set = query.dup.where("post_search_data.post_id < #{min_id}") - high_set = query.where("post_search_data.post_id >= #{min_id}") - - return { default: wrap_rows(high_set), remaining: wrap_rows(low_set) } - end - - # double wrapping so we get correct row numbers - { default: wrap_rows(query) } - end - - def aggregate_posts(post_sql) - return [] unless post_sql - - posts_eager_loads(Post) - .joins("JOIN (#{post_sql}) x ON x.id = posts.topic_id AND x.post_number = posts.post_number") - .order('row_number') - end - - def aggregate_search(opts = {}) - post_sql = aggregate_post_sql(opts) - - added = 0 - - aggregate_posts(post_sql[:default]).each do |p| - @results.add(p) - added += 1 - end - - if added < limit - aggregate_posts(post_sql[:remaining]).each { |p| @results.add(p) } - end - end - - def private_messages_search - raise Discourse::InvalidAccess.new("anonymous can not search PMs") unless @guardian.user - - aggregate_search(private_messages: true) - end - - def topic_search - if @search_context.is_a?(Topic) - posts = posts_eager_loads(posts_query(limit)) - .where('posts.topic_id = ?', @search_context.id) - - posts.each do |post| - @results.add(post) - end + elsif @order == :latest_topic + if opts[:aggregate_search] + posts = posts.order("MAX(topics.created_at) DESC") else - aggregate_search + posts = posts.order("topics.created_at DESC") end + elsif @order == :views + if opts[:aggregate_search] + posts = posts.order("MAX(topics.views) DESC") + else + posts = posts.order("topics.views DESC") + end + elsif @order == :likes + if opts[:aggregate_search] + posts = posts.order("MAX(posts.like_count) DESC") + else + posts = posts.order("posts.like_count DESC") + end + else + data_ranking = "TS_RANK_CD(post_search_data.search_data, #{ts_query})" + if opts[:aggregate_search] + posts = posts.order("MAX(#{data_ranking}) DESC") + else + posts = posts.order("#{data_ranking} DESC") + end + posts = posts.order("topics.bumped_at DESC") end - def posts_eager_loads(query) - query = query.includes(:user) - topic_eager_loads = [:category] + if secure_category_ids.present? + posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted) OR (categories.id IN (?))", secure_category_ids).references(:categories) + else + posts = posts.where("(categories.id IS NULL) OR (NOT categories.read_restricted)").references(:categories) + end - if SiteSetting.tagging_enabled - topic_eager_loads << :tags + posts = posts.offset(offset) + posts.limit(limit) + end + + def self.default_ts_config + "'#{Search.ts_config}'" + end + + def default_ts_config + self.class.default_ts_config + end + + def self.ts_query(term: , ts_config: nil, joiner: "&", weight_filter: nil) + + data = Post.exec_sql("SELECT TO_TSVECTOR(:config, :term)", + config: 'simple', + term: term).values[0][0] + + ts_config = ActiveRecord::Base.connection.quote(ts_config) if ts_config + all_terms = data.scan(/'([^']+)'\:\d+/).flatten + all_terms.map! do |t| + t.split(/[\)\(&']/)[0] + end.compact! + + query = ActiveRecord::Base.connection.quote( + all_terms + .map { |t| "'#{PG::Connection.escape_string(t)}':*#{weight_filter}" } + .join(" #{joiner} ") + ) + + "TO_TSQUERY(#{ts_config || default_ts_config}, #{query})" + end + + def ts_query(ts_config = nil, weight_filter: nil) + @ts_query_cache ||= {} + @ts_query_cache["#{ts_config || default_ts_config} #{@term} #{weight_filter}"] ||= + Search.ts_query(term: @term, ts_config: ts_config, weight_filter: weight_filter) + end + + def wrap_rows(query) + "SELECT *, row_number() over() row_number FROM (#{query.to_sql}) xxx" + end + + def aggregate_post_sql(opts) + min_or_max = @order == :latest ? "max" : "min" + + query = + if @order == :likes + # likes are a pain to aggregate so skip + posts_query(limit, private_messages: opts[:private_messages]) + .select('topics.id', "posts.post_number") + else + posts_query(limit, aggregate_search: true, private_messages: opts[:private_messages]) + .select('topics.id', "#{min_or_max}(posts.post_number) post_number") + .group('topics.id') end - query.includes(topic: topic_eager_loads) + min_id = Search.min_post_id + if min_id > 0 + low_set = query.dup.where("post_search_data.post_id < #{min_id}") + high_set = query.where("post_search_data.post_id >= #{min_id}") + + return { default: wrap_rows(high_set), remaining: wrap_rows(low_set) } end + # double wrapping so we get correct row numbers + { default: wrap_rows(query) } + end + + def aggregate_posts(post_sql) + return [] unless post_sql + + posts_eager_loads(Post) + .joins("JOIN (#{post_sql}) x ON x.id = posts.topic_id AND x.post_number = posts.post_number") + .order('row_number') + end + + def aggregate_search(opts = {}) + post_sql = aggregate_post_sql(opts) + + added = 0 + + aggregate_posts(post_sql[:default]).each do |p| + @results.add(p) + added += 1 + end + + if added < limit + aggregate_posts(post_sql[:remaining]).each { |p| @results.add(p) } + end + end + + def private_messages_search + raise Discourse::InvalidAccess.new("anonymous can not search PMs") unless @guardian.user + + aggregate_search(private_messages: true) + end + + def topic_search + if @search_context.is_a?(Topic) + posts = posts_eager_loads(posts_query(limit)) + .where('posts.topic_id = ?', @search_context.id) + + posts.each do |post| + @results.add(post) + end + else + aggregate_search + end + end + + def posts_eager_loads(query) + query = query.includes(:user) + topic_eager_loads = [:category] + + if SiteSetting.tagging_enabled + topic_eager_loads << :tags + end + + query.includes(topic: topic_eager_loads) + end + end diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 563eedf67a..ad73a7848f 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -423,147 +423,147 @@ class TopicQuery protected - def per_page_setting - @options[:slow_platform] ? 15 : 30 - end + def per_page_setting + @options[:slow_platform] ? 15 : 30 + end - def private_messages_for(user, type) - options = @options - options.reverse_merge!(per_page: per_page_setting) + def private_messages_for(user, type) + options = @options + options.reverse_merge!(per_page: per_page_setting) - result = Topic.includes(:tags) + result = Topic.includes(:tags) - if type == :group - result = result.includes(:allowed_users) - result = result.where(" - topics.id IN ( - SELECT topic_id FROM topic_allowed_groups - WHERE ( - group_id IN ( - SELECT group_id - FROM group_users - WHERE user_id = #{user.id.to_i} - OR #{user.staff?} - ) - ) - AND group_id IN (SELECT id FROM groups WHERE name ilike ?) - )", - @options[:group_name] - ) - elsif type == :user - result = result.includes(:allowed_users) - result = result.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})") - elsif type == :all - result = result.includes(:allowed_users) - result = result.where("topics.id IN ( - SELECT topic_id - FROM topic_allowed_users + if type == :group + result = result.includes(:allowed_users) + result = result.where(" + topics.id IN ( + SELECT topic_id FROM topic_allowed_groups + WHERE ( + group_id IN ( + SELECT group_id + FROM group_users WHERE user_id = #{user.id.to_i} - UNION ALL - SELECT topic_id FROM topic_allowed_groups - WHERE group_id IN ( - SELECT group_id FROM group_users WHERE user_id = #{user.id.to_i} - ) - )") - end - - result = result.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{user.id.to_i})") - .order("topics.bumped_at DESC") - .private_messages - - result = result.limit(options[:per_page]) unless options[:limit] == false - result = result.visible if options[:visible] || @user.nil? || @user.regular? - - if options[:page] - offset = options[:page].to_i * options[:per_page] - result = result.offset(offset) if offset > 0 - end - result + OR #{user.staff?} + ) + ) + AND group_id IN (SELECT id FROM groups WHERE name ilike ?) + )", + @options[:group_name] + ) + elsif type == :user + result = result.includes(:allowed_users) + result = result.where("topics.id IN (SELECT topic_id FROM topic_allowed_users WHERE user_id = #{user.id.to_i})") + elsif type == :all + result = result.includes(:allowed_users) + result = result.where("topics.id IN ( + SELECT topic_id + FROM topic_allowed_users + WHERE user_id = #{user.id.to_i} + UNION ALL + SELECT topic_id FROM topic_allowed_groups + WHERE group_id IN ( + SELECT group_id FROM group_users WHERE user_id = #{user.id.to_i} + ) + )") end - def apply_shared_drafts(result, category_id, options) - drafts_category_id = SiteSetting.shared_drafts_category.to_i - viewing_shared = category_id && category_id == drafts_category_id + result = result.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{user.id.to_i})") + .order("topics.bumped_at DESC") + .private_messages - if guardian.can_create_shared_draft? - if options[:destination_category_id] - destination_category_id = get_category_id(options[:destination_category_id]) - topic_ids = SharedDraft.where(category_id: destination_category_id).pluck(:topic_id) - return result.where(id: topic_ids) - elsif viewing_shared - result = result.includes(:shared_draft).references(:shared_draft) - else - return result.where('topics.category_id != ?', drafts_category_id) - end + result = result.limit(options[:per_page]) unless options[:limit] == false + result = result.visible if options[:visible] || @user.nil? || @user.regular? + + if options[:page] + offset = options[:page].to_i * options[:per_page] + result = result.offset(offset) if offset > 0 + end + result + end + + def apply_shared_drafts(result, category_id, options) + drafts_category_id = SiteSetting.shared_drafts_category.to_i + viewing_shared = category_id && category_id == drafts_category_id + + if guardian.can_create_shared_draft? + if options[:destination_category_id] + destination_category_id = get_category_id(options[:destination_category_id]) + topic_ids = SharedDraft.where(category_id: destination_category_id).pluck(:topic_id) + return result.where(id: topic_ids) + elsif viewing_shared + result = result.includes(:shared_draft).references(:shared_draft) + else + return result.where('topics.category_id != ?', drafts_category_id) end - - result end - def apply_ordering(result, options) - sort_column = SORTABLE_MAPPING[options[:order]] || 'default' - sort_dir = (options[:ascending] == "true") ? "ASC" : "DESC" + result + end - # If we are sorting in the default order desc, we should consider including pinned - # topics. Otherwise, just use bumped_at. - if sort_column == 'default' - if sort_dir == 'DESC' - # If something requires a custom order, for example "unread" which sorts the least read - # to the top, do nothing - return result if options[:unordered] - end - sort_column = 'bumped_at' + def apply_ordering(result, options) + sort_column = SORTABLE_MAPPING[options[:order]] || 'default' + sort_dir = (options[:ascending] == "true") ? "ASC" : "DESC" + + # If we are sorting in the default order desc, we should consider including pinned + # topics. Otherwise, just use bumped_at. + if sort_column == 'default' + if sort_dir == 'DESC' + # If something requires a custom order, for example "unread" which sorts the least read + # to the top, do nothing + return result if options[:unordered] end - - # If we are sorting by category, actually use the name - if sort_column == 'category_id' - # TODO forces a table scan, slow - return result.references(:categories).order(TopicQuerySQL.order_by_category_sql(sort_dir)) - end - - if sort_column == 'op_likes' - return result.includes(:first_post).order("(SELECT like_count FROM posts p3 WHERE p3.topic_id = topics.id AND p3.post_number = 1) #{sort_dir}") - end - - if sort_column.start_with?('custom_fields') - field = sort_column.split('.')[1] - return result.order("(SELECT CASE WHEN EXISTS (SELECT true FROM topic_custom_fields tcf WHERE tcf.topic_id::integer = topics.id::integer AND tcf.name = '#{field}') THEN (SELECT value::integer FROM topic_custom_fields tcf WHERE tcf.topic_id::integer = topics.id::integer AND tcf.name = '#{field}') ELSE 0 END) #{sort_dir}") - end - - result.order("topics.#{sort_column} #{sort_dir}") + sort_column = 'bumped_at' end - def get_category_id(category_id_or_slug) - return nil unless category_id_or_slug - category_id = category_id_or_slug.to_i - category_id = Category.where(slug: category_id_or_slug).pluck(:id).first if category_id == 0 - category_id + # If we are sorting by category, actually use the name + if sort_column == 'category_id' + # TODO forces a table scan, slow + return result.references(:categories).order(TopicQuerySQL.order_by_category_sql(sort_dir)) end - # Create results based on a bunch of default options - def default_results(options = {}) - options.reverse_merge!(@options) - options.reverse_merge!(per_page: per_page_setting) + if sort_column == 'op_likes' + return result.includes(:first_post).order("(SELECT like_count FROM posts p3 WHERE p3.topic_id = topics.id AND p3.post_number = 1) #{sort_dir}") + end - # Whether to return visible topics - options[:visible] = true if @user.nil? || @user.regular? - options[:visible] = false if @user && @user.id == options[:filtered_to_user] + if sort_column.start_with?('custom_fields') + field = sort_column.split('.')[1] + return result.order("(SELECT CASE WHEN EXISTS (SELECT true FROM topic_custom_fields tcf WHERE tcf.topic_id::integer = topics.id::integer AND tcf.name = '#{field}') THEN (SELECT value::integer FROM topic_custom_fields tcf WHERE tcf.topic_id::integer = topics.id::integer AND tcf.name = '#{field}') ELSE 0 END) #{sort_dir}") + end - # Start with a list of all topics - result = Topic.unscoped + result.order("topics.#{sort_column} #{sort_dir}") + end - if @user - result = result.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{@user.id.to_i})") - .references('tu') - end + def get_category_id(category_id_or_slug) + return nil unless category_id_or_slug + category_id = category_id_or_slug.to_i + category_id = Category.where(slug: category_id_or_slug).pluck(:id).first if category_id == 0 + category_id + end - category_id = get_category_id(options[:category]) - @options[:category_id] = category_id - if category_id - if options[:no_subcategories] - result = result.where('categories.id = ?', category_id) - else - sql = <<~SQL + # Create results based on a bunch of default options + def default_results(options = {}) + options.reverse_merge!(@options) + options.reverse_merge!(per_page: per_page_setting) + + # Whether to return visible topics + options[:visible] = true if @user.nil? || @user.regular? + options[:visible] = false if @user && @user.id == options[:filtered_to_user] + + # Start with a list of all topics + result = Topic.unscoped + + if @user + result = result.joins("LEFT OUTER JOIN topic_users AS tu ON (topics.id = tu.topic_id AND tu.user_id = #{@user.id.to_i})") + .references('tu') + end + + category_id = get_category_id(options[:category]) + @options[:category_id] = category_id + if category_id + if options[:no_subcategories] + result = result.where('categories.id = ?', category_id) + else + sql = <<~SQL categories.id IN ( SELECT c2.id FROM categories c2 WHERE c2.parent_category_id = :category_id UNION ALL @@ -573,356 +573,356 @@ class TopicQuery SELECT c3.topic_id FROM categories c3 WHERE c3.parent_category_id = :category_id ) SQL - result = result.where(sql, category_id: category_id) - end - result = result.references(:categories) + result = result.where(sql, category_id: category_id) + end + result = result.references(:categories) - if !@options[:order] - # category default sort order - sort_order, sort_ascending = Category.where(id: category_id).pluck(:sort_order, :sort_ascending).first - if sort_order - options[:order] = sort_order - options[:ascending] = !!sort_ascending ? 'true' : 'false' - end + if !@options[:order] + # category default sort order + sort_order, sort_ascending = Category.where(id: category_id).pluck(:sort_order, :sort_ascending).first + if sort_order + options[:order] = sort_order + options[:ascending] = !!sort_ascending ? 'true' : 'false' end end + end - # ALL TAGS: something like this? - # Topic.joins(:tags).where('tags.name in (?)', @options[:tags]).group('topic_id').having('count(*)=?', @options[:tags].size).select('topic_id') + # ALL TAGS: something like this? + # Topic.joins(:tags).where('tags.name in (?)', @options[:tags]).group('topic_id').having('count(*)=?', @options[:tags].size).select('topic_id') - if SiteSetting.tagging_enabled - result = result.preload(:tags) + if SiteSetting.tagging_enabled + result = result.preload(:tags) - if @options[:tags] && @options[:tags].size > 0 + if @options[:tags] && @options[:tags].size > 0 - if @options[:match_all_tags] - # ALL of the given tags: - tags_count = @options[:tags].length - @options[:tags] = Tag.where(name: @options[:tags]).pluck(:id) unless @options[:tags][0].is_a?(Integer) + if @options[:match_all_tags] + # ALL of the given tags: + tags_count = @options[:tags].length + @options[:tags] = Tag.where(name: @options[:tags]).pluck(:id) unless @options[:tags][0].is_a?(Integer) - if tags_count == @options[:tags].length - @options[:tags].each_with_index do |tag, index| - sql_alias = ['t', index].join - result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}") - end - else - result = result.none # don't return any results unless all tags exist in the database + if tags_count == @options[:tags].length + @options[:tags].each_with_index do |tag, index| + sql_alias = ['t', index].join + result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}") end else - # ANY of the given tags: - result = result.joins(:tags) - if @options[:tags][0].is_a?(Integer) - result = result.where("tags.id in (?)", @options[:tags]) - else - result = result.where("tags.name in (?)", @options[:tags]) - end + result = result.none # don't return any results unless all tags exist in the database end - elsif @options[:no_tags] - # the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags")) - result = result.where.not(id: TopicTag.distinct.pluck(:topic_id)) - end - end - - result = apply_ordering(result, options) - result = result.listable_topics.includes(:category) - result = apply_shared_drafts(result, category_id, options) - - if options[:exclude_category_ids] && options[:exclude_category_ids].is_a?(Array) && options[:exclude_category_ids].size > 0 - result = result.where("categories.id NOT IN (?)", options[:exclude_category_ids]).references(:categories) - end - - # Don't include the category topics if excluded - if options[:no_definitions] - result = result.where('COALESCE(categories.topic_id, 0) <> topics.id') - end - - result = result.limit(options[:per_page]) unless options[:limit] == false - result = result.visible if options[:visible] - result = result.where.not(topics: { id: options[:except_topic_ids] }).references(:topics) if options[:except_topic_ids] - - if options[:page] - offset = options[:page].to_i * options[:per_page] - result = result.offset(offset) if offset > 0 - end - - if options[:topic_ids] - result = result.where('topics.id in (?)', options[:topic_ids]).references(:topics) - end - - if search = options[:search] - result = result.where("topics.id in (select pp.topic_id from post_search_data pd join posts pp on pp.id = pd.post_id where pd.search_data @@ #{Search.ts_query(term: search.to_s)})") - end - - # NOTE protect against SYM attack can be removed with Ruby 2.2 - # - state = options[:state] - if @user && state && - TopicUser.notification_levels.keys.map(&:to_s).include?(state) - level = TopicUser.notification_levels[state.to_sym] - result = result.where('topics.id IN ( - SELECT topic_id - FROM topic_users - WHERE user_id = ? AND - notification_level = ?)', @user.id, level) - end - - require_deleted_clause = true - - if before = options[:before] - if (before = before.to_i) > 0 - result = result.where('topics.created_at < ?', before.to_i.days.ago) - end - end - - if bumped_before = options[:bumped_before] - if (bumped_before = bumped_before.to_i) > 0 - result = result.where('topics.bumped_at < ?', bumped_before.to_i.days.ago) - end - end - - if status = options[:status] - case status - when 'open' - result = result.where('NOT topics.closed AND NOT topics.archived') - when 'closed' - result = result.where('topics.closed') - when 'archived' - result = result.where('topics.archived') - when 'listed' - result = result.where('topics.visible') - when 'unlisted' - result = result.where('NOT topics.visible') - when 'deleted' - guardian = @guardian - if guardian.is_staff? - result = result.where('topics.deleted_at IS NOT NULL') - require_deleted_clause = false + else + # ANY of the given tags: + result = result.joins(:tags) + if @options[:tags][0].is_a?(Integer) + result = result.where("tags.id in (?)", @options[:tags]) + else + result = result.where("tags.name in (?)", @options[:tags]) end end + elsif @options[:no_tags] + # the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags")) + result = result.where.not(id: TopicTag.distinct.pluck(:topic_id)) end - - if (filter = options[:filter]) && @user - action = - if filter == "bookmarked" - PostActionType.types[:bookmark] - elsif filter == "liked" - PostActionType.types[:like] - end - if action - result = result.where('topics.id IN (SELECT pp.topic_id - FROM post_actions pa - JOIN posts pp ON pp.id = pa.post_id - WHERE pa.user_id = :user_id AND - pa.post_action_type_id = :action AND - pa.deleted_at IS NULL - )', user_id: @user.id, - action: action - ) - end - end - - result = result.where('topics.deleted_at IS NULL') if require_deleted_clause - result = result.where('topics.posts_count <= ?', options[:max_posts]) if options[:max_posts].present? - result = result.where('topics.posts_count >= ?', options[:min_posts]) if options[:min_posts].present? - - result = TopicQuery.apply_custom_filters(result, self) - - @guardian.filter_allowed_categories(result) end - def remove_muted_topics(list, user) - if user - list = list.where('COALESCE(tu.notification_level,1) > :muted', muted: TopicUser.notification_levels[:muted]) - end + result = apply_ordering(result, options) + result = result.listable_topics.includes(:category) + result = apply_shared_drafts(result, category_id, options) + if options[:exclude_category_ids] && options[:exclude_category_ids].is_a?(Array) && options[:exclude_category_ids].size > 0 + result = result.where("categories.id NOT IN (?)", options[:exclude_category_ids]).references(:categories) + end + + # Don't include the category topics if excluded + if options[:no_definitions] + result = result.where('COALESCE(categories.topic_id, 0) <> topics.id') + end + + result = result.limit(options[:per_page]) unless options[:limit] == false + result = result.visible if options[:visible] + result = result.where.not(topics: { id: options[:except_topic_ids] }).references(:topics) if options[:except_topic_ids] + + if options[:page] + offset = options[:page].to_i * options[:per_page] + result = result.offset(offset) if offset > 0 + end + + if options[:topic_ids] + result = result.where('topics.id in (?)', options[:topic_ids]).references(:topics) + end + + if search = options[:search] + result = result.where("topics.id in (select pp.topic_id from post_search_data pd join posts pp on pp.id = pd.post_id where pd.search_data @@ #{Search.ts_query(term: search.to_s)})") + end + + # NOTE protect against SYM attack can be removed with Ruby 2.2 + # + state = options[:state] + if @user && state && + TopicUser.notification_levels.keys.map(&:to_s).include?(state) + level = TopicUser.notification_levels[state.to_sym] + result = result.where('topics.id IN ( + SELECT topic_id + FROM topic_users + WHERE user_id = ? AND + notification_level = ?)', @user.id, level) + end + + require_deleted_clause = true + + if before = options[:before] + if (before = before.to_i) > 0 + result = result.where('topics.created_at < ?', before.to_i.days.ago) + end + end + + if bumped_before = options[:bumped_before] + if (bumped_before = bumped_before.to_i) > 0 + result = result.where('topics.bumped_at < ?', bumped_before.to_i.days.ago) + end + end + + if status = options[:status] + case status + when 'open' + result = result.where('NOT topics.closed AND NOT topics.archived') + when 'closed' + result = result.where('topics.closed') + when 'archived' + result = result.where('topics.archived') + when 'listed' + result = result.where('topics.visible') + when 'unlisted' + result = result.where('NOT topics.visible') + when 'deleted' + guardian = @guardian + if guardian.is_staff? + result = result.where('topics.deleted_at IS NOT NULL') + require_deleted_clause = false + end + end + end + + if (filter = options[:filter]) && @user + action = + if filter == "bookmarked" + PostActionType.types[:bookmark] + elsif filter == "liked" + PostActionType.types[:like] + end + if action + result = result.where('topics.id IN (SELECT pp.topic_id + FROM post_actions pa + JOIN posts pp ON pp.id = pa.post_id + WHERE pa.user_id = :user_id AND + pa.post_action_type_id = :action AND + pa.deleted_at IS NULL + )', user_id: @user.id, + action: action + ) + end + end + + result = result.where('topics.deleted_at IS NULL') if require_deleted_clause + result = result.where('topics.posts_count <= ?', options[:max_posts]) if options[:max_posts].present? + result = result.where('topics.posts_count >= ?', options[:min_posts]) if options[:min_posts].present? + + result = TopicQuery.apply_custom_filters(result, self) + + @guardian.filter_allowed_categories(result) + end + + def remove_muted_topics(list, user) + if user + list = list.where('COALESCE(tu.notification_level,1) > :muted', muted: TopicUser.notification_levels[:muted]) + end + + list + end + def remove_muted_categories(list, user, opts = nil) + category_id = get_category_id(opts[:exclude]) if opts + + if user + list = list.references("cu") + .where(" + NOT EXISTS ( + SELECT 1 + FROM category_users cu + WHERE cu.user_id = :user_id + AND cu.category_id = topics.category_id + AND cu.notification_level = :muted + AND cu.category_id <> :category_id + AND (tu.notification_level IS NULL OR tu.notification_level < :tracking) + )", user_id: user.id, + muted: CategoryUser.notification_levels[:muted], + tracking: TopicUser.notification_levels[:tracking], + category_id: category_id || -1) + end + + list + end + def remove_muted_tags(list, user, opts = nil) + if user.nil? || !SiteSetting.tagging_enabled || !SiteSetting.remove_muted_tags_from_latest list - end - def remove_muted_categories(list, user, opts = nil) - category_id = get_category_id(opts[:exclude]) if opts - - if user - list = list.references("cu") - .where(" - NOT EXISTS ( - SELECT 1 - FROM category_users cu - WHERE cu.user_id = :user_id - AND cu.category_id = topics.category_id - AND cu.notification_level = :muted - AND cu.category_id <> :category_id - AND (tu.notification_level IS NULL OR tu.notification_level < :tracking) - )", user_id: user.id, - muted: CategoryUser.notification_levels[:muted], - tracking: TopicUser.notification_levels[:tracking], - category_id: category_id || -1) - end - - list - end - def remove_muted_tags(list, user, opts = nil) - if user.nil? || !SiteSetting.tagging_enabled || !SiteSetting.remove_muted_tags_from_latest + else + if !TagUser.lookup(user, :muted).exists? list else - if !TagUser.lookup(user, :muted).exists? - list + showing_tag = if opts[:filter] + f = opts[:filter].split('/') + f[0] == 'tags' ? f[1] : nil else - showing_tag = if opts[:filter] - f = opts[:filter].split('/') - f[0] == 'tags' ? f[1] : nil - else - nil - end + nil + end - if TagUser.lookup(user, :muted).joins(:tag).where('tags.name = ?', showing_tag).exists? - list # if viewing the topic list for a muted tag, show all the topics - else - muted_tag_ids = TagUser.lookup(user, :muted).pluck(:tag_id) - list = list.where(" - EXISTS ( - SELECT 1 - FROM topic_tags tt - WHERE tt.tag_id NOT IN (:tag_ids) - AND tt.topic_id = topics.id - ) OR NOT EXISTS (SELECT 1 FROM topic_tags tt WHERE tt.topic_id = topics.id)", tag_ids: muted_tag_ids) - end + if TagUser.lookup(user, :muted).joins(:tag).where('tags.name = ?', showing_tag).exists? + list # if viewing the topic list for a muted tag, show all the topics + else + muted_tag_ids = TagUser.lookup(user, :muted).pluck(:tag_id) + list = list.where(" + EXISTS ( + SELECT 1 + FROM topic_tags tt + WHERE tt.tag_id NOT IN (:tag_ids) + AND tt.topic_id = topics.id + ) OR NOT EXISTS (SELECT 1 FROM topic_tags tt WHERE tt.topic_id = topics.id)", tag_ids: muted_tag_ids) end end end + end - def new_messages(params) - TopicQuery.new_filter(messages_for_groups_or_user(params[:my_group_ids]), Time.at(SiteSetting.min_new_topics_time).to_datetime) - .limit(params[:count]) - end + def new_messages(params) + TopicQuery.new_filter(messages_for_groups_or_user(params[:my_group_ids]), Time.at(SiteSetting.min_new_topics_time).to_datetime) + .limit(params[:count]) + end - def unread_messages(params) - TopicQuery.unread_filter( - messages_for_groups_or_user(params[:my_group_ids]), - @user&.id, - staff: @user&.staff?) - .limit(params[:count]) - end + def unread_messages(params) + TopicQuery.unread_filter( + messages_for_groups_or_user(params[:my_group_ids]), + @user&.id, + staff: @user&.staff?) + .limit(params[:count]) + end - def related_messages_user(params) - messages = messages_for_user.limit(params[:count]) - messages = allowed_messages(messages, params) - end + def related_messages_user(params) + messages = messages_for_user.limit(params[:count]) + messages = allowed_messages(messages, params) + end - def related_messages_group(params) - messages = messages_for_groups_or_user(params[:my_group_ids]).limit(params[:count]) - messages = allowed_messages(messages, params) - end + def related_messages_group(params) + messages = messages_for_groups_or_user(params[:my_group_ids]).limit(params[:count]) + messages = allowed_messages(messages, params) + end - def allowed_messages(messages, params) - user_ids = (params[:target_user_ids] || []) - group_ids = ((params[:target_group_ids] - params[:my_group_ids]) || []) - - if user_ids.present? - messages = - messages.joins(" - LEFT JOIN topic_allowed_users ta2 - ON topics.id = ta2.topic_id - AND ta2.user_id IN (#{sanitize_sql_array(user_ids)}) - ") - end - - if group_ids.present? - messages = - messages.joins(" - LEFT JOIN topic_allowed_groups tg2 - ON topics.id = tg2.topic_id - AND tg2.group_id IN (#{sanitize_sql_array(group_ids)}) - ") - end + def allowed_messages(messages, params) + user_ids = (params[:target_user_ids] || []) + group_ids = ((params[:target_group_ids] - params[:my_group_ids]) || []) + if user_ids.present? messages = - if user_ids.present? && group_ids.present? - messages.where("ta2.topic_id IS NOT NULL OR tg2.topic_id IS NOT NULL") - elsif user_ids.present? - messages.where("ta2.topic_id IS NOT NULL") - elsif group_ids.present? - messages.where("tg2.topic_id IS NOT NULL") - end + messages.joins(" + LEFT JOIN topic_allowed_users ta2 + ON topics.id = ta2.topic_id + AND ta2.user_id IN (#{sanitize_sql_array(user_ids)}) + ") end - def messages_for_groups_or_user(group_ids) - if group_ids.present? - base_messages - .joins(" - LEFT JOIN ( - SELECT * FROM topic_allowed_groups _tg - LEFT JOIN group_users gu - ON gu.user_id = #{@user.id.to_i} - AND gu.group_id = _tg.group_id - WHERE gu.group_id IN (#{sanitize_sql_array(group_ids)}) - ) tg ON topics.id = tg.topic_id - ") - .where("tg.topic_id IS NOT NULL") - else - messages_for_user + if group_ids.present? + messages = + messages.joins(" + LEFT JOIN topic_allowed_groups tg2 + ON topics.id = tg2.topic_id + AND tg2.group_id IN (#{sanitize_sql_array(group_ids)}) + ") + end + + messages = + if user_ids.present? && group_ids.present? + messages.where("ta2.topic_id IS NOT NULL OR tg2.topic_id IS NOT NULL") + elsif user_ids.present? + messages.where("ta2.topic_id IS NOT NULL") + elsif group_ids.present? + messages.where("tg2.topic_id IS NOT NULL") end - end + end - def messages_for_user + def messages_for_groups_or_user(group_ids) + if group_ids.present? base_messages .joins(" - LEFT JOIN topic_allowed_users ta - ON topics.id = ta.topic_id - AND ta.user_id = #{@user.id.to_i} + LEFT JOIN ( + SELECT * FROM topic_allowed_groups _tg + LEFT JOIN group_users gu + ON gu.user_id = #{@user.id.to_i} + AND gu.group_id = _tg.group_id + WHERE gu.group_id IN (#{sanitize_sql_array(group_ids)}) + ) tg ON topics.id = tg.topic_id ") - .where("ta.topic_id IS NOT NULL") + .where("tg.topic_id IS NOT NULL") + else + messages_for_user + end + end + + def messages_for_user + base_messages + .joins(" + LEFT JOIN topic_allowed_users ta + ON topics.id = ta.topic_id + AND ta.user_id = #{@user.id.to_i} + ") + .where("ta.topic_id IS NOT NULL") + end + + def base_messages + query = Topic + .where('topics.archetype = ?', Archetype.private_message) + .joins("LEFT JOIN topic_users tu ON topics.id = tu.topic_id AND tu.user_id = #{@user.id.to_i}") + + query = query.includes(:tags) if SiteSetting.tagging_enabled + query.order('topics.bumped_at DESC') + end + + def random_suggested(topic, count, excluded_topic_ids = []) + result = default_results(unordered: true, per_page: count).where(closed: false, archived: false) + + if SiteSetting.limit_suggested_to_category + excluded_topic_ids += Category.where(id: topic.category_id).pluck(:id) + else + excluded_topic_ids += Category.topic_ids.to_a + end + result = result.where("topics.id NOT IN (?)", excluded_topic_ids) unless excluded_topic_ids.empty? + + result = remove_muted_categories(result, @user) + + # If we are in a category, prefer it for the random results + if topic.category_id + result = result.order("CASE WHEN topics.category_id = #{topic.category_id.to_i} THEN 0 ELSE 1 END") end - def base_messages - query = Topic - .where('topics.archetype = ?', Archetype.private_message) - .joins("LEFT JOIN topic_users tu ON topics.id = tu.topic_id AND tu.user_id = #{@user.id.to_i}") + # Best effort, it over selects, however if you have a high number + # of muted categories there is tiny chance we will not select enough + # in particular this can happen if current category is empty and tons + # of muted, big edge case + # + # we over select in case cache is stale + max = (count * 1.3).to_i + ids = SiteSetting.limit_suggested_to_category ? [] : RandomTopicSelector.next(max) + ids.concat(RandomTopicSelector.next(max, topic.category)) - query = query.includes(:tags) if SiteSetting.tagging_enabled - query.order('topics.bumped_at DESC') + result.where(id: ids.uniq) + end + + def suggested_ordering(result, options) + # Prefer unread in the same category + if options[:topic] && options[:topic].category_id + result = result.order("CASE WHEN topics.category_id = #{options[:topic].category_id.to_i} THEN 0 ELSE 1 END") end - def random_suggested(topic, count, excluded_topic_ids = []) - result = default_results(unordered: true, per_page: count).where(closed: false, archived: false) - - if SiteSetting.limit_suggested_to_category - excluded_topic_ids += Category.where(id: topic.category_id).pluck(:id) - else - excluded_topic_ids += Category.topic_ids.to_a - end - result = result.where("topics.id NOT IN (?)", excluded_topic_ids) unless excluded_topic_ids.empty? - - result = remove_muted_categories(result, @user) - - # If we are in a category, prefer it for the random results - if topic.category_id - result = result.order("CASE WHEN topics.category_id = #{topic.category_id.to_i} THEN 0 ELSE 1 END") - end - - # Best effort, it over selects, however if you have a high number - # of muted categories there is tiny chance we will not select enough - # in particular this can happen if current category is empty and tons - # of muted, big edge case - # - # we over select in case cache is stale - max = (count * 1.3).to_i - ids = SiteSetting.limit_suggested_to_category ? [] : RandomTopicSelector.next(max) - ids.concat(RandomTopicSelector.next(max, topic.category)) - - result.where(id: ids.uniq) - end - - def suggested_ordering(result, options) - # Prefer unread in the same category - if options[:topic] && options[:topic].category_id - result = result.order("CASE WHEN topics.category_id = #{options[:topic].category_id.to_i} THEN 0 ELSE 1 END") - end - - result.order('topics.bumped_at DESC') - end + result.order('topics.bumped_at DESC') + end private - def sanitize_sql_array(input) - ActiveRecord::Base.send(:sanitize_sql_array, input.join(',')) - end + def sanitize_sql_array(input) + ActiveRecord::Base.send(:sanitize_sql_array, input.join(',')) + end end diff --git a/lib/topic_retriever.rb b/lib/topic_retriever.rb index 82f815d9f7..1addac713f 100644 --- a/lib/topic_retriever.rb +++ b/lib/topic_retriever.rb @@ -12,48 +12,48 @@ class TopicRetriever private - def invalid_url? - !EmbeddableHost.url_allowed?(@embed_url) + def invalid_url? + !EmbeddableHost.url_allowed?(@embed_url) + end + + def retrieved_recently? + # We can disable the throttle for some users, such as staff + return false if @opts[:no_throttle] + + # Throttle other users to once every 60 seconds + retrieved_key = "retrieved_topic" + if $redis.setnx(retrieved_key, "1") + $redis.expire(retrieved_key, 60) + return false end - def retrieved_recently? - # We can disable the throttle for some users, such as staff - return false if @opts[:no_throttle] + true + end - # Throttle other users to once every 60 seconds - retrieved_key = "retrieved_topic" - if $redis.setnx(retrieved_key, "1") - $redis.expire(retrieved_key, 60) - return false - end + def perform_retrieve + # It's possible another process or job found the embed already. So if that happened bail out. + return if TopicEmbed.where(embed_url: @embed_url).exists? - true - end - - def perform_retrieve - # It's possible another process or job found the embed already. So if that happened bail out. + # First check RSS if that is enabled + if SiteSetting.feed_polling_enabled? + Jobs::PollFeed.new.execute({}) return if TopicEmbed.where(embed_url: @embed_url).exists? - - # First check RSS if that is enabled - if SiteSetting.feed_polling_enabled? - Jobs::PollFeed.new.execute({}) - return if TopicEmbed.where(embed_url: @embed_url).exists? - end - - fetch_http end - def fetch_http - if @author_username.nil? - username = SiteSetting.embed_by_username.downcase - else - username = @author_username - end + fetch_http + end - user = User.where(username_lower: username.downcase).first - return if user.blank? - - TopicEmbed.import_remote(user, @embed_url) + def fetch_http + if @author_username.nil? + username = SiteSetting.embed_by_username.downcase + else + username = @author_username end + user = User.where(username_lower: username.downcase).first + return if user.blank? + + TopicEmbed.import_remote(user, @embed_url) + end + end diff --git a/lib/topics_bulk_action.rb b/lib/topics_bulk_action.rb index 2d16fb5c21..b0b5e91b7a 100644 --- a/lib/topics_bulk_action.rb +++ b/lib/topics_bulk_action.rb @@ -27,156 +27,156 @@ class TopicsBulkAction private - def find_group - return unless @options[:group] + def find_group + return unless @options[:group] - group = Group.where('name ilike ?', @options[:group]).first - raise Discourse::InvalidParameters.new(:group) unless group - unless group.group_users.where(user_id: @user.id).exists? - raise Discourse::InvalidParameters.new(:group) - end - group + group = Group.where('name ilike ?', @options[:group]).first + raise Discourse::InvalidParameters.new(:group) unless group + unless group.group_users.where(user_id: @user.id).exists? + raise Discourse::InvalidParameters.new(:group) end + group + end - def move_messages_to_inbox - group = find_group - topics.each do |t| - if guardian.can_see?(t) && t.private_message? - if group - GroupArchivedMessage.move_to_inbox!(group.id, t) - else - UserArchivedMessage.move_to_inbox!(@user.id, t) - end + def move_messages_to_inbox + group = find_group + topics.each do |t| + if guardian.can_see?(t) && t.private_message? + if group + GroupArchivedMessage.move_to_inbox!(group.id, t) + else + UserArchivedMessage.move_to_inbox!(@user.id, t) end end end + end - def archive_messages - group = find_group - topics.each do |t| - if guardian.can_see?(t) && t.private_message? - if group - GroupArchivedMessage.archive!(group.id, t) - else - UserArchivedMessage.archive!(@user.id, t) - end + def archive_messages + group = find_group + topics.each do |t| + if guardian.can_see?(t) && t.private_message? + if group + GroupArchivedMessage.archive!(group.id, t) + else + UserArchivedMessage.archive!(@user.id, t) end end end + end - def dismiss_posts - sql = " - UPDATE topic_users tu - SET highest_seen_post_number = t.highest_post_number , last_read_post_number = highest_post_number - FROM topics t - WHERE t.id = tu.topic_id AND tu.user_id = :user_id AND t.id IN (:topic_ids) - " + def dismiss_posts + sql = " + UPDATE topic_users tu + SET highest_seen_post_number = t.highest_post_number , last_read_post_number = highest_post_number + FROM topics t + WHERE t.id = tu.topic_id AND tu.user_id = :user_id AND t.id IN (:topic_ids) + " - Topic.exec_sql(sql, user_id: @user.id, topic_ids: @topic_ids) - @changed_ids.concat @topic_ids - end + Topic.exec_sql(sql, user_id: @user.id, topic_ids: @topic_ids) + @changed_ids.concat @topic_ids + end - def reset_read - PostTiming.destroy_for(@user.id, @topic_ids) - end + def reset_read + PostTiming.destroy_for(@user.id, @topic_ids) + end - def change_category - topics.each do |t| - if guardian.can_edit?(t) - @changed_ids << t.id if t.change_category_to_id(@operation[:category_id]) - end + def change_category + topics.each do |t| + if guardian.can_edit?(t) + @changed_ids << t.id if t.change_category_to_id(@operation[:category_id]) end end + end - def change_notification_level - topics.each do |t| - if guardian.can_see?(t) - TopicUser.change(@user, t.id, notification_level: @operation[:notification_level_id].to_i) - @changed_ids << t.id - end - end - end - - def close - topics.each do |t| - if guardian.can_moderate?(t) - t.update_status('closed', true, @user) - @changed_ids << t.id - end - end - end - - def unlist - topics.each do |t| - if guardian.can_moderate?(t) - t.update_status('visible', false, @user) - @changed_ids << t.id - end - end - end - - def relist - topics.each do |t| - if guardian.can_moderate?(t) - t.update_status('visible', true, @user) - @changed_ids << t.id - end - end - end - - def archive - topics.each do |t| - if guardian.can_moderate?(t) - t.update_status('archived', true, @user) - @changed_ids << t.id - end - end - end - - def delete - topics.each do |t| - if guardian.can_delete?(t) - PostDestroyer.new(@user, t.ordered_posts.first).destroy - end - end - end - - def change_tags - tags = @operation[:tags] - tags = DiscourseTagging.tags_for_saving(tags, guardian) if tags.present? - - topics.each do |t| - if guardian.can_edit?(t) - if tags.present? - DiscourseTagging.tag_topic_by_names(t, guardian, tags) - else - t.tags = [] - end - @changed_ids << t.id - end - end - end - - def append_tags - tags = @operation[:tags] - tags = DiscourseTagging.tags_for_saving(tags, guardian) if tags.present? - - topics.each do |t| - if guardian.can_edit?(t) - if tags.present? - DiscourseTagging.tag_topic_by_names(t, guardian, tags, append: true) - end + def change_notification_level + topics.each do |t| + if guardian.can_see?(t) + TopicUser.change(@user, t.id, notification_level: @operation[:notification_level_id].to_i) @changed_ids << t.id - end end end + end - def guardian - @guardian ||= Guardian.new(@user) + def close + topics.each do |t| + if guardian.can_moderate?(t) + t.update_status('closed', true, @user) + @changed_ids << t.id + end end + end - def topics - @topics ||= Topic.where(id: @topic_ids) + def unlist + topics.each do |t| + if guardian.can_moderate?(t) + t.update_status('visible', false, @user) + @changed_ids << t.id + end end + end + + def relist + topics.each do |t| + if guardian.can_moderate?(t) + t.update_status('visible', true, @user) + @changed_ids << t.id + end + end + end + + def archive + topics.each do |t| + if guardian.can_moderate?(t) + t.update_status('archived', true, @user) + @changed_ids << t.id + end + end + end + + def delete + topics.each do |t| + if guardian.can_delete?(t) + PostDestroyer.new(@user, t.ordered_posts.first).destroy + end + end + end + + def change_tags + tags = @operation[:tags] + tags = DiscourseTagging.tags_for_saving(tags, guardian) if tags.present? + + topics.each do |t| + if guardian.can_edit?(t) + if tags.present? + DiscourseTagging.tag_topic_by_names(t, guardian, tags) + else + t.tags = [] + end + @changed_ids << t.id + end + end + end + + def append_tags + tags = @operation[:tags] + tags = DiscourseTagging.tags_for_saving(tags, guardian) if tags.present? + + topics.each do |t| + if guardian.can_edit?(t) + if tags.present? + DiscourseTagging.tag_topic_by_names(t, guardian, tags, append: true) + end + @changed_ids << t.id + end + end + end + + def guardian + @guardian ||= Guardian.new(@user) + end + + def topics + @topics ||= Topic.where(id: @topic_ids) + end end diff --git a/lib/validators/censored_words_validator.rb b/lib/validators/censored_words_validator.rb index 96749c845c..b2c70bc931 100644 --- a/lib/validators/censored_words_validator.rb +++ b/lib/validators/censored_words_validator.rb @@ -10,23 +10,23 @@ class CensoredWordsValidator < ActiveModel::EachValidator private - def censor_words(value, regexp) - censored_words = value.scan(regexp) - censored_words.flatten! - censored_words.compact! - censored_words.map!(&:strip) - censored_words.select!(&:present?) - censored_words.uniq! - censored_words - end + def censor_words(value, regexp) + censored_words = value.scan(regexp) + censored_words.flatten! + censored_words.compact! + censored_words.map!(&:strip) + censored_words.select!(&:present?) + censored_words.uniq! + censored_words + end - def join_censored_words(censored_words) - censored_words.map!(&:downcase) - censored_words.uniq! - censored_words.join(", ".freeze) - end + def join_censored_words(censored_words) + censored_words.map!(&:downcase) + censored_words.uniq! + censored_words.join(", ".freeze) + end - def censored_words_regexp - WordWatcher.word_matcher_regexp :censor - end + def censored_words_regexp + WordWatcher.word_matcher_regexp :censor + end end diff --git a/lib/validators/pop3_polling_enabled_setting_validator.rb b/lib/validators/pop3_polling_enabled_setting_validator.rb index d002f4eee7..0b79dc8d88 100644 --- a/lib/validators/pop3_polling_enabled_setting_validator.rb +++ b/lib/validators/pop3_polling_enabled_setting_validator.rb @@ -30,15 +30,15 @@ class POP3PollingEnabledSettingValidator private - def authentication_works? - @authentication_works ||= begin - pop3 = Net::POP3.new(SiteSetting.pop3_polling_host, SiteSetting.pop3_polling_port) - pop3.enable_ssl(OpenSSL::SSL::VERIFY_NONE) if SiteSetting.pop3_polling_ssl - pop3.auth_only(SiteSetting.pop3_polling_username, SiteSetting.pop3_polling_password) - rescue Net::POPAuthenticationError - false - else - true - end + def authentication_works? + @authentication_works ||= begin + pop3 = Net::POP3.new(SiteSetting.pop3_polling_host, SiteSetting.pop3_polling_port) + pop3.enable_ssl(OpenSSL::SSL::VERIFY_NONE) if SiteSetting.pop3_polling_ssl + pop3.auth_only(SiteSetting.pop3_polling_username, SiteSetting.pop3_polling_password) + rescue Net::POPAuthenticationError + false + else + true end + end end diff --git a/lib/validators/topic_title_length_validator.rb b/lib/validators/topic_title_length_validator.rb index bdee42c81c..6e4a1d1701 100644 --- a/lib/validators/topic_title_length_validator.rb +++ b/lib/validators/topic_title_length_validator.rb @@ -6,17 +6,17 @@ class TopicTitleLengthValidator < ActiveModel::EachValidator private - def title_validator(record) - length_range = - if record.user.try(:admin?) - 1..SiteSetting.max_topic_title_length - elsif record.private_message? - SiteSetting.private_message_title_length - else - SiteSetting.topic_title_length - end + def title_validator(record) + length_range = + if record.user.try(:admin?) + 1..SiteSetting.max_topic_title_length + elsif record.private_message? + SiteSetting.private_message_title_length + else + SiteSetting.topic_title_length + end - ActiveModel::Validations::LengthValidator.new(attributes: :title, in: length_range, allow_blank: true) - end + ActiveModel::Validations::LengthValidator.new(attributes: :title, in: length_range, allow_blank: true) + end end diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/certificate_generator.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/certificate_generator.rb index bb1f4dbeff..2fad2f8477 100644 --- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/certificate_generator.rb +++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/certificate_generator.rb @@ -563,49 +563,49 @@ module DiscourseNarrativeBot private - def name - @user.username.titleize - end + def name + @user.username.titleize + end - def logo_group(size, width, height) - return unless SiteSetting.logo_small_url.present? + def logo_group(size, width, height) + return unless SiteSetting.logo_small_url.present? - begin - uri = URI(SiteSetting.logo_small_url) + begin + uri = URI(SiteSetting.logo_small_url) - logo_uri = - if uri.host.blank? || uri.scheme.blank? - URI("#{Discourse.base_url}/#{uri.path}") - else - uri - end + logo_uri = + if uri.host.blank? || uri.scheme.blank? + URI("#{Discourse.base_url}/#{uri.path}") + else + uri + end - <<~URL + <<~URL URL - rescue URI::InvalidURIError - '' - end + rescue URI::InvalidURIError + '' end + end - def base64_image_link(url) - if image = fetch_image(url) - "xlink:href=\"data:image/png;base64,#{Base64.strict_encode64(image)}\"" - else - "" - end + def base64_image_link(url) + if image = fetch_image(url) + "xlink:href=\"data:image/png;base64,#{Base64.strict_encode64(image)}\"" + else + "" end + end - def fetch_image(url) - URI(url).open('rb', redirect: true, allow_redirections: :all).read - rescue OpenURI::HTTPError - # Ignore if fetching image returns a non 200 response - end + def fetch_image(url) + URI(url).open('rb', redirect: true, allow_redirections: :all).read + rescue OpenURI::HTTPError + # Ignore if fetching image returns a non 200 response + end - def avatar_url - UrlHelper.absolute(Discourse.base_uri + @user.avatar_template.gsub('{size}', '250')) - end + def avatar_url + UrlHelper.absolute(Discourse.base_uri + @user.avatar_template.gsub('{size}', '250')) + end end end diff --git a/script/import_scripts/quandora/quandora_question.rb b/script/import_scripts/quandora/quandora_question.rb index 6105ef895d..9eb59c9e30 100644 --- a/script/import_scripts/quandora/quandora_question.rb +++ b/script/import_scripts/quandora/quandora_question.rb @@ -8,102 +8,102 @@ class QuandoraQuestion @question = JSON.parse question_json end - def topic - topic = {} - topic[:id] = @question['uid'] - topic[:author_id] = @question['author']['uid'] - topic[:title] = unescape @question['title'] - topic[:raw] = unescape @question['content'] - topic[:created_at] = Time.parse @question['created'] - topic - end + def topic + topic = {} + topic[:id] = @question['uid'] + topic[:author_id] = @question['author']['uid'] + topic[:title] = unescape @question['title'] + topic[:raw] = unescape @question['content'] + topic[:created_at] = Time.parse @question['created'] + topic + end - def users - users = {} - user = user_from_author @question['author'] - users[user[:id]] = user - replies.each do |reply| - user = user_from_author reply[:author] - users[user[:id]] = user - end - users.values.to_a - end + def users + users = {} + user = user_from_author @question['author'] + users[user[:id]] = user + replies.each do |reply| + user = user_from_author reply[:author] + users[user[:id]] = user + end + users.values.to_a + end - def user_from_author(author) - email = author['email'] - email = "#{author['uid']}@noemail.com" unless email + def user_from_author(author) + email = author['email'] + email = "#{author['uid']}@noemail.com" unless email - user = {} - user[:id] = author['uid'] - user[:name] = "#{author['firstName']} #{author['lastName']}" - user[:email] = email - user[:staged] = true - user - end + user = {} + user[:id] = author['uid'] + user[:name] = "#{author['firstName']} #{author['lastName']}" + user[:email] = email + user[:staged] = true + user + end - def replies - posts = [] - answers = @question['answersList'] - comments = @question['comments'] - comments.each_with_index do |comment, i| - posts << post_from_comment(comment, i, @question) - end - answers.each do |answer| - posts << post_from_answer(answer) - comments = answer['comments'] - comments.each_with_index do |comment, i| - posts << post_from_comment(comment, i, answer) - end - end - order_replies posts - end + def replies + posts = [] + answers = @question['answersList'] + comments = @question['comments'] + comments.each_with_index do |comment, i| + posts << post_from_comment(comment, i, @question) + end + answers.each do |answer| + posts << post_from_answer(answer) + comments = answer['comments'] + comments.each_with_index do |comment, i| + posts << post_from_comment(comment, i, answer) + end + end + order_replies posts + end - def order_replies(posts) - posts = posts.sort_by { |p| p[:created_at] } - posts.each_with_index do |p, i| - p[:post_number] = i + 2 - end - posts.each do |p| - parent = posts.select { |pp| pp[:id] == p[:parent_id] } - p[:reply_to_post_number] = parent[0][:post_number] if parent.size > 0 - end - posts - end + def order_replies(posts) + posts = posts.sort_by { |p| p[:created_at] } + posts.each_with_index do |p, i| + p[:post_number] = i + 2 + end + posts.each do |p| + parent = posts.select { |pp| pp[:id] == p[:parent_id] } + p[:reply_to_post_number] = parent[0][:post_number] if parent.size > 0 + end + posts + end - def post_from_answer(answer) - post = {} - post[:id] = answer['uid'] - post[:parent_id] = @question['uid'] - post[:author] = answer['author'] - post[:author_id] = answer['author']['uid'] - post[:raw] = unescape answer['content'] - post[:created_at] = Time.parse answer['created'] - post - end + def post_from_answer(answer) + post = {} + post[:id] = answer['uid'] + post[:parent_id] = @question['uid'] + post[:author] = answer['author'] + post[:author_id] = answer['author']['uid'] + post[:raw] = unescape answer['content'] + post[:created_at] = Time.parse answer['created'] + post + end - def post_from_comment(comment, index, parent) - if comment['created'] - created_at = Time.parse comment['created'] - else - created_at = Time.parse parent['created'] - end - parent_id = parent['uid'] - parent_id = "#{parent['uid']}-#{index - 1}" if index > 0 - post = {} - id = "#{parent['uid']}-#{index}" - post[:id] = id - post[:parent_id] = parent_id - post[:author] = comment['author'] - post[:author_id] = comment['author']['uid'] - post[:raw] = unescape comment['text'] - post[:created_at] = created_at - post - end + def post_from_comment(comment, index, parent) + if comment['created'] + created_at = Time.parse comment['created'] + else + created_at = Time.parse parent['created'] + end + parent_id = parent['uid'] + parent_id = "#{parent['uid']}-#{index - 1}" if index > 0 + post = {} + id = "#{parent['uid']}-#{index}" + post[:id] = id + post[:parent_id] = parent_id + post[:author] = comment['author'] + post[:author_id] = comment['author']['uid'] + post[:raw] = unescape comment['text'] + post[:created_at] = created_at + post + end private - def unescape(html) - return nil unless html - CGI.unescapeHTML html - end + def unescape(html) + return nil unless html + CGI.unescapeHTML html + end end diff --git a/script/import_scripts/socialcast/socialcast_message.rb b/script/import_scripts/socialcast/socialcast_message.rb index a82149f2ab..e121c5695d 100644 --- a/script/import_scripts/socialcast/socialcast_message.rb +++ b/script/import_scripts/socialcast/socialcast_message.rb @@ -18,81 +18,81 @@ class SocialcastMessage } } - def initialize(message_json) - @parsed_json = JSON.parse message_json - end + def initialize(message_json) + @parsed_json = JSON.parse message_json + end - def topic - topic = {} - topic[:id] = @parsed_json['id'] - topic[:author_id] = @parsed_json['user']['id'] - topic[:title] = title - topic[:raw] = @parsed_json['body'] - topic[:created_at] = Time.parse @parsed_json['created_at'] - topic[:tags] = tags - topic[:category] = category - topic - end + def topic + topic = {} + topic[:id] = @parsed_json['id'] + topic[:author_id] = @parsed_json['user']['id'] + topic[:title] = title + topic[:raw] = @parsed_json['body'] + topic[:created_at] = Time.parse @parsed_json['created_at'] + topic[:tags] = tags + topic[:category] = category + topic + end - def title - CreateTitle.from_body @parsed_json['body'] - end + def title + CreateTitle.from_body @parsed_json['body'] + end - def tags - tags = [] - if group - if TAGS_AND_CATEGORIES[group] - tags = TAGS_AND_CATEGORIES[group][:tags] - else - tags << group - end - end - tags << DEFAULT_TAG - tags - end + def tags + tags = [] + if group + if TAGS_AND_CATEGORIES[group] + tags = TAGS_AND_CATEGORIES[group][:tags] + else + tags << group + end + end + tags << DEFAULT_TAG + tags + end - def category - category = DEFAULT_CATEGORY - if group && TAGS_AND_CATEGORIES[group] - category = TAGS_AND_CATEGORIES[group][:category] - end - category - end + def category + category = DEFAULT_CATEGORY + if group && TAGS_AND_CATEGORIES[group] + category = TAGS_AND_CATEGORIES[group][:category] + end + category + end - def group - @parsed_json['group']['groupname'].downcase if @parsed_json['group'] && @parsed_json['group']['groupname'] - end + def group + @parsed_json['group']['groupname'].downcase if @parsed_json['group'] && @parsed_json['group']['groupname'] + end - def url - @parsed_json['url'] - end + def url + @parsed_json['url'] + end - def message_type - @parsed_json['message_type'] - end + def message_type + @parsed_json['message_type'] + end - def replies - posts = [] - comments = @parsed_json['comments'] - comments.each do |comment| - posts << post_from_comment(comment) - end - posts - end + def replies + posts = [] + comments = @parsed_json['comments'] + comments.each do |comment| + posts << post_from_comment(comment) + end + posts + end - def post_from_comment(comment) - post = {} - post[:id] = comment['id'] - post[:author_id] = comment['user']['id'] - post[:raw] = comment['text'] - post[:created_at] = Time.parse comment['created_at'] - post - end + def post_from_comment(comment) + post = {} + post[:id] = comment['id'] + post[:author_id] = comment['user']['id'] + post[:raw] = comment['text'] + post[:created_at] = Time.parse comment['created_at'] + post + end - private + private - def unescape(html) - return nil unless html - CGI.unescapeHTML html - end + def unescape(html) + return nil unless html + CGI.unescapeHTML html + end end diff --git a/script/import_scripts/socialcast/socialcast_user.rb b/script/import_scripts/socialcast/socialcast_user.rb index 54107b4636..fb4217318c 100644 --- a/script/import_scripts/socialcast/socialcast_user.rb +++ b/script/import_scripts/socialcast/socialcast_user.rb @@ -8,17 +8,17 @@ class SocialcastUser @parsed_json = JSON.parse user_json end - def user - email = @parsed_json['contact_info']['email'] - email = "#{@parsed_json['id']}@noemail.com" unless email + def user + email = @parsed_json['contact_info']['email'] + email = "#{@parsed_json['id']}@noemail.com" unless email - user = {} - user[:id] = @parsed_json['id'] - user[:name] = @parsed_json['name'] - user[:username] = @parsed_json['username'] - user[:email] = email - user[:staged] = true - user - end + user = {} + user[:id] = @parsed_json['id'] + user[:name] = @parsed_json['name'] + user[:username] = @parsed_json['username'] + user[:email] = email + user[:staged] = true + user + end end diff --git a/script/import_scripts/vanilla.rb b/script/import_scripts/vanilla.rb index 9471290559..0a9b057eec 100644 --- a/script/import_scripts/vanilla.rb +++ b/script/import_scripts/vanilla.rb @@ -28,226 +28,226 @@ class ImportScripts::Vanilla < ImportScripts::Base private - def check_file_exist - raise ArgumentError.new("File does not exist: #{@vanilla_file}") unless File.exist?(@vanilla_file) - end + def check_file_exist + raise ArgumentError.new("File does not exist: #{@vanilla_file}") unless File.exist?(@vanilla_file) + end - def parse_file - puts "parsing file..." - file = read_file + def parse_file + puts "parsing file..." + file = read_file - # TODO: parse header & validate version number - header = file.readline + # TODO: parse header & validate version number + header = file.readline - until file.eof? - line = file.readline - next if line.blank? - next if line.start_with?("//") + until file.eof? + line = file.readline + next if line.blank? + next if line.start_with?("//") - if m = /^Table: (\w+)/.match(line) - # extract table name - table = m[1].underscore.pluralize - # read the data until an empty line - data = [] - # first line is the table definition, turn that into a proper csv header - data << file.readline.split(",").map { |c| c.split(":")[0].underscore }.join(",") - until (line = file.readline).blank? - data << line.strip - end - # PERF: don't parse useless tables - useless_tables = ["user_meta"] - useless_tables << "activities" unless @use_lastest_activity_as_user_bio - next if useless_tables.include?(table) - # parse the data - puts "parsing #{table}..." - parsed_data = CSV.parse(data.join("\n"), headers: true, header_converters: :symbol).map { |row| row.to_hash } - instance_variable_set("@#{table}".to_sym, parsed_data) + if m = /^Table: (\w+)/.match(line) + # extract table name + table = m[1].underscore.pluralize + # read the data until an empty line + data = [] + # first line is the table definition, turn that into a proper csv header + data << file.readline.split(",").map { |c| c.split(":")[0].underscore }.join(",") + until (line = file.readline).blank? + data << line.strip end + # PERF: don't parse useless tables + useless_tables = ["user_meta"] + useless_tables << "activities" unless @use_lastest_activity_as_user_bio + next if useless_tables.include?(table) + # parse the data + puts "parsing #{table}..." + parsed_data = CSV.parse(data.join("\n"), headers: true, header_converters: :symbol).map { |row| row.to_hash } + instance_variable_set("@#{table}".to_sym, parsed_data) end end + end - def read_file - puts "reading file..." - string = File.read(@vanilla_file).gsub("\\N", "") - .gsub(/\\$\n/m, "\\n") - .gsub("\\,", ",") - .gsub(/(? 0 - puts "", "importing first-level categories..." - create_categories(first_level_categories) { |category| import_category(category) } - - # adds other categories - second_level_categories = @categories.select { |c| c[:parent_category_id] != "-1" } - if second_level_categories.count > 0 - puts "", "importing second-level categories..." - create_categories(second_level_categories) { |category| import_category(category) } - end - end - end - - def import_category(category) - c = { - id: category[:category_id], - name: category[:name], - user_id: user_id_from_imported_user_id(category[:insert_user_id]) || Discourse::SYSTEM_USER_ID, - position: category[:sort].to_i, - created_at: parse_category_date(category[:date_inserted]), - description: clean_up(category[:description]), + u = { + id: user[:user_id], + email: user[:email], + username: user[:name], + created_at: parse_date(user[:date_inserted]), + bio_raw: clean_up(bio_raw), + avatar_url: user[:photo], + moderator: @user_roles.select { |ur| ur[:user_id] == user[:user_id] }.map { |ur| ur[:role_id] }.include?(moderator_role_id), + admin: @user_roles.select { |ur| ur[:user_id] == user[:user_id] }.map { |ur| ur[:role_id] }.include?(admin_role_id), } - if category[:parent_category_id] != "-1" - c[:parent_category_id] = category_id_from_imported_category_id(category[:parent_category_id]) - end - c + + u end + end - def parse_category_date(date) - date == "0000-00-00 00:00:00" ? @root_category_created_at : parse_date(date) - end + def import_categories + puts "", "importing categories..." - def import_topics - puts "", "importing topics..." + # save some information about the root category + @root_category = @categories.select { |c| c[:category_id] == "-1" }.first + @root_category_created_at = parse_date(@root_category[:date_inserted]) - create_posts(@discussions) do |discussion| - { - id: "discussion#" + discussion[:discussion_id], - user_id: user_id_from_imported_user_id(discussion[:insert_user_id]) || Discourse::SYSTEM_USER_ID, - title: discussion[:name], - category: category_id_from_imported_category_id(discussion[:category_id]), - raw: clean_up(discussion[:body]), - created_at: parse_date(discussion[:date_inserted]), - } + # removes root category + @categories.reject! { |c| c[:category_id] == "-1" } + + # adds root's child categories + first_level_categories = @categories.select { |c| c[:parent_category_id] == "-1" } + if first_level_categories.count > 0 + puts "", "importing first-level categories..." + create_categories(first_level_categories) { |category| import_category(category) } + + # adds other categories + second_level_categories = @categories.select { |c| c[:parent_category_id] != "-1" } + if second_level_categories.count > 0 + puts "", "importing second-level categories..." + create_categories(second_level_categories) { |category| import_category(category) } end end + end - def import_posts - puts "", "importing posts..." - - create_posts(@comments) do |comment| - next unless t = topic_lookup_from_imported_post_id("discussion#" + comment[:discussion_id]) - - { - id: "comment#" + comment[:comment_id], - user_id: user_id_from_imported_user_id(comment[:insert_user_id]) || Discourse::SYSTEM_USER_ID, - topic_id: t[:topic_id], - raw: clean_up(comment[:body]), - created_at: parse_date(comment[:date_inserted]), - } - end + def import_category(category) + c = { + id: category[:category_id], + name: category[:name], + user_id: user_id_from_imported_user_id(category[:insert_user_id]) || Discourse::SYSTEM_USER_ID, + position: category[:sort].to_i, + created_at: parse_category_date(category[:date_inserted]), + description: clean_up(category[:description]), + } + if category[:parent_category_id] != "-1" + c[:parent_category_id] = category_id_from_imported_category_id(category[:parent_category_id]) end + c + end - def import_private_topics - puts "", "importing private topics..." + def parse_category_date(date) + date == "0000-00-00 00:00:00" ? @root_category_created_at : parse_date(date) + end - create_posts(@conversations) do |conversation| - next if conversation[:first_message_id].blank? + def import_topics + puts "", "importing topics..." - # list all other user ids in the conversation - user_ids_in_conversation = @user_conversations.select { |uc| uc[:conversation_id] == conversation[:conversation_id] && uc[:user_id] != conversation[:insert_user_id] } - .map { |uc| uc[:user_id] } - # retrieve their emails - user_emails_in_conversation = @users.select { |u| user_ids_in_conversation.include?(u[:user_id]) } - .map { |u| u[:email] } - # retrieve their usernames from the database - target_usernames = User.where("email IN (?)", user_emails_in_conversation).pluck(:username).to_a - - next if target_usernames.blank? - - user = find_user_by_import_id(conversation[:insert_user_id]) || Discourse.system_user - first_message = @conversation_messages.select { |cm| cm[:message_id] == conversation[:first_message_id] }.first - - { - archetype: Archetype.private_message, - id: "conversation#" + conversation[:conversation_id], - user_id: user.id, - title: "Private message from #{user.username}", - target_usernames: target_usernames, - raw: clean_up(first_message[:body]), - created_at: parse_date(conversation[:date_inserted]), - } - end + create_posts(@discussions) do |discussion| + { + id: "discussion#" + discussion[:discussion_id], + user_id: user_id_from_imported_user_id(discussion[:insert_user_id]) || Discourse::SYSTEM_USER_ID, + title: discussion[:name], + category: category_id_from_imported_category_id(discussion[:category_id]), + raw: clean_up(discussion[:body]), + created_at: parse_date(discussion[:date_inserted]), + } end + end - def import_private_posts - puts "", "importing private posts..." + def import_posts + puts "", "importing posts..." - first_message_ids = Set.new(@conversations.map { |c| c[:first_message_id] }.to_a) - @conversation_messages.reject! { |cm| first_message_ids.include?(cm[:message_id]) } + create_posts(@comments) do |comment| + next unless t = topic_lookup_from_imported_post_id("discussion#" + comment[:discussion_id]) - create_posts(@conversation_messages) do |message| - next unless t = topic_lookup_from_imported_post_id("conversation#" + message[:conversation_id]) - - { - archetype: Archetype.private_message, - id: "message#" + message[:message_id], - user_id: user_id_from_imported_user_id(message[:insert_user_id]) || Discourse::SYSTEM_USER_ID, - topic_id: t[:topic_id], - raw: clean_up(message[:body]), - created_at: parse_date(message[:date_inserted]), - } - end + { + id: "comment#" + comment[:comment_id], + user_id: user_id_from_imported_user_id(comment[:insert_user_id]) || Discourse::SYSTEM_USER_ID, + topic_id: t[:topic_id], + raw: clean_up(comment[:body]), + created_at: parse_date(comment[:date_inserted]), + } end + end - def parse_date(date) - DateTime.strptime(date, "%Y-%m-%d %H:%M:%S") - end + def import_private_topics + puts "", "importing private topics..." - def clean_up(raw) - return "" if raw.blank? - raw.gsub("\\n", "\n") - .gsub(/<\/?pre\s*>/i, "\n```\n") - .gsub(/<\/?code\s*>/i, "`") - .gsub("<", "<") - .gsub(">", ">") + create_posts(@conversations) do |conversation| + next if conversation[:first_message_id].blank? + + # list all other user ids in the conversation + user_ids_in_conversation = @user_conversations.select { |uc| uc[:conversation_id] == conversation[:conversation_id] && uc[:user_id] != conversation[:insert_user_id] } + .map { |uc| uc[:user_id] } + # retrieve their emails + user_emails_in_conversation = @users.select { |u| user_ids_in_conversation.include?(u[:user_id]) } + .map { |u| u[:email] } + # retrieve their usernames from the database + target_usernames = User.where("email IN (?)", user_emails_in_conversation).pluck(:username).to_a + + next if target_usernames.blank? + + user = find_user_by_import_id(conversation[:insert_user_id]) || Discourse.system_user + first_message = @conversation_messages.select { |cm| cm[:message_id] == conversation[:first_message_id] }.first + + { + archetype: Archetype.private_message, + id: "conversation#" + conversation[:conversation_id], + user_id: user.id, + title: "Private message from #{user.username}", + target_usernames: target_usernames, + raw: clean_up(first_message[:body]), + created_at: parse_date(conversation[:date_inserted]), + } end + end + + def import_private_posts + puts "", "importing private posts..." + + first_message_ids = Set.new(@conversations.map { |c| c[:first_message_id] }.to_a) + @conversation_messages.reject! { |cm| first_message_ids.include?(cm[:message_id]) } + + create_posts(@conversation_messages) do |message| + next unless t = topic_lookup_from_imported_post_id("conversation#" + message[:conversation_id]) + + { + archetype: Archetype.private_message, + id: "message#" + message[:message_id], + user_id: user_id_from_imported_user_id(message[:insert_user_id]) || Discourse::SYSTEM_USER_ID, + topic_id: t[:topic_id], + raw: clean_up(message[:body]), + created_at: parse_date(message[:date_inserted]), + } + end + end + + def parse_date(date) + DateTime.strptime(date, "%Y-%m-%d %H:%M:%S") + end + + def clean_up(raw) + return "" if raw.blank? + raw.gsub("\\n", "\n") + .gsub(/<\/?pre\s*>/i, "\n```\n") + .gsub(/<\/?code\s*>/i, "`") + .gsub("<", "<") + .gsub(">", ">") + end end From 1e805cfd3e3dc1e52557c1fbca7f5c404c3b2261 Mon Sep 17 00:00:00 2001 From: OsamaSayegh Date: Thu, 7 Jun 2018 08:51:52 +0300 Subject: [PATCH 0093/1439] REFACTOR: composer messages controller specs to requests (#5940) --- .../composer_messages_controller_spec.rb | 29 ---------------- .../composer_messages_controller_spec.rb | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 29 deletions(-) delete mode 100644 spec/controllers/composer_messages_controller_spec.rb create mode 100644 spec/requests/composer_messages_controller_spec.rb diff --git a/spec/controllers/composer_messages_controller_spec.rb b/spec/controllers/composer_messages_controller_spec.rb deleted file mode 100644 index 27338ed890..0000000000 --- a/spec/controllers/composer_messages_controller_spec.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'rails_helper' - -describe ComposerMessagesController do - - context '.index' do - - it 'requires you to be logged in' do - get :index, format: :json - expect(response.status).to eq(403) - end - - context 'when logged in' do - let!(:user) { log_in } - let(:args) { { 'topic_id' => '123', 'post_id' => '333', 'composer_action' => 'reply' } } - - it 'redirects to your user preferences' do - get :index, format: :json - expect(response).to be_successful - end - - it 'delegates args to the finder' do - finder = mock - ComposerMessagesFinder.expects(:new).with(instance_of(User), has_entries(args)).returns(finder) - finder.expects(:find) - get :index, params: args, format: :json - end - end - end -end diff --git a/spec/requests/composer_messages_controller_spec.rb b/spec/requests/composer_messages_controller_spec.rb new file mode 100644 index 0000000000..ea3163ccfa --- /dev/null +++ b/spec/requests/composer_messages_controller_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + +describe ComposerMessagesController do + let(:topic) { Fabricate(:topic, created_at: 10.years.ago, last_posted_at: 10.years.ago) } + let(:post) { Fabricate(:post, topic: topic, post_number: 1, created_at: 10.years.ago) } + + context '#index' do + it 'requires you to be logged in' do + get "/composer_messages.json" + expect(response.status).to eq(403) + end + + context 'when logged in' do + let!(:user) { sign_in(Fabricate(:user)) } + let(:args) { { 'topic_id' => post.topic.id, 'post_id' => '333', 'composer_action' => 'reply' } } + + it 'redirects to your user preferences' do + get "/composer_messages.json" + expect(response.status).to eq(200) + end + + it 'delegates args to the finder' do + user.user_stat.update!(post_count: 10) + SiteSetting.disable_avatar_education_message = true + + get "/composer_messages.json", params: args + expect(response.status).to eq(200) + json = JSON.parse(response.body) + expect(json["composer_messages"].first["id"]).to eq("reviving_old") + end + end + end +end From 24c7d2913b8a70a1d3bacf5f1158fdb3b7c1ac8b Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 15:53:31 +1000 Subject: [PATCH 0094/1439] DEV: organise fixture so all drops happen at the end --- db/fixtures/001_categories.rb | 9 - db/fixtures/002_groups.rb | 9 - db/fixtures/009_users.rb | 72 -------- db/fixtures/600_themes.rb | 9 - .../{999_settings.rb => 990_settings.rb} | 0 db/fixtures/{999_topics.rb => 990_topics.rb} | 46 ----- db/fixtures/999_delayed.rb | 163 ++++++++++++++++-- 7 files changed, 153 insertions(+), 155 deletions(-) rename db/fixtures/{999_settings.rb => 990_settings.rb} (100%) rename db/fixtures/{999_topics.rb => 990_topics.rb} (76%) diff --git a/db/fixtures/001_categories.rb b/db/fixtures/001_categories.rb index f21181180e..aef949349c 100644 --- a/db/fixtures/001_categories.rb +++ b/db/fixtures/001_categories.rb @@ -25,12 +25,3 @@ if uncat_id == -1 || !Category.exists?(uncat_id) Category.exec_sql "INSERT INTO site_settings(name, data_type, value, created_at, updated_at) VALUES ('uncategorized_category_id', 3, #{category_id}, now(), now())" end - -Migration::ColumnDropper.drop( - table: 'categories', - after_migration: 'AddSuppressFromLatestToCategories', - columns: ['logo_url', 'background_url', 'suppress_from_homepage'], - on_drop: ->() { - STDERR.puts 'Removing superflous categories columns!' - } -) diff --git a/db/fixtures/002_groups.rb b/db/fixtures/002_groups.rb index cbf32466c3..319bb30797 100644 --- a/db/fixtures/002_groups.rb +++ b/db/fixtures/002_groups.rb @@ -4,12 +4,3 @@ if g = Group.find_by(name: 'trust_level_5', id: 15) end Group.where(name: 'everyone').update_all(visibility_level: Group.visibility_levels[:owners]) - -Migration::ColumnDropper.drop( - table: 'groups', - after_migration: 'SplitAliasLevels', - columns: %w[visible public alias_level], - on_drop: ->() { - STDERR.puts 'Removing superflous visible group column!' - } -) diff --git a/db/fixtures/009_users.rb b/db/fixtures/009_users.rb index fb6f6ee5ba..a2ca6f7dda 100644 --- a/db/fixtures/009_users.rb +++ b/db/fixtures/009_users.rb @@ -33,78 +33,6 @@ UserOption.where(user_id: -1).update_all( Group.user_trust_level_change!(-1, TrustLevel[4]) -Migration::ColumnDropper.drop( - table: 'users', - after_migration: 'DropEmailFromUsers', - columns: %w[ - email - email_always - mailing_list_mode - email_digests - email_direct - email_private_messages - external_links_in_new_tab - enable_quoting - dynamic_favicon - disable_jump_reply - edit_history_public - automatically_unpin_topics - digest_after_days - auto_track_topics_after_msecs - new_topic_duration_minutes - last_redirected_to_top_at - auth_token - auth_token_updated_at - ], - on_drop: ->() { - STDERR.puts 'Removing superflous users columns!' - } -) - -Migration::ColumnDropper.drop( - table: 'users', - after_migration: 'RenameBlockedSilence', - columns: %w[ - blocked - ], - on_drop: ->() { - STDERR.puts 'Removing user blocked column!' - } -) - -Migration::ColumnDropper.drop( - table: 'users', - after_migration: 'AddSilencedTillToUsers', - columns: %w[ - silenced - ], - on_drop: ->() { - STDERR.puts 'Removing user silenced column!' - } -) - -Migration::ColumnDropper.drop( - table: 'users', - after_migration: 'AddTrustLevelLocksToUsers', - columns: %w[ - trust_level_locked - ], - on_drop: ->() { - STDERR.puts 'Removing user trust_level_locked!' - } -) - -Migration::ColumnDropper.drop( - table: 'user_auth_tokens', - after_migration: 'RemoveLegacyAuthToken', - columns: %w[ - legacy - ], - on_drop: ->() { - STDERR.puts 'Removing user_auth_token legacy column!' - } -) - # User for the smoke tests if ENV["SMOKE"] == "1" UserEmail.seed do |ue| diff --git a/db/fixtures/600_themes.rb b/db/fixtures/600_themes.rb index 84694a5ec0..0575e1ea29 100644 --- a/db/fixtures/600_themes.rb +++ b/db/fixtures/600_themes.rb @@ -17,12 +17,3 @@ if !Theme.exists? default_theme.set_default! end - -Migration::ColumnDropper.drop( - table: 'theme_fields', - after_migration: 'AddUploadIdToThemeFields', - columns: ['target'], - on_drop: ->() { - STDERR.puts 'Removing superflous theme_fields target column!' - } -) diff --git a/db/fixtures/999_settings.rb b/db/fixtures/990_settings.rb similarity index 100% rename from db/fixtures/999_settings.rb rename to db/fixtures/990_settings.rb diff --git a/db/fixtures/999_topics.rb b/db/fixtures/990_topics.rb similarity index 76% rename from db/fixtures/999_topics.rb rename to db/fixtures/990_topics.rb index 78ee61a92d..1433f611d8 100644 --- a/db/fixtures/999_topics.rb +++ b/db/fixtures/990_topics.rb @@ -61,49 +61,3 @@ if seed_welcome_topics skip_validations: true, category: staff ? staff.name : nil) end - -# run this later, cause we need to make sure new application controller resilience is in place first - -Migration::ColumnDropper.drop( - table: 'user_stats', - after_migration: 'DropUnreadTrackingColumns', - columns: %w{ - first_topic_unread_at - }, - on_drop: ->() { - STDERR.puts "Removing superflous user stats columns!" - ActiveRecord::Base.exec_sql "DROP FUNCTION IF EXISTS first_unread_topic_for(int)" - } -) - -Migration::ColumnDropper.drop( - table: 'topics', - after_migration: 'DropUnreadTrackingColumns', - columns: %w{ - inappropriate_count - bookmark_count - off_topic_count - illegal_count - notify_user_count - last_unread_at - }, - on_drop: ->() { - STDERR.puts "Removing superflous topic columns!" - } -) - -Migration::ColumnDropper.drop( - table: 'topics', - after_migration: 'RemoveAutoCloseColumnsFromTopics', - columns: %w{ - auto_close_at - auto_close_user_id - auto_close_started_at - auto_close_based_on_last_post - auto_close_hours - }, - on_drop: ->() { - STDERR.puts "Removing superflous topic columns!" - }, - delay: 3600 -) diff --git a/db/fixtures/999_delayed.rb b/db/fixtures/999_delayed.rb index 00f440f379..c36e36bb96 100644 --- a/db/fixtures/999_delayed.rb +++ b/db/fixtures/999_delayed.rb @@ -2,6 +2,159 @@ require 'migration/table_dropper' +Migration::ColumnDropper.drop( + table: 'user_profiles', + after_migration: 'DropUserCardBadgeColumns', + columns: ['card_image_badge_id'], + on_drop: ->() { + STDERR.puts "Removing user_profiles column card_image_badge_id" + }, + delay: 3600 +) + +Migration::ColumnDropper.drop( + table: 'categories', + after_migration: 'AddSuppressFromLatestToCategories', + columns: ['logo_url', 'background_url', 'suppress_from_homepage'], + on_drop: ->() { + STDERR.puts 'Removing superflous categories columns!' + } +) + +Migration::ColumnDropper.drop( + table: 'groups', + after_migration: 'SplitAliasLevels', + columns: %w[visible public alias_level], + on_drop: ->() { + STDERR.puts 'Removing superflous visible group column!' + } +) + +Migration::ColumnDropper.drop( + table: 'theme_fields', + after_migration: 'AddUploadIdToThemeFields', + columns: ['target'], + on_drop: ->() { + STDERR.puts 'Removing superflous theme_fields target column!' + } +) + +Migration::ColumnDropper.drop( + table: 'user_stats', + after_migration: 'DropUnreadTrackingColumns', + columns: %w{ + first_topic_unread_at + }, + on_drop: ->() { + STDERR.puts "Removing superflous user stats columns!" + ActiveRecord::Base.exec_sql "DROP FUNCTION IF EXISTS first_unread_topic_for(int)" + } +) + +Migration::ColumnDropper.drop( + table: 'topics', + after_migration: 'DropUnreadTrackingColumns', + columns: %w{ + inappropriate_count + bookmark_count + off_topic_count + illegal_count + notify_user_count + last_unread_at + }, + on_drop: ->() { + STDERR.puts "Removing superflous topic columns!" + } +) + +Migration::ColumnDropper.drop( + table: 'topics', + after_migration: 'RemoveAutoCloseColumnsFromTopics', + columns: %w{ + auto_close_at + auto_close_user_id + auto_close_started_at + auto_close_based_on_last_post + auto_close_hours + }, + on_drop: ->() { + STDERR.puts "Removing superflous topic columns!" + }, + delay: 3600 +) + +Migration::ColumnDropper.drop( + table: 'users', + after_migration: 'DropEmailFromUsers', + columns: %w[ + email + email_always + mailing_list_mode + email_digests + email_direct + email_private_messages + external_links_in_new_tab + enable_quoting + dynamic_favicon + disable_jump_reply + edit_history_public + automatically_unpin_topics + digest_after_days + auto_track_topics_after_msecs + new_topic_duration_minutes + last_redirected_to_top_at + auth_token + auth_token_updated_at + ], + on_drop: ->() { + STDERR.puts 'Removing superflous users columns!' + } +) + +Migration::ColumnDropper.drop( + table: 'users', + after_migration: 'RenameBlockedSilence', + columns: %w[ + blocked + ], + on_drop: ->() { + STDERR.puts 'Removing user blocked column!' + } +) + +Migration::ColumnDropper.drop( + table: 'users', + after_migration: 'AddSilencedTillToUsers', + columns: %w[ + silenced + ], + on_drop: ->() { + STDERR.puts 'Removing user silenced column!' + } +) + +Migration::ColumnDropper.drop( + table: 'users', + after_migration: 'AddTrustLevelLocksToUsers', + columns: %w[ + trust_level_locked + ], + on_drop: ->() { + STDERR.puts 'Removing user trust_level_locked!' + } +) + +Migration::ColumnDropper.drop( + table: 'user_auth_tokens', + after_migration: 'RemoveLegacyAuthToken', + columns: %w[ + legacy + ], + on_drop: ->() { + STDERR.puts 'Removing user_auth_token legacy column!' + } +) + Migration::TableDropper.delayed_rename( old_name: 'topic_status_updates', new_name: 'topic_timers', @@ -26,13 +179,3 @@ Migration::TableDropper.delayed_drop( STDERR.puts "Dropping versions. It isn't used anymore." } ) - -Migration::ColumnDropper.drop( - table: 'user_profiles', - after_migration: 'DropUserCardBadgeColumns', - columns: ['card_image_badge_id'], - on_drop: ->() { - STDERR.puts "Removing user_profiles column card_image_badge_id" - }, - delay: 3600 -) From c3ac32d991f7e7c81b9854a626c0f9ef863b7860 Mon Sep 17 00:00:00 2001 From: Joe <33972521+hnb-ku@users.noreply.github.com> Date: Thu, 7 Jun 2018 14:03:54 +0800 Subject: [PATCH 0095/1439] FIX: user-fields layout in desktop create account form --- app/assets/stylesheets/desktop/login.scss | 33 ++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/desktop/login.scss b/app/assets/stylesheets/desktop/login.scss index 0828ae0e69..341053187f 100644 --- a/app/assets/stylesheets/desktop/login.scss +++ b/app/assets/stylesheets/desktop/login.scss @@ -75,7 +75,8 @@ flex: 1 1 50%; align-items: center; padding: 0 15px; - form, table { + form, + table { width: 100%; } @@ -93,13 +94,39 @@ input, label { margin-bottom: 0; - width: 100%; + width: 100%; } .tip { max-width: 340px; } } + .user-field { + display: flex; + flex-direction: column; + + &.confirm { + margin-top: 5px; + } + + > label { + width: auto; + font-weight: bold; + } + + .select-kit { + width: 242px; // match text-input width + } + + .controls { + margin-left: 0; + + .instructions { + margin-top: 5px; + } + } + } + .invites-show { padding-top: 20px; @@ -174,4 +201,4 @@ width: 240px; } } -} \ No newline at end of file +} From e806e6e96ffe4e2c8277dded2007bd453fa4d75b Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 16:13:15 +1000 Subject: [PATCH 0096/1439] correct specs --- .../jobs/onceoff/remap_old_bot_iamges_spec.rb | 4 +- .../spec/controllers/polls_controller_spec.rb | 48 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/plugins/discourse-narrative-bot/spec/jobs/onceoff/remap_old_bot_iamges_spec.rb b/plugins/discourse-narrative-bot/spec/jobs/onceoff/remap_old_bot_iamges_spec.rb index 31badd3612..baba2beb38 100644 --- a/plugins/discourse-narrative-bot/spec/jobs/onceoff/remap_old_bot_iamges_spec.rb +++ b/plugins/discourse-narrative-bot/spec/jobs/onceoff/remap_old_bot_iamges_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Jobs::DiscourseNarrativeBot::RemapOldBotImages do context "when bot's post contains an old link" do let(:post) do Fabricate(:post, - user_id: -2, + user: User.find(-2), raw: 'If you’d like to learn more, select below and **bookmark this private message**. If you do, there may be a :gift: in your future!' ) end @@ -25,7 +25,7 @@ RSpec.describe Jobs::DiscourseNarrativeBot::RemapOldBotImages do context 'subfolder' do let(:post) do Fabricate(:post, - user_id: -2, + user: User.find(-2), raw: 'If you’d like to learn more, select below and **bookmark this private message**. If you do, there may be a :gift: in your future!' ) end diff --git a/plugins/poll/spec/controllers/polls_controller_spec.rb b/plugins/poll/spec/controllers/polls_controller_spec.rb index 390d342f13..7b97fcc6b4 100644 --- a/plugins/poll/spec/controllers/polls_controller_spec.rb +++ b/plugins/poll/spec/controllers/polls_controller_spec.rb @@ -6,8 +6,8 @@ describe ::DiscoursePoll::PollsController do let!(:user) { log_in } let(:topic) { Fabricate(:topic) } - let(:poll) { Fabricate(:post, topic_id: topic.id, user_id: user.id, raw: "[poll]\n- A\n- B\n[/poll]") } - let(:multi_poll) { Fabricate(:post, topic_id: topic.id, user_id: user.id, raw: "[poll min=1 max=2 type=multiple public=true]\n- A\n- B\n[/poll]") } + let(:poll) { Fabricate(:post, topic: topic, user: user, raw: "[poll]\n- A\n- B\n[/poll]") } + let(:multi_poll) { Fabricate(:post, topic: topic, user: user, raw: "[poll min=1 max=2 type=multiple public=true]\n- A\n- B\n[/poll]") } describe "#vote" do @@ -18,7 +18,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["name"]).to eq("poll") expect(json["poll"]["voters"]).to eq(1) @@ -30,7 +30,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["A", "B"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.requires_at_least_1_valid_option")) end @@ -40,13 +40,13 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) put :vote, params: { post_id: poll.id, poll_name: "poll", options: ["e89dec30bbd9bf50fabf6a05b4324edf"] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["voters"]).to eq(1) expect(json["poll"]["options"][0]["votes"]).to eq(0) @@ -60,7 +60,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) end it "ensures topic is not archived" do @@ -70,7 +70,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["A"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.topic_must_be_open_to_vote")) end @@ -82,7 +82,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["A"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.post_is_deleted")) end @@ -94,7 +94,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["A"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.user_cant_post_in_topic")) end @@ -104,7 +104,7 @@ describe ::DiscoursePoll::PollsController do post_id: Fabricate(:post).id, poll_name: "foobar", options: ["A"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.no_polls_associated_with_this_post")) end @@ -114,7 +114,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "foobar", options: ["A"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.no_poll_with_this_name", name: "foobar")) end @@ -126,7 +126,7 @@ describe ::DiscoursePoll::PollsController do post_id: closed_poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"] }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.poll_must_be_open_to_vote")) end @@ -139,7 +139,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", options: ["5c24fc1df56d764b550ceae1b9319125"] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["voters"]).to eq(18) @@ -157,7 +157,7 @@ describe ::DiscoursePoll::PollsController do format: :json end.first - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["voters"]).to eq(1) @@ -172,7 +172,7 @@ describe ::DiscoursePoll::PollsController do params: body.merge(options: ["e89dec30bbd9bf50fabf6a05b4324edf"]), format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["voters"]).to eq(1) @@ -188,7 +188,7 @@ describe ::DiscoursePoll::PollsController do params: body.merge(options: ["e89dec30bbd9bf50fabf6a05b4324edf", "5c24fc1df56d764b550ceae1b9319125"]), format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["voters"]).to eq(2) @@ -208,7 +208,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", status: "closed" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["status"]).to eq("closed") end @@ -221,7 +221,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", status: "closed" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["poll"]["status"]).to eq("closed") end @@ -233,7 +233,7 @@ describe ::DiscoursePoll::PollsController do post_id: poll.id, poll_name: "poll", status: "closed" }, format: :json - expect(response).not_to be_success + expect(response.status).not_to eq(200) json = ::JSON.parse(response.body) expect(json["errors"][0]).to eq(I18n.t("poll.post_is_deleted")) end @@ -253,7 +253,7 @@ describe ::DiscoursePoll::PollsController do post_id: multi_poll.id, poll_name: "poll", options: [first] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) user2 = log_in @@ -261,7 +261,7 @@ describe ::DiscoursePoll::PollsController do post_id: multi_poll.id, poll_name: "poll", options: [first] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) user3 = log_in @@ -271,13 +271,13 @@ describe ::DiscoursePoll::PollsController do options: [first, second] }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) get :voters, params: { poll_name: 'poll', post_id: multi_poll.id, voter_limit: 2 }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = JSON.parse(response.body) From 855b0df0858d1d6ab8542a65edd75c56e260ad2d Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 16:18:45 +1000 Subject: [PATCH 0097/1439] attempt to reset cache --- db/fixtures/999_delayed.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/fixtures/999_delayed.rb b/db/fixtures/999_delayed.rb index c36e36bb96..59b96b993d 100644 --- a/db/fixtures/999_delayed.rb +++ b/db/fixtures/999_delayed.rb @@ -179,3 +179,5 @@ Migration::TableDropper.delayed_drop( STDERR.puts "Dropping versions. It isn't used anymore." } ) + +Discourse.reset_active_record_cache From e51b8d31981d0670e0b29f98755bdef121d1d11e Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 14:03:01 +0800 Subject: [PATCH 0098/1439] Upgrade puppeteer which was accidentally downgraded. --- package.json | 2 +- yarn.lock | 210 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 129 insertions(+), 83 deletions(-) diff --git a/package.json b/package.json index 499196c42d..c52e09aaa5 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,6 @@ "chrome-launcher": "^0.10.2", "chrome-remote-interface": "^0.25.6", "eslint": "^4.19.1", - "puppeteer": "^0.13.0" + "puppeteer": "^1.4.0" } } diff --git a/yarn.lock b/yarn.lock index 2895facd2c..a806bafb98 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,54 +2,77 @@ # yarn lockfile v1 -"@babel/code-frame@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz#473d021ecc573a2cce1c07d5b509d5215f46ba35" +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + dependencies: + "@babel/highlight" "7.0.0-beta.44" + +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" + dependencies: + "@babel/types" "7.0.0-beta.44" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^3.0.0" -"@babel/helper-function-name@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.31.tgz#afe63ad799209989348b1109b44feb66aa245f57" +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.31" - "@babel/template" "7.0.0-beta.31" - "@babel/traverse" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - -"@babel/helper-get-function-arity@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.31.tgz#1176d79252741218e0aec872ada07efb2b37a493" - dependencies: - "@babel/types" "7.0.0-beta.31" - -"@babel/template@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.31.tgz#577bb29389f6c497c3e7d014617e7d6713f68bda" - dependencies: - "@babel/code-frame" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - babylon "7.0.0-beta.31" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" lodash "^4.2.0" -"@babel/traverse@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.31.tgz#db399499ad74aefda014f0c10321ab255134b1df" +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" dependencies: - "@babel/code-frame" "7.0.0-beta.31" - "@babel/helper-function-name" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - babylon "7.0.0-beta.31" - debug "^3.0.1" - globals "^10.0.0" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" + globals "^11.1.0" invariant "^2.2.0" lodash "^4.2.0" -"@babel/types@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.31.tgz#42c9c86784f674c173fb21882ca9643334029de4" +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" dependencies: esutils "^2.0.2" lodash "^4.2.0" @@ -63,9 +86,9 @@ version "0.3.29" resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.3.29.tgz#7f2ad7ec55f914482fc9b1ec4bb1ae6028d46066" -"@types/node@6.0.66": - version "6.0.66" - resolved "https://registry.yarnpkg.com/@types/node/-/node-6.0.66.tgz#5680b74a6135d33d4c00447e7c3dc691a4601625" +"@types/node@^9.3.0": + version "9.6.20" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.20.tgz#b59a1bd357ae2df7d44d5ac98e9b64eb96ea1fef" "@types/rimraf@^0.0.28": version "0.0.28" @@ -81,9 +104,9 @@ acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7" +acorn@^5.5.0: + version "5.6.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.6.2.tgz#b1da1d7be2ac1b4a327fb9eab851702c5045b4e7" agent-base@^4.1.0: version "4.1.2" @@ -158,18 +181,20 @@ babel-code-frame@^6.22.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-eslint@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.0.3.tgz#f29ecf02336be438195325cd47c468da81ee4e98" +babel-eslint@^8.2.3: + version "8.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.3.tgz#1a2e6681cc9bc4473c32899e59915e19cd6733cf" dependencies: - "@babel/code-frame" "7.0.0-beta.31" - "@babel/traverse" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - babylon "7.0.0-beta.31" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + eslint-scope "~3.7.1" + eslint-visitor-keys "^1.0.0" -babylon@7.0.0-beta.31: - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.31.tgz#7ec10f81e0e456fd0f855ad60fa30c2ac454283f" +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" balanced-match@^1.0.0: version "1.0.0" @@ -214,22 +239,22 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" -chrome-launcher@^0.10.0: - version "0.10.0" - resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.0.tgz#4291ab1d20bb097da80b085e8c8c8e6b3e3d72c9" +chrome-launcher@^0.10.2: + version "0.10.2" + resolved "https://registry.yarnpkg.com/chrome-launcher/-/chrome-launcher-0.10.2.tgz#f7d860ddec627b6f01015736b5ae1e33b3d165b1" dependencies: "@types/core-js" "^0.9.41" "@types/mkdirp" "^0.3.29" - "@types/node" "6.0.66" + "@types/node" "^9.3.0" "@types/rimraf" "^0.0.28" is-wsl "^1.1.0" lighthouse-logger "^1.0.0" mkdirp "0.5.1" rimraf "^2.6.1" -chrome-remote-interface@^0.25.4: - version "0.25.4" - resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.25.4.tgz#3a84aa9ef053dc2fd25d3b4c30d7501cb5f73883" +chrome-remote-interface@^0.25.6: + version "0.25.6" + resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.25.6.tgz#172bc82d87091a2ae90711a7b6c940da64ce32ef" dependencies: commander "2.11.x" ws "3.3.x" @@ -296,7 +321,7 @@ debug@2.6.9, debug@^2.6.8: dependencies: ms "2.0.0" -debug@^3.0.1, debug@^3.1.0: +debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -318,9 +343,9 @@ del@^2.0.2: pinkie-promise "^2.0.0" rimraf "^2.2.8" -doctrine@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: esutils "^2.0.2" @@ -338,28 +363,32 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -eslint-scope@^3.7.1: +eslint-scope@^3.7.1, eslint-scope@~3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint@^4.13.1: - version "4.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.13.1.tgz#0055e0014464c7eb7878caf549ef2941992b444f" +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.19.1.tgz#32d1d653e1d90408854bfb296f076ec7e186a300" dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" chalk "^2.1.0" concat-stream "^1.6.0" cross-spawn "^5.1.0" - debug "^3.0.1" - doctrine "^2.0.2" + debug "^3.1.0" + doctrine "^2.1.0" eslint-scope "^3.7.1" - espree "^3.5.2" + eslint-visitor-keys "^1.0.0" + espree "^3.5.4" esquery "^1.0.0" - estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" functional-red-black-tree "^1.0.1" @@ -380,18 +409,19 @@ eslint@^4.13.1: path-is-inside "^1.0.2" pluralize "^7.0.0" progress "^2.0.0" + regexpp "^1.0.1" require-uncached "^1.0.3" semver "^5.3.0" strip-ansi "^4.0.0" strip-json-comments "~2.0.1" - table "^4.0.1" + table "4.0.2" text-table "~0.2.0" -espree@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" +espree@^3.5.4: + version "3.5.4" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.4.tgz#b0f447187c8a8bed944b815a660bddf5deb5d1a7" dependencies: - acorn "^5.2.1" + acorn "^5.5.0" acorn-jsx "^3.0.0" esprima@^4.0.0: @@ -411,7 +441,7 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -495,14 +525,14 @@ glob@^7.0.3, glob@^7.0.5, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^10.0.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-10.4.0.tgz#5c477388b128a9e4c5c5d01c7a2aca68c68b2da7" - globals@^11.0.1: version "11.1.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.1.0.tgz#632644457f5f0e3ae711807183700ebf2e4633e4" +globals@^11.1.0: + version "11.5.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.5.0.tgz#6bc840de6771173b191f13d3a9c94d441ee92642" + globby@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" @@ -634,6 +664,10 @@ js-yaml@^3.9.1: argparse "^1.0.7" esprima "^4.0.0" +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" @@ -820,6 +854,10 @@ readable-stream@^2.2.2: string_decoder "~1.0.3" util-deprecate "~1.0.1" +regexpp@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-1.1.0.tgz#0e3516dd0b7904f413d2d4193dce4618c3a689ab" + require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -888,6 +926,10 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +source-map@^0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -931,7 +973,7 @@ supports-color@^4.0.0: dependencies: has-flag "^2.0.0" -table@^4.0.1: +table@4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: @@ -960,6 +1002,10 @@ to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" From 610510ebad054b3c283690026405be05e8d6766b Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 15:03:09 +0800 Subject: [PATCH 0099/1439] Fix broken discourse narrative bot spec after upgrade. --- .../advanced_user_narrative_spec.rb | 10 +++++----- .../new_user_narrative_spec.rb | 20 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb index 8ec9fc24b9..0f560a561c 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb @@ -78,7 +78,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do #{I18n.t('discourse_narrative_bot.advanced_user_narrative.edit.instructions', base_uri: '')} RAW - new_post = Post.offset(1).last + new_post = topic.ordered_posts.last(2).first expect(narrative.get_data(user)).to eq("topic_id" => topic.id, "state" => "tutorial_edit", @@ -108,7 +108,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do #{I18n.t('discourse_narrative_bot.advanced_user_narrative.edit.instructions', base_uri: '')} RAW - new_post = Post.offset(1).last + new_post = topic.ordered_posts.last(2).first expect(narrative.get_data(user)).to eq("topic_id" => new_post.topic.id, "state" => "tutorial_edit", @@ -231,7 +231,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do DiscourseNarrativeBot::TrackSelector.new(:reply, user, post_id: post.id).select - new_post = Post.offset(1).last + new_post = topic.ordered_posts.last(2).first expect(new_post.raw).to eq(I18n.t( 'discourse_narrative_bot.advanced_user_narrative.recover.instructions', base_uri: '') @@ -267,7 +267,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do RAW expect(narrative.get_data(user)[:state].to_sym).to eq(:tutorial_recover) - expect(Post.offset(1).last.raw).to eq(expected_raw.chomp) + expect(topic.ordered_posts.last(2).first.raw).to eq(expected_raw.chomp) end context 'when user is an admin' do @@ -675,7 +675,7 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do post.update!(raw: "[details=\"This is a test\"]\nwooohoo\n[/details]") narrative.input(:reply, user, post: post) - expect(Post.offset(1).last.raw).to eq(I18n.t( + expect(topic.ordered_posts.last(2).first.raw).to eq(I18n.t( 'discourse_narrative_bot.advanced_user_narrative.details.reply', base_uri: '' )) diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb index 31ce253ce0..2a5af3af7b 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/new_user_narrative_spec.rb @@ -7,8 +7,9 @@ describe DiscourseNarrativeBot::NewUserNarrative do let(:user) { Fabricate(:user) } let(:topic) do - Fabricate(:private_message_topic, first_post: first_post, - topic_allowed_users: [ + Fabricate(:private_message_topic, + first_post: first_post, + topic_allowed_users: [ Fabricate.build(:topic_allowed_user, user: discobot_user), Fabricate.build(:topic_allowed_user, user: user), ] @@ -926,7 +927,7 @@ describe DiscourseNarrativeBot::NewUserNarrative do DiscourseNarrativeBot::TrackSelector.new(:reply, user, post_id: post.id).select end.to change { Post.count }.by(2) - new_post = Post.offset(1).last + new_post = topic.ordered_posts.last(2).first expect(new_post.raw).to eq(I18n.t( 'discourse_narrative_bot.new_user_narrative.search.reply', @@ -935,12 +936,15 @@ describe DiscourseNarrativeBot::NewUserNarrative do expect(first_post.reload.raw).to eq('Hello world') - expect(narrative.get_data(user)).to include("state" => "end", - "topic_id" => new_post.topic_id, - "track" => described_class.to_s) + expect(narrative.get_data(user)).to include( + "state" => "end", + "topic_id" => new_post.topic_id, + "track" => described_class.to_s + ) - expect(user.badges.where(name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME).exists?) - .to eq(true) + expect(user.badges.where( + name: DiscourseNarrativeBot::NewUserNarrative::BADGE_NAME).exists? + ).to eq(true) end end end From 49f39ca64ddca256e4803bd150829e0fc319dd84 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 15:07:39 +0800 Subject: [PATCH 0100/1439] Fix another failing spec. --- .../advanced_user_narrative_spec.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb index 0f560a561c..32a5a4e3f4 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/advanced_user_narrative_spec.rb @@ -108,15 +108,17 @@ RSpec.describe DiscourseNarrativeBot::AdvancedUserNarrative do #{I18n.t('discourse_narrative_bot.advanced_user_narrative.edit.instructions', base_uri: '')} RAW - new_post = topic.ordered_posts.last(2).first + new_post = Topic.last.ordered_posts.last(2).first - expect(narrative.get_data(user)).to eq("topic_id" => new_post.topic.id, - "state" => "tutorial_edit", - "last_post_id" => new_post.id, - "track" => described_class.to_s, - "tutorial_edit" => { + expect(narrative.get_data(user)).to eq( + "topic_id" => new_post.topic.id, + "state" => "tutorial_edit", + "last_post_id" => new_post.id, + "track" => described_class.to_s, + "tutorial_edit" => { "post_id" => Post.last.id - }) + } + ) expect(new_post.raw).to eq(expected_raw.chomp) expect(new_post.topic.id).to_not eq(topic.id) From 1d5c176ea5d1afba4a8e66e6abfdf89483e9399c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 15:20:06 +0800 Subject: [PATCH 0101/1439] DEV: `docker:test` rake task should install plugins first before migrating. --- lib/tasks/docker.rake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake index f66450a050..8febcde160 100644 --- a/lib/tasks/docker.rake +++ b/lib/tasks/docker.rake @@ -70,13 +70,13 @@ task 'docker:test' do ENV["RAILS_ENV"] = "test" - @good &&= run_or_fail("bundle exec rake db:create db:migrate") - if ENV["INSTALL_OFFICIAL_PLUGINS"] @good &&= run_or_fail("bundle exec rake plugin:install_all_official") @good &&= run_or_fail("bundle exec rails r 'puts \"installing all gems\"'") end + @good &&= run_or_fail("bundle exec rake db:create db:migrate") + unless ENV["JS_ONLY"] unless ENV["SKIP_CORE"] From 3533bdb83f7a6221ea64e2e8e36b690f481e5adf Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 15:56:16 +0800 Subject: [PATCH 0102/1439] Remove line that is no longer required. --- lib/tasks/docker.rake | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake index 8febcde160..e9c3525992 100644 --- a/lib/tasks/docker.rake +++ b/lib/tasks/docker.rake @@ -72,7 +72,6 @@ task 'docker:test' do if ENV["INSTALL_OFFICIAL_PLUGINS"] @good &&= run_or_fail("bundle exec rake plugin:install_all_official") - @good &&= run_or_fail("bundle exec rails r 'puts \"installing all gems\"'") end @good &&= run_or_fail("bundle exec rake db:create db:migrate") From 3a8f69c3d2c937889ae53d0c9855a2e15c2c8ebc Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 7 Jun 2018 16:11:09 +0800 Subject: [PATCH 0103/1439] DEV: Assert for 200 response code to avoid changing magic helper in the future. --- .../spec/controllers/posts_controller_spec.rb | 38 +++--- spec/controllers/admin/api_controller_spec.rb | 2 +- .../admin/backups_controller_spec.rb | 18 +-- .../admin/badges_controller_spec.rb | 12 +- .../admin/color_schemes_controller_spec.rb | 8 +- .../admin/dashboard_controller_spec.rb | 4 +- .../admin/email_controller_spec.rb | 2 +- .../admin/emojis_controller_spec.rb | 2 +- .../admin/impersonate_controller_spec.rb | 4 +- .../admin/permalinks_controller_spec.rb | 6 +- .../admin/plugins_controller_spec.rb | 2 +- .../admin/reports_controller_spec.rb | 6 +- .../screened_ip_addresses_controller_spec.rb | 8 +- .../admin/site_texts_controller_spec.rb | 8 +- .../staff_action_logs_controller_spec.rb | 4 +- .../admin/themes_controller_spec.rb | 10 +- .../admin/user_fields_controller_spec.rb | 16 +-- .../admin/users_controller_spec.rb | 48 +++---- .../admin/web_hooks_controller_spec.rb | 4 +- spec/requests/about_controller_spec.rb | 4 +- .../requests/admin/backups_controller_spec.rb | 6 +- .../admin/email_templates_controller_spec.rb | 6 +- .../admin/flagged_topics_controller_spec.rb | 2 +- spec/requests/admin/flags_controller_spec.rb | 4 +- .../moderation_history_controller_spec.rb | 8 +- spec/requests/admin/search_logs_spec.rb | 4 +- spec/requests/categories_controller_spec.rb | 8 +- .../directory_items_controller_spec.rb | 12 +- spec/requests/email_controller_spec.rb | 4 +- spec/requests/embed_controller_spec.rb | 10 +- spec/requests/export_csv_controller_spec.rb | 6 +- .../requests/extra_locales_controller_spec.rb | 2 +- spec/requests/groups_controller_spec.rb | 58 ++++---- spec/requests/invites_controller_spec.rb | 38 +++--- spec/requests/list_controller_spec.rb | 44 +++--- .../requests/notifications_controller_spec.rb | 8 +- .../omniauth_callbacks_controller_spec.rb | 8 +- spec/requests/onebox_controller_spec.rb | 10 +- .../post_action_users_controller_spec.rb | 2 +- spec/requests/post_actions_controller_spec.rb | 18 +-- spec/requests/posts_controller_spec.rb | 106 +++++++-------- spec/requests/queued_posts_controller_spec.rb | 10 +- spec/requests/search_controller_spec.rb | 32 ++--- spec/requests/session_controller_spec.rb | 54 ++++---- .../similar_topics_controller_spec.rb | 8 +- spec/requests/site_controller_spec.rb | 2 +- spec/requests/static_controller_spec.rb | 10 +- spec/requests/steps_controller_spec.rb | 2 +- spec/requests/tags_controller_spec.rb | 44 +++--- spec/requests/topics_controller_spec.rb | 106 +++++++-------- spec/requests/uploads_controller_spec.rb | 4 +- spec/requests/user_avatars_controller_spec.rb | 2 +- spec/requests/user_badges_controller_spec.rb | 2 +- spec/requests/users_controller_spec.rb | 126 +++++++++--------- spec/requests/users_email_controller_spec.rb | 10 +- spec/requests/webhooks_controller_spec.rb | 10 +- spec/support/integration_helpers.rb | 4 +- 57 files changed, 498 insertions(+), 498 deletions(-) diff --git a/plugins/poll/spec/controllers/posts_controller_spec.rb b/plugins/poll/spec/controllers/posts_controller_spec.rb index 917592e53c..96ccc97e7c 100644 --- a/plugins/poll/spec/controllers/posts_controller_spec.rb +++ b/plugins/poll/spec/controllers/posts_controller_spec.rb @@ -16,7 +16,7 @@ describe PostsController do title: title, raw: "[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["poll"]).to be @@ -29,7 +29,7 @@ describe PostsController do topic_id: post_1.topic.id, raw: "[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["poll"]).to be @@ -43,7 +43,7 @@ describe PostsController do title: title, raw: "[poll name=#{name} close=#{close_date.iso8601}]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["polls"][name]["close"]).to be @@ -99,7 +99,7 @@ describe PostsController do title: title, raw: "[poll name=]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["cooked"]).to include("<script>") @@ -111,7 +111,7 @@ describe PostsController do title: title, raw: "[Polls are awesome](/foobar)\n[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]).to be @@ -122,7 +122,7 @@ describe PostsController do title: title, raw: "[poll name=1]\n- A\n[poll name=2]\n- B\n- C\n[/poll]\n- D\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["1"]).to_not be @@ -148,7 +148,7 @@ describe PostsController do id: post_id, post: { raw: "[poll]\n- A\n- B\n- C\n[/poll]" } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["polls"]["poll"]["options"][2]["html"]).to eq("C") end @@ -160,7 +160,7 @@ describe PostsController do id: post_id, post: { raw: "[poll]\n- A\n- B\n- C\n[/poll]" } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["polls_votes"]).to_not be end @@ -196,7 +196,7 @@ describe PostsController do id: post_id, post: { raw: new_option } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["polls"]["poll"]["options"][1]["html"]).to eq("C") end @@ -208,14 +208,14 @@ describe PostsController do id: post_id, post: { raw: new_option } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["polls"]["poll"]["options"][1]["html"]).to eq("C") end it "support changes on the post" do put :update, params: { id: post_id, post: { raw: updated } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["cooked"]).to match("before") end @@ -248,7 +248,7 @@ describe PostsController do id: post_id, post: { raw: new_option } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["polls"]["poll"]["options"][1]["html"]).to eq("C") expect(json["post"]["polls"]["poll"]["voters"]).to eq(1) @@ -267,7 +267,7 @@ describe PostsController do id: post_id, post: { raw: new_option } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["polls"]["poll"]["options"][1]["html"]).to eq("C") @@ -278,7 +278,7 @@ describe PostsController do it "support changes on the post" do put :update, params: { id: post_id, post: { raw: updated } }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["post"]["cooked"]).to match("before") end @@ -322,7 +322,7 @@ describe PostsController do title: title, raw: "[poll]\n- A\n- B\n[/poll]\n[poll name=foo]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["poll"]).to be @@ -363,7 +363,7 @@ describe PostsController do title: title, raw: "[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to eq("

[poll]

\n
    \n
  • A
  • \n
  • B
    \n[/poll]
  • \n
") end @@ -399,7 +399,7 @@ describe PostsController do title: title, raw: "[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["poll"]).to be @@ -418,7 +418,7 @@ describe PostsController do title: title, raw: "[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["poll"]).to be @@ -437,7 +437,7 @@ describe PostsController do title: title, raw: "[poll]\n- A\n- B\n[/poll]" }, format: :json - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["cooked"]).to match("data-poll-") expect(json["polls"]["poll"]).to be diff --git a/spec/controllers/admin/api_controller_spec.rb b/spec/controllers/admin/api_controller_spec.rb index 27d73ea3ea..48f63ed739 100644 --- a/spec/controllers/admin/api_controller_spec.rb +++ b/spec/controllers/admin/api_controller_spec.rb @@ -11,7 +11,7 @@ describe Admin::ApiController do context '.index' do it "succeeds" do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end diff --git a/spec/controllers/admin/backups_controller_spec.rb b/spec/controllers/admin/backups_controller_spec.rb index a4f1757a46..f3ebecd147 100644 --- a/spec/controllers/admin/backups_controller_spec.rb +++ b/spec/controllers/admin/backups_controller_spec.rb @@ -28,7 +28,7 @@ describe Admin::BackupsController do get :index, format: :html, xhr: true - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -40,7 +40,7 @@ describe Admin::BackupsController do get :index, format: :json, xhr: true - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json[0]["filename"]).to eq("backup1") @@ -58,7 +58,7 @@ describe Admin::BackupsController do get :status, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -72,7 +72,7 @@ describe Admin::BackupsController do with_uploads: false, client_id: "foo" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -139,7 +139,7 @@ describe Admin::BackupsController do delete :destroy, params: { id: backup_filename }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end it "doesn't remove the backup if not found" do @@ -162,7 +162,7 @@ describe Admin::BackupsController do get :logs, format: :html, xhr: true - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -175,7 +175,7 @@ describe Admin::BackupsController do post :restore, params: { id: backup_filename, client_id: "foo" }, format: :json expect(SiteSetting.disable_emails).to eq(true) - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -188,7 +188,7 @@ describe Admin::BackupsController do expect { put :readonly, params: { enable: true }, format: :json } .to change { UserHistory.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) user_history = UserHistory.last @@ -202,7 +202,7 @@ describe Admin::BackupsController do expect { put :readonly, params: { enable: false }, format: :json } .to change { UserHistory.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) user_history = UserHistory.last diff --git a/spec/controllers/admin/badges_controller_spec.rb b/spec/controllers/admin/badges_controller_spec.rb index 6751072d3a..441d366f08 100644 --- a/spec/controllers/admin/badges_controller_spec.rb +++ b/spec/controllers/admin/badges_controller_spec.rb @@ -9,7 +9,7 @@ describe Admin::BadgesController do context 'index' do it 'returns badge index' do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -79,7 +79,7 @@ describe Admin::BadgesController do it 'returns JSON' do get :badge_types, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)["badge_types"]).to be_present end end @@ -87,7 +87,7 @@ describe Admin::BadgesController do context '.destroy' do it 'deletes the badge' do delete :destroy, params: { id: badge.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(Badge.where(id: badge.id).exists?).to eq(false) expect(UserHistory.where(acting_user_id: user.id, action: UserHistory.actions[:delete_badge]).exists?).to eq(true) end @@ -104,7 +104,7 @@ describe Admin::BadgesController do name: "123456" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) editor_badge.reload expect(editor_badge.name).to eq(editor_badge_name) @@ -127,7 +127,7 @@ describe Admin::BadgesController do enabled: true }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) badge.reload expect(badge.name).to eq('123456') expect(badge.query).to eq('select 123') @@ -147,7 +147,7 @@ describe Admin::BadgesController do enabled: true }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) badge.reload expect(badge.name).to eq('123456') expect(badge.query).to eq(sql) diff --git a/spec/controllers/admin/color_schemes_controller_spec.rb b/spec/controllers/admin/color_schemes_controller_spec.rb index e748d1e002..efc1a48810 100644 --- a/spec/controllers/admin/color_schemes_controller_spec.rb +++ b/spec/controllers/admin/color_schemes_controller_spec.rb @@ -21,7 +21,7 @@ describe Admin::ColorSchemesController do Fabricate(:color_scheme) get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)).to be_present end end @@ -30,7 +30,7 @@ describe Admin::ColorSchemesController do it "returns JSON" do post :create, params: valid_params, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['id']).to be_present end @@ -51,7 +51,7 @@ describe Admin::ColorSchemesController do it "returns success" do ColorSchemeRevisor.expects(:revise).returns(existing) put :update, params: valid_params.merge(id: existing.id), format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end it "returns JSON" do @@ -78,7 +78,7 @@ describe Admin::ColorSchemesController do expect { delete :destroy, params: { id: existing.id }, format: :json }.to change { ColorScheme.count }.by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) end end end diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/controllers/admin/dashboard_controller_spec.rb index cfde3a4ef5..f10397a345 100644 --- a/spec/controllers/admin/dashboard_controller_spec.rb +++ b/spec/controllers/admin/dashboard_controller_spec.rb @@ -23,7 +23,7 @@ describe Admin::DashboardController do it 'returns discourse version info' do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['version_check']).to be_present end end @@ -50,7 +50,7 @@ describe Admin::DashboardController do it 'returns an empty array' do get :problems, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json['problems'].size).to eq(0) end diff --git a/spec/controllers/admin/email_controller_spec.rb b/spec/controllers/admin/email_controller_spec.rb index 7f881f974f..a8f838f64d 100644 --- a/spec/controllers/admin/email_controller_spec.rb +++ b/spec/controllers/admin/email_controller_spec.rb @@ -76,7 +76,7 @@ describe Admin::EmailController do last_seen_at: 1.week.ago, username: user.username }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end diff --git a/spec/controllers/admin/emojis_controller_spec.rb b/spec/controllers/admin/emojis_controller_spec.rb index 7a1f3618c6..5faafdfeb3 100644 --- a/spec/controllers/admin/emojis_controller_spec.rb +++ b/spec/controllers/admin/emojis_controller_spec.rb @@ -23,7 +23,7 @@ describe Admin::EmojisController do it "returns a list of custom emojis" do Emoji.expects(:custom).returns([custom_emoji]) get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json[0]["name"]).to eq(custom_emoji.name) expect(json[0]["url"]).to eq(custom_emoji.url) diff --git a/spec/controllers/admin/impersonate_controller_spec.rb b/spec/controllers/admin/impersonate_controller_spec.rb index b9793cc80c..2a43778f63 100644 --- a/spec/controllers/admin/impersonate_controller_spec.rb +++ b/spec/controllers/admin/impersonate_controller_spec.rb @@ -13,7 +13,7 @@ describe Admin::ImpersonateController do context 'index' do it 'returns success' do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -48,7 +48,7 @@ describe Admin::ImpersonateController do it "returns success" do post :create, params: { username_or_email: user.email }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end it "also works with an email address" do diff --git a/spec/controllers/admin/permalinks_controller_spec.rb b/spec/controllers/admin/permalinks_controller_spec.rb index 3befb17ff5..1084eed210 100644 --- a/spec/controllers/admin/permalinks_controller_spec.rb +++ b/spec/controllers/admin/permalinks_controller_spec.rb @@ -17,7 +17,7 @@ describe Admin::PermalinksController do get :index, params: { filter: "topic" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) expect(result.length).to eq(2) end @@ -30,7 +30,7 @@ describe Admin::PermalinksController do get :index, params: { filter: "discourse" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) expect(result.length).to eq(2) end @@ -43,7 +43,7 @@ describe Admin::PermalinksController do get :index, params: { filter: "discourse" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) expect(result.length).to eq(3) end diff --git a/spec/controllers/admin/plugins_controller_spec.rb b/spec/controllers/admin/plugins_controller_spec.rb index 7e599c5533..a1907c2374 100644 --- a/spec/controllers/admin/plugins_controller_spec.rb +++ b/spec/controllers/admin/plugins_controller_spec.rb @@ -11,7 +11,7 @@ describe Admin::PluginsController do it 'should return JSON' do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body).has_key?('plugins')).to eq(true) end end diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/controllers/admin/reports_controller_spec.rb index 021576405e..d440b94102 100644 --- a/spec/controllers/admin/reports_controller_spec.rb +++ b/spec/controllers/admin/reports_controller_spec.rb @@ -45,7 +45,7 @@ describe Admin::ReportsController do end it "renders the report as JSON" do - expect(response).to be_successful + expect(response.status).to eq(200) end it "renders the report as JSON" do @@ -67,7 +67,7 @@ describe Admin::ReportsController do get :show, params: { type: 'topics', category_id: category.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) report = JSON.parse(response.body)["report"] @@ -87,7 +87,7 @@ describe Admin::ReportsController do get :show, params: { type: 'signups', group_id: group.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) report = JSON.parse(response.body)["report"] diff --git a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb b/spec/controllers/admin/screened_ip_addresses_controller_spec.rb index 4176173d3b..fb4ed1e9bb 100644 --- a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb +++ b/spec/controllers/admin/screened_ip_addresses_controller_spec.rb @@ -18,13 +18,13 @@ describe Admin::ScreenedIpAddressesController do get :index, params: { filter: "1.2.*" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) expect(result.length).to eq(3) get :index, params: { filter: "4.5.6.7" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) expect(result.length).to eq(1) end @@ -45,7 +45,7 @@ describe Admin::ScreenedIpAddressesController do SiteSetting.min_ban_entries_for_roll_up = 3 post :roll_up, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) subnet = ScreenedIpAddress.where(ip_address: "1.2.3.0/24").first expect(subnet).to be_present @@ -65,7 +65,7 @@ describe Admin::ScreenedIpAddressesController do SiteSetting.min_ban_entries_for_roll_up = 5 post :roll_up, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) subnet = ScreenedIpAddress.where(ip_address: "1.2.0.0/16").first expect(subnet).to be_present diff --git a/spec/controllers/admin/site_texts_controller_spec.rb b/spec/controllers/admin/site_texts_controller_spec.rb index 6acb89da03..d9bce36487 100644 --- a/spec/controllers/admin/site_texts_controller_spec.rb +++ b/spec/controllers/admin/site_texts_controller_spec.rb @@ -14,7 +14,7 @@ describe Admin::SiteTextsController do context '.index' do it 'returns json' do get :index, params: { q: 'title' }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)).to be_present end end @@ -22,7 +22,7 @@ describe Admin::SiteTextsController do context '.show' do it 'returns a site text for a key that exists' do get :show, params: { id: 'title' }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -71,7 +71,7 @@ describe Admin::SiteTextsController do orig_title = I18n.t(:title) put :update, params: { id: 'title', site_text: { value: 'hello' } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -84,7 +84,7 @@ describe Admin::SiteTextsController do # Revert put :revert, params: { id: 'title' }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present diff --git a/spec/controllers/admin/staff_action_logs_controller_spec.rb b/spec/controllers/admin/staff_action_logs_controller_spec.rb index 5f12839e38..0950429f62 100644 --- a/spec/controllers/admin/staff_action_logs_controller_spec.rb +++ b/spec/controllers/admin/staff_action_logs_controller_spec.rb @@ -17,7 +17,7 @@ describe Admin::StaffActionLogsController do get :index, params: { action_id: UserHistory.actions[:delete_topic] }, format: :json json = JSON.parse(response.body) - expect(response).to be_successful + expect(response.status).to eq(200) expect(json["staff_action_logs"].length).to eq(1) expect(json["staff_action_logs"][0]["action_name"]).to eq("delete_topic") @@ -41,7 +41,7 @@ describe Admin::StaffActionLogsController do .log_theme_change(original_json, theme) get :diff, params: { id: record.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) parsed = JSON.parse(response.body) expect(parsed["side_by_side"]).to include("up") diff --git a/spec/controllers/admin/themes_controller_spec.rb b/spec/controllers/admin/themes_controller_spec.rb index e129499d4c..30625c7d57 100644 --- a/spec/controllers/admin/themes_controller_spec.rb +++ b/spec/controllers/admin/themes_controller_spec.rb @@ -66,7 +66,7 @@ describe Admin::ThemesController do upload.destroy post :import, params: { theme: uploaded_json }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) temp.unlink theme = Theme.last @@ -79,7 +79,7 @@ describe Admin::ThemesController do it 'imports a theme' do post :import, params: { theme: theme_file }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) @@ -113,7 +113,7 @@ describe Admin::ThemesController do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) @@ -133,7 +133,7 @@ describe Admin::ThemesController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) @@ -186,7 +186,7 @@ describe Admin::ThemesController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) diff --git a/spec/controllers/admin/user_fields_controller_spec.rb b/spec/controllers/admin/user_fields_controller_spec.rb index b885c8b389..47ed6de465 100644 --- a/spec/controllers/admin/user_fields_controller_spec.rb +++ b/spec/controllers/admin/user_fields_controller_spec.rb @@ -16,7 +16,7 @@ describe Admin::UserFieldsController do user_field: { name: 'hello', description: 'hello desc', field_type: 'text' } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) }.to change(UserField, :count).by(1) end @@ -31,7 +31,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end.to change(UserField, :count).by(1) expect(UserFieldOption.count).to eq(3) @@ -43,7 +43,7 @@ describe Admin::UserFieldsController do it "returns a list of user fields" do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['user_fields']).to be_present end @@ -55,7 +55,7 @@ describe Admin::UserFieldsController do it "deletes the user field" do expect { delete :destroy, params: { id: user_field.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) }.to change(UserField, :count).by(-1) end end @@ -69,7 +69,7 @@ describe Admin::UserFieldsController do user_field: { name: 'fraggle', field_type: 'confirm', description: 'muppet' } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) user_field.reload expect(user_field.name).to eq('fraggle') expect(user_field.field_type).to eq('confirm') @@ -86,7 +86,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) user_field.reload expect(user_field.name).to eq('fraggle') expect(user_field.field_type).to eq('dropdown') @@ -105,7 +105,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) user_field.reload expect(user_field.user_field_options.size).to eq(2) @@ -119,7 +119,7 @@ describe Admin::UserFieldsController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) user_field.reload expect(user_field.user_field_options.size).to eq(2) end diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index d82e74e06f..8288d07675 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -15,7 +15,7 @@ describe Admin::UsersController do context '#index' do it 'returns success' do get :index, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end it 'returns JSON' do @@ -48,7 +48,7 @@ describe Admin::UsersController do context 'an existing user' do it 'returns success' do get :show, params: { id: @user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -135,7 +135,7 @@ describe Admin::UsersController do format: :json } ) - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user).to be_suspended @@ -160,7 +160,7 @@ describe Admin::UsersController do it "can have an associated post" do put(:suspend, params: suspend_params) - expect(response).to be_successful + expect(response.status).to eq(200) log = UserHistory.where(target_user_id: user.id).order('id desc').first expect(log).to be_present @@ -171,7 +171,7 @@ describe Admin::UsersController do put(:suspend, params: suspend_params.merge(post_action: 'delete')) post.reload expect(post.deleted_at).to be_present - expect(response).to be_successful + expect(response.status).to eq(200) end it "can edit an associated post" do @@ -182,7 +182,7 @@ describe Admin::UsersController do post.reload expect(post.deleted_at).to be_blank expect(post.raw).to eq("this is the edited content") - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -205,7 +205,7 @@ describe Admin::UsersController do format: :json } ) - expect(response).to be_successful + expect(response.status).to eq(200) log = UserHistory.where(target_user_id: user.id).order('id desc').first expect(log).to be_present @@ -274,7 +274,7 @@ describe Admin::UsersController do group_id: group.id, user_id: user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) expect(GroupUser.where(user_id: user.id, group_id: group.id).exists?).to eq(true) group_history = GroupHistory.last @@ -288,7 +288,7 @@ describe Admin::UsersController do group_id: group.id, user_id: user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -378,7 +378,7 @@ describe Admin::UsersController do @another_user.reload expect(@another_user.trust_level).to eq(2) - expect(response).to be_successful + expect(response.status).to eq(200) end it "raises no error when demoting a user below their current trust level (locks trust level)" do @@ -394,7 +394,7 @@ describe Admin::UsersController do level: TrustLevel[0] }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) @another_user.reload expect(@another_user.trust_level).to eq(TrustLevel[0]) expect(@another_user.manual_locked_trust_level).to eq(TrustLevel[0]) @@ -474,7 +474,7 @@ describe Admin::UsersController do users: [reject_me.id, reject_me_too.id] }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['success'].to_i).to eq(2) expect(json['failed'].to_i).to eq(0) @@ -493,7 +493,7 @@ describe Admin::UsersController do users: [reject_me.id, reject_me_too.id] }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['success'].to_i).to eq(1) expect(json['failed'].to_i).to eq(1) @@ -506,7 +506,7 @@ describe Admin::UsersController do users: [reject_me.id] }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['success'].to_i).to eq(0) expect(json['failed'].to_i).to eq(1) @@ -538,7 +538,7 @@ describe Admin::UsersController do it "doesn't return an error if delete_posts == true" do delete :destroy, params: { id: delete_me.id, delete_posts: true }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -555,7 +555,7 @@ describe Admin::UsersController do it "returns success" do put :activate, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['success']).to eq("OK") end @@ -567,7 +567,7 @@ describe Admin::UsersController do expect(@reg_user.email_confirmed?).to eq(false) put :activate, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) @reg_user.reload expect(@reg_user.email_confirmed?).to eq(true) @@ -581,7 +581,7 @@ describe Admin::UsersController do it "returns success" do put :log_out, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['success']).to eq("OK") end @@ -612,7 +612,7 @@ describe Admin::UsersController do it "punishes the user for spamming" do put :silence, params: { user_id: @reg_user.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) @reg_user.reload expect(@reg_user).to be_silenced end @@ -626,7 +626,7 @@ describe Admin::UsersController do post_action: 'edit', post_edit: "this is the new contents for the post" }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) silence_post.reload expect(silence_post.raw).to eq("this is the new contents for the post") @@ -742,7 +742,7 @@ describe Admin::UsersController do name: 'Bill', username: 'bill22', email: 'bill@bill.com' }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) u = User.find_by_email('bill@bill.com') expect(u.name).to eq("Bill") @@ -758,7 +758,7 @@ describe Admin::UsersController do name: 'Bill', username: 'bill22', email: 'bill@bill.com', send_email: '0' }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["password_url"]).to be_present end @@ -806,7 +806,7 @@ describe Admin::UsersController do sso.email = "bob2@bob.com" post :sync_sso, params: Rack::Utils.parse_query(sso.payload), format: :json - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.email).to eq("bob2@bob.com") @@ -820,7 +820,7 @@ describe Admin::UsersController do sso.email = "dr@claw.com" sso.external_id = "2" post :sync_sso, params: Rack::Utils.parse_query(sso.payload), format: :json - expect(response).to be_successful + expect(response.status).to eq(200) user = User.find_by_email('dr@claw.com') expect(user).to be_present diff --git a/spec/controllers/admin/web_hooks_controller_spec.rb b/spec/controllers/admin/web_hooks_controller_spec.rb index 1d87cb43ce..3cd84de6e9 100644 --- a/spec/controllers/admin/web_hooks_controller_spec.rb +++ b/spec/controllers/admin/web_hooks_controller_spec.rb @@ -28,7 +28,7 @@ describe Admin::WebHooksController do } }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["web_hook"]["payload_url"]).to be_present @@ -62,7 +62,7 @@ describe Admin::WebHooksController do post :ping, params: { id: web_hook.id }, format: :json - expect(response).to be_successful + expect(response.status).to eq(200) end end end diff --git a/spec/requests/about_controller_spec.rb b/spec/requests/about_controller_spec.rb index ec4e07d4bc..cf7ab39d5e 100644 --- a/spec/requests/about_controller_spec.rb +++ b/spec/requests/about_controller_spec.rb @@ -8,7 +8,7 @@ describe AboutController do SiteSetting.login_required = false get "/about" - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should redirect to login page for anonymous user when login_required is true' do @@ -23,7 +23,7 @@ describe AboutController do sign_in(Fabricate(:user)) get "/about" - expect(response).to be_successful + expect(response.status).to eq(200) end end end diff --git a/spec/requests/admin/backups_controller_spec.rb b/spec/requests/admin/backups_controller_spec.rb index d4be1f1674..e83e149c59 100644 --- a/spec/requests/admin/backups_controller_spec.rb +++ b/spec/requests/admin/backups_controller_spec.rb @@ -21,7 +21,7 @@ RSpec.describe Admin::BackupsController do post "/admin/backups/rollback.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should not allow rollback via a GET request' do @@ -36,7 +36,7 @@ RSpec.describe Admin::BackupsController do delete "/admin/backups/cancel.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should not allow cancel via a GET request' do @@ -59,7 +59,7 @@ RSpec.describe Admin::BackupsController do put "/admin/backups/#{backup_filename}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "returns 404 when the backup does not exist" do diff --git a/spec/requests/admin/email_templates_controller_spec.rb b/spec/requests/admin/email_templates_controller_spec.rb index 8957a56717..b37a5e65a2 100644 --- a/spec/requests/admin/email_templates_controller_spec.rb +++ b/spec/requests/admin/email_templates_controller_spec.rb @@ -33,7 +33,7 @@ RSpec.describe Admin::EmailTemplatesController do sign_in(admin) get '/admin/customize/email_templates.json' - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['email_templates']).to be_present @@ -169,7 +169,7 @@ RSpec.describe Admin::EmailTemplatesController do email_template: { subject: email_subject, body: email_body } }, headers: headers - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -265,7 +265,7 @@ RSpec.describe Admin::EmailTemplatesController do it "returns the restored email template" do delete '/admin/customize/email_templates/user_notifications.admin_login', headers: headers - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present diff --git a/spec/requests/admin/flagged_topics_controller_spec.rb b/spec/requests/admin/flagged_topics_controller_spec.rb index 87dfde84e3..3d27ac33af 100644 --- a/spec/requests/admin/flagged_topics_controller_spec.rb +++ b/spec/requests/admin/flagged_topics_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Admin::FlaggedTopicsController do shared_examples "successfully retrieve list of flagged topics" do it "returns a list of flagged topics" do get "/admin/flagged_topics.json" - expect(response).to be_successful + expect(response.status).to eq(200) data = ::JSON.parse(response.body) expect(data['flagged_topics']).to be_present diff --git a/spec/requests/admin/flags_controller_spec.rb b/spec/requests/admin/flags_controller_spec.rb index 1d711d590b..c8ebc0ea77 100644 --- a/spec/requests/admin/flags_controller_spec.rb +++ b/spec/requests/admin/flags_controller_spec.rb @@ -13,7 +13,7 @@ RSpec.describe Admin::FlagsController do it 'should return the right response when nothing is flagged' do get '/admin/flags.json' - expect(response).to be_successful + expect(response.status).to eq(200) data = ::JSON.parse(response.body) expect(data["users"]).to eq([]) @@ -25,7 +25,7 @@ RSpec.describe Admin::FlagsController do get '/admin/flags.json' - expect(response).to be_successful + expect(response.status).to eq(200) data = ::JSON.parse(response.body) expect(data["users"].length).to eq(2) diff --git a/spec/requests/admin/moderation_history_controller_spec.rb b/spec/requests/admin/moderation_history_controller_spec.rb index 1b73f38668..b35989ad30 100644 --- a/spec/requests/admin/moderation_history_controller_spec.rb +++ b/spec/requests/admin/moderation_history_controller_spec.rb @@ -22,7 +22,7 @@ RSpec.describe Admin::BackupsController do describe "for a post" do it "returns an empty array when the post doesn't exist" do get "/admin/moderation_history.json?filter=post&post_id=99999999" - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['moderation_history']).to be_blank end @@ -31,7 +31,7 @@ RSpec.describe Admin::BackupsController do p = Fabricate(:post, topic: p.topic) PostDestroyer.new(Discourse.system_user, p).destroy get "/admin/moderation_history.json?filter=post&post_id=#{p.id}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['moderation_history']).to be_present end @@ -40,7 +40,7 @@ RSpec.describe Admin::BackupsController do describe "for a topic" do it "returns empty history when the topic doesn't exist" do get "/admin/moderation_history.json?filter=topic&topic_id=1234" - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['moderation_history']).to be_blank end @@ -48,7 +48,7 @@ RSpec.describe Admin::BackupsController do p = Fabricate(:post) PostDestroyer.new(Discourse.system_user, p).destroy get "/admin/moderation_history.json?filter=topic&topic_id=#{p.topic_id}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['moderation_history']).to be_present end end diff --git a/spec/requests/admin/search_logs_spec.rb b/spec/requests/admin/search_logs_spec.rb index f872fb8700..b234ea2abf 100644 --- a/spec/requests/admin/search_logs_spec.rb +++ b/spec/requests/admin/search_logs_spec.rb @@ -28,7 +28,7 @@ RSpec.describe Admin::SearchLogsController do sign_in(admin) get '/admin/logs/search_logs.json' - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json[0]['term']).to eq('ruby') @@ -51,7 +51,7 @@ RSpec.describe Admin::SearchLogsController do sign_in(admin) get '/admin/logs/search_logs/term/ruby.json' - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['term']['type']).to eq('search_log_term') diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb index be6039564b..e3a76cacbf 100644 --- a/spec/requests/categories_controller_spec.rb +++ b/spec/requests/categories_controller_spec.rb @@ -136,7 +136,7 @@ describe CategoriesController do expect do delete "/categories/#{category.slug}.json" end.to change(Category, :count).by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) expect(UserHistory.count).to eq(1) end end @@ -321,14 +321,14 @@ describe CategoriesController do it 'accepts valid custom slug' do put "/category/#{category.id}/slug.json", params: { slug: 'valid-slug' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(category.reload.slug).to eq('valid-slug') end it 'accepts not well formed custom slug' do put "/category/#{category.id}/slug.json", params: { slug: ' valid slug' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(category.reload.slug).to eq('valid-slug') end @@ -336,7 +336,7 @@ describe CategoriesController do SiteSetting.slug_generation_method = 'none' put "/category/#{category.id}/slug.json", params: { slug: ' another !_ slug @' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(category.reload.slug).to eq('another-slug') SiteSetting.slug_generation_method = 'ascii' end diff --git a/spec/requests/directory_items_controller_spec.rb b/spec/requests/directory_items_controller_spec.rb index f9b0e08b88..8a188db107 100644 --- a/spec/requests/directory_items_controller_spec.rb +++ b/spec/requests/directory_items_controller_spec.rb @@ -24,7 +24,7 @@ describe DirectoryItemsController do it "succeeds" do get '/directory_items.json', params: { period: 'all' } - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -37,7 +37,7 @@ describe DirectoryItemsController do it "succeeds with a valid value" do get '/directory_items.json', params: { period: 'all' } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -58,7 +58,7 @@ describe DirectoryItemsController do it "finds user by name" do get '/directory_items.json', params: { period: 'all', name: 'eviltrout' } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -69,7 +69,7 @@ describe DirectoryItemsController do it "finds staged user by name" do get '/directory_items.json', params: { period: 'all', name: 'stage_user' } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -80,7 +80,7 @@ describe DirectoryItemsController do it "excludes users by username" do get '/directory_items.json', params: { period: 'all', exclude_usernames: "stage_user,eviltrout" } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -92,7 +92,7 @@ describe DirectoryItemsController do it "filters users by group" do get '/directory_items.json', params: { period: 'all', group: group.name } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present diff --git a/spec/requests/email_controller_spec.rb b/spec/requests/email_controller_spec.rb index 062c24461a..3b6a1a8f30 100644 --- a/spec/requests/email_controller_spec.rb +++ b/spec/requests/email_controller_spec.rb @@ -145,7 +145,7 @@ RSpec.describe EmailController do key = SecureRandom.hex $redis.set(key, user.email) get '/email/unsubscribed', params: { key: key, topic_id: topic.id } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(topic.title) end end @@ -155,7 +155,7 @@ RSpec.describe EmailController do key = SecureRandom.hex $redis.set(key, user.email) get '/email/unsubscribed', params: { key: key, topic_id: private_topic.id } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to_not include(private_topic.title) end end diff --git a/spec/requests/embed_controller_spec.rb b/spec/requests/embed_controller_spec.rb index c62222a8cc..f6cb42e88c 100644 --- a/spec/requests/embed_controller_spec.rb +++ b/spec/requests/embed_controller_spec.rb @@ -27,7 +27,7 @@ describe EmbedController do it "allows a topic to be embedded by id" do topic = Fabricate(:topic) get '/embed/comments', params: { topic_id: topic.id }, headers: headers - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -85,7 +85,7 @@ describe EmbedController do end after do - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.headers['X-Frame-Options']).to eq("ALLOWALL") end @@ -139,7 +139,7 @@ describe EmbedController do params: { embed_url: embed_url }, headers: { 'REFERER' => "http://eviltrout.com/wat/1-2-3.html" } - expect(response).to be_successful + expect(response.status).to eq(200) end it "works with the second host" do @@ -147,7 +147,7 @@ describe EmbedController do params: { embed_url: embed_url }, headers: { 'REFERER' => "http://eviltrout.com/wat/1-2-3.html" } - expect(response).to be_successful + expect(response.status).to eq(200) end it "works with a host with a path" do @@ -155,7 +155,7 @@ describe EmbedController do params: { embed_url: embed_url }, headers: { 'REFERER' => "https://example.com/some-other-path" } - expect(response).to be_successful + expect(response.status).to eq(200) end it "contains custom class name" do diff --git a/spec/requests/export_csv_controller_spec.rb b/spec/requests/export_csv_controller_spec.rb index cc84bd0403..1fe2a15e7c 100644 --- a/spec/requests/export_csv_controller_spec.rb +++ b/spec/requests/export_csv_controller_spec.rb @@ -10,7 +10,7 @@ describe ExportCsvController do describe ".export_entity" do it "enqueues export job" do post "/export_csv/export_entity.json", params: { entity: "user_archive" } - expect(response).to be_success + expect(response.status).to eq(200) expect(Jobs::ExportCsvFile.jobs.size).to eq(1) job_data = Jobs::ExportCsvFile.jobs.first["args"].first @@ -40,7 +40,7 @@ describe ExportCsvController do describe ".export_entity" do it "enqueues export job" do post "/export_csv/export_entity.json", params: { entity: "staff_action" } - expect(response).to be_success + expect(response.status).to eq(200) expect(Jobs::ExportCsvFile.jobs.size).to eq(1) job_data = Jobs::ExportCsvFile.jobs.first["args"].first @@ -51,7 +51,7 @@ describe ExportCsvController do it "should not rate limit export for staff" do UserExport.create(file_name: "screened-email-150116-010145", user_id: admin.id) post "/export_csv/export_entity.json", params: { entity: "staff_action" } - expect(response).to be_success + expect(response.status).to eq(200) expect(Jobs::ExportCsvFile.jobs.size).to eq(1) job_data = Jobs::ExportCsvFile.jobs.first["args"].first diff --git a/spec/requests/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb index 3093d9f38f..a190489f4f 100644 --- a/spec/requests/extra_locales_controller_spec.rb +++ b/spec/requests/extra_locales_controller_spec.rb @@ -42,7 +42,7 @@ describe ExtraLocalesController do get "/extra-locales/admin" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body.include?("github_badges")).to eq(true) end end diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb index 7e2b69fc77..cae3ae4c7f 100644 --- a/spec/requests/groups_controller_spec.rb +++ b/spec/requests/groups_controller_spec.rb @@ -152,7 +152,7 @@ describe GroupsController do staff_group get "/groups.json" - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) @@ -382,7 +382,7 @@ describe GroupsController do sign_in(user) get "/groups/#{group.name}/mentionable.json" - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) expect(response_body["mentionable"]).to eq(false) @@ -393,7 +393,7 @@ describe GroupsController do ) get "/groups/#{group.name}/mentionable.json" - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) expect(response_body["mentionable"]).to eq(true) @@ -405,7 +405,7 @@ describe GroupsController do sign_in(user) get "/groups/#{group.name}/messageable.json" - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) expect(response_body["messageable"]).to eq(false) @@ -416,7 +416,7 @@ describe GroupsController do ) get "/groups/#{group.name}/messageable.json" - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) expect(response_body["messageable"]).to eq(true) @@ -645,7 +645,7 @@ describe GroupsController do order: 'last_seen_at', desc: true } - expect(response).to be_successful + expect(response.status).to eq(200) members = JSON.parse(response.body)["members"] @@ -653,7 +653,7 @@ describe GroupsController do get "/groups/#{group.name}/members.json", params: { order: 'last_seen_at' } - expect(response).to be_successful + expect(response.status).to eq(200) members = JSON.parse(response.body)["members"] @@ -663,7 +663,7 @@ describe GroupsController do order: 'last_posted_at', desc: true } - expect(response).to be_successful + expect(response.status).to eq(200) members = JSON.parse(response.body)["members"] @@ -673,7 +673,7 @@ describe GroupsController do it "should not allow members to be sorted by columns that are not allowed" do get "/groups/#{group.name}/members.json", params: { order: 'email' } - expect(response).to be_successful + expect(response.status).to eq(200) members = JSON.parse(response.body)["members"] @@ -808,7 +808,7 @@ describe GroupsController do put "/groups/#{group.id}/members.json", params: { usernames: user2.username } end.to change { group.users.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) group_history = GroupHistory.last @@ -834,7 +834,7 @@ describe GroupsController do params: { usernames: [user1.username, user2.username].join(",") } end.to change { group.users.count }.by(2) - expect(response).to be_successful + expect(response.status).to eq(200) end it "adds by id" do @@ -843,7 +843,7 @@ describe GroupsController do params: { user_ids: [user1.id, user2.id].join(",") } end.to change { group.users.count }.by(2) - expect(response).to be_successful + expect(response.status).to eq(200) end it "adds by email" do @@ -852,7 +852,7 @@ describe GroupsController do params: { user_emails: [user1.email, user2.email].join(",") } end.to change { group.users.count }.by(2) - expect(response).to be_successful + expect(response.status).to eq(200) end it 'fails when multiple member already exists' do @@ -920,7 +920,7 @@ describe GroupsController do params: { usernames: other_user.username } end.to change { group.users.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) group_history = GroupHistory.last @@ -938,7 +938,7 @@ describe GroupsController do params: { usernames: other_user.username } end.to change { group.users.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should not allow an underprivilege user to add another user to a group' do @@ -971,7 +971,7 @@ describe GroupsController do delete "/groups/#{group.id}/members.json", params: { user_id: user.id } end.to change { group.users.count }.by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) end it "removes by username" do @@ -979,7 +979,7 @@ describe GroupsController do delete "/groups/#{group.id}/members.json", params: { username: user.username } end.to change { group.users.count }.by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) end it "removes user.primary_group_id when user is removed from group" do @@ -996,7 +996,7 @@ describe GroupsController do params: { user_email: user.email } end.to change { group.users.count }.by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) end context 'public group' do @@ -1010,7 +1010,7 @@ describe GroupsController do params: { username: other_user.username } end.to change { group.users.count }.by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -1022,7 +1022,7 @@ describe GroupsController do params: { username: other_user.username } end.to change { group.users.count }.by(-1) - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should not allow a underprivilege user to leave a group for another user' do @@ -1077,7 +1077,7 @@ describe GroupsController do it 'should allow group owner to view history' do get "/groups/#{group.name}/logs.json" - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body)["logs"].last @@ -1109,7 +1109,7 @@ describe GroupsController do get "/groups/#{group.name}/logs.json" - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body)["logs"].first @@ -1132,7 +1132,7 @@ describe GroupsController do filters: { "action" => "add_user_to_group" } } - expect(response).to be_successful + expect(response.status).to eq(200) logs = JSON.parse(response.body)["logs"] @@ -1167,7 +1167,7 @@ describe GroupsController do post "/groups/#{group.name}/request_membership.json", params: { reason: 'Please add me in' } - expect(response).to be_successful + expect(response.status).to eq(200) post = Post.last topic = post.topic @@ -1217,7 +1217,7 @@ describe GroupsController do get '/groups/search.json' - expect(response).to be_successful + expect(response.status).to eq(200) groups = JSON.parse(response.body) expected_ids = Group::AUTO_GROUPS.map { |name, id| id } @@ -1229,7 +1229,7 @@ describe GroupsController do ['GO', 'nerys'].each do |term| get "/groups/search.json?term=#{term}" - expect(response).to be_successful + expect(response.status).to eq(200) groups = JSON.parse(response.body) expect(groups.length).to eq(1) @@ -1238,7 +1238,7 @@ describe GroupsController do get "/groups/search.json?term=KingOfTheNorth" - expect(response).to be_successful + expect(response.status).to eq(200) groups = JSON.parse(response.body) expect(groups).to eq([]) @@ -1255,7 +1255,7 @@ describe GroupsController do get "/groups/search.json?term=north" - expect(response).to be_successful + expect(response.status).to eq(200) groups = JSON.parse(response.body) expect(groups.length).to eq(1) @@ -1269,7 +1269,7 @@ describe GroupsController do get '/groups/search.json?ignore_automatic=true' - expect(response).to be_successful + expect(response.status).to eq(200) groups = JSON.parse(response.body) expect(groups.length).to eq(2) diff --git a/spec/requests/invites_controller_spec.rb b/spec/requests/invites_controller_spec.rb index b945453b71..4b4586ce13 100644 --- a/spec/requests/invites_controller_spec.rb +++ b/spec/requests/invites_controller_spec.rb @@ -8,7 +8,7 @@ describe InvitesController do it "returns error if invite not found" do get "/invites/nopeNOPEnope" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body expect(body).to_not have_tag(:script, with: { src: '/assets/application.js' }) @@ -18,7 +18,7 @@ describe InvitesController do it "renders the accept invite page if invite exists" do get "/invites/#{invite.invite_key}" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) @@ -29,7 +29,7 @@ describe InvitesController do invite.update_attributes!(redeemed_at: 1.day.ago) get "/invites/#{invite.invite_key}" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body expect(body).to_not have_tag(:script, with: { src: '/assets/application.js' }) @@ -100,7 +100,7 @@ describe InvitesController do group = Fabricate(:group) sign_in(Fabricate(:admin)) post "/invites.json", params: { email: email, group_names: group.name } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Invite.find_by(email: email).invited_groups.count).to eq(1) end @@ -112,7 +112,7 @@ describe InvitesController do post "/invites.json", params: { email: email, group_names: group.name } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Invite.find_by(email: email).invited_groups.count).to eq(1) end @@ -120,7 +120,7 @@ describe InvitesController do user = sign_in(Fabricate(:admin)) invite = Invite.invite_by_email("invite@example.com", user) post "/invites.json", params: { email: invite.email } - expect(response).to be_successful + expect(response.status).to eq(200) end it "responds with error message in case of validation failure" do @@ -182,7 +182,7 @@ describe InvitesController do email: email, group_names: group.name } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Invite.find_by(email: email).invited_groups.count).to eq(1) end @@ -195,7 +195,7 @@ describe InvitesController do email: email, group_names: "security,support" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Invite.find_by(email: email).invited_groups.count).to eq(2) end end @@ -205,7 +205,7 @@ describe InvitesController do context 'with an invalid invite id' do it "redirects to the root and doesn't change the session" do put "/invites/show/doesntexist.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["success"]).to eq(false) expect(json["message"]).to eq(I18n.t('invite.not_found')) @@ -223,7 +223,7 @@ describe InvitesController do it "redirects to the root" do put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["success"]).to eq(false) expect(json["message"]).to eq(I18n.t('invite.not_found')) @@ -254,7 +254,7 @@ describe InvitesController do :user_logged_in, :user_first_logged_in ) invite.reload - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(invite.user_id) expect(invite.redeemed?).to be_truthy end @@ -271,7 +271,7 @@ describe InvitesController do context 'failure' do it "doesn't log in the user if there's a validation error" do put "/invites/show/#{invite.invite_key}.json", params: { password: "password" } - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["success"]).to eq(false) expect(json["errors"]["password"]).to be_present @@ -286,13 +286,13 @@ describe InvitesController do it 'sends a welcome message if set' do user.send_welcome_message = true put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::SendSystemMessage.jobs.size).to eq(1) end it "sends password reset email if password is not set" do put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(1) end @@ -300,20 +300,20 @@ describe InvitesController do SiteSetting.sso_url = "https://www.example.com/sso" SiteSetting.enable_sso = true put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) end it "does not send password reset email if local login is disabled" do SiteSetting.enable_local_logins = false put "/invites/show/#{invite.invite_key}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) end it 'sends an activation email if password is set' do put "/invites/show/#{invite.invite_key}.json", params: { password: "verystrongpassword" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::InvitePasswordInstructionsEmail.jobs.size).to eq(0) expect(Jobs::CriticalUserEmail.jobs.size).to eq(1) end @@ -381,7 +381,7 @@ describe InvitesController do it "resends the invite" do SiteSetting.queue_jobs = true post "/invites/reinvite.json", params: { email: invite.email } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::InviteEmail.jobs.size).to eq(1) end end @@ -412,7 +412,7 @@ describe InvitesController do SiteSetting.queue_jobs = true sign_in(Fabricate(:admin)) post "/invites/upload_csv.json", params: { file: file, name: filename } - expect(response).to be_successful + expect(response.status).to eq(200) expect(Jobs::BulkInvite.jobs.size).to eq(1) end end diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index f7bb4286cf..0f72cedfa0 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -13,19 +13,19 @@ RSpec.describe ListController do describe '#index' do it "doesn't throw an error with a negative page" do get "/#{Discourse.anonymous_filters[1]}", params: { page: -1024 } - expect(response).to be_successful + expect(response.status).to eq(200) end it "doesn't throw an error with page params as an array" do get "/#{Discourse.anonymous_filters[1]}", params: { page: ['7'] } - expect(response).to be_successful + expect(response.status).to eq(200) end (Discourse.anonymous_filters - [:categories]).each do |filter| context "#{filter}" do it "succeeds" do get "/#{filter}" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -34,7 +34,7 @@ RSpec.describe ListController do p = create_post get "/latest.json", params: { topic_ids: "#{p.topic_id}" } - expect(response).to be_successful + expect(response.status).to eq(200) parsed = JSON.parse(response.body) expect(parsed["topic_list"]["topics"].length).to eq(1) end @@ -238,20 +238,20 @@ RSpec.describe ListController do describe 'RSS feeds' do it 'renders latest RSS' do get "/latest.rss" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.content_type).to eq('application/rss+xml') end it 'renders top RSS' do get "/top.rss" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.content_type).to eq('application/rss+xml') end TopTopic.periods.each do |period| it "renders #{period} top RSS" do get "/top/#{period}.rss" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.content_type).to eq('application/rss+xml') end end @@ -312,7 +312,7 @@ RSpec.describe ListController do it 'uses the correct category' do get "/c/#{other_category.slug}/l/latest.json" - expect(response).to be_successful + expect(response.status).to eq(200) body = JSON.parse(response.body) expect(body["topic_list"]["topics"].first["category_id"]) .to eq(other_category.id) @@ -340,7 +340,7 @@ RSpec.describe ListController do describe 'feed' do it 'renders RSS' do get "/c/#{category.slug}.rss" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.content_type).to eq('application/rss+xml') end end @@ -349,7 +349,7 @@ RSpec.describe ListController do it "has a top default view" do category.update_attributes!(default_view: 'top', default_top_period: 'monthly') get "/c/#{category.slug}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to eq("monthly") end @@ -357,7 +357,7 @@ RSpec.describe ListController do it "has a default view of nil" do category.update_attributes!(default_view: nil) get "/c/#{category.slug}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to be_blank end @@ -365,7 +365,7 @@ RSpec.describe ListController do it "has a default view of ''" do category.update_attributes!(default_view: '') get "/c/#{category.slug}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to be_blank end @@ -373,7 +373,7 @@ RSpec.describe ListController do it "has a default view of latest" do category.update_attributes!(default_view: 'latest') get "/c/#{category.slug}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["for_period"]).to be_blank end @@ -382,13 +382,13 @@ RSpec.describe ListController do describe "renders canonical tag" do it 'for category default view' do get "/c/#{category.slug}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(css_select("link[rel=canonical]").length).to eq(1) end it 'for category latest view' do get "/c/#{category.slug}/l/latest" - expect(response).to be_successful + expect(response.status).to eq(200) expect(css_select("link[rel=canonical]").length).to eq(1) end end @@ -403,7 +403,7 @@ RSpec.describe ListController do it "should respond with a list" do get "/topics/created-by/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -421,7 +421,7 @@ RSpec.describe ListController do pm.topic_allowed_users.create!(user: user) sign_in(user) get "/topics/private-messages/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -442,7 +442,7 @@ RSpec.describe ListController do it "succeeds when the user can see private messages" do sign_in(user) get "/topics/private-messages-sent/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -465,7 +465,7 @@ RSpec.describe ListController do it "succeeds when the user can see private messages" do sign_in(user) get "/topics/private-messages-unread/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["topic_list"]["topics"].size).to eq(1) end @@ -481,7 +481,7 @@ RSpec.describe ListController do it "succeeds" do sign_in(user) get "/read" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -546,7 +546,7 @@ RSpec.describe ListController do it "suppresses categories from the latest list" do get "/#{SiteSetting.homepage}.json" - expect(response).to be_successful + expect(response.status).to eq(200) topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } expect(topic_titles).not_to include(topic_in_sub_category.title, topic_in_category_two.title) @@ -554,7 +554,7 @@ RSpec.describe ListController do it "does not suppress" do get "/#{SiteSetting.homepage}.json", params: { category: category_one.id } - expect(response).to be_successful + expect(response.status).to eq(200) topic_titles = JSON.parse(response.body)["topic_list"]["topics"].map { |t| t["title"] } expect(topic_titles).to include(topic_in_sub_category.title) diff --git a/spec/requests/notifications_controller_spec.rb b/spec/requests/notifications_controller_spec.rb index f7dede2aa5..e22721f82b 100644 --- a/spec/requests/notifications_controller_spec.rb +++ b/spec/requests/notifications_controller_spec.rb @@ -36,12 +36,12 @@ describe NotificationsController do describe '#index' do it 'should succeed for recent' do get "/notifications", params: { recent: true } - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should succeed for history' do get "/notifications" - expect(response).to be_successful + expect(response.status).to eq(200) end it 'should mark notifications as viewed' do @@ -72,14 +72,14 @@ describe NotificationsController do it 'should succeed' do put "/notifications/mark-read.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "can update a single notification" do notification = Fabricate(:notification, user: user) notification2 = Fabricate(:notification, user: user) put "/notifications/mark-read.json", params: { id: notification.id } - expect(response).to be_successful + expect(response.status).to eq(200) notification.reload notification2.reload diff --git a/spec/requests/omniauth_callbacks_controller_spec.rb b/spec/requests/omniauth_callbacks_controller_spec.rb index a7316c7651..c4deba0b83 100644 --- a/spec/requests/omniauth_callbacks_controller_spec.rb +++ b/spec/requests/omniauth_callbacks_controller_spec.rb @@ -80,7 +80,7 @@ RSpec.describe Users::OmniauthCallbacksController do expect(events.map { |event| event[:event_name] }).to include(:user_logged_in, :user_first_logged_in) - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) @@ -106,7 +106,7 @@ RSpec.describe Users::OmniauthCallbacksController do expect(events.map { |event| event[:event_name] }).to include(:user_logged_in, :user_first_logged_in) - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.email_confirmed?).to eq(true) @@ -125,7 +125,7 @@ RSpec.describe Users::OmniauthCallbacksController do expect(events.map { |event| event[:event_name] }).to include(:user_logged_in, :user_first_logged_in) - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.staged).to eq(false) @@ -185,7 +185,7 @@ RSpec.describe Users::OmniauthCallbacksController do it 'should return the right response' do get "/auth/google_oauth2/callback.json" - expect(response).to be_successful + expect(response.status).to eq(200) response_body = JSON.parse(response.body) diff --git a/spec/requests/onebox_controller_spec.rb b/spec/requests/onebox_controller_spec.rb index 04d9da91fc..21728df3e7 100644 --- a/spec/requests/onebox_controller_spec.rb +++ b/spec/requests/onebox_controller_spec.rb @@ -56,13 +56,13 @@ describe OneboxController do bypass_limiting Rails.cache.delete("onebox__#{url}") get "/onebox.json", params: { url: url } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include("Onebox1") bypass_limiting stub_request(:get, url).to_return(status: 200, body: html2).then.to_raise get "/onebox.json", params: { url: url, refresh: 'true' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include("Onebox2") end @@ -75,12 +75,12 @@ describe OneboxController do get "/onebox.json", params: { url: url, refresh: "true" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include('Onebox1') expect(response.body).to include('bodycontent') get "/onebox.json", params: { url: url } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include('Onebox1') expect(response.body).to include('bodycontent') end @@ -104,7 +104,7 @@ describe OneboxController do stub_request(:get, url).to_return(body: html).then.to_raise get "/onebox.json", params: { url: url, refresh: "true" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include("Onebox1") end end diff --git a/spec/requests/post_action_users_controller_spec.rb b/spec/requests/post_action_users_controller_spec.rb index 04d40eb866..1fdf4bb529 100644 --- a/spec/requests/post_action_users_controller_spec.rb +++ b/spec/requests/post_action_users_controller_spec.rb @@ -53,7 +53,7 @@ describe PostActionUsersController do id: post.id, post_action_type_id: PostActionType.types[:like] } - expect(response).to be_successful + expect(response.status).to eq(200) end it "paginates post actions" do diff --git a/spec/requests/post_actions_controller_spec.rb b/spec/requests/post_actions_controller_spec.rb index f3e8a38557..6be7be749f 100644 --- a/spec/requests/post_actions_controller_spec.rb +++ b/spec/requests/post_actions_controller_spec.rb @@ -37,7 +37,7 @@ RSpec.describe PostActionsController do it 'returns success' do delete "/post_actions/#{post.id}.json", params: { post_action_type_id: PostActionType.types[:bookmark] } - expect(response).to be_success + expect(response.status).to eq(200) end it 'deletes the action' do @@ -45,7 +45,7 @@ RSpec.describe PostActionsController do post_action_type_id: PostActionType.types[:bookmark] } - expect(response).to be_success + expect(response.status).to eq(200) expect(PostAction.exists?( user_id: user.id, post_id: post.id, @@ -137,7 +137,7 @@ RSpec.describe PostActionsController do post_action = PostAction.last - expect(response).to be_success + expect(response.status).to eq(200) expect(post_action.post_id).to eq(post_1.id) expect(post_action.post_action_type_id).to eq(PostActionType.types[:like]) end @@ -165,7 +165,7 @@ RSpec.describe PostActionsController do message: message } - expect(response).to be_success + expect(response.status).to eq(200) expect(PostAction.last.post_id).to eq(post_1.id) expect(Post.last.raw).to include(message) end @@ -180,7 +180,7 @@ RSpec.describe PostActionsController do is_warning: true } - expect(response).to be_success + expect(response.status).to eq(200) expect(PostAction.last.post_id).to eq(post_1.id) post = Post.last @@ -209,7 +209,7 @@ RSpec.describe PostActionsController do take_action: 'true' } - expect(response).to be_successful + expect(response.status).to eq(200) post_action = PostAction.last @@ -225,7 +225,7 @@ RSpec.describe PostActionsController do post_action_type_id: PostActionType.types[:like] } - expect(response).to be_successful + expect(response.status).to eq(200) post_action = PostAction.last @@ -282,7 +282,7 @@ RSpec.describe PostActionsController do id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] } - expect(response).to be_success + expect(response.status).to eq(200) flag.reload expect(flag.deferred_at).to be_present end @@ -294,7 +294,7 @@ RSpec.describe PostActionsController do id: flagged_post.id, post_action_type_id: PostActionType.types[:spam] } - expect(response).to be_success + expect(response.status).to eq(200) flag.reload expect(flag.deferred_at).to be_present end diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb index 74d6c3ea35..7f6620bd05 100644 --- a/spec/requests/posts_controller_spec.rb +++ b/spec/requests/posts_controller_spec.rb @@ -14,7 +14,7 @@ shared_examples 'finding and showing post' do it 'succeeds' do get url - expect(response).to be_successful + expect(response.status).to eq(200) end context "deleted post" do @@ -36,13 +36,13 @@ shared_examples 'finding and showing post' do it "can find posts as a moderator" do sign_in(Fabricate(:moderator)) get url - expect(response).to be_successful + expect(response.status).to eq(200) end it "can find posts as a admin" do sign_in(Fabricate(:admin)) get url - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -277,7 +277,7 @@ describe PostsController do it 'passes the edit reason through' do put "/posts/#{post.id}.json", params: update_params - expect(response).to be_successful + expect(response.status).to eq(200) post.reload expect(post.edit_reason).to eq("typo") expect(post.raw).to eq("edited body") @@ -307,7 +307,7 @@ describe PostsController do put "/posts/#{post.id}.json", params: param - expect(response).to be_successful + expect(response.status).to eq(200) expect(TopicLink.count).to eq(1) end @@ -330,7 +330,7 @@ describe PostsController do PostDestroyer.new(moderator, first_post).destroy put "/posts/#{first_post.id}.json", params: update_params - expect(response).to be_successful + expect(response.status).to eq(200) post.reload expect(post.raw).to eq('edited body') @@ -373,7 +373,7 @@ describe PostsController do it 'creates a bookmark' do put "/posts/#{post.id}/bookmark.json", params: { bookmarked: "true" } - expect(response).to be_successful + expect(response.status).to eq(200) post_action = PostAction.find_by(user: user, post: post) expect(post_action.post_action_type_id).to eq(PostActionType.types[:bookmark]) @@ -435,7 +435,7 @@ describe PostsController do api_key: api_key.key } - expect(response).to be_successful + expect(response.status).to eq(200) expect(PostAction.where( post: post, user: user, @@ -460,7 +460,7 @@ describe PostsController do api_username: user.username } - expect(response).to be_successful + expect(response.status).to eq(200) expect(PostAction.where( post: post, user: user, @@ -587,7 +587,7 @@ describe PostsController do it "can rebake the post" do sign_in(Fabricate(:moderator)) put "/posts/#{post.id}/rebake.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -617,7 +617,7 @@ describe PostsController do wpid: 1 } - expect(response).to be_successful + expect(response.status).to eq(200) original = response.body post "/posts.json", params: { @@ -628,7 +628,7 @@ describe PostsController do wpid: 2 } - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to eq(original) end @@ -647,7 +647,7 @@ describe PostsController do reply_to_post_number: 1 } - expect(response).to be_successful + expect(response.status).to eq(200) expect(post_1.topic.user.notifications.count).to eq(1) post_1.topic.user.notifications.destroy_all @@ -660,7 +660,7 @@ describe PostsController do import_mode: true } - expect(response).to be_successful + expect(response.status).to eq(200) expect(post_1.topic.user.notifications.count).to eq(0) post "/posts.json", params: { @@ -672,7 +672,7 @@ describe PostsController do import_mode: false } - expect(response).to be_successful + expect(response.status).to eq(200) expect(post_1.topic.user.notifications.count).to eq(1) end end @@ -694,7 +694,7 @@ describe PostsController do title: 'this is the test title for the topic' } - expect(response).to be_successful + expect(response.status).to eq(200) parsed = ::JSON.parse(response.body) expect(parsed["action"]).to eq("enqueued") @@ -747,7 +747,7 @@ describe PostsController do title: 'when I eat s3 sometimes when not looking' } - expect(response).to be_successful + expect(response.status).to eq(200) parsed = ::JSON.parse(response.body) expect(parsed["action"]).to eq("enqueued") @@ -780,7 +780,7 @@ describe PostsController do archetype: Archetype.private_message } - expect(response).to be_successful + expect(response.status).to eq(200) parsed = ::JSON.parse(response.body) post = Post.find(parsed['id']) @@ -796,7 +796,7 @@ describe PostsController do nested_post: true } - expect(response).to be_successful + expect(response.status).to eq(200) parsed = ::JSON.parse(response.body) expect(parsed['post']).to be_present expect(parsed['post']['cooked']).to be_present @@ -807,7 +807,7 @@ describe PostsController do title = "this is a title #{SecureRandom.hash}" post "/posts.json", params: { raw: raw, title: title, wpid: 1 } - expect(response).to be_successful + expect(response.status).to eq(200) post "/posts.json", params: { raw: raw, title: title, wpid: 2 } expect(response).not_to be_successful @@ -835,7 +835,7 @@ describe PostsController do meta_data: { xyz: 'abc' } } - expect(response).to be_successful + expect(response.status).to eq(200) new_post = Post.last topic = new_post.topic @@ -858,7 +858,7 @@ describe PostsController do image_sizes: { width: '100', height: '200' } } - expect(response).to be_successful + expect(response.status).to eq(200) new_post = Post.last topic = new_post.topic @@ -883,7 +883,7 @@ describe PostsController do target_usernames: "#{user_2.username},#{user_3.username}" } - expect(response).to be_successful + expect(response.status).to eq(200) new_post = Post.last new_topic = Topic.last @@ -956,7 +956,7 @@ describe PostsController do category: destination_category.id, shared_draft: 'true' } - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) topic = Topic.find(result['topic_id']) expect(topic.category_id).to eq(shared_category.id) @@ -983,7 +983,7 @@ describe PostsController do is_warning: true } - expect(response).to be_successful + expect(response.status).to eq(200) new_topic = Topic.last @@ -1000,7 +1000,7 @@ describe PostsController do is_warning: false } - expect(response).to be_successful + expect(response.status).to eq(200) new_topic = Topic.last @@ -1020,7 +1020,7 @@ describe PostsController do is_warning: true } - expect(response).to be_successful + expect(response.status).to eq(200) new_topic = Topic.last @@ -1058,7 +1058,7 @@ describe PostsController do it "ensures staff can see the revisions" do sign_in(Fabricate(:admin)) get "/posts/#{post.id}/revisions/#{post_revision.number}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "ensures poster can see the revisions" do @@ -1069,13 +1069,13 @@ describe PostsController do pr = Fabricate(:post_revision, user: user, post: post) get "/posts/#{pr.post_id}/revisions/#{pr.number}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "ensures trust level 4 can see the revisions" do sign_in(Fabricate(:user, trust_level: 4)) get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -1085,7 +1085,7 @@ describe PostsController do it "ensures anyone can see the revisions" do get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -1099,7 +1099,7 @@ describe PostsController do it "also work on deleted post" do sign_in(admin) get "/posts/#{deleted_post_revision.post_id}/revisions/#{deleted_post_revision.number}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -1114,7 +1114,7 @@ describe PostsController do it "also work on deleted topic" do sign_in(admin) get "/posts/#{post_revision.post_id}/revisions/#{post_revision.number}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -1173,7 +1173,7 @@ describe PostsController do it "works!" do put "/posts/#{post_id}/revisions/#{revision_id}/revert.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "supports reverting posts in deleted topics" do @@ -1181,7 +1181,7 @@ describe PostsController do PostDestroyer.new(moderator, first_post).destroy put "/posts/#{post_id}/revisions/#{revision_id}/revert.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -1202,7 +1202,7 @@ describe PostsController do it "retrieves the body when you can see the post" do TopicEmbed.expects(:expanded_for).with(post).returns("full content") get "/posts/#{post.id}/expand-embed.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['cooked']).to eq("full content") end end @@ -1220,7 +1220,7 @@ describe PostsController do it "can see the flagged posts when authorized" do sign_in(Fabricate(:moderator)) get "/posts/system/flagged.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "only shows agreed and deferred flags" do @@ -1241,7 +1241,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{user.username}/flagged.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body).length).to eq(2) end @@ -1261,7 +1261,7 @@ describe PostsController do it "can see the deleted posts when authorized" do sign_in(Fabricate(:moderator)) get "/posts/system/deleted.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "doesn't return secured categories for moderators if they don't have access" do @@ -1278,7 +1278,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{user.username}/deleted.json" - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data.length).to eq(0) @@ -1294,7 +1294,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{user.username}/deleted.json" - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data.length).to eq(0) @@ -1313,7 +1313,7 @@ describe PostsController do sign_in(Fabricate(:admin)) get "/posts/#{user.username}/deleted.json" - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data.length).to eq(1) @@ -1327,7 +1327,7 @@ describe PostsController do it "can be viewed by anonymous" do post = Fabricate(:post, raw: "123456789") get "/posts/#{post.id}/raw.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to eq("123456789") end end @@ -1338,7 +1338,7 @@ describe PostsController do post = Fabricate(:post, topic: topic, post_number: 1, raw: "123456789") post.save get "/raw/#{topic.id}/1.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to eq("123456789") end end @@ -1366,7 +1366,7 @@ describe PostsController do get "/u/#{user.username}/activity.rss" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body @@ -1384,7 +1384,7 @@ describe PostsController do private_post get "/private-posts.rss" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body @@ -1398,7 +1398,7 @@ describe PostsController do public_post private_post get "/private-posts.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) post_ids = json['private_posts'].map { |p| p['id'] } @@ -1415,7 +1415,7 @@ describe PostsController do get "/posts.rss" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body @@ -1431,7 +1431,7 @@ describe PostsController do topicless_post get "/posts.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) post_ids = json['latest_posts'].map { |p| p['id'] } @@ -1448,7 +1448,7 @@ describe PostsController do post = Fabricate(:post, cooked: "WAt") get "/posts/#{post.id}/cooked.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json).to be_present @@ -1473,7 +1473,7 @@ describe PostsController do sign_in(Fabricate(:moderator)) get "/posts/#{post.id}/raw-email.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['raw_email']).to eq('email_content') @@ -1488,12 +1488,12 @@ describe PostsController do it 'can lock and unlock the post' do put "/posts/#{public_post.id}/locked.json", params: { locked: "true" } - expect(response).to be_successful + expect(response.status).to eq(200) public_post.reload expect(public_post).to be_locked put "/posts/#{public_post.id}/locked.json", params: { locked: "false" } - expect(response).to be_successful + expect(response.status).to eq(200) public_post.reload expect(public_post).not_to be_locked end diff --git a/spec/requests/queued_posts_controller_spec.rb b/spec/requests/queued_posts_controller_spec.rb index 421c0d9bc7..d8911e52e1 100644 --- a/spec/requests/queued_posts_controller_spec.rb +++ b/spec/requests/queued_posts_controller_spec.rb @@ -24,7 +24,7 @@ describe QueuedPostsController do it 'returns the queued posts' do get "/queued-posts.json" - expect(response).to be_success + expect(response.status).to eq(200) end end @@ -53,7 +53,7 @@ describe QueuedPostsController do queued_post: { state: 'approved' } } - expect(response).to be_success + expect(response.status).to eq(200) qp.reload expect(qp.state).to eq(QueuedPost.states[:approved]) @@ -67,7 +67,7 @@ describe QueuedPostsController do queued_post: { state: 'rejected' } } - expect(response).to be_success + expect(response.status).to eq(200) qp.reload expect(qp.state).to eq(QueuedPost.states[:rejected]) @@ -92,7 +92,7 @@ describe QueuedPostsController do queued_post: changes } - expect(response).to be_success + expect(response.status).to eq(200) queued_topic.reload expect(queued_topic.raw).to eq(changes[:raw]) @@ -111,7 +111,7 @@ describe QueuedPostsController do } original_category = queued_reply.post_options['category'] - expect(response).to be_success + expect(response.status).to eq(200) queued_reply.reload expect(queued_reply.raw).to eq(changes[:raw]) diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb index 1a5ab80d24..0990a0c1e8 100644 --- a/spec/requests/search_controller_spec.rb +++ b/spec/requests/search_controller_spec.rb @@ -17,7 +17,7 @@ describe SearchController do term: 'awesome', include_blurb: true } - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data['posts'][0]['id']).to eq(my_post.id) expect(data['posts'][0]['blurb']).to eq('this is my really awesome post') @@ -32,7 +32,7 @@ describe SearchController do term: user.username, type_filter: 'topic' } - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data['posts'][0]['id']).to eq(my_post.id) @@ -42,7 +42,7 @@ describe SearchController do term: user.username, type_filter: 'user' } - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data['posts']).to be_blank @@ -61,7 +61,7 @@ describe SearchController do search_for_id: true } - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data['topics'][0]['id']).to eq(post.topic_id) @@ -77,7 +77,7 @@ describe SearchController do search_for_id: true } - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data['topics'][0]['id']).to eq(my_post.topic_id) @@ -90,7 +90,7 @@ describe SearchController do SiteSetting.log_search_queries = true get "/search/query.json", params: { term: 'wookie' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.where(term: 'wookie')).to be_present json = JSON.parse(response.body) @@ -105,7 +105,7 @@ describe SearchController do it "doesn't log when disabled" do SiteSetting.log_search_queries = false get "/search/query.json", params: { term: 'wookie' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.where(term: 'wookie')).to be_blank end end @@ -114,14 +114,14 @@ describe SearchController do it "logs the search term" do SiteSetting.log_search_queries = true get "/search.json", params: { q: 'bantha' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.where(term: 'bantha')).to be_present end it "doesn't log when disabled" do SiteSetting.log_search_queries = false get "/search.json", params: { q: 'bantha' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.where(term: 'bantha')).to be_blank end end @@ -155,7 +155,7 @@ describe SearchController do term: 'test', search_context: { type: 'user', id: user.username } } - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -187,7 +187,7 @@ describe SearchController do search_result_type: 'topic' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.find(search_log_id).search_result_id).to be_blank end @@ -207,7 +207,7 @@ describe SearchController do search_result_type: 'user' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.find(search_log_id).search_result_id).to eq(12345) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:user]) end @@ -228,7 +228,7 @@ describe SearchController do search_result_type: 'topic' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.find(search_log_id).search_result_id).to eq(22222) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:topic]) end @@ -246,7 +246,7 @@ describe SearchController do search_result_type: 'topic' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.find(search_log_id).search_result_id).to be_blank end @@ -266,7 +266,7 @@ describe SearchController do search_result_type: 'category' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.find(search_log_id).search_result_id).to eq(23456) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:category]) end @@ -288,7 +288,7 @@ describe SearchController do search_result_type: 'tag' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SearchLog.find(search_log_id).search_result_id).to eq(tag.id) expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:tag]) end diff --git a/spec/requests/session_controller_spec.rb b/spec/requests/session_controller_spec.rb index 51bff909d0..2cb726282a 100644 --- a/spec/requests/session_controller_spec.rb +++ b/spec/requests/session_controller_spec.rb @@ -28,7 +28,7 @@ RSpec.describe SessionController do it 'returns the right response' do get "/session/email-login/adasdad" - expect(response).to be_successful + expect(response.status).to eq(200) expect(CGI.unescapeHTML(response.body)).to match( I18n.t('email_login.invalid_token') @@ -41,7 +41,7 @@ RSpec.describe SessionController do get "/session/email-login/#{email_token.token}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(CGI.unescapeHTML(response.body)).to match( I18n.t('email_login.invalid_token') @@ -823,7 +823,7 @@ RSpec.describe SessionController do login: user.username, password: 'sssss' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['error']).to eq( I18n.t("login.incorrect_username_email_or_password") ) @@ -837,7 +837,7 @@ RSpec.describe SessionController do login: user.username, password: ('s' * (User.max_password_length + 1)) } - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['error']).to eq( I18n.t("login.incorrect_username_email_or_password") ) @@ -855,7 +855,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq(I18n.t('login.suspended_with_reason', date: I18n.l(user.suspended_till, format: :date_only), reason: Rack::Utils.escape_html(user.suspend_reason) @@ -872,7 +872,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq(I18n.t('login.not_activated')) end end @@ -885,7 +885,7 @@ RSpec.describe SessionController do } end - expect(response).to be_successful + expect(response.status).to eq(200) expect(events.map { |event| event[:event_name] }).to contain_exactly( :user_logged_in, :user_first_logged_in ) @@ -908,7 +908,7 @@ RSpec.describe SessionController do password: 'myawesomepassword', } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq(I18n.t( 'login.invalid_second_factor_code' )) @@ -923,7 +923,7 @@ RSpec.describe SessionController do second_factor_token: '00000000' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq(I18n.t( 'login.invalid_second_factor_code' )) @@ -937,7 +937,7 @@ RSpec.describe SessionController do password: 'myawesomepassword', second_factor_token: ROTP::TOTP.new(user_second_factor.data).now } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(session[:current_user_id]).to eq(user.id) @@ -957,7 +957,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: "@" + user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(session[:current_user_id]).to be_nil @@ -969,7 +969,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: "@" + user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(session[:current_user_id]).to eq(user.id) @@ -981,7 +981,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: user.email, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(user.id) end end @@ -994,7 +994,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['error']).not_to be_present end @@ -1002,7 +1002,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: email, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(::JSON.parse(response.body)['error']).not_to be_present end end @@ -1020,12 +1020,12 @@ RSpec.describe SessionController do end it "doesn't log in the user" do - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to be_blank end it "shows the 'not approved' error message" do - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq( I18n.t('login.not_approved') ) @@ -1040,7 +1040,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: user.email, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(user.id) end end @@ -1063,7 +1063,7 @@ RSpec.describe SessionController do post "/session.json", params: { login: user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(user.id) end @@ -1076,7 +1076,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to be_present expect(session[:current_user_id]).not_to eq(user.id) end @@ -1090,7 +1090,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(user.id) end end @@ -1105,13 +1105,13 @@ RSpec.describe SessionController do it "doesn't log in the user" do post_login - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to be_blank end it "shows the 'not activated' error message" do post_login - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq( I18n.t 'login.not_activated' ) @@ -1122,7 +1122,7 @@ RSpec.describe SessionController do it "shows the 'not approved' error message" do post_login - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)['error']).to eq( I18n.t 'login.not_approved' ) @@ -1141,7 +1141,7 @@ RSpec.describe SessionController do login: user.username, password: 'myawesomepassword' } - expect(response).to be_successful + expect(response.status).to eq(200) end post "/session.json", params: { @@ -1164,7 +1164,7 @@ RSpec.describe SessionController do second_factor_token: '000000' } - expect(response).to be_successful + expect(response.status).to eq(200) end post "/session.json", params: { @@ -1285,7 +1285,7 @@ RSpec.describe SessionController do it "returns the JSON for the user" do get "/session/current.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['current_user']).to be_present expect(json['current_user']['id']).to eq(user.id) diff --git a/spec/requests/similar_topics_controller_spec.rb b/spec/requests/similar_topics_controller_spec.rb index d6692bab3f..93e234f22e 100644 --- a/spec/requests/similar_topics_controller_spec.rb +++ b/spec/requests/similar_topics_controller_spec.rb @@ -30,7 +30,7 @@ describe SimilarTopicsController do reindex_posts get "/topics/similar_to.json", params: { title: title, raw: raw } - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["similar_topics"].size).to eq(0) end @@ -48,7 +48,7 @@ describe SimilarTopicsController do get "/topics/similar_to.json", params: { title: title, raw: raw } - expect(response).to be_success + expect(response.status).to eq(200) similar_topics = ::JSON.parse(response.body)["similar_topics"] expect(similar_topics.size).to eq(1) expect(similar_topics.first["topic_id"]).to eq(topic.id) @@ -66,7 +66,7 @@ describe SimilarTopicsController do it "passes a user through if logged in" do get "/topics/similar_to.json", params: { title: title, raw: raw } - expect(response).to be_success + expect(response.status).to eq(200) similar_topics = ::JSON.parse(response.body)["similar_topics"].map { |topic| topic["topic_id"] } expect(similar_topics.size).to eq(2) expect(similar_topics).to include(topic.id) @@ -82,7 +82,7 @@ describe SimilarTopicsController do get "/topics/similar_to.json", params: { title: title, raw: raw } - expect(response).to be_success + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["similar_topics"].size).to eq(0) end diff --git a/spec/requests/site_controller_spec.rb b/spec/requests/site_controller_spec.rb index d57ca36da8..b084dec7b1 100644 --- a/spec/requests/site_controller_spec.rb +++ b/spec/requests/site_controller_spec.rb @@ -32,7 +32,7 @@ describe SiteController do get "/site/statistics.json" json = JSON.parse(response.body) - expect(response).to be_successful + expect(response.status).to eq(200) expect(json["topic_count"]).to be_present expect(json["post_count"]).to be_present expect(json["user_count"]).to be_present diff --git a/spec/requests/static_controller_spec.rb b/spec/requests/static_controller_spec.rb index 994167fad7..490d2966dc 100644 --- a/spec/requests/static_controller_spec.rb +++ b/spec/requests/static_controller_spec.rb @@ -98,7 +98,7 @@ describe StaticController do it "should return the right response" do get "/faq" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(I18n.t('js.faq')) end end @@ -113,7 +113,7 @@ describe StaticController do it "renders the #{id} page" do get "/#{id}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(text) end end @@ -150,7 +150,7 @@ describe StaticController do get "/login" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(PrettyText.cook(I18n.t( 'login_required.welcome_message', title: SiteSetting.title @@ -177,7 +177,7 @@ describe StaticController do get '/faq' - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(I18n.t('js.faq')) end @@ -186,7 +186,7 @@ describe StaticController do get '/guidelines' - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(I18n.t('guidelines')) end end diff --git a/spec/requests/steps_controller_spec.rb b/spec/requests/steps_controller_spec.rb index 44a6c9bdff..6f304bf70a 100644 --- a/spec/requests/steps_controller_spec.rb +++ b/spec/requests/steps_controller_spec.rb @@ -40,7 +40,7 @@ describe StepsController do fields: { contact_email: "eviltrout@example.com" } } - expect(response).to be_successful + expect(response.status).to eq(200) expect(SiteSetting.contact_email).to eq("eviltrout@example.com") end diff --git a/spec/requests/tags_controller_spec.rb b/spec/requests/tags_controller_spec.rb index 3b58b6e89a..9be7b71022 100644 --- a/spec/requests/tags_controller_spec.rb +++ b/spec/requests/tags_controller_spec.rb @@ -16,7 +16,7 @@ describe TagsController do it "should return the right response" do get "/tags.json" - expect(response).to be_successful + expect(response.status).to eq(200) tags = JSON.parse(response.body)["tags"] expect(tags.length).to eq(1) @@ -41,7 +41,7 @@ describe TagsController do get "/tags.json" - expect(response).to be_successful + expect(response.status).to eq(200) tags = JSON.parse(response.body)["tags"] expect(tags.length).to eq(2) @@ -57,7 +57,7 @@ describe TagsController do it "should return the right response" do get "/tags/test" - expect(response).to be_successful + expect(response.status).to eq(200) end it "should handle invalid tags" do @@ -72,7 +72,7 @@ describe TagsController do it "should return the right response" do get "/tags/check.json", params: { tag_values: [tag.name] } - expect(response).to be_successful + expect(response.status).to eq(200) tag = JSON.parse(response.body)["valid"].first expect(tag["value"]).to eq('test') @@ -141,7 +141,7 @@ describe TagsController do it "can see their own pm tags" do get "/tags/personal_messages/#{moderator.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) tag = JSON.parse(response.body)['tags'] expect(tag[0]["id"]).to eq('test') @@ -156,7 +156,7 @@ describe TagsController do it "can see pm tags for regular user" do get "/tags/personal_messages/#{regular_user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) tag = JSON.parse(response.body)['tags'] expect(tag[0]["id"]).to eq('test') @@ -165,7 +165,7 @@ describe TagsController do it "can see their own pm tags" do get "/tags/personal_messages/#{admin.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) tag = JSON.parse(response.body)['tags'] expect(tag[0]["id"]).to eq('test') @@ -195,7 +195,7 @@ describe TagsController do context 'tagging enabled' do it "can filter by tag" do get "/tags/#{tag.name}/l/latest.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "can filter by two tags" do @@ -205,7 +205,7 @@ describe TagsController do additional_tag_ids: other_tag.name } - expect(response).to be_successful + expect(response.status).to eq(200) topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -222,7 +222,7 @@ describe TagsController do additional_tag_ids: "#{other_tag.name}/#{third_tag.name}" } - expect(response).to be_successful + expect(response.status).to eq(200) topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -239,7 +239,7 @@ describe TagsController do additional_tag_ids: "notatag" } - expect(response).to be_successful + expect(response.status).to eq(200) topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -249,17 +249,17 @@ describe TagsController do it "can filter by category and tag" do get "/tags/c/#{category.slug}/#{tag.name}/l/latest.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "can filter by category, sub-category, and tag" do get "/tags/c/#{category.slug}/#{subcategory.slug}/#{tag.name}/l/latest.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "can filter by category, no sub-category, and tag" do get "/tags/c/#{category.slug}/none/#{tag.name}/l/latest.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "can handle subcategories with the same name" do @@ -272,7 +272,7 @@ describe TagsController do t = Fabricate(:topic, category_id: subcategory2.id, tags: [other_tag]) get "/tags/c/#{category2.slug}/#{subcategory2.slug}/#{other_tag.name}/l/latest.json" - expect(response).to be_successful + expect(response.status).to eq(200) topic_ids = JSON.parse(response.body)["topic_list"]["topics"] .map { |topic| topic["id"] } @@ -284,7 +284,7 @@ describe TagsController do sign_in(Fabricate(:user)) get "/tags/#{tag.name}/l/bookmarks.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -303,7 +303,7 @@ describe TagsController do tag_names = ['stuff', 'stinky', 'stumped'] tag_names.each { |name| Fabricate(:tag, name: name) } get "/tags/filter/search.json", params: { q: 'stu' } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }.sort).to eq(['stuff', 'stumped']) end @@ -312,7 +312,7 @@ describe TagsController do yup, nope = Fabricate(:tag, name: 'yup'), Fabricate(:tag, name: 'nope') category = Fabricate(:category, tags: [yup]) get "/tags/filter/search.json", params: { q: 'nope', categoryId: category.id } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }.sort).to eq([]) expect(json["forbidden"]).to be_present @@ -322,7 +322,7 @@ describe TagsController do c = Fabricate(:private_category, group: Fabricate(:group)) Fabricate(:topic, category: c, tags: [Fabricate(:tag, name: "cooltag")]) get "/tags/filter/search.json", params: { q: "cool" } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }).to eq(['cooltag']) end @@ -332,12 +332,12 @@ describe TagsController do tag_names.each { |name| Fabricate(:tag, name: name) } get "/tags/filter/search.json", params: { q: '房' } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }).to eq(['房地产']) get "/tags/filter/search.json", params: { q: 'тема' } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json["results"].map { |j| j["id"] }).to eq(['тема-в-разработке']) end @@ -354,7 +354,7 @@ describe TagsController do it 'deletes the tag' do tag = Fabricate(:tag) delete "/tags/#{tag.name}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(Tag.where(id: tag.id)).to be_empty end end diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index f23881b74c..39b8e3288e 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}/wordpress.json", params: { best: 3 } - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) # The JSON has the data the wordpress plugin needs @@ -105,7 +105,7 @@ RSpec.describe TopicsController do } end.to change { Topic.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) @@ -127,7 +127,7 @@ RSpec.describe TopicsController do } end.to change { Topic.count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) result = JSON.parse(response.body) @@ -143,7 +143,7 @@ RSpec.describe TopicsController do post "/t/#{topic.id}/move-posts.json", params: { post_ids: [p2.id] } - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) expect(result['success']).to eq(false) expect(result['url']).to be_blank @@ -193,7 +193,7 @@ RSpec.describe TopicsController do destination_topic_id: dest_topic.id } - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) expect(result['success']).to eq(true) expect(result['url']).to be_present @@ -207,7 +207,7 @@ RSpec.describe TopicsController do post_ids: [p2.id] } - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) expect(result['success']).to eq(false) expect(result['url']).to be_blank @@ -251,7 +251,7 @@ RSpec.describe TopicsController do destination_topic_id: dest_topic.id } - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) expect(result['success']).to eq(true) expect(result['url']).to be_present @@ -317,7 +317,7 @@ RSpec.describe TopicsController do } topic.reload p1.reload - expect(response).to be_successful + expect(response.status).to eq(200) expect(topic.user.username).to eq(user_a.username) expect(p1.user.username).to eq(user_a.username) end @@ -327,7 +327,7 @@ RSpec.describe TopicsController do username: user_a.username_lower, post_ids: [p1.id, p2.id] } - expect(response).to be_successful + expect(response.status).to eq(200) p1.reload p2.reload @@ -347,7 +347,7 @@ RSpec.describe TopicsController do username: user_a.username_lower, post_ids: [p3.id] } - expect(response).to be_successful + expect(response.status).to eq(200) t2.reload p3.reload expect(t2.deleted_at).to be_nil @@ -392,7 +392,7 @@ RSpec.describe TopicsController do timestamp: new_timestamp.to_f } - expect(response).to be_successful + expect(response.status).to eq(200) expect(topic.reload.created_at).to be_within_one_second_of(new_timestamp) expect(p1.reload.created_at).to be_within_one_second_of(new_timestamp) expect(p2.reload.created_at).to be_within_one_second_of(old_timestamp) @@ -424,7 +424,7 @@ RSpec.describe TopicsController do expect do put "/t/#{topic.id}/clear-pin.json" end.to change { TopicUser.where(topic_id: topic.id, user_id: user.id).count }.by(1) - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -479,7 +479,7 @@ RSpec.describe TopicsController do status: 'closed', enabled: 'false' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(topic.reload.closed).to eq(false) expect(topic.topic_timers).to eq([]) @@ -560,7 +560,7 @@ RSpec.describe TopicsController do put "/t/#{topic.id}/recover.json" topic.reload post.reload - expect(response).to be_successful + expect(response.status).to eq(200) expect(topic.trashed?).to be_falsey expect(post.trashed?).to be_falsey end @@ -595,7 +595,7 @@ RSpec.describe TopicsController do it 'succeeds' do delete "/t/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) topic.reload expect(topic.trashed?).to be_truthy end @@ -609,7 +609,7 @@ RSpec.describe TopicsController do it "returns JSON for the slug" do get "/t/id_for/#{topic.slug}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = ::JSON.parse(response.body) expect(json['topic_id']).to eq(topic.id) expect(json['url']).to eq(topic.url) @@ -785,7 +785,7 @@ RSpec.describe TopicsController do it 'correctly renders canoicals' do get "/t/#{topic.id}", params: { slug: topic.slug } - expect(response).to be_successful + expect(response.status).to eq(200) expect(css_select("link[rel=canonical]").length).to eq(1) expect(response.headers["Cache-Control"]).to eq("no-cache, no-store") end @@ -802,7 +802,7 @@ RSpec.describe TopicsController do Fabricate(:post, topic: topic) get "/t/#{topic.id}.json", params: { slug: topic.slug } - expect(response).to be_successful + expect(response.status).to eq(200) get "/t/#{topic.id}.json", params: { slug: "just-guessing" } expect(response.status).to eq(301) @@ -813,7 +813,7 @@ RSpec.describe TopicsController do it 'shows a topic correctly' do get "/t/#{topic.slug}/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it 'return 404 for an invalid page' do @@ -1042,7 +1042,7 @@ RSpec.describe TopicsController do SiteSetting.max_prints_per_hour_per_user = 10 get "/t/#{topic.slug}/#{topic.id}/print", headers: { HTTP_USER_AGENT: "Rails Testing" } - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body expect(body).to have_tag(:body, class: 'crawler') @@ -1108,20 +1108,20 @@ RSpec.describe TopicsController do it 'grabs the correct set of posts' do get "/t/#{topic.slug}/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(extract_post_stream).to eq(@post_ids[0..1]) get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 1 } - expect(response).to be_successful + expect(response.status).to eq(200) expect(extract_post_stream).to eq(@post_ids[0..1]) get "/t/#{topic.slug}/#{topic.id}.json", params: { page: 2 } - expect(response).to be_successful + expect(response.status).to eq(200) 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).to be_successful + expect(response.status).to eq(200) expect(extract_post_stream).to eq(@post_ids[-2..-1]) end end @@ -1134,7 +1134,7 @@ RSpec.describe TopicsController do it 'shows the topic' do get "/t/#{topic.slug}/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end @@ -1150,7 +1150,7 @@ RSpec.describe TopicsController do it 'shows the topic if valid api key is provided' do get "/t/#{topic.slug}/#{topic.id}.json", params: { api_key: api_key.key } - expect(response).to be_successful + expect(response.status).to eq(200) topic.reload expect(topic.views).to eq(1) end @@ -1226,7 +1226,7 @@ RSpec.describe TopicsController do expect { get "/t/#{topic.id}.json" }.not_to change(IncomingLink, :count) - expect(response).to be_successful + expect(response.status).to eq(200) end it "doesn't raise an error on a very long link" do @@ -1245,7 +1245,7 @@ RSpec.describe TopicsController do body = response.body - expect(response).to be_successful + expect(response.status).to eq(200) expect(body).to have_tag(:script, with: { src: '/assets/application.js' }) expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) end @@ -1272,7 +1272,7 @@ RSpec.describe TopicsController do body = response.body - expect(response).to be_successful + expect(response.status).to eq(200) expect(body).to have_tag(:body, with: { class: 'crawler' }) expect(body).to_not have_tag(:meta, with: { name: 'fragment' }) end @@ -1288,7 +1288,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.cookies['cn']).to eq(nil) notification.reload @@ -1301,7 +1301,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}.json", headers: { "Discourse-Clear-Notifications" => "2828,100,#{notification.id}" } - expect(response).to be_successful + expect(response.status).to eq(200) notification.reload expect(notification.read).to eq(true) end @@ -1323,7 +1323,7 @@ RSpec.describe TopicsController do it "uses the default locale" do get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_successful + expect(response.status).to eq(200) expect(I18n.locale).to eq(:en) end end @@ -1335,7 +1335,7 @@ RSpec.describe TopicsController do get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_successful + expect(response.status).to eq(200) expect(I18n.locale).to eq(:en) end end @@ -1353,7 +1353,7 @@ RSpec.describe TopicsController do context "with an anonymous user" do it "uses the locale from the headers" do get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_successful + expect(response.status).to eq(200) expect(I18n.locale).to eq(:fr) end end @@ -1364,7 +1364,7 @@ RSpec.describe TopicsController do sign_in(user) get "/t/#{topic.id}.json", headers: headers("fr") - expect(response).to be_successful + expect(response.status).to eq(200) expect(I18n.locale).to eq(:fr) end end @@ -1377,7 +1377,7 @@ RSpec.describe TopicsController do SiteSetting.default_locale = "en" get "/t/#{topic.id}.json", headers: headers("zh-CN") - expect(response).to be_successful + expect(response.status).to eq(200) expect(I18n.locale).to eq(:zh_CN) end end @@ -1388,7 +1388,7 @@ RSpec.describe TopicsController do SiteSetting.default_locale = 'en' get "/t/#{topic.id}.json", headers: headers("") - expect(response).to be_successful + expect(response.status).to eq(200) expect(I18n.locale).to eq(:en) end end @@ -1398,14 +1398,14 @@ RSpec.describe TopicsController do describe "read only header" do it "returns no read only header by default" do get "/t/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.headers['Discourse-Readonly']).to eq(nil) end it "returns a readonly header if the site is read only" do Discourse.received_readonly! get "/t/#{topic.id}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.headers['Discourse-Readonly']).to eq('true') end end @@ -1416,7 +1416,7 @@ RSpec.describe TopicsController do it 'returns first posts of the topic' do get "/t/#{topic.id}/posts.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.content_type).to eq('application/json') end end @@ -1426,7 +1426,7 @@ RSpec.describe TopicsController do it 'renders rss of the topic' do get "/t/foo/#{topic.id}.rss" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.content_type).to eq('application/rss+xml') end end @@ -1473,7 +1473,7 @@ RSpec.describe TopicsController do topic = Fabricate(:topic, user: sign_in(Fabricate(:admin))) put "/t/#{topic.id}/make-banner.json" - expect(response).to be_successful + expect(response.status).to eq(200) topic.reload expect(topic.archetype).to eq(Archetype.banner) end @@ -1492,7 +1492,7 @@ RSpec.describe TopicsController do topic = Fabricate(:topic, user: sign_in(Fabricate(:admin)), archetype: Archetype.banner) put "/t/#{topic.id}/remove-banner.json" - expect(response).to be_successful + expect(response.status).to eq(200) topic.reload expect(topic.archetype).to eq(Archetype.default) end @@ -1601,7 +1601,7 @@ RSpec.describe TopicsController do user.user_stat.update_column(:new_since, old_date) put "/topics/reset-new.json" - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.user_stat.new_since.to_date).not_to eq(old_date.to_date) end @@ -1611,7 +1611,7 @@ RSpec.describe TopicsController do it "works" do get "/topics/feature_stats.json", params: { category_id: 1 } - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["pinned_in_category_count"]).to eq(0) expect(json["pinned_globally_count"]).to eq(0) @@ -1676,7 +1676,7 @@ RSpec.describe TopicsController do topic.reload expect(topic.archetype).to eq(Archetype.private_message) - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) expect(result['success']).to eq(true) @@ -1702,7 +1702,7 @@ RSpec.describe TopicsController do topic.reload expect(topic.archetype).to eq(Archetype.default) - expect(response).to be_successful + expect(response.status).to eq(200) result = ::JSON.parse(response.body) expect(result['success']).to eq(true) @@ -1724,7 +1724,7 @@ RSpec.describe TopicsController do timings: { post_1.post_number => 2 } } - expect(response).to be_successful + expect(response.status).to eq(200) post_timing = PostTiming.first @@ -1772,7 +1772,7 @@ RSpec.describe TopicsController do status_type: TopicTimer.types[1] } - expect(response).to be_successful + expect(response.status).to eq(200) topic_status_update = TopicTimer.last @@ -1798,7 +1798,7 @@ RSpec.describe TopicsController do status_type: TopicTimer.types[1] } - expect(response).to be_successful + expect(response.status).to eq(200) expect(topic.reload.public_topic_timer).to eq(nil) json = JSON.parse(response.body) @@ -1816,7 +1816,7 @@ RSpec.describe TopicsController do category_id: topic.category_id } - expect(response).to be_successful + expect(response.status).to eq(200) topic_status_update = TopicTimer.last @@ -2036,7 +2036,7 @@ RSpec.describe TopicsController do let!(:shared_draft) { Fabricate(:shared_draft, topic: topic, category: category) } it "allows staff to update the category id" do put "/t/#{topic.id}/shared-draft.json", params: { category_id: other_cat.id } - expect(response).to be_successful + expect(response.status).to eq(200) topic.reload expect(topic.shared_draft.category_id).to eq(other_cat.id) end @@ -2045,7 +2045,7 @@ RSpec.describe TopicsController do context "without a shared draft" do it "allows staff to update the category id" do put "/t/#{topic.id}/shared-draft.json", params: { category_id: other_cat.id } - expect(response).to be_successful + expect(response.status).to eq(200) topic.reload expect(topic.shared_draft.category_id).to eq(other_cat.id) end diff --git a/spec/requests/uploads_controller_spec.rb b/spec/requests/uploads_controller_spec.rb index 9fa184f0e5..fac1a98d8d 100644 --- a/spec/requests/uploads_controller_spec.rb +++ b/spec/requests/uploads_controller_spec.rb @@ -122,7 +122,7 @@ describe UploadsController do for_private_message: "true", } - expect(response).to be_successful + expect(response.status).to eq(200) id = JSON.parse(response.body)["id"] expect(id).to be_present end @@ -137,7 +137,7 @@ describe UploadsController do type: "composer", } - expect(response).to be_successful + expect(response.status).to eq(200) data = JSON.parse(response.body) expect(data["id"]).to be_present end diff --git a/spec/requests/user_avatars_controller_spec.rb b/spec/requests/user_avatars_controller_spec.rb index 0d86117abc..be10954e8a 100644 --- a/spec/requests/user_avatars_controller_spec.rb +++ b/spec/requests/user_avatars_controller_spec.rb @@ -59,7 +59,7 @@ describe UserAvatarsController do get "/user_avatar/default/#{user.username}/51/#{upload.id}.png" - expect(response).to be_successful + expect(response.status).to eq(200) end end end diff --git a/spec/requests/user_badges_controller_spec.rb b/spec/requests/user_badges_controller_spec.rb index 84b1b2ebbb..f565caa1a7 100644 --- a/spec/requests/user_badges_controller_spec.rb +++ b/spec/requests/user_badges_controller_spec.rb @@ -11,7 +11,7 @@ describe UserBadgesController do UserBadge.create!(badge: badge, user: user, post_id: p.id, granted_by_id: -1, granted_at: Time.now) get "/user_badges.json", params: { badge_id: badge.id } - expect(response).to be_successful + expect(response.status).to eq(200) parsed = JSON.parse(response.body) expect(parsed["topics"]).to eq(nil) diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb index 1714816a00..a99aacba9a 100644 --- a/spec/requests/users_controller_spec.rb +++ b/spec/requests/users_controller_spec.rb @@ -64,7 +64,7 @@ describe UsersController do :user_logged_in, :user_first_logged_in ) - expect(response).to be_successful + expect(response.status).to eq(200) expect(flash[:error]).to be_blank expect(session[:current_user_id]).to be_present @@ -81,7 +81,7 @@ describe UsersController do end it 'should return the right response' do - expect(response).to be_successful + expect(response.status).to eq(200) expect(CGI.unescapeHTML(response.body)) .to include(I18n.t('activation.approval_required')) @@ -116,7 +116,7 @@ describe UsersController do it "returns success" do SiteSetting.login_required = true get "/u/password-reset/#{token}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(CGI.unescapeHTML(response.body)).to include(I18n.t('password_reset.no_token')) end end @@ -127,7 +127,7 @@ describe UsersController do end it 'disallows login' do - expect(response).to be_successful + expect(response.status).to eq(200) expect(CGI.unescapeHTML(response.body)) .to include(I18n.t('password_reset.no_token')) @@ -144,7 +144,7 @@ describe UsersController do it 'disallows login' do get "/u/password-reset/ev!l_trout@!" - expect(response).to be_successful + expect(response.status).to eq(200) expect(CGI.unescapeHTML(response.body)) .to include(I18n.t('password_reset.no_token')) @@ -159,7 +159,7 @@ describe UsersController do it "responds with proper error message" do put "/u/password-reset/evil_trout!.json", params: { password: "awesomeSecretPassword" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)["message"]).to eq(I18n.t('password_reset.no_token')) expect(session[:current_user_id]).to be_blank end @@ -189,7 +189,7 @@ describe UsersController do :user_logged_in, :user_first_logged_in ) - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include('{"is_developer":false,"admin":false,"second_factor_required":false}') expect(session["password-#{token}"]).to be_blank @@ -294,7 +294,7 @@ describe UsersController do it "fails when the password is blank" do put "/u/password-reset/#{token}.json", params: { password: '' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)["errors"]).to be_present expect(session[:current_user_id]).to be_blank end @@ -302,7 +302,7 @@ describe UsersController do it "fails when the password is too long" do put "/u/password-reset/#{token}.json", params: { password: ('x' * (User.max_password_length + 1)) } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)["errors"]).to be_present expect(session[:current_user_id]).to be_blank end @@ -310,7 +310,7 @@ describe UsersController do it "logs in the user" do put "/u/password-reset/#{token}.json", params: { password: 'ksjafh928r' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)["errors"]).to be_blank expect(session[:current_user_id]).to be_present end @@ -331,14 +331,14 @@ describe UsersController do it "token doesn't match any records" do email_token = user.email_tokens.create(email: user.email) get "/u/confirm-email-token/#{SecureRandom.hex}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(email_token.reload.confirmed).to eq(false) end it "token matches" do email_token = user.email_tokens.create(email: user.email) get "/u/confirm-email-token/#{email_token.token}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(email_token.reload.confirmed).to eq(true) end end @@ -442,11 +442,11 @@ describe UsersController do user.save! post "/u/toggle-anon.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(AnonymousShadowCreator.get(user).id) post "/u/toggle-anon.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(session[:current_user_id]).to eq(user.id) end end @@ -934,7 +934,7 @@ describe UsersController do it "should succeed without the optional field" do post "/u.json", params: create_params - expect(response).to be_successful + expect(response.status).to eq(200) inserted = User.find_by_email(@user.email) expect(inserted).to be_present expect(inserted.custom_fields).to be_present @@ -946,7 +946,7 @@ describe UsersController do it "should succeed with the optional field" do create_params[:user_fields][optional_field.id.to_s] = 'value3' post "/u.json", params: create_params.merge(create_params) - expect(response).to be_successful + expect(response.status).to eq(200) inserted = User.find_by_email(@user.email) expect(inserted).to be_present expect(inserted.custom_fields).to be_present @@ -958,7 +958,7 @@ describe UsersController do it "trims excessively long fields" do create_params[:user_fields][optional_field.id.to_s] = ('x' * 3000) post "/u.json", params: create_params.merge(create_params) - expect(response).to be_successful + expect(response.status).to eq(200) inserted = User.find_by_email(@user.email) val = inserted.custom_fields["user_field_#{optional_field.id}"] @@ -980,7 +980,7 @@ describe UsersController do it "should succeed" do post "/u.json", params: create_params - expect(response).to be_successful + expect(response.status).to eq(200) inserted = User.find_by_email(@user.email) expect(inserted).to be_present expect(inserted.custom_fields).not_to be_present @@ -1073,7 +1073,7 @@ describe UsersController do it 'should succeed in normal circumstances' do put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.reload.username).to eq(new_username) end @@ -1097,7 +1097,7 @@ describe UsersController do put "/u/#{user.username}/preferences/username.json", params: { new_username: new_username } - expect(response).to be_successful + expect(response.status).to eq(200) expect(UserHistory.where(action: UserHistory.actions[:change_username], target_user_id: user.id, acting_user_id: acting_user.id)).to be_present expect(user.reload.username).to eq(new_username) end @@ -1221,7 +1221,7 @@ describe UsersController do user = Fabricate(:user) get "/u/#{user.username}/invited.json", params: { username: user.username } - expect(response).to be_successful + expect(response.status).to eq(200) end it 'filters by email' do @@ -1366,14 +1366,14 @@ describe UsersController do it "should be able to update a user" do put "/u/#{user.username}.json", params: { name: 'test.test' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.reload.name).to eq('test.test') end it "should be able to update a user" do put "/u/#{user.username}.json", params: { name: 'testing123' } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.reload.name).to eq('testing123') end end @@ -1391,7 +1391,7 @@ describe UsersController do user_fields: { user_field.id.to_s => 'happy' } } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload @@ -1417,7 +1417,7 @@ describe UsersController do watched_tags: "#{tags[0].name},#{tags[1].name}" } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload @@ -1460,7 +1460,7 @@ describe UsersController do it "should update the user field" do put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' } } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.user_fields[user_field.id.to_s]).to eq 'happy' end @@ -1480,13 +1480,13 @@ describe UsersController do it "should retain existing user fields" do put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy', optional_field.id.to_s => 'feet' } } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.user_fields[user_field.id.to_s]).to eq('happy') expect(user.user_fields[optional_field.id.to_s]).to eq('feet') put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'sad' } } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload @@ -1501,7 +1501,7 @@ describe UsersController do it "does not update the user field" do put "/u/#{user.username}.json", params: { name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' } } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.user_fields[user_field.id.to_s]).to be_blank end end @@ -1748,7 +1748,7 @@ describe UsersController do it 'can successfully pick the system avatar' do put "/u/#{user.username}/preferences/avatar/pick.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.reload.uploaded_avatar_id).to eq(nil) end @@ -1757,7 +1757,7 @@ describe UsersController do upload_id: upload.id, type: "gravatar" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.reload.uploaded_avatar_id).to eq(upload.id) expect(user.user_avatar.reload.gravatar_upload_id).to eq(upload.id) end @@ -1767,7 +1767,7 @@ describe UsersController do upload_id: upload.id, type: "custom" } - expect(response).to be_successful + expect(response.status).to eq(200) expect(user.reload.uploaded_avatar_id).to eq(upload.id) expect(user.user_avatar.reload.custom_upload_id).to eq(upload.id) end @@ -1807,7 +1807,7 @@ describe UsersController do delete "/u/#{user.username}/preferences/user_image.json", params: { type: 'profile_background' } expect(user.reload.user_profile.profile_background).to eq("") - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -1843,7 +1843,7 @@ describe UsersController do it "deletes your account when you're allowed to" do UserDestroyer.any_instance.expects(:destroy).with(user, anything).returns(user) delete "/u/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end end end @@ -1894,7 +1894,7 @@ describe UsersController do get "/u/#{Fabricate(:user).username}/emails.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["email"]).to be_present expect(json["associated_accounts"]).to be_present @@ -1906,7 +1906,7 @@ describe UsersController do get "/u/#{inactive_user.username}/emails.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["email"]).to be_present expect(json["associated_accounts"]).to be_present @@ -2034,7 +2034,7 @@ describe UsersController do create_post(user: user) get "/u/#{user.username_lower}/summary.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["user_summary"]["topic_count"]).to eq(1) @@ -2058,7 +2058,7 @@ describe UsersController do ac = AdminConfirmation.new(user, Fabricate(:admin)) ac.create_confirmation get "/u/confirm-admin/#{ac.token}.josn" - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.admin?).to eq(false) @@ -2071,7 +2071,7 @@ describe UsersController do ac = AdminConfirmation.new(user, admin) ac.create_confirmation get "/u/confirm-admin/#{ac.token}.josn", params: { token: ac.token } - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.admin?).to eq(false) @@ -2096,7 +2096,7 @@ describe UsersController do ac = AdminConfirmation.new(user, Fabricate(:admin)) ac.create_confirmation post "/u/confirm-admin/#{ac.token}.josn" - expect(response).to be_successful + expect(response.status).to eq(200) user.reload expect(user.admin?).to eq(true) @@ -2285,7 +2285,7 @@ describe UsersController do it "returns success" do get "/u/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)["user"]["username"]).to eq(user.username) end @@ -2320,7 +2320,7 @@ describe UsersController do it 'returns success' do get "/u/#{user.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) json = JSON.parse(response.body) expect(json["user"]["has_title_badges"]).to eq(false) @@ -2341,7 +2341,7 @@ describe UsersController do SiteSetting.show_inactive_accounts = true inactive = Fabricate(:user, active: false) get "/u/#{inactive.username}.json" - expect(response).to be_successful + expect(response.status).to eq(200) end it "raises an error on invalid access" do @@ -2374,7 +2374,7 @@ describe UsersController do it "returns fetch for a matching external_id" do get "/u/by-external/997.json" - expect(response).to be_successful + expect(response.status).to eq(200) expect(JSON.parse(response.body)["user"]["username"]).to eq(user.username) end @@ -2414,7 +2414,7 @@ describe UsersController do it "should be able to view a user" do get "/u/#{user.username}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(user.username) end @@ -2426,7 +2426,7 @@ describe UsersController do it "should be able to view a user" do get "/u/#{user.username}" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include(user.username) end end @@ -2435,7 +2435,7 @@ describe UsersController do describe '#badges' do it "renders fine by default" do get "/u/#{user.username}/badges" - expect(response).to be_successful + expect(response.status).to eq(200) end it "fails if badges are disabled" do @@ -2449,7 +2449,7 @@ describe UsersController do it "returns a message when no session is present" do get "/u/account-created" - expect(response).to be_successful + expect(response.status).to eq(200) body = response.body @@ -2470,7 +2470,7 @@ describe UsersController do user = create_user get "/u/account-created" - expect(response).to be_successful + expect(response.status).to eq(200) expect(response.body).to include( "{\"message\":\"#{I18n.t("login.activate_email", email: user.email).gsub!(" signature } - expect(response).to be_successful + expect(response.status).to eq(200) email_log.reload expect(email_log.bounced).to eq(true) @@ -51,7 +51,7 @@ describe WebhooksController do ] } - expect(response).to be_successful + expect(response.status).to eq(200) email_log.reload expect(email_log.bounced).to eq(true) @@ -71,7 +71,7 @@ describe WebhooksController do "CustomID" => message_id } - expect(response).to be_successful + expect(response.status).to eq(200) email_log.reload expect(email_log.bounced).to eq(true) @@ -96,7 +96,7 @@ describe WebhooksController do }] } - expect(response).to be_successful + expect(response.status).to eq(200) email_log.reload expect(email_log.bounced).to eq(true) @@ -123,7 +123,7 @@ describe WebhooksController do }] } - expect(response).to be_successful + expect(response.status).to eq(200) email_log.reload expect(email_log.bounced).to eq(true) diff --git a/spec/support/integration_helpers.rb b/spec/support/integration_helpers.rb index 7269dcd530..f2d72771c6 100644 --- a/spec/support/integration_helpers.rb +++ b/spec/support/integration_helpers.rb @@ -2,7 +2,7 @@ module IntegrationHelpers def create_user get "/u/hp.json" - expect(response).to be_successful + expect(response.status).to eq(200) body = JSON.parse(response.body) honeypot = body["value"] @@ -17,7 +17,7 @@ module IntegrationHelpers challenge: challenge.reverse } - expect(response).to be_successful + expect(response.status).to eq(200) body = JSON.parse(response.body) User.find(body["user_id"]) From 322b66bceea0d05da78451fe1076da66852d40a0 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 18:15:12 +1000 Subject: [PATCH 0104/1439] attempt to shuffle order of operation for test --- lib/tasks/docker.rake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/tasks/docker.rake b/lib/tasks/docker.rake index e9c3525992..ba8537c07b 100644 --- a/lib/tasks/docker.rake +++ b/lib/tasks/docker.rake @@ -70,11 +70,13 @@ task 'docker:test' do ENV["RAILS_ENV"] = "test" + @good &&= run_or_fail("bundle exec rake db:create") + if ENV["INSTALL_OFFICIAL_PLUGINS"] @good &&= run_or_fail("bundle exec rake plugin:install_all_official") end - @good &&= run_or_fail("bundle exec rake db:create db:migrate") + @good &&= run_or_fail("bundle exec rake db:migrate") unless ENV["JS_ONLY"] From ab089cd68b1cf9cda2792b24e19e3299ae99423e Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 7 Jun 2018 10:44:21 +0200 Subject: [PATCH 0105/1439] FIX: makes format number round the value before using parseInt --- .../admin/components/dashboard-mini-chart.js.es6 | 4 ++-- .../admin/templates/components/admin-report-counts.hbs | 8 ++++---- .../admin/templates/components/dashboard-mini-chart.hbs | 4 ++-- .../javascripts/discourse/helpers/application.js.es6 | 6 +----- app/assets/javascripts/discourse/lib/formatter.js.es6 | 8 ++------ test/javascripts/lib/formatter-test.js.es6 | 4 ++-- 6 files changed, 13 insertions(+), 21 deletions(-) diff --git a/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 b/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 index 5992e47953..e31ac3b5df 100644 --- a/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 +++ b/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 @@ -100,7 +100,7 @@ export default Ember.Component.extend(AsyncReport, { labels, datasets: reportsForPeriod.map(report => { return { - data: Ember.makeArray(report.data).map(d => number(d.y, { ceil: true })), + data: Ember.makeArray(report.data).map(d => number(d.y)), backgroundColor: "rgba(200,220,240,0.3)", borderColor: report.color }; @@ -147,7 +147,7 @@ export default Ember.Component.extend(AsyncReport, { scales: { yAxes: [{ display: true, - ticks: { callback: (label) => number(label, { ceil: true }) } + ticks: { callback: (label) => number(label) } }], xAxes: [{ display: true, diff --git a/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs b/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs index d7f37040f6..4b4a406c59 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report-counts.hbs @@ -5,18 +5,18 @@ {{report.title}} -{{number report.todayCount ceil=true}} +{{number report.todayCount}} - {{number report.yesterdayCount ceil=true}} {{d-icon report.yesterdayTrendIcon}} + {{number report.yesterdayCount}} {{d-icon report.yesterdayTrendIcon}} - {{number report.lastSevenDaysCount ceil=true}} {{d-icon report.sevenDaysTrendIcon}} + {{number report.lastSevenDaysCount}} {{d-icon report.sevenDaysTrendIcon}} - {{number report.lastThirtyDaysCount ceil=true}} {{d-icon report.thirtyDaysTrendIcon}} + {{number report.lastThirtyDaysCount}} {{d-icon report.thirtyDaysTrendIcon}} {{#if allTime}} diff --git a/app/assets/javascripts/admin/templates/components/dashboard-mini-chart.hbs b/app/assets/javascripts/admin/templates/components/dashboard-mini-chart.hbs index 62e956cd8c..328e0829ff 100644 --- a/app/assets/javascripts/admin/templates/components/dashboard-mini-chart.hbs +++ b/app/assets/javascripts/admin/templates/components/dashboard-mini-chart.hbs @@ -14,9 +14,9 @@
{{#if report.average}} - {{number report.currentAverage ceil=true}}{{#if report.percent}}%{{/if}} + {{number report.currentAverage}}{{#if report.percent}}%{{/if}} {{else}} - {{number report.currentTotal ceil=true noTitle="true"}}{{#if report.percent}}%{{/if}} + {{number report.currentTotal noTitle="true"}}{{#if report.percent}}%{{/if}} {{/if}} diff --git a/app/assets/javascripts/discourse/helpers/application.js.es6 b/app/assets/javascripts/discourse/helpers/application.js.es6 index d43c1a7791..997f2f07b2 100644 --- a/app/assets/javascripts/discourse/helpers/application.js.es6 +++ b/app/assets/javascripts/discourse/helpers/application.js.es6 @@ -8,11 +8,7 @@ registerUnbound('raw-date', dt => longDate(new Date(dt))); registerUnbound('age-with-tooltip', dt => new safe(autoUpdatingRelativeAge(new Date(dt), {title: true}))); registerUnbound('number', (orig, params) => { - if (params.ceil) { - orig = Math.ceil(orig); - } - - orig = parseInt(orig, 10); + orig = parseInt(Math.round(orig), 10); if (isNaN(orig)) { orig = 0; } let title = I18n.toNumber(orig, { precision: 0 }); diff --git a/app/assets/javascripts/discourse/lib/formatter.js.es6 b/app/assets/javascripts/discourse/lib/formatter.js.es6 index 3eed7e3d97..2c213e8623 100644 --- a/app/assets/javascripts/discourse/lib/formatter.js.es6 +++ b/app/assets/javascripts/discourse/lib/formatter.js.es6 @@ -301,14 +301,10 @@ export function relativeAge(date, options) { return "UNKNOWN FORMAT"; } -export function number(val, options = {}) { +export function number(val) { let formattedNumber; - if (options.ceil) { - val = Math.ceil(val); - } - - val = parseInt(val, 10); + val = parseInt(Math.round(val), 10); if (isNaN(val)) val = 0; if (val > 999999) { diff --git a/test/javascripts/lib/formatter-test.js.es6 b/test/javascripts/lib/formatter-test.js.es6 index e7299cb464..d00bade3dc 100644 --- a/test/javascripts/lib/formatter-test.js.es6 +++ b/test/javascripts/lib/formatter-test.js.es6 @@ -213,8 +213,8 @@ QUnit.test("number", assert => { assert.equal(number(2499999), "2.5M", "it abbreviates millions"); assert.equal(number(1000000), "1.0M", "it abbreviates a million"); assert.equal(number(999999), "999k", "it abbreviates hundreds of thousands"); - assert.equal(number(18.2), "18", "it returns a float number converted to an integer as a string"); - assert.equal(number(18.6, { ceil: true }), "19", "it ceils the value if requested"); + assert.equal(number(18.2), "18", "it returns a float number rounded to an integer as a string"); + assert.equal(number(18.6), "19", "it returns a float number rounded to an integer as a string"); }); QUnit.test("durationTiny", assert => { From 1071aa21ab310a51ebb2654840caafb59b95c36c Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 7 Jun 2018 10:59:17 +0200 Subject: [PATCH 0106/1439] FIX: slightly safer rounding --- app/assets/javascripts/discourse/helpers/application.js.es6 | 2 +- app/assets/javascripts/discourse/lib/formatter.js.es6 | 2 +- test/javascripts/lib/formatter-test.js.es6 | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/helpers/application.js.es6 b/app/assets/javascripts/discourse/helpers/application.js.es6 index 997f2f07b2..96e3f5f4b6 100644 --- a/app/assets/javascripts/discourse/helpers/application.js.es6 +++ b/app/assets/javascripts/discourse/helpers/application.js.es6 @@ -8,7 +8,7 @@ registerUnbound('raw-date', dt => longDate(new Date(dt))); registerUnbound('age-with-tooltip', dt => new safe(autoUpdatingRelativeAge(new Date(dt), {title: true}))); registerUnbound('number', (orig, params) => { - orig = parseInt(Math.round(orig), 10); + orig = Math.round(parseFloat(orig)); if (isNaN(orig)) { orig = 0; } let title = I18n.toNumber(orig, { precision: 0 }); diff --git a/app/assets/javascripts/discourse/lib/formatter.js.es6 b/app/assets/javascripts/discourse/lib/formatter.js.es6 index 2c213e8623..50f6904234 100644 --- a/app/assets/javascripts/discourse/lib/formatter.js.es6 +++ b/app/assets/javascripts/discourse/lib/formatter.js.es6 @@ -304,7 +304,7 @@ export function relativeAge(date, options) { export function number(val) { let formattedNumber; - val = parseInt(Math.round(val), 10); + val = Math.round(parseFloat(val)); if (isNaN(val)) val = 0; if (val > 999999) { diff --git a/test/javascripts/lib/formatter-test.js.es6 b/test/javascripts/lib/formatter-test.js.es6 index d00bade3dc..984f689a63 100644 --- a/test/javascripts/lib/formatter-test.js.es6 +++ b/test/javascripts/lib/formatter-test.js.es6 @@ -211,10 +211,13 @@ QUnit.test("number", assert => { assert.equal(number(NaN), "0", "it returns 0 for NaN"); assert.equal(number(3333), "3.3k", "it abbreviates thousands"); assert.equal(number(2499999), "2.5M", "it abbreviates millions"); + assert.equal(number("2499999.5"), "2.5M", "it abbreviates millions"); assert.equal(number(1000000), "1.0M", "it abbreviates a million"); assert.equal(number(999999), "999k", "it abbreviates hundreds of thousands"); assert.equal(number(18.2), "18", "it returns a float number rounded to an integer as a string"); assert.equal(number(18.6), "19", "it returns a float number rounded to an integer as a string"); + assert.equal(number("12.3"), "12", "it returns a string float rounded to an integer as a string"); + assert.equal(number("12.6"), "13", "it returns a string float rounded to an integer as a string"); }); QUnit.test("durationTiny", assert => { From 74ced977bed2d951aabd43a3ae154caefce3bfce Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 7 Jun 2018 11:18:17 +0200 Subject: [PATCH 0107/1439] FIX: incorrect backup and update times on dashboard --- .../javascripts/admin/controllers/admin-dashboard-next.js.es6 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 index 2f24cf9edd..433558917b 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-next.js.es6 @@ -114,12 +114,12 @@ export default Ember.Controller.extend({ return moment().locale("en").utc().subtract(1, "day").endOf("day"); }, - @computed("updated_at") + @computed("model.attributes.updated_at") updatedTimestamp(updatedAt) { return moment(updatedAt).format("LLL"); }, - @computed("last_backup_taken_at") + @computed("model.attributes.last_backup_taken_at") backupTimestamp(lastBackupTakenAt) { return moment(lastBackupTakenAt).format("LLL"); }, From d3b8ee761c71a5f875b6399db471584ac233d2b9 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 19:47:53 +1000 Subject: [PATCH 0108/1439] revert to rails 5.1 for now --- Gemfile | 14 +++++++------- Gemfile.lock | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index 60b197bdcd..daf906ca0d 100644 --- a/Gemfile +++ b/Gemfile @@ -13,13 +13,13 @@ if rails_master? gem 'rails', git: 'https://github.com/rails/rails.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else - gem 'actionmailer', '~> 5.2' - gem 'actionpack', '~> 5.2' - gem 'actionview', '~> 5.2' - gem 'activemodel', '~> 5.2' - gem 'activerecord', '~> 5.2' - gem 'activesupport', '~> 5.2' - gem 'railties', '~> 5.2' + gem 'actionmailer', '~> 5.1' + gem 'actionpack', '~> 5.1' + gem 'actionview', '~> 5.1' + gem 'activemodel', '~> 5.1' + gem 'activerecord', '~> 5.1' + gem 'activesupport', '~> 5.1' + gem 'railties', '~> 5.1' gem 'sprockets-rails' gem 'seed-fu' end diff --git a/Gemfile.lock b/Gemfile.lock index 3d018a3270..966a6612f8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -405,13 +405,13 @@ PLATFORMS ruby DEPENDENCIES - actionmailer (~> 5.2) - actionpack (~> 5.2) - actionview (~> 5.2) + actionmailer (~> 5.1) + actionpack (~> 5.1) + actionview (~> 5.1) active_model_serializers (~> 0.8.3) - activemodel (~> 5.2) - activerecord (~> 5.2) - activesupport (~> 5.2) + activemodel (~> 5.1) + activerecord (~> 5.1) + activesupport (~> 5.1) annotate aws-sdk-s3 barber @@ -479,7 +479,7 @@ DEPENDENCIES rack-mini-profiler rack-protection rails_multisite - railties (~> 5.2) + railties (~> 5.1) rake rb-fsevent rb-inotify (~> 0.9) From 3291f2c0ebd2922e2da0d7c8e27b2875e18cd836 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 19:56:07 +1000 Subject: [PATCH 0109/1439] move plugin fixture to the front of the queue --- plugins/discourse-narrative-bot/plugin.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/discourse-narrative-bot/plugin.rb b/plugins/discourse-narrative-bot/plugin.rb index aaecead511..f3ad97fbd9 100644 --- a/plugins/discourse-narrative-bot/plugin.rb +++ b/plugins/discourse-narrative-bot/plugin.rb @@ -22,7 +22,7 @@ end require_relative 'lib/discourse_narrative_bot/welcome_post_type_site_setting.rb' after_initialize do - SeedFu.fixture_paths << Rails.root.join("plugins", "discourse-narrative-bot", "db", "fixtures").to_s + SeedFu.fixture_paths.unshift Rails.root.join("plugins", "discourse-narrative-bot", "db", "fixtures").to_s Mime::Type.register "image/svg+xml", :svg From 8b88b713090a5babac47451f61f58af31288b659 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 20:10:52 +1000 Subject: [PATCH 0110/1439] Attempt very aggressively to clear cache --- db/fixtures/999_delayed.rb | 2 ++ plugins/discourse-narrative-bot/plugin.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/db/fixtures/999_delayed.rb b/db/fixtures/999_delayed.rb index 59b96b993d..8862fdd729 100644 --- a/db/fixtures/999_delayed.rb +++ b/db/fixtures/999_delayed.rb @@ -180,4 +180,6 @@ Migration::TableDropper.delayed_drop( } ) +STDERR.puts "Resetting Active Record Cache" Discourse.reset_active_record_cache +ActiveRecord::Base.connection.close diff --git a/plugins/discourse-narrative-bot/plugin.rb b/plugins/discourse-narrative-bot/plugin.rb index f3ad97fbd9..aaecead511 100644 --- a/plugins/discourse-narrative-bot/plugin.rb +++ b/plugins/discourse-narrative-bot/plugin.rb @@ -22,7 +22,7 @@ end require_relative 'lib/discourse_narrative_bot/welcome_post_type_site_setting.rb' after_initialize do - SeedFu.fixture_paths.unshift Rails.root.join("plugins", "discourse-narrative-bot", "db", "fixtures").to_s + SeedFu.fixture_paths << Rails.root.join("plugins", "discourse-narrative-bot", "db", "fixtures").to_s Mime::Type.register "image/svg+xml", :svg From e031b06afa0666663c92afd1764137499670c0ec Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 20:20:15 +1000 Subject: [PATCH 0111/1439] attempt to reset column info on user table explicitly --- db/fixtures/999_delayed.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/db/fixtures/999_delayed.rb b/db/fixtures/999_delayed.rb index 8862fdd729..6739571eee 100644 --- a/db/fixtures/999_delayed.rb +++ b/db/fixtures/999_delayed.rb @@ -183,3 +183,5 @@ Migration::TableDropper.delayed_drop( STDERR.puts "Resetting Active Record Cache" Discourse.reset_active_record_cache ActiveRecord::Base.connection.close +# for some reason connection tables may be off? +User.reset_column_information From 799081e846966340e6609f7b6cb1d11cf64ceb86 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 20:30:19 +1000 Subject: [PATCH 0112/1439] attempt all column dropping upfront prior to loading cache --- db/fixtures/{999_delayed.rb => 000_delayed_drops.rb} | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) rename db/fixtures/{999_delayed.rb => 000_delayed_drops.rb} (97%) diff --git a/db/fixtures/999_delayed.rb b/db/fixtures/000_delayed_drops.rb similarity index 97% rename from db/fixtures/999_delayed.rb rename to db/fixtures/000_delayed_drops.rb index 6739571eee..eda3f843db 100644 --- a/db/fixtures/999_delayed.rb +++ b/db/fixtures/000_delayed_drops.rb @@ -1,6 +1,7 @@ # Delayed migration steps require 'migration/table_dropper' +require 'migration/column_dropper' Migration::ColumnDropper.drop( table: 'user_profiles', @@ -182,6 +183,3 @@ Migration::TableDropper.delayed_drop( STDERR.puts "Resetting Active Record Cache" Discourse.reset_active_record_cache -ActiveRecord::Base.connection.close -# for some reason connection tables may be off? -User.reset_column_information From 1834417e2fcf8648908070cdfd62b6e0b2f996b3 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 20:38:22 +1000 Subject: [PATCH 0113/1439] downgrade rails properly --- Gemfile | 14 +++---- Gemfile.lock | 62 +++++++++++++++---------------- lib/freedom_patches/fast_pluck.rb | 4 ++ 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/Gemfile b/Gemfile index daf906ca0d..dafa11dcba 100644 --- a/Gemfile +++ b/Gemfile @@ -13,13 +13,13 @@ if rails_master? gem 'rails', git: 'https://github.com/rails/rails.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else - gem 'actionmailer', '~> 5.1' - gem 'actionpack', '~> 5.1' - gem 'actionview', '~> 5.1' - gem 'activemodel', '~> 5.1' - gem 'activerecord', '~> 5.1' - gem 'activesupport', '~> 5.1' - gem 'railties', '~> 5.1' + gem 'actionmailer', '5.1.5' + gem 'actionpack', '5.1.5' + gem 'actionview', '5.1.5' + gem 'activemodel', '5.1.5' + gem 'activerecord', '5.1.5' + gem 'activesupport', '5.1.5' + gem 'railties', '5.1.5' gem 'sprockets-rails' gem 'seed-fu' end diff --git a/Gemfile.lock b/Gemfile.lock index 966a6612f8..a614a233fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,39 +1,39 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (5.2.0) - actionpack (= 5.2.0) - actionview (= 5.2.0) - activejob (= 5.2.0) + actionmailer (5.1.5) + actionpack (= 5.1.5) + actionview (= 5.1.5) + activejob (= 5.1.5) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.0) - actionview (= 5.2.0) - activesupport (= 5.2.0) + actionpack (5.1.5) + actionview (= 5.1.5) + activesupport (= 5.1.5) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.0) - activesupport (= 5.2.0) + actionview (5.1.5) + activesupport (= 5.1.5) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) active_model_serializers (0.8.4) activemodel (>= 3.0) - activejob (5.2.0) - activesupport (= 5.2.0) + activejob (5.1.5) + activesupport (= 5.1.5) globalid (>= 0.3.6) - activemodel (5.2.0) - activesupport (= 5.2.0) - activerecord (5.2.0) - activemodel (= 5.2.0) - activesupport (= 5.2.0) - arel (>= 9.0) - activesupport (5.2.0) + activemodel (5.1.5) + activesupport (= 5.1.5) + activerecord (5.1.5) + activemodel (= 5.1.5) + activesupport (= 5.1.5) + arel (~> 8.0) + activesupport (5.1.5) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) + i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.5.2) @@ -41,7 +41,7 @@ GEM annotate (2.7.4) activerecord (>= 3.2, < 6.0) rake (>= 10.4, < 13.0) - arel (9.0.0) + arel (8.0.0) ast (2.4.0) aws-eventstream (1.0.0) aws-partitions (1.91.0) @@ -135,7 +135,7 @@ GEM hkdf (0.3.0) htmlentities (4.3.4) http_accept_language (2.0.5) - i18n (1.0.1) + i18n (0.9.5) concurrent-ruby (~> 1.0) image_size (1.5.0) in_threads (1.5.0) @@ -272,9 +272,9 @@ GEM rails_multisite (2.0.4) activerecord (> 4.2, < 6) railties (> 4.2, < 6) - railties (5.2.0) - actionpack (= 5.2.0) - activesupport (= 5.2.0) + railties (5.1.5) + actionpack (= 5.1.5) + activesupport (= 5.1.5) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) @@ -405,13 +405,13 @@ PLATFORMS ruby DEPENDENCIES - actionmailer (~> 5.1) - actionpack (~> 5.1) - actionview (~> 5.1) + actionmailer (= 5.1.5) + actionpack (= 5.1.5) + actionview (= 5.1.5) active_model_serializers (~> 0.8.3) - activemodel (~> 5.1) - activerecord (~> 5.1) - activesupport (~> 5.1) + activemodel (= 5.1.5) + activerecord (= 5.1.5) + activesupport (= 5.1.5) annotate aws-sdk-s3 barber @@ -479,7 +479,7 @@ DEPENDENCIES rack-mini-profiler rack-protection rails_multisite - railties (~> 5.1) + railties (= 5.1.5) rake rb-fsevent rb-inotify (~> 0.9) diff --git a/lib/freedom_patches/fast_pluck.rb b/lib/freedom_patches/fast_pluck.rb index 9999e5a9db..3b31b6df9a 100644 --- a/lib/freedom_patches/fast_pluck.rb +++ b/lib/freedom_patches/fast_pluck.rb @@ -1,6 +1,10 @@ # Speeds up #pluck so its about 2.2x faster, importantly makes pluck avoid creation of a slew # of AR objects # +# + +# until we upgrade rails +return require_dependency 'sql_builder' From 945cb90e7e2892aa6339da3833f6bdc61d195874 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 7 Jun 2018 20:55:42 +1000 Subject: [PATCH 0114/1439] update specs --- spec/components/migration/safe_migrate_spec.rb | 5 +++++ spec/controllers/admin/themes_controller_spec.rb | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/spec/components/migration/safe_migrate_spec.rb b/spec/components/migration/safe_migrate_spec.rb index 15659e4b90..c8cec0f0eb 100644 --- a/spec/components/migration/safe_migrate_spec.rb +++ b/spec/components/migration/safe_migrate_spec.rb @@ -27,6 +27,7 @@ describe Migration::SafeMigrate do end it "bans all table removal" do + skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/drop_table" @@ -44,6 +45,7 @@ describe Migration::SafeMigrate do end it "bans all table renames" do + skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/rename_table" @@ -61,6 +63,7 @@ describe Migration::SafeMigrate do end it "bans all column removal" do + skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/remove_column" @@ -78,6 +81,7 @@ describe Migration::SafeMigrate do end it "bans all column renames" do + skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/rename_column" @@ -95,6 +99,7 @@ describe Migration::SafeMigrate do end it "supports being disabled" do + skip("waiting on rails 5.2") Migration::SafeMigrate.enable! Migration::SafeMigrate.disable! diff --git a/spec/controllers/admin/themes_controller_spec.rb b/spec/controllers/admin/themes_controller_spec.rb index 30625c7d57..5644319663 100644 --- a/spec/controllers/admin/themes_controller_spec.rb +++ b/spec/controllers/admin/themes_controller_spec.rb @@ -66,7 +66,7 @@ describe Admin::ThemesController do upload.destroy post :import, params: { theme: uploaded_json }, format: :json - expect(response.status).to eq(200) + expect(response.status).to eq(201) temp.unlink theme = Theme.last @@ -79,7 +79,7 @@ describe Admin::ThemesController do it 'imports a theme' do post :import, params: { theme: theme_file }, format: :json - expect(response.status).to eq(200) + expect(response.status).to eq(201) json = ::JSON.parse(response.body) @@ -133,7 +133,7 @@ describe Admin::ThemesController do } }, format: :json - expect(response.status).to eq(200) + expect(response.status).to eq(201) json = ::JSON.parse(response.body) From d556975cdc4562d8a69dbdbb3e844b341b65de27 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 7 Jun 2018 14:56:49 +0200 Subject: [PATCH 0115/1439] FIX: do not use number helper for charts Y value --- .../javascripts/admin/components/dashboard-mini-chart.js.es6 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 b/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 index e31ac3b5df..36a95dc15c 100644 --- a/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 +++ b/app/assets/javascripts/admin/components/dashboard-mini-chart.js.es6 @@ -100,7 +100,7 @@ export default Ember.Component.extend(AsyncReport, { labels, datasets: reportsForPeriod.map(report => { return { - data: Ember.makeArray(report.data).map(d => number(d.y)), + data: Ember.makeArray(report.data).map(d => Math.round(parseFloat(d.y))), backgroundColor: "rgba(200,220,240,0.3)", borderColor: report.color }; @@ -116,6 +116,7 @@ export default Ember.Component.extend(AsyncReport, { if (this._chart) { this._chart.destroy(); } + this._chart = new window.Chart(context, this._buildChartConfig(data)); }); }); From f9ab3848ed8c2c07c6e699d43b7b9ae22134cd5b Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 7 Jun 2018 09:44:35 +0530 Subject: [PATCH 0116/1439] FEATURE: support disabling emails for non-staff users --- .../discourse/components/global-notice.js.es6 | 2 +- app/controllers/admin/backups_controller.rb | 2 +- config/locales/server.en.yml | 2 +- config/site_settings.yml | 7 ++- .../20180607095414_migrate_disable_emails.rb | 11 +++++ lib/email/sender.rb | 7 ++- script/bulk_import/vanilla.rb | 2 +- script/import_scripts/base.rb | 2 +- script/import_scripts/ipboard.rb | 2 +- script/import_scripts/mbox.rb | 2 +- script/import_scripts/modx.rb | 2 +- script/import_scripts/mybb.rb | 2 +- script/import_scripts/mylittleforum.rb | 2 +- spec/components/email/sender_spec.rb | 45 ++++++++++++++----- .../admin/backups_controller_spec.rb | 4 +- 15 files changed, 69 insertions(+), 25 deletions(-) create mode 100644 db/migrate/20180607095414_migrate_disable_emails.rb diff --git a/app/assets/javascripts/discourse/components/global-notice.js.es6 b/app/assets/javascripts/discourse/components/global-notice.js.es6 index 9ea7f4104b..c8479c462d 100644 --- a/app/assets/javascripts/discourse/components/global-notice.js.es6 +++ b/app/assets/javascripts/discourse/components/global-notice.js.es6 @@ -22,7 +22,7 @@ export default Ember.Component.extend(bufferedRender({ notices.push([I18n.t("read_only_mode.enabled"), 'alert-read-only']); } - if (this.siteSettings.disable_emails) { + if (this.siteSettings.disable_emails === "yes" || this.siteSettings.disable_emails === "non-staff") { notices.push([I18n.t("emails_are_disabled"), 'alert-emails-disabled']); } diff --git a/app/controllers/admin/backups_controller.rb b/app/controllers/admin/backups_controller.rb index 9fd0f9c9bb..ef8950fd5b 100644 --- a/app/controllers/admin/backups_controller.rb +++ b/app/controllers/admin/backups_controller.rb @@ -99,7 +99,7 @@ class Admin::BackupsController < Admin::AdminController client_id: params.fetch(:client_id), publish_to_message_bus: true, } - SiteSetting.set_and_log(:disable_emails, true, current_user) + SiteSetting.set_and_log(:disable_emails, 'yes', current_user) BackupRestore.restore!(current_user.id, opts) rescue BackupRestore::OperationRunningError render json: failed_json.merge(message: I18n.t("backup.operation_already_running")) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index fd9451fa16..62138552cd 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1486,7 +1486,7 @@ en: alternative_reply_by_email_addresses: "List of alternative templates for reply by email incoming email addresses. Example: %{reply_key}@reply.example.com|replies+%{reply_key}@example.com" incoming_email_prefer_html: "Use HTML instead of text for incoming email." - disable_emails: "Prevent Discourse from sending any kind of emails" + disable_emails: "Prevent Discourse from sending any kind of emails. Select 'yes' to disable emails for all users. Select 'non-staff' to disable emails for non-staff users only." strip_images_from_short_emails: "Strip images from emails having size less than 2800 Bytes" short_email_length: "Short email length in Bytes" diff --git a/config/site_settings.yml b/config/site_settings.yml index 637fee437c..b972b8f80d 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -783,8 +783,13 @@ email: email_prefix: '' email_site_title: '' disable_emails: - default: false client: true + type: enum + default: 'no' + choices: + - 'no' + - 'yes' + - 'non-staff' strip_images_from_short_emails: true short_email_length: 2800 display_name_on_email_from: diff --git a/db/migrate/20180607095414_migrate_disable_emails.rb b/db/migrate/20180607095414_migrate_disable_emails.rb new file mode 100644 index 0000000000..d679ba7eb7 --- /dev/null +++ b/db/migrate/20180607095414_migrate_disable_emails.rb @@ -0,0 +1,11 @@ +class MigrateDisableEmails < ActiveRecord::Migration[5.1] + def up + execute "UPDATE site_settings SET data_type = 7 WHERE name = 'disable_emails';" + execute "UPDATE site_settings SET value = 'yes' WHERE value = 't' AND name = 'disable_emails';" + execute "UPDATE site_settings SET value = 'no' WHERE value = 'f' AND name = 'disable_emails';" + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/lib/email/sender.rb b/lib/email/sender.rb index 6ded4b88e9..f36b949692 100644 --- a/lib/email/sender.rb +++ b/lib/email/sender.rb @@ -22,7 +22,7 @@ module Email end def send - return if SiteSetting.disable_emails && @email_type.to_s != "admin_login" + return if SiteSetting.disable_emails == "yes" && @email_type.to_s != "admin_login" return if ActionMailer::Base::NullMail === @message return if ActionMailer::Base::NullMail === (@message.message rescue nil) @@ -30,6 +30,11 @@ module Email return skip(I18n.t('email_log.message_blank')) if @message.blank? return skip(I18n.t('email_log.message_to_blank')) if @message.to.blank? + if SiteSetting.disable_emails == "non-staff" + user = User.find_by_email(to_address) + return unless user && user.staff? + end + if @message.text_part return skip(I18n.t('email_log.text_part_body_blank')) if @message.text_part.body.to_s.blank? else diff --git a/script/bulk_import/vanilla.rb b/script/bulk_import/vanilla.rb index 771a3ef67b..584b995619 100644 --- a/script/bulk_import/vanilla.rb +++ b/script/bulk_import/vanilla.rb @@ -55,7 +55,7 @@ class BulkImport::Vanilla < BulkImport::Base # SiteSetting.port = 3000 # SiteSetting.automatic_backups_enabled = false - # SiteSetting.disable_emails = true + # SiteSetting.disable_emails = "non-staff" # etc. import_users diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index fc50cc13cd..92f33b9c9c 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -75,7 +75,7 @@ class ImportScripts::Base min_personal_message_post_length: 1, min_personal_message_title_length: 1, allow_duplicate_topic_titles: true, - disable_emails: true, + disable_emails: "non-staff", max_attachment_size_kb: 102400, max_image_size_kb: 102400, authorized_extensions: '*' diff --git a/script/import_scripts/ipboard.rb b/script/import_scripts/ipboard.rb index 18708898bf..f1b10b6a5b 100644 --- a/script/import_scripts/ipboard.rb +++ b/script/import_scripts/ipboard.rb @@ -70,7 +70,7 @@ class ImportScripts::IpboardSQL < ImportScripts::Base # Site settings # ################# # don't send any emails - SiteSetting.disable_emails = true + SiteSetting.disable_emails = "non-staff" # don't send digests (so you can enable email without users noticing) SiteSetting.disable_digest_emails = true # keep site and users private diff --git a/script/import_scripts/mbox.rb b/script/import_scripts/mbox.rb index d0b379aa12..2f125cbf33 100755 --- a/script/import_scripts/mbox.rb +++ b/script/import_scripts/mbox.rb @@ -27,7 +27,7 @@ class ImportScripts::Mbox < ImportScripts::Base BATCH_SIZE = 1000 # Site settings - SiteSetting.disable_emails = true + SiteSetting.disable_emails = "non-staff" # Comment out if each file contains a single message # Use formail to split yourself: http://linuxcommand.org/man_pages/formail1.html diff --git a/script/import_scripts/modx.rb b/script/import_scripts/modx.rb index 191135f6bf..682954bce0 100644 --- a/script/import_scripts/modx.rb +++ b/script/import_scripts/modx.rb @@ -24,7 +24,7 @@ class ImportScripts::Modx < ImportScripts::Base def initialize super - SiteSetting.disable_emails = true + SiteSetting.disable_emails = "non-staff" @old_username_to_new_usernames = {} diff --git a/script/import_scripts/mybb.rb b/script/import_scripts/mybb.rb index f9201ecacf..cc3ed9e662 100644 --- a/script/import_scripts/mybb.rb +++ b/script/import_scripts/mybb.rb @@ -37,7 +37,7 @@ class ImportScripts::MyBB < ImportScripts::Base end def execute - SiteSetting.disable_emails = true + SiteSetting.disable_emails = "non-staff" import_users import_categories import_posts diff --git a/script/import_scripts/mylittleforum.rb b/script/import_scripts/mylittleforum.rb index f0ec152472..4b10494eb4 100644 --- a/script/import_scripts/mylittleforum.rb +++ b/script/import_scripts/mylittleforum.rb @@ -33,7 +33,7 @@ class ImportScripts::MylittleforumSQL < ImportScripts::Base QUIET = true # Site settings - SiteSetting.disable_emails = true + SiteSetting.disable_emails = "non-staff" if FORCE_HOSTNAME SiteSetting.force_hostname = FORCE_HOSTNAME end diff --git a/spec/components/email/sender_spec.rb b/spec/components/email/sender_spec.rb index 7c73e7e2fb..65838ab1d0 100644 --- a/spec/components/email/sender_spec.rb +++ b/spec/components/email/sender_spec.rb @@ -3,18 +3,41 @@ require 'email/sender' describe Email::Sender do - it "doesn't deliver mail when mails are disabled" do - SiteSetting.disable_emails = true - Mail::Message.any_instance.expects(:deliver_now).never - message = Mail::Message.new(to: "hello@world.com" , body: "hello") - expect(Email::Sender.new(message, :hello).send).to eq(nil) - end + context "disable_emails is enabled" do + let(:user) { Fabricate(:user) } + let(:moderator) { Fabricate(:moderator) } - it "delivers mail when mails are disabled but the email_type is admin_login" do - SiteSetting.disable_emails = true - Mail::Message.any_instance.expects(:deliver_now).once - message = Mail::Message.new(to: "hello@world.com" , body: "hello") - Email::Sender.new(message, :admin_login).send + context "disable_emails is enabled for everyone" do + before { SiteSetting.disable_emails = "yes" } + + it "doesn't deliver mail when mails are disabled" do + Mail::Message.any_instance.expects(:deliver_now).never + message = Mail::Message.new(to: moderator.email , body: "hello") + expect(Email::Sender.new(message, :hello).send).to eq(nil) + end + + it "delivers mail when mails are disabled but the email_type is admin_login" do + Mail::Message.any_instance.expects(:deliver_now).once + message = Mail::Message.new(to: moderator.email , body: "hello") + Email::Sender.new(message, :admin_login).send + end + end + + context "disable_emails is enabled for non-staff users" do + before { SiteSetting.disable_emails = "non-staff" } + + it "doesn't deliver mail to normal user" do + Mail::Message.any_instance.expects(:deliver_now).never + message = Mail::Message.new(to: user.email, body: "hello") + expect(Email::Sender.new(message, :hello).send).to eq(nil) + end + + it "delivers mail to staff user" do + Mail::Message.any_instance.expects(:deliver_now).once + message = Mail::Message.new(to: moderator.email, body: "hello") + Email::Sender.new(message, :hello).send + end + end end it "doesn't deliver mail when the message is of type NullMail" do diff --git a/spec/controllers/admin/backups_controller_spec.rb b/spec/controllers/admin/backups_controller_spec.rb index f3ebecd147..6531a01712 100644 --- a/spec/controllers/admin/backups_controller_spec.rb +++ b/spec/controllers/admin/backups_controller_spec.rb @@ -169,12 +169,12 @@ describe Admin::BackupsController do describe ".restore" do it "starts a restore" do - expect(SiteSetting.disable_emails).to eq(false) + expect(SiteSetting.disable_emails).to eq("no") BackupRestore.expects(:restore!).with(@admin.id, filename: backup_filename, publish_to_message_bus: true, client_id: "foo") post :restore, params: { id: backup_filename, client_id: "foo" }, format: :json - expect(SiteSetting.disable_emails).to eq(true) + expect(SiteSetting.disable_emails).to eq("yes") expect(response.status).to eq(200) end From 620a1524cb02bbdad414d9724c4b86ca1696470d Mon Sep 17 00:00:00 2001 From: Vinoth Kannan Date: Thu, 7 Jun 2018 19:11:55 +0530 Subject: [PATCH 0117/1439] Use plus addressing email address for duplicates --- script/import_scripts/lithium.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/script/import_scripts/lithium.rb b/script/import_scripts/lithium.rb index 108fec921e..4c14c15c11 100644 --- a/script/import_scripts/lithium.rb +++ b/script/import_scripts/lithium.rb @@ -128,6 +128,8 @@ class ImportScripts::Lithium < ImportScripts::Base ORDER BY user_id SQL + duplicate_emails = mysql_query("SELECT email FROM users GROUP BY email HAVING COUNT(email) > 1").map { |e| [e["email"], 0] }.to_h + create_users(users, total: user_count, offset: offset) do |user| profile = profiles.select { |p| p["user_id"] == user["id"] } result = profile.select { |p| p["param"] == "profile.location" } @@ -135,11 +137,17 @@ class ImportScripts::Lithium < ImportScripts::Base username = user["login_canon"] username = USERNAME_MAPPINGS[username] if USERNAME_MAPPINGS[username].present? + email = user["email"].presence || fake_email + if duplicate_emails.key?(email) + duplicate_emails[email] += 1 + email.sub!("@", "+#{duplicate_emails[email]}@") + end + { id: user["id"], name: user["nlogin"], username: username, - email: user["email"].presence || fake_email, + email: email, location: location, custom_fields: user_custom_fields(user, profile), # website: user["homepage"].strip, From 8d57c712c3c06fc7287a7f8be2ff8bb1bf087396 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Jun 2018 10:51:16 -0400 Subject: [PATCH 0118/1439] Add DbHelper.find(needle) * searches the entire database for a text string (such as an old CDN name) --- lib/db_helper.rb | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib/db_helper.rb b/lib/db_helper.rb index 9d5e117696..0f06f66ff0 100644 --- a/lib/db_helper.rb +++ b/lib/db_helper.rb @@ -22,4 +22,21 @@ class DbHelper SiteSetting.refresh! end + def self.find(needle) + connection = ActiveRecord::Base.connection.raw_connection + text_columns = connection.async_exec(REMAP_SQL).to_a + args = ["%#{needle}%"] + found = {} + + text_columns.each do |rc| + table_name = rc["table_name"] + column_name = rc["column_name"] + result = connection.async_exec("SELECT #{column_name} FROM #{table_name} WHERE #{column_name} LIKE $1", args) rescue nil + if result&.ntuples > 0 + found["#{column_name}.#{table_name}"] = result.map {|r| r[column_name]} + end + end + found + end + end From 7e5f5a0b6bfc3a851a3feb45017287193e3393fd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Jun 2018 10:59:34 -0400 Subject: [PATCH 0119/1439] DbHelper.find: column.table? strike that, reverse it --- lib/db_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/db_helper.rb b/lib/db_helper.rb index 0f06f66ff0..2881628e04 100644 --- a/lib/db_helper.rb +++ b/lib/db_helper.rb @@ -33,7 +33,7 @@ class DbHelper column_name = rc["column_name"] result = connection.async_exec("SELECT #{column_name} FROM #{table_name} WHERE #{column_name} LIKE $1", args) rescue nil if result&.ntuples > 0 - found["#{column_name}.#{table_name}"] = result.map {|r| r[column_name]} + found["#{table_name}.#{column_name}"] = result.map {|r| r[column_name]} end end found From beef0d9dd210a1d14fe5f0da7021f19609a9eab9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Jun 2018 11:05:41 -0400 Subject: [PATCH 0120/1439] fix my lint errors --- lib/db_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/db_helper.rb b/lib/db_helper.rb index 2881628e04..0d85ed78cd 100644 --- a/lib/db_helper.rb +++ b/lib/db_helper.rb @@ -33,7 +33,7 @@ class DbHelper column_name = rc["column_name"] result = connection.async_exec("SELECT #{column_name} FROM #{table_name} WHERE #{column_name} LIKE $1", args) rescue nil if result&.ntuples > 0 - found["#{table_name}.#{column_name}"] = result.map {|r| r[column_name]} + found["#{table_name}.#{column_name}"] = result.map { |r| r[column_name] } end end found From c6bf8f6e24547e7777350dfa60b762ba073c6d21 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Thu, 7 Jun 2018 17:38:47 +0200 Subject: [PATCH 0121/1439] FIX: Uploading JPEG files didn't work anymore --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index a614a233fb..39e313a35b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -108,7 +108,7 @@ GEM erubi (1.7.1) excon (0.62.0) execjs (2.7.0) - exifr (1.3.4) + exifr (1.2.5) fabrication (2.20.1) fakeweb (1.3.0) faraday (0.12.2) From f10b663eb4825e0d35fa8fe0dcb4d47a9619515c Mon Sep 17 00:00:00 2001 From: Angus McLeod Date: Thu, 7 Jun 2018 15:44:20 +1000 Subject: [PATCH 0122/1439] BUGFIX: string in server_plugin_outlet needs to be mutable --- app/helpers/application_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f59ac7cfe6..6b543ba5b3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -329,7 +329,7 @@ module ApplicationHelper erbs = ApplicationHelper.all_connectors.select { |c| c =~ matcher } return "" if erbs.blank? - result = "" + result = +"" erbs.each { |erb| result << render(file: erb) } result.html_safe end From eba50f45913322bc91b5a2b3c0b04f4b287a0639 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 7 Jun 2018 13:16:03 -0400 Subject: [PATCH 0123/1439] DbHelper.remap: add options to anchor at left and right of the column value --- lib/db_helper.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/db_helper.rb b/lib/db_helper.rb index 0d85ed78cd..08979cb510 100644 --- a/lib/db_helper.rb +++ b/lib/db_helper.rb @@ -8,10 +8,10 @@ class DbHelper AND (data_type LIKE 'char%' OR data_type LIKE 'text%') ORDER BY table_name, column_name" - def self.remap(from, to) + def self.remap(from, to, anchor_left = false, anchor_right = false) connection = ActiveRecord::Base.connection.raw_connection remappable_columns = connection.async_exec(REMAP_SQL).to_a - args = [from, to, "%#{from}%"] + args = [from, to, "#{anchor_left ? '' : "%"}#{from}#{anchor_right ? '' : "%"}"] remappable_columns.each do |rc| table_name = rc["table_name"] @@ -22,10 +22,10 @@ class DbHelper SiteSetting.refresh! end - def self.find(needle) + def self.find(needle, anchor_left = false, anchor_right = false) connection = ActiveRecord::Base.connection.raw_connection text_columns = connection.async_exec(REMAP_SQL).to_a - args = ["%#{needle}%"] + args = ["#{anchor_left ? '' : "%"}#{needle}#{anchor_right ? '' : "%"}"] found = {} text_columns.each do |rc| From b4e0cddcc986436f1c81f948cafef931bdb062f1 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 7 Jun 2018 22:49:38 +0530 Subject: [PATCH 0124/1439] disable all outgoing emails in base importer --- script/import_scripts/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index 92f33b9c9c..78c04ea6b1 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -75,7 +75,7 @@ class ImportScripts::Base min_personal_message_post_length: 1, min_personal_message_title_length: 1, allow_duplicate_topic_titles: true, - disable_emails: "non-staff", + disable_emails: 'yes', max_attachment_size_kb: 102400, max_image_size_kb: 102400, authorized_extensions: '*' From 1ba8e8948d5c0eb4762fb4f9dcd15bed74afc852 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 7 Jun 2018 18:13:57 -0400 Subject: [PATCH 0125/1439] FIX: add support for string avatar_type values in PHPBB3 importer --- .../phpbb3/importers/avatar_importer.rb | 20 +++++++++---------- .../phpbb3/support/constants.rb | 4 ++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/script/import_scripts/phpbb3/importers/avatar_importer.rb b/script/import_scripts/phpbb3/importers/avatar_importer.rb index a9cd22d4c9..2178ed800c 100644 --- a/script/import_scripts/phpbb3/importers/avatar_importer.rb +++ b/script/import_scripts/phpbb3/importers/avatar_importer.rb @@ -47,16 +47,16 @@ module ImportScripts::PhpBB3 def get_avatar_path(avatar_type, filename) case avatar_type - when Constants::AVATAR_TYPE_UPLOADED then + when Constants::AVATAR_TYPE_UPLOADED, Constants::AVATAR_TYPE_STRING_UPLOADED then filename.gsub!(/_[0-9]+\./, '.') # we need 1337.jpg, not 1337_2983745.jpg get_uploaded_path(filename) - when Constants::AVATAR_TYPE_GALLERY then + when Constants::AVATAR_TYPE_GALLERY, Constants::AVATAR_TYPE_STRING_GALLERY then get_gallery_path(filename) - when Constants::AVATAR_TYPE_REMOTE then + when Constants::AVATAR_TYPE_REMOTE, Constants::AVATAR_TYPE_STRING_REMOTE then download_avatar(filename) - else - Rails.logger.error("Invalid avatar type #{avatar_type}. Skipping...") - nil + else + puts "Invalid avatar type #{avatar_type}. Skipping..." + nil end end @@ -97,13 +97,13 @@ module ImportScripts::PhpBB3 def is_allowed_avatar_type?(avatar_type) case avatar_type - when Constants::AVATAR_TYPE_UPLOADED then + when Constants::AVATAR_TYPE_UPLOADED, Constants::AVATAR_TYPE_STRING_UPLOADED then @settings.import_uploaded_avatars - when Constants::AVATAR_TYPE_REMOTE then + when Constants::AVATAR_TYPE_REMOTE, Constants::AVATAR_TYPE_STRING_REMOTE then @settings.import_remote_avatars - when Constants::AVATAR_TYPE_GALLERY then + when Constants::AVATAR_TYPE_GALLERY, Constants::AVATAR_TYPE_STRING_GALLERY then @settings.import_gallery_avatars - else + else false end end diff --git a/script/import_scripts/phpbb3/support/constants.rb b/script/import_scripts/phpbb3/support/constants.rb index af7482d5da..6e9612e678 100644 --- a/script/import_scripts/phpbb3/support/constants.rb +++ b/script/import_scripts/phpbb3/support/constants.rb @@ -19,6 +19,10 @@ module ImportScripts::PhpBB3 AVATAR_TYPE_REMOTE = 2 AVATAR_TYPE_GALLERY = 3 + AVATAR_TYPE_STRING_UPLOADED = 'avatar.driver.upload' + AVATAR_TYPE_STRING_REMOTE = 'avatar.driver.remote' + AVATAR_TYPE_STRING_GALLERY = 'avatar.driver.local' + FORUM_TYPE_CATEGORY = 0 FORUM_TYPE_POST = 1 FORUM_TYPE_LINK = 2 From f4fdcda5028635199ff34d24cca00f0d79145362 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 8 Jun 2018 09:33:50 +0800 Subject: [PATCH 0126/1439] Upgrade to Rails 5.2 take 2. --- Gemfile | 14 ++++++------ Gemfile.lock | 62 ++++++++++++++++++++++++++-------------------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Gemfile b/Gemfile index dafa11dcba..bec856bd2a 100644 --- a/Gemfile +++ b/Gemfile @@ -13,13 +13,13 @@ if rails_master? gem 'rails', git: 'https://github.com/rails/rails.git' gem 'seed-fu', git: 'https://github.com/SamSaffron/seed-fu.git', branch: 'discourse' else - gem 'actionmailer', '5.1.5' - gem 'actionpack', '5.1.5' - gem 'actionview', '5.1.5' - gem 'activemodel', '5.1.5' - gem 'activerecord', '5.1.5' - gem 'activesupport', '5.1.5' - gem 'railties', '5.1.5' + gem 'actionmailer', '5.2' + gem 'actionpack', '5.2' + gem 'actionview', '5.2' + gem 'activemodel', '5.2' + gem 'activerecord', '5.2' + gem 'activesupport', '5.2' + gem 'railties', '5.2' gem 'sprockets-rails' gem 'seed-fu' end diff --git a/Gemfile.lock b/Gemfile.lock index 39e313a35b..f4bea23c8f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,39 +1,39 @@ GEM remote: https://rubygems.org/ specs: - actionmailer (5.1.5) - actionpack (= 5.1.5) - actionview (= 5.1.5) - activejob (= 5.1.5) + actionmailer (5.2.0) + actionpack (= 5.2.0) + actionview (= 5.2.0) + activejob (= 5.2.0) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.1.5) - actionview (= 5.1.5) - activesupport (= 5.1.5) + actionpack (5.2.0) + actionview (= 5.2.0) + activesupport (= 5.2.0) rack (~> 2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.1.5) - activesupport (= 5.1.5) + actionview (5.2.0) + activesupport (= 5.2.0) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) active_model_serializers (0.8.4) activemodel (>= 3.0) - activejob (5.1.5) - activesupport (= 5.1.5) + activejob (5.2.0) + activesupport (= 5.2.0) globalid (>= 0.3.6) - activemodel (5.1.5) - activesupport (= 5.1.5) - activerecord (5.1.5) - activemodel (= 5.1.5) - activesupport (= 5.1.5) - arel (~> 8.0) - activesupport (5.1.5) + activemodel (5.2.0) + activesupport (= 5.2.0) + activerecord (5.2.0) + activemodel (= 5.2.0) + activesupport (= 5.2.0) + arel (>= 9.0) + activesupport (5.2.0) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) + i18n (>= 0.7, < 2) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.5.2) @@ -41,7 +41,7 @@ GEM annotate (2.7.4) activerecord (>= 3.2, < 6.0) rake (>= 10.4, < 13.0) - arel (8.0.0) + arel (9.0.0) ast (2.4.0) aws-eventstream (1.0.0) aws-partitions (1.91.0) @@ -135,7 +135,7 @@ GEM hkdf (0.3.0) htmlentities (4.3.4) http_accept_language (2.0.5) - i18n (0.9.5) + i18n (1.0.1) concurrent-ruby (~> 1.0) image_size (1.5.0) in_threads (1.5.0) @@ -272,9 +272,9 @@ GEM rails_multisite (2.0.4) activerecord (> 4.2, < 6) railties (> 4.2, < 6) - railties (5.1.5) - actionpack (= 5.1.5) - activesupport (= 5.1.5) + railties (5.2.0) + actionpack (= 5.2.0) + activesupport (= 5.2.0) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) @@ -405,13 +405,13 @@ PLATFORMS ruby DEPENDENCIES - actionmailer (= 5.1.5) - actionpack (= 5.1.5) - actionview (= 5.1.5) + actionmailer (= 5.2) + actionpack (= 5.2) + actionview (= 5.2) active_model_serializers (~> 0.8.3) - activemodel (= 5.1.5) - activerecord (= 5.1.5) - activesupport (= 5.1.5) + activemodel (= 5.2) + activerecord (= 5.2) + activesupport (= 5.2) annotate aws-sdk-s3 barber @@ -479,7 +479,7 @@ DEPENDENCIES rack-mini-profiler rack-protection rails_multisite - railties (= 5.1.5) + railties (= 5.2) rake rb-fsevent rb-inotify (~> 0.9) From e262cb07d49068be95e66598b303c3b0863b2679 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 8 Jun 2018 09:55:26 +0800 Subject: [PATCH 0127/1439] Add discourse-group-tracker to official plugin list. --- lib/plugin/metadata.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugin/metadata.rb b/lib/plugin/metadata.rb index 097845103d..f33059fe04 100644 --- a/lib/plugin/metadata.rb +++ b/lib/plugin/metadata.rb @@ -52,7 +52,7 @@ class Plugin::Metadata "discourse-user-card-badges", "discourse-policy", "discourse-github-linkback", - + "discourse-group-tracker", ]) FIELDS ||= [:name, :about, :version, :authors, :url, :required_version] From 8e0c1c87820c2ecd30225fb81caaa656fbd00eae Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 8 Jun 2018 10:04:06 +0800 Subject: [PATCH 0128/1439] Re-enable skipped specs. --- spec/components/migration/safe_migrate_spec.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/spec/components/migration/safe_migrate_spec.rb b/spec/components/migration/safe_migrate_spec.rb index c8cec0f0eb..15659e4b90 100644 --- a/spec/components/migration/safe_migrate_spec.rb +++ b/spec/components/migration/safe_migrate_spec.rb @@ -27,7 +27,6 @@ describe Migration::SafeMigrate do end it "bans all table removal" do - skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/drop_table" @@ -45,7 +44,6 @@ describe Migration::SafeMigrate do end it "bans all table renames" do - skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/rename_table" @@ -63,7 +61,6 @@ describe Migration::SafeMigrate do end it "bans all column removal" do - skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/remove_column" @@ -81,7 +78,6 @@ describe Migration::SafeMigrate do end it "bans all column renames" do - skip("waiting on rails 5.2") Migration::SafeMigrate.enable! path = File.expand_path "#{Rails.root}/spec/fixtures/migrate/rename_column" @@ -99,7 +95,6 @@ describe Migration::SafeMigrate do end it "supports being disabled" do - skip("waiting on rails 5.2") Migration::SafeMigrate.enable! Migration::SafeMigrate.disable! From 1a00aaa8258c0e4d85e92c4b2e638a34a13002fd Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Fri, 8 Jun 2018 10:51:16 +0800 Subject: [PATCH 0129/1439] Revert "Add discourse-group-tracker to official plugin list." This reverts commit e262cb07d49068be95e66598b303c3b0863b2679. --- lib/plugin/metadata.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugin/metadata.rb b/lib/plugin/metadata.rb index f33059fe04..097845103d 100644 --- a/lib/plugin/metadata.rb +++ b/lib/plugin/metadata.rb @@ -52,7 +52,7 @@ class Plugin::Metadata "discourse-user-card-badges", "discourse-policy", "discourse-github-linkback", - "discourse-group-tracker", + ]) FIELDS ||= [:name, :about, :version, :authors, :url, :required_version] From 42847252a4faa10f34e0e9a2a084d8fd5a514758 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 8 Jun 2018 13:38:25 +1000 Subject: [PATCH 0130/1439] remove conditional code --- lib/freedom_patches/pool_drainer.rb | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/freedom_patches/pool_drainer.rb b/lib/freedom_patches/pool_drainer.rb index 0e0350d635..dc9a2f499c 100644 --- a/lib/freedom_patches/pool_drainer.rb +++ b/lib/freedom_patches/pool_drainer.rb @@ -1,27 +1,24 @@ +class ActiveRecord::ConnectionAdapters::AbstractAdapter + module LastUseExtension + attr_reader :last_use, :first_use -if Rails.version >= "4.2.0" - class ActiveRecord::ConnectionAdapters::AbstractAdapter - module LastUseExtension - attr_reader :last_use, :first_use + def initialize(connection, logger = nil, pool = nil) + super + @last_use = false + @first_use = Time.now + end - def initialize(connection, logger = nil, pool = nil) - super - @last_use = false - @first_use = Time.now - end - - def lease - @lock.synchronize do - unless in_use? - @last_use = Time.now - super - end + def lease + @lock.synchronize do + unless in_use? + @last_use = Time.now + super end end end - - prepend LastUseExtension end + + prepend LastUseExtension end class ActiveRecord::ConnectionAdapters::ConnectionPool From b7d92061e210cd5381e1b79740444cf8e05f2874 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Mon, 4 Jun 2018 18:34:41 -0700 Subject: [PATCH 0131/1439] FEATURE: add an option to create undismissable modals --- .../discourse/components/d-modal-body.js.es6 | 4 +++- .../discourse/components/d-modal.js.es6 | 12 +++++++++++- .../discourse/templates/components/d-modal.hbs | 8 +++++--- test/javascripts/acceptance/modal-test.js.es6 | 17 +++++++++++++++++ 4 files changed, 36 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 index 04c9754dd8..04beaa9fdb 100644 --- a/app/assets/javascripts/discourse/components/d-modal-body.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal-body.js.es6 @@ -1,6 +1,7 @@ export default Ember.Component.extend({ classNames: ['modal-body'], fixed: false, + dismissable: true, didInsertElement() { this._super(); @@ -44,7 +45,8 @@ export default Ember.Component.extend({ 'rawTitle', 'fixed', 'subtitle', - 'rawSubtitle' + 'rawSubtitle', + 'dismissable' ) ); }, diff --git a/app/assets/javascripts/discourse/components/d-modal.js.es6 b/app/assets/javascripts/discourse/components/d-modal.js.es6 index a57f4daea0..43cc66e462 100644 --- a/app/assets/javascripts/discourse/components/d-modal.js.es6 +++ b/app/assets/javascripts/discourse/components/d-modal.js.es6 @@ -3,6 +3,7 @@ import { on } from "ember-addons/ember-computed-decorators"; export default Ember.Component.extend({ classNameBindings: [':modal', ':d-modal', 'modalClass', 'modalStyle'], attributeBindings: ['data-keyboard'], + dismissable: true, init() { this._super(...arguments); @@ -21,7 +22,7 @@ export default Ember.Component.extend({ @on("didInsertElement") setUp() { $('html').on('keydown.discourse-modal', e => { - if (e.which === 27) { + if (e.which === 27 && this.get('dismissable')) { Em.run.next(() => $('.modal-header a.close').click()); } }); @@ -48,6 +49,12 @@ export default Ember.Component.extend({ // of another modal is not used this.set('subtitle', null); } + + if ('dismissable' in data) { + this.set('dismissable', data.dismissable); + } else { + this.set('dismissable', true); + } }); }, @@ -57,6 +64,9 @@ export default Ember.Component.extend({ }, click(e) { + if(!this.get('dismissable')) { + return; + } const $target = $(e.target); if ($target.hasClass("modal-middle-container") || $target.hasClass("modal-outer-container")) { diff --git a/app/assets/javascripts/discourse/templates/components/d-modal.hbs b/app/assets/javascripts/discourse/templates/components/d-modal.hbs index 852b29f884..f9b339428a 100644 --- a/app/assets/javascripts/discourse/templates/components/d-modal.hbs +++ b/app/assets/javascripts/discourse/templates/components/d-modal.hbs @@ -2,9 +2,11 @@