","post_number":1,"post_type":1,"updated_at":"2016-12-01T02:47:18.317Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":null,"incoming_link_count":0,"reads":1,"score":0,"yours":true,"topic_id":13,"topic_slug":"this-is-a-test-topic-for-polls","display_username":null,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_bg_color":null,"primary_group_flair_color":null,"version":2,"can_edit":true,"can_delete":false,"can_recover":true,"can_wiki":true,"read":true,"user_title":null,"actions_summary":[{"id":3,"can_act":true},{"id":4,"can_act":true},{"id":5,"hidden":true,"can_act":true},{"id":7,"can_act":true},{"id":8,"can_act":true}],"moderator":false,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":4,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"polls":{"poll":{"options":[{"id":"57ddd734344eb7436d64a7d68a0df444","html":"test","votes":0},{"id":"b5b78d79ab5b5d75d4d33d8b87f5d2aa","html":"haha","votes":0}],"voters":2,"status":"open","name":"poll"},"test":{"options":[{"id":"c26ad90783b0d80936e5fdb292b7963c","html":"donkey","votes":0},{"id":"99f2b9ac452ba73b115fcf3556e6d2d4","html":"kong","votes":0}],"voters":3,"status":"open","name":"test"}}}],"stream":[19]},"timeline_lookup":[[1,0]],"id":13,"title":"This is a test topic for polls","fancy_title":"This is a test topic for polls","posts_count":1,"created_at":"2016-12-01T02:39:48.055Z","views":1,"reply_count":0,"participant_count":1,"like_count":0,"last_posted_at":"2016-12-01T02:39:49.199Z","visible":true,"closed":false,"archived":false,"has_summary":false,"archetype":"regular","slug":"this-is-a-test-topic-for-polls","category_id":1,"word_count":10,"deleted_at":null,"user_id":1,"draft":null,"draft_key":"topic_13","draft_sequence":4,"posted":true,"unpinned":null,"pinned_globally":false,"pinned":false,"pinned_at":null,"pinned_until":null,"details":{"auto_close_at":null,"auto_close_hours":null,"auto_close_based_on_last_post":false,"created_by":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"},"last_poster":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"},"participants":[{"id":1,"username":"tgx","avatar_template":"/images/avatar.png","post_count":1}],"suggested_topics":[{"id":8,"title":"Welcome to Discourse","fancy_title":"Welcome to Discourse","slug":"welcome-to-discourse","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-11-24T02:10:54.328Z","last_posted_at":"2016-11-24T02:10:54.393Z","bumped":true,"bumped_at":"2016-11-24T02:10:54.393Z","unseen":false,"pinned":true,"unpinned":null,"excerpt":"The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! \n\nEdit this into a brief description of your community: \n\n\nWho is it for?\nWhat can they …","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"archetype":"regular","like_count":0,"views":0,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":-1,"username":"system","avatar_template":"/images/avatar.png"}}]},{"id":12,"title":"Some testing topic testing","fancy_title":"Some testing topic testing","slug":"some-testing-topic-testing","posts_count":4,"reply_count":0,"highest_post_number":4,"image_url":null,"created_at":"2016-11-24T08:36:08.773Z","last_posted_at":"2016-12-01T01:15:52.008Z","bumped":true,"bumped_at":"2016-12-01T01:15:52.008Z","unseen":false,"last_read_post_number":4,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":2,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"}}]},{"id":11,"title":"Some testing topic","fancy_title":"Some testing topic","slug":"some-testing-topic","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2016-11-24T08:35:26.758Z","last_posted_at":"2016-11-24T08:35:26.894Z","bumped":true,"bumped_at":"2016-11-24T08:35:26.894Z","unseen":false,"last_read_post_number":1,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":0,"category_id":1,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"}}]}],"notification_level":3,"notifications_reason_id":1,"can_move_posts":true,"can_edit":true,"can_delete":true,"can_recover":true,"can_remove_allowed_users":true,"can_invite_to":true,"can_create_post":true,"can_reply_as_new_topic":true,"can_flag_topic":true},"highest_post_number":1,"last_read_post_number":1,"last_read_post_id":19,"deleted_by":null,"has_deleted":false,"actions_summary":[{"id":4,"count":0,"hidden":false,"can_act":true},{"id":7,"count":0,"hidden":false,"can_act":true},{"id":8,"count":0,"hidden":false,"can_act":true}],"chunk_size":20,"bookmarked":false}
+ {
+ post_stream: {
+ posts: [
+ {
+ id: 19,
+ name: null,
+ username: "tgx",
+ avatar_template: "/images/avatar.png",
+ created_at: "2016-12-01T02:39:49.199Z",
+ cooked:
+ '
","post_number":1,"post_type":1,"updated_at":"2017-01-31T08:39:06.237Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":null,"incoming_link_count":0,"reads":1,"score":0,"yours":true,"topic_id":12,"topic_slug":"this-is-a-topic-created-for-testing","display_username":null,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_bg_color":null,"primary_group_flair_color":null,"version":1,"can_edit":true,"can_delete":false,"can_recover":true,"can_wiki":true,"read":true,"user_title":null,"actions_summary":[{"id":3,"can_act":true},{"id":4,"can_act":true},{"id":5,"hidden":true,"can_act":true},{"id":7,"can_act":true},{"id":8,"can_act":true}],"moderator":false,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":4,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"polls":{"poll":{"options":[{"id":"4d8a15e3cc35750f016ce15a43937620","html":"1","votes":29},{"id":"cd314db7dfbac2b10687b6f39abfdf41","html":"2","votes":29},{"id":"68b434ff88aeae7054e42cd05a4d9056","html":"3","votes":42}],"voters":100,"status":"open","name":"poll","type":"multiple","min":"1","max":"3","public":"true"}}}],"stream":[15]},"timeline_lookup":[[1,0]],"id":12,"title":"This is a topic created for testing","fancy_title":"This is a topic created for testing","posts_count":1,"created_at":"2017-01-31T08:39:06.094Z","views":1,"reply_count":0,"participant_count":1,"like_count":0,"last_posted_at":"2017-01-31T08:39:06.237Z","visible":true,"closed":false,"archived":false,"has_summary":false,"archetype":"regular","slug":"this-is-a-topic-created-for-testing","category_id":1,"word_count":13,"deleted_at":null,"user_id":1,"draft":null,"draft_key":"topic_12","draft_sequence":1,"posted":true,"unpinned":null,"pinned_globally":false,"pinned":false,"pinned_at":null,"pinned_until":null,"details":{"auto_close_at":null,"auto_close_hours":null,"auto_close_based_on_last_post":false,"created_by":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"},"last_poster":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"},"participants":[{"id":1,"username":"tgx","avatar_template":"/images/avatar.png","post_count":1,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_color":null,"primary_group_flair_bg_color":null}],"suggested_topics":[{"id":8,"title":"Welcome to Discourse","fancy_title":"Welcome to Discourse","slug":"welcome-to-discourse","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2017-01-31T07:53:45.363Z","last_posted_at":"2017-01-31T07:53:45.439Z","bumped":true,"bumped_at":"2017-01-31T07:53:45.439Z","unseen":false,"pinned":true,"unpinned":null,"excerpt":"The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! \n\nEdit this into a brief description of your community: \n\n\nWho is it for?\nWhat can they …","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"archetype":"regular","like_count":0,"views":0,"category_id":1,"featured_link":null,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":-1,"username":"system","avatar_template":"/images/avatar.png"}}]},{"id":11,"title":"This is a test post to try out posts","fancy_title":"This is a test post to try out posts","slug":"this-is-a-test-post-to-try-out-posts","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2017-01-31T07:55:58.407Z","last_posted_at":"2017-01-31T07:55:58.634Z","bumped":true,"bumped_at":"2017-01-31T07:55:58.634Z","unseen":false,"last_read_post_number":1,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":1,"category_id":1,"featured_link":null,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"}}]}],"notification_level":3,"notifications_reason_id":1,"can_move_posts":true,"can_edit":true,"can_delete":true,"can_recover":true,"can_remove_allowed_users":true,"can_invite_to":true,"can_create_post":true,"can_reply_as_new_topic":true,"can_flag_topic":true},"highest_post_number":1,"last_read_post_number":1,"last_read_post_id":15,"deleted_by":null,"has_deleted":false,"actions_summary":[{"id":4,"count":0,"hidden":false,"can_act":true},{"id":7,"count":0,"hidden":false,"can_act":true},{"id":8,"count":0,"hidden":false,"can_act":true}],"chunk_size":20,"bookmarked":false,"featured_link":null}
+ {
+ post_stream: {
+ posts: [
+ {
+ id: 15,
+ name: null,
+ username: "tgx",
+ avatar_template: "/images/avatar.png",
+ created_at: "2017-01-31T08:39:06.237Z",
+ cooked:
+ '
","post_number":1,"post_type":1,"updated_at":"2017-01-31T09:11:11.281Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":null,"incoming_link_count":0,"reads":1,"score":0,"yours":true,"topic_id":13,"topic_slug":"this-is-a-topic-for-testing-number-poll","display_username":null,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_bg_color":null,"primary_group_flair_color":null,"version":1,"can_edit":true,"can_delete":false,"can_recover":true,"can_wiki":true,"read":true,"user_title":null,"actions_summary":[{"id":3,"can_act":true},{"id":4,"can_act":true},{"id":5,"hidden":true,"can_act":true},{"id":7,"can_act":true},{"id":8,"can_act":true}],"moderator":false,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":4,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"polls":{"poll":{"options":[{"id":"4d8a15e3cc35750f016ce15a43937620","html":"1","votes":2},{"id":"cd314db7dfbac2b10687b6f39abfdf41","html":"2","votes":1},{"id":"68b434ff88aeae7054e42cd05a4d9056","html":"3","votes":1},{"id":"aa2393b424f2f395abb63bf785760a3b","html":"4","votes":0},{"id":"8b2f2930cac0574c3450f5db9a6fb7f9","html":"5","votes":1},{"id":"60cad69e0cfcb3fa77a68d11d3758002","html":"6","votes":0},{"id":"9ab1070dec27185440cdabb4948a5e9a","html":"7","votes":1},{"id":"99944bf07088f815a966d585daed6a7e","html":"8","votes":3},{"id":"345a83050400d78f5fac98d381b45e23","html":"9","votes":3},{"id":"46c01f638a50d86e020f47469733b8be","html":"10","votes":3},{"id":"07f7f85b2a3809faff68a35e81a664eb","html":"11","votes":2},{"id":"b3e8c14e714910cb8dd7089f097be133","html":"12","votes":4},{"id":"b4f15431e07443c372d521e4ed131abe","html":"13","votes":2},{"id":"a77bc9a30933e5af327211db2da46e17","html":"14","votes":2},{"id":"303d7c623da1985e94a9d27d43596934","html":"15","votes":2},{"id":"4e885ead68ff4456f102843df9fbbd7f","html":"16","votes":1},{"id":"cbf6e2b72e403b12d7ee63a138f32647","html":"17","votes":2},{"id":"9364fa2d67fbd62c473165441ad69571","html":"18","votes":2},{"id":"eb8661f072794ea57baa7827cd8ffc88","html":"19","votes":1},{"id":"b373436e858c0821135f994a5ff3345f","html":"20","votes":2}],"voters":35,"status":"open","name":"poll","type":"number","min":"1","max":"20","step":"1","public":"true"}}}],"stream":[16]},"timeline_lookup":[[1,0]],"id":13,"title":"This is a topic for testing number poll","fancy_title":"This is a topic for testing number poll","posts_count":1,"created_at":"2017-01-31T09:11:11.161Z","views":1,"reply_count":0,"participant_count":1,"like_count":0,"last_posted_at":"2017-01-31T09:11:11.281Z","visible":true,"closed":false,"archived":false,"has_summary":false,"archetype":"regular","slug":"this-is-a-topic-for-testing-number-poll","category_id":1,"word_count":12,"deleted_at":null,"user_id":1,"draft":null,"draft_key":"topic_13","draft_sequence":1,"posted":true,"unpinned":null,"pinned_globally":false,"pinned":false,"pinned_at":null,"pinned_until":null,"details":{"auto_close_at":null,"auto_close_hours":null,"auto_close_based_on_last_post":false,"created_by":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"},"last_poster":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"},"participants":[{"id":1,"username":"tgx","avatar_template":"/images/avatar.png","post_count":1,"primary_group_name":null,"primary_group_flair_url":null,"primary_group_flair_color":null,"primary_group_flair_bg_color":null}],"suggested_topics":[{"id":8,"title":"Welcome to Discourse","fancy_title":"Welcome to Discourse","slug":"welcome-to-discourse","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2017-01-31T07:53:45.363Z","last_posted_at":"2017-01-31T07:53:45.439Z","bumped":true,"bumped_at":"2017-01-31T07:53:45.439Z","unseen":false,"pinned":true,"unpinned":null,"excerpt":"The first paragraph of this pinned topic will be visible as a welcome message to all new visitors on your homepage. It's important! \n\nEdit this into a brief description of your community: \n\n\nWho is it for?\nWhat can they …","visible":true,"closed":false,"archived":false,"bookmarked":null,"liked":null,"archetype":"regular","like_count":0,"views":0,"category_id":1,"featured_link":null,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":-1,"username":"system","avatar_template":"/images/avatar.png"}}]},{"id":11,"title":"This is a test post to try out posts","fancy_title":"This is a test post to try out posts","slug":"this-is-a-test-post-to-try-out-posts","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2017-01-31T07:55:58.407Z","last_posted_at":"2017-01-31T07:55:58.634Z","bumped":true,"bumped_at":"2017-01-31T07:55:58.634Z","unseen":false,"last_read_post_number":1,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":1,"category_id":1,"featured_link":null,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"}}]},{"id":12,"title":"This is a topic created for testing","fancy_title":"This is a topic created for testing","slug":"this-is-a-topic-created-for-testing","posts_count":1,"reply_count":0,"highest_post_number":1,"image_url":null,"created_at":"2017-01-31T08:39:06.094Z","last_posted_at":"2017-01-31T08:39:06.237Z","bumped":true,"bumped_at":"2017-01-31T09:10:46.528Z","unseen":false,"last_read_post_number":1,"unread":0,"new_posts":0,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"notification_level":3,"bookmarked":false,"liked":false,"archetype":"regular","like_count":0,"views":1,"category_id":1,"featured_link":null,"posters":[{"extras":"latest single","description":"Original Poster, Most Recent Poster","user":{"id":1,"username":"tgx","avatar_template":"/images/avatar.png"}}]}],"notification_level":3,"notifications_reason_id":1,"can_move_posts":true,"can_edit":true,"can_delete":true,"can_recover":true,"can_remove_allowed_users":true,"can_invite_to":true,"can_create_post":true,"can_reply_as_new_topic":true,"can_flag_topic":true},"highest_post_number":1,"last_read_post_number":1,"last_read_post_id":16,"deleted_by":null,"has_deleted":false,"actions_summary":[{"id":4,"count":0,"hidden":false,"can_act":true},{"id":7,"count":0,"hidden":false,"can_act":true},{"id":8,"count":0,"hidden":false,"can_act":true}],"chunk_size":20,"bookmarked":false,"featured_link":null}
+ {
+ post_stream: {
+ posts: [
+ {
+ id: 16,
+ name: null,
+ username: "tgx",
+ avatar_template: "/images/avatar.png",
+ created_at: "2017-01-31T09:11:11.281Z",
+ cooked:
+ '
"
+ expect(PrettyText.format_for_email(html, post)).to eq(html)
+ end
end
it 'Is smart about linebreaks and IMG tags' do
@@ -852,15 +857,15 @@ describe PrettyText do
expect(cooked).to include(element)
end
- cooked = PrettyText.cook("[`a` #known::tag here](http://somesite.com)")
+ cooked = PrettyText.cook("[`a` #known::tag here](http://example.com)")
html = <<~HTML
-
HTML
expect(cooked).to eq(html.strip)
- cooked = PrettyText.cook("`a` #known::tag here")
+ cooked = PrettyText.cook("`a` #known::tag here")
expect(cooked).to eq(html.strip)
diff --git a/spec/components/rate_limiter/limit_exceeded_spec.rb b/spec/components/rate_limiter/limit_exceeded_spec.rb
new file mode 100644
index 0000000000..f913add176
--- /dev/null
+++ b/spec/components/rate_limiter/limit_exceeded_spec.rb
@@ -0,0 +1,20 @@
+require 'rails_helper'
+
+RSpec.describe RateLimiter::LimitExceeded do
+ describe '#description' do
+ it 'should return the right description' do
+ [
+ [3, I18n.t("rate_limiter.short_time")],
+ [59, I18n.t("rate_limiter.seconds", count: 59)],
+ [3599, I18n.t("rate_limiter.minutes", count: 59)],
+ [7000, I18n.t("rate_limiter.hours", count: 1)]
+ ].each do |available_in, time_left|
+
+ expect(described_class.new(available_in).description).to eq(I18n.t(
+ "rate_limiter.too_many_requests",
+ time_left: time_left
+ ))
+ end
+ end
+ end
+end
diff --git a/spec/components/scheduler/manager_spec.rb b/spec/components/scheduler/manager_spec.rb
index 4e96014726..aeaa9a3e64 100644
--- a/spec/components/scheduler/manager_spec.rb
+++ b/spec/components/scheduler/manager_spec.rb
@@ -61,7 +61,11 @@ describe Scheduler::Manager do
before do
expect(ActiveRecord::Base.connection_pool.connections.length).to eq(1)
@thread_count = Thread.list.count
- @thread_ids = Thread.list.map { |t| t.object_id }
+
+ @backtraces = {}
+ Thread.list.each do |t|
+ @backtraces[t.object_id] = t.backtrace
+ end
end
after do
@@ -81,11 +85,17 @@ describe Scheduler::Manager do
on_thread_mismatch = lambda do
current = Thread.list.map { |t| t.object_id }
- extra = current - @thread_ids
- missing = @thread_ids - current
+ old_threads = @backtraces.keys
+ extra = current - old_threads
+
+ missing = old_threads - current
if missing.length > 0
STDERR.puts "\nMissing Threads #{missing.length} thread/s"
+ missing.each do |id|
+ STDERR.puts @backtraces[id]
+ STDERR.puts
+ end
end
if extra.length > 0
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index e293a87fd2..9ad75bf58c 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -895,7 +895,7 @@ describe Search do
str << "page page on Atmosphere](https://atmospherejs.com/grigio/babel)xxx: aaa.js:222 aaa'\"bbb"
ts_query = Search.ts_query(term: str, ts_config: "simple")
- Post.exec_sql("SELECT to_tsvector('bbb') @@ " << ts_query)
+ DB.exec("SELECT to_tsvector('bbb') @@ " << ts_query)
end
context '#word_to_date' do
@@ -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/site_setting_extension_spec.rb b/spec/components/site_setting_extension_spec.rb
index 4171b9db4c..1e67d99a29 100644
--- a/spec/components/site_setting_extension_spec.rb
+++ b/spec/components/site_setting_extension_spec.rb
@@ -433,13 +433,13 @@ describe SiteSettingExtension do
settings.refresh!
expect {
settings.set("provider", "haxxed")
- }.to raise_error(ArgumentError)
+ }.to raise_error(Discourse::InvalidParameters)
end
end
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
@@ -447,7 +447,7 @@ describe SiteSettingExtension do
it "raises an error when set for an invalid setting name" do
expect {
settings.set_and_log("provider", "haxxed")
- }.to raise_error(ArgumentError)
+ }.to raise_error(Discourse::InvalidParameters)
end
it "scrubs secret setting values from logs" do
@@ -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)
@@ -592,6 +601,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' })
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/components/sql_builder_spec.rb b/spec/components/sql_builder_spec.rb
deleted file mode 100644
index 4ccdde49a2..0000000000
--- a/spec/components/sql_builder_spec.rb
+++ /dev/null
@@ -1,75 +0,0 @@
-# encoding: utf-8
-require 'rails_helper'
-require_dependency 'sql_builder'
-
-describe SqlBuilder do
-
- describe "attached" do
- before do
- @builder = Post.sql_builder("select * from posts /*where*/ /*limit*/")
- end
-
- it "should find a post by id" do
- p = Fabricate(:post)
- @builder.where('id = :id and topic_id = :topic_id', id: p.id, topic_id: p.topic_id)
- p2 = @builder.exec.first
- expect(p2.id).to eq(p.id)
- expect(p2).to eq(p)
- end
- end
-
- describe "map_exec" do
- class SqlBuilder::TestClass
- attr_accessor :int, :string, :date, :text, :bool
- end
-
- it "correctly maps to a klass" do
- rows = SqlBuilder.new("SELECT
- 1 AS int,
- 'string' AS string,
- CAST(NOW() at time zone 'utc' AS timestamp without time zone) AS date,
- 'text'::text AS text,
- true AS bool")
- .map_exec(SqlBuilder::TestClass)
-
- expect(rows.count).to eq(1)
- row = rows[0]
- expect(row.int).to eq(1)
- expect(row.string).to eq("string")
- expect(row.text).to eq("text")
- expect(row.bool).to eq(true)
- expect(row.date).to be_within(10.seconds).of(DateTime.now)
- end
- end
-
- describe "detached" do
- before do
- @builder = SqlBuilder.new("select * from (select :a A union all select :b) as X /*where*/ /*order_by*/ /*limit*/ /*offset*/")
- end
-
- it "should allow for 1 param exec" do
- expect(@builder.exec(a: 1, b: 2).values[0][0]).to eq(1)
- end
-
- it "should allow for a single where" do
- @builder.where(":a = 1")
- expect(@builder.exec(a: 1, b: 2).values[0][0]).to eq(1)
- end
-
- it "should allow where chaining" do
- @builder.where(":a = 1")
- @builder.where("2 = 1")
- expect(@builder.exec(a: 1, b: 2).to_a.length).to eq(0)
- end
-
- it "should allow order by" do
- expect(@builder.order_by("A desc").limit(1)
- .exec(a: 1, b: 2).values[0][0]).to eq(2)
- end
- it "should allow offset" do
- expect(@builder.order_by("A desc").offset(1)
- .exec(a: 1, b: 2).values[0][0]).to eq(1)
- end
- end
-
-end
diff --git a/spec/components/stylesheet/manager_spec.rb b/spec/components/stylesheet/manager_spec.rb
index 9e5b6ff347..b534133b9e 100644
--- a/spec/components/stylesheet/manager_spec.rb
+++ b/spec/components/stylesheet/manager_spec.rb
@@ -87,6 +87,45 @@ describe Stylesheet::Manager do
expect(digest1).not_to eq(digest2)
end
+
+ let(:image) { file_from_fixtures("logo.png") }
+ let(:image2) { file_from_fixtures("logo-dev.png") }
+
+ it 'can correctly account for theme uploads in digest' do
+ theme = Theme.create!(
+ name: 'parent',
+ user_id: -1
+ )
+
+ upload = UploadCreator.new(image, "logo.png").create_for(-1)
+ field = ThemeField.create!(
+ theme_id: theme.id,
+ target_id: Theme.targets[:common],
+ name: "logo",
+ value: "",
+ upload_id: upload.id,
+ type_id: ThemeField.types[:theme_upload_var]
+ )
+
+ manager = Stylesheet::Manager.new(:desktop_theme, theme.key)
+ digest1 = manager.digest
+ field.destroy!
+
+ upload = UploadCreator.new(image2, "logo.png").create_for(-1)
+ field = ThemeField.create!(
+ theme_id: theme.id,
+ target_id: Theme.targets[:common],
+ name: "logo",
+ value: "",
+ upload_id: upload.id,
+ type_id: ThemeField.types[:theme_upload_var]
+ )
+
+ manager = Stylesheet::Manager.new(:desktop_theme, theme.key)
+ digest2 = manager.digest
+
+ expect(digest1).not_to eq(digest2)
+ end
end
describe 'color_scheme_digest' do
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/topic_view_spec.rb b/spec/components/topic_view_spec.rb
index 06fb8099a0..b06b7210fe 100644
--- a/spec/components/topic_view_spec.rb
+++ b/spec/components/topic_view_spec.rb
@@ -364,6 +364,35 @@ describe TopicView do
end
end
+ describe 'when a megalodon topic is closed' do
+ before do
+ @original_const = TopicView::MEGA_TOPIC_POSTS_COUNT
+ TopicView.send(:remove_const, "MEGA_TOPIC_POSTS_COUNT")
+ TopicView.const_set("MEGA_TOPIC_POSTS_COUNT", 1)
+ topic.update!(closed: true)
+ SiteSetting.summary_max_results = 2
+ end
+
+ after do
+ TopicView.send(:remove_const, "MEGA_TOPIC_POSTS_COUNT")
+ TopicView.const_set("MEGA_TOPIC_POSTS_COUNT", @original_const)
+ end
+
+ it 'should be forced into summary mode without gaps' do
+ topic_view = TopicView.new(topic.id, evil_trout, post_number: 1)
+
+ expect(topic_view.contains_gaps?).to eq(false)
+ expect(topic_view.posts).to eq([p5])
+ end
+
+ it 'should not be forced into summary mode if post_number is not blank' do
+ topic_view = TopicView.new(topic.id, evil_trout, post_number: 2)
+
+ expect(topic_view.contains_gaps?).to eq(false)
+ expect(topic_view.posts).to eq([p1, p2, p3])
+ end
+ end
+
it "#restricts to correct topic" do
t2 = Fabricate(:topic)
@@ -549,4 +578,37 @@ describe TopicView do
end
end
end
+
+ describe '#filtered_post_stream' do
+ let!(:post) { Fabricate(:post, topic: topic, user: first_poster) }
+ let!(:post2) { Fabricate(:post, topic: topic, user: evil_trout) }
+ let!(:post3) { Fabricate(:post, topic: topic, user: first_poster) }
+
+ it 'should return the right columns' do
+ expect(topic_view.filtered_post_stream).to eq([
+ [post.id, post.post_number, 0],
+ [post2.id, post2.post_number, 0],
+ [post3.id, post3.post_number, 0]
+ ])
+ end
+
+ describe 'for mega topics' do
+ it 'should return the right columns' do
+ begin
+ original_const = TopicView::MEGA_TOPIC_POSTS_COUNT
+ TopicView.send(:remove_const, "MEGA_TOPIC_POSTS_COUNT")
+ TopicView.const_set("MEGA_TOPIC_POSTS_COUNT", 2)
+
+ expect(topic_view.filtered_post_stream).to eq([
+ [post.id, post.post_number],
+ [post2.id, post2.post_number],
+ [post3.id, post3.post_number]
+ ])
+ ensure
+ TopicView.send(:remove_const, "MEGA_TOPIC_POSTS_COUNT")
+ TopicView.const_set("MEGA_TOPIC_POSTS_COUNT", original_const)
+ end
+ end
+ end
+ end
end
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/components/wizard/step_updater_spec.rb b/spec/components/wizard/step_updater_spec.rb
index ddc3513508..b57d3000db 100644
--- a/spec/components/wizard/step_updater_spec.rb
+++ b/spec/components/wizard/step_updater_spec.rb
@@ -237,6 +237,15 @@ describe Wizard::StepUpdater do
expect(SiteSetting.favicon_url).to eq('/uploads/favicon.png')
expect(SiteSetting.apple_touch_icon_url).to eq('/uploads/apple.png')
end
+
+ it "updates large_icon_url if the uploaded icon size is greater than 180x180" do
+ upload = Fabricate(:upload, width: 512, height: 512)
+ updater = wizard.create_updater('icons', apple_touch_icon_url: upload.url)
+ updater.update
+
+ expect(updater).to be_success
+ expect(SiteSetting.large_icon_url).to eq(upload.url)
+ end
end
context "emoji step" do
@@ -252,12 +261,13 @@ describe Wizard::StepUpdater do
context "homepage step" do
it "updates the fields correctly" do
- updater = wizard.create_updater('homepage', homepage_style: "categories")
+ updater = wizard.create_updater('homepage', homepage_style: "categories_and_top_topics")
updater.update
expect(updater).to be_success
expect(wizard.completed_steps?('homepage')).to eq(true)
expect(SiteSetting.top_menu).to eq('categories|latest|new|unread|top')
+ expect(SiteSetting.desktop_category_page_style).to eq('categories_and_top_topics')
updater = wizard.create_updater('homepage', homepage_style: "latest")
updater.update
diff --git a/spec/controllers/admin/admin_controller_spec.rb b/spec/controllers/admin/admin_controller_spec.rb
deleted file mode 100644
index f26b081a9d..0000000000
--- a/spec/controllers/admin/admin_controller_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'rails_helper'
-
-describe Admin::AdminController do
-
- context 'index' do
-
- it 'needs you to be logged in' do
- get :index, format: :json
- expect(response.status).to eq(403)
- end
-
- it "raises an error if you aren't an admin" do
- _user = log_in
- get :index, format: :json
- expect(response).to be_forbidden
- end
-
- end
-
-end
diff --git a/spec/controllers/admin/api_controller_spec.rb b/spec/controllers/admin/api_controller_spec.rb
deleted file mode 100644
index af72b0529a..0000000000
--- a/spec/controllers/admin/api_controller_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'rails_helper'
-
-describe Admin::ApiController do
-
- it "is a subclass of AdminController" do
- expect(Admin::ApiController < Admin::AdminController).to eq(true)
- end
-
- let!(:user) { log_in(:admin) }
-
- context '.index' do
- it "succeeds" do
- get :index, format: :json
- expect(response).to be_success
- end
- end
-
- context '.regenerate_key' do
- let(:api_key) { Fabricate(:api_key) }
-
- 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.status).to eq(404)
- end
-
- it "delegates to the api key's `regenerate!` method" do
- ApiKey.any_instance.expects(:regenerate!)
- put :regenerate_key, params: { id: api_key.id }, format: :json
- end
- end
-
- context '.revoke_key' do
- let(:api_key) { Fabricate(:api_key) }
-
- 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.status).to eq(404)
- end
-
- it "delegates to the api key's `regenerate!` method" do
- ApiKey.any_instance.expects(:destroy)
- delete :revoke_key, params: { id: api_key.id }, format: :json
- end
- end
-
- context '.create_master_key' do
- it "creates a record" do
- expect do
- post :create_master_key, format: :json
- end.to change(ApiKey, :count).by(1)
- end
- end
-
-end
diff --git a/spec/controllers/admin/backups_controller_spec.rb b/spec/controllers/admin/backups_controller_spec.rb
deleted file mode 100644
index 4f7a6c7894..0000000000
--- a/spec/controllers/admin/backups_controller_spec.rb
+++ /dev/null
@@ -1,264 +0,0 @@
-require "rails_helper"
-
-describe Admin::BackupsController do
-
- it "is a subclass of AdminController" do
- expect(Admin::BackupsController < Admin::AdminController).to eq(true)
- end
-
- let(:backup_filename) { "2014-02-10-065935.tar.gz" }
-
- context "while logged in as an admin" do
-
- before { @admin = log_in(:admin) }
-
- describe ".index" do
-
- context "html format" do
-
- it "preloads important data" do
- Backup.expects(:all).returns([])
- subject.expects(:store_preloaded).with("backups", "[]")
-
- BackupRestore.expects(:operations_status).returns({})
- subject.expects(:store_preloaded).with("operations_status", "{}")
-
- BackupRestore.expects(:logs).returns([])
- subject.expects(:store_preloaded).with("logs", "[]")
-
- get :index, format: :html, xhr: true
-
- expect(response).to be_success
- end
-
- end
-
- context "json format" do
-
- it "returns a list of all the backups" do
- Backup.expects(:all).returns([Backup.new("backup1"), Backup.new("backup2")])
-
- get :index, format: :json, xhr: true
-
- expect(response).to be_success
-
- json = JSON.parse(response.body)
- expect(json[0]["filename"]).to eq("backup1")
- expect(json[1]["filename"]).to eq("backup2")
- end
-
- end
-
- end
-
- describe ".status" do
-
- it "returns the current backups status" do
- BackupRestore.expects(:operations_status)
-
- get :status, format: :json
-
- expect(response).to be_success
- end
-
- end
-
- describe ".create" do
-
- it "starts a backup" do
- BackupRestore.expects(:backup!).with(@admin.id, publish_to_message_bus: true, with_uploads: false, client_id: "foo")
-
- post :create, params: {
- with_uploads: false, client_id: "foo"
- }, format: :json
-
- expect(response).to be_success
- end
-
- end
-
- describe ".show" do
-
- it "uses send_file to transmit the backup" do
- begin
- token = EmailBackupToken.set(@admin.id)
- path = File.join(Backup.base_directory, backup_filename)
- File.open(path, "w") { |f| f.write("hello") }
-
- Backup.create_from_filename(backup_filename)
-
- StaffActionLogger.any_instance.expects(:log_backup_download).once
-
- get :show, params: { id: backup_filename, token: token }, format: :json
-
- expect(response.headers['Content-Length']).to eq("5")
- expect(response.headers['Content-Disposition']).to match(/attachment; filename/)
- ensure
- File.delete(path)
- EmailBackupToken.del(@admin.id)
- end
- end
-
- it "returns 422 when token is bad" do
- begin
- path = File.join(Backup.base_directory, backup_filename)
- File.open(path, "w") { |f| f.write("hello") }
-
- Backup.create_from_filename(backup_filename)
-
- get :show, params: { id: backup_filename, token: "bad_value" }, xhr: true
-
- expect(response.status).to eq(422)
- ensure
- File.delete(path)
- end
- end
-
- it "returns 404 when the backup does not exist" do
- token = EmailBackupToken.set(@admin.id)
- Backup.expects(:[]).returns(nil)
-
- get :show, params: { id: backup_filename, token: token }, format: :json
-
- EmailBackupToken.del(@admin.id)
-
- expect(response).to be_not_found
- end
-
- end
-
- describe ".destroy" do
-
- let(:b) { Backup.new(backup_filename) }
-
- it "removes the backup if found" do
- Backup.expects(:[]).with(backup_filename).returns(b)
- b.expects(:remove)
-
- StaffActionLogger.any_instance.expects(:log_backup_destroy).with(b).once
-
- delete :destroy, params: { id: backup_filename }, format: :json
-
- expect(response).to be_success
- 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
- end
-
- end
-
- describe ".logs" do
-
- it "preloads important data" do
- BackupRestore.expects(:operations_status).returns({})
- subject.expects(:store_preloaded).with("operations_status", "{}")
-
- BackupRestore.expects(:logs).returns([])
- subject.expects(:store_preloaded).with("logs", "[]")
-
- get :logs, format: :html, xhr: true
-
- expect(response).to be_success
- end
- end
-
- describe ".restore" do
-
- it "starts a restore" do
- expect(SiteSetting.disable_emails).to eq(false)
- 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(response).to be_success
- end
-
- end
-
- describe ".readonly" do
-
- it "enables readonly mode" do
- Discourse.expects(:enable_readonly_mode)
-
- expect { put :readonly, params: { enable: true }, format: :json }
- .to change { UserHistory.count }.by(1)
-
- expect(response).to be_success
-
- user_history = UserHistory.last
-
- expect(UserHistory.last.action).to eq(UserHistory.actions[:change_readonly_mode])
- expect(UserHistory.last.new_value).to eq('t')
- end
-
- it "disables readonly mode" do
- Discourse.expects(:disable_readonly_mode)
-
- expect { put :readonly, params: { enable: false }, format: :json }
- .to change { UserHistory.count }.by(1)
-
- expect(response).to be_success
-
- user_history = UserHistory.last
-
- expect(UserHistory.last.action).to eq(UserHistory.actions[:change_readonly_mode])
- expect(UserHistory.last.new_value).to eq('f')
- end
-
- end
-
- describe "#upload_backup_chunk" do
- describe "when filename contains invalid characters" do
- it "should raise an error" do
- ['灰色.tar.gz', '; echo \'haha\'.tar.gz'].each do |invalid_filename|
- described_class.any_instance.expects(:has_enough_space_on_disk?).returns(true)
-
- post :upload_backup_chunk, params: {
- resumableFilename: invalid_filename, resumableTotalSize: 1
- }
-
- expect(response.status).to eq(415)
- expect(response.body).to eq(I18n.t('backup.invalid_filename'))
- end
- end
- end
-
- describe "when filename is valid" do
- it "should upload the file successfully" do
- begin
- described_class.any_instance.expects(:has_enough_space_on_disk?).returns(true)
-
- filename = 'test_Site-0123456789.tar.gz'
-
- post :upload_backup_chunk, params: {
- resumableFilename: filename,
- resumableTotalSize: 1,
- resumableIdentifier: 'test',
- resumableChunkNumber: '1',
- resumableChunkSize: '1',
- resumableCurrentChunkSize: '1',
- file: fixture_file_upload(Tempfile.new)
- }, format: :json
-
- expect(response.status).to eq(200)
- expect(response.body).to eq("")
- ensure
- begin
- File.delete(
- File.join(Backup.base_directory, 'tmp', 'test', "#{filename}.part1")
- )
- rescue Errno::ENOENT
- end
- end
- end
- end
- end
-
- end
-
-end
diff --git a/spec/controllers/admin/emojis_controller_spec.rb b/spec/controllers/admin/emojis_controller_spec.rb
deleted file mode 100644
index 1b494f0571..0000000000
--- a/spec/controllers/admin/emojis_controller_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require "rails_helper"
-
-describe Admin::EmojisController do
-
- let(:custom_emoji) do
- Emoji.new("/path/to/hello").tap do |e|
- e.name = "hello"
- e.url = "/url/to/hello.png"
- end
- end
-
- let(:custom_emoji2) do
- Emoji.new("/path/to/hello2").tap do |e|
- e.name = "hello2"
- e.url = "/url/to/hello2.png"
- end
- end
-
- context "when logged in" do
- let!(:user) { log_in(:admin) }
-
- context ".index" do
- it "returns a list of custom emojis" do
- Emoji.expects(:custom).returns([custom_emoji])
- get :index, format: :json
- expect(response).to be_success
- json = ::JSON.parse(response.body)
- expect(json[0]["name"]).to eq(custom_emoji.name)
- expect(json[0]["url"]).to eq(custom_emoji.url)
- end
- end
- end
-
-end
diff --git a/spec/controllers/admin/impersonate_controller_spec.rb b/spec/controllers/admin/impersonate_controller_spec.rb
deleted file mode 100644
index 866e6898b5..0000000000
--- a/spec/controllers/admin/impersonate_controller_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require 'rails_helper'
-
-describe Admin::ImpersonateController do
-
- it "is a subclass of AdminController" do
- expect(Admin::ImpersonateController < Admin::AdminController).to eq(true)
- end
-
- context 'while logged in as an admin' do
- let!(:admin) { log_in(:admin) }
- let(:user) { Fabricate(:user) }
-
- context 'index' do
- it 'returns success' do
- get :index, format: :json
- expect(response).to be_success
- end
- end
-
- context 'create' do
-
- it 'requires a username_or_email parameter' do
- expect { put :create, format: :json }.to raise_error(ActionController::ParameterMissing)
- end
-
- it 'returns 404 when that user does not exist' do
- post :create, params: { username_or_email: 'hedonismbot' }, format: :json
- expect(response.status).to eq(404)
- end
-
- it "raises an invalid access error if the user can't be impersonated" do
- Guardian.any_instance.expects(:can_impersonate?).with(user).returns(false)
- post :create, params: { username_or_email: user.email }, format: :json
- expect(response).to be_forbidden
- end
-
- context 'success' do
-
- it "logs the impersonation" do
- StaffActionLogger.any_instance.expects(:log_impersonate)
- post :create, params: { username_or_email: user.username }, format: :json
- end
-
- it "changes the current user session id" do
- post :create, params: { username_or_email: user.username }, format: :json
- expect(session[:current_user_id]).to eq(user.id)
- end
-
- it "returns success" do
- post :create, params: { username_or_email: user.email }, format: :json
- expect(response).to be_success
- end
-
- it "also works with an email address" do
- post :create, params: { username_or_email: user.email }, format: :json
- expect(session[:current_user_id]).to eq(user.id)
- end
-
- end
-
- end
-
- end
-
-end
diff --git a/spec/controllers/admin/site_settings_controller_spec.rb b/spec/controllers/admin/site_settings_controller_spec.rb
deleted file mode 100644
index 874f375602..0000000000
--- a/spec/controllers/admin/site_settings_controller_spec.rb
+++ /dev/null
@@ -1,81 +0,0 @@
-require 'rails_helper'
-
-describe Admin::SiteSettingsController do
-
- it "is a subclass of AdminController" do
- expect(Admin::SiteSettingsController < Admin::AdminController).to eq(true)
- end
-
- context 'while logged in as an admin' do
- before do
- @user = log_in(:admin)
- end
-
- context 'index' do
- it 'returns success' do
- get :index, format: :json
- expect(response).to be_success
- end
-
- it 'returns JSON' do
- get :index, format: :json
- expect(::JSON.parse(response.body)).to be_present
- end
- end
-
- context 'update' do
-
- before do
- SiteSetting.setting(:test_setting, "default")
- SiteSetting.refresh!
- end
-
- it 'sets the value when the param is present' do
- put :update, params: {
- id: 'test_setting', test_setting: 'hello'
- }, format: :json
-
- expect(SiteSetting.test_setting).to eq('hello')
- end
-
- it 'allows value to be a blank string' do
- put :update, params: {
- id: 'test_setting', test_setting: ''
- }, format: :json
-
- expect(SiteSetting.test_setting).to eq('')
- end
-
- it 'logs the change' do
- SiteSetting.test_setting = 'previous'
- StaffActionLogger.any_instance.expects(:log_site_setting_change).with('test_setting', 'previous', 'hello')
-
- put :update, params: {
- id: 'test_setting', test_setting: 'hello'
- }, format: :json
-
- expect(SiteSetting.test_setting).to eq('hello')
- end
-
- it 'does not allow changing of hidden settings' do
- SiteSetting.setting(:hidden_setting, "hidden", hidden: true)
- SiteSetting.refresh!
-
- put :update, params: {
- id: 'hidden_setting', hidden_setting: 'not allowed'
- }, format: :json
-
- expect(SiteSetting.hidden_setting).to eq("hidden")
- expect(response.status).to eq(422)
- end
-
- it 'fails when a setting does not exist' do
- expect {
- put :update, params: { id: 'provider', provider: 'gotcha' }, format: :json
- }.to raise_error(ArgumentError)
- end
- end
-
- end
-
-end
diff --git a/spec/controllers/admin/site_texts_controller_spec.rb b/spec/controllers/admin/site_texts_controller_spec.rb
deleted file mode 100644
index 7a1676a831..0000000000
--- a/spec/controllers/admin/site_texts_controller_spec.rb
+++ /dev/null
@@ -1,159 +0,0 @@
-require 'rails_helper'
-
-describe Admin::SiteTextsController do
-
- it "is a subclass of AdminController" do
- expect(Admin::SiteTextsController < Admin::AdminController).to eq(true)
- end
-
- context 'while logged in as an admin' do
- before do
- @user = log_in(:admin)
- end
-
- context '.index' do
- it 'returns json' do
- get :index, params: { q: 'title' }, format: :json
- expect(response).to be_success
- expect(::JSON.parse(response.body)).to be_present
- end
- end
-
- 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
-
- json = ::JSON.parse(response.body)
- expect(json).to be_present
-
- site_text = json['site_text']
- expect(site_text).to be_present
-
- expect(site_text['id']).to eq('title')
- expect(site_text['value']).to eq(I18n.t(:title))
- end
-
- 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
- end
- end
-
- context '#update and #revert' do
- after do
- TranslationOverride.delete_all
- I18n.reload!
- end
-
- describe 'failure' do
- before do
- I18n.backend.store_translations(:en, some_key: '%{first} %{second}')
- end
-
- it 'returns the right error message' do
- put :update, params: {
- id: 'some_key', site_text: { value: 'hello %{key} %{omg}' }
- }, format: :json
-
- expect(response.status).to eq(422)
-
- body = JSON.parse(response.body)
-
- expect(body['message']).to eq(I18n.t(
- 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys',
- keys: 'key, omg'
- ))
- end
- end
-
- it 'updates and reverts the key' do
- orig_title = I18n.t(:title)
-
- put :update, params: { id: 'title', site_text: { value: 'hello' } }, format: :json
- expect(response).to be_success
-
- json = ::JSON.parse(response.body)
- expect(json).to be_present
-
- site_text = json['site_text']
- expect(site_text).to be_present
-
- expect(site_text['id']).to eq('title')
- expect(site_text['value']).to eq('hello')
-
- # Revert
- put :revert, params: { id: 'title' }, format: :json
- expect(response).to be_success
-
- json = ::JSON.parse(response.body)
- expect(json).to be_present
-
- site_text = json['site_text']
- expect(site_text).to be_present
-
- expect(site_text['id']).to eq('title')
- expect(site_text['value']).to eq(orig_title)
- end
-
- it 'returns not found for missing keys' do
- put :update, params: {
- id: 'made_up_no_key_exists', site_text: { value: 'hello' }
- }, format: :json
-
- expect(response).not_to be_success
- end
-
- it 'logs the change' do
- original_title = I18n.t(:title)
-
- put :update, params: {
- id: 'title', site_text: { value: 'yay' }
- }, format: :json
-
- log = UserHistory.last
-
- expect(log.previous_value).to eq(original_title)
- expect(log.new_value).to eq('yay')
- expect(log.action).to eq(UserHistory.actions[:change_site_text])
-
- put :revert, params: { id: 'title' }, format: :json
-
- log = UserHistory.last
-
- expect(log.previous_value).to eq('yay')
- expect(log.new_value).to eq(original_title)
- expect(log.action).to eq(UserHistory.actions[:change_site_text])
- end
-
- it 'returns site texts for the correct locale' do
- SiteSetting.default_locale = :ru
-
- ru_title = 'title ru'
- ru_mf_text = 'ru {NUM_RESULTS, plural, one {1 result} other {many} }'
-
- put :update, params: { id: 'title', site_text: { value: ru_title } }, format: :json
- put :update, params: { id: 'js.topic.read_more_MF', site_text: { value: ru_mf_text } }, format: :json
-
- get :show, params: { id: 'title' }, format: :json
- json = ::JSON.parse(response.body)
- expect(json['site_text']['value']).to eq(ru_title)
-
- get :show, params: { id: 'js.topic.read_more_MF' }, format: :json
- json = ::JSON.parse(response.body)
- expect(json['site_text']['value']).to eq(ru_mf_text)
-
- SiteSetting.default_locale = :en
-
- get :show, params: { id: 'title' }, format: :json
- json = ::JSON.parse(response.body)
- expect(json['site_text']['value']).to_not eq(ru_title)
-
- get :show, params: { id: 'js.topic.read_more_MF' }, format: :json
- json = ::JSON.parse(response.body)
- expect(json['site_text']['value']).to_not eq(ru_mf_text)
- end
- end
- end
-
-end
diff --git a/spec/controllers/admin/themes_controller_spec.rb b/spec/controllers/admin/themes_controller_spec.rb
deleted file mode 100644
index c2c00b78df..0000000000
--- a/spec/controllers/admin/themes_controller_spec.rb
+++ /dev/null
@@ -1,205 +0,0 @@
-require 'rails_helper'
-require_dependency 'theme_serializer'
-
-describe Admin::ThemesController do
-
- it "is a subclass of AdminController" do
- expect(Admin::UsersController < Admin::AdminController).to eq(true)
- end
-
- context 'while logged in as an admin' do
- before do
- @user = log_in(:admin)
- end
-
- context '.generate_key_pair' do
- it 'can generate key pairs' do
- post :generate_key_pair, format: :json
- json = JSON.parse(response.body)
- expect(json["private_key"]).to include("RSA PRIVATE KEY")
- expect(json["public_key"]).to include("ssh-rsa ")
- end
- end
-
- context '.upload_asset' do
- render_views
-
- let(:upload) do
- Rack::Test::UploadedFile.new(file_from_fixtures("fake.woff2", "woff2"))
- end
-
- it 'can create a theme upload' do
- post :upload_asset, params: { file: upload }, format: :json
- expect(response.status).to eq(201)
-
- upload = Upload.find_by(original_filename: "fake.woff2")
-
- expect(upload.id).not_to be_nil
- expect(JSON.parse(response.body)["upload_id"]).to eq(upload.id)
- end
- end
-
- context '.import' do
- let(:theme_file) do
- Rack::Test::UploadedFile.new(file_from_fixtures("sam-s-simple-theme.dcstyle.json", "json"))
- end
-
- let :image do
- file_from_fixtures("logo.png")
- end
-
- it 'can import a theme with an upload' do
- upload = Fabricate(:upload)
- theme = Theme.new(name: 'with-upload', user_id: -1)
- upload = UploadCreator.new(image, "logo.png").create_for(-1)
- theme.set_field(target: :common, name: :logo, upload_id: upload.id, type: :theme_upload_var)
- theme.save
-
- json = ThemeWithEmbeddedUploadsSerializer.new(theme, root: 'theme').to_json
- theme.destroy
-
- temp = Tempfile.new
- temp.write(json)
- temp.rewind
-
- uploaded_json = Rack::Test::UploadedFile.new(temp)
- upload.destroy
-
- post :import, params: { theme: uploaded_json }, format: :json
- expect(response).to be_success
- temp.unlink
-
- theme = Theme.last
- expect(theme.theme_fields.count).to eq(1)
- expect(theme.theme_fields.first.upload).not_to eq(nil)
- expect(theme.theme_fields.first.upload.filesize).to eq(upload.filesize)
- expect(theme.theme_fields.first.upload.sha1).to eq(upload.sha1)
- expect(theme.theme_fields.first.upload.original_filename).to eq(upload.original_filename)
- end
-
- it 'imports a theme' do
- post :import, params: { theme: theme_file }, format: :json
- expect(response).to be_success
-
- json = ::JSON.parse(response.body)
-
- expect(json["theme"]["name"]).to eq("Sam's Simple Theme")
- expect(json["theme"]["theme_fields"].length).to eq(2)
- expect(UserHistory.where(action: UserHistory.actions[:change_theme]).count).to eq(1)
- end
- end
-
- context ' .index' do
- it 'correctly returns themes' do
-
- ColorScheme.destroy_all
- Theme.destroy_all
-
- theme = Theme.new(name: 'my name', user_id: -1)
- theme.set_field(target: :common, name: :scss, value: '.body{color: black;}')
- theme.set_field(target: :desktop, name: :after_header, value: 'test')
-
- theme.remote_theme = RemoteTheme.new(
- remote_url: 'awesome.git',
- remote_version: '7',
- local_version: '8',
- remote_updated_at: Time.zone.now
- )
-
- theme.save!
-
- # this will get serialized as well
- ColorScheme.create_from_base(name: "test", colors: [])
-
- get :index, format: :json
-
- expect(response).to be_success
-
- json = ::JSON.parse(response.body)
-
- expect(json["extras"]["color_schemes"].length).to eq(2)
- theme_json = json["themes"].find { |t| t["id"] == theme.id }
- expect(theme_json["theme_fields"].length).to eq(2)
- expect(theme_json["remote_theme"]["remote_version"]).to eq("7")
- end
- end
-
- context ' .create' do
- it 'creates a theme' do
- post :create, params: {
- theme: {
- name: 'my test name',
- theme_fields: [name: 'scss', target: 'common', value: 'body{color: red;}']
- }
- }, format: :json
-
- expect(response).to be_success
-
- json = ::JSON.parse(response.body)
-
- expect(json["theme"]["theme_fields"].length).to eq(1)
- expect(UserHistory.where(action: UserHistory.actions[:change_theme]).count).to eq(1)
- end
- end
-
- context ' .update' do
- let(:theme) { Theme.create(name: 'my name', user_id: -1) }
-
- it 'can change default theme' do
- SiteSetting.default_theme_key = nil
-
- put :update, params: {
- id: theme.id, theme: { default: true }
- }, format: :json
-
- expect(SiteSetting.default_theme_key).to eq(theme.key)
- end
-
- it 'can unset default theme' do
- SiteSetting.default_theme_key = theme.key
-
- put :update, params: {
- id: theme.id, theme: { default: false }
- }, format: :json
-
- expect(SiteSetting.default_theme_key).to be_blank
- end
-
- it 'updates a theme' do
- theme.set_field(target: :common, name: :scss, value: '.body{color: black;}')
- theme.save
-
- child_theme = Theme.create(name: 'my name', user_id: -1)
-
- upload = Fabricate(:upload)
-
- put :update, params: {
- id: theme.id,
- theme: {
- child_theme_ids: [child_theme.id],
- name: 'my test name',
- theme_fields: [
- { name: 'scss', target: 'common', value: '' },
- { name: 'scss', target: 'desktop', value: 'body{color: blue;}' },
- { name: 'bob', target: 'common', value: '', type_id: 2, upload_id: upload.id },
- ]
- }
- }, format: :json
-
- expect(response).to be_success
-
- json = ::JSON.parse(response.body)
-
- fields = json["theme"]["theme_fields"].sort { |a, b| a["value"] <=> b["value"] }
-
- expect(fields[0]["value"]).to eq('')
- expect(fields[0]["upload_id"]).to eq(upload.id)
- expect(fields[1]["value"]).to eq('body{color: blue;}')
- expect(fields.length).to eq(2)
- expect(json["theme"]["child_themes"].length).to eq(1)
- expect(UserHistory.where(action: UserHistory.actions[:change_theme]).count).to eq(1)
- end
- end
- end
-
-end
diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb
deleted file mode 100644
index d026d7bfb5..0000000000
--- a/spec/controllers/admin/users_controller_spec.rb
+++ /dev/null
@@ -1,840 +0,0 @@
-require 'rails_helper'
-require_dependency 'single_sign_on'
-
-describe Admin::UsersController do
-
- it 'is a subclass of AdminController' do
- expect(Admin::UsersController < Admin::AdminController).to eq(true)
- end
-
- context 'while logged in as an admin' do
- before do
- @user = log_in(:admin)
- end
-
- context '#index' do
- it 'returns success' do
- get :index, format: :json
- expect(response).to be_success
- end
-
- it 'returns JSON' do
- get :index, format: :json
- expect(::JSON.parse(response.body)).to be_present
- end
-
- context 'when showing emails' do
-
- it "returns email for all the users" do
- get :index, params: { show_emails: "true" }, format: :json
- data = ::JSON.parse(response.body)
- data.each do |user|
- expect(user["email"]).to be_present
- end
- end
-
- it "logs only 1 enty" do
- expect(UserHistory.where(action: UserHistory.actions[:check_email], acting_user_id: @user.id).count).to eq(0)
-
- get :index, params: { show_emails: "true" }, format: :json
-
- expect(UserHistory.where(action: UserHistory.actions[:check_email], acting_user_id: @user.id).count).to eq(1)
- end
-
- end
- end
-
- describe '#show' do
- context 'an existing user' do
- it 'returns success' do
- get :show, params: { id: @user.id }, format: :json
- expect(response).to be_success
- end
- end
-
- context 'an existing user' do
- it 'returns success' do
- get :show, params: { id: 0 }, format: :json
- expect(response).not_to be_success
- end
- end
- end
-
- context '#approve_bulk' do
-
- let(:evil_trout) { Fabricate(:evil_trout) }
-
- it "does nothing without uesrs" do
- User.any_instance.expects(:approve).never
- put :approve_bulk, format: :json
- end
-
- it "won't approve the user when not allowed" do
- Guardian.any_instance.expects(:can_approve?).with(evil_trout).returns(false)
- User.any_instance.expects(:approve).never
- put :approve_bulk, params: { users: [evil_trout.id] }, format: :json
- end
-
- it "approves the user when permitted" do
- Guardian.any_instance.expects(:can_approve?).with(evil_trout).returns(true)
- User.any_instance.expects(:approve).once
- put :approve_bulk, params: { users: [evil_trout.id] }, format: :json
- end
-
- end
-
- context '#generate_api_key' do
- let(:evil_trout) { Fabricate(:evil_trout) }
-
- it 'calls generate_api_key' do
- User.any_instance.expects(:generate_api_key).with(@user)
- post :generate_api_key, params: { user_id: evil_trout.id }, format: :json
- end
- end
-
- context '#revoke_api_key' do
-
- let(:evil_trout) { Fabricate(:evil_trout) }
-
- it 'calls revoke_api_key' do
- User.any_instance.expects(:revoke_api_key)
- delete :revoke_api_key, params: { user_id: evil_trout.id }, format: :json
- end
-
- end
-
- context '#approve' do
-
- let(:evil_trout) { Fabricate(:evil_trout) }
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_approve?).with(evil_trout).returns(false)
- put :approve, params: { user_id: evil_trout.id }, format: :json
- expect(response).to be_forbidden
- end
-
- it 'calls approve' do
- User.any_instance.expects(:approve).with(@user)
- put :approve, params: { user_id: evil_trout.id }, format: :json
- end
-
- end
-
- context '#suspend' do
- let(:user) { Fabricate(:evil_trout) }
-
- it "works properly" do
- Fabricate(:api_key, user: user)
- expect(user).not_to be_suspended
- put(
- :suspend,
- params: {
- user_id: user.id,
- suspend_until: 5.hours.from_now,
- reason: "because I said so",
- format: :json
- }
- )
- expect(response).to be_success
-
- user.reload
- expect(user).to be_suspended
- expect(user.suspended_at).to be_present
- expect(user.suspended_till).to be_present
- expect(ApiKey.where(user_id: user.id).count).to eq(0)
-
- log = UserHistory.where(target_user_id: user.id).order('id desc').first
- expect(log).to be_present
- expect(log.details).to match(/because I said so/)
- end
-
- context "with an associated post" do
- let(:post) { Fabricate(:post) }
- let(:suspend_params) do
- { user_id: user.id,
- suspend_until: 5.hours.from_now,
- reason: "because of this post",
- post_id: post.id,
- format: :json }
- end
-
- it "can have an associated post" do
- put(:suspend, params: suspend_params)
- expect(response).to be_success
-
- log = UserHistory.where(target_user_id: user.id).order('id desc').first
- expect(log).to be_present
- expect(log.post_id).to eq(post.id)
- end
-
- it "can delete an associated post" do
- put(:suspend, params: suspend_params.merge(post_action: 'delete'))
- post.reload
- expect(post.deleted_at).to be_present
- expect(response).to be_success
- end
-
- it "can edit an associated post" do
- put(:suspend, params: suspend_params.merge(
- post_action: 'edit',
- post_edit: 'this is the edited content'
- ))
- post.reload
- expect(post.deleted_at).to be_blank
- expect(post.raw).to eq("this is the edited content")
- expect(response).to be_success
- end
- end
-
- it "can send a message to the user" do
- Jobs.expects(:enqueue).with(
- :critical_user_email,
- has_entries(
- type: :account_suspended,
- user_id: user.id
- )
- )
-
- put(
- :suspend,
- params: {
- user_id: user.id,
- suspend_until: 10.days.from_now,
- reason: "short reason",
- message: "long reason",
- format: :json
- }
- )
- expect(response).to be_success
-
- log = UserHistory.where(target_user_id: user.id).order('id desc').first
- expect(log).to be_present
- expect(log.details).to match(/short reason/)
- expect(log.details).to match(/long reason/)
- end
-
- it "also revoke any api keys" do
- User.any_instance.expects(:revoke_api_key)
- put :suspend, params: { user_id: user.id }, format: :json
- end
-
- end
-
- context '#revoke_admin' do
- before do
- @another_admin = Fabricate(:admin)
- end
-
- it 'raises an error unless the user can revoke access' do
- Guardian.any_instance.expects(:can_revoke_admin?).with(@another_admin).returns(false)
- put :revoke_admin, params: { user_id: @another_admin.id }, format: :json
- expect(response).to be_forbidden
- end
-
- it 'updates the admin flag' do
- put :revoke_admin, params: { user_id: @another_admin.id }, format: :json
- @another_admin.reload
- expect(@another_admin).not_to be_admin
- end
- end
-
- context '#grant_admin' do
- before do
- @another_user = Fabricate(:coding_horror)
- end
-
- after do
- $redis.flushall
- end
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_grant_admin?).with(@another_user).returns(false)
- put :grant_admin, params: { user_id: @another_user.id }, format: :json
- expect(response).to be_forbidden
- end
-
- it "returns a 404 if the username doesn't exist" do
- put :grant_admin, params: { user_id: 123123 }, format: :json
- expect(response).to be_forbidden
- end
-
- it 'updates the admin flag' do
- expect(AdminConfirmation.exists_for?(@another_user.id)).to eq(false)
- put :grant_admin, params: { user_id: @another_user.id }, format: :json
- expect(AdminConfirmation.exists_for?(@another_user.id)).to eq(true)
- end
- end
-
- context '#add_group' do
- let(:user) { Fabricate(:user) }
- let(:group) { Fabricate(:group) }
-
- it 'adds the user to the group' do
- post :add_group, params: {
- group_id: group.id, user_id: user.id
- }, format: :json
-
- expect(response).to be_success
- expect(GroupUser.where(user_id: user.id, group_id: group.id).exists?).to eq(true)
-
- group_history = GroupHistory.last
-
- expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group])
- expect(group_history.acting_user).to eq(@user)
- expect(group_history.target_user).to eq(user)
-
- # Doing it again doesn't raise an error
- post :add_group, params: {
- group_id: group.id, user_id: user.id
- }, format: :json
-
- expect(response).to be_success
- end
- end
-
- context '#primary_group' do
- let(:group) { Fabricate(:group) }
-
- before do
- @another_user = Fabricate(:coding_horror)
- end
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_change_primary_group?).with(@another_user).returns(false)
- put :primary_group, params: {
- user_id: @another_user.id
- }, format: :json
-
- expect(response).to be_forbidden
- end
-
- it "returns a 404 if the user doesn't exist" do
- put :primary_group, params: {
- user_id: 123123
- }, format: :json
-
- expect(response).to be_forbidden
- end
-
- it "changes the user's primary group" do
- group.add(@another_user)
- put :primary_group, params: {
- user_id: @another_user.id, primary_group_id: group.id
- }, format: :json
-
- @another_user.reload
- expect(@another_user.primary_group_id).to eq(group.id)
- end
-
- it "doesn't change primary group if they aren't a member of the group" do
- put :primary_group, params: {
- user_id: @another_user.id, primary_group_id: group.id
- }, format: :json
-
- @another_user.reload
- expect(@another_user.primary_group_id).to be_nil
- end
-
- it "remove user's primary group" do
- group.add(@another_user)
-
- put :primary_group, params: {
- user_id: @another_user.id, primary_group_id: ""
- }, format: :json
-
- @another_user.reload
- expect(@another_user.primary_group_id).to be(nil)
- end
- end
-
- context '#trust_level' do
- before do
- @another_user = Fabricate(:coding_horror, created_at: 1.month.ago)
- end
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_change_trust_level?).with(@another_user).returns(false)
- put :trust_level, params: {
- user_id: @another_user.id
- }, format: :json
-
- expect(response).not_to be_success
- end
-
- it "returns a 404 if the username doesn't exist" do
- put :trust_level, params: {
- user_id: 123123
- }, format: :json
-
- expect(response).not_to be_success
- end
-
- it "upgrades the user's trust level" do
- StaffActionLogger.any_instance.expects(:log_trust_level_change).with(@another_user, @another_user.trust_level, 2).once
-
- put :trust_level, params: {
- user_id: @another_user.id, level: 2
- }, format: :json
-
- @another_user.reload
- expect(@another_user.trust_level).to eq(2)
- expect(response).to be_success
- end
-
- it "raises no error when demoting a user below their current trust level (locks trust level)" do
- stat = @another_user.user_stat
- stat.topics_entered = SiteSetting.tl1_requires_topics_entered + 1
- stat.posts_read_count = SiteSetting.tl1_requires_read_posts + 1
- stat.time_read = SiteSetting.tl1_requires_time_spent_mins * 60
- stat.save!
- @another_user.update_attributes(trust_level: TrustLevel[1])
-
- put :trust_level, params: {
- user_id: @another_user.id,
- level: TrustLevel[0]
- }, format: :json
-
- expect(response).to be_success
- @another_user.reload
- expect(@another_user.trust_level).to eq(TrustLevel[0])
- expect(@another_user.manual_locked_trust_level).to eq(TrustLevel[0])
- end
- end
-
- describe '#revoke_moderation' do
- before do
- @moderator = Fabricate(:moderator)
- end
-
- it 'raises an error unless the user can revoke access' do
- Guardian.any_instance.expects(:can_revoke_moderation?).with(@moderator).returns(false)
- put :revoke_moderation, params: {
- user_id: @moderator.id
- }, format: :json
-
- expect(response).to be_forbidden
- end
-
- it 'updates the moderator flag' do
- put :revoke_moderation, params: {
- user_id: @moderator.id
- }, format: :json
-
- @moderator.reload
- expect(@moderator.moderator).not_to eq(true)
- end
- end
-
- context '#grant_moderation' do
- before do
- @another_user = Fabricate(:coding_horror)
- end
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_grant_moderation?).with(@another_user).returns(false)
- put :grant_moderation, params: { user_id: @another_user.id }, format: :json
- expect(response).to be_forbidden
- end
-
- it "returns a 404 if the username doesn't exist" do
- put :grant_moderation, params: { user_id: 123123 }, format: :json
- expect(response).to be_forbidden
- end
-
- it 'updates the moderator flag' do
- put :grant_moderation, params: { user_id: @another_user.id }, format: :json
- @another_user.reload
- expect(@another_user.moderator).to eq(true)
- end
- end
-
- context '#reject_bulk' do
- let(:reject_me) { Fabricate(:user) }
- let(:reject_me_too) { Fabricate(:user) }
-
- it 'does nothing without users' do
- UserDestroyer.any_instance.expects(:destroy).never
- delete :reject_bulk, format: :json
- end
-
- it "won't delete users if not allowed" do
- Guardian.any_instance.stubs(:can_delete_user?).returns(false)
- UserDestroyer.any_instance.expects(:destroy).never
-
- delete :reject_bulk, params: {
- users: [reject_me.id]
- }, format: :json
- end
-
- it "reports successes" do
- Guardian.any_instance.stubs(:can_delete_user?).returns(true)
- UserDestroyer.any_instance.stubs(:destroy).returns(true)
-
- delete :reject_bulk, params: {
- users: [reject_me.id, reject_me_too.id]
- }, format: :json
-
- expect(response).to be_success
- json = ::JSON.parse(response.body)
- expect(json['success'].to_i).to eq(2)
- expect(json['failed'].to_i).to eq(0)
- end
-
- context 'failures' do
- before do
- Guardian.any_instance.stubs(:can_delete_user?).returns(true)
- end
-
- it 'can handle some successes and some failures' do
- UserDestroyer.any_instance.stubs(:destroy).with(reject_me, anything).returns(false)
- UserDestroyer.any_instance.stubs(:destroy).with(reject_me_too, anything).returns(true)
-
- delete :reject_bulk, params: {
- users: [reject_me.id, reject_me_too.id]
- }, format: :json
-
- expect(response).to be_success
- json = ::JSON.parse(response.body)
- expect(json['success'].to_i).to eq(1)
- expect(json['failed'].to_i).to eq(1)
- end
-
- it 'reports failure due to a user still having posts' do
- UserDestroyer.any_instance.expects(:destroy).with(reject_me, anything).raises(UserDestroyer::PostsExistError)
-
- delete :reject_bulk, params: {
- users: [reject_me.id]
- }, format: :json
-
- expect(response).to be_success
- json = ::JSON.parse(response.body)
- expect(json['success'].to_i).to eq(0)
- expect(json['failed'].to_i).to eq(1)
- end
- end
- end
-
- context '#destroy' do
- let(:delete_me) { Fabricate(:user) }
-
- it "returns a 403 if the user doesn't exist" do
- delete :destroy, params: { id: 123123 }, format: :json
- expect(response).to be_forbidden
- end
-
- context "user has post" do
- let(:topic) { create_topic(user: delete_me) }
-
- before do
- _post = create_post(topic: topic, user: delete_me)
- end
-
- it "returns an api response that the user can't be deleted because it has posts" do
- delete :destroy, params: { id: delete_me.id }, format: :json
- expect(response).to be_forbidden
- json = ::JSON.parse(response.body)
- expect(json['deleted']).to eq(false)
- end
-
- 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
- end
- end
-
- it "deletes the user record" do
- UserDestroyer.any_instance.expects(:destroy).returns(true)
- delete :destroy, params: { id: delete_me.id }, format: :json
- end
- end
-
- context 'activate' do
- before do
- @reg_user = Fabricate(:inactive_user)
- end
-
- it "returns success" do
- put :activate, params: { user_id: @reg_user.id }, format: :json
- expect(response).to be_success
- json = ::JSON.parse(response.body)
- expect(json['success']).to eq("OK")
- end
-
- it "should confirm email even when the tokens are expired" do
- @reg_user.email_tokens.update_all(confirmed: false, expired: true)
-
- @reg_user.reload
- expect(@reg_user.email_confirmed?).to eq(false)
-
- put :activate, params: { user_id: @reg_user.id }, format: :json
- expect(response).to be_success
-
- @reg_user.reload
- expect(@reg_user.email_confirmed?).to eq(true)
- end
- end
-
- context 'log_out' do
- before do
- @reg_user = Fabricate(:user)
- end
-
- it "returns success" do
- put :log_out, params: { user_id: @reg_user.id }, format: :json
- expect(response).to be_success
- 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
- end
- end
-
- context 'silence' do
- before do
- @reg_user = Fabricate(:user)
- end
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_silence_user?).with(@reg_user).returns(false)
- put :silence, params: { user_id: @reg_user.id }, format: :json
- expect(response).to be_forbidden
- @reg_user.reload
- expect(@reg_user).not_to be_silenced
- end
-
- it "returns a 403 if the user doesn't exist" do
- put :silence, params: { user_id: 123123 }, format: :json
- expect(response).to be_forbidden
- end
-
- it "punishes the user for spamming" do
- put :silence, params: { user_id: @reg_user.id }, format: :json
- expect(response).to be_success
- @reg_user.reload
- expect(@reg_user).to be_silenced
- end
-
- it "can have an associated post" do
- silence_post = Fabricate(:post, user: @reg_user)
-
- put :silence, params: {
- user_id: @reg_user.id,
- post_id: silence_post.id,
- post_action: 'edit',
- post_edit: "this is the new contents for the post"
- }, format: :json
- expect(response).to be_success
-
- silence_post.reload
- expect(silence_post.raw).to eq("this is the new contents for the post")
-
- log = UserHistory.where(
- target_user_id: @reg_user.id,
- action: UserHistory.actions[:silence_user]
- ).first
- expect(log).to be_present
- expect(log.post_id).to eq(silence_post.id)
-
- @reg_user.reload
- expect(@reg_user).to be_silenced
- end
-
- it "will set a length of time if provided" do
- future_date = 1.month.from_now.to_date
- put(
- :silence,
- params: {
- user_id: @reg_user.id,
- silenced_till: future_date
- },
- format: :json
- )
- @reg_user.reload
- expect(@reg_user.silenced_till).to eq(future_date)
- end
-
- it "will send a message if provided" do
- Jobs.stubs(:enqueue)
- Jobs.expects(:enqueue).with(
- :critical_user_email,
- has_entries(
- type: :account_silenced,
- user_id: @reg_user.id
- )
- )
-
- put(
- :silence,
- params: {
- user_id: @reg_user.id,
- message: "Email this to the user"
- },
- format: :json
- )
- end
- end
-
- context 'unsilence' do
- before do
- @reg_user = Fabricate(:user)
- end
-
- it "raises an error when the user doesn't have permission" do
- Guardian.any_instance.expects(:can_unsilence_user?).with(@reg_user).returns(false)
- put :unsilence, params: { user_id: @reg_user.id }, format: :json
- expect(response).to be_forbidden
- end
-
- it "returns a 403 if the user doesn't exist" do
- put :unsilence, params: { user_id: 123123 }, format: :json
- expect(response).to be_forbidden
- end
-
- it "punishes the user for spamming" do
- UserSilencer.expects(:unsilence).with(@reg_user, @user, anything)
- put :unsilence, params: { user_id: @reg_user.id }, format: :json
- end
- end
-
- context 'ip-info' do
-
- it "uses ipinfo.io webservice to retrieve the info" do
- Excon.expects(:get).with("https://ipinfo.io/123.123.123.123/json", read_timeout: 10, connect_timeout: 10)
- get :ip_info, params: { ip: "123.123.123.123" }, format: :json
- end
-
- end
-
- context "delete_other_accounts_with_same_ip" do
-
- it "works" do
- Fabricate(:user, ip_address: "42.42.42.42")
- Fabricate(:user, ip_address: "42.42.42.42")
-
- UserDestroyer.any_instance.expects(:destroy).twice
-
- delete :delete_other_accounts_with_same_ip, params: {
- ip: "42.42.42.42", exclude: -1, order: "trust_level DESC"
- }, format: :json
- end
-
- end
-
- context ".invite_admin" do
- it "doesn't work when not via API" do
- controller.stubs(:is_api?).returns(false)
-
- post :invite_admin, params: {
- name: 'Bill', username: 'bill22', email: 'bill@bill.com'
- }, format: :json
-
- expect(response).not_to be_success
- end
-
- it 'should invite admin' do
- controller.stubs(:is_api?).returns(true)
- Jobs.expects(:enqueue).with(:critical_user_email, anything).returns(true)
-
- post :invite_admin, params: {
- name: 'Bill', username: 'bill22', email: 'bill@bill.com'
- }, format: :json
-
- expect(response).to be_success
-
- u = User.find_by_email('bill@bill.com')
- expect(u.name).to eq("Bill")
- expect(u.username).to eq("bill22")
- expect(u.admin).to eq(true)
- end
-
- it "doesn't send the email with send_email falsy" do
- controller.stubs(:is_api?).returns(true)
- Jobs.expects(:enqueue).with(:user_email, anything).never
-
- post :invite_admin, params: {
- name: 'Bill', username: 'bill22', email: 'bill@bill.com', send_email: '0'
- }, format: :json
-
- expect(response).to be_success
- json = ::JSON.parse(response.body)
- expect(json["password_url"]).to be_present
- end
- end
-
- context 'remove_group' do
- it "also clears the user's primary group" do
- g = Fabricate(:group)
- u = Fabricate(:user, primary_group: g)
- delete :remove_group, params: { group_id: g.id, user_id: u.id }, format: :json
-
- expect(u.reload.primary_group).to be_nil
- end
- end
- end
-
- context '#sync_sso' do
- let(:sso) { SingleSignOn.new }
- let(:sso_secret) { "sso secret" }
-
- before do
- log_in(:admin)
-
- SiteSetting.email_editable = false
- SiteSetting.sso_url = "https://www.example.com/sso"
- SiteSetting.enable_sso = true
- SiteSetting.sso_overrides_email = true
- SiteSetting.sso_overrides_name = true
- SiteSetting.sso_overrides_username = true
- SiteSetting.sso_secret = sso_secret
- sso.sso_secret = sso_secret
- end
-
- it 'can sync up with the sso' do
- sso.name = "Bob The Bob"
- sso.username = "bob"
- sso.email = "bob@bob.com"
- sso.external_id = "1"
-
- user = DiscourseSingleSignOn.parse(sso.payload)
- .lookup_or_create_user
-
- sso.name = "Bill"
- sso.username = "Hokli$$!!"
- sso.email = "bob2@bob.com"
-
- post :sync_sso, params: Rack::Utils.parse_query(sso.payload), format: :json
- expect(response).to be_success
-
- user.reload
- expect(user.email).to eq("bob2@bob.com")
- expect(user.name).to eq("Bill")
- expect(user.username).to eq("Hokli")
- end
-
- it 'should create new users' do
- sso.name = "Dr. Claw"
- sso.username = "dr_claw"
- 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
-
- user = User.find_by_email('dr@claw.com')
- expect(user).to be_present
- expect(user.ip_address).to be_blank
- end
-
- it 'should return the right message if the record is invalid' do
- sso.email = ""
- sso.name = ""
- sso.external_id = "1"
-
- post :sync_sso, params: Rack::Utils.parse_query(sso.payload), format: :json
- expect(response.status).to eq(403)
- expect(JSON.parse(response.body)["message"]).to include("Primary email can't be blank")
- end
- end
-end
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/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/controllers/composer_messages_controller_spec.rb b/spec/controllers/composer_messages_controller_spec.rb
deleted file mode 100644
index c2333fa33f..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_success
- 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/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/controllers/export_csv_controller_spec.rb b/spec/controllers/export_csv_controller_spec.rb
deleted file mode 100644
index 2e1256653c..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_success
- 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
- 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
- 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_success
- 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
- end
- end
- end
-end
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/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/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/controllers/post_actions_controller_spec.rb b/spec/controllers/post_actions_controller_spec.rb
deleted file mode 100644
index 0994fc601d..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_success
- 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_success
- 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_success
- end
-
- end
-
- end
-
- end
-
-end
diff --git a/spec/controllers/queued_posts_controller_spec.rb b/spec/controllers/queued_posts_controller_spec.rb
deleted file mode 100644
index ac88c50479..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_success
- 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_success
- 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_success
- 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_success
-
- 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_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) }
-
- before do
- put :update, params: {
- id: queued_topic.id, queued_post: changes
- }, format: :json
-
- expect(response).to be_success
- 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_success
- 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/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/controllers/steps_controller_spec.rb b/spec/controllers/steps_controller_spec.rb
deleted file mode 100644
index ec1f7fd608..0000000000
--- a/spec/controllers/steps_controller_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-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
- expect(response.status).to eq(403)
- end
-
- it "raises an error if you aren't an admin" do
- log_in(:moderator)
-
- put :update, params: {
- id: 'made-up-id', fields: { forum_title: "updated title" }
- }, format: :json
-
- expect(response).to be_forbidden
- end
-
- context "as an admin" do
- before do
- log_in(: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
- 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
-
- expect(response).to be_success
- 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
-
- expect(response).to_not be_success
- end
- end
-
-end
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/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/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
deleted file mode 100644
index a98cd9ebe7..0000000000
--- a/spec/controllers/uploads_controller_spec.rb
+++ /dev/null
@@ -1,250 +0,0 @@
-require 'rails_helper'
-
-describe UploadsController do
-
- context '.create' do
-
- it 'requires you to be logged in' do
- post :create, format: :json
- expect(response.status).to eq(403)
- end
-
- context 'logged in' do
-
- before { @user = log_in :user }
-
- let(:logo) do
- Rack::Test::UploadedFile.new(file_from_fixtures("logo.png"))
- end
-
- let(:fake_jpg) do
- Rack::Test::UploadedFile.new(file_from_fixtures("fake.jpg"))
- end
-
- let(:text_file) do
- Rack::Test::UploadedFile.new(File.new("#{Rails.root}/LICENSE.txt"))
- 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)
- 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 }
-
- expect(response.status).to eq 200
- expect(JSON.parse(response.body)["id"]).to be
- 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 }
-
- expect(response.status).to eq 200
- 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)
-
- 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 }
-
- json = ::JSON.parse(response.body)
-
- expect(response.status).to eq 200
- expect(json["id"]).to be
- 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
-
- post :create, params: {
- file: logo,
- retain_hours: 100,
- type: "profile_background",
- format: :json
- }
-
- id = JSON.parse(response.body)["id"]
- 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 }
-
- 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.max_attachment_size_kb = 1
-
- Jobs.expects(:enqueue).never
-
- post :create, params: { file: text_file, type: "avatar", format: :json }
-
- expect(response.status).to eq 422
- errors = JSON.parse(response.body)["errors"]
- expect(errors).to be
- 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
- 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
- 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)
-
- post :create, 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
- 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)
-
- post :create, params: {
- file: text_file,
- type: "composer",
- format: :json
- }
-
- expect(response).to be_success
- data = JSON.parse(response.body)
- expect(data["id"]).to be
- 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: {
- file: text_file,
- type: "composer",
- format: :json
- }
-
- data = JSON.parse(response.body)
- expect(data["errors"].first).to eq(I18n.t("upload.unauthorized", authorized_extensions: ''))
- 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 :create, params: { file: fake_jpg, type: "composer", format: :json }
-
- expect(response.status).to eq 422
- message = JSON.parse(response.body)["errors"]
- expect(message).to contain_exactly(I18n.t("upload.images.size_not_found"))
- end
-
- end
-
- end
-
- context '.show' do
-
- let(:site) { "default" }
- let(:sha) { Digest::SHA1.hexdigest("discourse") }
-
- it "returns 404 when using external storage" do
- store = stub(internal?: false)
- Discourse.stubs(:store).returns(store)
- Upload.expects(:find_by).never
-
- get :show, params: { site: site, sha: sha, extension: "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)
- 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" }
- 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)
-
- get :show, params: { site: site, sha: sha, format: :json }
- expect(response).to be_success
- 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
-
- get :show, params: { site: site, sha: sha, extension: "pdf", format: :json }
- expect(response.response_code).to eq(404)
- end
-
- end
-
- 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/fixtures/images/image_no_extension b/spec/fixtures/images/image_no_extension
new file mode 100644
index 0000000000..5c900b61f7
Binary files /dev/null and b/spec/fixtures/images/image_no_extension differ
diff --git a/spec/integrity/onceoff_integrity_spec.rb b/spec/integrity/onceoff_integrity_spec.rb
new file mode 100644
index 0000000000..8143fe7946
--- /dev/null
+++ b/spec/integrity/onceoff_integrity_spec.rb
@@ -0,0 +1,14 @@
+require "rails_helper"
+
+describe Jobs::Onceoff do
+ it "can run all once off jobs without errors" do
+ # load all once offs
+
+ Dir[Rails.root + 'app/jobs/onceoff/*.rb'].each do |f|
+ require_relative '../../app/jobs/onceoff/' + File.basename(f)
+ end
+ ObjectSpace.each_object(Class).select { |klass| klass < Jobs::Onceoff }.each do |j|
+ j.new.execute_onceoff(nil)
+ end
+ end
+end
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
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
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)
diff --git a/spec/jobs/toggle_topic_closed_spec.rb b/spec/jobs/toggle_topic_closed_spec.rb
index 77e1afbe08..24b9d3c307 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
@@ -28,7 +28,7 @@ describe Jobs::ToggleTopicClosed do
it 'should be work' do
topic.update!(closed: true)
- 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: false
@@ -37,7 +37,7 @@ describe Jobs::ToggleTopicClosed do
expect(topic.reload.closed).to eq(false)
expect(Post.last.raw).to eq(I18n.t(
- 'topic_statuses.autoclosed_disabled_minutes', count: 60
+ 'topic_statuses.autoclosed_disabled_minutes', count: 61
))
end
end
@@ -53,7 +53,7 @@ describe Jobs::ToggleTopicClosed do
user: admin
)
- 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: false
diff --git a/spec/mailers/user_notifications_spec.rb b/spec/mailers/user_notifications_spec.rb
index bb8118d499..53ca30b5b5 100644
--- a/spec/mailers/user_notifications_spec.rb
+++ b/spec/mailers/user_notifications_spec.rb
@@ -440,7 +440,7 @@ describe UserNotifications do
notification_data_hash: notification.data_hash
)
- expect(mail.body).to include("#{I18n.t("user_notifications.pm_participants")} [group1 (2)](http://test.localhost/groups/group1), [group2 (1)](http://test.localhost/groups/group2), [one](http://test.localhost/u/one), [two](http://test.localhost/u/two)")
+ expect(mail.body).to include("[group1 (2)](http://test.localhost/groups/group1), [group2 (1)](http://test.localhost/groups/group2), [one](http://test.localhost/u/one), [two](http://test.localhost/u/two)")
end
context "when SiteSetting.group_name_in_subject is true" do
diff --git a/spec/models/discourse_single_sign_on_spec.rb b/spec/models/discourse_single_sign_on_spec.rb
index 8d7ddf0a3e..2aa6e6d520 100644
--- a/spec/models/discourse_single_sign_on_spec.rb
+++ b/spec/models/discourse_single_sign_on_spec.rb
@@ -2,7 +2,7 @@ require "rails_helper"
describe DiscourseSingleSignOn do
before do
- @sso_url = "http://somesite.com/discourse_sso"
+ @sso_url = "http://example.com/discourse_sso"
@sso_secret = "shjkfdhsfkjh"
SiteSetting.sso_url = @sso_url
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 4027250bef..30a3ba3f42 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -406,7 +406,7 @@ describe Group do
user = Fabricate(:user)
user.change_trust_level!(TrustLevel[2])
- Group.exec_sql("UPDATE groups SET user_count = 0 WHERE id = #{Group::AUTO_GROUPS[:trust_level_2]}")
+ DB.exec("UPDATE groups SET user_count = 0 WHERE id = #{Group::AUTO_GROUPS[:trust_level_2]}")
Group.refresh_automatic_groups!
diff --git a/spec/models/incoming_link_spec.rb b/spec/models/incoming_link_spec.rb
index 00e3b9825c..c44fa14fcd 100644
--- a/spec/models/incoming_link_spec.rb
+++ b/spec/models/incoming_link_spec.rb
@@ -69,7 +69,7 @@ describe IncomingLink do
end
it "does nothing if referer is same as host" do
- add(post_id: 1, host: 'somesite.com', referer: 'http://somesite.com')
+ add(post_id: 1, host: 'example.com', referer: 'http://example.com')
expect(IncomingLink.count).to eq 0
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/post_spec.rb b/spec/models/post_spec.rb
index 8a7d577684..9c89c807dd 100644
--- a/spec/models/post_spec.rb
+++ b/spec/models/post_spec.rb
@@ -452,6 +452,13 @@ describe Post do
post_two_links.user.trust_level = TrustLevel[1]
expect(post_one_link).not_to be_valid
end
+
+ it "will skip the check for whitelisted domains" do
+ SiteSetting.whitelisted_link_domains = 'www.bbc.co.uk'
+ SiteSetting.min_trust_to_post_links = 2
+ post_two_links.user.trust_level = TrustLevel[1]
+ expect(post_one_link).to be_valid
+ end
end
end
@@ -798,12 +805,13 @@ describe Post do
let!(:p1) { Fabricate(:post, post_args.merge(score: 4, percent_rank: 0.33)) }
let!(:p2) { Fabricate(:post, post_args.merge(score: 10, percent_rank: 0.66)) }
let!(:p3) { Fabricate(:post, post_args.merge(score: 5, percent_rank: 0.99)) }
+ let!(:p4) { Fabricate(:post, percent_rank: 0.99) }
it "returns the OP and posts above the threshold in summary mode" do
SiteSetting.summary_percent_filter = 66
- expect(Post.summary.order(:post_number)).to eq([p1, p2])
+ expect(Post.summary(topic.id).order(:post_number)).to eq([p1, p2])
+ expect(Post.summary(p4.topic.id)).to eq([p4])
end
-
end
context 'sort_order' do
@@ -935,12 +943,12 @@ describe Post do
end
describe "has_host_spam" do
- let(:raw) { "hello from my site http://www.somesite.com http://#{GlobalSetting.hostname} http://#{RailsMultisite::ConnectionManagement.current_hostname}" }
+ let(:raw) { "hello from my site http://www.example.net http://#{GlobalSetting.hostname} http://#{RailsMultisite::ConnectionManagement.current_hostname}" }
it "correctly detects host spam" do
post = Fabricate(:post, raw: raw)
- expect(post.total_hosts_usage).to eq("www.somesite.com" => 1)
+ expect(post.total_hosts_usage).to eq("www.example.net" => 1)
post.acting_user.trust_level = 0
expect(post.has_host_spam?).to eq(false)
@@ -949,7 +957,7 @@ describe Post do
expect(post.has_host_spam?).to eq(true)
- SiteSetting.white_listed_spam_host_domains = "bla.com|boo.com | somesite.com "
+ SiteSetting.white_listed_spam_host_domains = "bla.com|boo.com | example.net "
expect(post.has_host_spam?).to eq(false)
end
@@ -960,6 +968,26 @@ describe Post do
expect(post.has_host_spam?).to eq(false)
end
+ it "punishes previously staged users that were created within 1 day" do
+ SiteSetting.newuser_spam_host_threshold = 1
+ SiteSetting.newuser_max_links = 3
+ user = Fabricate(:user, staged: true, trust_level: 0)
+ user.created_at = 1.hour.ago
+ user.unstage
+ post = Fabricate(:post, raw: raw, user: user)
+ expect(post.has_host_spam?).to eq(true)
+ end
+
+ it "doesn't punish previously staged users over 1 day old" do
+ SiteSetting.newuser_spam_host_threshold = 1
+ SiteSetting.newuser_max_links = 3
+ user = Fabricate(:user, staged: true, trust_level: 0)
+ user.created_at = 1.day.ago
+ user.unstage
+ post = Fabricate(:post, raw: raw, user: user)
+ expect(post.has_host_spam?).to eq(false)
+ end
+
it "ignores private messages" do
SiteSetting.newuser_spam_host_threshold = 1
user = Fabricate(:user, trust_level: 0)
@@ -987,7 +1015,7 @@ describe Post do
first_baked = post.baked_at
first_cooked = post.cooked
- Post.exec_sql("UPDATE posts SET cooked = 'frogs' WHERE id = ?", post.id)
+ DB.exec("UPDATE posts SET cooked = 'frogs' WHERE id = ?", [ post.id ])
post.reload
post.expects(:publish_change_to_clients!).with(:rebaked)
diff --git a/spec/models/queued_post_spec.rb b/spec/models/queued_post_spec.rb
index b6e5113efe..5616ef41a0 100644
--- a/spec/models/queued_post_spec.rb
+++ b/spec/models/queued_post_spec.rb
@@ -86,6 +86,11 @@ describe QueuedPost do
# It removes the pending action
expect(UserAction.where(queued_post_id: qp.id).count).to eq(0)
+ # 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)
end
diff --git a/spec/models/search_log_spec.rb b/spec/models/search_log_spec.rb
index 8811fca9ab..af9069b16d 100644
--- a/spec/models/search_log_spec.rb
+++ b/spec/models/search_log_spec.rb
@@ -101,7 +101,7 @@ RSpec.describe SearchLog, type: :model do
log = SearchLog.find(log_id)
expect(log.term).to eq('hello')
expect(log.search_type).to eq(SearchLog.search_types[:full_page])
- expect(log.ip_address).to eq('192.168.0.1')
+ expect(log.ip_address).to eq(nil)
expect(log.user_id).to eq(user.id)
action, updated_log_id = SearchLog.log(
@@ -183,11 +183,12 @@ RSpec.describe SearchLog, type: :model do
end
context "trending" do
+ let(:user) { Fabricate(:user) }
before do
SearchLog.log(term: 'ruby', search_type: :header, ip_address: '127.0.0.1')
SearchLog.log(term: 'php', search_type: :header, ip_address: '127.0.0.1')
SearchLog.log(term: 'java', search_type: :header, ip_address: '127.0.0.1')
- SearchLog.log(term: 'ruby', search_type: :header, ip_address: '127.0.0.1', user_id: Fabricate(:user).id)
+ SearchLog.log(term: 'ruby', search_type: :header, ip_address: '127.0.0.1', user_id: user.id)
SearchLog.log(term: 'swift', search_type: :header, ip_address: '127.0.0.1')
SearchLog.log(term: 'ruby', search_type: :header, ip_address: '127.0.0.2')
end
@@ -207,6 +208,7 @@ RSpec.describe SearchLog, type: :model do
expect(top_trending.click_through).to eq(0)
SearchLog.where(term: 'ruby', ip_address: '127.0.0.1').update_all(search_result_id: 12)
+ SearchLog.where(term: 'ruby', user_id: user.id).update_all(search_result_id: 12)
SearchLog.where(term: 'ruby', ip_address: '127.0.0.2').update_all(search_result_id: 24)
top_trending = SearchLog.trending.first
expect(top_trending.click_through).to eq(3)
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_link_spec.rb b/spec/models/topic_link_spec.rb
index 606ba5f7ba..d3d53a0728 100644
--- a/spec/models/topic_link_spec.rb
+++ b/spec/models/topic_link_spec.rb
@@ -330,7 +330,7 @@ http://b.com/#{'a' * 500}
array = TopicLink.topic_map(Guardian.new, post.topic_id)
expect(array.length).to eq(6)
- expect(array[0]["clicks"]).to eq(1)
+ expect(array[0].clicks).to eq(1)
end
it 'secures internal links correctly' do
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..b702f9a77e 100644
--- a/spec/models/topic_timer_spec.rb
+++ b/spec/models/topic_timer_spec.rb
@@ -1,10 +1,23 @@
require 'rails_helper'
RSpec.describe TopicTimer, type: :model do
- let(:topic_timer) { Fabricate(:topic_timer) }
+ let(:topic_timer) {
+ # we should not need to do this but somehow
+ # fabricator is failing here
+ TopicTimer.create!(
+ user_id: -1,
+ topic: Fabricate(:topic),
+ execute_at: 1.hour.from_now,
+ status_type: TopicTimer.types[:close]
+ )
+ }
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/models/topic_user_spec.rb b/spec/models/topic_user_spec.rb
index c0ed6c986b..ed9de27c3a 100644
--- a/spec/models/topic_user_spec.rb
+++ b/spec/models/topic_user_spec.rb
@@ -311,8 +311,10 @@ describe TopicUser do
it 'should update tracking state when you reply' do
new_user.user_option.update_column(:notification_level_when_replying, 3)
post_creator.create
- TopicUser.exec_sql("UPDATE topic_users set notification_level=2
- WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: topic_new_user.topic_id, user_id: topic_new_user.user_id)
+ DB.exec("UPDATE topic_users set notification_level=2
+ WHERE topic_id = :topic_id AND user_id = :user_id",
+ topic_id: topic_new_user.topic_id, user_id: topic_new_user.user_id)
+
TopicUser.auto_notification(topic_new_user.user_id, topic_new_user.topic_id, TopicUser.notification_reasons[:created_post], TopicUser.notification_levels[:watching])
tu = TopicUser.find_by(user_id: topic_new_user.user_id, topic_id: topic_new_user.topic_id)
@@ -322,7 +324,7 @@ describe TopicUser do
it 'should not update tracking state when you reply' do
new_user.user_option.update_column(:notification_level_when_replying, 3)
post_creator.create
- TopicUser.exec_sql("UPDATE topic_users set notification_level=3
+ DB.exec("UPDATE topic_users set notification_level=3
WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: topic_new_user.topic_id, user_id: topic_new_user.user_id)
TopicUser.auto_notification(topic_new_user.user_id, topic_new_user.topic_id, TopicUser.notification_reasons[:created_post], TopicUser.notification_levels[:tracking])
@@ -333,7 +335,7 @@ describe TopicUser do
it 'should not update tracking state when state manually set to normal you reply' do
new_user.user_option.update_column(:notification_level_when_replying, 3)
post_creator.create
- TopicUser.exec_sql("UPDATE topic_users set notification_level=1
+ DB.exec("UPDATE topic_users set notification_level=1
WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: topic_new_user.topic_id, user_id: topic_new_user.user_id)
TopicUser.auto_notification(topic_new_user.user_id, topic_new_user.topic_id, TopicUser.notification_reasons[:created_post], TopicUser.notification_levels[:tracking])
@@ -344,7 +346,7 @@ describe TopicUser do
it 'should not update tracking state when state manually set to muted you reply' do
new_user.user_option.update_column(:notification_level_when_replying, 3)
post_creator.create
- TopicUser.exec_sql("UPDATE topic_users set notification_level=0
+ DB.exec("UPDATE topic_users set notification_level=0
WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: topic_new_user.topic_id, user_id: topic_new_user.user_id)
TopicUser.auto_notification(topic_new_user.user_id, topic_new_user.topic_id, TopicUser.notification_reasons[:created_post], TopicUser.notification_levels[:tracking])
@@ -417,7 +419,7 @@ describe TopicUser do
p2 = Fabricate(:post, user: p1.user, topic: p1.topic, post_number: 2)
p1.topic.notifier.watch_topic!(p1.user_id)
- TopicUser.exec_sql("UPDATE topic_users set highest_seen_post_number=1, last_read_post_number=0
+ DB.exec("UPDATE topic_users set highest_seen_post_number=1, last_read_post_number=0
WHERE topic_id = :topic_id AND user_id = :user_id", topic_id: p1.topic_id, user_id: p1.user_id)
[p1, p2].each do |p|
diff --git a/spec/models/topic_view_item_spec.rb b/spec/models/topic_view_item_spec.rb
index d811a56c40..da0762d871 100644
--- a/spec/models/topic_view_item_spec.rb
+++ b/spec/models/topic_view_item_spec.rb
@@ -27,4 +27,14 @@ describe TopicViewItem do
expect(user.user_stat.topics_entered).to eq(1)
end
+ it "does not log IP address for logged-in users" do
+ topic = Fabricate(:topic)
+ user = Fabricate(:user)
+ add(topic.id, "1.1.1.1", user.id)
+
+ expect(TopicViewItem.find_by(topic_id: topic.id, user_id: user.id).ip_address).to eq(nil)
+ add(topic.id, "1.2.3.4", nil)
+ expect(TopicViewItem.find_by(topic_id: topic.id, user_id: nil).ip_address).to eq("1.2.3.4")
+ end
+
end
diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb
index 32b86bbc18..697cd266ee 100644
--- a/spec/models/upload_spec.rb
+++ b/spec/models/upload_spec.rb
@@ -106,6 +106,13 @@ describe Upload do
SiteSetting.enable_s3_uploads = false
end
+ it "should return the right upload when using base url (not CDN) for s3" do
+ upload
+ url = "https://#{SiteSetting.s3_upload_bucket}.s3.amazonaws.com#{path}"
+
+ expect(Upload.get_from_url(url)).to eq(upload)
+ end
+
it "should return the right upload when using a CDN for s3" do
upload
s3_cdn_url = 'https://mycdn.slowly.net'
diff --git a/spec/models/user_action_spec.rb b/spec/models/user_action_spec.rb
index 6ab8a1537a..9a172ded34 100644
--- a/spec/models/user_action_spec.rb
+++ b/spec/models/user_action_spec.rb
@@ -43,7 +43,7 @@ describe UserAction do
end
def stats_for_user(viewer = nil)
- UserAction.stats(user.id, Guardian.new(viewer)).map { |r| r["action_type"].to_i }.sort
+ UserAction.stats(user.id, Guardian.new(viewer)).map { |r| r.action_type.to_i }.sort
end
def stream(viewer = nil)
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
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 ")
+ expect(user.user_profile.bio_excerpt(500, keep_emoji_images: true)).to eq("hello ")
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 f86eb06bc6..96495386b6 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -131,6 +131,8 @@ RSpec.configure do |config|
x.exception.cause = ex
end
end
+
+ unfreeze_time
end
config.before :each do |x|
@@ -153,15 +155,10 @@ 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
- # 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
diff --git a/spec/requests/about_controller_spec.rb b/spec/requests/about_controller_spec.rb
index e4e4b01a0a..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_success
+ 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_success
+ expect(response.status).to eq(200)
end
end
end
diff --git a/spec/requests/admin/admin_controller_spec.rb b/spec/requests/admin/admin_controller_spec.rb
index c479ada153..062f3a3a0e 100644
--- a/spec/requests/admin/admin_controller_spec.rb
+++ b/spec/requests/admin/admin_controller_spec.rb
@@ -1,11 +1,19 @@
require 'rails_helper'
RSpec.describe Admin::AdminController do
- it "should return the right response if user isn't a staff" do
- get "/admin", params: { api_key: 'asdiasiduga' }
- expect(response.status).to eq(404)
+ describe '#index' do
+ it "needs you to be logged in" do
+ get "/admin.json"
+ expect(response.status).to eq(404)
+ end
- get "/admin"
- expect(response.status).to eq(404)
+ it "should return the right response if user isn't a staff" do
+ sign_in(Fabricate(:user))
+ get "/admin", params: { api_key: 'asdiasiduga' }
+ expect(response.status).to eq(404)
+
+ get "/admin"
+ expect(response.status).to eq(404)
+ end
end
end
diff --git a/spec/requests/admin/api_controller_spec.rb b/spec/requests/admin/api_controller_spec.rb
new file mode 100644
index 0000000000..feee32728b
--- /dev/null
+++ b/spec/requests/admin/api_controller_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+describe Admin::ApiController do
+
+ it "is a subclass of AdminController" do
+ expect(Admin::ApiController < Admin::AdminController).to eq(true)
+ end
+
+ let(:admin) { Fabricate(:admin) }
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
+ it "succeeds" do
+ get "/admin/api/keys.json"
+ expect(response.status).to eq(200)
+ end
+ end
+
+ describe '#regenerate_key' do
+ let(:api_key) { Fabricate(:api_key) }
+
+ it "returns 404 when there is no key" do
+ put "/admin/api/key.json", params: { id: 1234 }
+ expect(response.status).to eq(404)
+ end
+
+ it "delegates to the api key's `regenerate!` method" do
+ prev_value = api_key.key
+ put "/admin/api/key.json", params: { id: api_key.id }
+ expect(response.status).to eq(200)
+
+ api_key.reload
+ expect(api_key.key).not_to eq(prev_value)
+ expect(api_key.created_by.id).to eq(admin.id)
+ end
+ end
+
+ describe '#revoke_key' do
+ let(:api_key) { Fabricate(:api_key) }
+
+ it "returns 404 when there is no key" do
+ delete "/admin/api/key.json", params: { id: 1234 }
+ expect(response.status).to eq(404)
+ end
+
+ it "delegates to the api key's `regenerate!` method" do
+ delete "/admin/api/key.json", params: { id: api_key.id }
+ expect(response.status).to eq(200)
+ expect(ApiKey.where(key: api_key.key).count).to eq(0)
+ end
+ end
+
+ describe '#create_master_key' do
+ it "creates a record" do
+ expect do
+ post "/admin/api/key.json"
+ end.to change(ApiKey, :count).by(1)
+ 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 7504cb31c3..4224bcb07b 100644
--- a/spec/requests/admin/backups_controller_spec.rb
+++ b/spec/requests/admin/backups_controller_spec.rb
@@ -2,16 +2,254 @@ require 'rails_helper'
RSpec.describe Admin::BackupsController do
let(:admin) { Fabricate(:admin) }
+ let(:backup_filename) { "2014-02-10-065935.tar.gz" }
+ let(:backup_filename2) { "2014-02-11-065935.tar.gz" }
+
+ it "is a subclass of AdminController" do
+ expect(Admin::BackupsController < Admin::AdminController).to eq(true)
+ end
before do
sign_in(admin)
end
+ after do
+ $redis.flushall
+ end
+
describe "#index" 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.status).to eq(403)
+ end
+
+ context "html format" do
+ it "preloads important data" do
+ get "/admin/backups.html"
+ expect(response.status).to eq(200)
+
+ preloaded = controller.instance_variable_get("@preloaded").map do |key, value|
+ [key, JSON.parse(value)]
+ end.to_h
+
+ expect(preloaded["backups"].size).to eq(Backup.all.size)
+ expect(preloaded["operations_status"].symbolize_keys).to eq(BackupRestore.operations_status)
+ expect(preloaded["logs"].size).to eq(BackupRestore.logs.size)
+ end
+ end
+
+ context "json format" do
+ it "returns a list of all the backups" do
+ begin
+ paths = []
+ [backup_filename, backup_filename2].each do |name|
+ path = File.join(Backup.base_directory, name)
+ paths << path
+ File.open(path, "w") { |f| f.write("hello") }
+ Backup.create_from_filename(name)
+ end
+
+ get "/admin/backups.json"
+
+ expect(response.status).to eq(200)
+
+ json = JSON.parse(response.body).map { |backup| backup["filename"] }
+ expect(json).to include(backup_filename)
+ expect(json).to include(backup_filename2)
+ ensure
+ paths.each { |path| File.delete(path) }
+ end
+ end
+ end
+ end
+
+ describe '#status' do
+ it "returns the current backups status" do
+ get "/admin/backups/status.json"
+ expect(response.body).to eq(BackupRestore.operations_status.to_json)
+ expect(response.status).to eq(200)
+ end
+ end
+
+ describe '#create' do
+ it "starts a backup" do
+ BackupRestore.expects(:backup!).with(admin.id, publish_to_message_bus: true, with_uploads: false, client_id: "foo")
+
+ post "/admin/backups.json", params: {
+ with_uploads: false, client_id: "foo"
+ }
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ describe '#show' do
+ it "uses send_file to transmit the backup" do
+ begin
+ token = EmailBackupToken.set(admin.id)
+ path = File.join(Backup.base_directory, backup_filename)
+ File.open(path, "w") { |f| f.write("hello") }
+
+ Backup.create_from_filename(backup_filename)
+
+ expect do
+ get "/admin/backups/#{backup_filename}.json", params: { token: token }
+ end.to change { UserHistory.where(action: UserHistory.actions[:backup_download]).count }.by(1)
+
+ expect(response.headers['Content-Length']).to eq("5")
+ expect(response.headers['Content-Disposition']).to match(/attachment; filename/)
+ ensure
+ File.delete(path)
+ EmailBackupToken.del(admin.id)
+ end
+ end
+
+ it "returns 422 when token is bad" do
+ begin
+ path = File.join(Backup.base_directory, backup_filename)
+ File.open(path, "w") { |f| f.write("hello") }
+
+ Backup.create_from_filename(backup_filename)
+
+ get "/admin/backups/#{backup_filename}.json", params: { token: "bad_value" }
+
+ expect(response.status).to eq(422)
+ expect(response.headers['Content-Disposition']).not_to match(/attachment; filename/)
+ ensure
+ File.delete(path)
+ end
+ end
+
+ it "returns 404 when the backup does not exist" do
+ token = EmailBackupToken.set(admin.id)
+ get "/admin/backups/#{backup_filename}.json", params: { token: token }
+
+ EmailBackupToken.del(admin.id)
+ expect(response.status).to eq(404)
+ end
+ end
+
+ describe '#destroy' do
+ let(:b) { Backup.new(backup_filename) }
+
+ it "removes the backup if found" do
+ begin
+ path = File.join(Backup.base_directory, backup_filename)
+ File.open(path, "w") { |f| f.write("hello") }
+
+ Backup.create_from_filename(backup_filename)
+
+ expect do
+ delete "/admin/backups/#{backup_filename}.json"
+ end.to change { UserHistory.where(action: UserHistory.actions[:backup_destroy]).count }.by(1)
+
+ expect(response.status).to eq(200)
+ expect(File.exists?(path)).to eq(false)
+ ensure
+ File.delete(path) if File.exists?(path)
+ end
+ end
+
+ it "doesn't remove the backup if not found" do
+ delete "/admin/backups/#{backup_filename}.json"
+ expect(response.status).to eq(404)
+ end
+ end
+
+ describe '#logs' do
+ it "preloads important data" do
+ get "/admin/backups/logs.html"
+ expect(response.status).to eq(200)
+
+ preloaded = controller.instance_variable_get("@preloaded").map do |key, value|
+ [key, JSON.parse(value)]
+ end.to_h
+
+ expect(preloaded["operations_status"].symbolize_keys).to eq(BackupRestore.operations_status)
+ expect(preloaded["logs"].size).to eq(BackupRestore.logs.size)
+ end
+ end
+
+ describe '#restore' do
+ it "starts a restore" do
+ 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 "/admin/backups/#{backup_filename}/restore.json", params: { client_id: "foo" }
+
+ expect(SiteSetting.disable_emails).to eq("yes")
+ expect(response.status).to eq(200)
+ end
+ end
+
+ describe '#readonly' do
+ it "enables readonly mode" do
+ expect(Discourse.readonly_mode?).to eq(false)
+
+ expect { put "/admin/backups/readonly.json", params: { enable: true } }
+ .to change { UserHistory.where(action: UserHistory.actions[:change_readonly_mode], new_value: "t").count }.by(1)
+
+ expect(Discourse.readonly_mode?).to eq(true)
+ expect(response.status).to eq(200)
+ end
+
+ it "disables readonly mode" do
+ Discourse.enable_readonly_mode(Discourse::USER_READONLY_MODE_KEY)
+ expect(Discourse.readonly_mode?).to eq(true)
+
+ expect { put "/admin/backups/readonly.json", params: { enable: false } }
+ .to change { UserHistory.where(action: UserHistory.actions[:change_readonly_mode], new_value: "f").count }.by(1)
+
+ expect(response.status).to eq(200)
+ expect(Discourse.readonly_mode?).to eq(false)
+ end
+ end
+
+ describe "#upload_backup_chunk" do
+ describe "when filename contains invalid characters" do
+ it "should raise an error" do
+ ['灰色.tar.gz', '; echo \'haha\'.tar.gz'].each do |invalid_filename|
+ described_class.any_instance.expects(:has_enough_space_on_disk?).returns(true)
+
+ post "/admin/backups/upload", params: {
+ resumableFilename: invalid_filename, resumableTotalSize: 1
+ }
+
+ expect(response.status).to eq(415)
+ expect(response.body).to eq(I18n.t('backup.invalid_filename'))
+ end
+ end
+ end
+
+ describe "when filename is valid" do
+ it "should upload the file successfully" do
+ begin
+ described_class.any_instance.expects(:has_enough_space_on_disk?).returns(true)
+
+ filename = 'test_Site-0123456789.tar.gz'
+
+ post "/admin/backups/upload.json", params: {
+ resumableFilename: filename,
+ resumableTotalSize: 1,
+ resumableIdentifier: 'test',
+ resumableChunkNumber: '1',
+ resumableChunkSize: '1',
+ resumableCurrentChunkSize: '1',
+ file: fixture_file_upload(Tempfile.new)
+ }
+
+ expect(response.status).to eq(200)
+ expect(response.body).to eq("")
+ ensure
+ begin
+ File.delete(
+ File.join(Backup.base_directory, 'tmp', 'test', "#{filename}.part1")
+ )
+ rescue Errno::ENOENT
+ end
+ end
+ end
end
end
@@ -21,7 +259,7 @@ RSpec.describe Admin::BackupsController do
post "/admin/backups/rollback.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
end
it 'should not allow rollback via a GET request' do
@@ -36,7 +274,7 @@ RSpec.describe Admin::BackupsController do
delete "/admin/backups/cancel.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
end
it 'should not allow cancel via a GET request' do
@@ -59,7 +297,7 @@ RSpec.describe Admin::BackupsController do
put "/admin/backups/#{backup_filename}.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
end
it "returns 404 when the backup does not exist" do
@@ -67,6 +305,5 @@ RSpec.describe Admin::BackupsController do
expect(response).to be_not_found
end
-
end
end
diff --git a/spec/controllers/admin/badges_controller_spec.rb b/spec/requests/admin/badges_controller_spec.rb
similarity index 67%
rename from spec/controllers/admin/badges_controller_spec.rb
rename to spec/requests/admin/badges_controller_spec.rb
index d5995aac40..add572d95f 100644
--- a/spec/controllers/admin/badges_controller_spec.rb
+++ b/spec/requests/admin/badges_controller_spec.rb
@@ -1,60 +1,62 @@
require 'rails_helper'
describe Admin::BadgesController do
-
context "while logged in as an admin" do
- let!(:user) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
let!(:badge) { Fabricate(:badge) }
- context 'index' do
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
it 'returns badge index' do
- get :index, format: :json
- expect(response).to be_success
+ get "/admin/badges.json"
+ expect(response.status).to eq(200)
end
end
- context 'preview' do
+ describe '#preview' do
it 'allows preview enable_badge_sql is enabled' do
SiteSetting.enable_badge_sql = true
- get :preview, params: {
+ post "/admin/badges/preview.json", params: {
sql: 'select id as user_id, created_at granted_at from users'
- }, format: :json
+ }
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)["grant_count"]).to be > 0
end
+
it 'does not allow anything if enable_badge_sql is disabled' do
SiteSetting.enable_badge_sql = false
- get :preview, params: {
+ post "/admin/badges/preview.json", params: {
sql: 'select id as user_id, created_at granted_at from users'
- }, format: :json
+ }
expect(response.status).to eq(403)
end
end
- describe '.create' do
- render_views
-
+ describe '#create' do
it 'can create badges correctly' do
SiteSetting.enable_badge_sql = true
- post :create, params: {
+ post "/admin/badges.json", params: {
name: 'test', query: 'select 1 as user_id, null as granted_at', badge_type_id: 1
- }, format: :json
+ }
json = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(json["badge"]["name"]).to eq('test')
expect(json["badge"]["query"]).to eq('select 1 as user_id, null as granted_at')
- expect(UserHistory.where(acting_user_id: user.id, action: UserHistory.actions[:create_badge]).exists?).to eq(true)
+ expect(UserHistory.where(acting_user_id: admin.id, action: UserHistory.actions[:create_badge]).exists?).to eq(true)
end
end
- context '.save_badge_groupings' do
-
+ describe '#save_badge_groupings' do
it 'can save badge groupings' do
groupings = BadgeGrouping.all.order(:position).to_a
groupings << BadgeGrouping.new(name: 'Test 1')
@@ -65,7 +67,8 @@ describe Admin::BadgesController do
names = groupings.map { |g| g.name }
ids = groupings.map { |g| g.id.to_s }
- post :save_badge_groupings, params: { ids: ids, names: names }, format: :json
+ post "/admin/badges/badge_groupings.json", params: { ids: ids, names: names }
+ expect(response.status).to eq(200)
groupings2 = BadgeGrouping.all.order(:position).to_a
@@ -75,40 +78,38 @@ describe Admin::BadgesController do
end
end
- context '.badge_types' do
+ describe '#badge_types' do
it 'returns JSON' do
- get :badge_types, format: :json
+ get "/admin/badges/types.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(::JSON.parse(response.body)["badge_types"]).to be_present
end
end
- context '.destroy' do
+ describe '#destroy' do
it 'deletes the badge' do
- delete :destroy, params: { id: badge.id }, format: :json
- expect(response).to be_success
+ delete "/admin/badges/#{badge.id}.json"
+ 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)
+ expect(UserHistory.where(acting_user_id: admin.id, action: UserHistory.actions[:delete_badge]).exists?).to eq(true)
end
end
- context '.update' do
-
+ describe '#update' do
it 'does not update the name of system badges' do
editor_badge = Badge.find(Badge::Editor)
editor_badge_name = editor_badge.name
- put :update, params: {
- id: editor_badge.id,
+ put "/admin/badges/#{editor_badge.id}.json", params: {
name: "123456"
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
editor_badge.reload
expect(editor_badge.name).to eq(editor_badge_name)
- expect(UserHistory.where(acting_user_id: user.id, action: UserHistory.actions[:change_badge]).exists?).to eq(true)
+ expect(UserHistory.where(acting_user_id: admin.id, action: UserHistory.actions[:change_badge]).exists?).to eq(true)
end
it 'does not allow query updates if badge_sql is disabled' do
@@ -117,17 +118,16 @@ describe Admin::BadgesController do
SiteSetting.enable_badge_sql = false
- put :update, params: {
- id: badge.id,
+ put "/admin/badges/#{badge.id}.json", params: {
name: "123456",
query: "select id user_id, created_at granted_at from users",
badge_type_id: badge.badge_type_id,
allow_title: false,
multiple_grant: false,
enabled: true
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
badge.reload
expect(badge.name).to eq('123456')
expect(badge.query).to eq('select 123')
@@ -137,17 +137,16 @@ describe Admin::BadgesController do
SiteSetting.enable_badge_sql = true
sql = "select id user_id, created_at granted_at from users"
- put :update, params: {
- id: badge.id,
+ put "/admin/badges/#{badge.id}.json", params: {
name: "123456",
query: sql,
badge_type_id: badge.badge_type_id,
allow_title: false,
multiple_grant: false,
enabled: true
- }, format: :json
+ }
- expect(response).to be_success
+ 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/requests/admin/color_schemes_controller_spec.rb
similarity index 51%
rename from spec/controllers/admin/color_schemes_controller_spec.rb
rename to spec/requests/admin/color_schemes_controller_spec.rb
index 6b11e219fb..f3c59e3c01 100644
--- a/spec/controllers/admin/color_schemes_controller_spec.rb
+++ b/spec/requests/admin/color_schemes_controller_spec.rb
@@ -6,7 +6,7 @@ describe Admin::ColorSchemesController do
end
context "while logged in as an admin" do
- let!(:user) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
let(:valid_params) { { color_scheme: {
name: 'Such Design',
colors: [
@@ -16,21 +16,26 @@ describe Admin::ColorSchemesController do
}
} }
- describe "index" do
- it "returns JSON" do
- Fabricate(:color_scheme)
- get :index, format: :json
+ before do
+ sign_in(admin)
+ end
- expect(response).to be_success
- expect(::JSON.parse(response.body)).to be_present
+ describe "#index" do
+ it "returns JSON" do
+ scheme_name = Fabricate(:color_scheme).name
+ get "/admin/color_schemes.json"
+
+ expect(response.status).to eq(200)
+ schemes = JSON.parse(response.body).map { |scheme| scheme["name"] }
+ expect(schemes).to include(scheme_name)
end
end
- describe "create" do
+ describe "#create" do
it "returns JSON" do
- post :create, params: valid_params, format: :json
+ post "/admin/color_schemes.json", params: valid_params
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(::JSON.parse(response.body)['id']).to be_present
end
@@ -38,47 +43,50 @@ describe Admin::ColorSchemesController do
params = valid_params
params[:color_scheme][:colors][0][:hex] = 'cool color please'
- post :create, params: valid_params, format: :json
+ post "/admin/color_schemes.json", params: valid_params
- expect(response).not_to be_success
+ expect(response.status).to eq(422)
expect(::JSON.parse(response.body)['errors']).to be_present
end
end
- describe "update" do
+ describe "#update" do
let(:existing) { Fabricate(:color_scheme) }
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
- end
+ put "/admin/color_schemes/#{existing.id}.json", params: valid_params
+ expect(response.status).to eq(200)
- it "returns JSON" do
- ColorSchemeRevisor.expects(:revise).returns(existing)
- put :update, params: valid_params.merge(id: existing.id), format: :json
- expect(::JSON.parse(response.body)['id']).to be_present
+ existing.reload
+ new_colors = valid_params[:color_scheme][:colors]
+ updated_colors = existing.colors.map { |color| { name: color.name, hex: color.hex } }
+
+ expect(new_colors & updated_colors).to eq(new_colors)
+ expect(existing.name).to eq(valid_params[:color_scheme][:name])
end
it "returns failure with invalid params" do
color_scheme = Fabricate(:color_scheme)
- params = valid_params.merge(id: color_scheme.id)
+ params = valid_params
+
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
+
+ put "/admin/color_schemes/#{color_scheme.id}.json", params: params
+
+ expect(response.status).to eq(422)
expect(::JSON.parse(response.body)['errors']).to be_present
end
end
- describe "destroy" do
+ describe "#destroy" do
let!(:existing) { Fabricate(:color_scheme) }
it "returns success" do
expect {
- delete :destroy, params: { id: existing.id }, format: :json
+ delete "/admin/color_schemes/#{existing.id}.json"
}.to change { ColorScheme.count }.by(-1)
- expect(response).to be_success
+ expect(response.status).to eq(200)
end
end
end
diff --git a/spec/controllers/admin/dashboard_controller_spec.rb b/spec/requests/admin/dashboard_controller_spec.rb
similarity index 78%
rename from spec/controllers/admin/dashboard_controller_spec.rb
rename to spec/requests/admin/dashboard_controller_spec.rb
index c190f72b7e..5d26979267 100644
--- a/spec/controllers/admin/dashboard_controller_spec.rb
+++ b/spec/requests/admin/dashboard_controller_spec.rb
@@ -12,18 +12,22 @@ describe Admin::DashboardController do
end
context 'while logged in as an admin' do
- let!(:admin) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
- context '.index' do
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
context 'version checking is enabled' do
before do
SiteSetting.version_checks = true
end
it 'returns discourse version info' do
- get :index, format: :json
+ get "/admin/dashboard.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)['version_check']).to be_present
end
end
@@ -34,23 +38,24 @@ describe Admin::DashboardController do
end
it 'does not return discourse version info' do
- get :index, format: :json
+ get "/admin/dashboard.json"
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json['version_check']).not_to be_present
end
end
end
- context '.problems' do
+ describe '#problems' do
context 'when there are no problems' do
before do
AdminDashboardData.stubs(:fetch_problems).returns([])
end
it 'returns an empty array' do
- get :problems, format: :json
+ get "/admin/dashboard/problems.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json['problems'].size).to eq(0)
end
@@ -62,7 +67,8 @@ describe Admin::DashboardController do
end
it 'returns an array of strings' do
- get :problems, format: :json
+ get "/admin/dashboard/problems.json"
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json['problems'].size).to eq(2)
expect(json['problems'][0]).to be_a(String)
diff --git a/spec/controllers/admin/email_controller_spec.rb b/spec/requests/admin/email_controller_spec.rb
similarity index 51%
rename from spec/controllers/admin/email_controller_spec.rb
rename to spec/requests/admin/email_controller_spec.rb
index 0b0c2ffca2..ff8b46e71b 100644
--- a/spec/controllers/admin/email_controller_spec.rb
+++ b/spec/requests/admin/email_controller_spec.rb
@@ -1,26 +1,28 @@
require 'rails_helper'
describe Admin::EmailController do
+ let(:admin) { Fabricate(:admin) }
+
+ before do
+ sign_in(admin)
+ end
it "is a subclass of AdminController" do
expect(Admin::EmailController < Admin::AdminController).to eq(true)
end
- let!(:user) { log_in(:admin) }
-
- context '.index' do
+ describe '#index' do
before do
- subject
+ Admin::EmailController.any_instance
.expects(:action_mailer_settings)
.returns(
username: 'username',
password: 'secret'
)
-
- get :index, format: :json
end
it 'does not include the password in the response' do
+ get "/admin/email.json"
mail_settings = JSON.parse(response.body)['settings']
expect(
@@ -29,84 +31,74 @@ describe Admin::EmailController do
end
end
- context '.sent' do
- before do
- get :sent, format: :json
+ describe '#sent' do
+ it "succeeds" do
+ get "/admin/email/sent.json"
+ expect(response.status).to eq(200)
end
-
- subject { response }
- it { is_expected.to be_success }
end
- context '.skipped' do
- before do
- get :skipped, format: :json
+ describe '#skipped' do
+ it "succeeds" do
+ get "/admin/email/skipped.json"
+ expect(response.status).to eq(200)
end
-
- subject { response }
- it { is_expected.to be_success }
end
- context '.test' do
+ describe '#test' do
it 'raises an error without the email parameter' do
- expect do
- post :test, format: :json
- end.to raise_error(ActionController::ParameterMissing)
+ post "/admin/email/test.json"
+ expect(response.status).to eq(400)
end
context 'with an email address' do
it 'enqueues a test email job' do
- job_mock = mock
- Jobs::TestEmail.expects(:new).returns(job_mock)
- job_mock.expects(:execute).with(to_address: 'eviltrout@test.domain')
- post :test, params: { email_address: 'eviltrout@test.domain' }, format: :json
+ post "/admin/email/test.json", params: { email_address: 'eviltrout@test.domain' }
+ expect(response.status).to eq(200)
+ expect(ActionMailer::Base.deliveries.map(&:to).flatten).to include('eviltrout@test.domain')
end
end
end
- context '.preview_digest' do
+ describe '#preview_digest' do
it 'raises an error without the last_seen_at parameter' do
- expect do
- get :preview_digest, format: :json
- end.to raise_error(ActionController::ParameterMissing)
+ get "/admin/email/preview-digest.json"
+ expect(response.status).to eq(400)
end
it "previews the digest" do
- get :preview_digest, params: {
- last_seen_at: 1.week.ago, username: user.username
- }, format: :json
-
- expect(response).to be_success
+ get "/admin/email/preview-digest.json", params: {
+ last_seen_at: 1.week.ago, username: admin.username
+ }
+ expect(response.status).to eq(200)
end
end
- context '#handle_mail' do
- before do
- log_in_user(Fabricate(:admin))
- end
-
+ describe '#handle_mail' do
it 'should enqueue the right job' do
- expect { post :handle_mail, params: { email: email('cc') }, format: :json }
+ expect { post "/admin/email/handle_mail.json", params: { email: email('cc') } }
.to change { Jobs::ProcessEmail.jobs.count }.by(1)
+ expect(response.status).to eq(200)
end
end
- context '.rejected' do
+ describe '#rejected' do
it 'should provide a string for a blank error' do
Fabricate(:incoming_email, error: "")
- get :rejected, format: :json
+ get "/admin/email/rejected.json"
+ expect(response.status).to eq(200)
rejected = JSON.parse(response.body)
expect(rejected.first['error']).to eq(I18n.t("emails.incoming.unrecognized_error"))
end
end
- context '.incoming' do
+ describe '#incoming' do
it 'should provide a string for a blank error' do
incoming_email = Fabricate(:incoming_email, error: "")
- get :incoming, params: { id: incoming_email.id }, format: :json
+ get "/admin/email/incoming/#{incoming_email.id}.json"
+ expect(response.status).to eq(200)
incoming = JSON.parse(response.body)
expect(incoming['error']).to eq(I18n.t("emails.incoming.unrecognized_error"))
end
end
-
end
diff --git a/spec/requests/admin/email_templates_controller_spec.rb b/spec/requests/admin/email_templates_controller_spec.rb
index 9babb31b38..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_success
+ expect(response.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json).to be_present
diff --git a/spec/controllers/admin/embeddable_hosts_controller_spec.rb b/spec/requests/admin/embeddable_hosts_controller_spec.rb
similarity index 99%
rename from spec/controllers/admin/embeddable_hosts_controller_spec.rb
rename to spec/requests/admin/embeddable_hosts_controller_spec.rb
index 54a97ed938..403ed76e1e 100644
--- a/spec/controllers/admin/embeddable_hosts_controller_spec.rb
+++ b/spec/requests/admin/embeddable_hosts_controller_spec.rb
@@ -1,9 +1,7 @@
require 'rails_helper'
describe Admin::EmbeddableHostsController do
-
it "is a subclass of AdminController" do
expect(Admin::EmbeddableHostsController < Admin::AdminController).to eq(true)
end
-
end
diff --git a/spec/controllers/admin/embedding_controller_spec.rb b/spec/requests/admin/embedding_controller_spec.rb
similarity index 98%
rename from spec/controllers/admin/embedding_controller_spec.rb
rename to spec/requests/admin/embedding_controller_spec.rb
index 49a989e15b..9531c3a618 100644
--- a/spec/controllers/admin/embedding_controller_spec.rb
+++ b/spec/requests/admin/embedding_controller_spec.rb
@@ -1,9 +1,7 @@
require 'rails_helper'
describe Admin::EmbeddingController do
-
it "is a subclass of AdminController" do
expect(Admin::EmbeddingController < Admin::AdminController).to eq(true)
end
-
end
diff --git a/spec/requests/admin/emojis_controller_spec.rb b/spec/requests/admin/emojis_controller_spec.rb
index 3d781af215..24019fc343 100644
--- a/spec/requests/admin/emojis_controller_spec.rb
+++ b/spec/requests/admin/emojis_controller_spec.rb
@@ -8,6 +8,20 @@ RSpec.describe Admin::EmojisController do
sign_in(admin)
end
+ describe '#index' do
+ it "returns a list of custom emojis" do
+ CustomEmoji.create!(name: 'osama-test-emoji', upload: upload)
+ Emoji.clear_cache
+
+ get "/admin/customize/emojis.json"
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)
+ expect(json[0]["name"]).to eq("osama-test-emoji")
+ expect(json[0]["url"]).to eq(upload.url)
+ end
+ end
+
describe "#create" do
describe 'when upload is invalid' do
it 'should publish the right error' do
diff --git a/spec/requests/admin/flagged_topics_controller_spec.rb b/spec/requests/admin/flagged_topics_controller_spec.rb
index 8f768294bc..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_success
+ 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 98ee91c851..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_success
+ expect(response.status).to eq(200)
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.status).to eq(200)
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/impersonate_controller_spec.rb b/spec/requests/admin/impersonate_controller_spec.rb
new file mode 100644
index 0000000000..3cb2657330
--- /dev/null
+++ b/spec/requests/admin/impersonate_controller_spec.rb
@@ -0,0 +1,62 @@
+require 'rails_helper'
+
+describe Admin::ImpersonateController do
+
+ it "is a subclass of AdminController" do
+ expect(Admin::ImpersonateController < Admin::AdminController).to eq(true)
+ end
+
+ context 'while logged in as an admin' do
+ let(:admin) { Fabricate(:admin) }
+ let(:user) { Fabricate(:user) }
+ let(:another_admin) { Fabricate(:admin) }
+
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
+ it 'returns success' do
+ get "/admin/impersonate.json"
+ expect(response.status).to eq(200)
+ end
+ end
+
+ describe '#create' do
+ it 'requires a username_or_email parameter' do
+ post "/admin/impersonate.json"
+ expect(response.status).to eq(400)
+ expect(session[:current_user_id]).to eq(admin.id)
+ end
+
+ it 'returns 404 when that user does not exist' do
+ post "/admin/impersonate.json", params: { username_or_email: 'hedonismbot' }
+ expect(response.status).to eq(404)
+ expect(session[:current_user_id]).to eq(admin.id)
+ end
+
+ it "raises an invalid access error if the user can't be impersonated" do
+ post "/admin/impersonate.json", params: { username_or_email: another_admin.email }
+ expect(response.status).to eq(403)
+ expect(session[:current_user_id]).to eq(admin.id)
+ end
+
+ context 'success' do
+ it "succeeds and logs the impersonation" do
+ expect do
+ post "/admin/impersonate.json", params: { username_or_email: user.username }
+ end.to change { UserHistory.where(action: UserHistory.actions[:impersonate]).count }.by(1)
+
+ expect(response.status).to eq(200)
+ expect(session[:current_user_id]).to eq(user.id)
+ end
+
+ it "also works with an email address" do
+ post "/admin/impersonate.json", params: { username_or_email: user.email }
+ expect(response.status).to eq(200)
+ expect(session[:current_user_id]).to eq(user.id)
+ end
+ end
+ 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..b35989ad30 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.status).to eq(200)
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.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_success
+ 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_success
+ expect(response.status).to eq(200)
expect(::JSON.parse(response.body)['moderation_history']).to be_present
end
end
diff --git a/spec/controllers/admin/permalinks_controller_spec.rb b/spec/requests/admin/permalinks_controller_spec.rb
similarity index 76%
rename from spec/controllers/admin/permalinks_controller_spec.rb
rename to spec/requests/admin/permalinks_controller_spec.rb
index 1075150ab1..c0fa35abde 100644
--- a/spec/controllers/admin/permalinks_controller_spec.rb
+++ b/spec/requests/admin/permalinks_controller_spec.rb
@@ -6,18 +6,22 @@ describe Admin::PermalinksController do
expect(Admin::PermalinksController < Admin::AdminController).to eq(true)
end
- let!(:user) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
- describe 'index' do
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
it 'filters url' do
Fabricate(:permalink, url: "/forum/23")
Fabricate(:permalink, url: "/forum/98")
Fabricate(:permalink, url: "/discuss/topic/45")
Fabricate(:permalink, url: "/discuss/topic/76")
- get :index, params: { filter: "topic" }, format: :json
+ get "/admin/permalinks.json", params: { filter: "topic" }
- expect(response).to be_success
+ expect(response.status).to eq(200)
result = JSON.parse(response.body)
expect(result.length).to eq(2)
end
@@ -28,9 +32,9 @@ describe Admin::PermalinksController do
Fabricate(:permalink, external_url: "http://www.discourse.org")
Fabricate(:permalink, external_url: "http://try.discourse.org")
- get :index, params: { filter: "discourse" }, format: :json
+ get "/admin/permalinks.json", params: { filter: "discourse" }
- expect(response).to be_success
+ expect(response.status).to eq(200)
result = JSON.parse(response.body)
expect(result.length).to eq(2)
end
@@ -41,9 +45,9 @@ describe Admin::PermalinksController do
Fabricate(:permalink, url: "/discuss/topic/45", external_url: "http://discourse.org")
Fabricate(:permalink, url: "/discuss/topic/76", external_url: "http://try.discourse.org")
- get :index, params: { filter: "discourse" }, format: :json
+ get "/admin/permalinks.json", params: { filter: "discourse" }
- expect(response).to be_success
+ 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/requests/admin/plugins_controller_spec.rb
similarity index 73%
rename from spec/controllers/admin/plugins_controller_spec.rb
rename to spec/requests/admin/plugins_controller_spec.rb
index 9df2c2737e..57175ebbb4 100644
--- a/spec/controllers/admin/plugins_controller_spec.rb
+++ b/spec/requests/admin/plugins_controller_spec.rb
@@ -7,13 +7,14 @@ describe Admin::PluginsController do
end
context "while logged in as an admin" do
- let!(:admin) { log_in(:admin) }
+ before do
+ sign_in(Fabricate(:admin))
+ end
it 'should return JSON' do
- get :index, format: :json
- expect(response).to be_success
+ get "/admin/plugins.json"
+ expect(response.status).to eq(200)
expect(::JSON.parse(response.body).has_key?('plugins')).to eq(true)
end
end
-
end
diff --git a/spec/controllers/admin/reports_controller_spec.rb b/spec/requests/admin/reports_controller_spec.rb
similarity index 51%
rename from spec/controllers/admin/reports_controller_spec.rb
rename to spec/requests/admin/reports_controller_spec.rb
index 740df64afb..27795f6579 100644
--- a/spec/controllers/admin/reports_controller_spec.rb
+++ b/spec/requests/admin/reports_controller_spec.rb
@@ -6,68 +6,51 @@ describe Admin::ReportsController do
end
context 'while logged in as an admin' do
- let!(:admin) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
let(:user) { Fabricate(:user) }
- context '.show' do
+ before do
+ sign_in(admin)
+ end
+ describe '#show' do
context "invalid id form" do
let(:invalid_id) { "!!&asdfasdf" }
- it "never calls Report.find" do
- Report.expects(:find).never
- get :show, params: { type: invalid_id }, format: :json
- end
-
it "returns 404" do
- get :show, params: { type: invalid_id }, format: :json
+ get "/admin/reports/#{invalid_id}.json"
expect(response.status).to eq(404)
end
end
context "valid type form" do
-
context 'missing report' do
- before do
- Report.expects(:find).with('active', instance_of(Hash)).returns(nil)
- get :show, params: { type: 'active' }, format: :json
- end
-
- it "renders the report as JSON" do
+ it "returns a 404 error" do
+ get "/admin/reports/nonexistent.json"
expect(response.status).to eq(404)
end
end
context 'a report is found' do
- before do
- Report.expects(:find).with('active', instance_of(Hash)).returns(Report.new('active'))
- get :show, params: { type: 'active' }, format: :json
- end
-
it "renders the report as JSON" do
- expect(response).to be_success
- end
+ Fabricate(:topic)
+ get "/admin/reports/topics.json"
- it "renders the report as JSON" do
- expect(::JSON.parse(response.body)).to be_present
+ expect(response.status).to eq(200)
+ expect(JSON.parse(response.body)["report"]["total"]).to eq(1)
end
-
end
-
end
describe 'when report is scoped to a category' do
let(:category) { Fabricate(:category) }
- let(:topic) { Fabricate(:topic, category: category) }
- let(:other_topic) { Fabricate(:topic) }
+ let!(:topic) { Fabricate(:topic, category: category) }
+ let!(:other_topic) { Fabricate(:topic) }
it 'should render the report as JSON' do
- topic
- other_topic
+ get "/admin/reports/topics.json", params: { category_id: category.id }
- get :show, params: { type: 'topics', category_id: category.id }, format: :json
-
- expect(response).to be_success
+ expect(response.status).to eq(200)
report = JSON.parse(response.body)["report"]
@@ -78,16 +61,15 @@ describe Admin::ReportsController do
describe 'when report is scoped to a group' do
let(:user) { Fabricate(:user) }
- let(:other_user) { Fabricate(:user) }
+ let!(:other_user) { Fabricate(:user) }
let(:group) { Fabricate(:group) }
it 'should render the report as JSON' do
- other_user
group.add(user)
- get :show, params: { type: 'signups', group_id: group.id }, format: :json
+ get "/admin/reports/signups.json", params: { group_id: group.id }
- expect(response).to be_success
+ expect(response.status).to eq(200)
report = JSON.parse(response.body)["report"]
@@ -95,9 +77,6 @@ describe Admin::ReportsController do
expect(report["data"].count).to eq(1)
end
end
-
end
-
end
-
end
diff --git a/spec/controllers/admin/screened_emails_controller_spec.rb b/spec/requests/admin/screened_emails_controller_spec.rb
similarity index 51%
rename from spec/controllers/admin/screened_emails_controller_spec.rb
rename to spec/requests/admin/screened_emails_controller_spec.rb
index fb4486a9b4..8d9ce25032 100644
--- a/spec/controllers/admin/screened_emails_controller_spec.rb
+++ b/spec/requests/admin/screened_emails_controller_spec.rb
@@ -5,18 +5,17 @@ describe Admin::ScreenedEmailsController do
expect(Admin::ScreenedEmailsController < Admin::AdminController).to eq(true)
end
- let!(:user) { log_in(:admin) }
-
- context '.index' do
+ describe '#index' do
before do
- get :index, format: :json
+ sign_in(Fabricate(:admin))
end
- subject { response }
- it { is_expected.to be_success }
-
it 'returns JSON' do
- expect(::JSON.parse(subject.body)).to be_a(Array)
+ Fabricate(:screened_email)
+ get "/admin/logs/screened_emails.json"
+ expect(response.status).to eq(200)
+ json = JSON.parse(response.body)
+ expect(json.size).to eq(1)
end
end
end
diff --git a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb b/spec/requests/admin/screened_ip_addresses_controller_spec.rb
similarity index 72%
rename from spec/controllers/admin/screened_ip_addresses_controller_spec.rb
rename to spec/requests/admin/screened_ip_addresses_controller_spec.rb
index 664fc85cdb..7737b1ee53 100644
--- a/spec/controllers/admin/screened_ip_addresses_controller_spec.rb
+++ b/spec/requests/admin/screened_ip_addresses_controller_spec.rb
@@ -6,33 +6,34 @@ describe Admin::ScreenedIpAddressesController do
expect(Admin::ScreenedIpAddressesController < Admin::AdminController).to eq(true)
end
- let!(:user) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
- describe 'index' do
+ before do
+ sign_in(admin)
+ end
+ describe '#index' do
it 'filters screened ip addresses' do
Fabricate(:screened_ip_address, ip_address: "1.2.3.4")
Fabricate(:screened_ip_address, ip_address: "1.2.3.5")
Fabricate(:screened_ip_address, ip_address: "1.2.3.6")
Fabricate(:screened_ip_address, ip_address: "4.5.6.7")
- get :index, params: { filter: "1.2.*" }, format: :json
+ get "/admin/logs/screened_ip_addresses.json", params: { filter: "1.2.*" }
- expect(response).to be_success
+ 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
+ get "/admin/logs/screened_ip_addresses.json", params: { filter: "4.5.6.7" }
- expect(response).to be_success
+ expect(response.status).to eq(200)
result = JSON.parse(response.body)
expect(result.length).to eq(1)
end
-
end
- describe 'roll_up' do
-
+ describe '#roll_up' do
it "rolls up 1.2.3.* entries" do
Fabricate(:screened_ip_address, ip_address: "1.2.3.4", match_count: 1)
Fabricate(:screened_ip_address, ip_address: "1.2.3.5", match_count: 1)
@@ -41,11 +42,13 @@ describe Admin::ScreenedIpAddressesController do
Fabricate(:screened_ip_address, ip_address: "42.42.42.4", match_count: 1)
Fabricate(:screened_ip_address, ip_address: "42.42.42.5", match_count: 1)
- StaffActionLogger.any_instance.expects(:log_roll_up)
SiteSetting.min_ban_entries_for_roll_up = 3
- post :roll_up, format: :json
- expect(response).to be_success
+ expect do
+ post "/admin/logs/screened_ip_addresses/roll_up.json"
+ end.to change { UserHistory.where(action: UserHistory.actions[:roll_up]).count }.by(1)
+
+ expect(response.status).to eq(200)
subnet = ScreenedIpAddress.where(ip_address: "1.2.3.0/24").first
expect(subnet).to be_present
@@ -61,17 +64,17 @@ describe Admin::ScreenedIpAddressesController do
Fabricate(:screened_ip_address, ip_address: "1.2.42.0/24", match_count: 1)
- StaffActionLogger.any_instance.expects(:log_roll_up)
SiteSetting.min_ban_entries_for_roll_up = 5
- post :roll_up, format: :json
- expect(response).to be_success
+ expect do
+ post "/admin/logs/screened_ip_addresses/roll_up.json"
+ end.to change { UserHistory.where(action: UserHistory.actions[:roll_up]).count }.by(1)
+
+ expect(response.status).to eq(200)
subnet = ScreenedIpAddress.where(ip_address: "1.2.0.0/16").first
expect(subnet).to be_present
expect(subnet.match_count).to eq(6)
end
-
end
-
end
diff --git a/spec/controllers/admin/screened_urls_controller_spec.rb b/spec/requests/admin/screened_urls_controller_spec.rb
similarity index 51%
rename from spec/controllers/admin/screened_urls_controller_spec.rb
rename to spec/requests/admin/screened_urls_controller_spec.rb
index 86d7fce0b7..e4d4ba05e9 100644
--- a/spec/controllers/admin/screened_urls_controller_spec.rb
+++ b/spec/requests/admin/screened_urls_controller_spec.rb
@@ -5,18 +5,17 @@ describe Admin::ScreenedUrlsController do
expect(Admin::ScreenedUrlsController < Admin::AdminController).to eq(true)
end
- let!(:user) { log_in(:admin) }
-
- context '.index' do
+ describe '#index' do
before do
- get :index, format: :json
+ sign_in(Fabricate(:admin))
end
- subject { response }
- it { is_expected.to be_success }
-
it 'returns JSON' do
- expect(::JSON.parse(subject.body)).to be_a(Array)
+ Fabricate(:screened_url)
+ get "/admin/logs/screened_urls.json"
+ expect(response.status).to eq(200)
+ json = JSON.parse(response.body)
+ expect(json.size).to eq(1)
end
end
end
diff --git a/spec/requests/admin/search_logs_spec.rb b/spec/requests/admin/search_logs_spec.rb
index f811bfd44f..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_success
+ 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_success
+ 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/admin/site_settings_controller_spec.rb b/spec/requests/admin/site_settings_controller_spec.rb
new file mode 100644
index 0000000000..fd17c3dc39
--- /dev/null
+++ b/spec/requests/admin/site_settings_controller_spec.rb
@@ -0,0 +1,84 @@
+require 'rails_helper'
+
+describe Admin::SiteSettingsController do
+
+ it "is a subclass of AdminController" do
+ expect(Admin::SiteSettingsController < Admin::AdminController).to eq(true)
+ end
+
+ context 'while logged in as an admin' do
+ let(:admin) { Fabricate(:admin) }
+
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
+ it 'returns valid info' do
+ get "/admin/site_settings.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json["site_settings"].length).to be > 100
+
+ locale = json["site_settings"].select do |s|
+ s["setting"] == "default_locale"
+ end
+
+ expect(locale.length).to eq(1)
+ end
+ end
+
+ describe '#update' do
+ before do
+ SiteSetting.setting(:test_setting, "default")
+ SiteSetting.refresh!
+ end
+
+ it 'sets the value when the param is present' do
+ put "/admin/site_settings/test_setting.json", params: {
+ test_setting: 'hello'
+ }
+ expect(response.status).to eq(200)
+ expect(SiteSetting.test_setting).to eq('hello')
+ end
+
+ it 'allows value to be a blank string' do
+ put "/admin/site_settings/test_setting.json", params: {
+ test_setting: ''
+ }
+ expect(response.status).to eq(200)
+ expect(SiteSetting.test_setting).to eq('')
+ end
+
+ it 'logs the change' do
+ SiteSetting.test_setting = 'previous'
+
+ expect do
+ put "/admin/site_settings/test_setting.json", params: {
+ test_setting: 'hello'
+ }
+ end.to change { UserHistory.where(action: UserHistory.actions[:change_site_setting]).count }.by(1)
+
+ expect(response.status).to eq(200)
+ expect(SiteSetting.test_setting).to eq('hello')
+ end
+
+ it 'does not allow changing of hidden settings' do
+ SiteSetting.setting(:hidden_setting, "hidden", hidden: true)
+ SiteSetting.refresh!
+
+ put "/admin/site_settings/hidden_setting.json", params: {
+ hidden_setting: 'not allowed'
+ }
+
+ expect(SiteSetting.hidden_setting).to eq("hidden")
+ expect(response.status).to eq(422)
+ end
+
+ it 'fails when a setting does not exist' do
+ put "/admin/site_settings/provider.json", params: { provider: 'gotcha' }
+ expect(response.status).to eq(422)
+ end
+ end
+ end
+end
diff --git a/spec/requests/admin/site_texts_controller_spec.rb b/spec/requests/admin/site_texts_controller_spec.rb
index f19c6015c8..0ee4383e23 100644
--- a/spec/requests/admin/site_texts_controller_spec.rb
+++ b/spec/requests/admin/site_texts_controller_spec.rb
@@ -9,7 +9,11 @@ RSpec.describe Admin::SiteTextsController do
I18n.reload!
end
- context "#update" do
+ it "is a subclass of AdminController" do
+ expect(Admin::SiteTextsController < Admin::AdminController).to eq(true)
+ end
+
+ context "when not logged in as an admin" do
it "raises an error if you aren't logged in" do
put '/admin/customize/site_texts/some_key.json', params: {
site_text: { value: 'foo' }
@@ -21,18 +25,47 @@ RSpec.describe Admin::SiteTextsController do
it "raises an error if you aren't an admin" do
sign_in(user)
- put '/admin/customize/site_texts/some_key', params: {
+ put "/admin/customize/site_texts/some_key.json", params: {
site_text: { value: 'foo' }
}
expect(response.status).to eq(404)
end
+ end
- context "when logged in as admin" do
- before do
- sign_in(admin)
+ context "when logged in as amin" do
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
+ it 'returns json' do
+ get "/admin/customize/site_texts.json", params: { q: 'title' }
+ expect(response.status).to eq(200)
+ expect(::JSON.parse(response.body)).to be_present
+ end
+ end
+
+ describe '#show' do
+ it 'returns a site text for a key that exists' do
+ get "/admin/customize/site_texts/js.topic.list.json"
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)
+
+ site_text = json['site_text']
+
+ expect(site_text['id']).to eq('js.topic.list')
+ expect(site_text['value']).to eq(I18n.t("js.topic.list"))
end
+ it 'returns not found for missing keys' do
+ get "/admin/customize/site_texts/made_up_no_key_exists.json"
+ expect(response.status).to eq(404)
+ end
+ end
+
+ describe '#update & #revert' do
it "returns 'not found' when an unknown key is used" do
put '/admin/customize/site_texts/some_key.json', params: {
site_text: { value: 'foo' }
@@ -68,6 +101,106 @@ RSpec.describe Admin::SiteTextsController do
json = ::JSON.parse(response.body)
expect(json['error_type']).to eq('not_found')
end
+
+ it "returns the right error message" do
+ I18n.backend.store_translations(:en, some_key: '%{first} %{second}')
+
+ put "/admin/customize/site_texts/some_key.json", params: {
+ site_text: { value: 'hello %{key} %{omg}' }
+ }
+
+ expect(response.status).to eq(422)
+
+ body = JSON.parse(response.body)
+
+ expect(body['message']).to eq(I18n.t(
+ 'activerecord.errors.models.translation_overrides.attributes.value.invalid_interpolation_keys',
+ keys: 'key, omg'
+ ))
+ end
+
+ it 'logs the change' do
+ original_title = I18n.t(:title)
+
+ put "/admin/customize/site_texts/title.json", params: {
+ site_text: { value: 'yay' }
+ }
+ expect(response.status).to eq(200)
+
+ log = UserHistory.last
+
+ expect(log.previous_value).to eq(original_title)
+ expect(log.new_value).to eq('yay')
+ expect(log.action).to eq(UserHistory.actions[:change_site_text])
+
+ delete "/admin/customize/site_texts/title.json"
+ expect(response.status).to eq(200)
+
+ log = UserHistory.last
+
+ expect(log.previous_value).to eq('yay')
+ expect(log.new_value).to eq(original_title)
+ expect(log.action).to eq(UserHistory.actions[:change_site_text])
+ end
+
+ it 'updates and reverts the key' do
+ orig_title = I18n.t(:title)
+
+ put "/admin/customize/site_texts/title.json", params: { site_text: { value: 'hello' } }
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)
+
+ site_text = json['site_text']
+
+ expect(site_text['id']).to eq('title')
+ expect(site_text['value']).to eq('hello')
+
+ # Revert
+ delete "/admin/customize/site_texts/title.json"
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)
+
+ site_text = json['site_text']
+
+ expect(site_text['id']).to eq('title')
+ expect(site_text['value']).to eq(orig_title)
+ end
+
+ it 'returns site texts for the correct locale' do
+ SiteSetting.default_locale = :ru
+
+ ru_title = 'title ru'
+ ru_mf_text = 'ru {NUM_RESULTS, plural, one {1 result} other {many} }'
+
+ put "/admin/customize/site_texts/title.json", params: { site_text: { value: ru_title } }
+ expect(response.status).to eq(200)
+ put "/admin/customize/site_texts/js.topic.read_more_MF.json", params: { site_text: { value: ru_mf_text } }
+ expect(response.status).to eq(200)
+
+ get "/admin/customize/site_texts/title.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json['site_text']['value']).to eq(ru_title)
+
+ get "/admin/customize/site_texts/js.topic.read_more_MF.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json['site_text']['value']).to eq(ru_mf_text)
+
+ SiteSetting.default_locale = :en
+
+ get "/admin/customize/site_texts/title.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json['site_text']['value']).to_not eq(ru_title)
+
+ get "/admin/customize/site_texts/js.topic.read_more_MF.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json['site_text']['value']).to_not eq(ru_mf_text)
+ end
end
end
end
diff --git a/spec/controllers/admin/staff_action_logs_controller_spec.rb b/spec/requests/admin/staff_action_logs_controller_spec.rb
similarity index 73%
rename from spec/controllers/admin/staff_action_logs_controller_spec.rb
rename to spec/requests/admin/staff_action_logs_controller_spec.rb
index 3da6dfa158..12acd22244 100644
--- a/spec/controllers/admin/staff_action_logs_controller_spec.rb
+++ b/spec/requests/admin/staff_action_logs_controller_spec.rb
@@ -5,29 +5,30 @@ describe Admin::StaffActionLogsController do
expect(Admin::StaffActionLogsController < Admin::AdminController).to eq(true)
end
- let!(:user) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
- context '.index' do
+ before do
+ sign_in(admin)
+ end
+ describe '#index' do
it 'generates logs' do
-
topic = Fabricate(:topic)
- _record = StaffActionLogger.new(Discourse.system_user).log_topic_delete_recover(topic, "delete_topic")
+ StaffActionLogger.new(Discourse.system_user).log_topic_delete_recover(topic, "delete_topic")
- get :index, params: { action_id: UserHistory.actions[:delete_topic] }, format: :json
+ get "/admin/logs/staff_action_logs.json", params: { action_id: UserHistory.actions[:delete_topic] }
json = JSON.parse(response.body)
- expect(response).to be_success
+ 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")
expect(json["user_history_actions"]).to include("id" => UserHistory.actions[:delete_topic], "name" => 'delete_topic')
-
end
end
- context '.diff' do
+ describe '#diff' do
it 'can generate diffs for theme changes' do
theme = Theme.new(user_id: -1, name: 'bob')
theme.set_field(target: :mobile, name: :scss, value: 'body {.up}')
@@ -40,8 +41,8 @@ describe Admin::StaffActionLogsController do
record = StaffActionLogger.new(Discourse.system_user)
.log_theme_change(original_json, theme)
- get :diff, params: { id: record.id }, format: :json
- expect(response).to be_success
+ get "/admin/logs/staff_action_logs/#{record.id}/diff.json"
+ expect(response.status).to eq(200)
parsed = JSON.parse(response.body)
expect(parsed["side_by_side"]).to include("up")
diff --git a/spec/requests/admin/themes_controller_spec.rb b/spec/requests/admin/themes_controller_spec.rb
new file mode 100644
index 0000000000..e0416191af
--- /dev/null
+++ b/spec/requests/admin/themes_controller_spec.rb
@@ -0,0 +1,202 @@
+require 'rails_helper'
+require_dependency 'theme_serializer'
+
+describe Admin::ThemesController do
+ let(:admin) { Fabricate(:admin) }
+
+ it "is a subclass of AdminController" do
+ expect(Admin::UsersController < Admin::AdminController).to eq(true)
+ end
+
+ before do
+ sign_in(admin)
+ end
+
+ describe '#generate_key_pair' do
+ it 'can generate key pairs' do
+ post "/admin/themes/generate_key_pair.json"
+ expect(response.status).to eq(200)
+ json = JSON.parse(response.body)
+ expect(json["private_key"]).to include("RSA PRIVATE KEY")
+ expect(json["public_key"]).to include("ssh-rsa ")
+ end
+ end
+
+ describe '#upload_asset' do
+ let(:upload) do
+ Rack::Test::UploadedFile.new(file_from_fixtures("fake.woff2", "woff2"))
+ end
+
+ it 'can create a theme upload' do
+ post "/admin/themes/upload_asset.json", params: { file: upload }
+ expect(response.status).to eq(201)
+
+ upload = Upload.find_by(original_filename: "fake.woff2")
+
+ expect(upload.id).not_to be_nil
+ expect(JSON.parse(response.body)["upload_id"]).to eq(upload.id)
+ end
+ end
+
+ describe '#import' do
+ let(:theme_file) do
+ Rack::Test::UploadedFile.new(file_from_fixtures("sam-s-simple-theme.dcstyle.json", "json"))
+ end
+
+ let(:image) do
+ file_from_fixtures("logo.png")
+ end
+
+ it 'can import a theme with an upload' do
+ upload = Fabricate(:upload)
+ theme = Theme.new(name: 'with-upload', user_id: -1)
+ upload = UploadCreator.new(image, "logo.png").create_for(-1)
+ theme.set_field(target: :common, name: :logo, upload_id: upload.id, type: :theme_upload_var)
+ theme.save!
+
+ json = ThemeWithEmbeddedUploadsSerializer.new(theme, root: 'theme').to_json
+ theme.destroy
+
+ temp = Tempfile.new
+ temp.write(json)
+ temp.rewind
+
+ uploaded_json = Rack::Test::UploadedFile.new(temp)
+ upload.destroy
+
+ post "/admin/themes/import.json", params: { theme: uploaded_json }
+ expect(response.status).to eq(201)
+ temp.unlink
+
+ theme = Theme.last
+ expect(theme.theme_fields.count).to eq(1)
+ expect(theme.theme_fields.first.upload).not_to eq(nil)
+ expect(theme.theme_fields.first.upload.filesize).to eq(upload.filesize)
+ expect(theme.theme_fields.first.upload.sha1).to eq(upload.sha1)
+ expect(theme.theme_fields.first.upload.original_filename).to eq(upload.original_filename)
+ end
+
+ it 'imports a theme' do
+ post "/admin/themes/import.json", params: { theme: theme_file }
+ expect(response.status).to eq(201)
+
+ json = ::JSON.parse(response.body)
+
+ expect(json["theme"]["name"]).to eq("Sam's Simple Theme")
+ expect(json["theme"]["theme_fields"].length).to eq(2)
+ expect(UserHistory.where(action: UserHistory.actions[:change_theme]).count).to eq(1)
+ end
+ end
+
+ describe '#index' do
+ it 'correctly returns themes' do
+ ColorScheme.destroy_all
+ Theme.destroy_all
+
+ theme = Theme.new(name: 'my name', user_id: -1)
+ theme.set_field(target: :common, name: :scss, value: '.body{color: black;}')
+ theme.set_field(target: :desktop, name: :after_header, value: 'test')
+
+ theme.remote_theme = RemoteTheme.new(
+ remote_url: 'awesome.git',
+ remote_version: '7',
+ local_version: '8',
+ remote_updated_at: Time.zone.now
+ )
+
+ theme.save!
+
+ # this will get serialized as well
+ ColorScheme.create_from_base(name: "test", colors: [])
+
+ get "/admin/themes.json"
+
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)
+
+ expect(json["extras"]["color_schemes"].length).to eq(2)
+ theme_json = json["themes"].find { |t| t["id"] == theme.id }
+ expect(theme_json["theme_fields"].length).to eq(2)
+ expect(theme_json["remote_theme"]["remote_version"]).to eq("7")
+ end
+ end
+
+ describe '#create' do
+ it 'creates a theme' do
+ post "/admin/themes.json", params: {
+ theme: {
+ name: 'my test name',
+ theme_fields: [name: 'scss', target: 'common', value: 'body{color: red;}']
+ }
+ }
+
+ expect(response.status).to eq(201)
+
+ json = ::JSON.parse(response.body)
+
+ expect(json["theme"]["theme_fields"].length).to eq(1)
+ expect(UserHistory.where(action: UserHistory.actions[:change_theme]).count).to eq(1)
+ end
+ end
+
+ describe '#update' do
+ let(:theme) { Theme.create(name: 'my name', user_id: -1) }
+
+ it 'can change default theme' do
+ SiteSetting.default_theme_key = nil
+
+ put "/admin/themes/#{theme.id}.json", params: {
+ id: theme.id, theme: { default: true }
+ }
+
+ expect(response.status).to eq(200)
+ expect(SiteSetting.default_theme_key).to eq(theme.key)
+ end
+
+ it 'can unset default theme' do
+ SiteSetting.default_theme_key = theme.key
+
+ put "/admin/themes/#{theme.id}.json", params: {
+ theme: { default: false }
+ }
+
+ expect(response.status).to eq(200)
+ expect(SiteSetting.default_theme_key).to be_blank
+ end
+
+ it 'updates a theme' do
+ theme.set_field(target: :common, name: :scss, value: '.body{color: black;}')
+ theme.save
+
+ child_theme = Theme.create(name: 'my name', user_id: -1)
+
+ upload = Fabricate(:upload)
+
+ put "/admin/themes/#{theme.id}.json", params: {
+ theme: {
+ child_theme_ids: [child_theme.id],
+ name: 'my test name',
+ theme_fields: [
+ { name: 'scss', target: 'common', value: '' },
+ { name: 'scss', target: 'desktop', value: 'body{color: blue;}' },
+ { name: 'bob', target: 'common', value: '', type_id: 2, upload_id: upload.id },
+ ]
+ }
+ }
+
+ expect(response.status).to eq(200)
+
+ json = ::JSON.parse(response.body)
+
+ fields = json["theme"]["theme_fields"].sort { |a, b| a["value"] <=> b["value"] }
+
+ expect(fields[0]["value"]).to eq('')
+ expect(fields[0]["upload_id"]).to eq(upload.id)
+ expect(fields[1]["value"]).to eq('body{color: blue;}')
+ expect(fields.length).to eq(2)
+ expect(json["theme"]["child_themes"].length).to eq(1)
+ expect(UserHistory.where(action: UserHistory.actions[:change_theme]).count).to eq(1)
+ end
+ end
+end
diff --git a/spec/controllers/admin/user_fields_controller_spec.rb b/spec/requests/admin/user_fields_controller_spec.rb
similarity index 69%
rename from spec/controllers/admin/user_fields_controller_spec.rb
rename to spec/requests/admin/user_fields_controller_spec.rb
index de46a1cf0c..f388eeb419 100644
--- a/spec/controllers/admin/user_fields_controller_spec.rb
+++ b/spec/requests/admin/user_fields_controller_spec.rb
@@ -1,92 +1,93 @@
require 'rails_helper'
describe Admin::UserFieldsController do
-
it "is a subclass of AdminController" do
expect(Admin::UserFieldsController < Admin::AdminController).to eq(true)
end
context "when logged in" do
- let!(:user) { log_in(:admin) }
+ let(:admin) { Fabricate(:admin) }
- context '.create' do
+ before do
+ sign_in(admin)
+ end
+
+ describe '#create' do
it "creates a user field" do
expect {
- post :create, params: {
+ post "/admin/customize/user_fields.json", params: {
user_field: { name: 'hello', description: 'hello desc', field_type: 'text' }
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
}.to change(UserField, :count).by(1)
end
it "creates a user field with options" do
expect do
- post :create, params: {
+ post "/admin/customize/user_fields.json", params: {
user_field: {
name: 'hello',
description: 'hello desc',
field_type: 'dropdown',
options: ['a', 'b', 'c']
}
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
end.to change(UserField, :count).by(1)
expect(UserFieldOption.count).to eq(3)
end
end
- context '.index' do
+ describe '#index' do
let!(:user_field) { Fabricate(:user_field) }
it "returns a list of user fields" do
- get :index, format: :json
- expect(response).to be_success
+ get "/admin/customize/user_fields.json"
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json['user_fields']).to be_present
end
end
- context '.destroy' do
+ describe '#destroy' do
let!(:user_field) { Fabricate(:user_field) }
it "deletes the user field" do
expect {
- delete :destroy, params: { id: user_field.id }, format: :json
- expect(response).to be_success
+ delete "/admin/customize/user_fields/#{user_field.id}.json"
+ expect(response.status).to eq(200)
}.to change(UserField, :count).by(-1)
end
end
- context '.update' do
+ describe '#update' do
let!(:user_field) { Fabricate(:user_field) }
it "updates the user field" do
- put :update, params: {
- id: user_field.id,
+ put "/admin/customize/user_fields/#{user_field.id}.json", params: {
user_field: { name: 'fraggle', field_type: 'confirm', description: 'muppet' }
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
user_field.reload
expect(user_field.name).to eq('fraggle')
expect(user_field.field_type).to eq('confirm')
end
it "updates the user field options" do
- put :update, params: {
- id: user_field.id,
+ put "/admin/customize/user_fields/#{user_field.id}.json", params: {
user_field: {
name: 'fraggle',
field_type: 'dropdown',
description: 'muppet',
options: ['hello', 'hello', 'world']
}
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
user_field.reload
expect(user_field.name).to eq('fraggle')
expect(user_field.field_type).to eq('dropdown')
@@ -94,8 +95,7 @@ describe Admin::UserFieldsController do
end
it "keeps options when updating the user field" do
- put :update, params: {
- id: user_field.id,
+ put "/admin/customize/user_fields/#{user_field.id}.json", params: {
user_field: {
name: 'fraggle',
field_type: 'dropdown',
@@ -103,27 +103,25 @@ describe Admin::UserFieldsController do
options: ['hello', 'hello', 'world'],
position: 1
}
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
user_field.reload
expect(user_field.user_field_options.size).to eq(2)
- put :update, params: {
- id: user_field.id,
+ put "/admin/customize/user_fields/#{user_field.id}.json", params: {
user_field: {
name: 'fraggle',
field_type: 'dropdown',
description: 'muppet',
position: 2
}
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
user_field.reload
expect(user_field.user_field_options.size).to eq(2)
end
end
end
-
end
diff --git a/spec/requests/admin/users_controller_spec.rb b/spec/requests/admin/users_controller_spec.rb
index a89e92f9cf..67cf0ee5b9 100644
--- a/spec/requests/admin/users_controller_spec.rb
+++ b/spec/requests/admin/users_controller_spec.rb
@@ -4,6 +4,808 @@ RSpec.describe Admin::UsersController do
let(:admin) { Fabricate(:admin) }
let(:user) { Fabricate(:user) }
+ it 'is a subclass of AdminController' do
+ expect(Admin::UsersController < Admin::AdminController).to eq(true)
+ end
+
+ before do
+ sign_in(admin)
+ end
+
+ describe '#index' do
+ it 'returns success with JSON' do
+ get "/admin/users/list.json"
+ expect(response.status).to eq(200)
+ expect(JSON.parse(response.body)).to be_present
+ end
+
+ context 'when showing emails' do
+ it "returns email for all the users" do
+ get "/admin/users/list.json", params: { show_emails: "true" }
+ expect(response.status).to eq(200)
+ data = ::JSON.parse(response.body)
+ data.each do |user|
+ expect(user["email"]).to be_present
+ end
+ end
+
+ it "logs only 1 enty" do
+ expect do
+ get "/admin/users/list.json", params: { show_emails: "true" }
+ end.to change { UserHistory.where(action: UserHistory.actions[:check_email], acting_user_id: admin.id).count }.by(1)
+ expect(response.status).to eq(200)
+ end
+ end
+ end
+
+ describe '#show' do
+ context 'an existing user' do
+ it 'returns success' do
+ get "/admin/users/#{user.id}.json"
+ expect(response.status).to eq(200)
+ end
+ end
+
+ context 'a non-existing user' do
+ it 'returns 404 error' do
+ get "/admin/users/0.json"
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
+ describe '#approve' do
+ let(:evil_trout) { Fabricate(:evil_trout, approved: false) }
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{evil_trout.id}/approve.json"
+ expect(response.status).to eq(404)
+ evil_trout.reload
+ expect(evil_trout.approved).to eq(false)
+ end
+
+ it 'calls approve' do
+ put "/admin/users/#{evil_trout.id}/approve.json"
+ expect(response.status).to eq(200)
+ evil_trout.reload
+ expect(evil_trout.approved).to eq(true)
+ end
+ end
+
+ describe '#approve_bulk' do
+ let(:evil_trout) { Fabricate(:evil_trout, approved: false) }
+
+ it "does nothing without uesrs" do
+ put "/admin/users/approve-bulk.json"
+ evil_trout.reload
+ expect(response.status).to eq(200)
+ expect(evil_trout.approved).to eq(false)
+ end
+
+ it "won't approve the user when not allowed" do
+ sign_in(user)
+ put "/admin/users/approve-bulk.json", params: { users: [evil_trout.id] }
+ expect(response.status).to eq(404)
+ evil_trout.reload
+ expect(evil_trout.approved).to eq(false)
+ end
+
+ it "approves the user when permitted" do
+ put "/admin/users/approve-bulk.json", params: { users: [evil_trout.id] }
+ expect(response.status).to eq(200)
+ evil_trout.reload
+ expect(evil_trout.approved).to eq(true)
+ end
+ end
+
+ describe '#generate_api_key' do
+ it 'calls generate_api_key' do
+ post "/admin/users/#{user.id}/generate_api_key.json"
+ expect(response.status).to eq(200)
+ json = JSON.parse(response.body)
+ expect(json["api_key"]["user"]["id"]).to eq(user.id)
+ expect(json["api_key"]["key"]).to be_present
+ end
+ end
+
+ describe '#revoke_api_key' do
+ it 'calls revoke_api_key' do
+ ApiKey.create!(user: user, key: SecureRandom.hex)
+ delete "/admin/users/#{user.id}/revoke_api_key.json"
+ expect(response.status).to eq(200)
+ expect(ApiKey.where(user: user).count).to eq(0)
+ end
+ end
+
+ describe '#suspend' do
+ let(:post) { Fabricate(:post) }
+ let(:suspend_params) do
+ { suspend_until: 5.hours.from_now,
+ reason: "because of this post",
+ post_id: post.id }
+ end
+
+ it "works properly" do
+ expect(user).not_to be_suspended
+ put "/admin/users/#{user.id}/suspend.json", params: {
+ suspend_until: 5.hours.from_now,
+ reason: "because I said so"
+ }
+
+ expect(response.status).to eq(200)
+
+ user.reload
+ expect(user).to be_suspended
+ expect(user.suspended_at).to be_present
+ expect(user.suspended_till).to be_present
+
+ log = UserHistory.where(target_user_id: user.id).order('id desc').first
+ expect(log.details).to match(/because I said so/)
+ end
+
+ context "with an associated post" do
+ it "can have an associated post" do
+ put "/admin/users/#{user.id}/suspend.json", params: suspend_params
+
+ expect(response.status).to eq(200)
+
+ log = UserHistory.where(target_user_id: user.id).order('id desc').first
+ expect(log.post_id).to eq(post.id)
+ end
+
+ it "can delete an associated post" do
+ put "/admin/users/#{user.id}/suspend.json", params: suspend_params.merge(post_action: 'delete')
+ post.reload
+ expect(post.deleted_at).to be_present
+ expect(response.status).to eq(200)
+ end
+
+ it "can edit an associated post" do
+ put "/admin/users/#{user.id}/suspend.json", params: suspend_params.merge(
+ post_action: 'edit',
+ post_edit: 'this is the edited content'
+ )
+
+ expect(response.status).to eq(200)
+ post.reload
+ expect(post.deleted_at).to be_blank
+ expect(post.raw).to eq("this is the edited content")
+ expect(response.status).to eq(200)
+ end
+ end
+
+ it "can send a message to the user" do
+ put "/admin/users/#{user.id}/suspend.json", params: {
+ suspend_until: 10.days.from_now,
+ reason: "short reason",
+ message: "long reason"
+ }
+
+ expect(response.status).to eq(200)
+
+ expect(Jobs::CriticalUserEmail.jobs.size).to eq(1)
+ job_args = Jobs::CriticalUserEmail.jobs.first["args"].first
+ expect(job_args["type"]).to eq("account_suspended")
+ expect(job_args["user_id"]).to eq(user.id)
+
+ log = UserHistory.where(target_user_id: user.id).order('id desc').first
+ expect(log).to be_present
+ expect(log.details).to match(/short reason/)
+ expect(log.details).to match(/long reason/)
+ end
+
+ it "also revokes any api keys" do
+ Fabricate(:api_key, user: user)
+ put "/admin/users/#{user.id}/suspend.json", params: suspend_params
+
+ expect(response.status).to eq(200)
+ user.reload
+
+ expect(user).to be_suspended
+ expect(ApiKey.where(user_id: user.id).count).to eq(0)
+ end
+ end
+
+ describe '#revoke_admin' do
+ let(:another_admin) { Fabricate(:admin) }
+
+ it 'raises an error unless the user can revoke access' do
+ sign_in(user)
+ put "/admin/users/#{another_admin.id}/revoke_admin.json"
+ expect(response.status).to eq(404)
+ another_admin.reload
+ expect(another_admin.admin).to eq(true)
+ end
+
+ it 'updates the admin flag' do
+ put "/admin/users/#{another_admin.id}/revoke_admin.json"
+ expect(response.status).to eq(200)
+ another_admin.reload
+ expect(another_admin.admin).to eq(false)
+ end
+ end
+
+ describe '#grant_admin' do
+ let(:another_user) { Fabricate(:coding_horror) }
+
+ after do
+ $redis.flushall
+ end
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{another_user.id}/grant_admin.json"
+ expect(response.status).to eq(404)
+ expect(AdminConfirmation.exists_for?(another_user.id)).to eq(false)
+ end
+
+ it "returns a 403 if the username doesn't exist" do
+ put "/admin/users/123123/grant_admin.json"
+ expect(response.status).to eq(403)
+ end
+
+ it 'updates the admin flag' do
+ expect(AdminConfirmation.exists_for?(another_user.id)).to eq(false)
+ put "/admin/users/#{another_user.id}/grant_admin.json"
+ expect(response.status).to eq(200)
+ expect(AdminConfirmation.exists_for?(another_user.id)).to eq(true)
+ end
+ end
+
+ describe '#add_group' do
+ let(:group) { Fabricate(:group) }
+
+ it 'adds the user to the group' do
+ post "/admin/users/#{user.id}/groups.json", params: {
+ group_id: group.id
+ }
+
+ 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
+
+ expect(group_history.action).to eq(GroupHistory.actions[:add_user_to_group])
+ expect(group_history.acting_user).to eq(admin)
+ expect(group_history.target_user).to eq(user)
+
+ # Doing it again doesn't raise an error
+ post "/admin/users/#{user.id}/groups.json", params: {
+ group_id: group.id
+ }
+
+ expect(response.status).to eq(200)
+ end
+ end
+
+ describe '#remove_group' do
+ it "also clears the user's primary group" do
+ g = Fabricate(:group)
+ u = Fabricate(:user, primary_group: g)
+ delete "/admin/users/#{u.id}/groups/#{g.id}.json"
+
+ expect(response.status).to eq(200)
+ expect(u.reload.primary_group).to eq(nil)
+ end
+ end
+
+ describe '#trust_level' do
+ let(:another_user) { Fabricate(:coding_horror, created_at: 1.month.ago) }
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{another_user.id}/trust_level.json"
+ expect(response.status).to eq(404)
+ end
+
+ it "returns a 422 if the username doesn't exist" do
+ put "/admin/users/123123/trust_level.json"
+ expect(response.status).to eq(422)
+ end
+
+ it "upgrades the user's trust level" do
+ put "/admin/users/#{another_user.id}/trust_level.json", params: { level: 2 }
+
+ expect(response.status).to eq(200)
+ another_user.reload
+ expect(another_user.trust_level).to eq(2)
+
+ expect(UserHistory.where(
+ target_user: another_user,
+ acting_user: admin,
+ action: UserHistory.actions[:change_trust_level]
+ ).count).to eq(1)
+ end
+
+ it "raises no error when demoting a user below their current trust level (locks trust level)" do
+ stat = another_user.user_stat
+ stat.topics_entered = SiteSetting.tl1_requires_topics_entered + 1
+ stat.posts_read_count = SiteSetting.tl1_requires_read_posts + 1
+ stat.time_read = SiteSetting.tl1_requires_time_spent_mins * 60
+ stat.save!
+ another_user.update_attributes(trust_level: TrustLevel[1])
+
+ put "/admin/users/#{another_user.id}/trust_level.json", params: {
+ level: TrustLevel[0]
+ }
+
+ 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])
+ end
+ end
+
+ describe '#grant_moderation' do
+ let(:another_user) { Fabricate(:coding_horror) }
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{another_user.id}/grant_moderation.json"
+ expect(response.status).to eq(404)
+ end
+
+ it "returns a 403 if the username doesn't exist" do
+ put "/admin/users/123123/grant_moderation.json"
+ expect(response.status).to eq(403)
+ end
+
+ it 'updates the moderator flag' do
+ put "/admin/users/#{another_user.id}/grant_moderation.json"
+ expect(response.status).to eq(200)
+ another_user.reload
+ expect(another_user.moderator).to eq(true)
+ end
+ end
+
+ describe '#revoke_moderation' do
+ let(:moderator) { Fabricate(:moderator) }
+
+ it 'raises an error unless the user can revoke access' do
+ sign_in(user)
+ put "/admin/users/#{moderator.id}/revoke_moderation.json"
+ expect(response.status).to eq(404)
+ moderator.reload
+ expect(moderator.moderator).to eq(true)
+ end
+
+ it 'updates the moderator flag' do
+ put "/admin/users/#{moderator.id}/revoke_moderation.json"
+ expect(response.status).to eq(200)
+ moderator.reload
+ expect(moderator.moderator).to eq(false)
+ end
+ end
+
+ describe '#primary_group' do
+ let(:group) { Fabricate(:group) }
+ let(:another_user) { Fabricate(:coding_horror) }
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{another_user.id}/primary_group.json"
+ expect(response.status).to eq(404)
+ another_user.reload
+ expect(another_user.primary_group_id).to eq(nil)
+ end
+
+ it "returns a 404 if the user doesn't exist" do
+ put "/admin/users/123123/primary_group.json"
+ expect(response.status).to eq(403)
+ end
+
+ it "changes the user's primary group" do
+ group.add(another_user)
+ put "/admin/users/#{another_user.id}/primary_group.json", params: {
+ primary_group_id: group.id
+ }
+
+ expect(response.status).to eq(200)
+ another_user.reload
+ expect(another_user.primary_group_id).to eq(group.id)
+ end
+
+ it "doesn't change primary group if they aren't a member of the group" do
+ put "/admin/users/#{another_user.id}/primary_group.json", params: {
+ primary_group_id: group.id
+ }
+
+ expect(response.status).to eq(200)
+ another_user.reload
+ expect(another_user.primary_group_id).to eq(nil)
+ end
+
+ it "remove user's primary group" do
+ group.add(another_user)
+
+ put "/admin/users/#{another_user.id}/primary_group.json", params: {
+ primary_group_id: ""
+ }
+
+ expect(response.status).to eq(200)
+ another_user.reload
+ expect(another_user.primary_group_id).to eq(nil)
+ end
+ end
+
+ describe '#destroy' do
+ let(:delete_me) { Fabricate(:user) }
+
+ it "returns a 403 if the user doesn't exist" do
+ delete "/admin/users/123123drink.json"
+ expect(response.status).to eq(403)
+ end
+
+ context "user has post" do
+ let(:topic) { Fabricate(:topic, user: delete_me) }
+ let!(:post) { Fabricate(:post, topic: topic, user: delete_me) }
+
+ it "returns an api response that the user can't be deleted because it has posts" do
+ delete "/admin/users/#{delete_me.id}.json"
+ expect(response.status).to eq(403)
+ json = ::JSON.parse(response.body)
+ expect(json['deleted']).to eq(false)
+ end
+
+ it "doesn't return an error if delete_posts == true" do
+ delete "/admin/users/#{delete_me.id}.json", params: { delete_posts: true }
+ expect(response.status).to eq(200)
+ expect(Post.where(id: post.id).count).to eq(0)
+ expect(Topic.where(id: topic.id).count).to eq(0)
+ expect(User.where(id: delete_me.id).count).to eq(0)
+ end
+ end
+
+ it "deletes the user record" do
+ delete "/admin/users/#{delete_me.id}.json"
+ expect(response.status).to eq(200)
+ expect(User.where(id: delete_me.id).count).to eq(0)
+ end
+ end
+
+ describe '#activate' do
+ let(:reg_user) { Fabricate(:inactive_user) }
+
+ it "returns success" do
+ put "/admin/users/#{reg_user.id}/activate.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json['success']).to eq("OK")
+ reg_user.reload
+ expect(reg_user.active).to eq(true)
+ end
+
+ it "should confirm email even when the tokens are expired" do
+ reg_user.email_tokens.update_all(confirmed: false, expired: true)
+
+ reg_user.reload
+ expect(reg_user.email_confirmed?).to eq(false)
+
+ put "/admin/users/#{reg_user.id}/activate.json"
+ expect(response.status).to eq(200)
+
+ reg_user.reload
+ expect(reg_user.email_confirmed?).to eq(true)
+ end
+ end
+
+ describe '#log_out' do
+ let(:reg_user) { Fabricate(:user) }
+
+ it "returns success" do
+ post "/admin/users/#{reg_user.id}/log_out.json"
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json['success']).to eq("OK")
+ end
+
+ it "returns 404 when user_id does not exist" do
+ post "/admin/users/123123drink/log_out.json"
+ expect(response.status).to eq(404)
+ end
+ end
+
+ describe '#silence' do
+ let(:reg_user) { Fabricate(:user) }
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{reg_user.id}/silence.json"
+ expect(response.status).to eq(404)
+ reg_user.reload
+ expect(reg_user).not_to be_silenced
+ end
+
+ it "returns a 403 if the user doesn't exist" do
+ put "/admin/users/123123/silence.json"
+ expect(response.status).to eq(403)
+ end
+
+ it "punishes the user for spamming" do
+ put "/admin/users/#{reg_user.id}/silence.json"
+ expect(response.status).to eq(200)
+ reg_user.reload
+ expect(reg_user).to be_silenced
+ end
+
+ it "can have an associated post" do
+ silence_post = Fabricate(:post, user: reg_user)
+
+ put "/admin/users/#{reg_user.id}/silence.json", params: {
+ post_id: silence_post.id,
+ post_action: 'edit',
+ post_edit: "this is the new contents for the post"
+ }
+ expect(response.status).to eq(200)
+
+ silence_post.reload
+ expect(silence_post.raw).to eq("this is the new contents for the post")
+
+ log = UserHistory.where(
+ target_user_id: reg_user.id,
+ action: UserHistory.actions[:silence_user]
+ ).first
+ expect(log).to be_present
+ expect(log.post_id).to eq(silence_post.id)
+
+ reg_user.reload
+ expect(reg_user).to be_silenced
+ end
+
+ it "will set a length of time if provided" do
+ future_date = 1.month.from_now.to_date
+ put "/admin/users/#{reg_user.id}/silence.json", params: {
+ silenced_till: future_date
+ }
+
+ expect(response.status).to eq(200)
+ reg_user.reload
+ expect(reg_user).to be_silenced
+ expect(reg_user.silenced_till).to eq(future_date)
+ end
+
+ it "will send a message if provided" do
+ expect do
+ put "/admin/users/#{reg_user.id}/silence.json", params: {
+ message: "Email this to the user"
+ }
+ end.to change { Jobs::CriticalUserEmail.jobs.size }.by(1)
+
+ expect(response.status).to eq(200)
+ reg_user.reload
+ expect(reg_user).to be_silenced
+ end
+ end
+
+ describe '#unsilence' do
+ let(:reg_user) { Fabricate(:user, silenced_till: 10.years.from_now) }
+
+ it "raises an error when the user doesn't have permission" do
+ sign_in(user)
+ put "/admin/users/#{reg_user.id}/unsilence.json"
+ expect(response.status).to eq(404)
+ end
+
+ it "returns a 403 if the user doesn't exist" do
+ put "/admin/users/123123/unsilence.json"
+ expect(response.status).to eq(403)
+ end
+
+ it "unsilences the user" do
+ put "/admin/users/#{reg_user.id}/unsilence.json"
+ expect(response.status).to eq(200)
+ reg_user.reload
+ expect(reg_user.silenced?).to eq(false)
+ log = UserHistory.where(
+ target_user_id: reg_user.id,
+ action: UserHistory.actions[:unsilence_user]
+ ).first
+ expect(log).to be_present
+ end
+ end
+
+ describe '#reject_bulk' do
+ let(:reject_me) { Fabricate(:user) }
+ let(:reject_me_too) { Fabricate(:user) }
+
+ it 'does nothing without users' do
+ delete "/admin/users/reject-bulk.json"
+ expect(response.status).to eq(200)
+ expect(User.where(id: reject_me.id).count).to eq(1)
+ expect(User.where(id: reject_me_too.id).count).to eq(1)
+ end
+
+ it "won't delete users if not allowed" do
+ sign_in(user)
+ delete "/admin/users/reject-bulk.json", params: {
+ users: [reject_me.id]
+ }
+ expect(response.status).to eq(404)
+ expect(User.where(id: reject_me.id).count).to eq(1)
+ end
+
+ it "reports successes" do
+ delete "/admin/users/reject-bulk.json", params: {
+ users: [reject_me.id, reject_me_too.id]
+ }
+
+ 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)
+ expect(User.where(id: reject_me.id).count).to eq(0)
+ expect(User.where(id: reject_me_too.id).count).to eq(0)
+ end
+
+ context 'failures' do
+ it 'can handle some successes and some failures' do
+ stat = reject_me_too.user_stat
+ stat.first_post_created_at = (SiteSetting.delete_user_max_post_age.to_i + 1).days.ago
+ stat.post_count = 10
+ stat.save!
+
+ delete "/admin/users/reject-bulk.json", params: {
+ users: [reject_me.id, reject_me_too.id]
+ }
+
+ 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)
+ expect(User.where(id: reject_me.id).count).to eq(0)
+ expect(User.where(id: reject_me_too.id).count).to eq(1)
+ end
+
+ it 'reports failure due to a user still having posts' do
+ Fabricate(:post, user: reject_me)
+
+ delete "/admin/users/reject-bulk.json", params: {
+ users: [reject_me.id]
+ }
+
+ 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)
+ expect(User.where(id: reject_me.id).count).to eq(1)
+ end
+ end
+ end
+
+ describe '#ip_info' do
+ it "uses ipinfo.io webservice to retrieve the info" do
+ ip = "192.168.1.1"
+ ip_data = {
+ city: "Jeddah",
+ country: "SA",
+ ip: ip
+ }
+ url = "https://ipinfo.io/#{ip}/json"
+
+ stub_request(:get, url).to_return(status: 200, body: ip_data.to_json)
+ get "/admin/users/ip-info.json", params: { ip: ip }
+ expect(response.status).to eq(200)
+ expect(JSON.parse(response.body).symbolize_keys).to eq(ip_data)
+ end
+ end
+
+ describe '#delete_other_accounts_with_same_ip' do
+ it "works" do
+ user_a = Fabricate(:user, ip_address: "42.42.42.42")
+ user_b = Fabricate(:user, ip_address: "42.42.42.42")
+
+ delete "/admin/users/delete-others-with-same-ip.json", params: {
+ ip: "42.42.42.42", exclude: -1, order: "trust_level DESC"
+ }
+ expect(response.status).to eq(200)
+ expect(User.where(id: user_a.id).count).to eq(0)
+ expect(User.where(id: user_b.id).count).to eq(0)
+ end
+ end
+
+ describe '#invite_admin' do
+ let(:api_key) { Fabricate(:api_key, user: admin, key: SecureRandom.hex) }
+ let(:api_params) do
+ { api_key: api_key.key, api_username: admin.username }
+ end
+
+ it "doesn't work when not via API" do
+ post "/admin/users/invite_admin.json", params: {
+ name: 'Bill', username: 'bill22', email: 'bill@bill.com'
+ }
+
+ expect(response.status).to eq(403)
+ end
+
+ it 'should invite admin' do
+ expect do
+ post "/admin/users/invite_admin.json", params: api_params.merge(
+ name: 'Bill', username: 'bill22', email: 'bill@bill.com'
+ )
+ end.to change { Jobs::CriticalUserEmail.jobs.size }.by(1)
+
+ expect(response.status).to eq(200)
+
+ u = User.find_by_email('bill@bill.com')
+ expect(u.name).to eq("Bill")
+ expect(u.username).to eq("bill22")
+ expect(u.admin).to eq(true)
+ end
+
+ it "doesn't send the email with send_email falsey" do
+ expect do
+ post "/admin/users/invite_admin.json", params: api_params.merge(
+ name: 'Bill', username: 'bill22', email: 'bill@bill.com', send_email: '0'
+ )
+ end.to change { Jobs::CriticalUserEmail.jobs.size }.by(0)
+
+ expect(response.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json["password_url"]).to be_present
+ end
+ end
+
+ describe '#sync_sso' do
+ let(:sso) { SingleSignOn.new }
+ let(:sso_secret) { "sso secret" }
+
+ before do
+ SiteSetting.email_editable = false
+ SiteSetting.sso_url = "https://www.example.com/sso"
+ SiteSetting.enable_sso = true
+ SiteSetting.sso_overrides_email = true
+ SiteSetting.sso_overrides_name = true
+ SiteSetting.sso_overrides_username = true
+ SiteSetting.sso_secret = sso_secret
+ sso.sso_secret = sso_secret
+ end
+
+ it 'can sync up with the sso' do
+ sso.name = "Bob The Bob"
+ sso.username = "bob"
+ sso.email = "bob@bob.com"
+ sso.external_id = "1"
+
+ user = DiscourseSingleSignOn.parse(sso.payload).lookup_or_create_user
+
+ sso.name = "Bill"
+ sso.username = "Hokli$$!!"
+ sso.email = "bob2@bob.com"
+
+ post "/admin/users/sync_sso.json", params: Rack::Utils.parse_query(sso.payload)
+ expect(response.status).to eq(200)
+
+ user.reload
+ expect(user.email).to eq("bob2@bob.com")
+ expect(user.name).to eq("Bill")
+ expect(user.username).to eq("Hokli")
+ end
+
+ it 'should create new users' do
+ sso.name = "Dr. Claw"
+ sso.username = "dr_claw"
+ sso.email = "dr@claw.com"
+ sso.external_id = "2"
+ post "/admin/users/sync_sso.json", params: Rack::Utils.parse_query(sso.payload)
+ expect(response.status).to eq(200)
+
+ user = User.find_by_email('dr@claw.com')
+ expect(user).to be_present
+ expect(user.ip_address).to be_blank
+ end
+
+ it 'should return the right message if the record is invalid' do
+ sso.email = ""
+ sso.name = ""
+ sso.external_id = "1"
+
+ post "/admin/users/sync_sso.json", params: Rack::Utils.parse_query(sso.payload)
+ expect(response.status).to eq(403)
+ expect(JSON.parse(response.body)["message"]).to include("Primary email can't be blank")
+ end
+ end
+
describe '#disable_second_factor' do
let(:second_factor) { user.create_totp }
diff --git a/spec/controllers/admin/versions_controller_spec.rb b/spec/requests/admin/versions_controller_spec.rb
similarity index 73%
rename from spec/controllers/admin/versions_controller_spec.rb
rename to spec/requests/admin/versions_controller_spec.rb
index 62c8cea39d..f8ef30aa50 100644
--- a/spec/controllers/admin/versions_controller_spec.rb
+++ b/spec/requests/admin/versions_controller_spec.rb
@@ -15,21 +15,23 @@ describe Admin::VersionsController do
end
context 'while logged in as an admin' do
+ let(:admin) { Fabricate(:admin) }
before do
- @user = log_in(:admin)
+ sign_in(admin)
end
describe 'show' do
- subject { get :show, format: :json }
- it { is_expected.to be_success }
-
it 'should return the currently available version' do
- json = JSON.parse(subject.body)
+ get "/admin/version_check.json"
+ expect(response.status).to eq(200)
+ json = JSON.parse(response.body)
expect(json['latest_version']).to eq('1.2.33')
end
it "should return the installed version" do
- json = JSON.parse(subject.body)
+ get "/admin/version_check.json"
+ json = JSON.parse(response.body)
+ expect(response.status).to eq(200)
expect(json['installed_version']).to eq(Discourse::VERSION::STRING)
end
end
diff --git a/spec/controllers/admin/web_hooks_controller_spec.rb b/spec/requests/admin/web_hooks_controller_spec.rb
similarity index 65%
rename from spec/controllers/admin/web_hooks_controller_spec.rb
rename to spec/requests/admin/web_hooks_controller_spec.rb
index 6b793dd0de..eed31ce051 100644
--- a/spec/controllers/admin/web_hooks_controller_spec.rb
+++ b/spec/requests/admin/web_hooks_controller_spec.rb
@@ -7,14 +7,16 @@ describe Admin::WebHooksController do
end
context 'while logged in as an admin' do
- before do
- @user = log_in(:admin)
- end
let(:web_hook) { Fabricate(:web_hook) }
+ let(:admin) { Fabricate(:admin) }
+
+ before do
+ sign_in(admin)
+ end
describe '#create' do
it 'creates a webhook' do
- post :create, params: {
+ post "/admin/api/web_hooks.json", params: {
web_hook: {
payload_url: 'https://meta.discourse.org/',
content_type: 1,
@@ -26,16 +28,16 @@ describe Admin::WebHooksController do
group_ids: [],
category_ids: []
}
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
- expect(json["web_hook"]["payload_url"]).to be_present
+ expect(json["web_hook"]["payload_url"]).to eq("https://meta.discourse.org/")
end
it 'returns error when field is not filled correctly' do
- post :create, params: {
+ post "/admin/api/web_hooks.json", params: {
web_hook: {
content_type: 1,
secret: "a_secret_for_webhooks",
@@ -46,9 +48,9 @@ describe Admin::WebHooksController do
group_ids: [],
category_ids: []
}
- }, format: :json
+ }
- expect(response.status).to eq 422
+ expect(response.status).to eq(422)
response_body = JSON.parse(response.body)
expect(response_body["errors"]).to be_present
@@ -57,12 +59,14 @@ describe Admin::WebHooksController do
describe '#ping' do
it 'enqueues the ping event' do
- Jobs.expects(:enqueue)
- .with(:emit_web_hook_event, web_hook_id: web_hook.id, event_type: 'ping', event_name: 'ping')
+ expect do
+ post "/admin/api/web_hooks/#{web_hook.id}/ping.json"
+ end.to change { Jobs::EmitWebHookEvent.jobs.size }.by(1)
- post :ping, params: { id: web_hook.id }, format: :json
-
- expect(response).to be_success
+ expect(response.status).to eq(200)
+ job_args = Jobs::EmitWebHookEvent.jobs.first["args"].first
+ expect(job_args["web_hook_id"]).to eq(web_hook.id)
+ expect(job_args["event_type"]).to eq("ping")
end
end
end
diff --git a/spec/requests/categories_controller_spec.rb b/spec/requests/categories_controller_spec.rb
index 9f0b113aec..e3a76cacbf 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.status).to eq(200)
+ 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.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.status).to eq(200)
+ 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.status).to eq(200)
+ 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
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
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
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
diff --git a/spec/requests/directory_items_controller_spec.rb b/spec/requests/directory_items_controller_spec.rb
index c912634703..8a188db107 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.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_success
+ expect(response.status).to eq(200)
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.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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json).to be_present
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
diff --git a/spec/requests/email_controller_spec.rb b/spec/requests/email_controller_spec.rb
index 196b3b277a..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_success
+ expect(response.status).to eq(200)
expect(response.body).to include(topic.title)
end
end
@@ -155,9 +155,122 @@ 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.status).to eq(200)
expect(response.body).to_not include(private_topic.title)
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
diff --git a/spec/requests/embed_controller_spec.rb b/spec/requests/embed_controller_spec.rb
index 42b6f018d3..f7f5c11eee 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.status).to eq(200)
end
end
@@ -71,21 +71,45 @@ describe EmbedController do
context "with a host" do
let!(:embeddable_host) { Fabricate(:embeddable_host) }
+ let(:headers) { { 'REFERER' => embed_url } }
+
+ before do
+ SiteSetting.queue_jobs = false
+ end
it "raises an error with no referer" do
get '/embed/comments', params: { embed_url: embed_url }
expect(response.body).to match(I18n.t('embed.error'))
end
+ it "includes CSS from embedded_scss field" do
+ theme = Theme.create!(name: "Awesome blog", user_id: -1)
+ theme.set_default!
+
+ ThemeField.create!(
+ theme_id: theme.id,
+ name: "embedded_scss",
+ target_id: 0,
+ type_id: 1,
+ value: ".test-osama-15 {\n" + " color: red;\n" + "}\n"
+ )
+
+ topic_embed = Fabricate(:topic_embed, embed_url: embed_url)
+ post = Fabricate(:post, topic: topic_embed.topic)
+
+ get '/embed/comments', params: { embed_url: embed_url }, headers: headers
+
+ html = Nokogiri::HTML.fragment(response.body)
+ css_link = html.at("link[data-target=embedded_theme]").attribute("href").value
+
+ get css_link
+ expect(response.status).to eq(200)
+ expect(response.body).to include(".test-osama-15")
+ end
+
context "success" do
- let(:headers) { { 'REFERER' => embed_url } }
-
- before do
- SiteSetting.queue_jobs = false
- end
-
after do
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(response.headers['X-Frame-Options']).to eq("ALLOWALL")
end
@@ -139,7 +163,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.status).to eq(200)
end
it "works with the second host" do
@@ -147,7 +171,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.status).to eq(200)
end
it "works with a host with a path" do
@@ -155,7 +179,7 @@ describe EmbedController do
params: { embed_url: embed_url },
headers: { 'REFERER' => "https://example.com/some-other-path" }
- expect(response).to be_success
+ 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
new file mode 100644
index 0000000000..1fe2a15e7c
--- /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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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
diff --git a/spec/controllers/extra_locales_controller_spec.rb b/spec/requests/extra_locales_controller_spec.rb
similarity index 69%
rename from spec/controllers/extra_locales_controller_spec.rb
rename to spec/requests/extra_locales_controller_spec.rb
index c3aa308d51..a190489f4f 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_success
- 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_success
+ 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_success
+ expect(response.status).to eq(200)
expect(response.body.include?("github_badges")).to eq(true)
end
-
end
-
end
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 e239a9af30..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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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
diff --git a/spec/requests/groups_controller_spec.rb b/spec/requests/groups_controller_spec.rb
index b268542391..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_success
+ expect(response.status).to eq(200)
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
@@ -380,25 +380,49 @@ 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 }
-
- expect(response).to be_success
+ get "/groups/#{group.name}/mentionable.json"
+ expect(response.status).to eq(200)
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
+ get "/groups/#{group.name}/mentionable.json"
+ expect(response.status).to eq(200)
response_body = JSON.parse(response.body)
expect(response_body["mentionable"]).to eq(true)
end
end
+ describe '#messageable' do
+ it "should return the right response" do
+ sign_in(user)
+
+ get "/groups/#{group.name}/messageable.json"
+ expect(response.status).to eq(200)
+
+ response_body = JSON.parse(response.body)
+ expect(response_body["messageable"]).to eq(false)
+
+ group.update!(
+ messageable_level: Group::ALIAS_LEVELS[:everyone],
+ visibility_level: Group.visibility_levels[:staff]
+ )
+
+ get "/groups/#{group.name}/messageable.json"
+ expect(response.status).to eq(200)
+
+ response_body = JSON.parse(response.body)
+ expect(response_body["messageable"]).to eq(true)
+ end
+ end
+
describe '#update' do
let(:group) do
Fabricate(:group,
@@ -621,7 +645,7 @@ describe GroupsController do
order: 'last_seen_at', desc: true
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
members = JSON.parse(response.body)["members"]
@@ -629,7 +653,7 @@ describe GroupsController do
get "/groups/#{group.name}/members.json", params: { order: 'last_seen_at' }
- expect(response).to be_success
+ expect(response.status).to eq(200)
members = JSON.parse(response.body)["members"]
@@ -639,7 +663,7 @@ describe GroupsController do
order: 'last_posted_at', desc: true
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
members = JSON.parse(response.body)["members"]
@@ -649,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.status).to eq(200)
members = JSON.parse(response.body)["members"]
@@ -784,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.status).to eq(200)
group_history = GroupHistory.last
@@ -810,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.status).to eq(200)
end
it "adds by id" do
@@ -819,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.status).to eq(200)
end
it "adds by email" do
@@ -828,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.status).to eq(200)
end
it 'fails when multiple member already exists' do
@@ -896,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.status).to eq(200)
group_history = GroupHistory.last
@@ -914,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.status).to eq(200)
end
it 'should not allow an underprivilege user to add another user to a group' do
@@ -947,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.status).to eq(200)
end
it "removes by username" do
@@ -955,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.status).to eq(200)
end
it "removes user.primary_group_id when user is removed from group" do
@@ -972,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.status).to eq(200)
end
context 'public group' do
@@ -986,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.status).to eq(200)
end
end
@@ -998,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.status).to eq(200)
end
it 'should not allow a underprivilege user to leave a group for another user' do
@@ -1053,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.status).to eq(200)
result = JSON.parse(response.body)["logs"].last
@@ -1085,7 +1109,7 @@ describe GroupsController do
get "/groups/#{group.name}/logs.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
result = JSON.parse(response.body)["logs"].first
@@ -1108,7 +1132,7 @@ describe GroupsController do
filters: { "action" => "add_user_to_group" }
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
logs = JSON.parse(response.body)["logs"]
@@ -1143,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.status).to eq(200)
post = Post.last
topic = post.topic
@@ -1193,7 +1217,7 @@ describe GroupsController do
get '/groups/search.json'
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)
expected_ids = Group::AUTO_GROUPS.map { |name, id| id }
@@ -1205,7 +1229,7 @@ describe GroupsController do
['GO', 'nerys'].each do |term|
get "/groups/search.json?term=#{term}"
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)
expect(groups.length).to eq(1)
@@ -1214,7 +1238,7 @@ describe GroupsController do
get "/groups/search.json?term=KingOfTheNorth"
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)
expect(groups).to eq([])
@@ -1231,7 +1255,7 @@ describe GroupsController do
get "/groups/search.json?term=north"
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)
expect(groups.length).to eq(1)
@@ -1245,7 +1269,7 @@ describe GroupsController do
get '/groups/search.json?ignore_automatic=true'
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)
expect(groups.length).to eq(2)
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 e68387fa55..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_success
+ 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_success
+ 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
diff --git a/spec/requests/invites_controller_spec.rb b/spec/requests/invites_controller_spec.rb
index 4f622c196a..4b4586ce13 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) }
@@ -9,7 +8,7 @@ describe InvitesController do
it "returns error if invite not found" do
get "/invites/nopeNOPEnope"
- expect(response).to be_success
+ expect(response.status).to eq(200)
body = response.body
expect(body).to_not have_tag(:script, with: { src: '/assets/application.js' })
@@ -19,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.status).to eq(200)
body = response.body
expect(body).to have_tag(:script, with: { src: '/assets/application.js' })
@@ -30,11 +29,392 @@ describe InvitesController do
invite.update_attributes!(redeemed_at: 1.day.ago)
get "/invites/#{invite.invite_key}"
- expect(response).to be_success
+ expect(response.status).to eq(200)
body = response.body
expect(body).to_not have_tag(:script, with: { src: '/assets/application.js' })
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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.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'))
+ 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.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'))
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.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.status).to eq(200)
+ 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.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.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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ expect(Jobs::BulkInvite.jobs.size).to eq(1)
+ end
+ end
+ end
end
diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb
index 288d49cd29..0f72cedfa0 100644
--- a/spec/requests/list_controller_spec.rb
+++ b/spec/requests/list_controller_spec.rb
@@ -1,18 +1,42 @@
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
get "/#{Discourse.anonymous_filters[1]}", params: { page: -1024 }
- expect(response).to be_success
+ 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_success
+ expect(response.status).to eq(200)
+ end
+
+ (Discourse.anonymous_filters - [:categories]).each do |filter|
+ context "#{filter}" do
+ it "succeeds" do
+ get "/#{filter}"
+ expect(response.status).to eq(200)
+ 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.status).to eq(200)
+ parsed = JSON.parse(response.body)
+ expect(parsed["topic_list"]["topics"].length).to eq(1)
end
end
@@ -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.status).to eq(200)
+ expect(response.content_type).to eq('application/rss+xml')
+ end
+
+ it 'renders top RSS' do
+ get "/top.rss"
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.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)
+ end
+
+ it "does not suppress" do
+ get "/#{SiteSetting.homepage}.json", params: { category: category_one.id }
+ 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)
+ 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
diff --git a/spec/controllers/metadata_controller_spec.rb b/spec/requests/metadata_controller_spec.rb
similarity index 76%
rename from spec/controllers/metadata_controller_spec.rb
rename to spec/requests/metadata_controller_spec.rb
index 96558ec0c7..de317972d6 100644
--- a/spec/controllers/metadata_controller_spec.rb
+++ b/spec/requests/metadata_controller_spec.rb
@@ -1,15 +1,15 @@
require 'rails_helper'
RSpec.describe MetadataController do
- describe 'manifest.json' do
+ describe 'manifest.webmanifest' do
it 'returns the right output' do
-
title = 'MyApp'
SiteSetting.title = title
SiteSetting.large_icon_url = "http://big.square/png"
- get :manifest
- expect(response.content_type).to eq('application/json')
+ get "/manifest.webmanifest"
+ expect(response.status).to eq(200)
+ expect(response.content_type).to eq('application/manifest+json')
manifest = JSON.parse(response.body)
expect(manifest["name"]).to eq(title)
@@ -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.webmanifest"
+ 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.webmanifest"
+ 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')
diff --git a/spec/controllers/notifications_controller_spec.rb b/spec/requests/notifications_controller_spec.rb
similarity index 76%
rename from spec/controllers/notifications_controller_spec.rb
rename to spec/requests/notifications_controller_spec.rb
index d322abd848..e22721f82b 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,68 +23,63 @@ 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 }
- expect(response).to be_success
+ get "/notifications", params: { recent: true }
+ expect(response.status).to eq(200)
end
it 'should succeed for history' do
- get :index
- expect(response).to be_success
+ get "/notifications"
+ expect(response.status).to eq(200)
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
- expect(response).to be_success
+ put "/notifications/mark-read.json"
+ 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 :mark_read, params: { id: notification.id }, format: :json
- expect(response).to be_success
+ put "/notifications/mark-read.json", params: { id: notification.id }
+ expect(response.status).to eq(200)
notification.reload
notification2.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
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
diff --git a/spec/requests/omniauth_callbacks_controller_spec.rb b/spec/requests/omniauth_callbacks_controller_spec.rb
index 5e0a18edd9..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_success
+ 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_success
+ 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_success
+ 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_success
+ 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
new file mode 100644
index 0000000000..21728df3e7
--- /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.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.status).to eq(200)
+ 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.status).to eq(200)
+ expect(response.body).to include('Onebox1')
+ expect(response.body).to include('bodycontent')
+
+ get "/onebox.json", params: { url: url }
+ expect(response.status).to eq(200)
+ 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.status).to eq(200)
+ 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
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
diff --git a/spec/controllers/post_action_users_controller_spec.rb b/spec/requests/post_action_users_controller_spec.rb
similarity index 67%
rename from spec/controllers/post_action_users_controller_spec.rb
rename to spec/requests/post_action_users_controller_spec.rb
index fdd6add07c..1fdf4bb529 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,44 +21,39 @@ 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]
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
end
it "paginates post actions" do
@@ -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"]
diff --git a/spec/requests/post_actions_controller_spec.rb b/spec/requests/post_actions_controller_spec.rb
index cb20f94f3a..882b107eb7 100644
--- a/spec/requests/post_actions_controller_spec.rb
+++ b/spec/requests/post_actions_controller_spec.rb
@@ -5,18 +5,112 @@ 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.status).to eq(200)
+ end
+
+ it 'deletes the action' do
+ delete "/post_actions/#{post.id}.json", params: {
+ post_action_type_id: PostActionType.types[:bookmark]
+ }
+
+ expect(response.status).to eq(200)
+ 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.status).to eq(403)
+ end
+
+ it 'fails when the user tries to notify user that has disabled PM' do
+ sign_in(Fabricate(:user))
+ user2 = Fabricate(:user)
+
+ post = Fabricate(:post, user: user2)
+ user2.user_option.update!(allow_private_messages: false)
+
+ post "/post_actions.json", params: {
+ id: post.id,
+ post_action_type_id: PostActionType.types[:notify_user],
+ message: 'testing',
+ flag_topic: false
+ }
+
+ expect(response.status).to eq(422)
+
+ expect(JSON.parse(response.body)["errors"].first).to eq(I18n.t(
+ :not_accepting_pms, username: user2.username
+ ))
+ end
+
describe 'as a moderator' do
let(:user) { Fabricate(:moderator) }
let(:post_1) { Fabricate(:post, user: Fabricate(:coding_horror)) }
@@ -64,12 +158,13 @@ RSpec.describe PostActionsController do
post_action = PostAction.last
+ 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
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 +174,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 be_forbidden
end
it 'passes the message through' do
@@ -91,6 +186,7 @@ RSpec.describe PostActionsController do
message: message
}
+ expect(response.status).to eq(200)
expect(PostAction.last.post_id).to eq(post_1.id)
expect(Post.last.raw).to include(message)
end
@@ -105,6 +201,7 @@ RSpec.describe PostActionsController do
is_warning: true
}
+ expect(response.status).to eq(200)
expect(PostAction.last.post_id).to eq(post_1.id)
post = Post.last
@@ -133,7 +230,7 @@ RSpec.describe PostActionsController do
take_action: 'true'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
post_action = PostAction.last
@@ -149,7 +246,7 @@ RSpec.describe PostActionsController do
post_action_type_id: PostActionType.types[:like]
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
post_action = PostAction.last
@@ -158,4 +255,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.status).to eq(200)
+ 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.status).to eq(200)
+ flag.reload
+ expect(flag.deferred_at).to be_present
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb
index f43a5b511f..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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
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.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_success
+ expect(response.status).to eq(200)
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.status).to eq(200)
post.reload
expect(post.raw).to eq('edited body')
@@ -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
@@ -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.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])
@@ -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.status).to eq(200)
+ 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.status).to eq(200)
+ 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
@@ -522,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.status).to eq(200)
end
end
end
@@ -552,7 +617,7 @@ describe PostsController do
wpid: 1
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
original = response.body
post "/posts.json", params: {
@@ -563,7 +628,7 @@ describe PostsController do
wpid: 2
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(response.body).to eq(original)
end
@@ -582,7 +647,7 @@ describe PostsController do
reply_to_post_number: 1
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(post_1.topic.user.notifications.count).to eq(1)
post_1.topic.user.notifications.destroy_all
@@ -595,7 +660,7 @@ describe PostsController do
import_mode: true
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(post_1.topic.user.notifications.count).to eq(0)
post "/posts.json", params: {
@@ -607,7 +672,7 @@ describe PostsController do
import_mode: false
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(post_1.topic.user.notifications.count).to eq(1)
end
end
@@ -629,7 +694,7 @@ describe PostsController do
title: 'this is the test title for the topic'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
parsed = ::JSON.parse(response.body)
expect(parsed["action"]).to eq("enqueued")
@@ -655,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
@@ -668,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
@@ -682,7 +747,7 @@ describe PostsController do
title: 'when I eat s3 sometimes when not looking'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
parsed = ::JSON.parse(response.body)
expect(parsed["action"]).to eq("enqueued")
@@ -703,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])
@@ -715,7 +780,7 @@ describe PostsController do
archetype: Archetype.private_message
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
parsed = ::JSON.parse(response.body)
post = Post.find(parsed['id'])
@@ -731,7 +796,7 @@ describe PostsController do
nested_post: true
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
parsed = ::JSON.parse(response.body)
expect(parsed['post']).to be_present
expect(parsed['post']['cooked']).to be_present
@@ -742,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.status).to eq(200)
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
@@ -770,7 +835,7 @@ describe PostsController do
meta_data: { xyz: 'abc' }
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
new_post = Post.last
topic = new_post.topic
@@ -793,7 +858,7 @@ describe PostsController do
image_sizes: { width: '100', height: '200' }
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
new_post = Post.last
topic = new_post.topic
@@ -818,7 +883,7 @@ describe PostsController do
target_usernames: "#{user_2.username},#{user_3.username}"
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
new_post = Post.last
new_topic = Topic.last
@@ -831,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
@@ -860,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
@@ -875,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
@@ -891,7 +956,7 @@ describe PostsController do
category: destination_category.id,
shared_draft: 'true'
}
- expect(response).to be_success
+ 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)
@@ -918,7 +983,7 @@ describe PostsController do
is_warning: true
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
new_topic = Topic.last
@@ -935,7 +1000,7 @@ describe PostsController do
is_warning: false
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
new_topic = Topic.last
@@ -955,7 +1020,7 @@ describe PostsController do
is_warning: true
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
new_topic = Topic.last
@@ -993,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.status).to eq(200)
end
it "ensures poster can see the revisions" do
@@ -1004,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.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_success
+ expect(response.status).to eq(200)
end
end
@@ -1020,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.status).to eq(200)
end
end
@@ -1034,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.status).to eq(200)
end
end
@@ -1049,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.status).to eq(200)
end
end
end
@@ -1070,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
@@ -1086,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
@@ -1108,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.status).to eq(200)
end
it "supports reverting posts in deleted topics" do
@@ -1116,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.status).to eq(200)
end
end
end
@@ -1131,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.status).to eq(200)
expect(::JSON.parse(response.body)['cooked']).to eq("full content")
end
end
@@ -1155,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.status).to eq(200)
end
it "only shows agreed and deferred flags" do
@@ -1176,7 +1241,7 @@ describe PostsController do
sign_in(Fabricate(:moderator))
get "/posts/#{user.username}/flagged.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body).length).to eq(2)
end
@@ -1196,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.status).to eq(200)
end
it "doesn't return secured categories for moderators if they don't have access" do
@@ -1213,7 +1278,7 @@ describe PostsController do
sign_in(Fabricate(:moderator))
get "/posts/#{user.username}/deleted.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
expect(data.length).to eq(0)
@@ -1229,7 +1294,7 @@ describe PostsController do
sign_in(Fabricate(:moderator))
get "/posts/#{user.username}/deleted.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
expect(data.length).to eq(0)
@@ -1248,7 +1313,7 @@ describe PostsController do
sign_in(Fabricate(:admin))
get "/posts/#{user.username}/deleted.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
expect(data.length).to eq(1)
@@ -1262,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.status).to eq(200)
expect(response.body).to eq("123456789")
end
end
@@ -1273,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.status).to eq(200)
expect(response.body).to eq("123456789")
end
end
@@ -1301,7 +1366,7 @@ describe PostsController do
get "/u/#{user.username}/activity.rss"
- expect(response).to be_success
+ expect(response.status).to eq(200)
body = response.body
@@ -1319,7 +1384,7 @@ describe PostsController do
private_post
get "/private-posts.rss"
- expect(response).to be_success
+ expect(response.status).to eq(200)
body = response.body
@@ -1333,7 +1398,7 @@ describe PostsController do
public_post
private_post
get "/private-posts.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
post_ids = json['private_posts'].map { |p| p['id'] }
@@ -1350,7 +1415,7 @@ describe PostsController do
get "/posts.rss"
- expect(response).to be_success
+ expect(response.status).to eq(200)
body = response.body
@@ -1366,7 +1431,7 @@ describe PostsController do
topicless_post
get "/posts.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
post_ids = json['latest_posts'].map { |p| p['id'] }
@@ -1383,7 +1448,7 @@ describe PostsController do
post = Fabricate(:post, cooked: "WAt")
get "/posts/#{post.id}/cooked.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json).to be_present
@@ -1408,7 +1473,7 @@ describe PostsController do
sign_in(Fabricate(:moderator))
get "/posts/#{post.id}/raw-email.json"
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = ::JSON.parse(response.body)
expect(json['raw_email']).to eq('email_content')
@@ -1423,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.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_success
+ 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
new file mode 100644
index 0000000000..d8911e52e1
--- /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.status).to eq(200)
+ 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.status).to eq(200)
+
+ 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.status).to eq(200)
+
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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
diff --git a/spec/controllers/search_controller_spec.rb b/spec/requests/search_controller_spec.rb
similarity index 70%
rename from spec/controllers/search_controller_spec.rb
rename to spec/requests/search_controller_spec.rb
index f81f9ef937..84346d1b8d 100644
--- a/spec/controllers/search_controller_spec.rb
+++ b/spec/requests/search_controller_spec.rb
@@ -1,20 +1,29 @@
require 'rails_helper'
describe SearchController do
-
context "integration" do
before do
SearchIndexer.enable
end
+ before do
+ # TODO be a bit more strategic here instead of junking
+ # all of redis
+ $redis.flushall
+ end
+
+ after do
+ $redis.flushall
+ end
+
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
+ 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')
@@ -25,21 +34,21 @@ 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
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
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
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
expect(data['posts']).to be_blank
@@ -52,13 +61,13 @@ 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
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
expect(data['topics'][0]['id']).to eq(post.topic_id)
@@ -68,13 +77,13 @@ 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
+ expect(response.status).to eq(200)
data = JSON.parse(response.body)
expect(data['topics'][0]['id']).to eq(my_post.topic_id)
@@ -85,9 +94,9 @@ 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(response.status).to eq(200)
expect(SearchLog.where(term: 'wookie')).to be_present
json = JSON.parse(response.body)
@@ -101,8 +110,8 @@ describe SearchController do
it "doesn't log when disabled" do
SiteSetting.log_search_queries = false
- get :query, params: { term: 'wookie' }, format: :json
- expect(response).to be_success
+ get "/search/query.json", params: { term: 'wookie' }
+ expect(response.status).to eq(200)
expect(SearchLog.where(term: 'wookie')).to be_blank
end
end
@@ -110,31 +119,30 @@ describe SearchController do
context "#show" do
it "logs the search term" do
SiteSetting.log_search_queries = true
- get :show, params: { q: 'bantha' }, format: :json
- expect(response).to be_success
+ get "/search.json", params: { q: 'bantha' }
+ 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 :show, params: { q: 'bantha' }, format: :json
- expect(response).to be_success
+ get "/search.json", params: { q: 'bantha' }
+ expect(response.status).to eq(200)
expect(SearchLog.where(term: 'bantha')).to be_blank
end
end
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,19 +150,18 @@ 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
+ expect(response.status).to eq(200)
end
end
@@ -166,128 +173,128 @@ 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',
+ term: SecureRandom.hex,
search_type: :header,
user_id: -10,
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'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(SearchLog.find(search_log_id).search_result_id).to be_blank
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',
+ term: SecureRandom.hex,
search_type: :header,
user_id: user.id,
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(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
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',
+ term: SecureRandom.hex,
search_type: :header,
- ip_address: '192.168.0.1'
+ ip_address: ip_address
)
- post :click, 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)
- expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:topic])
- 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'
- )
-
- post :click, params: {
+ post "/search/click.json", params: {
search_log_id: search_log_id,
search_result_id: 22222,
search_result_type: 'topic'
}
- expect(response).to be_success
+ 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
+
+ it "doesn't record the click for a different IP" do
+ _, search_log_id = SearchLog.log(
+ term: SecureRandom.hex,
+ search_type: :header,
+ ip_address: '192.168.0.19'
+ )
+
+ post "/search/click", params: {
+ search_log_id: search_log_id,
+ search_result_id: 22222,
+ search_result_type: 'topic'
+ }
+
+ expect(response.status).to eq(200)
expect(SearchLog.find(search_log_id).search_result_id).to be_blank
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',
+ term: SecureRandom.hex,
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(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
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',
+ term: SecureRandom.hex,
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(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 3dfb07c583..43e8a4b568 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.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_success
+ expect(response.status).to eq(200)
expect(CGI.unescapeHTML(response.body)).to match(
I18n.t('email_login.invalid_token')
@@ -226,7 +226,7 @@ RSpec.describe SessionController do
describe '#sso_login' do
before do
- @sso_url = "http://somesite.com/discourse_sso"
+ @sso_url = "http://example.com/discourse_sso"
@sso_secret = "shjkfdhsfkjh"
SiteSetting.sso_url = @sso_url
@@ -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
@@ -823,7 +823,7 @@ RSpec.describe SessionController do
login: user.username, password: 'sssss'
}
- expect(response).to be_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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
new file mode 100644
index 0000000000..93e234f22e
--- /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.status).to eq(200)
+ 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.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)
+ 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.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)
+ 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.status).to eq(200)
+ json = ::JSON.parse(response.body)
+ expect(json["similar_topics"].size).to eq(0)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/site_controller_spec.rb b/spec/requests/site_controller_spec.rb
similarity index 93%
rename from spec/controllers/site_controller_spec.rb
rename to spec/requests/site_controller_spec.rb
index c36a79589c..b084dec7b1 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,15 +25,14 @@ 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_success
+ 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
@@ -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
diff --git a/spec/requests/static_controller_spec.rb b/spec/requests/static_controller_spec.rb
index 624bdadb2c..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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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
new file mode 100644
index 0000000000..6f304bf70a
--- /dev/null
+++ b/spec/requests/steps_controller_spec.rb
@@ -0,0 +1,55 @@
+require 'rails_helper'
+
+describe StepsController do
+ before do
+ SiteSetting.wizard_enabled = true
+ end
+
+ it 'needs you to be logged in' do
+ 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
+ sign_in(Fabricate(:moderator))
+
+ 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
+ sign_in(Fabricate(:admin))
+ end
+
+ it "raises an error if the wizard is disabled" do
+ SiteSetting.wizard_enabled = false
+ 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 "/wizard/steps/contact.json", params: {
+ fields: { contact_email: "eviltrout@example.com" }
+ }
+
+ expect(response.status).to eq(200)
+ expect(SiteSetting.contact_email).to eq("eviltrout@example.com")
+ end
+
+ it "returns errors if the field has them" do
+ put "/wizard/steps/contact.json", params: {
+ fields: { contact_email: "not-an-email" }
+ }
+
+ expect(response.status).to eq(422)
+ end
+ end
+end
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 a68ccc62be..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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
end
-
end
diff --git a/spec/requests/tags_controller_spec.rb b/spec/requests/tags_controller_spec.rb
index 65165852a9..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_success
+ 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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
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.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_success
+ expect(response.status).to eq(200)
tag = JSON.parse(response.body)['tags']
expect(tag[0]["id"]).to eq('test')
@@ -165,11 +165,208 @@ 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.status).to eq(200)
tag = JSON.parse(response.body)['tags']
expect(tag[0]["id"]).to eq('test')
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.status).to eq(200)
+ 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.status).to eq(200)
+
+ 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.status).to eq(200)
+
+ 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.status).to eq(200)
+
+ 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.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.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.status).to eq(200)
+ 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.status).to eq(200)
+
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.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
+ 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.status).to eq(200)
+ 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.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.status).to eq(200)
+ 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.status).to eq(200)
+ 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_successful
+ json = ::JSON.parse(response.body)
+ expect(json['error_type']).to eq('not_found')
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb
index 597ced4be5..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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
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.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_success
+ expect(response.status).to eq(200)
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.status).to eq(200)
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.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)
@@ -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.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
end
it 'return 404 for an invalid page' do
@@ -1042,10 +1040,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", headers: { HTTP_USER_AGENT: "Rails Testing" }
- get "/t/#{topic.slug}/#{topic.id}/print"
+ expect(response.status).to eq(200)
+ body = response.body
- expect(response).to be_successful
+ 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
@@ -1097,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.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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
expect(extract_post_stream).to eq(@post_ids[-2..-1])
end
end
@@ -1123,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
@@ -1139,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
@@ -1168,6 +1179,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.status).to eq(200)
+ 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.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
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.status).to eq(200)
+ 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.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.status).to eq(200)
+ expect(response.headers['Discourse-Readonly']).to eq('true')
+ end
+ end
end
describe '#posts' do
@@ -1175,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.status).to eq(200)
expect(response.content_type).to eq('application/json')
end
end
@@ -1185,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.status).to eq(200)
expect(response.content_type).to eq('application/rss+xml')
end
end
@@ -1232,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.status).to eq(200)
topic.reload
expect(topic.archetype).to eq(Archetype.banner)
end
@@ -1251,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.status).to eq(200)
topic.reload
expect(topic.archetype).to eq(Archetype.default)
end
@@ -1360,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.status).to eq(200)
user.reload
expect(user.user_stat.new_since.to_date).not_to eq(old_date.to_date)
end
@@ -1370,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.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)
@@ -1430,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.status).to eq(200)
result = ::JSON.parse(response.body)
expect(result['success']).to eq(true)
@@ -1456,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.status).to eq(200)
result = ::JSON.parse(response.body)
expect(result['success']).to eq(true)
@@ -1483,7 +1724,7 @@ RSpec.describe TopicsController do
timings: { post_1.post_number => 2 }
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
post_timing = PostTiming.first
@@ -1531,7 +1772,7 @@ RSpec.describe TopicsController do
status_type: TopicTimer.types[1]
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
topic_status_update = TopicTimer.last
@@ -1557,7 +1798,7 @@ RSpec.describe TopicsController do
status_type: TopicTimer.types[1]
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(topic.reload.public_topic_timer).to eq(nil)
json = JSON.parse(response.body)
@@ -1575,7 +1816,7 @@ RSpec.describe TopicsController do
category_id: topic.category_id
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
topic_status_update = TopicTimer.last
@@ -1795,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.status).to eq(200)
topic.reload
expect(topic.shared_draft.category_id).to eq(other_cat.id)
end
@@ -1804,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.status).to eq(200)
topic.reload
expect(topic.shared_draft.category_id).to eq(other_cat.id)
end
@@ -1870,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
new file mode 100644
index 0000000000..fac1a98d8d
--- /dev/null
+++ b/spec/requests/uploads_controller_spec.rb
@@ -0,0 +1,242 @@
+require 'rails_helper'
+
+describe UploadsController do
+ describe '#create' do
+ it 'requires you to be logged in' do
+ post "/uploads.json"
+ expect(response.status).to eq(403)
+ end
+
+ context 'logged in' do
+ let!(:user) { sign_in(Fabricate(:user)) }
+
+ let(:logo) do
+ Rack::Test::UploadedFile.new(file_from_fixtures("logo.png"))
+ end
+
+ let(:fake_jpg) do
+ Rack::Test::UploadedFile.new(file_from_fixtures("fake.jpg"))
+ end
+
+ let(:text_file) do
+ Rack::Test::UploadedFile.new(File.new("#{Rails.root}/LICENSE.txt"))
+ end
+
+ it 'expects a type' do
+ post "/uploads.json", params: { file: logo }
+ expect(response.status).to eq(400)
+ end
+
+ it 'is successful with an image' do
+ post "/uploads.json", params: { file: logo, type: "avatar" }
+ expect(response.status).to eq 200
+ 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 = "*"
+
+ 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 = "*"
+ 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 "/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(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
+ sign_in(Fabricate(:admin))
+
+ post "/uploads.json", params: {
+ file: logo,
+ retain_hours: 100,
+ type: "profile_background",
+ }
+
+ 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
+ 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
+
+ post "/uploads.json", params: { file: text_file, type: "avatar" }
+
+ expect(response.status).to eq(422)
+ expect(Jobs::CreateAvatarThumbnails.jobs.size).to eq(0)
+ errors = JSON.parse(response.body)["errors"]
+ 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 "/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 "/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)
+
+ post "/uploads.json", params: {
+ file: text_file,
+ type: "composer",
+ for_private_message: "true",
+ }
+
+ expect(response.status).to eq(200)
+ id = JSON.parse(response.body)["id"]
+ 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)
+
+ post "/uploads.json", params: {
+ file: text_file,
+ type: "composer",
+ }
+
+ expect(response.status).to eq(200)
+ data = JSON.parse(response.body)
+ 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 "/uploads.json", params: {
+ file: text_file,
+ type: "composer",
+ }
+
+ data = JSON.parse(response.body)
+ expect(data["errors"].first).to eq(I18n.t("upload.unauthorized", authorized_extensions: ''))
+ end
+
+ it 'returns an error when it could not determine the dimensions of an image' do
+ post "/uploads.json", params: { file: fake_jpg, type: "composer" }
+
+ 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
+
+ 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
+ SiteSetting.enable_s3_uploads = true
+ SiteSetting.s3_access_key_id = "fakeid7974664"
+ SiteSetting.s3_secret_access_key = "fakesecretid7974664"
+
+ get "/uploads/#{site}/#{sha}.pdf"
+ expect(response.response_code).to eq(404)
+ end
+
+ it "returns 404 when the upload doesn't exist" do
+ get "/uploads/#{site}/#{sha}.pdf"
+ expect(response.status).to eq(404)
+ end
+
+ it 'uses send_file' do
+ 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 = "*"
+ upload = upload_file("image_no_extension")
+
+ 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
+ it "returns 404 when an anonymous user tries to download a file" do
+ upload = upload_file("logo.png")
+ delete "/session/#{user.username}.json" # upload a file, then sign out
+
+ 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
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 79cf2ac108..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_success
-
+ }
+ 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)
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
diff --git a/spec/controllers/user_avatars_controller_spec.rb b/spec/requests/user_avatars_controller_spec.rb
similarity index 72%
rename from spec/controllers/user_avatars_controller_spec.rb
rename to spec/requests/user_avatars_controller_spec.rb
index 7218cd8a06..be10954e8a 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,11 +57,9 @@ 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_success
+ expect(response.status).to eq(200)
end
end
end
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..f565caa1a7 100644
--- a/spec/controllers/user_badges_controller_spec.rb
+++ b/spec/requests/user_badges_controller_spec.rb
@@ -8,10 +8,10 @@ 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
- expect(response).to be_success
+ get "/user_badges.json", params: { badge_id: badge.id }
+ expect(response.status).to eq(200)
parsed = JSON.parse(response.body)
expect(parsed["topics"]).to eq(nil)
@@ -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
diff --git a/spec/requests/users_controller_spec.rb b/spec/requests/users_controller_spec.rb
index 5b7e588c52..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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
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.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_success
+ expect(response.status).to eq(200)
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.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_success
+ 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_success
+ expect(response.status).to eq(200)
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.status).to eq(200)
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.status).to eq(200)
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.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_success
+ 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_success
+ 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_success
+ 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_success
+ expect(response.status).to eq(200)
expect(response.body).to include(
"{\"message\":\"#{I18n.t("login.activate_email", email: user.email).gsub!("", "<\\/")}\",\"show_controls\":true,\"username\":\"#{user.username}\",\"email\":\"#{user.email}\"}"
@@ -2491,14 +2491,14 @@ describe UsersController do
it "searches when provided the term only" do
get "/u/search/users.json", params: { term: user.name.split(" ").last }
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json["users"].map { |u| u["username"] }).to include(user.username)
end
it "searches when provided the topic only" do
get "/u/search/users.json", params: { topic_id: topic.id }
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json["users"].map { |u| u["username"] }).to include(user.username)
end
@@ -2508,7 +2508,7 @@ describe UsersController do
term: user.name.split(" ").last, topic_id: topic.id
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json["users"].map { |u| u["username"] }).to include(user.username)
end
@@ -2529,7 +2529,7 @@ describe UsersController do
term: user.name.split(" ").last, topic_id: private_topic.id, topic_allowed_users: "true"
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
json = JSON.parse(response.body)
expect(json["users"].map { |u| u["username"] }).to_not include(user.username)
expect(json["users"].map { |u| u["username"] }).to include(privileged_user.username)
@@ -2591,7 +2591,7 @@ describe UsersController do
it "only returns visible groups" do
get "/u/search/users.json", params: { include_groups: "true" }
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)["groups"]
@@ -2605,7 +2605,7 @@ describe UsersController do
include_messageable_groups: 'false'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)).not_to have_key(:groups)
end
@@ -2615,7 +2615,7 @@ describe UsersController do
include_messageable_groups: 'true'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)["groups"].map { |group| group['name'] })
.to contain_exactly(messageable_group.name, Group.find(Group::AUTO_GROUPS[:moderators]).name)
@@ -2627,7 +2627,7 @@ describe UsersController do
include_mentionable_groups: 'true'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
groups = JSON.parse(response.body)["groups"]
@@ -2643,7 +2643,7 @@ describe UsersController do
include_messageable_groups: 'false'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)).not_to have_key(:groups)
get "/u/search/users.json", params: {
@@ -2651,7 +2651,7 @@ describe UsersController do
include_messageable_groups: 'true'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)).not_to have_key(:groups)
get "/u/search/users.json", params: {
@@ -2659,7 +2659,7 @@ describe UsersController do
include_mentionable_groups: 'true'
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)).not_to have_key(:groups)
end
end
@@ -2687,7 +2687,7 @@ describe UsersController do
it "enqueues the right email" do
post "/u/email-login.json", params: { login: user.email }
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)['user_found']).to eq(true)
job_args = Jobs::CriticalUserEmail.jobs.last["args"].first
@@ -2713,7 +2713,7 @@ describe UsersController do
it 'should not enqueue the email to login' do
post "/u/email-login.json", params: { login: '@random' }
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body)['user_found']).to eq(false)
expect(Jobs::CriticalUserEmail.jobs).to eq([])
end
@@ -2724,7 +2724,7 @@ describe UsersController do
SiteSetting.hide_email_address_taken = true
post "/u/email-login.json", params: { login: user.email }
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(JSON.parse(response.body).has_key?('user_found')).to eq(false)
end
end
diff --git a/spec/requests/users_email_controller_spec.rb b/spec/requests/users_email_controller_spec.rb
index e562810319..5206a22fb4 100644
--- a/spec/requests/users_email_controller_spec.rb
+++ b/spec/requests/users_email_controller_spec.rb
@@ -6,7 +6,7 @@ describe UsersEmailController do
it 'errors out for invalid tokens' do
get "/u/authorize-email/asdfasdf"
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(response.body).to include(I18n.t('change_email.already_done'))
end
@@ -21,7 +21,7 @@ describe UsersEmailController do
it 'confirms with a correct token' do
get "/u/authorize-email/#{user.email_tokens.last.token}"
- expect(response).to be_success
+ expect(response.status).to eq(200)
body = CGI.unescapeHTML(response.body)
@@ -52,7 +52,7 @@ describe UsersEmailController do
:user_logged_in, :user_first_logged_in
)
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(response.body).to include(I18n.t('change_email.confirmed'))
user.reload
@@ -66,7 +66,7 @@ describe UsersEmailController do
get "/u/authorize-email/#{user.email_tokens.last.token}"
- expect(response).to be_success
+ expect(response.status).to eq(200)
expect(group.reload.users.include?(user)).to eq(true)
end
@@ -149,7 +149,7 @@ describe UsersEmailController do
email: other_user.email
}
- expect(response).to_not be_success
+ expect(response).to_not be_successful
end
it 'raises an error if there is whitespace too' do
@@ -157,7 +157,7 @@ describe UsersEmailController do
email: "#{other_user.email} "
}
- expect(response).to_not be_success
+ expect(response).to_not be_successful
end
end
@@ -171,7 +171,7 @@ describe UsersEmailController do
email: other_user.email
}
- expect(response).to be_success
+ expect(response.status).to eq(200)
end
end
end
@@ -184,7 +184,7 @@ describe UsersEmailController do
email: other_user.email.upcase
}
- expect(response).to_not be_success
+ expect(response).to_not be_successful
end
end
@@ -195,7 +195,7 @@ describe UsersEmailController do
email: "not_good@mailinator.com"
}
- expect(response).to_not be_success
+ expect(response).to_not be_successful
end
it 'raises an error when new email domain is not present in email_domains_whitelist site setting' do
@@ -205,7 +205,7 @@ describe UsersEmailController do
email: new_email
}
- expect(response).to_not be_success
+ expect(response).to_not be_successful
end
context 'success' do
diff --git a/spec/controllers/webhooks_controller_spec.rb b/spec/requests/webhooks_controller_spec.rb
similarity index 76%
rename from spec/controllers/webhooks_controller_spec.rb
rename to spec/requests/webhooks_controller_spec.rb
index b5b049ca8a..ec94b93942 100644
--- a/spec/controllers/webhooks_controller_spec.rb
+++ b/spec/requests/webhooks_controller_spec.rb
@@ -7,39 +7,40 @@ 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_success
+ expect(response.status).to eq(200)
email_log.reload
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,46 +49,42 @@ describe WebhooksController do
"status" => "5.0.0"
}
]
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
email_log.reload
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_success
+ expect(response.status).to eq(200)
email_log.reload
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,24 +94,22 @@ describe WebhooksController do
}
}
}]
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
email_log.reload
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,15 +121,13 @@ describe WebhooksController do
}
}
}]
- }, format: :json
+ }
- expect(response).to be_success
+ expect(response.status).to eq(200)
email_log.reload
expect(email_log.bounced).to eq(true)
expect(email_log.user.user_stat.bounce_score).to eq(2)
end
-
end
-
end
diff --git a/spec/controllers/wizard_controller_spec.rb b/spec/requests/wizard_controller_spec.rb
similarity index 70%
rename from spec/controllers/wizard_controller_spec.rb
rename to spec/requests/wizard_controller_spec.rb
index 0875e31c26..9c8c72f6e2 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
- expect(response).to be_success
+ sign_in(Fabricate(:admin))
+ get "/wizard.json"
+ expect(response.status).to eq(200)
end
it "returns JSON when the mime type is appropriate" do
- log_in(:admin)
- get :index, format: 'json'
- expect(response).to be_success
+ sign_in(Fabricate(:admin))
+ get "/wizard.json"
+ expect(response.status).to eq(200)
expect(::JSON.parse(response.body).has_key?('wizard')).to eq(true)
end
end
-
end
diff --git a/spec/serializers/post_serializer_spec.rb b/spec/serializers/post_serializer_spec.rb
index 5e75727cfc..40d2574d70 100644
--- a/spec/serializers/post_serializer_spec.rb
+++ b/spec/serializers/post_serializer_spec.rb
@@ -80,7 +80,7 @@ describe PostSerializer do
end
context "a hidden post with add_raw enabled" do
- let(:user) { Fabricate.build(:user) }
+ let(:user) { Fabricate.build(:user, id: 101) }
let(:raw) { "Raw contents of the post." }
def serialized_post_for_user(u)
@@ -132,12 +132,19 @@ describe PostSerializer do
end
context "a hidden wiki post" do
- let(:post) { Fabricate.build(:post, raw: raw, user: user, wiki: true, hidden: true, hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached]) }
+ let(:post) {
+ Fabricate.build(
+ :post,
+ raw: raw,
+ user: user,
+ wiki: true,
+ hidden: true,
+ hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached])
+ }
it "can view edit history only if authorized" do
expect(serialized_post_for_user(nil)[:can_view_edit_history]).to eq(false)
expect(serialized_post_for_user(Fabricate(:user))[:can_view_edit_history]).to eq(false)
-
expect(serialized_post_for_user(user)[:can_view_edit_history]).to eq(true)
expect(serialized_post_for_user(Fabricate(:moderator))[:can_view_edit_history]).to eq(true)
expect(serialized_post_for_user(Fabricate(:admin))[:can_view_edit_history]).to eq(true)
diff --git a/spec/serializers/single_sign_on_record_serializer_spec.rb b/spec/serializers/single_sign_on_record_serializer_spec.rb
new file mode 100644
index 0000000000..6564f343f3
--- /dev/null
+++ b/spec/serializers/single_sign_on_record_serializer_spec.rb
@@ -0,0 +1,36 @@
+require 'rails_helper'
+
+RSpec.describe SingleSignOnRecordSerializer do
+ let(:user) { Fabricate(:user) }
+ let :sso do
+ SingleSignOnRecord.create!(user_id: user.id, external_id: '12345', external_email: user.email, last_payload: '')
+ end
+
+ context "admin" do
+ let(:admin) { Fabricate(:admin) }
+ let :serializer do
+ SingleSignOnRecordSerializer.new(sso, scope: Guardian.new(admin), root: false)
+ end
+
+ it "should include user sso info" do
+ payload = serializer.as_json
+ expect(payload[:user_id]).to eq(user.id)
+ expect(payload[:external_id]).to eq('12345')
+ expect(payload[:external_email]).to eq(user.email)
+ end
+ end
+
+ context "moderator" do
+ let(:moderator) { Fabricate(:moderator) }
+ let :serializer do
+ SingleSignOnRecordSerializer.new(sso, scope: Guardian.new(moderator), root: false)
+ end
+
+ it "should include user sso info" do
+ payload = serializer.as_json
+ expect(payload[:user_id]).to eq(user.id)
+ expect(payload[:external_id]).to eq('12345')
+ expect(payload[:external_email]).to be_nil
+ end
+ end
+end
diff --git a/spec/services/badge_granter_spec.rb b/spec/services/badge_granter_spec.rb
index 64d4b96fa7..451cb158a1 100644
--- a/spec/services/badge_granter_spec.rb
+++ b/spec/services/badge_granter_spec.rb
@@ -118,7 +118,8 @@ describe BadgeGranter do
describe 'grant' do
it 'allows overriding of granted_at does not notify old bronze' do
- badge = Fabricate(:badge, badge_type_id: BadgeType::Bronze)
+ badge = Badge.create!(name: 'a badge', badge_type_id: BadgeType::Bronze)
+
time = 1.year.ago
user_badge = BadgeGranter.grant(badge, user, created_at: time)
diff --git a/spec/services/destroy_task_spec.rb b/spec/services/destroy_task_spec.rb
index 1319393853..afcb205250 100644
--- a/spec/services/destroy_task_spec.rb
+++ b/spec/services/destroy_task_spec.rb
@@ -4,11 +4,11 @@ describe DestroyTask do
describe 'destroy topics' do
let!(:c) { Fabricate(:category) }
- let!(:t) { Fabricate(:topic, category_id: c.id) }
- let!(:p) { Fabricate(:post, topic_id: t.id) }
+ let!(:t) { Fabricate(:topic, category: c) }
+ let!(:p) { Fabricate(:post, topic: t) }
let!(:c2) { Fabricate(:category) }
- let!(:t2) { Fabricate(:topic, category_id: c2.id) }
- let!(:p2) { Fabricate(:post, topic_id: t2.id) }
+ let!(:t2) { Fabricate(:topic, category: c2) }
+ let!(:p2) { Fabricate(:post, topic: t2) }
it 'destroys all topics in a category' do
before_count = Topic.where(category_id: c.id).count
diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb
index 87408d112f..cf782d251a 100644
--- a/spec/services/post_alerter_spec.rb
+++ b/spec/services/post_alerter_spec.rb
@@ -36,13 +36,14 @@ describe PostAlerter do
context "private message" do
it "notifies for pms correctly" do
pm = Fabricate(:topic, archetype: 'private_message', category_id: nil)
- op = Fabricate(:post, user_id: pm.user_id)
+ op = Fabricate(:post, user: pm.user)
pm.allowed_users << pm.user
PostAlerter.post_created(op)
- reply = Fabricate(:post, user_id: pm.user_id, topic_id: pm.id, reply_to_post_number: 1)
+
+ reply = Fabricate(:post, user: pm.user, topic: pm, reply_to_post_number: 1)
PostAlerter.post_created(reply)
- reply2 = Fabricate(:post, topic_id: pm.id, reply_to_post_number: 1)
+ reply2 = Fabricate(:post, topic: pm, reply_to_post_number: 1)
PostAlerter.post_created(reply2)
# we get a green notification for a reply
@@ -52,7 +53,7 @@ describe PostAlerter do
Notification.destroy_all
- reply3 = Fabricate(:post, topic_id: pm.id)
+ reply3 = Fabricate(:post, topic: pm)
PostAlerter.post_created(reply3)
# no notification cause we are tracking
@@ -60,7 +61,7 @@ describe PostAlerter do
Notification.destroy_all
- reply4 = Fabricate(:post, topic_id: pm.id, reply_to_post_number: 1)
+ reply4 = Fabricate(:post, topic: pm, reply_to_post_number: 1)
PostAlerter.post_created(reply4)
# yes notification cause we were replied to
@@ -70,7 +71,7 @@ describe PostAlerter do
it "triggers :before_create_notifications_for_users" do
pm = Fabricate(:topic, archetype: 'private_message', category_id: nil)
- op = Fabricate(:post, user_id: pm.user_id, topic: pm)
+ op = Fabricate(:post, user: pm.user, topic: pm)
user1 = Fabricate(:user)
user2 = Fabricate(:user)
group = Fabricate(:group, users: [user2])
diff --git a/spec/services/post_owner_changer_spec.rb b/spec/services/post_owner_changer_spec.rb
index b9f836533e..aeeaeea605 100644
--- a/spec/services/post_owner_changer_spec.rb
+++ b/spec/services/post_owner_changer_spec.rb
@@ -5,19 +5,19 @@ describe PostOwnerChanger do
let!(:editor) { Fabricate(:admin) }
let(:topic) { Fabricate(:topic) }
let(:user_a) { Fabricate(:user) }
- let(:p1) { Fabricate(:post, topic_id: topic.id, post_number: 1) }
- let(:p2) { Fabricate(:post, topic_id: topic.id, post_number: 2) }
+ let(:p1) { Fabricate(:post, topic: topic, post_number: 1) }
+ let(:p2) { Fabricate(:post, topic: topic, post_number: 2) }
let(:p3) { Fabricate(:post) }
it "raises an error with a parameter missing" do
expect {
- described_class.new(post_ids: [p1.id], topic_id: topic.id, new_owner: nil, acting_user: editor)
+ PostOwnerChanger.new(post_ids: [p1.id], topic_id: topic.id, new_owner: nil, acting_user: editor)
}.to raise_error(ArgumentError)
end
it "calls PostRevisor" do
PostRevisor.any_instance.expects(:revise!)
- described_class.new(post_ids: [p1.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
+ PostOwnerChanger.new(post_ids: [p1.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
end
it "changes the user" do
@@ -39,7 +39,7 @@ describe PostOwnerChanger do
end
it "changes multiple posts" do
- described_class.new(post_ids: [p1.id, p2.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
+ PostOwnerChanger.new(post_ids: [p1.id, p2.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
p1.reload; p2.reload
expect(p1.user).not_to eq(nil)
expect(p1.user).to eq(user_a)
@@ -47,7 +47,7 @@ describe PostOwnerChanger do
end
it "ignores posts in other topics" do
- described_class.new(post_ids: [p1.id, p3.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
+ PostOwnerChanger.new(post_ids: [p1.id, p3.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
p1.reload; p3.reload
expect(p1.user).to eq(user_a)
@@ -56,7 +56,7 @@ describe PostOwnerChanger do
end
it "skips creating new post revision if skip_revision is true" do
- described_class.new(post_ids: [p1.id, p2.id], topic_id: topic.id, new_owner: user_a, acting_user: editor, skip_revision: true).change_owner!
+ PostOwnerChanger.new(post_ids: [p1.id, p2.id], topic_id: topic.id, new_owner: user_a, acting_user: editor, skip_revision: true).change_owner!
p1.reload; p2.reload
expect(p1.revisions.size).to eq(0)
expect(p2.revisions.size).to eq(0)
@@ -76,7 +76,7 @@ describe PostOwnerChanger do
end
it "changes the owner when the post is deleted" do
- p4 = Fabricate(:post, topic_id: topic.id, reply_to_post_number: p2.post_number)
+ p4 = Fabricate(:post, topic: topic, reply_to_post_number: p2.post_number)
PostDestroyer.new(editor, p4).destroy
PostOwnerChanger.new(post_ids: [p4.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
@@ -84,16 +84,16 @@ describe PostOwnerChanger do
end
context "sets topic notification level for the new owner" do
- let(:p4) { Fabricate(:post, post_number: 2, topic_id: topic.id) }
+ let(:p4) { Fabricate(:post, post_number: 2, topic: topic) }
it "'watching' if the first post gets a new owner" do
- described_class.new(post_ids: [p1.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
+ PostOwnerChanger.new(post_ids: [p1.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
tu = TopicUser.find_by(user_id: user_a.id, topic_id: topic.id)
expect(tu.notification_level).to eq(3)
end
it "'tracking' if other than the first post gets a new owner" do
- described_class.new(post_ids: [p4.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
+ PostOwnerChanger.new(post_ids: [p4.id], topic_id: topic.id, new_owner: user_a, acting_user: editor).change_owner!
tu = TopicUser.find_by(user_id: user_a.id, topic_id: topic.id)
expect(tu.notification_level).to eq(2)
end
@@ -129,7 +129,7 @@ describe PostOwnerChanger do
end
subject(:change_owners) do
- described_class.new(
+ PostOwnerChanger.new(
post_ids: [p1.id, p2.id],
topic_id: topic.id,
new_owner: user_a,
@@ -180,7 +180,7 @@ describe PostOwnerChanger do
user_stat = editor.user_stat
expect {
- described_class.new(
+ PostOwnerChanger.new(
post_ids: [whisper.id],
topic_id: topic.id,
new_owner: Fabricate(:admin),
diff --git a/spec/services/staff_action_logger_spec.rb b/spec/services/staff_action_logger_spec.rb
index 70132a7a51..56c8a81c36 100644
--- a/spec/services/staff_action_logger_spec.rb
+++ b/spec/services/staff_action_logger_spec.rb
@@ -488,4 +488,25 @@ 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)
+ 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
diff --git a/spec/services/user_anonymizer_spec.rb b/spec/services/user_anonymizer_spec.rb
index f397bc930b..9212958d23 100644
--- a/spec/services/user_anonymizer_spec.rb
+++ b/spec/services/user_anonymizer_spec.rb
@@ -23,7 +23,9 @@ describe UserAnonymizer do
end
describe "make_anonymous" do
- let(:user) { Fabricate(:user, username: "edward") }
+ let(:original_email) { "edward@example.net" }
+ let(:user) { Fabricate(:user, username: "edward", email: original_email) }
+ let(:another_user) { Fabricate(:evil_trout) }
subject(:make_anonymous) { described_class.make_anonymous(user, admin) }
it "changes username" do
@@ -33,7 +35,7 @@ describe UserAnonymizer do
it "changes email address" do
make_anonymous
- expect(user.reload.email).to eq("#{user.username}@example.com")
+ expect(user.reload.email).to eq("#{user.username}@anonymized.invalid")
end
it "turns off all notifications" do
@@ -201,6 +203,60 @@ describe UserAnonymizer do
expect(user.api_key).to eq(nil)
end
+ context "executes job" do
+ before do
+ SiteSetting.queue_jobs = false
+ end
+
+ it "removes invites" do
+ Fabricate(:invite, user: user)
+ Fabricate(:invite, user: another_user)
+
+ expect { make_anonymous }.to change { Invite.count }.by(-1)
+ expect(Invite.where(user_id: user.id).count).to eq(0)
+ end
+
+ it "removes email tokens" do
+ Fabricate(:email_token, user: user)
+ Fabricate(:email_token, user: another_user)
+
+ expect { make_anonymous }.to change { EmailToken.count }.by(-1)
+ expect(EmailToken.where(user_id: user.id).count).to eq(0)
+ end
+
+ it "removes email log entries" do
+ Fabricate(:email_log, user: user)
+ Fabricate(:email_log, user: another_user)
+
+ expect { make_anonymous }.to change { EmailLog.count }.by(-1)
+ expect(EmailLog.where(user_id: user.id).count).to eq(0)
+ end
+
+ it "removes incoming emails" do
+ Fabricate(:incoming_email, user: user, from_address: user.email)
+ Fabricate(:incoming_email, from_address: user.email, error: "Some error")
+ Fabricate(:incoming_email, user: another_user, from_address: another_user.email)
+
+ expect { make_anonymous }.to change { IncomingEmail.count }.by(-2)
+ expect(IncomingEmail.where(user_id: user.id).count).to eq(0)
+ expect(IncomingEmail.where(from_address: original_email).count).to eq(0)
+ end
+
+ it "removes raw email from posts" do
+ post1 = Fabricate(:post, user: user, via_email: true, raw_email: "raw email from user")
+ post2 = Fabricate(:post, user: another_user, via_email: true, raw_email: "raw email from another user")
+
+ make_anonymous
+
+ expect(post1.reload).to have_attributes(via_email: true, raw_email: nil)
+ expect(post2.reload).to have_attributes(via_email: true, raw_email: "raw email from another user")
+ end
+
+ it "does not delete profile views" do
+ UserProfileView.add(user.id, '127.0.0.1', another_user.id, Time.now, true)
+ expect { make_anonymous }.to_not change { UserProfileView.count }
+ end
+ end
end
describe "anonymize_ip" do
@@ -222,6 +278,7 @@ describe UserAnonymizer do
end
it "exhaustively replaces all user ips" do
+ SiteSetting.queue_jobs = false
link = IncomingLink.create!(current_user_id: user.id, ip_address: old_ip, post_id: post.id)
screened_email = ScreenedEmail.create!(email: user.email, ip_address: old_ip)
diff --git a/spec/services/user_destroyer_spec.rb b/spec/services/user_destroyer_spec.rb
index e958136b9d..0b506f5c7c 100644
--- a/spec/services/user_destroyer_spec.rb
+++ b/spec/services/user_destroyer_spec.rb
@@ -71,10 +71,15 @@ describe UserDestroyer do
end
context 'user deletes self' do
- let(:destroy_opts) { { delete_posts: true } }
+ let(:destroy_opts) { { delete_posts: true, context: "/u/username/preferences/account" } }
subject(:destroy) { UserDestroyer.new(@user).destroy(@user, destroy_opts) }
include_examples "successfully destroy a user"
+
+ it 'should log proper context' do
+ destroy
+ expect(UserHistory.where(action: UserHistory.actions[:delete_user]).last.context).to eq(I18n.t("staff_action_logs.user_delete_self", url: "/u/username/preferences/account"))
+ end
end
context "with a queued post" do
diff --git a/spec/services/user_merger_spec.rb b/spec/services/user_merger_spec.rb
index 2d81ad8e3b..fac984e6fc 100644
--- a/spec/services/user_merger_spec.rb
+++ b/spec/services/user_merger_spec.rb
@@ -850,6 +850,7 @@ describe UserMerger do
UserHistory.create(action: UserHistory.actions[:anonymize_user], target_user_id: walter.id, acting_user_id: source_user.id)
merge_users!
+ UserHistory.where(action: UserHistory.actions[:merge_user], target_user_id: target_user.id).delete_all
expect(UserHistory.where(target_user_id: target_user.id).count).to eq(1)
expect(UserHistory.where(target_user_id: source_user.id).count).to eq(0)
@@ -953,6 +954,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")
@@ -1019,4 +1029,15 @@ describe UserMerger do
merge_users!
end
+
+ it "correctly logs the merge" do
+ expect { merge_users! }.to change { UserHistory.count }.by(1)
+
+ log_entry = UserHistory.last
+ expect(log_entry.action).to eq(UserHistory.actions[:merge_user])
+ expect(log_entry.acting_user_id).to eq(Discourse::SYSTEM_USER_ID)
+ expect(log_entry.target_user_id).to eq(target_user.id)
+ expect(log_entry.context).to eq(I18n.t("staff_action_logs.user_merged", username: source_user.username))
+ expect(log_entry.email).to eq("alice@work.com")
+ end
end
diff --git a/spec/support/integration_helpers.rb b/spec/support/integration_helpers.rb
index 94d245caae..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_success
+ 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_success
+ expect(response.status).to eq(200)
body = JSON.parse(response.body)
User.find(body["user_id"])
diff --git a/test/javascripts/acceptance/about-test.js.es6 b/test/javascripts/acceptance/about-test.js.es6
index c7ef9fb85a..9393c068a3 100644
--- a/test/javascripts/acceptance/about-test.js.es6
+++ b/test/javascripts/acceptance/about-test.js.es6
@@ -4,9 +4,9 @@ acceptance("About");
QUnit.test("viewing", assert => {
visit("/about");
andThen(() => {
- assert.ok($('body.about-page').length, "has body class");
- assert.ok(exists('.about.admins .user-info'), 'has admins');
- assert.ok(exists('.about.moderators .user-info'), 'has moderators');
- assert.ok(exists('.about.stats tr td'), 'has stats');
+ assert.ok($("body.about-page").length, "has body class");
+ assert.ok(exists(".about.admins .user-info"), "has admins");
+ assert.ok(exists(".about.moderators .user-info"), "has moderators");
+ assert.ok(exists(".about.stats tr td"), "has stats");
});
-});
\ No newline at end of file
+});
diff --git a/test/javascripts/acceptance/account-created-test.js.es6 b/test/javascripts/acceptance/account-created-test.js.es6
index a0fc11267a..a009024bb4 100644
--- a/test/javascripts/acceptance/account-created-test.js.es6
+++ b/test/javascripts/acceptance/account-created-test.js.es6
@@ -1,97 +1,99 @@
import { acceptance } from "helpers/qunit-helpers";
-import PreloadStore from 'preload-store';
+import PreloadStore from "preload-store";
acceptance("Account Created");
QUnit.test("account created - message", assert => {
- PreloadStore.store('accountCreated', {
- message: "Hello World",
+ PreloadStore.store("accountCreated", {
+ message: "Hello World"
});
visit("/u/account-created");
andThen(() => {
- assert.ok(exists('.account-created'));
+ assert.ok(exists(".account-created"));
assert.equal(
- find('.account-created .ac-message').text().trim(),
+ find(".account-created .ac-message")
+ .text()
+ .trim(),
"Hello World",
"it displays the message"
);
- assert.notOk(exists('.activation-controls'));
+ assert.notOk(exists(".activation-controls"));
});
});
QUnit.test("account created - resend email", assert => {
- PreloadStore.store('accountCreated', {
+ PreloadStore.store("accountCreated", {
message: "Hello World",
- username: 'eviltrout',
- email: 'eviltrout@example.com',
+ username: "eviltrout",
+ email: "eviltrout@example.com",
show_controls: true
});
visit("/u/account-created");
andThen(() => {
- assert.ok(exists('.account-created'));
+ assert.ok(exists(".account-created"));
assert.equal(
- find('.account-created .ac-message').text().trim(),
+ find(".account-created .ac-message")
+ .text()
+ .trim(),
"Hello World",
"it displays the message"
);
});
- click('.activation-controls .resend');
+ click(".activation-controls .resend");
andThen(() => {
assert.equal(currentPath(), "account-created.resent");
- const email = find('.account-created .ac-message b').text();
- assert.equal(email, 'eviltrout@example.com');
+ const email = find(".account-created .ac-message b").text();
+ assert.equal(email, "eviltrout@example.com");
});
-
});
QUnit.test("account created - update email - cancel", assert => {
- PreloadStore.store('accountCreated', {
+ PreloadStore.store("accountCreated", {
message: "Hello World",
- username: 'eviltrout',
- email: 'eviltrout@example.com',
+ username: "eviltrout",
+ email: "eviltrout@example.com",
show_controls: true
});
visit("/u/account-created");
- click('.activation-controls .edit-email');
+ click(".activation-controls .edit-email");
andThen(() => {
assert.equal(currentPath(), "account-created.edit-email");
- assert.ok(find('.activation-controls .btn-primary:disabled').length);
+ assert.ok(find(".activation-controls .btn-primary:disabled").length);
});
- click('.activation-controls .edit-cancel');
+ click(".activation-controls .edit-cancel");
andThen(() => {
assert.equal(currentPath(), "account-created.index");
});
});
QUnit.test("account created - update email - submit", assert => {
- PreloadStore.store('accountCreated', {
+ PreloadStore.store("accountCreated", {
message: "Hello World",
- username: 'eviltrout',
- email: 'eviltrout@example.com',
+ username: "eviltrout",
+ email: "eviltrout@example.com",
show_controls: true
});
visit("/u/account-created");
- click('.activation-controls .edit-email');
+ click(".activation-controls .edit-email");
andThen(() => {
- assert.ok(find('.activation-controls .btn-primary:disabled').length);
+ assert.ok(find(".activation-controls .btn-primary:disabled").length);
});
- fillIn('.activate-new-email', 'newemail@example.com');
+ fillIn(".activate-new-email", "newemail@example.com");
andThen(() => {
- assert.notOk(find('.activation-controls .btn-primary:disabled').length);
+ assert.notOk(find(".activation-controls .btn-primary:disabled").length);
});
- click('.activation-controls .btn-primary');
+ click(".activation-controls .btn-primary");
andThen(() => {
assert.equal(currentPath(), "account-created.resent");
- const email = find('.account-created .ac-message b').text();
- assert.equal(email, 'newemail@example.com');
+ const email = find(".account-created .ac-message b").text();
+ assert.equal(email, "newemail@example.com");
});
-
-});
\ No newline at end of file
+});
diff --git a/test/javascripts/acceptance/admin-flags-test.js.es6 b/test/javascripts/acceptance/admin-flags-test.js.es6
index 3f38df94b1..9dcb5bf488 100644
--- a/test/javascripts/acceptance/admin-flags-test.js.es6
+++ b/test/javascripts/acceptance/admin-flags-test.js.es6
@@ -4,116 +4,136 @@ acceptance("Admin - Flagging", { loggedIn: true });
QUnit.test("flagged posts", assert => {
visit("/admin/flags/active");
andThen(() => {
- assert.equal(find('.flagged-posts .flagged-post').length, 1);
- assert.equal(find('.flagged-post .flag-user').length, 1, 'shows who flagged it');
- assert.equal(find('.flagged-post-response').length, 2);
- assert.equal(find('.flagged-post-response:eq(0) img.avatar').length, 1);
- assert.equal(find('.flagged-post-user-details .username').length, 1, 'shows the flagged username');
+ assert.equal(find(".flagged-posts .flagged-post").length, 1);
+ assert.equal(
+ find(".flagged-post .flag-user").length,
+ 1,
+ "shows who flagged it"
+ );
+ assert.equal(find(".flagged-post-response").length, 2);
+ assert.equal(find(".flagged-post-response:eq(0) img.avatar").length, 1);
+ assert.equal(
+ find(".flagged-post-user-details .username").length,
+ 1,
+ "shows the flagged username"
+ );
});
});
QUnit.test("flagged posts - agree", assert => {
- const agreeFlag = selectKit('.agree-flag');
+ const agreeFlag = selectKit(".agree-flag");
visit("/admin/flags/active");
- agreeFlag.expand().selectRowByValue('confirm-agree-keep');
+ agreeFlag.expand().selectRowByValue("confirm-agree-keep");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0, 'post was removed');
+ assert.equal(
+ find(".admin-flags .flagged-post").length,
+ 0,
+ "post was removed"
+ );
});
});
QUnit.test("flagged posts - agree + hide", assert => {
- const agreeFlag = selectKit('.agree-flag');
+ const agreeFlag = selectKit(".agree-flag");
visit("/admin/flags/active");
- agreeFlag.expand().selectRowByValue('confirm-agree-hide');
+ agreeFlag.expand().selectRowByValue("confirm-agree-hide");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0, 'post was removed');
+ assert.equal(
+ find(".admin-flags .flagged-post").length,
+ 0,
+ "post was removed"
+ );
});
});
QUnit.test("flagged posts - agree + deleteSpammer", assert => {
- const agreeFlag = selectKit('.agree-flag');
+ const agreeFlag = selectKit(".agree-flag");
visit("/admin/flags/active");
- agreeFlag.expand().selectRowByValue('delete-spammer');
+ agreeFlag.expand().selectRowByValue("delete-spammer");
- click('.confirm-delete');
+ click(".confirm-delete");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0, 'post was removed');
+ assert.equal(
+ find(".admin-flags .flagged-post").length,
+ 0,
+ "post was removed"
+ );
});
});
QUnit.test("flagged posts - disagree", assert => {
visit("/admin/flags/active");
- click('.disagree-flag');
+ click(".disagree-flag");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0);
+ assert.equal(find(".admin-flags .flagged-post").length, 0);
});
});
QUnit.test("flagged posts - defer", assert => {
visit("/admin/flags/active");
- click('.defer-flag');
+ click(".defer-flag");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0);
+ assert.equal(find(".admin-flags .flagged-post").length, 0);
});
});
QUnit.test("flagged posts - delete + defer", assert => {
- const deleteFlag = selectKit('.delete-flag');
+ const deleteFlag = selectKit(".delete-flag");
visit("/admin/flags/active");
- deleteFlag.expand().selectRowByValue('delete-defer');
+ deleteFlag.expand().selectRowByValue("delete-defer");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0);
+ assert.equal(find(".admin-flags .flagged-post").length, 0);
});
});
QUnit.test("flagged posts - delete + agree", assert => {
- const deleteFlag = selectKit('.delete-flag');
+ const deleteFlag = selectKit(".delete-flag");
visit("/admin/flags/active");
- deleteFlag.expand().selectRowByValue('delete-agree');
+ deleteFlag.expand().selectRowByValue("delete-agree");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0);
+ assert.equal(find(".admin-flags .flagged-post").length, 0);
});
});
QUnit.test("flagged posts - delete + deleteSpammer", assert => {
- const deleteFlag = selectKit('.delete-flag');
+ const deleteFlag = selectKit(".delete-flag");
visit("/admin/flags/active");
- deleteFlag.expand().selectRowByValue('delete-spammer');
+ deleteFlag.expand().selectRowByValue("delete-spammer");
- click('.confirm-delete');
+ click(".confirm-delete");
andThen(() => {
- assert.equal(find('.admin-flags .flagged-post').length, 0);
+ assert.equal(find(".admin-flags .flagged-post").length, 0);
});
});
QUnit.test("topics with flags", assert => {
visit("/admin/flags/topics");
andThen(() => {
- assert.equal(find('.flagged-topics .flagged-topic').length, 1);
- assert.equal(find('.flagged-topic .flagged-topic-user').length, 2);
- assert.equal(find('.flagged-topic .flag-counts').length, 3);
+ assert.equal(find(".flagged-topics .flagged-topic").length, 1);
+ assert.equal(find(".flagged-topic .flagged-topic-user").length, 2);
+ assert.equal(find(".flagged-topic .flag-counts").length, 3);
});
- click('.flagged-topic .show-details');
+ click(".flagged-topic .show-details");
andThen(() => {
- assert.equal(currentURL(), '/admin/flags/topics/280');
+ assert.equal(currentURL(), "/admin/flags/topics/280");
});
});
diff --git a/test/javascripts/acceptance/admin-search-log-term-test.js.es6 b/test/javascripts/acceptance/admin-search-log-term-test.js.es6
index 9d3fbd6b43..36c7864215 100644
--- a/test/javascripts/acceptance/admin-search-log-term-test.js.es6
+++ b/test/javascripts/acceptance/admin-search-log-term-test.js.es6
@@ -4,8 +4,8 @@ acceptance("Admin - Search Log Term", { loggedIn: true });
QUnit.test("show search log term details", assert => {
visit("/admin/logs/search_logs/term/ruby");
andThen(() => {
- assert.ok($('div.search-logs-filter').length, "has the search type filter");
- assert.ok(exists('canvas.chartjs-render-monitor'), "has graph canvas");
- assert.ok(exists('div.header-search-results'), "has header search results");
+ assert.ok($("div.search-logs-filter").length, "has the search type filter");
+ assert.ok(exists("canvas.chartjs-render-monitor"), "has graph canvas");
+ assert.ok(exists("div.header-search-results"), "has header search results");
});
});
diff --git a/test/javascripts/acceptance/admin-search-logs-test.js.es6 b/test/javascripts/acceptance/admin-search-logs-test.js.es6
index e1e7ed5355..2f8245f7f9 100644
--- a/test/javascripts/acceptance/admin-search-logs-test.js.es6
+++ b/test/javascripts/acceptance/admin-search-logs-test.js.es6
@@ -4,7 +4,10 @@ acceptance("Admin - Search Logs", { loggedIn: true });
QUnit.test("show search logs", assert => {
visit("/admin/logs/search_logs");
andThen(() => {
- assert.ok($('div.table.search-logs-list').length, "has the div class");
- assert.ok(exists('.search-logs-list .admin-list-item .col'), "has a list of search logs");
+ assert.ok($("div.table.search-logs-list").length, "has the div class");
+ assert.ok(
+ exists(".search-logs-list .admin-list-item .col"),
+ "has a list of search logs"
+ );
});
});
diff --git a/test/javascripts/acceptance/admin-site-text-test.js.es6 b/test/javascripts/acceptance/admin-site-text-test.js.es6
index c20dc09f4f..3146e0db41 100644
--- a/test/javascripts/acceptance/admin-site-text-test.js.es6
+++ b/test/javascripts/acceptance/admin-site-text-test.js.es6
@@ -5,50 +5,48 @@ acceptance("Admin - Site Texts", { loggedIn: true });
QUnit.test("search for a key", assert => {
visit("/admin/customize/site_texts");
- fillIn('.site-text-search', 'Test');
+ fillIn(".site-text-search", "Test");
andThen(() => {
- assert.ok(exists('.site-text'));
+ assert.ok(exists(".site-text"));
assert.ok(exists(".site-text:not(.overridden)"));
- assert.ok(exists('.site-text.overridden'));
+ assert.ok(exists(".site-text.overridden"));
});
-
// Only show overridden
- click('.extra-options input');
+ click(".extra-options input");
andThen(() => {
assert.ok(!exists(".site-text:not(.overridden)"));
- assert.ok(exists('.site-text.overridden'));
+ assert.ok(exists(".site-text.overridden"));
});
});
-
QUnit.test("edit and revert a site text by key", assert => {
visit("/admin/customize/site_texts/site.test");
andThen(() => {
- assert.equal(find('.title h3').text(), 'site.test');
- assert.ok(!exists('.save-messages .saved'));
- assert.ok(!exists('.save-messages .saved'));
- assert.ok(!exists('.revert-site-text'));
+ assert.equal(find(".title h3").text(), "site.test");
+ assert.ok(!exists(".save-messages .saved"));
+ assert.ok(!exists(".save-messages .saved"));
+ assert.ok(!exists(".revert-site-text"));
});
// Change the value
- fillIn('.site-text-value', 'New Test Value');
+ fillIn(".site-text-value", "New Test Value");
click(".save-changes");
andThen(() => {
- assert.ok(exists('.save-messages .saved'));
- assert.ok(exists('.revert-site-text'));
+ assert.ok(exists(".save-messages .saved"));
+ assert.ok(exists(".revert-site-text"));
});
// Revert the changes
- click('.revert-site-text');
+ click(".revert-site-text");
andThen(() => {
- assert.ok(exists('.bootbox.modal'));
+ assert.ok(exists(".bootbox.modal"));
});
- click('.bootbox.modal .btn-primary');
+ click(".bootbox.modal .btn-primary");
andThen(() => {
- assert.ok(!exists('.save-messages .saved'));
- assert.ok(!exists('.revert-site-text'));
+ assert.ok(!exists(".save-messages .saved"));
+ assert.ok(!exists(".revert-site-text"));
});
-});
\ No newline at end of file
+});
diff --git a/test/javascripts/acceptance/admin-suspend-user-test.js.es6 b/test/javascripts/acceptance/admin-suspend-user-test.js.es6
index cc67726886..055d890c05 100644
--- a/test/javascripts/acceptance/admin-suspend-user-test.js.es6
+++ b/test/javascripts/acceptance/admin-suspend-user-test.js.es6
@@ -4,17 +4,21 @@ acceptance("Admin - Suspend User", {
loggedIn: true,
pretend(server, helper) {
- server.put('/admin/users/:user_id/suspend', () => helper.response(200, {
- suspension: {
- suspended: true
- }
- }));
+ server.put("/admin/users/:user_id/suspend", () =>
+ helper.response(200, {
+ suspension: {
+ suspended: true
+ }
+ })
+ );
- server.put('/admin/users/:user_id/unsuspend', () => helper.response(200, {
- suspension: {
- suspended: false
- }
- }));
+ server.put("/admin/users/:user_id/unsuspend", () =>
+ helper.response(200, {
+ suspension: {
+ suspended: false
+ }
+ })
+ );
}
});
@@ -23,47 +27,55 @@ QUnit.test("suspend a user - cancel", assert => {
click(".suspend-user");
andThen(() => {
- assert.equal(find('.suspend-user-modal:visible').length, 1);
+ assert.equal(find(".suspend-user-modal:visible").length, 1);
});
- click('.d-modal-cancel');
+ click(".d-modal-cancel");
andThen(() => {
- assert.equal(find('.suspend-user-modal:visible').length, 0);
+ assert.equal(find(".suspend-user-modal:visible").length, 0);
});
});
QUnit.test("suspend, then unsuspend a user", assert => {
- const suspendUntilCombobox = selectKit('.suspend-until .combobox');
+ const suspendUntilCombobox = selectKit(".suspend-until .combobox");
visit("/admin/flags/active");
visit("/admin/users/1234/regular");
andThen(() => {
- assert.ok(!exists('.suspension-info'));
+ assert.ok(!exists(".suspension-info"));
});
click(".suspend-user");
andThen(() => {
- assert.equal(find('.perform-suspend[disabled]').length, 1, 'disabled by default');
+ assert.equal(
+ find(".perform-suspend[disabled]").length,
+ 1,
+ "disabled by default"
+ );
});
- suspendUntilCombobox.expand().selectRowByValue('tomorrow');
+ suspendUntilCombobox.expand().selectRowByValue("tomorrow");
- fillIn('.suspend-reason', "for breaking the rules");
- fillIn('.suspend-message', "this is an email reason why");
+ fillIn(".suspend-reason", "for breaking the rules");
+ fillIn(".suspend-message", "this is an email reason why");
andThen(() => {
- assert.equal(find('.perform-suspend[disabled]').length, 0, 'no longer disabled');
+ assert.equal(
+ find(".perform-suspend[disabled]").length,
+ 0,
+ "no longer disabled"
+ );
});
- click('.perform-suspend');
+ click(".perform-suspend");
andThen(() => {
- assert.equal(find('.suspend-user-modal:visible').length, 0);
- assert.ok(exists('.suspension-info'));
+ assert.equal(find(".suspend-user-modal:visible").length, 0);
+ assert.ok(exists(".suspension-info"));
});
- click('.unsuspend-user');
+ click(".unsuspend-user");
andThen(() => {
- assert.ok(!exists('.suspension-info'));
+ assert.ok(!exists(".suspension-info"));
});
});
diff --git a/test/javascripts/acceptance/admin-users-list-test.js.es6 b/test/javascripts/acceptance/admin-users-list-test.js.es6
index a6d3117e60..20fd19f20e 100644
--- a/test/javascripts/acceptance/admin-users-list-test.js.es6
+++ b/test/javascripts/acceptance/admin-users-list-test.js.es6
@@ -5,7 +5,7 @@ acceptance("Admin - Users List", { loggedIn: true });
QUnit.test("lists users", assert => {
visit("/admin/users/list/active");
andThen(() => {
- assert.ok(exists('.users-list .user'));
- assert.ok(!exists('.user:eq(0) .email small'), 'escapes email');
+ assert.ok(exists(".users-list .user"));
+ assert.ok(!exists(".user:eq(0) .email small"), "escapes email");
});
-});
\ No newline at end of file
+});
diff --git a/test/javascripts/acceptance/admin-watched-words-test.js.es6 b/test/javascripts/acceptance/admin-watched-words-test.js.es6
index 88fd0728bd..9554705ce4 100644
--- a/test/javascripts/acceptance/admin-watched-words-test.js.es6
+++ b/test/javascripts/acceptance/admin-watched-words-test.js.es6
@@ -4,43 +4,60 @@ acceptance("Admin - Watched Words", { loggedIn: true });
QUnit.test("list words in groups", assert => {
visit("/admin/logs/watched_words/action/block");
andThen(() => {
- assert.ok(exists('.watched-words-list'));
- assert.ok(!exists('.watched-words-list .watched-word'), "Don't show bad words by default.");
+ assert.ok(exists(".watched-words-list"));
+ assert.ok(
+ !exists(".watched-words-list .watched-word"),
+ "Don't show bad words by default."
+ );
});
- fillIn('.admin-controls .controls input[type=text]', 'li');
+ fillIn(".admin-controls .controls input[type=text]", "li");
andThen(() => {
- assert.equal(find('.watched-words-list .watched-word').length, 1, "When filtering, show words even if checkbox is unchecked.");
+ assert.equal(
+ find(".watched-words-list .watched-word").length,
+ 1,
+ "When filtering, show words even if checkbox is unchecked."
+ );
});
- fillIn('.admin-controls .controls input[type=text]', '');
+ fillIn(".admin-controls .controls input[type=text]", "");
andThen(() => {
- assert.ok(!exists('.watched-words-list .watched-word'), "Clearing the filter hides words again.");
+ assert.ok(
+ !exists(".watched-words-list .watched-word"),
+ "Clearing the filter hides words again."
+ );
});
- click('.show-words-checkbox');
+ click(".show-words-checkbox");
andThen(() => {
- assert.ok(exists('.watched-words-list .watched-word'), "Always show the words when checkbox is checked.");
+ assert.ok(
+ exists(".watched-words-list .watched-word"),
+ "Always show the words when checkbox is checked."
+ );
});
- click('.nav-stacked .censor a');
+ click(".nav-stacked .censor a");
andThen(() => {
- assert.ok(exists('.watched-words-list'));
- assert.ok(!exists('.watched-words-list .watched-word'), "Empty word list.");
+ assert.ok(exists(".watched-words-list"));
+ assert.ok(!exists(".watched-words-list .watched-word"), "Empty word list.");
});
});
QUnit.test("add words", assert => {
visit("/admin/logs/watched_words/action/block");
andThen(() => {
- click('.show-words-checkbox');
- fillIn('.watched-word-form input', 'poutine');
+ click(".show-words-checkbox");
+ fillIn(".watched-word-form input", "poutine");
});
- click('.watched-word-form button');
+ click(".watched-word-form button");
andThen(() => {
let found = [];
- _.each(find('.watched-words-list .watched-word'), i => {
- if ($(i).text().trim() === 'poutine') {
+ _.each(find(".watched-words-list .watched-word"), i => {
+ if (
+ $(i)
+ .text()
+ .trim() === "poutine"
+ ) {
found.push(true);
}
});
@@ -50,19 +67,22 @@ QUnit.test("add words", assert => {
QUnit.test("remove words", assert => {
visit("/admin/logs/watched_words/action/block");
- click('.show-words-checkbox');
+ click(".show-words-checkbox");
let word = null;
andThen(() => {
- _.each(find('.watched-words-list .watched-word'), i => {
- if ($(i).text().trim() === 'anise') {
+ _.each(find(".watched-words-list .watched-word"), i => {
+ if (
+ $(i)
+ .text()
+ .trim() === "anise"
+ ) {
word = i;
}
});
- click('#' + $(word).attr('id'));
+ click("#" + $(word).attr("id"));
});
andThen(() => {
- assert.equal(find('.watched-words-list .watched-word').length, 1);
+ assert.equal(find(".watched-words-list .watched-word").length, 1);
});
});
-
diff --git a/test/javascripts/acceptance/badges-test.js.es6 b/test/javascripts/acceptance/badges-test.js.es6
index 9052efe222..8ad8cc1f34 100644
--- a/test/javascripts/acceptance/badges-test.js.es6
+++ b/test/javascripts/acceptance/badges-test.js.es6
@@ -5,14 +5,14 @@ acceptance("Badges");
QUnit.test("Visit Badge Pages", assert => {
visit("/badges");
andThen(() => {
- assert.ok($('body.badges-page').length, "has body class");
- assert.ok(exists('.badge-groups .badge-card'), "has a list of badges");
+ assert.ok($("body.badges-page").length, "has body class");
+ assert.ok(exists(".badge-groups .badge-card"), "has a list of badges");
});
visit("/badges/9/autobiographer");
andThen(() => {
- assert.ok(exists('.badge-card'), "has the badge in the listing");
- assert.ok(exists('.user-info'), "has the list of users with that badge");
- assert.ok(!exists('.badge-card:eq(0) script'));
+ assert.ok(exists(".badge-card"), "has the badge in the listing");
+ assert.ok(exists(".user-info"), "has the list of users with that badge");
+ assert.ok(!exists(".badge-card:eq(0) script"));
});
-});
\ No newline at end of file
+});
diff --git a/test/javascripts/acceptance/category-chooser-test.js.es6 b/test/javascripts/acceptance/category-chooser-test.js.es6
index bd3979993f..13166969f4 100644
--- a/test/javascripts/acceptance/category-chooser-test.js.es6
+++ b/test/javascripts/acceptance/category-chooser-test.js.es6
@@ -1,29 +1,34 @@
-import { acceptance } from 'helpers/qunit-helpers';
+import { acceptance } from "helpers/qunit-helpers";
-acceptance('CategoryChooser', {
+acceptance("CategoryChooser", {
loggedIn: true,
settings: {
allow_uncategorized_topics: false
}
});
-QUnit.test('does not display uncategorized if not allowed', assert => {
- const categoryChooser = selectKit('.category-chooser');
+QUnit.test("does not display uncategorized if not allowed", assert => {
+ const categoryChooser = selectKit(".category-chooser");
- visit('/');
- click('#create-topic');
+ visit("/");
+ click("#create-topic");
categoryChooser.expand();
andThen(() => {
- assert.ok(categoryChooser.rowByIndex(0).name() !== 'uncategorized');
+ assert.ok(categoryChooser.rowByIndex(0).name() !== "uncategorized");
});
});
-QUnit.test('prefill category when category_id is set', assert => {
- visit('/new-topic?category_id=1');
+QUnit.test("prefill category when category_id is set", assert => {
+ visit("/new-topic?category_id=1");
andThen(() => {
- assert.equal(selectKit('.category-chooser').header().value(), 1);
+ assert.equal(
+ selectKit(".category-chooser")
+ .header()
+ .value(),
+ 1
+ );
});
});
diff --git a/test/javascripts/acceptance/category-edit-security-test.js.es6 b/test/javascripts/acceptance/category-edit-security-test.js.es6
index 2af84a1898..d73bc250be 100644
--- a/test/javascripts/acceptance/category-edit-security-test.js.es6
+++ b/test/javascripts/acceptance/category-edit-security-test.js.es6
@@ -7,17 +7,23 @@ acceptance("Category Edit - security", {
QUnit.test("default", assert => {
visit("/c/bug");
- click('.edit-category');
- click('li.edit-category-security a');
+ click(".edit-category");
+ click("li.edit-category-security a");
andThen(() => {
- const $permissionListItems = find('.permission-list li');
+ const $permissionListItems = find(".permission-list li");
- const badgeName = $permissionListItems.eq(0).find('.badge-group').text();
- assert.equal(badgeName, 'everyone');
+ const badgeName = $permissionListItems
+ .eq(0)
+ .find(".badge-group")
+ .text();
+ assert.equal(badgeName, "everyone");
- const permission = $permissionListItems.eq(0).find('.permission').text();
- assert.equal(permission, 'Create / Reply / See');
+ const permission = $permissionListItems
+ .eq(0)
+ .find(".permission")
+ .text();
+ assert.equal(permission, "Create / Reply / See");
});
});
@@ -26,20 +32,28 @@ QUnit.test("removing a permission", assert => {
visit("/c/bug");
- click('.edit-category');
- click('li.edit-category-security a');
- click('.edit-category-tab-security .edit-permission');
+ click(".edit-category");
+ click("li.edit-category-security a");
+ click(".edit-category-tab-security .edit-permission");
availableGroups.expand();
andThen(() => {
- assert.notOk(availableGroups.rowByValue('everyone').exists(), 'everyone is already used and is not in the available groups');
+ assert.notOk(
+ availableGroups.rowByValue("everyone").exists(),
+ "everyone is already used and is not in the available groups"
+ );
});
- click('.edit-category-tab-security .permission-list li:first-of-type .remove-permission');
+ click(
+ ".edit-category-tab-security .permission-list li:first-of-type .remove-permission"
+ );
availableGroups.expand();
andThen(() => {
- assert.ok(availableGroups.rowByValue('everyone').exists(), 'everyone has been removed and appears in the available groups');
+ assert.ok(
+ availableGroups.rowByValue("everyone").exists(),
+ "everyone has been removed and appears in the available groups"
+ );
});
});
@@ -49,21 +63,23 @@ QUnit.test("adding a permission", assert => {
visit("/c/bug");
- click('.edit-category');
- click('li.edit-category-security a');
- click('.edit-category-tab-security .edit-permission');
- availableGroups.expand().selectRowByValue('staff');
- permissionSelector.expand().selectRowByValue('2');
- click('.edit-category-tab-security .add-permission');
+ click(".edit-category");
+ click("li.edit-category-security a");
+ click(".edit-category-tab-security .edit-permission");
+ availableGroups.expand().selectRowByValue("staff");
+ permissionSelector.expand().selectRowByValue("2");
+ click(".edit-category-tab-security .add-permission");
andThen(() => {
- const $addedPermissionItem = find('.edit-category-tab-security .permission-list li:nth-child(2)');
+ const $addedPermissionItem = find(
+ ".edit-category-tab-security .permission-list li:nth-child(2)"
+ );
- const badgeName = $addedPermissionItem.find('.badge-group').text();
- assert.equal(badgeName, 'staff');
+ const badgeName = $addedPermissionItem.find(".badge-group").text();
+ assert.equal(badgeName, "staff");
- const permission = $addedPermissionItem.find('.permission').text();
- assert.equal(permission, 'Reply / See');
+ const permission = $addedPermissionItem.find(".permission").text();
+ assert.equal(permission, "Reply / See");
});
});
@@ -72,27 +88,43 @@ QUnit.test("adding a previously removed permission", assert => {
visit("/c/bug");
- click('.edit-category');
- click('li.edit-category-security a');
- click('.edit-category-tab-security .edit-permission');
- click('.edit-category-tab-security .permission-list li:first-of-type .remove-permission');
+ click(".edit-category");
+ click("li.edit-category-security a");
+ click(".edit-category-tab-security .edit-permission");
+ click(
+ ".edit-category-tab-security .permission-list li:first-of-type .remove-permission"
+ );
andThen(() => {
- assert.equal(find(".edit-category-tab-security .permission-list li").length, 0, 'it removes the permission from the list');
+ assert.equal(
+ find(".edit-category-tab-security .permission-list li").length,
+ 0,
+ "it removes the permission from the list"
+ );
});
- availableGroups.expand().selectRowByValue('everyone');
- click('.edit-category-tab-security .add-permission');
+ availableGroups.expand().selectRowByValue("everyone");
+ click(".edit-category-tab-security .add-permission");
andThen(() => {
- assert.equal(find(".edit-category-tab-security .permission-list li").length, 1, 'it adds the permission to the list');
+ assert.equal(
+ find(".edit-category-tab-security .permission-list li").length,
+ 1,
+ "it adds the permission to the list"
+ );
- const $permissionListItems = find('.permission-list li');
+ const $permissionListItems = find(".permission-list li");
- const badgeName = $permissionListItems.eq(0).find('.badge-group').text();
- assert.equal(badgeName, 'everyone');
+ const badgeName = $permissionListItems
+ .eq(0)
+ .find(".badge-group")
+ .text();
+ assert.equal(badgeName, "everyone");
- const permission = $permissionListItems.eq(0).find('.permission').text();
- assert.equal(permission, 'Create / Reply / See');
+ const permission = $permissionListItems
+ .eq(0)
+ .find(".permission")
+ .text();
+ assert.equal(permission, "Create / Reply / See");
});
});
diff --git a/test/javascripts/acceptance/category-edit-test.js.es6 b/test/javascripts/acceptance/category-edit-test.js.es6
index 4f9d2da99f..9dedfa8283 100644
--- a/test/javascripts/acceptance/category-edit-test.js.es6
+++ b/test/javascripts/acceptance/category-edit-test.js.es6
@@ -1,4 +1,4 @@
-import DiscourseURL from 'discourse/lib/url';
+import DiscourseURL from "discourse/lib/url";
import { acceptance } from "helpers/qunit-helpers";
acceptance("Category Edit", {
@@ -9,79 +9,101 @@ acceptance("Category Edit", {
QUnit.test("Can open the category modal", assert => {
visit("/c/bug");
- click('.edit-category');
+ click(".edit-category");
andThen(() => {
- assert.ok(visible('.d-modal'), 'it pops up a modal');
+ assert.ok(visible(".d-modal"), "it pops up a modal");
});
- click('a.close');
+ click("a.close");
andThen(() => {
- assert.ok(!visible('.d-modal'), 'it closes the modal');
+ assert.ok(!visible(".d-modal"), "it closes the modal");
});
});
QUnit.test("Change the category color", assert => {
visit("/c/bug");
- click('.edit-category');
- fillIn('#edit-text-color', '#ff0000');
- click('#save-category');
+ click(".edit-category");
+ fillIn("#edit-text-color", "#ff0000");
+ click("#save-category");
andThen(() => {
- assert.ok(!visible('.d-modal'), 'it closes the modal');
- assert.equal(DiscourseURL.redirectedTo, '/c/bug', 'it does one of the rare full page redirects');
+ assert.ok(!visible(".d-modal"), "it closes the modal");
+ assert.equal(
+ DiscourseURL.redirectedTo,
+ "/c/bug",
+ "it does one of the rare full page redirects"
+ );
});
});
QUnit.test("Change the topic template", assert => {
visit("/c/bug");
- click('.edit-category');
- click('.edit-category-topic-template');
- fillIn('.d-editor-input', 'this is the new topic template');
- click('#save-category');
+ click(".edit-category");
+ click(".edit-category-topic-template");
+ fillIn(".d-editor-input", "this is the new topic template");
+ click("#save-category");
andThen(() => {
- assert.ok(!visible('.d-modal'), 'it closes the modal');
- assert.equal(DiscourseURL.redirectedTo, '/c/bug', 'it does one of the rare full page redirects');
+ assert.ok(!visible(".d-modal"), "it closes the modal");
+ assert.equal(
+ DiscourseURL.redirectedTo,
+ "/c/bug",
+ "it does one of the rare full page redirects"
+ );
});
});
QUnit.test("Error Saving", assert => {
visit("/c/bug");
- click('.edit-category');
- click('.edit-category-settings');
- fillIn('.email-in', 'duplicate@example.com');
- click('#save-category');
+ click(".edit-category");
+ click(".edit-category-settings");
+ fillIn(".email-in", "duplicate@example.com");
+ click("#save-category");
andThen(() => {
- assert.ok(visible('#modal-alert'));
- assert.equal(find('#modal-alert').html(), "duplicate email");
+ assert.ok(visible("#modal-alert"));
+ assert.equal(find("#modal-alert").html(), "duplicate email");
});
});
QUnit.test("Subcategory list settings", assert => {
- const categoryChooser = selectKit('.edit-category-tab-general .category-chooser');
+ const categoryChooser = selectKit(
+ ".edit-category-tab-general .category-chooser"
+ );
visit("/c/bug");
- click('.edit-category');
- click('.edit-category-settings');
+ click(".edit-category");
+ click(".edit-category-settings");
andThen(() => {
- assert.ok(!visible(".subcategory-list-style-field"), "subcategory list style isn't visible by default");
+ assert.ok(
+ !visible(".subcategory-list-style-field"),
+ "subcategory list style isn't visible by default"
+ );
});
click(".show-subcategory-list-field input[type=checkbox]");
andThen(() => {
- assert.ok(visible(".subcategory-list-style-field"), "subcategory list style is shown if show subcategory list is checked");
+ assert.ok(
+ visible(".subcategory-list-style-field"),
+ "subcategory list style is shown if show subcategory list is checked"
+ );
});
- click('.edit-category-general');
+ click(".edit-category-general");
categoryChooser.expand().selectRowByValue(3);
- click('.edit-category-settings');
+ click(".edit-category-settings");
andThen(() => {
- assert.ok(!visible(".show-subcategory-list-field"), "show subcategory list isn't visible for child categories");
- assert.ok(!visible(".subcategory-list-style-field"), "subcategory list style isn't visible for child categories");
+ assert.ok(
+ !visible(".show-subcategory-list-field"),
+ "show subcategory list isn't visible for child categories"
+ );
+ assert.ok(
+ !visible(".subcategory-list-style-field"),
+ "subcategory list style isn't visible for child categories"
+ );
});
});
diff --git a/test/javascripts/acceptance/category-hashtag-test.js.es6 b/test/javascripts/acceptance/category-hashtag-test.js.es6
index bd410abc18..45864748b3 100644
--- a/test/javascripts/acceptance/category-hashtag-test.js.es6
+++ b/test/javascripts/acceptance/category-hashtag-test.js.es6
@@ -4,16 +4,26 @@ acceptance("Category hashtag", { loggedIn: true });
QUnit.test("category hashtag is cooked properly", assert => {
visit("/t/internationalization-localization/280");
- click('#topic-footer-buttons .btn.create');
+ click("#topic-footer-buttons .btn.create");
- fillIn('.d-editor-input', "this is a category hashtag #bug");
+ fillIn(".d-editor-input", "this is a category hashtag #bug");
andThen(() => {
// TODO: Test that the autocomplete shows
- assert.equal(find('.d-editor-preview:visible').html().trim(), "
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
",
- "created_at":"2015-01-23T14:59:21.941Z",
- "title":"The end of Clown Vomit, or, simplified category styles",
- "url":"/t/the-end-of-clown-vomit-or-simplified-category-styles/24249/63",
- "user_title":"designerator",
- "user_long_name":"",
- "category":{
- "id":9,
- "name":"ux",
- "color":"5F497A",
- "topic_id":2628,
- "topic_count":540,
- "created_at":"2013-02-10T03:52:21.322Z",
- "updated_at":"2015-01-22T18:05:32.152Z",
- "user_id":32,
- "topics_year":370,
- "topics_month":33,
- "topics_week":3,
- "slug":"ux",
- "description":"Discussion about the user interface of Discourse, how features are presented to the user in the client, including language and UI elements.",
- "text_color":"FFFFFF",
- "read_restricted":false,
- "auto_close_hours":null,
- "post_count":5823,
- "latest_post_id":94610,
- "latest_topic_id":24355,
- "position":25,
- "parent_category_id":null,
- "posts_year":4264,
- "posts_month":609,
- "posts_week":103,
- "email_in":null,
- "email_in_allow_strangers":false,
- "topics_day":0,
- "posts_day":28,
- "logo_url":null,
- "background_url":null,
- "allow_badges":true,
- "name_lower":"ux",
- "auto_close_based_on_last_post":false
+ id: 94603,
+ cooked:
+ "
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
",
- "created_at":"2015-01-23T14:51:55.497Z",
- "title":"The end of Clown Vomit, or, simplified category styles",
- "url":"/t/the-end-of-clown-vomit-or-simplified-category-styles/24249/62",
- "user_title":"designerator",
- "user_long_name":"",
- "category":{
- "id":9,
- "name":"ux",
- "color":"5F497A",
- "topic_id":2628,
- "topic_count":540,
- "created_at":"2013-02-10T03:52:21.322Z",
- "updated_at":"2015-01-22T18:05:32.152Z",
- "user_id":32,
- "topics_year":370,
- "topics_month":33,
- "topics_week":3,
- "slug":"ux",
- "description":"Discussion about the user interface of Discourse, how features are presented to the user in the client, including language and UI elements.",
- "text_color":"FFFFFF",
- "read_restricted":false,
- "auto_close_hours":null,
- "post_count":5823,
- "latest_post_id":94610,
- "latest_topic_id":24355,
- "position":25,
- "parent_category_id":null,
- "posts_year":4264,
- "posts_month":609,
- "posts_week":103,
- "email_in":null,
- "email_in_allow_strangers":false,
- "topics_day":0,
- "posts_day":28,
- "logo_url":null,
- "background_url":null,
- "allow_badges":true,
- "name_lower":"ux",
- "auto_close_based_on_last_post":false
+ id: 94601,
+ cooked:
+ "
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Agree that the markup isn't ideal - it's kind of hacked together at the moment; especially because we have two different styles. I think once we settle on the specifics it can be re-written entirely.
Any plans to support localization of UI elements, so that I (for example) could set up a completely German speaking forum?
","post_number":1,"post_type":1,"updated_at":"2013-02-05T21:29:00.280Z","like_count":0,"reply_count":1,"reply_to_post_number":null,"quote_count":0,"avg_time":25,"incoming_link_count":314,"reads":475,"score":1702.25,"yours":false,"topic_id":280,"topic_slug":"internationalization-localization","display_username":"Uwe Keim","primary_group_name":null,"version":1,"can_edit":true,"can_delete":false,"can_recover":true,"user_title":null,"raw":"Any plans to support localization of UI elements, so that I (for example) could set up a completely German speaking forum?","actions_summary":[{"id":2,"count":0,"hidden":false,"can_act":true,"can_defer_flags":false},{"id":3,"count":0,"hidden":false,"can_act":true,"can_defer_flags":false},{"id":4,"count":0,"hidden":false,"can_act":true,"can_defer_flags":false},{"id":5,"count":0,"hidden":true,"can_act":true,"can_defer_flags":false},{"id":6,"count":0,"hidden":false,"can_act":true,"can_defer_flags":false},{"id":7,"count":0,"hidden":false,"can_act":true,"can_defer_flags":false},{"id":8,"count":0,"hidden":false,"can_act":true,"can_defer_flags":false}],"moderator":false,"admin":false,"staff":false,"user_id":255,"hidden":false,"hidden_reason_id":null,"trust_level":2,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false},
- "/posts/18": {"id":18,"username":"eviltrout","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","name":"Evil Trout","uploaded_avatar_id":9,"created_at":"2015-08-13T14:49:11.840Z","cooked":"
This is the first post.
","post_number":1,"post_type":1,"updated_at":"2015-08-13T14:49:11.840Z","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":null,"incoming_link_count":0,"reads":1,"score":0,"yours":true,"topic_id":9,"topic_slug":"this-is-a-test-topic","display_username":"","primary_group_name":null,"version":1,"can_edit":true,"can_delete":false,"can_recover":true,"user_title":null,"raw":"This is the first post.","actions_summary":[{"id":3,"can_act":true},{"id":4,"can_act":true},{"id":5,"hidden":true,"can_act":true},{"id":7,"can_act":true},{"id":8,"can_act":true}],"moderator":false,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":4,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false},
- "/posts/19": {"id":19,"username":"eviltrout","avatar_template":"//www.gravatar.com/avatar/c6e17f2ae2a215e87ff9e878a4e63cd9.png?s={size}&r=pg&d=identicon","name":"Evil Trout","uploaded_avatar_id":9,"created_at":"2015-08-13T14:49:18.231Z","cooked":"