From 96c02caba7e37d771a8dc89aa4dab786a9cfbf9f Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 19 May 2020 10:20:00 +0800 Subject: [PATCH 01/80] DEV: Change use of Redis `flushall` to `flushdb`. FLUSHALL removes all keys from all databases. Instead we only want to remove keys from the current Redis database. --- config/initializers/001-redis.rb | 2 +- .../spec/discourse_narrative_bot/track_selector_spec.rb | 2 +- spec/components/auth/default_current_user_provider_spec.rb | 2 +- spec/components/discourse_redis_spec.rb | 4 ++-- spec/components/email/processor_spec.rb | 2 +- spec/components/pretty_text_spec.rb | 4 ++-- spec/jobs/bookmark_reminder_notifications_spec.rb | 2 +- spec/lib/bookmark_reminder_notification_handler_spec.rb | 2 +- spec/models/topic_spec.rb | 2 +- spec/requests/admin/backups_controller_spec.rb | 2 +- spec/requests/admin/users_controller_spec.rb | 2 +- spec/requests/search_controller_spec.rb | 4 ++-- spec/requests/topics_controller_spec.rb | 2 +- spec/requests/webhooks_controller_spec.rb | 2 +- spec/services/word_watcher_spec.rb | 2 +- 15 files changed, 18 insertions(+), 18 deletions(-) diff --git a/config/initializers/001-redis.rb b/config/initializers/001-redis.rb index e48441594e9..d11303a9d59 100644 --- a/config/initializers/001-redis.rb +++ b/config/initializers/001-redis.rb @@ -2,5 +2,5 @@ if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS'] puts "Flushing redis (development mode)" - Discourse.redis.flushall + Discourse.redis.flushdb end diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb index 4e24b9feaef..6914dff1d2f 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb @@ -472,7 +472,7 @@ describe DiscourseNarrativeBot::TrackSelector do let(:post) { Fabricate(:post, topic: topic) } after do - Discourse.redis.flushall + Discourse.redis.flushdb end describe 'when random reply massage has been displayed in the last 6 hours' do diff --git a/spec/components/auth/default_current_user_provider_spec.rb b/spec/components/auth/default_current_user_provider_spec.rb index 1b698cbf368..8c14233a5ba 100644 --- a/spec/components/auth/default_current_user_provider_spec.rb +++ b/spec/components/auth/default_current_user_provider_spec.rb @@ -237,7 +237,7 @@ describe Auth::DefaultCurrentUserProvider do end after do - Discourse.redis.flushall + Discourse.redis.flushdb end it "should not update last seen for suspended users" do diff --git a/spec/components/discourse_redis_spec.rb b/spec/components/discourse_redis_spec.rb index 6d4af1d8174..abc9a5917a8 100644 --- a/spec/components/discourse_redis_spec.rb +++ b/spec/components/discourse_redis_spec.rb @@ -21,11 +21,11 @@ describe DiscourseRedis do let(:raw_redis) { Redis.new(DiscourseRedis.config) } before do - raw_redis.flushall + raw_redis.flushdb end after do - raw_redis.flushall + raw_redis.flushdb end describe 'when namespace is enabled' do diff --git a/spec/components/email/processor_spec.rb b/spec/components/email/processor_spec.rb index 3fe4ab41b7a..606955551a1 100644 --- a/spec/components/email/processor_spec.rb +++ b/spec/components/email/processor_spec.rb @@ -5,7 +5,7 @@ require "email/processor" describe Email::Processor do after do - Discourse.redis.flushall + Discourse.redis.flushdb end let(:from) { "foo@bar.com" } diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb index 8969a526bd5..c5ef73c4d23 100644 --- a/spec/components/pretty_text_spec.rb +++ b/spec/components/pretty_text_spec.rb @@ -508,7 +508,7 @@ describe PrettyText do ['apple', 'banana'].each { |w| Fabricate(:watched_word, word: w, action: WatchedWord.actions[:censor]) } expect(PrettyText.cook("# banana")).not_to include('banana') ensure - Discourse.redis.flushall + Discourse.redis.flushdb end end end @@ -1166,7 +1166,7 @@ HTML end describe "censoring" do - after(:all) { Discourse.redis.flushall } + after(:all) { Discourse.redis.flushdb } def expect_cooked_match(raw, expected_cooked) expect(PrettyText.cook(raw)).to eq(expected_cooked) diff --git a/spec/jobs/bookmark_reminder_notifications_spec.rb b/spec/jobs/bookmark_reminder_notifications_spec.rb index 0bcfa0b3d21..25379d0ba39 100644 --- a/spec/jobs/bookmark_reminder_notifications_spec.rb +++ b/spec/jobs/bookmark_reminder_notifications_spec.rb @@ -22,7 +22,7 @@ RSpec.describe Jobs::BookmarkReminderNotifications do bookmark1.update_column(:reminder_at, five_minutes_ago - 10.minutes) bookmark2.update_column(:reminder_at, five_minutes_ago - 5.minutes) bookmark3.update_column(:reminder_at, five_minutes_ago) - Discourse.redis.flushall + Discourse.redis.flushdb end it "sends every reminder and marks the reminder_at to nil for all bookmarks, as well as last sent date" do diff --git a/spec/lib/bookmark_reminder_notification_handler_spec.rb b/spec/lib/bookmark_reminder_notification_handler_spec.rb index 6af860f2f04..3d9a6d77f64 100644 --- a/spec/lib/bookmark_reminder_notification_handler_spec.rb +++ b/spec/lib/bookmark_reminder_notification_handler_spec.rb @@ -8,7 +8,7 @@ RSpec.describe BookmarkReminderNotificationHandler do fab!(:user) { Fabricate(:user) } before do - Discourse.redis.flushall + Discourse.redis.flushdb end describe "#send_notification" do diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index d3815793009..d1d5d1cc911 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -33,7 +33,7 @@ describe Topic do describe 'censored words' do after do - Discourse.redis.flushall + Discourse.redis.flushdb end describe 'when title contains censored words' do diff --git a/spec/requests/admin/backups_controller_spec.rb b/spec/requests/admin/backups_controller_spec.rb index 466d4a938be..03b9245744d 100644 --- a/spec/requests/admin/backups_controller_spec.rb +++ b/spec/requests/admin/backups_controller_spec.rb @@ -35,7 +35,7 @@ RSpec.describe Admin::BackupsController do end after do - Discourse.redis.flushall + Discourse.redis.flushdb @paths&.each { |path| File.delete(path) if File.exists?(path) } @paths = nil diff --git a/spec/requests/admin/users_controller_spec.rb b/spec/requests/admin/users_controller_spec.rb index f62407d9569..099372cad00 100644 --- a/spec/requests/admin/users_controller_spec.rb +++ b/spec/requests/admin/users_controller_spec.rb @@ -293,7 +293,7 @@ RSpec.describe Admin::UsersController do fab!(:another_user) { Fabricate(:coding_horror) } after do - Discourse.redis.flushall + Discourse.redis.flushdb end it "raises an error when the user doesn't have permission" do diff --git a/spec/requests/search_controller_spec.rb b/spec/requests/search_controller_spec.rb index 947bd8754a9..dac11690d3e 100644 --- a/spec/requests/search_controller_spec.rb +++ b/spec/requests/search_controller_spec.rb @@ -26,11 +26,11 @@ describe SearchController do before do # TODO be a bit more strategic here instead of junking # all of redis - Discourse.redis.flushall + Discourse.redis.flushdb end after do - Discourse.redis.flushall + Discourse.redis.flushdb end context "when overloaded" do diff --git a/spec/requests/topics_controller_spec.rb b/spec/requests/topics_controller_spec.rb index 726b92228f2..9649f57f5ba 100644 --- a/spec/requests/topics_controller_spec.rb +++ b/spec/requests/topics_controller_spec.rb @@ -2127,7 +2127,7 @@ RSpec.describe TopicsController do let(:topic) { post.topic } after do - Discourse.redis.flushall + Discourse.redis.flushdb end it 'returns first post of the topic' do diff --git a/spec/requests/webhooks_controller_spec.rb b/spec/requests/webhooks_controller_spec.rb index 7772e0eb186..580c0c72f05 100644 --- a/spec/requests/webhooks_controller_spec.rb +++ b/spec/requests/webhooks_controller_spec.rb @@ -3,7 +3,7 @@ require "rails_helper" describe WebhooksController do - before { Discourse.redis.flushall } + before { Discourse.redis.flushdb } let(:email) { "em@il.com" } let(:message_id) { "12345@il.com" } diff --git a/spec/services/word_watcher_spec.rb b/spec/services/word_watcher_spec.rb index 0f6a2b7bb39..5cf70b65839 100644 --- a/spec/services/word_watcher_spec.rb +++ b/spec/services/word_watcher_spec.rb @@ -7,7 +7,7 @@ describe WordWatcher do let(:raw) { "Do you like liquorice?\n\nI really like them. One could even say that I am *addicted* to liquorice. Anf if\nyou can mix it up with some anise, then I'm in heaven ;)" } after do - Discourse.redis.flushall + Discourse.redis.flushdb end describe '.word_matcher_regexp' do From 05beaa7f45b3dfd9dead38cf4716481d58beab0b Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 19 May 2020 10:26:23 +0800 Subject: [PATCH 02/80] DEV: Remove override of `flushdb` in `DiscourseRedis`. --- lib/discourse_redis.rb | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/discourse_redis.rb b/lib/discourse_redis.rb index ff946cacfb5..6b630b7b34d 100644 --- a/lib/discourse_redis.rb +++ b/lib/discourse_redis.rb @@ -266,12 +266,6 @@ class DiscourseRedis end end - def flushdb - DiscourseRedis.ignore_readonly do - keys.each { |k| del(k) } - end - end - def reconnect @redis._client.reconnect end From 864fb45ff081cad58e122ca5b4a15ffebd4dbb31 Mon Sep 17 00:00:00 2001 From: Kris Date: Tue, 19 May 2020 00:24:17 -0400 Subject: [PATCH 03/80] Improve mobile friendliness of crawler view --- .../common/base/crawler_layout.scss | 30 +++++++++++++++++++ app/views/list/list.erb | 8 ++--- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/common/base/crawler_layout.scss b/app/assets/stylesheets/common/base/crawler_layout.scss index c279aceff4c..bff0addac1a 100644 --- a/app/assets/stylesheets/common/base/crawler_layout.scss +++ b/app/assets/stylesheets/common/base/crawler_layout.scss @@ -27,6 +27,36 @@ body.crawler { .topic-list { margin-bottom: 1em; + @media (max-width: 850px) { + td { + word-break: break-all; + &.posters { + a:not(:last-of-type) { + display: none; + } + a:last-of-type { + display: block; + } + } + } + + td, + th { + &.views { + display: none; + } + } + + .link-top-line { + a.title { + padding: 0; + } + } + + .link-bottom-line { + margin-top: 0.25em; + } + } } footer { diff --git a/app/views/list/list.erb b/app/views/list/list.erb index 2d32efb77bf..2338d39c6a5 100644 --- a/app/views/list/list.erb +++ b/app/views/list/list.erb @@ -47,8 +47,8 @@ <%= t 'js.topic.title' %> - <%= t 'js.replies' %> - <%= t 'js.views' %> + <%= t 'js.replies' %> + <%= t 'js.views' %> <%= t 'js.activity' %> @@ -101,10 +101,10 @@ <% end %> <% end %> - + '><%= t.posts_count %> - + '><%= t.views %> From 062cb1e1cb110d42a33033671df9186533d1a3c6 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Tue, 19 May 2020 13:40:58 +0800 Subject: [PATCH 04/80] UX: Remove caret from notifications-button. --- .../select-kit/app/components/notifications-button.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/javascripts/select-kit/app/components/notifications-button.js b/app/assets/javascripts/select-kit/app/components/notifications-button.js index f5423b9e64a..32dc2ad7ba1 100644 --- a/app/assets/javascripts/select-kit/app/components/notifications-button.js +++ b/app/assets/javascripts/select-kit/app/components/notifications-button.js @@ -13,8 +13,7 @@ export default DropdownSelectBoxComponent.extend({ autoFilterable: false, filterable: false, i18nPrefix: "", - i18nPostfix: "", - showCaret: true + i18nPostfix: "" }, modifyComponentForRow() { From 779dc30d2e06a57d9505262d91fea6404ffa2e97 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Tue, 19 May 2020 16:31:05 +1000 Subject: [PATCH 05/80] FIX: Join bookmarks migration on users to avoid missing user records * the post_actions table has no FK to users, so if a user has been deleted we may end up with dangling post_action records, which then interferes with the bookmarks migration because bookmarks DO have an FK to users --- ...20200409033412_create_bookmarks_from_post_action_bookmarks.rb | 1 + lib/tasks/bookmarks.rake | 1 + 2 files changed, 2 insertions(+) diff --git a/db/migrate/20200409033412_create_bookmarks_from_post_action_bookmarks.rb b/db/migrate/20200409033412_create_bookmarks_from_post_action_bookmarks.rb index 092a0e7b992..57b1885e350 100644 --- a/db/migrate/20200409033412_create_bookmarks_from_post_action_bookmarks.rb +++ b/db/migrate/20200409033412_create_bookmarks_from_post_action_bookmarks.rb @@ -16,6 +16,7 @@ class CreateBookmarksFromPostActionBookmarks < ActiveRecord::Migration[6.0] INNER JOIN posts ON posts.id = post_actions.post_id LEFT JOIN bookmarks ON bookmarks.post_id = post_actions.post_id AND bookmarks.user_id = post_actions.user_id INNER JOIN topics ON topics.id = posts.topic_id + INNER JOIN users ON users.id = post_actions.user_id WHERE bookmarks.id IS NULL AND post_action_type_id = :type_id AND post_actions.deleted_at IS NULL AND posts.deleted_at IS NULL LIMIT 2000 SQL diff --git a/lib/tasks/bookmarks.rake b/lib/tasks/bookmarks.rake index d3cf545d2d0..87fe005b075 100644 --- a/lib/tasks/bookmarks.rake +++ b/lib/tasks/bookmarks.rake @@ -22,6 +22,7 @@ task "bookmarks:sync_to_table" => :environment do |_t, args| INNER JOIN posts ON posts.id = post_actions.post_id LEFT JOIN bookmarks ON bookmarks.post_id = post_actions.post_id AND bookmarks.user_id = post_actions.user_id INNER JOIN topics ON topics.id = posts.topic_id + INNER JOIN users ON users.id = post_actions.user_id WHERE bookmarks.id IS NULL AND post_action_type_id = :type_id AND post_actions.deleted_at IS NULL AND posts.deleted_at IS NULL LIMIT 2000 SQL From 3623a395dc970e36bdf4b95c1054e01c5be746ef Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 09:51:34 +0200 Subject: [PATCH 06/80] UI: refinements to topic footer buttons (#9780) --- .../components/topic-footer-buttons.hbs | 4 +- .../templates/components/pinned-button.hbs | 5 +-- .../components/topic-notifications-button.hbs | 37 +++++++++++------- .../stylesheets/common/base/topic-post.scss | 38 ++++++++++++++++--- .../common/select-kit/pinned-button.scss | 21 ---------- .../topic-notifications-button.scss | 27 ------------- .../stylesheets/desktop/topic-post.scss | 17 ++------- app/assets/stylesheets/mobile/topic-post.scss | 20 +--------- 8 files changed, 67 insertions(+), 102 deletions(-) delete mode 100644 app/assets/stylesheets/common/select-kit/topic-notifications-button.scss diff --git a/app/assets/javascripts/discourse/app/templates/components/topic-footer-buttons.hbs b/app/assets/javascripts/discourse/app/templates/components/topic-footer-buttons.hbs index 007ec9c19d2..aa5b44a7163 100644 --- a/app/assets/javascripts/discourse/app/templates/components/topic-footer-buttons.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/topic-footer-buttons.hbs @@ -50,10 +50,10 @@ args=(hash topic=topic) tagName="" connectorTagName="span"}} - - {{pinned-button pinned=topic.pinned topic=topic}} +{{pinned-button pinned=topic.pinned topic=topic}} + {{#if showNotificationsButton}} {{topic-notifications-button notificationLevel=topic.details.notification_level diff --git a/app/assets/javascripts/select-kit/app/templates/components/pinned-button.hbs b/app/assets/javascripts/select-kit/app/templates/components/pinned-button.hbs index f54bdb6b5fe..91bfe147ff6 100644 --- a/app/assets/javascripts/select-kit/app/templates/components/pinned-button.hbs +++ b/app/assets/javascripts/select-kit/app/templates/components/pinned-button.hbs @@ -1,5 +1,4 @@ -{{pinned-options value=pinned topic=topic}} -

- {{html-safe reasonText}} + {{pinned-options value=pinned topic=topic}} + {{html-safe reasonText}}

diff --git a/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs b/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs index 50dd20e56eb..fa6f3e83a20 100644 --- a/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs +++ b/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs @@ -1,17 +1,28 @@ -{{topic-notifications-options - value=notificationLevel - topic=topic - onChange=(action "changeTopicNotificationLevel") - options=(hash - showFullTitle=showFullTitle - placement=placement - preventsClickPropagation=true - showCaret=showCaret - ) -}} - {{#if appendReason}}

- {{html-safe topic.details.notificationReasonText}} + {{topic-notifications-options + value=notificationLevel + topic=topic + onChange=(action "changeTopicNotificationLevel") + options=(hash + showFullTitle=showFullTitle + placement=placement + preventsClickPropagation=true + showCaret=showCaret + ) + }} + {{html-safe topic.details.notificationReasonText}}

+{{else}} + {{topic-notifications-options + value=notificationLevel + topic=topic + onChange=(action "changeTopicNotificationLevel") + options=(hash + showFullTitle=showFullTitle + placement=placement + preventsClickPropagation=true + showCaret=showCaret + ) + }} {{/if}} diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 6e465bbc6b6..3ebee34ed27 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1005,10 +1005,38 @@ a.mention-group { } #topic-footer-buttons { - .reason { - color: $primary-high; - display: inline; - margin: 0 0 0 8px; - line-height: $line-height-medium; + padding: 0.5em 0; + + .topic-footer-main-buttons { + margin: -0.5em 0; + + > .btn, + .topic-admin-menu-button-container { + margin: 0.5em 0.5em 0.5em 0; + } + + .topic-admin-menu-button-container { + display: inline-flex; + } + } + + .pinned-button:not(.is-hidden) + .topic-notifications-button { + margin-top: 0; + } + + .pinned-button, + .topic-notifications-button { + margin: 1em 0; + + .reason { + color: $primary-high; + display: inline-flex; + margin: 0; + align-items: center; + + .text { + margin-left: 0.5em; + } + } } } diff --git a/app/assets/stylesheets/common/select-kit/pinned-button.scss b/app/assets/stylesheets/common/select-kit/pinned-button.scss index f080b8a016c..3e51092ae39 100644 --- a/app/assets/stylesheets/common/select-kit/pinned-button.scss +++ b/app/assets/stylesheets/common/select-kit/pinned-button.scss @@ -1,28 +1,7 @@ #topic-footer-buttons { .pinned-button { - min-width: auto; - margin: 1em 0; - &.is-hidden { display: none; } - - .btn { - margin: 0; - } - - .reason { - display: inline; - line-height: $line-height-medium; - } - } -} - -.pinned-button { - margin: 0; - min-width: auto; - - .pinned-options { - display: inline; } } diff --git a/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss b/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss deleted file mode 100644 index 1e7c7972054..00000000000 --- a/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss +++ /dev/null @@ -1,27 +0,0 @@ -#topic-footer-buttons { - .topic-notifications-button { - min-width: auto; - margin: 1em 0; - - .btn { - margin: 0; - } - - .reason { - display: inline; - line-height: $line-height-medium; - } - } -} - -.topic-notifications-button .topic-notifications-options { - min-width: auto; -} - -.topic-notifications-button { - margin: 0; - - .topic-notifications-options { - display: inline-flex; - } -} diff --git a/app/assets/stylesheets/desktop/topic-post.scss b/app/assets/stylesheets/desktop/topic-post.scss index ca304b8e951..5adc17d3eb1 100644 --- a/app/assets/stylesheets/desktop/topic-post.scss +++ b/app/assets/stylesheets/desktop/topic-post.scss @@ -451,20 +451,15 @@ pre.copy-codeblocks:hover .copy-cmd { } } -@mixin topic-footer-button { - margin-bottom: 5px; - margin-right: 10px; -} - #topic-footer-buttons { - padding: 10px 10px 0 0; - float: left; - .btn { - @include topic-footer-button; + max-width: calc(690px + (11px * 2) + 45px); + + .bookmark { .d-icon-bookmark.bookmarked { color: $tertiary; } } + .bookmark.bookmarked .d-icon-bookmark, .bookmark.bookmarked .d-icon-discourse-bookmark-clock { color: $tertiary; @@ -474,10 +469,6 @@ pre.copy-codeblocks:hover .copy-cmd { } } -#topic-footer-button { - width: 757px; -} - .suggested-topics { clear: left; padding: 20px 0 15px 0; diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index 9cd4931ce83..f6fa70b25a4 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -235,20 +235,16 @@ a.reply-to-tab { } #topic-footer-buttons { - @include clearfix; - padding: 20px 0 0 0; .d-icon-bookmark.bookmarked, .d-icon-discourse-bookmark-clock.bookmarked { color: $tertiary; } - .combobox { + + .topic-footer-mobile-dropdown { margin-right: 0.5em; width: 160px; - margin-bottom: 0.5em; } -} -#topic-footer-buttons { .topic-notifications-button, .pinned-button { display: flex; @@ -263,11 +259,6 @@ a.reply-to-tab { } } -#topic-footer-button { - width: 100px; - margin: 0 auto; -} - .suggested-topics { clear: left; padding: 20px 0 15px 0; @@ -292,13 +283,6 @@ span.post-count { opacity: 0.8; } -#topic-footer-buttons { - .btn { - margin-bottom: 0.5em; - margin-right: 0.5em; - } -} - #topic-title { z-index: z("base") + 1; margin: 0 0 0 0 !important; From 7b7c0ef52fecf472860513744786c6f442f56960 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 10:02:40 +0200 Subject: [PATCH 07/80] DEV: removes brittle test (#9826) --- test/javascripts/acceptance/emoji-picker-test.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/test/javascripts/acceptance/emoji-picker-test.js b/test/javascripts/acceptance/emoji-picker-test.js index 6a4922ed5c0..a3d8472b535 100644 --- a/test/javascripts/acceptance/emoji-picker-test.js +++ b/test/javascripts/acceptance/emoji-picker-test.js @@ -168,19 +168,6 @@ QUnit.test( } ); -QUnit.test("emoji picker lazy loads emojis", async assert => { - await visit("/t/internationalization-localization/280"); - await click("#topic-footer-buttons .btn.create"); - - await click("button.emoji.btn"); - - assert.equal( - find('.emoji-picker button[title="massage_woman"]').css("background-image"), - "none", - "it doesn't load invisible emojis" - ); -}); - QUnit.test("emoji picker persists state", async assert => { await visit("/t/internationalization-localization/280"); await click("#topic-footer-buttons .btn.create"); From 1647ba4624965dae6b88576c9f120731616cac9f Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 11:29:38 +0200 Subject: [PATCH 08/80] FIX: applies flex on topic-footer-main-buttons (#9829) --- app/assets/stylesheets/common/base/topic-post.scss | 6 ++++-- app/assets/stylesheets/mobile/topic-post.scss | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 3ebee34ed27..54aa976c0c0 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1008,11 +1008,13 @@ a.mention-group { padding: 0.5em 0; .topic-footer-main-buttons { - margin: -0.5em 0; + margin: 0 0 -0.5em 0; + display: flex; + flex-wrap: wrap; > .btn, .topic-admin-menu-button-container { - margin: 0.5em 0.5em 0.5em 0; + margin: 0 0.5em 0.5em 0; } .topic-admin-menu-button-container { diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index f6fa70b25a4..db68682303d 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -241,7 +241,7 @@ a.reply-to-tab { } .topic-footer-mobile-dropdown { - margin-right: 0.5em; + margin: 0 0.5em 0.5em 0; width: 160px; } From f2574736a22850a6972ea8fda659b98603650807 Mon Sep 17 00:00:00 2001 From: dave0688 Date: Tue, 19 May 2020 10:32:56 +0100 Subject: [PATCH 09/80] FEATURE: Add same site cookie 'None' option to make cross domain systems possible (#9374) Previously reverted in cb8f8de4, but can be re-applied now that Rack has been updated --- config/site_settings.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index d49bb0e4cfa..ea4bbd4b665 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -1382,7 +1382,8 @@ security: - Lax - Strict - Disabled - regex: "^(Lax|Strict|Disabled)$" + - None + regex: "^(Lax|Strict|Disabled|None)$" enable_escaped_fragments: true allow_index_in_robots_txt: true moderators_create_categories: false From 725e38f9d7c42975c9d75afe0a1f79499693667b Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 19 May 2020 10:38:58 +0100 Subject: [PATCH 10/80] DEV: Allow plugins to request topic thumbnail sizes (#9828) In plugin.rb, you can register new sizes like ``` register_topic_thumbnail_size [512, 512] ``` For more information about thumbnails see https://github.com/discourse/discourse/commit/03818e642a1ae871bffdc0c39c10f05f0b8b0398 --- app/models/topic.rb | 8 +++--- lib/discourse_plugin_registry.rb | 2 ++ lib/plugin/instance.rb | 10 +++++++ spec/integration/topic_thumbnail_spec.rb | 33 ++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/app/models/topic.rb b/app/models/topic.rb index d331a308060..f02b4fc030f 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -33,11 +33,11 @@ class Topic < ActiveRecord::Base end def self.thumbnail_sizes - [ self.share_thumbnail_size ] + [ self.share_thumbnail_size ] + DiscoursePluginRegistry.topic_thumbnail_sizes end - def thumbnail_job_redis_key(extra_sizes) - "generate_topic_thumbnail_enqueue_#{id}_#{extra_sizes.inspect}" + def thumbnail_job_redis_key(sizes) + "generate_topic_thumbnail_enqueue_#{id}_#{sizes.inspect}" end def filtered_topic_thumbnails(extra_sizes: []) @@ -79,7 +79,7 @@ class Topic < ActiveRecord::Base if SiteSetting.create_thumbnails && enqueue_if_missing && records.length < thumbnail_sizes.length && - Discourse.redis.set(thumbnail_job_redis_key(extra_sizes), 1, nx: true, ex: 1.minute) + Discourse.redis.set(thumbnail_job_redis_key(thumbnail_sizes), 1, nx: true, ex: 1.minute) Jobs.enqueue(:generate_topic_thumbnails, { topic_id: id, extra_sizes: extra_sizes }) end diff --git a/lib/discourse_plugin_registry.rb b/lib/discourse_plugin_registry.rb index ae260e2ce1a..ab382a4d15c 100644 --- a/lib/discourse_plugin_registry.rb +++ b/lib/discourse_plugin_registry.rb @@ -75,6 +75,8 @@ class DiscoursePluginRegistry define_filtered_register :editable_group_custom_fields + define_filtered_register :topic_thumbnail_sizes + def self.register_auth_provider(auth_provider) self.auth_providers << auth_provider end diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index a993ce52f0b..ab48f7cbead 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -165,6 +165,16 @@ class Plugin::Instance DiscoursePluginRegistry.register_editable_group_custom_field(field, self) end + # Request a new size for topic thumbnails + # Will respect plugin enabled setting is enabled + # Size should be an array with two elements [max_width, max_height] + def register_topic_thumbnail_size(size) + if !(size.kind_of?(Array) && size.length == 2) + raise ArgumentError.new("Topic thumbnail dimension is not valid") + end + DiscoursePluginRegistry.register_topic_thumbnail_size(size, self) + end + def custom_avatar_column(column) reloadable_patch do |plugin| AvatarLookup.lookup_columns << column diff --git a/spec/integration/topic_thumbnail_spec.rb b/spec/integration/topic_thumbnail_spec.rb index 9ba35cbe970..c71cf8f96e8 100644 --- a/spec/integration/topic_thumbnail_spec.rb +++ b/spec/integration/topic_thumbnail_spec.rb @@ -84,5 +84,38 @@ describe "Topic Thumbnails" do expect(thumbnails.length).to eq(5) end end + + context "with a plugin" do + before do + plugin = Plugin::Instance.new + plugin.register_topic_thumbnail_size [512, 512] + end + + after do + DiscoursePluginRegistry.reset! + end + + it "includes the theme specified resolutions" do + topic_json = nil + + expect do + topic_json = get_topic + end.to change { Jobs::GenerateTopicThumbnails.jobs.size }.by(1) + + # Run the job + args = Jobs::GenerateTopicThumbnails.jobs.last["args"].first + Jobs::GenerateTopicThumbnails.new.execute(args.with_indifferent_access) + + # Request again + expect do + topic_json = get_topic + end.to change { Jobs::GenerateTopicThumbnails.jobs.size }.by(0) + + thumbnails = topic_json["thumbnails"] + + # Original + Optimized + 1 plugin request + expect(thumbnails.length).to eq(3) + end + end end end From e9f579bd3f133854dcd7dced202bff43be69364f Mon Sep 17 00:00:00 2001 From: David Taylor Date: Tue, 19 May 2020 11:04:02 +0100 Subject: [PATCH 11/80] DEV: Clean up thumbnail tests correctly --- spec/integration/topic_thumbnail_spec.rb | 2 +- spec/serializers/topic_view_serializer_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/integration/topic_thumbnail_spec.rb b/spec/integration/topic_thumbnail_spec.rb index c71cf8f96e8..dcdbb084d5a 100644 --- a/spec/integration/topic_thumbnail_spec.rb +++ b/spec/integration/topic_thumbnail_spec.rb @@ -10,7 +10,7 @@ describe "Topic Thumbnails" do context 'latest' do def get_topic - Discourse.redis.del(topic.thumbnail_job_redis_key([])) + Discourse.redis.del(topic.thumbnail_job_redis_key(Topic.thumbnail_sizes)) get '/latest.json' response.parsed_body["topic_list"]["topics"][0] end diff --git a/spec/serializers/topic_view_serializer_spec.rb b/spec/serializers/topic_view_serializer_spec.rb index 5da26a674ec..f6249b275bb 100644 --- a/spec/serializers/topic_view_serializer_spec.rb +++ b/spec/serializers/topic_view_serializer_spec.rb @@ -60,7 +60,7 @@ describe TopicViewSerializer do it 'should have thumbnails' do SiteSetting.create_thumbnails = true - Discourse.redis.del(topic.thumbnail_job_redis_key([])) + Discourse.redis.del(topic.thumbnail_job_redis_key(Topic.thumbnail_sizes)) json = nil expect do From 05ca0c908fb83e4e29af1dccee83110a227aafbb Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Tue, 19 May 2020 14:13:28 +0300 Subject: [PATCH 12/80] FIX: GroupArchivedMessage belongs to Group, not User --- app/models/group_archived_message.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/group_archived_message.rb b/app/models/group_archived_message.rb index 1715a57585f..8199a53cf62 100644 --- a/app/models/group_archived_message.rb +++ b/app/models/group_archived_message.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class GroupArchivedMessage < ActiveRecord::Base - belongs_to :user + belongs_to :group belongs_to :topic def self.move_to_inbox!(group_id, topic) From 7c3663ff737a8030d8669a923486144a7e20cfd3 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 13:27:57 +0200 Subject: [PATCH 13/80] UX: adds visual feedback when changing topic notifications level (#9831) --- .../discourse/app/models/topic-details.js | 12 +++++----- .../components/topic-notifications-button.js | 22 +++++++++++++++++-- .../components/topic-notifications-button.hbs | 2 ++ .../stylesheets/common/base/topic-post.scss | 8 +++++++ .../common/select-kit/select-kit.scss | 5 +++++ 5 files changed, 42 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/discourse/app/models/topic-details.js b/app/assets/javascripts/discourse/app/models/topic-details.js index 50449aa0e39..45dd1948415 100644 --- a/app/assets/javascripts/discourse/app/models/topic-details.js +++ b/app/assets/javascripts/discourse/app/models/topic-details.js @@ -61,12 +61,14 @@ const TopicDetails = RestModel.extend({ } }, - updateNotifications(v) { - this.set("notification_level", v); - this.set("notifications_reason_id", null); - return ajax("/t/" + this.get("topic.id") + "/notifications", { + updateNotifications(level) { + this.setProperties({ + notification_level: level, + notifications_reason_id: null + }); + return ajax(`/t/${this.get("topic.id")}/notifications`, { type: "POST", - data: { notification_level: v } + data: { notification_level: level } }); }, diff --git a/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js b/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js index 58329393e7c..a8743d8d59a 100644 --- a/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js +++ b/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js @@ -1,20 +1,38 @@ import Component from "@ember/component"; -import { action } from "@ember/object"; +import { action, computed } from "@ember/object"; +import { later, cancel } from "@ember/runloop"; export default Component.extend({ layoutName: "select-kit/templates/components/topic-notifications-button", classNames: ["topic-notifications-button"], + classNameBindings: ["isLoading"], appendReason: true, showFullTitle: true, placement: "bottom-start", notificationLevel: null, topic: null, showCaret: true, + isLoading: false, + icon: computed("isLoading", function() { + return this.isLoading ? "spinner" : null; + }), + + willDestroyElement() { + this._super(...arguments); + + this._endLoadingHandler && cancel(this._endLoadingHandler); + }, @action changeTopicNotificationLevel(levelId) { if (levelId !== this.notificationLevel) { - this.topic.details.updateNotifications(levelId); + this.set("isLoading", true); + this.topic.details.updateNotifications(levelId).finally(() => { + this._endLoadingHandler = later( + () => this.set("isLoading", false), + 250 + ); + }); } } }); diff --git a/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs b/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs index fa6f3e83a20..f21111ebbd5 100644 --- a/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs +++ b/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs @@ -5,6 +5,7 @@ topic=topic onChange=(action "changeTopicNotificationLevel") options=(hash + icon=icon showFullTitle=showFullTitle placement=placement preventsClickPropagation=true @@ -19,6 +20,7 @@ topic=topic onChange=(action "changeTopicNotificationLevel") options=(hash + icon=icon showFullTitle=showFullTitle placement=placement preventsClickPropagation=true diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 54aa976c0c0..a290f2ce179 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1026,6 +1026,14 @@ a.mention-group { margin-top: 0; } + .topic-notifications-button.is-loading { + pointer-events: none; + user-select: none; + .topic-notifications-options { + opacity: 0.5; + } + } + .pinned-button, .topic-notifications-button { margin: 1em 0; diff --git a/app/assets/stylesheets/common/select-kit/select-kit.scss b/app/assets/stylesheets/common/select-kit/select-kit.scss index 130bad52f80..a9769b59710 100644 --- a/app/assets/stylesheets/common/select-kit/select-kit.scss +++ b/app/assets/stylesheets/common/select-kit/select-kit.scss @@ -63,6 +63,11 @@ flex-direction: row; min-height: 30px; + .d-icon-spinner { + -webkit-animation: rotate-forever 1s infinite linear; + animation: rotate-forever 1s infinite linear; + } + .selected-name { text-align: left; flex: 0 1 auto; From b4c5ff17a3ace1ab293b7c28821d11a4324ea1af Mon Sep 17 00:00:00 2001 From: Daniel Waterworth Date: Tue, 19 May 2020 14:03:54 +0100 Subject: [PATCH 14/80] FIX: Show a useful message when starting a plugin fails without a backtrace --- lib/plugin_initialization_guard.rb | 53 ++++++++++++++++++------------ 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/lib/plugin_initialization_guard.rb b/lib/plugin_initialization_guard.rb index a5a164e9e2e..11fd9430905 100644 --- a/lib/plugin_initialization_guard.rb +++ b/lib/plugin_initialization_guard.rb @@ -6,33 +6,44 @@ def plugin_initialization_guard(&block) rescue => error plugins_directory = Rails.root + 'plugins' - plugin_path = error.backtrace_locations.lazy.map do |location| - Pathname.new(location.absolute_path) - .ascend - .lazy - .find { |path| path.parent == plugins_directory } - end.next + if error.backtrace + plugin_path = error.backtrace_locations.lazy.map do |location| + Pathname.new(location.absolute_path) + .ascend + .lazy + .find { |path| path.parent == plugins_directory } + end.next - raise unless plugin_path + raise unless plugin_path - stack_trace = error.backtrace.each_with_index.inject([]) do |messages, (line, index)| - if index == 0 - messages << "#{line}: #{error} (#{error.class})" - else - messages << "\t#{index}: from #{line}" - end - end.reverse.join("\n") + stack_trace = error.backtrace.each_with_index.inject([]) do |messages, (line, index)| + if index == 0 + messages << "#{line}: #{error} (#{error.class})" + else + messages << "\t#{index}: from #{line}" + end + end.reverse.join("\n") - STDERR.puts <<~MESSAGE - #{stack_trace} + STDERR.puts <<~MESSAGE + #{stack_trace} - ** INCOMPATIBLE PLUGIN ** + ** INCOMPATIBLE PLUGIN ** - You are unable to build Discourse due to errors in the plugin at - #{plugin_path} + You are unable to build Discourse due to errors in the plugin at + #{plugin_path} - Please try removing this plugin and rebuilding again! - MESSAGE + Please try removing this plugin and rebuilding again! + MESSAGE + else + STDERR.puts <<~MESSAGE + ** PLUGIN FAILURE ** + + You are unable to build Discourse due to this error during plugin + initialization: + + #{error} + MESSAGE + end exit 1 end end From f038f8f1547ab5b5a98e28596ef50552180415c7 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Tue, 19 May 2020 18:45:29 +0530 Subject: [PATCH 15/80] FIX: description for 'uncategorized' category was blank --- app/controllers/list_controller.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/controllers/list_controller.rb b/app/controllers/list_controller.rb index 81511387f73..5eadbbcf6d7 100644 --- a/app/controllers/list_controller.rb +++ b/app/controllers/list_controller.rb @@ -331,7 +331,13 @@ class ListController < ApplicationController params[:category] = @category.id.to_s - @description_meta = @category.description_text + @description_meta = if @category.uncategorized? + I18n.t('category.uncategorized_description', locale: SiteSetting.default_locale) + else + @category.description_text + end + @description_meta = SiteSetting.site_description if @description_meta.blank? + if !guardian.can_see?(@category) if SiteSetting.detailed_404 raise Discourse::InvalidAccess From 38c05a4f07f029dbf4ba0ae189d2318db151046d Mon Sep 17 00:00:00 2001 From: Daniel Waterworth Date: Tue, 19 May 2020 14:27:12 +0100 Subject: [PATCH 16/80] FIX: Check backtrace and backtrace_locations before trying to print an error ... during plugin initialization. --- lib/plugin_initialization_guard.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/plugin_initialization_guard.rb b/lib/plugin_initialization_guard.rb index 11fd9430905..42c1bda864f 100644 --- a/lib/plugin_initialization_guard.rb +++ b/lib/plugin_initialization_guard.rb @@ -6,7 +6,7 @@ def plugin_initialization_guard(&block) rescue => error plugins_directory = Rails.root + 'plugins' - if error.backtrace + if error.backtrace && error.backtrace_locations plugin_path = error.backtrace_locations.lazy.map do |location| Pathname.new(location.absolute_path) .ascend From ab6737c44a8177c8dc730c23793ef0e475004082 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 17:13:40 +0200 Subject: [PATCH 17/80] UX: improves topic-notifications-button loading behavior (#9832) --- .../discourse/app/models/topic-details.js | 9 +++++---- .../components/topic-notifications-button.js | 16 +++------------- .../stylesheets/common/base/topic-post.scss | 8 -------- .../select-kit/topic-notifications-button.scss | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 25 deletions(-) create mode 100644 app/assets/stylesheets/common/select-kit/topic-notifications-button.scss diff --git a/app/assets/javascripts/discourse/app/models/topic-details.js b/app/assets/javascripts/discourse/app/models/topic-details.js index 45dd1948415..d8d5ea0036f 100644 --- a/app/assets/javascripts/discourse/app/models/topic-details.js +++ b/app/assets/javascripts/discourse/app/models/topic-details.js @@ -62,13 +62,14 @@ const TopicDetails = RestModel.extend({ }, updateNotifications(level) { - this.setProperties({ - notification_level: level, - notifications_reason_id: null - }); return ajax(`/t/${this.get("topic.id")}/notifications`, { type: "POST", data: { notification_level: level } + }).then(() => { + this.setProperties({ + notification_level: level, + notifications_reason_id: null + }); }); }, diff --git a/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js b/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js index a8743d8d59a..d9c09001823 100644 --- a/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js +++ b/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js @@ -1,6 +1,5 @@ import Component from "@ember/component"; import { action, computed } from "@ember/object"; -import { later, cancel } from "@ember/runloop"; export default Component.extend({ layoutName: "select-kit/templates/components/topic-notifications-button", @@ -17,22 +16,13 @@ export default Component.extend({ return this.isLoading ? "spinner" : null; }), - willDestroyElement() { - this._super(...arguments); - - this._endLoadingHandler && cancel(this._endLoadingHandler); - }, - @action changeTopicNotificationLevel(levelId) { if (levelId !== this.notificationLevel) { this.set("isLoading", true); - this.topic.details.updateNotifications(levelId).finally(() => { - this._endLoadingHandler = later( - () => this.set("isLoading", false), - 250 - ); - }); + this.topic.details + .updateNotifications(levelId) + .finally(() => this.set("isLoading", false)); } } }); diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index a290f2ce179..54aa976c0c0 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1026,14 +1026,6 @@ a.mention-group { margin-top: 0; } - .topic-notifications-button.is-loading { - pointer-events: none; - user-select: none; - .topic-notifications-options { - opacity: 0.5; - } - } - .pinned-button, .topic-notifications-button { margin: 1em 0; diff --git a/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss b/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss new file mode 100644 index 00000000000..b3808031a1d --- /dev/null +++ b/app/assets/stylesheets/common/select-kit/topic-notifications-button.scss @@ -0,0 +1,18 @@ +.topic-notifications-button { + &.is-loading { + pointer-events: none; + user-select: none; + + .d-icon-spinner { + margin: 0; + } + + .selected-name .d-icon { + display: none; + } + + .topic-notifications-options { + opacity: 0.5; + } + } +} From 01c27d991ab47046484badaf33d086aa2621bbb3 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 19 May 2020 11:34:53 -0400 Subject: [PATCH 18/80] Build(deps-dev): Bump minitest from 5.14.0 to 5.14.1 (#9807) Bumps [minitest](https://github.com/seattlerb/minitest) from 5.14.0 to 5.14.1. - [Release notes](https://github.com/seattlerb/minitest/releases) - [Changelog](https://github.com/seattlerb/minitest/blob/master/History.rdoc) - [Commits](https://github.com/seattlerb/minitest/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 752d48c3c90..dd28a916442 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -195,7 +195,7 @@ GEM mini_sql (0.2.5) mini_suffix (0.3.0) ffi (~> 1.9) - minitest (5.14.0) + minitest (5.14.1) mocha (1.11.2) mock_redis (0.23.0) msgpack (1.3.3) From b23fe547abe42f6b1c576e579bd55e4320dae54f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 19 May 2020 12:40:39 -0400 Subject: [PATCH 19/80] Build(deps): Bump puma from 4.3.3 to 4.3.4 (#9824) Bumps [puma](https://github.com/puma/puma) from 4.3.3 to 4.3.4. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/compare/v4.3.3...v4.3.4) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index dd28a916442..9dded399220 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -262,7 +262,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.5) - puma (4.3.3) + puma (4.3.4) nio4r (~> 2.0) r2 (0.2.7) rack (2.2.2) From 42229fecadd23348bf74da7f98119bd2d82a225b Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 19 May 2020 12:46:16 -0400 Subject: [PATCH 20/80] Build(deps): Bump rbtrace from 0.4.12 to 0.4.13 (#9827) Bumps [rbtrace](https://github.com/tmm1/rbtrace) from 0.4.12 to 0.4.13. - [Release notes](https://github.com/tmm1/rbtrace/releases) - [Commits](https://github.com/tmm1/rbtrace/compare/v0.4.12...v0.4.13) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9dded399220..f2c187b9b81 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -294,7 +294,7 @@ GEM rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) - rbtrace (0.4.12) + rbtrace (0.4.13) ffi (>= 1.0.6) msgpack (>= 0.4.3) optimist (>= 3.0.0) From 05d8091bd35ba5e2a5f468efce7e37cfab898295 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 20:39:29 +0200 Subject: [PATCH 21/80] DEV: adds triggerOnChangeOnTab option to select-kit (#9833) Usage: ``` options=(hash triggerOnChangeOnTab=false) ``` This will prevent to select the row when pressing tab. --- .../discourse/app/templates/components/d-navigation.hbs | 3 +++ .../javascripts/select-kit/app/components/select-kit.js | 3 ++- .../app/components/select-kit/select-kit-header.js | 6 +++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/app/templates/components/d-navigation.hbs b/app/assets/javascripts/discourse/app/templates/components/d-navigation.hbs index e9e0b9a34f1..2ac52d5f71b 100644 --- a/app/assets/javascripts/discourse/app/templates/components/d-navigation.hbs +++ b/app/assets/javascripts/discourse/app/templates/components/d-navigation.hbs @@ -3,6 +3,9 @@ {{#if showCategoryAdmin}} {{categories-admin-dropdown onChange=(action "selectCategoryAdminDropdownAction") + options=(hash + triggerOnChangeOnTab=false + ) }} {{/if}} diff --git a/app/assets/javascripts/select-kit/app/components/select-kit.js b/app/assets/javascripts/select-kit/app/components/select-kit.js index f2fbbbf1c2b..140e96782d6 100644 --- a/app/assets/javascripts/select-kit/app/components/select-kit.js +++ b/app/assets/javascripts/select-kit/app/components/select-kit.js @@ -271,7 +271,8 @@ export default Component.extend( selectedNameComponent: "selected-name", castInteger: false, preventsClickPropagation: false, - focusAfterOnChange: true + focusAfterOnChange: true, + triggerOnChangeOnTab: true }, autoFilterable: computed("content.[]", "selectKit.filter", function() { diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-header.js b/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-header.js index 785b2a47022..5697826f59f 100644 --- a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-header.js +++ b/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-header.js @@ -140,7 +140,11 @@ export default Component.extend(UtilsMixin, { this._focusFilterInput(); } else if (event.keyCode === 9) { // Tab - if (this.selectKit.highlighted && this.selectKit.isExpanded) { + if ( + this.selectKit.highlighted && + this.selectKit.isExpanded && + this.selectKit.options.triggerOnChangeOnTab + ) { this.selectKit.select( this.getValue(this.selectKit.highlighted), this.selectKit.highlighted From a239900522a119b12e1a126f0c255d10ace9035b Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Tue, 19 May 2020 20:44:54 +0200 Subject: [PATCH 22/80] UI: reduces category row description margin (#9834) --- app/assets/stylesheets/common/select-kit/category-row.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/common/select-kit/category-row.scss b/app/assets/stylesheets/common/select-kit/category-row.scss index 2bbe33c96ea..df43c956035 100644 --- a/app/assets/stylesheets/common/select-kit/category-row.scss +++ b/app/assets/stylesheets/common/select-kit/category-row.scss @@ -9,6 +9,9 @@ -ms-flex: 1 1 auto; flex: 1 1 auto; } + .category-desc p { + margin: 0; + } .category-status { .badge-wrapper.box { margin-bottom: 1px; From 52228b1fa659cef0d4c17c401ea553a0acd7bee8 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Tue, 19 May 2020 16:09:03 -0300 Subject: [PATCH 23/80] DEV: These routes don't exist anymore (#9823) --- app/assets/javascripts/admin/models/admin-user.js | 6 ------ config/routes.rb | 1 - 2 files changed, 7 deletions(-) diff --git a/app/assets/javascripts/admin/models/admin-user.js b/app/assets/javascripts/admin/models/admin-user.js index 71b8078f6ed..9977fa8dd46 100644 --- a/app/assets/javascripts/admin/models/admin-user.js +++ b/app/assets/javascripts/admin/models/admin-user.js @@ -77,12 +77,6 @@ const AdminUser = User.extend({ }); }, - revokeApiKey() { - return ajax(`/admin/users/${this.id}/revoke_api_key`, { - type: "DELETE" - }).then(() => this.set("api_key", null)); - }, - deleteAllPosts() { let deletedPosts = 0; const user = this; diff --git a/config/routes.rb b/config/routes.rb index d3a1082d435..a881b260d19 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -120,7 +120,6 @@ Discourse::Application.routes.draw do put "unsuspend" put "revoke_admin", constraints: AdminConstraint.new put "grant_admin", constraints: AdminConstraint.new - post "generate_api_key", constraints: AdminConstraint.new put "revoke_moderation", constraints: AdminConstraint.new put "grant_moderation", constraints: AdminConstraint.new put "approve" From 0a700d81fca8d84c83428e44e6ff31f392535fc1 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Tue, 19 May 2020 22:34:37 +0200 Subject: [PATCH 24/80] FIX: Restoring backups could fail for database dumps > 8GiB This is a temporary fix until we ship a new image with bsdtar. --- lib/backup_restore/backup_file_handler.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/backup_restore/backup_file_handler.rb b/lib/backup_restore/backup_file_handler.rb index c5e37024880..7b26356989e 100644 --- a/lib/backup_restore/backup_file_handler.rb +++ b/lib/backup_restore/backup_file_handler.rb @@ -65,9 +65,10 @@ module BackupRestore return if !@is_archive log "Unzipping archive, this may take a while..." - pipeline = Compression::Pipeline.new([Compression::Tar.new, Compression::Gzip.new]) - unzipped_path = pipeline.decompress(@tmp_directory, @archive_path, available_size) - pipeline.strip_directory(unzipped_path, @tmp_directory) + Discourse::Utils.execute_command( + 'tar', '--extract', '--gzip', '--file', @archive_path, '--directory', @tmp_directory, + failure_message: "Failed to decompress archive." + ) end def extract_db_dump From 72f139191e9b3aeebeca31ffa8b75977afe5d816 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Wed, 20 May 2020 10:40:38 +1000 Subject: [PATCH 25/80] FIX: S3 store has_been_uploaded? was not taking into account s3 bucket path (#9810) In some cases, between Discourse forums the hostname of a URL could match if they are hosting S3 files on the same bucket but the S3 bucket path might not. So e.g. https://testbucket.somesite.com/testpath/some/file/url.png vs https://testbucket.somesite.com/prodpath/some/file/url.png. So has_been_uploaded? was returning true for the second URL, even though it may have been uploaded on a different Discourse forum. This is a very rare case but must be accounted for, because this impacts UrlHelper.is_local which mistakenly thinks the file has already been downloaded and thus allows the URL to be cooked, where we want to return the full URL to be downloaded using PullHotlinkedImages. --- lib/file_store/s3_store.rb | 22 ++++++++++- spec/components/file_store/s3_store_spec.rb | 8 +++- spec/multisite/s3_store_spec.rb | 43 +++++++++++++++++++++ 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/lib/file_store/s3_store.rb b/lib/file_store/s3_store.rb index 6a26ebd7ee6..46dece4cfcd 100644 --- a/lib/file_store/s3_store.rb +++ b/lib/file_store/s3_store.rb @@ -79,12 +79,30 @@ module FileStore def has_been_uploaded?(url) return false if url.blank? + parsed_url = URI.parse(url) base_hostname = URI.parse(absolute_base_url).hostname - return true if url[base_hostname] + if url[base_hostname] + # if the hostnames match it means the upload is in the same + # bucket on s3. however, the bucket folder path may differ in + # some cases, and we do not want to assume the url is uploaded + # here. e.g. the path of the current site could be /prod and the + # other site could be /staging + if s3_bucket_folder_path.present? + return parsed_url.path.starts_with?("/#{s3_bucket_folder_path}") + else + return true + end + return false + end return false if SiteSetting.Upload.s3_cdn_url.blank? cdn_hostname = URI.parse(SiteSetting.Upload.s3_cdn_url || "").hostname - cdn_hostname.presence && url[cdn_hostname] + return true if cdn_hostname.presence && url[cdn_hostname] + false + end + + def s3_bucket_folder_path + @s3_helper.s3_bucket_folder_path end def s3_bucket_name diff --git a/spec/components/file_store/s3_store_spec.rb b/spec/components/file_store/s3_store_spec.rb index 99f57c71047..81e39d0e20b 100644 --- a/spec/components/file_store/s3_store_spec.rb +++ b/spec/components/file_store/s3_store_spec.rb @@ -251,7 +251,7 @@ describe FileStore::S3Store do before do optimized_image.update!( - url: "//s3-upload-bucket.s3.dualstack.us-west-1.amazonaws.com#{image_path}" + url: "//s3-upload-bucket.s3.dualstack.us-west-1.amazonaws.com/#{image_path}" ) end @@ -272,6 +272,12 @@ describe FileStore::S3Store do SiteSetting.s3_upload_bucket = "s3-upload-bucket/discourse-uploads" end + before do + optimized_image.update!( + url: "//s3-upload-bucket.s3.dualstack.us-west-1.amazonaws.com/discourse-uploads/#{image_path}" + ) + end + it "removes the file from s3 with the right paths" do s3_helper.expects(:s3_bucket).returns(s3_bucket).at_least_once s3_object = stub diff --git a/spec/multisite/s3_store_spec.rb b/spec/multisite/s3_store_spec.rb index 922c5f433ba..064c699a12b 100644 --- a/spec/multisite/s3_store_spec.rb +++ b/spec/multisite/s3_store_spec.rb @@ -217,4 +217,47 @@ RSpec.describe 'Multisite s3 uploads', type: :multisite do end end end + + describe "#has_been_uploaded?" do + before do + SiteSetting.s3_region = 'us-west-1' + SiteSetting.s3_upload_bucket = "s3-upload-bucket/test" + SiteSetting.s3_access_key_id = "s3-access-key-id" + SiteSetting.s3_secret_access_key = "s3-secret-access-key" + SiteSetting.enable_s3_uploads = true + end + + let(:store) { FileStore::S3Store.new } + let(:client) { Aws::S3::Client.new(stub_responses: true) } + let(:resource) { Aws::S3::Resource.new(client: client) } + let(:s3_bucket) { resource.bucket(SiteSetting.s3_upload_bucket) } + let(:s3_helper) { store.s3_helper } + + it "returns false for blank urls" do + url = "" + expect(store.has_been_uploaded?(url)).to eq(false) + end + + it "returns true if the base hostname is the same for both urls" do + url = "https://s3-upload-bucket.s3.dualstack.us-west-1.amazonaws.com/test/original/2X/d/dd7964f5fd13e1103c5244ca30abe1936c0a4b88.png" + expect(store.has_been_uploaded?(url)).to eq(true) + end + + it "returns false if the base hostname is the same for both urls BUT the bucket name is different in the path" do + bucket = "someotherbucket" + url = "https://s3-upload-bucket.s3.dualstack.us-west-1.amazonaws.com/#{bucket}/original/2X/d/dd7964f5fd13e1103c5244ca30abe1936c0a4b88.png" + expect(store.has_been_uploaded?(url)).to eq(false) + end + + it "returns false if the hostnames do not match and the s3_cdn_url is blank" do + url = "https://www.someotherhostname.com/test/original/2X/d/dd7964f5fd13e1103c5244ca30abe1936c0a4b88.png" + expect(store.has_been_uploaded?(url)).to eq(false) + end + + it "returns true if the s3_cdn_url is present and matches the url hostname" do + SiteSetting.s3_cdn_url = "https://www.someotherhostname.com" + url = "https://www.someotherhostname.com/test/original/2X/d/dd7964f5fd13e1103c5244ca30abe1936c0a4b88.png" + expect(store.has_been_uploaded?(url)).to eq(true) + end + end end From e334133294b2308da7fbacc772a12b99eb6d30c2 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Wed, 20 May 2020 10:45:49 +1000 Subject: [PATCH 26/80] PERF: Remove foreign keys from bookmarks (#9837) As a general rule we do not add FKs in Discourse and instead rely on consistency checks at weekly/daily intervals --- .../20200520001619_remove_fks_from_bookmarks.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 db/post_migrate/20200520001619_remove_fks_from_bookmarks.rb diff --git a/db/post_migrate/20200520001619_remove_fks_from_bookmarks.rb b/db/post_migrate/20200520001619_remove_fks_from_bookmarks.rb new file mode 100644 index 00000000000..80fee6dab4f --- /dev/null +++ b/db/post_migrate/20200520001619_remove_fks_from_bookmarks.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class RemoveFksFromBookmarks < ActiveRecord::Migration[6.0] + def change + remove_foreign_key :bookmarks, :topics + remove_foreign_key :bookmarks, :posts + remove_foreign_key :bookmarks, :users + end +end From a93d0a8fcc3a9004c63a99b14189d7e26bc6328d Mon Sep 17 00:00:00 2001 From: Kris Date: Tue, 19 May 2020 21:11:49 -0400 Subject: [PATCH 27/80] UX: Remove bold from category badge text --- app/assets/stylesheets/common/base/_topic-list.scss | 1 - app/assets/stylesheets/common/components/badges.scss | 1 - app/assets/stylesheets/mobile/discourse.scss | 5 ----- 3 files changed, 7 deletions(-) diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index aa51fccce15..a80e54c4fda 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -53,7 +53,6 @@ color: $primary-medium; } span.badge-category { - font-weight: normal; color: $primary-medium; } a.discourse-tag { diff --git a/app/assets/stylesheets/common/components/badges.scss b/app/assets/stylesheets/common/components/badges.scss index 3881ee7b70f..20ed535931d 100644 --- a/app/assets/stylesheets/common/components/badges.scss +++ b/app/assets/stylesheets/common/components/badges.scss @@ -17,7 +17,6 @@ .badge-wrapper { font-size: $font-down-1; - font-weight: bold; white-space: nowrap; position: relative; display: inline-flex; diff --git a/app/assets/stylesheets/mobile/discourse.scss b/app/assets/stylesheets/mobile/discourse.scss index 260f8d4b13f..c9406abca6b 100644 --- a/app/assets/stylesheets/mobile/discourse.scss +++ b/app/assets/stylesheets/mobile/discourse.scss @@ -63,11 +63,6 @@ blockquote { margin-bottom: 9px; } -// categories should not be bold on mobile; they fight with the topic title too much -.badge-wrapper { - font-weight: normal; -} - .mobile-nav { margin: 0; padding: 0; From 6b92c78033a1a26eea56f0417b6811581fab7a38 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 20 May 2020 11:27:57 +1000 Subject: [PATCH 28/80] FIX: purge all associated data on user delete This commit reorganises the delete dependencies on users and make sure all are covered. We forgot some on bookmarks, security keys, anon users and so on. --- app/models/user.rb | 122 ++++++++++++++++++++++----------------------- 1 file changed, 59 insertions(+), 63 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 9d682a62bd8..5d162848ebb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -7,102 +7,95 @@ class User < ActiveRecord::Base include SecondFactorManager include HasDestroyedWebHook + DEFAULT_FEATURED_BADGE_COUNT = 3 + + # not deleted on user delete has_many :posts - has_many :notifications, dependent: :delete_all - has_many :topic_users, dependent: :delete_all + has_many :topics + has_many :uploads + has_many :category_users, dependent: :destroy has_many :tag_users, dependent: :destroy has_many :user_api_keys, dependent: :destroy - has_many :topics - has_many :bookmarks + has_many :topic_allowed_users, dependent: :destroy + has_many :user_archived_messages, dependent: :destroy + has_many :email_change_requests, dependent: :destroy + has_many :email_tokens, dependent: :destroy + has_many :invites, dependent: :destroy + has_many :topic_links, dependent: :destroy + has_many :user_uploads, dependent: :destroy + has_many :user_emails, dependent: :destroy + has_many :user_associated_accounts, dependent: :destroy + has_many :oauth2_user_infos, dependent: :destroy + has_many :user_second_factors, dependent: :destroy + has_many :user_badges, -> { for_enabled_badges }, dependent: :destroy + has_many :user_auth_tokens, dependent: :destroy + has_many :group_users, dependent: :destroy + has_many :user_warnings, dependent: :destroy + has_many :api_keys, dependent: :destroy + has_many :push_subscriptions, dependent: :destroy + has_many :acting_group_histories, dependent: :destroy, foreign_key: :acting_user_id, class_name: 'GroupHistory' + has_many :targeted_group_histories, dependent: :destroy, foreign_key: :target_user_id, class_name: 'GroupHistory' + has_many :reviewable_scores, dependent: :destroy - # dependent deleting handled via before_destroy + has_one :user_option, dependent: :destroy + has_one :user_avatar, dependent: :destroy + has_one :github_user_info, dependent: :destroy + has_one :primary_email, -> { where(primary: true) }, class_name: 'UserEmail', dependent: :destroy + has_one :user_stat, dependent: :destroy + has_one :user_profile, dependent: :destroy, inverse_of: :user + has_one :single_sign_on_record, dependent: :destroy + has_one :anonymous_user_master, class_name: 'AnonymousUser', dependent: :destroy + has_one :anonymous_user_shadow, ->(record) { where(active: true) }, foreign_key: :master_user_id, class_name: 'AnonymousUser', dependent: :destroy + + # delete all is faster but bypasses callbacks + has_many :bookmarks, dependent: :delete_all + has_many :notifications, dependent: :delete_all + has_many :topic_users, dependent: :delete_all + has_many :email_logs, dependent: :delete_all + has_many :incoming_emails, dependent: :delete_all + has_many :user_visits, dependent: :delete_all + has_many :user_auth_token_logs, dependent: :delete_all + has_many :group_requests, dependent: :delete_all + has_many :muted_user_records, class_name: 'MutedUser', dependent: :delete_all + has_many :ignored_user_records, class_name: 'IgnoredUser', dependent: :delete_all + + # dependent deleting handled via before_destroy (special cases) has_many :user_actions has_many :post_actions + has_many :post_timings + has_many :directory_items + has_many :security_keys, -> { + where(enabled: true) + }, class_name: "UserSecurityKey" - DEFAULT_FEATURED_BADGE_COUNT = 3 - - has_many :user_badges, -> { for_enabled_badges }, dependent: :destroy has_many :badges, through: :user_badges has_many :default_featured_user_badges, -> { for_enabled_badges.grouped_with_count.where("featured_rank <= ?", DEFAULT_FEATURED_BADGE_COUNT) }, class_name: "UserBadge" - has_many :email_logs, dependent: :delete_all - has_many :incoming_emails, dependent: :delete_all - has_many :post_timings - has_many :topic_allowed_users, dependent: :destroy has_many :topics_allowed, through: :topic_allowed_users, source: :topic - has_many :email_tokens, dependent: :destroy - has_many :user_visits, dependent: :destroy - has_many :invites, dependent: :destroy - has_many :topic_links, dependent: :destroy - has_many :uploads - has_many :user_warnings - has_many :user_archived_messages, dependent: :destroy - has_many :email_change_requests, dependent: :destroy - - # see before_destroy - has_many :directory_items - has_many :user_auth_tokens, dependent: :destroy - has_many :user_auth_token_logs, dependent: :destroy - - has_many :group_users, dependent: :destroy has_many :groups, through: :group_users - has_many :group_requests, dependent: :destroy has_many :secure_categories, through: :groups, source: :categories - has_many :user_uploads, dependent: :destroy - has_many :user_emails, dependent: :destroy - - has_one :primary_email, -> { where(primary: true) }, class_name: 'UserEmail', dependent: :destroy - - has_one :user_option, dependent: :destroy - has_one :user_avatar, dependent: :destroy - has_many :user_associated_accounts, dependent: :destroy - has_one :github_user_info, dependent: :destroy - has_many :oauth2_user_infos, dependent: :destroy - has_many :user_second_factors, dependent: :destroy - + # deleted in user_second_factors relationship has_many :totps, -> { where(method: UserSecondFactor.methods[:totp], enabled: true) }, class_name: "UserSecondFactor" - has_many :security_keys, -> { - where(enabled: true) - }, class_name: "UserSecurityKey" - - has_one :anonymous_user_master, class_name: 'AnonymousUser' - has_one :anonymous_user_shadow, ->(record) { where(active: true) }, foreign_key: :master_user_id, class_name: 'AnonymousUser' - has_one :master_user, through: :anonymous_user_master has_one :shadow_user, through: :anonymous_user_shadow, source: :user - has_one :user_stat, dependent: :destroy - has_one :user_profile, dependent: :destroy, inverse_of: :user has_one :profile_background_upload, through: :user_profile has_one :card_background_upload, through: :user_profile - has_one :single_sign_on_record, dependent: :destroy belongs_to :approved_by, class_name: 'User' belongs_to :primary_group, class_name: 'Group' - has_many :muted_user_records, class_name: 'MutedUser' has_many :muted_users, through: :muted_user_records - - has_many :ignored_user_records, class_name: 'IgnoredUser' has_many :ignored_users, through: :ignored_user_records - has_many :api_keys, dependent: :destroy - - has_many :push_subscriptions, dependent: :destroy - belongs_to :uploaded_avatar, class_name: 'Upload' - has_many :acting_group_histories, dependent: :destroy, foreign_key: :acting_user_id, class_name: 'GroupHistory' - has_many :targeted_group_histories, dependent: :destroy, foreign_key: :target_user_id, class_name: 'GroupHistory' - - has_many :reviewable_scores, dependent: :destroy - delegate :last_sent_email_address, to: :email_logs validates_presence_of :username @@ -164,6 +157,9 @@ class User < ActiveRecord::Base DirectoryItem.where(user_id: self.id) .where('period_type in (?)', DirectoryItem.period_types.values) .delete_all + + # our relationship filters on enabled, this makes sure everything is deleted + UserSecurityKey.where(user_id: self.id).delete_all end # Skip validating email, for example from a particular auth provider plugin @@ -933,7 +929,7 @@ class User < ActiveRecord::Base def activate if email_token = self.email_tokens.active.where(email: self.email).first - user = EmailToken.confirm(email_token.token, skip_reviewable: true) + EmailToken.confirm(email_token.token, skip_reviewable: true) end self.update!(active: true) create_reviewable From 234cd5c3e7f8d1be7c98af7eeb572e5b79f0a16a Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 20 May 2020 10:16:28 +0800 Subject: [PATCH 29/80] FIX: Switch discobot to pull avatar from gravatar. --- app/models/user_avatar.rb | 12 ++++++++++-- .../db/fixtures/001_discobot.rb | 14 +++++++------- ...st_gravatar_download_attempt_on_user_avatars.rb | 12 ++++++++++++ plugins/discourse-narrative-bot/plugin.rb | 6 ++++++ 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb diff --git a/app/models/user_avatar.rb b/app/models/user_avatar.rb index f6dbf133126..bd2751d6b45 100644 --- a/app/models/user_avatar.rb +++ b/app/models/user_avatar.rb @@ -5,6 +5,14 @@ class UserAvatar < ActiveRecord::Base belongs_to :gravatar_upload, class_name: 'Upload' belongs_to :custom_upload, class_name: 'Upload' + @@custom_user_gravatar_email_hash = { + Discourse::SYSTEM_USER_ID => User.email_hash("info@discourse.org") + } + + def self.register_custom_user_gravatar_email_hash(user_id, email) + @@custom_user_gravatar_email_hash[user_id] = User.email_hash(email) + end + def contains_upload?(id) gravatar_upload_id == id || custom_upload_id == id end @@ -12,14 +20,14 @@ class UserAvatar < ActiveRecord::Base def update_gravatar! DistributedMutex.synchronize("update_gravatar_#{user_id}") do begin - self.update!(last_gravatar_download_attempt: Time.now) + self.update!(last_gravatar_download_attempt: Time.zone.now) max = Discourse.avatar_sizes.max # The user could be deleted before this executes return if user.blank? || user.primary_email.blank? - email_hash = user_id == Discourse::SYSTEM_USER_ID ? User.email_hash("info@discourse.org") : user.email_hash + email_hash = @@custom_user_gravatar_email_hash[user_id] || user.email_hash gravatar_url = "https://#{SiteSetting.gravatar_base_url}/avatar/#{email_hash}.png?s=#{max}&d=404&reset_cache=#{SecureRandom.urlsafe_base64(5)}" # follow redirects in case gravatar change rules on us diff --git a/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb b/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb index 3972a350fbf..bc204e4021b 100644 --- a/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb +++ b/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb @@ -4,20 +4,20 @@ discobot_username = 'discobot' def seed_primary_email UserEmail.seed do |ue| - ue.id = -2 + ue.id = DiscourseNarrativeBot::BOT_USER_ID ue.email = "discobot_email" ue.primary = true - ue.user_id = -2 + ue.user_id = DiscourseNarrativeBot::BOT_USER_ID end end -unless user = User.find_by(id: -2) +unless user = User.find_by(id: DiscourseNarrativeBot::BOT_USER_ID) suggested_username = UserNameSuggester.suggest(discobot_username) seed_primary_email User.seed do |u| - u.id = -2 + u.id = DiscourseNarrativeBot::BOT_USER_ID u.name = discobot_username u.username = suggested_username u.username_lower = suggested_username.downcase @@ -32,7 +32,7 @@ unless user = User.find_by(id: -2) begin UserAvatar.import_url_for_user( "https://cdn.discourse.org/dev/uploads/default/original/2X/e/edb63d57a720838a7ce6a68f02ba4618787f2299.png", - User.find(-2), + User.find(DiscourseNarrativeBot::BOT_USER_ID), override_gravatar: true ) rescue @@ -41,7 +41,7 @@ unless user = User.find_by(id: -2) end end -bot = User.find(-2) +bot = User.find(DiscourseNarrativeBot::BOT_USER_ID) # ensure discobot has a primary email unless bot.primary_email @@ -62,4 +62,4 @@ if !bot.user_profile.bio_raw ) end -Group.user_trust_level_change!(-2, TrustLevel[4]) +Group.user_trust_level_change!(DiscourseNarrativeBot::BOT_USER_ID, TrustLevel[4]) diff --git a/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb b/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb new file mode 100644 index 00000000000..5f80851d7ec --- /dev/null +++ b/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb @@ -0,0 +1,12 @@ +class ClearLastGravatarDownloadAttemptOnUserAvatars < ActiveRecord::Migration[6.0] + def up + execute <<~SQL + UPDATE user_avatars + SET last_gravatar_download_attempt = null + WHERE user_id = -2 AND custom_upload_id IS NULL AND gravatar_upload_id IS NULL + SQL + end + + def down + end +end diff --git a/plugins/discourse-narrative-bot/plugin.rb b/plugins/discourse-narrative-bot/plugin.rb index a6be5dd056f..61047c0e8b2 100644 --- a/plugins/discourse-narrative-bot/plugin.rb +++ b/plugins/discourse-narrative-bot/plugin.rb @@ -55,6 +55,7 @@ after_initialize do module ::DiscourseNarrativeBot PLUGIN_NAME = "discourse-narrative-bot".freeze + BOT_USER_ID = -2 class Engine < ::Rails::Engine engine_name PLUGIN_NAME @@ -271,4 +272,9 @@ after_initialize do end end end + + UserAvatar.register_custom_user_gravatar_email_hash( + DiscourseNarrativeBot::BOT_USER_ID, + "discobot@discourse.org" + ) end From b7387d4611b0b3416daf48ba1e4ca82e1d83ecaa Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 20 May 2020 10:22:51 +0800 Subject: [PATCH 30/80] DEV: Remove code unused code when seeding narrative bot. --- .../db/fixtures/001_discobot.rb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb b/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb index bc204e4021b..fda50b48299 100644 --- a/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb +++ b/plugins/discourse-narrative-bot/db/fixtures/001_discobot.rb @@ -26,19 +26,6 @@ unless user = User.find_by(id: DiscourseNarrativeBot::BOT_USER_ID) u.approved = true u.trust_level = TrustLevel[4] end - - # TODO Pull the user avatar from that thread for now. In the future, pull it from a local file or from some central discobot repo. - if !Rails.env.test? - begin - UserAvatar.import_url_for_user( - "https://cdn.discourse.org/dev/uploads/default/original/2X/e/edb63d57a720838a7ce6a68f02ba4618787f2299.png", - User.find(DiscourseNarrativeBot::BOT_USER_ID), - override_gravatar: true - ) - rescue - # In case the avatar can't be downloaded, don't fail seed - end - end end bot = User.find(DiscourseNarrativeBot::BOT_USER_ID) From 37983a78150315b7b8cf2818f8cedbc0c78a689d Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 20 May 2020 10:33:34 +0800 Subject: [PATCH 31/80] Fix lint. --- ...5508_clear_last_gravatar_download_attempt_on_user_avatars.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb b/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb index 5f80851d7ec..d7f30797b57 100644 --- a/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb +++ b/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClearLastGravatarDownloadAttemptOnUserAvatars < ActiveRecord::Migration[6.0] def up execute <<~SQL From 05f7d5a2def9590ccba5e2894942d119442cd741 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 20 May 2020 14:12:58 +1000 Subject: [PATCH 32/80] UX: Rename "Edit Message" to "Edit" This reduces the space taken by the button. --- config/locales/client.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 9746f37f376..a647dc5cde1 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -2100,7 +2100,7 @@ en: help: "Move message back to Inbox" edit_message: help: "Edit first post of the message" - title: "Edit Message" + title: "Edit" defer: help: "Mark as unread" title: "Defer" From b031e3220ae5504ab265999270f109b2b8b973df Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 20 May 2020 15:28:01 +1000 Subject: [PATCH 33/80] FIX: migrations should not fail when db is part migrated When part migrated the translate overrides may have missing columns in that case just silently ignore overrides --- lib/freedom_patches/translate_accelerator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/freedom_patches/translate_accelerator.rb b/lib/freedom_patches/translate_accelerator.rb index ee724d56d12..5a82623f8f7 100644 --- a/lib/freedom_patches/translate_accelerator.rb +++ b/lib/freedom_patches/translate_accelerator.rb @@ -164,7 +164,7 @@ module I18n by_site[locale].with_indifferent_access rescue ActiveRecord::StatementInvalid => e - if PG::UndefinedTable === e.cause + if PG::UndefinedTable === e.cause || PG::UndefinedColumn === e.cause {} else raise From e97cb20c2a5601d5ca7e6e9f23c2d7138539b2d8 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 20 May 2020 16:46:49 +1000 Subject: [PATCH 34/80] UX: strip text from PM bookmark and share buttons Also organize priorities in an easier to reason about way and shift bookmark topic so it is after link. (consistent with posts) --- .../app/initializers/topic-footer-buttons.js | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js b/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js index a13ccd2219f..e00c947310e 100644 --- a/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js +++ b/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js @@ -3,6 +3,13 @@ import showModal from "discourse/lib/show-modal"; import { registerTopicFooterButton } from "discourse/lib/register-topic-footer-button"; import { formattedReminderTime } from "discourse/lib/bookmark"; +const SHARE_PRIORITY = 1000; +const BOOKMARK_PRIORITY = 900; +const ARCHIVE_PRIORITY = 800; +const FLAG_PRIORITY = 700; +const EDIT_MESSAGE_PRIORITY = 600; +const DEFER_PRIORITY = 500; + export default { name: "topic-footer-buttons", @@ -11,8 +18,12 @@ export default { registerTopicFooterButton({ id: "share-and-invite", icon: "link", - priority: 999, - label: "topic.share.title", + priority: SHARE_PRIORITY, + label() { + if (!this.get("topic.isPrivateMessage") || this.site.mobileView) { + return "topic.share.title"; + } + }, title: "topic.share.help", action() { const panels = [ @@ -67,7 +78,7 @@ export default { registerTopicFooterButton({ id: "flag", icon: "flag", - priority: 998, + priority: FLAG_PRIORITY, label: "topic.flag_topic.title", title: "topic.flag_topic.help", action: "showFlagTopic", @@ -93,14 +104,16 @@ export default { } return "bookmark"; }, - priority: 1000, + priority: BOOKMARK_PRIORITY, classNames() { const bookmarked = this.get("topic.bookmarked"); return bookmarked ? ["bookmark", "bookmarked"] : ["bookmark"]; }, label() { - const bookmarked = this.get("topic.bookmarked"); - return bookmarked ? "bookmarked.clear_bookmarks" : "bookmarked.title"; + if (!this.get("topic.isPrivateMessage") || this.site.mobileView) { + const bookmarked = this.get("topic.bookmarked"); + return bookmarked ? "bookmarked.clear_bookmarks" : "bookmarked.title"; + } }, translatedTitle() { const bookmarked = this.get("topic.bookmarked"); @@ -126,7 +139,7 @@ export default { registerTopicFooterButton({ id: "archive", - priority: 996, + priority: ARCHIVE_PRIORITY, icon() { return this.archiveIcon; }, @@ -155,7 +168,7 @@ export default { registerTopicFooterButton({ id: "edit-message", - priority: 750, + priority: EDIT_MESSAGE_PRIORITY, icon: "pencil-alt", label: "topic.edit_message.title", title: "topic.edit_message.help", @@ -170,7 +183,7 @@ export default { registerTopicFooterButton({ id: "defer", icon: "circle", - priority: 300, + priority: DEFER_PRIORITY, label: "topic.defer.title", title: "topic.defer.help", action: "deferTopic", From 30bbc485d02edf7e37b73fc5fdd988365bc90617 Mon Sep 17 00:00:00 2001 From: Sam Saffron Date: Wed, 20 May 2020 16:53:48 +1000 Subject: [PATCH 35/80] DEV: remove superfluous comment --- Gemfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Gemfile b/Gemfile index 6c72e48bab4..949b45404ca 100644 --- a/Gemfile +++ b/Gemfile @@ -127,10 +127,6 @@ gem 'mini_racer' # TODO: determine why highline is being held back and upgrade to latest gem 'highline', '~> 1.7.0', require: false -# TODO: Upgrading breaks Sidekiq Web -# This is a bit of a hornets nest cause in an ideal world we much prefer -# if Sidekiq reused session and CSRF mitigation with Discourse on the -# _forum_session cookie instead of a rack.session cookie gem 'rack', '2.2.2' gem 'rack-protection' # security From f7f436e536ba0df963d2f7257a4a700bdfc96bbc Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 20 May 2020 15:40:00 +0800 Subject: [PATCH 36/80] DEV: Install `rails_failover` gem to test our Redis changes. --- Gemfile | 2 ++ Gemfile.lock | 3 +++ app/models/global_setting.rb | 24 ++++++++++++++++++------ config/initializers/001-redis.rb | 17 +++++++++++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index 949b45404ca..a80f23dbc0f 100644 --- a/Gemfile +++ b/Gemfile @@ -248,3 +248,5 @@ end gem 'webpush', require: false gem 'colored2', require: false gem 'maxminddb' + +gem 'rails_failover', require: false diff --git a/Gemfile.lock b/Gemfile.lock index f2c187b9b81..29f2fee8997 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -277,6 +277,8 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) + rails_failover (0.1.0) + redis (~> 4) rails_multisite (2.1.2) activerecord (> 5.0, < 7) railties (> 5.0, < 7) @@ -509,6 +511,7 @@ DEPENDENCIES rack (= 2.2.2) rack-mini-profiler rack-protection + rails_failover rails_multisite railties (= 6.0.3) rake diff --git a/app/models/global_setting.rb b/app/models/global_setting.rb index f4425919ed3..21e5a137dcf 100644 --- a/app/models/global_setting.rb +++ b/app/models/global_setting.rb @@ -164,9 +164,15 @@ class GlobalSetting c[:port] = redis_port if redis_port if redis_slave_host && redis_slave_port - c[:slave_host] = redis_slave_host - c[:slave_port] = redis_slave_port - c[:connector] = DiscourseRedis::Connector + if ENV["RAILS_FAILOVER"] + c[:replica_host] = redis_slave_host + c[:replica_port] = redis_slave_port + c[:connector] = RailsFailover::Redis::Connector + else + c[:slave_host] = redis_slave_host + c[:slave_port] = redis_slave_port + c[:connector] = DiscourseRedis::Connector + end end c[:password] = redis_password if redis_password.present? @@ -188,9 +194,15 @@ class GlobalSetting c[:port] = message_bus_redis_port if message_bus_redis_port if message_bus_redis_slave_host && message_bus_redis_slave_port - c[:slave_host] = message_bus_redis_slave_host - c[:slave_port] = message_bus_redis_slave_port - c[:connector] = DiscourseRedis::Connector + if ENV["RAILS_FAILOVER"] + c[:replica_host] = message_bus_redis_slave_host + c[:replica_port] = message_bus_redis_slave_port + c[:connector] = RailsFailover::Redis::Connector + else + c[:slave_host] = message_bus_redis_slave_host + c[:slave_port] = message_bus_redis_slave_port + c[:connector] = DiscourseRedis::Connector + end end c[:password] = message_bus_redis_password if message_bus_redis_password.present? diff --git a/config/initializers/001-redis.rb b/config/initializers/001-redis.rb index d11303a9d59..14ce997b8f9 100644 --- a/config/initializers/001-redis.rb +++ b/config/initializers/001-redis.rb @@ -4,3 +4,20 @@ if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS'] puts "Flushing redis (development mode)" Discourse.redis.flushdb end + +if ENV['RAILS_FAILOVER'] + require 'rails_failover' + + message_bus_keepalive_interval = MessageBus.keepalive_interval + + RailsFailover::Redis.register_master_up_callback do + MessageBus.keepalive_interval = message_bus_keepalive_interval + Discourse.clear_readonly! + Discourse.request_refresh! + end + + RailsFailover::Redis.register_master_down_callback do + # Disables MessageBus keepalive when Redis is in readonly mode + MessageBus.keepalive_interval = 0 + end +end From 2f03a879f96f258542ef7d002f6ad4ca0e55767c Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 20 May 2020 16:06:40 +0800 Subject: [PATCH 37/80] DEV: Require `rails_failover` before global settings. --- config/application.rb | 4 ++++ config/initializers/001-redis.rb | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/application.rb b/config/application.rb index 43a8bf3091d..ba4486320c4 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,6 +27,10 @@ require_relative '../lib/discourse_plugin_registry' require_relative '../lib/plugin_gem' +if ENV['RAILS_FAILOVER'] + require 'rails_failover' +end + # Global config require_relative '../app/models/global_setting' GlobalSetting.configure! diff --git a/config/initializers/001-redis.rb b/config/initializers/001-redis.rb index 14ce997b8f9..f28c59a3b1d 100644 --- a/config/initializers/001-redis.rb +++ b/config/initializers/001-redis.rb @@ -6,8 +6,6 @@ if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS'] end if ENV['RAILS_FAILOVER'] - require 'rails_failover' - message_bus_keepalive_interval = MessageBus.keepalive_interval RailsFailover::Redis.register_master_up_callback do From 3aecc1990b8e8ffea8da50fb48d3e76610306098 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Wed, 20 May 2020 16:17:59 +0800 Subject: [PATCH 38/80] DEV: Review follow up to 234cd5c3e7f8d1be7c98af7eeb572e5b79f0a16a. --- ...15508_clear_last_gravatar_download_attempt_on_user_avatars.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb b/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb index d7f30797b57..c9029730814 100644 --- a/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb +++ b/plugins/discourse-narrative-bot/db/post_migrate/20200520015508_clear_last_gravatar_download_attempt_on_user_avatars.rb @@ -10,5 +10,6 @@ class ClearLastGravatarDownloadAttemptOnUserAvatars < ActiveRecord::Migration[6. end def down + raise ActiveRecord::IrreversibleMigration end end From fb15da43da1a4f8f733812dc4af455f27e756418 Mon Sep 17 00:00:00 2001 From: Bianca Nenciu Date: Wed, 20 May 2020 12:07:48 +0300 Subject: [PATCH 39/80] Remove old web hooks in favor of 'reviewable' web hook (#9776) * FIX: Emit web hooks for flags * FEATURE: Remove 'flag' web hook in favor of 'reviewable' web hook * FEATURE: Remove 'queued post' web hook in favor of 'reviewable' web hook * FIX: Do not set a default value for web hooks with no events --- .../admin/routes/admin-web-hooks-show.js | 3 +-- app/models/web_hook_event_type.rb | 2 -- config/locales/client.en.yml | 6 ------ db/fixtures/007_web_hook_event_types.rb | 10 --------- .../20200514075356_remove_flag_web_hooks.rb | 21 +++++++++++++++++++ ...0514075407_remove_queued_post_web_hooks.rb | 21 +++++++++++++++++++ spec/fabricators/web_hook_fabricator.rb | 16 -------------- 7 files changed, 43 insertions(+), 36 deletions(-) create mode 100644 db/migrate/20200514075356_remove_flag_web_hooks.rb create mode 100644 db/migrate/20200514075407_remove_queued_post_web_hooks.rb diff --git a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js index 34aed775cc5..f0860e79f71 100644 --- a/app/assets/javascripts/admin/routes/admin-web-hooks-show.js +++ b/app/assets/javascripts/admin/routes/admin-web-hooks-show.js @@ -1,5 +1,4 @@ import { get } from "@ember/object"; -import { isEmpty } from "@ember/utils"; import DiscourseRoute from "discourse/routes/discourse"; export default DiscourseRoute.extend({ @@ -15,7 +14,7 @@ export default DiscourseRoute.extend({ }, setupController(controller, model) { - if (model.get("isNew") || isEmpty(model.get("web_hook_event_types"))) { + if (model.get("isNew")) { model.set("web_hook_event_types", controller.get("defaultEventTypes")); } diff --git a/app/models/web_hook_event_type.rb b/app/models/web_hook_event_type.rb index 952c1c2062c..442f14cb8ce 100644 --- a/app/models/web_hook_event_type.rb +++ b/app/models/web_hook_event_type.rb @@ -7,8 +7,6 @@ class WebHookEventType < ActiveRecord::Base GROUP = 4 CATEGORY = 5 TAG = 6 - FLAG = 7 - QUEUED_POST = 8 REVIEWABLE = 9 NOTIFICATION = 10 SOLVED = 11 diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index a647dc5cde1..0da7d673427 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3598,12 +3598,6 @@ en: tag_event: name: "Tag Event" details: "When a tag is created, updated or destroyed." - flag_event: - name: "Flag Event" - details: "When a flag is created, agreed, disagreed or ignored." - queued_post_event: - name: "Post Approval Event" - details: "When a new queued post is created, approved or rejected." reviewable_event: name: "Reviewable Event" details: "When a new item is ready for review and when its status is updated." diff --git a/db/fixtures/007_web_hook_event_types.rb b/db/fixtures/007_web_hook_event_types.rb index 8bf8e938055..ec666ec5ad2 100644 --- a/db/fixtures/007_web_hook_event_types.rb +++ b/db/fixtures/007_web_hook_event_types.rb @@ -30,16 +30,6 @@ WebHookEventType.seed do |b| b.name = "tag" end -WebHookEventType.seed do |b| - b.id = WebHookEventType::FLAG - b.name = "flag" -end - -WebHookEventType.seed do |b| - b.id = WebHookEventType::QUEUED_POST - b.name = "queued_post" -end - WebHookEventType.seed do |b| b.id = WebHookEventType::REVIEWABLE b.name = "reviewable" diff --git a/db/migrate/20200514075356_remove_flag_web_hooks.rb b/db/migrate/20200514075356_remove_flag_web_hooks.rb new file mode 100644 index 00000000000..448b7fb771b --- /dev/null +++ b/db/migrate/20200514075356_remove_flag_web_hooks.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class RemoveFlagWebHooks < ActiveRecord::Migration[6.0] + def up + flag_event_type_id = 7 + + DB.exec <<~SQL + DELETE FROM web_hook_event_types_hooks + WHERE web_hook_event_type_id = #{flag_event_type_id} + SQL + + DB.exec <<~SQL + DELETE FROM web_hook_event_types + WHERE id = #{flag_event_type_id} + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20200514075407_remove_queued_post_web_hooks.rb b/db/migrate/20200514075407_remove_queued_post_web_hooks.rb new file mode 100644 index 00000000000..632e5013dc9 --- /dev/null +++ b/db/migrate/20200514075407_remove_queued_post_web_hooks.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class RemoveQueuedPostWebHooks < ActiveRecord::Migration[6.0] + def up + queued_post_event_type_id = 8 + + DB.exec <<~SQL + DELETE FROM web_hook_event_types_hooks + WHERE web_hook_event_type_id = #{queued_post_event_type_id} + SQL + + DB.exec <<~SQL + DELETE FROM web_hook_event_types + WHERE id = #{queued_post_event_type_id} + SQL + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/spec/fabricators/web_hook_fabricator.rb b/spec/fabricators/web_hook_fabricator.rb index 46472510808..9edc591791f 100644 --- a/spec/fabricators/web_hook_fabricator.rb +++ b/spec/fabricators/web_hook_fabricator.rb @@ -71,22 +71,6 @@ Fabricator(:tag_web_hook, from: :web_hook) do end end -Fabricator(:flag_web_hook, from: :web_hook) do - transient flag_hook: WebHookEventType.find_by(name: 'flag') - - after_build do |web_hook, transients| - web_hook.web_hook_event_types = [transients[:flag_hook]] - end -end - -Fabricator(:queued_post_web_hook, from: :web_hook) do - transient queued_post_hook: WebHookEventType.find_by(name: 'queued_post') - - after_build do |web_hook, transients| - web_hook.web_hook_event_types = [transients[:queued_post_hook]] - end -end - Fabricator(:reviewable_web_hook, from: :web_hook) do transient reviewable_hook: WebHookEventType.find_by(name: 'reviewable') From 02f44def5693ff3ab88259f65453ed9b4b7f5711 Mon Sep 17 00:00:00 2001 From: Osama Sayegh Date: Wed, 20 May 2020 12:46:27 +0300 Subject: [PATCH 40/80] FIX: Don't blow up when trying to parse invalid or non-ASCII URLs (#9838) * FIX: Don't blow up when trying to parseinvalid or non-ASCII URLs Follow-up to https://github.com/discourse/discourse/commit/72f139191e9b3aeebeca31ffa8b75977afe5d816 --- lib/file_store/s3_store.rb | 7 ++++++- spec/components/file_store/s3_store_spec.rb | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/file_store/s3_store.rb b/lib/file_store/s3_store.rb index 46dece4cfcd..f42fa73057b 100644 --- a/lib/file_store/s3_store.rb +++ b/lib/file_store/s3_store.rb @@ -79,7 +79,12 @@ module FileStore def has_been_uploaded?(url) return false if url.blank? - parsed_url = URI.parse(url) + begin + parsed_url = URI.parse(URI.encode(url)) + rescue URI::InvalidURIError + return false + end + base_hostname = URI.parse(absolute_base_url).hostname if url[base_hostname] # if the hostnames match it means the upload is in the same diff --git a/spec/components/file_store/s3_store_spec.rb b/spec/components/file_store/s3_store_spec.rb index 81e39d0e20b..15c36b05be6 100644 --- a/spec/components/file_store/s3_store_spec.rb +++ b/spec/components/file_store/s3_store_spec.rb @@ -304,6 +304,15 @@ describe FileStore::S3Store do describe ".has_been_uploaded?" do + it "doesn't crash for invalid URLs" do + expect(store.has_been_uploaded?("https://site.discourse.com/#bad#6")).to eq(false) + end + + it "doesn't crash if URL contains non-ascii characters" do + expect(store.has_been_uploaded?("//s3-upload-bucket.s3.dualstack.us-east-1.amazonaws.com/æ¼¢1337.png")).to eq(true) + expect(store.has_been_uploaded?("//s3-upload-bucket.s3.amazonaws.com/æ¼¢1337.png")).to eq(false) + end + it "identifies S3 uploads" do expect(store.has_been_uploaded?("//s3-upload-bucket.s3.dualstack.us-east-1.amazonaws.com/1337.png")).to eq(true) end From 30631a963ff6c619395b771ec3e97ea6e20a49c2 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Wed, 20 May 2020 14:07:00 +0200 Subject: [PATCH 41/80] UX: moves editFirstPost in taggable Pms in dropdown on mobile (#9840) --- .../discourse/app/initializers/topic-footer-buttons.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js b/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js index e00c947310e..a2de76d3e9d 100644 --- a/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js +++ b/app/assets/javascripts/discourse/app/initializers/topic-footer-buttons.js @@ -175,6 +175,9 @@ export default { action: "editFirstPost", classNames: ["edit-message"], dependentKeys: ["editFirstPost", "showEditOnFooter"], + dropdown() { + return this.site.mobileView && this.get("topic.isPrivateMessage"); + }, displayed() { return this.showEditOnFooter; } From 4a533ec594c1b2fb54a3d9125a24f1ac4d8fc254 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Wed, 20 May 2020 19:22:20 +0530 Subject: [PATCH 42/80] FIX: do not parameterize tag_id (#9839) Parameterizing tag_id was breaking tags with non-ascii characters or emoji. Bug report: https://meta.discourse.org/t/unable-to-see-pm-lists-for-non-ascii-tag/151723/4 --- lib/topic_query_params.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/topic_query_params.rb b/lib/topic_query_params.rb index e1bb23cb9f7..bab30135a17 100644 --- a/lib/topic_query_params.rb +++ b/lib/topic_query_params.rb @@ -3,7 +3,7 @@ module TopicQueryParams def build_topic_list_options options = {} - params[:tags] = [params[:tag_id].parameterize] if params[:tag_id].present? && guardian.can_tag_pms? + params[:tags] = [params[:tag_id]] if params[:tag_id].present? && guardian.can_tag_pms? TopicQuery.public_valid_options.each do |key| if params.key?(key) From cfff8b1f27f9d709179452d67cd99430bffb1a91 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 20 May 2020 10:37:43 -0400 Subject: [PATCH 43/80] Build(deps): Bump puma from 4.3.4 to 4.3.5 (#9836) Bumps [puma](https://github.com/puma/puma) from 4.3.4 to 4.3.5. - [Release notes](https://github.com/puma/puma/releases) - [Changelog](https://github.com/puma/puma/blob/master/History.md) - [Commits](https://github.com/puma/puma/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 29f2fee8997..9709a203c63 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -262,7 +262,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (4.0.5) - puma (4.3.4) + puma (4.3.5) nio4r (~> 2.0) r2 (0.2.7) rack (2.2.2) From bd57ae83f1a4b1dea92ae9234013e2ebd41df6b6 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Wed, 20 May 2020 10:26:20 -0500 Subject: [PATCH 44/80] DEV: Guardian for hiding about stats (#9841) --- .../discourse/app/templates/about.hbs | 88 ++++++++++--------- app/controllers/about_controller.rb | 2 +- app/serializers/about_serializer.rb | 11 ++- lib/guardian.rb | 4 + test/javascripts/fixtures/about.js | 1 + 5 files changed, 61 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/discourse/app/templates/about.hbs b/app/assets/javascripts/discourse/app/templates/about.hbs index 63cae2c2609..2659b0ebac4 100644 --- a/app/assets/javascripts/discourse/app/templates/about.hbs +++ b/app/assets/javascripts/discourse/app/templates/about.hbs @@ -64,50 +64,52 @@ {{/each}} {{/if}} -
-

{{d-icon "far-chart-bar"}} {{i18n "about.stats"}}

+ {{#if model.can_see_about_stats}} +
+

{{d-icon "far-chart-bar"}} {{i18n "about.stats"}}

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 {{i18n "about.stat.last_7_days"}}{{i18n "about.stat.last_30_days"}}{{i18n "about.stat.all_time"}}
{{i18n "about.topic_count"}}{{number model.stats.topics_7_days}}{{number model.stats.topics_30_days}}{{number model.stats.topic_count}}
{{i18n "about.post_count"}}{{number model.stats.posts_7_days}}{{number model.stats.posts_30_days}}{{number model.stats.post_count}}
{{i18n "about.user_count"}}{{number model.stats.users_7_days}}{{number model.stats.users_30_days}}{{number model.stats.user_count}}
{{i18n "about.active_user_count"}}{{number model.stats.active_users_7_days}}{{number model.stats.active_users_30_days}}
{{i18n "about.like_count"}}{{number model.stats.likes_7_days}}{{number model.stats.likes_30_days}}{{number model.stats.like_count}}
-
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 {{i18n "about.stat.last_7_days"}}{{i18n "about.stat.last_30_days"}}{{i18n "about.stat.all_time"}}
{{i18n "about.topic_count"}}{{number model.stats.topics_7_days}}{{number model.stats.topics_30_days}}{{number model.stats.topic_count}}
{{i18n "about.post_count"}}{{number model.stats.posts_7_days}}{{number model.stats.posts_30_days}}{{number model.stats.post_count}}
{{i18n "about.user_count"}}{{number model.stats.users_7_days}}{{number model.stats.users_30_days}}{{number model.stats.user_count}}
{{i18n "about.active_user_count"}}{{number model.stats.active_users_7_days}}{{number model.stats.active_users_30_days}}
{{i18n "about.like_count"}}{{number model.stats.likes_7_days}}{{number model.stats.likes_30_days}}{{number model.stats.like_count}}
+
+ {{/if}} {{#if contactInfo}}
diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb index fe2d3a2327d..3f3f9e15a36 100644 --- a/app/controllers/about_controller.rb +++ b/app/controllers/about_controller.rb @@ -16,7 +16,7 @@ class AboutController < ApplicationController render :index end format.json do - render_serialized(@about, AboutSerializer) + render_json_dump(AboutSerializer.new(@about, scope: guardian)) end end end diff --git a/app/serializers/about_serializer.rb b/app/serializers/about_serializer.rb index 308f990fd6c..8230c590a4c 100644 --- a/app/serializers/about_serializer.rb +++ b/app/serializers/about_serializer.rb @@ -21,7 +21,16 @@ class AboutSerializer < ApplicationSerializer :title, :locale, :version, - :https + :https, + :can_see_about_stats + + def can_see_about_stats + scope.can_see_about_stats? + end + + def include_stats? + can_see_about_stats + end def stats object.class.fetch_cached_stats || Jobs::AboutStats.new.execute({}) diff --git a/lib/guardian.rb b/lib/guardian.rb index 00d496e46eb..456461fead6 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -493,6 +493,10 @@ class Guardian is_staff? end + def can_see_about_stats? + true + end + def auth_token if cookie = request&.cookies[Auth::DefaultCurrentUserProvider::TOKEN_COOKIE] UserAuthToken.hash_token(cookie) diff --git a/test/javascripts/fixtures/about.js b/test/javascripts/fixtures/about.js index 7f9f17cbba5..4c7de6a87a3 100644 --- a/test/javascripts/fixtures/about.js +++ b/test/javascripts/fixtures/about.js @@ -1,6 +1,7 @@ export default { "about.json": { about: { + can_see_about_stats: true, stats: { topic_count: 27480, post_count: 490358, From 6c9c8dfefdc2682b848c4a34ce1a8b7e386c3756 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 20 May 2020 11:31:11 -0400 Subject: [PATCH 45/80] FIX: `guidFor` is not part of `Ember.Object` --- app/assets/javascripts/discourse-loader.js | 1 - .../javascripts/discourse/app/initializers/copy-codeblocks.js | 3 ++- app/assets/javascripts/select-kit/app/components/select-kit.js | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/discourse-loader.js b/app/assets/javascripts/discourse-loader.js index d11217a985a..fc829ae12f0 100644 --- a/app/assets/javascripts/discourse-loader.js +++ b/app/assets/javascripts/discourse-loader.js @@ -36,7 +36,6 @@ var define, requirejs; default: Ember.Object, get: Ember.get, getProperties: Ember.getProperties, - guidFor: Ember.guidFor, set: Ember.set, setProperties: Ember.setProperties, computed: Ember.computed, diff --git a/app/assets/javascripts/discourse/app/initializers/copy-codeblocks.js b/app/assets/javascripts/discourse/app/initializers/copy-codeblocks.js index a0b0d509621..f6fcef5e17e 100644 --- a/app/assets/javascripts/discourse/app/initializers/copy-codeblocks.js +++ b/app/assets/javascripts/discourse/app/initializers/copy-codeblocks.js @@ -3,6 +3,7 @@ import { cancel, later } from "@ember/runloop"; import { Promise } from "rsvp"; import { iconHTML } from "discourse-common/lib/icon-library"; import I18n from "I18n"; +import { guidFor } from "@ember/object/internals"; // http://github.com/feross/clipboard-copy function clipboardCopy(text) { @@ -90,7 +91,7 @@ export default { const state = button.innerHTML; button.innerHTML = I18n.t("copy_codeblock.copied"); - const commandId = Ember.guidFor(button); + const commandId = guidFor(button); if (_fadeCopyCodeblocksRunners[commandId]) { cancel(_fadeCopyCodeblocksRunners[commandId]); diff --git a/app/assets/javascripts/select-kit/app/components/select-kit.js b/app/assets/javascripts/select-kit/app/components/select-kit.js index 140e96782d6..02acfb5a2e1 100644 --- a/app/assets/javascripts/select-kit/app/components/select-kit.js +++ b/app/assets/javascripts/select-kit/app/components/select-kit.js @@ -1,5 +1,6 @@ import I18n from "I18n"; -import EmberObject, { computed, get, guidFor } from "@ember/object"; +import EmberObject, { computed, get } from "@ember/object"; +import { guidFor } from "@ember/object/internals"; import Component from "@ember/component"; import deprecated from "discourse-common/lib/deprecated"; import { makeArray } from "discourse-common/lib/helpers"; From 8e7efb48ae0d43a4c3a32d75f65da6512c568da0 Mon Sep 17 00:00:00 2001 From: Jordan Vidrine <30537603+jordanvidrine@users.noreply.github.com> Date: Wed, 20 May 2020 10:39:04 -0500 Subject: [PATCH 46/80] FIX: Update default_template.html --- app/views/email/default_template.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/email/default_template.html b/app/views/email/default_template.html index 382f939273b..99b2e94995c 100644 --- a/app/views/email/default_template.html +++ b/app/views/email/default_template.html @@ -3,6 +3,8 @@ + + From 09ca75d17e8e3a38e84e3e39e41e2ee11fa3a9e9 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 20 May 2020 11:48:35 -0400 Subject: [PATCH 47/80] FIX: select-kit was in the wrong place `app/` means we want to merge it into our application there. `addon` means give it its own module namespace, which is what we wanted. --- app/assets/javascripts/application.js | 2 +- app/assets/javascripts/select-kit/addon/.gitkeep | 0 .../{app => addon}/components/admin-group-selector.js | 0 .../{app => addon}/components/categories-admin-dropdown.js | 0 .../select-kit/{app => addon}/components/category-chooser.js | 0 .../select-kit/{app => addon}/components/category-drop.js | 0 .../components/category-drop/category-drop-header.js | 0 .../{app => addon}/components/category-notifications-button.js | 0 .../select-kit/{app => addon}/components/category-row.js | 0 .../select-kit/{app => addon}/components/category-selector.js | 0 .../select-kit/{app => addon}/components/color-palettes.js | 0 .../components/color-palettes/color-palettes-row.js | 0 .../select-kit/{app => addon}/components/combo-box.js | 0 .../{app => addon}/components/combo-box/combo-box-header.js | 0 .../select-kit/{app => addon}/components/composer-actions.js | 0 .../select-kit/{app => addon}/components/create-color-row.js | 0 .../select-kit/{app => addon}/components/dropdown-select-box.js | 0 .../dropdown-select-box/dropdown-select-box-header.js | 0 .../components/dropdown-select-box/dropdown-select-box-row.js | 0 .../{app => addon}/components/future-date-input-selector.js | 0 .../future-date-input-selector-header.js | 0 .../future-date-input-selector-row.js | 0 .../components/future-date-input-selector/mixin.js | 0 .../select-kit/{app => addon}/components/group-dropdown.js | 0 .../{app => addon}/components/group-members-dropdown.js | 0 .../{app => addon}/components/group-notifications-button.js | 0 .../select-kit/{app => addon}/components/icon-picker.js | 0 .../select-kit/{app => addon}/components/list-setting.js | 0 .../select-kit/{app => addon}/components/mini-tag-chooser.js | 0 .../components/mini-tag-chooser/mini-tag-chooser-header.js | 0 .../components/mini-tag-chooser/selected-collection.js | 0 .../select-kit/{app => addon}/components/multi-select.js | 0 .../components/multi-select/multi-select-filter.js | 0 .../components/multi-select/multi-select-header.js | 0 .../{app => addon}/components/multi-select/selected-category.js | 0 .../{app => addon}/components/multi-select/selected-color.js | 0 .../select-kit/{app => addon}/components/none-category-row.js | 0 .../{app => addon}/components/notifications-button.js | 0 .../components/notifications-button/notifications-button-row.js | 0 .../{app => addon}/components/notifications-filter.js | 0 .../notifications-filter/notifications-filter-header.js | 0 .../select-kit/{app => addon}/components/period-chooser.js | 0 .../components/period-chooser/period-chooser-header.js | 0 .../components/period-chooser/period-chooser-row.js | 0 .../select-kit/{app => addon}/components/pinned-button.js | 0 .../select-kit/{app => addon}/components/pinned-options.js | 0 .../components/search-advanced-category-chooser.js | 0 .../select-kit/{app => addon}/components/select-kit.js | 0 .../{app => addon}/components/select-kit/errors-collection.js | 0 .../{app => addon}/components/select-kit/select-kit-body.js | 0 .../components/select-kit/select-kit-collection.js | 0 .../components/select-kit/select-kit-create-row.js | 0 .../{app => addon}/components/select-kit/select-kit-filter.js | 0 .../{app => addon}/components/select-kit/select-kit-header.js | 0 .../{app => addon}/components/select-kit/select-kit-none-row.js | 0 .../{app => addon}/components/select-kit/select-kit-row.js | 0 .../components/select-kit/single-select-header.js | 0 .../select-kit/{app => addon}/components/selected-color.js | 0 .../select-kit/{app => addon}/components/selected-name.js | 0 .../select-kit/{app => addon}/components/single-select.js | 0 .../select-kit/{app => addon}/components/tag-chooser-row.js | 0 .../select-kit/{app => addon}/components/tag-chooser.js | 0 .../select-kit/{app => addon}/components/tag-drop.js | 0 .../{app => addon}/components/tag-drop/tag-drop-header.js | 0 .../select-kit/{app => addon}/components/tag-group-chooser.js | 0 .../{app => addon}/components/tag-notifications-button.js | 0 .../javascripts/select-kit/{app => addon}/components/tag-row.js | 0 .../select-kit/{app => addon}/components/timezone-input.js | 0 .../{app => addon}/components/toolbar-popup-menu-options.js | 0 .../toolbar-popup-menu-options-heading.js | 0 .../{app => addon}/components/topic-footer-mobile-dropdown.js | 0 .../{app => addon}/components/topic-notifications-button.js | 0 .../{app => addon}/components/topic-notifications-options.js | 0 .../select-kit/{app => addon}/components/user-chooser.js | 0 .../{app => addon}/components/user-chooser/user-row.js | 0 .../{app => addon}/components/user-notifications-dropdown.js | 0 .../javascripts/select-kit/{app => addon}/mixins/plugin-api.js | 0 app/assets/javascripts/select-kit/{app => addon}/mixins/tags.js | 0 .../javascripts/select-kit/{app => addon}/mixins/utils.js | 0 .../templates/components/category-drop/category-drop-header.hbs | 0 .../{app => addon}/templates/components/category-row.hbs | 0 .../templates/components/color-palettes/color-palettes-row.hbs | 0 .../templates/components/combo-box/combo-box-header.hbs | 0 .../{app => addon}/templates/components/create-color-row.hbs | 0 .../dropdown-select-box/dropdown-select-box-header.hbs | 0 .../components/dropdown-select-box/dropdown-select-box-row.hbs | 0 .../future-date-input-selector-header.hbs | 0 .../future-date-input-selector-row.hbs | 0 .../components/mini-tag-chooser/mini-tag-chooser-header.hbs | 0 .../components/mini-tag-chooser/selected-collection.hbs | 0 .../{app => addon}/templates/components/multi-select.hbs | 0 .../templates/components/multi-select/multi-select-header.hbs | 0 .../templates/components/multi-select/selected-category.hbs | 0 .../notifications-filter/notifications-filter-header.hbs | 0 .../components/period-chooser/period-chooser-header.hbs | 0 .../templates/components/period-chooser/period-chooser-row.hbs | 0 .../{app => addon}/templates/components/pinned-button.hbs | 0 .../templates/components/select-kit/errors-collection.hbs | 0 .../templates/components/select-kit/select-kit-body.hbs | 0 .../templates/components/select-kit/select-kit-collection.hbs | 0 .../templates/components/select-kit/select-kit-filter.hbs | 0 .../templates/components/select-kit/select-kit-row.hbs | 0 .../templates/components/select-kit/single-select-header.hbs | 0 .../{app => addon}/templates/components/selected-name.hbs | 0 .../{app => addon}/templates/components/single-select.hbs | 0 .../{app => addon}/templates/components/tag-chooser-row.hbs | 0 .../templates/components/tag-drop/tag-drop-header.hbs | 0 .../select-kit/{app => addon}/templates/components/tag-row.hbs | 0 .../toolbar-popup-menu-options-heading.hbs | 0 .../templates/components/topic-notifications-button.hbs | 0 .../templates/components/user-chooser/user-row.hbs | 0 111 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 app/assets/javascripts/select-kit/addon/.gitkeep rename app/assets/javascripts/select-kit/{app => addon}/components/admin-group-selector.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/categories-admin-dropdown.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/category-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/category-drop.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/category-drop/category-drop-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/category-notifications-button.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/category-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/category-selector.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/color-palettes.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/color-palettes/color-palettes-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/combo-box.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/combo-box/combo-box-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/composer-actions.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/create-color-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/dropdown-select-box.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/dropdown-select-box/dropdown-select-box-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/dropdown-select-box/dropdown-select-box-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/future-date-input-selector.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/future-date-input-selector/future-date-input-selector-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/future-date-input-selector/future-date-input-selector-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/future-date-input-selector/mixin.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/group-dropdown.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/group-members-dropdown.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/group-notifications-button.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/icon-picker.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/list-setting.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/mini-tag-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/mini-tag-chooser/mini-tag-chooser-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/mini-tag-chooser/selected-collection.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/multi-select.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/multi-select/multi-select-filter.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/multi-select/multi-select-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/multi-select/selected-category.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/multi-select/selected-color.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/none-category-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/notifications-button.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/notifications-button/notifications-button-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/notifications-filter.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/notifications-filter/notifications-filter-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/period-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/period-chooser/period-chooser-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/period-chooser/period-chooser-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/pinned-button.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/pinned-options.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/search-advanced-category-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/errors-collection.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-body.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-collection.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-create-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-filter.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-none-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/select-kit-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/select-kit/single-select-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/selected-color.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/selected-name.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/single-select.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-chooser-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-drop.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-drop/tag-drop-header.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-group-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-notifications-button.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/tag-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/timezone-input.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/toolbar-popup-menu-options.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/topic-footer-mobile-dropdown.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/topic-notifications-button.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/topic-notifications-options.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/user-chooser.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/user-chooser/user-row.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/components/user-notifications-dropdown.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/mixins/plugin-api.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/mixins/tags.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/mixins/utils.js (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/category-drop/category-drop-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/category-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/color-palettes/color-palettes-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/combo-box/combo-box-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/create-color-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/dropdown-select-box/dropdown-select-box-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/dropdown-select-box/dropdown-select-box-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/future-date-input-selector/future-date-input-selector-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/future-date-input-selector/future-date-input-selector-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/mini-tag-chooser/mini-tag-chooser-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/mini-tag-chooser/selected-collection.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/multi-select.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/multi-select/multi-select-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/multi-select/selected-category.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/notifications-filter/notifications-filter-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/period-chooser/period-chooser-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/period-chooser/period-chooser-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/pinned-button.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/select-kit/errors-collection.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/select-kit/select-kit-body.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/select-kit/select-kit-collection.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/select-kit/select-kit-filter.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/select-kit/select-kit-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/select-kit/single-select-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/selected-name.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/single-select.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/tag-chooser-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/tag-drop/tag-drop-header.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/tag-row.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/topic-notifications-button.hbs (100%) rename app/assets/javascripts/select-kit/{app => addon}/templates/components/user-chooser/user-row.hbs (100%) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 4445fd79869..40f1d275bb4 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -1,6 +1,6 @@ //= require_tree ./discourse-common/addon //= require ./polyfills -//= require_tree ./select-kit/app +//= require_tree ./select-kit/addon //= require ./discourse/app/app //= require ./app-boot diff --git a/app/assets/javascripts/select-kit/addon/.gitkeep b/app/assets/javascripts/select-kit/addon/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/app/assets/javascripts/select-kit/app/components/admin-group-selector.js b/app/assets/javascripts/select-kit/addon/components/admin-group-selector.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/admin-group-selector.js rename to app/assets/javascripts/select-kit/addon/components/admin-group-selector.js diff --git a/app/assets/javascripts/select-kit/app/components/categories-admin-dropdown.js b/app/assets/javascripts/select-kit/addon/components/categories-admin-dropdown.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/categories-admin-dropdown.js rename to app/assets/javascripts/select-kit/addon/components/categories-admin-dropdown.js diff --git a/app/assets/javascripts/select-kit/app/components/category-chooser.js b/app/assets/javascripts/select-kit/addon/components/category-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/category-chooser.js rename to app/assets/javascripts/select-kit/addon/components/category-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/category-drop.js b/app/assets/javascripts/select-kit/addon/components/category-drop.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/category-drop.js rename to app/assets/javascripts/select-kit/addon/components/category-drop.js diff --git a/app/assets/javascripts/select-kit/app/components/category-drop/category-drop-header.js b/app/assets/javascripts/select-kit/addon/components/category-drop/category-drop-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/category-drop/category-drop-header.js rename to app/assets/javascripts/select-kit/addon/components/category-drop/category-drop-header.js diff --git a/app/assets/javascripts/select-kit/app/components/category-notifications-button.js b/app/assets/javascripts/select-kit/addon/components/category-notifications-button.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/category-notifications-button.js rename to app/assets/javascripts/select-kit/addon/components/category-notifications-button.js diff --git a/app/assets/javascripts/select-kit/app/components/category-row.js b/app/assets/javascripts/select-kit/addon/components/category-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/category-row.js rename to app/assets/javascripts/select-kit/addon/components/category-row.js diff --git a/app/assets/javascripts/select-kit/app/components/category-selector.js b/app/assets/javascripts/select-kit/addon/components/category-selector.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/category-selector.js rename to app/assets/javascripts/select-kit/addon/components/category-selector.js diff --git a/app/assets/javascripts/select-kit/app/components/color-palettes.js b/app/assets/javascripts/select-kit/addon/components/color-palettes.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/color-palettes.js rename to app/assets/javascripts/select-kit/addon/components/color-palettes.js diff --git a/app/assets/javascripts/select-kit/app/components/color-palettes/color-palettes-row.js b/app/assets/javascripts/select-kit/addon/components/color-palettes/color-palettes-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/color-palettes/color-palettes-row.js rename to app/assets/javascripts/select-kit/addon/components/color-palettes/color-palettes-row.js diff --git a/app/assets/javascripts/select-kit/app/components/combo-box.js b/app/assets/javascripts/select-kit/addon/components/combo-box.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/combo-box.js rename to app/assets/javascripts/select-kit/addon/components/combo-box.js diff --git a/app/assets/javascripts/select-kit/app/components/combo-box/combo-box-header.js b/app/assets/javascripts/select-kit/addon/components/combo-box/combo-box-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/combo-box/combo-box-header.js rename to app/assets/javascripts/select-kit/addon/components/combo-box/combo-box-header.js diff --git a/app/assets/javascripts/select-kit/app/components/composer-actions.js b/app/assets/javascripts/select-kit/addon/components/composer-actions.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/composer-actions.js rename to app/assets/javascripts/select-kit/addon/components/composer-actions.js diff --git a/app/assets/javascripts/select-kit/app/components/create-color-row.js b/app/assets/javascripts/select-kit/addon/components/create-color-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/create-color-row.js rename to app/assets/javascripts/select-kit/addon/components/create-color-row.js diff --git a/app/assets/javascripts/select-kit/app/components/dropdown-select-box.js b/app/assets/javascripts/select-kit/addon/components/dropdown-select-box.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/dropdown-select-box.js rename to app/assets/javascripts/select-kit/addon/components/dropdown-select-box.js diff --git a/app/assets/javascripts/select-kit/app/components/dropdown-select-box/dropdown-select-box-header.js b/app/assets/javascripts/select-kit/addon/components/dropdown-select-box/dropdown-select-box-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/dropdown-select-box/dropdown-select-box-header.js rename to app/assets/javascripts/select-kit/addon/components/dropdown-select-box/dropdown-select-box-header.js diff --git a/app/assets/javascripts/select-kit/app/components/dropdown-select-box/dropdown-select-box-row.js b/app/assets/javascripts/select-kit/addon/components/dropdown-select-box/dropdown-select-box-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/dropdown-select-box/dropdown-select-box-row.js rename to app/assets/javascripts/select-kit/addon/components/dropdown-select-box/dropdown-select-box-row.js diff --git a/app/assets/javascripts/select-kit/app/components/future-date-input-selector.js b/app/assets/javascripts/select-kit/addon/components/future-date-input-selector.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/future-date-input-selector.js rename to app/assets/javascripts/select-kit/addon/components/future-date-input-selector.js diff --git a/app/assets/javascripts/select-kit/app/components/future-date-input-selector/future-date-input-selector-header.js b/app/assets/javascripts/select-kit/addon/components/future-date-input-selector/future-date-input-selector-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/future-date-input-selector/future-date-input-selector-header.js rename to app/assets/javascripts/select-kit/addon/components/future-date-input-selector/future-date-input-selector-header.js diff --git a/app/assets/javascripts/select-kit/app/components/future-date-input-selector/future-date-input-selector-row.js b/app/assets/javascripts/select-kit/addon/components/future-date-input-selector/future-date-input-selector-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/future-date-input-selector/future-date-input-selector-row.js rename to app/assets/javascripts/select-kit/addon/components/future-date-input-selector/future-date-input-selector-row.js diff --git a/app/assets/javascripts/select-kit/app/components/future-date-input-selector/mixin.js b/app/assets/javascripts/select-kit/addon/components/future-date-input-selector/mixin.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/future-date-input-selector/mixin.js rename to app/assets/javascripts/select-kit/addon/components/future-date-input-selector/mixin.js diff --git a/app/assets/javascripts/select-kit/app/components/group-dropdown.js b/app/assets/javascripts/select-kit/addon/components/group-dropdown.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/group-dropdown.js rename to app/assets/javascripts/select-kit/addon/components/group-dropdown.js diff --git a/app/assets/javascripts/select-kit/app/components/group-members-dropdown.js b/app/assets/javascripts/select-kit/addon/components/group-members-dropdown.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/group-members-dropdown.js rename to app/assets/javascripts/select-kit/addon/components/group-members-dropdown.js diff --git a/app/assets/javascripts/select-kit/app/components/group-notifications-button.js b/app/assets/javascripts/select-kit/addon/components/group-notifications-button.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/group-notifications-button.js rename to app/assets/javascripts/select-kit/addon/components/group-notifications-button.js diff --git a/app/assets/javascripts/select-kit/app/components/icon-picker.js b/app/assets/javascripts/select-kit/addon/components/icon-picker.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/icon-picker.js rename to app/assets/javascripts/select-kit/addon/components/icon-picker.js diff --git a/app/assets/javascripts/select-kit/app/components/list-setting.js b/app/assets/javascripts/select-kit/addon/components/list-setting.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/list-setting.js rename to app/assets/javascripts/select-kit/addon/components/list-setting.js diff --git a/app/assets/javascripts/select-kit/app/components/mini-tag-chooser.js b/app/assets/javascripts/select-kit/addon/components/mini-tag-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/mini-tag-chooser.js rename to app/assets/javascripts/select-kit/addon/components/mini-tag-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/mini-tag-chooser/mini-tag-chooser-header.js b/app/assets/javascripts/select-kit/addon/components/mini-tag-chooser/mini-tag-chooser-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/mini-tag-chooser/mini-tag-chooser-header.js rename to app/assets/javascripts/select-kit/addon/components/mini-tag-chooser/mini-tag-chooser-header.js diff --git a/app/assets/javascripts/select-kit/app/components/mini-tag-chooser/selected-collection.js b/app/assets/javascripts/select-kit/addon/components/mini-tag-chooser/selected-collection.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/mini-tag-chooser/selected-collection.js rename to app/assets/javascripts/select-kit/addon/components/mini-tag-chooser/selected-collection.js diff --git a/app/assets/javascripts/select-kit/app/components/multi-select.js b/app/assets/javascripts/select-kit/addon/components/multi-select.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/multi-select.js rename to app/assets/javascripts/select-kit/addon/components/multi-select.js diff --git a/app/assets/javascripts/select-kit/app/components/multi-select/multi-select-filter.js b/app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-filter.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/multi-select/multi-select-filter.js rename to app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-filter.js diff --git a/app/assets/javascripts/select-kit/app/components/multi-select/multi-select-header.js b/app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/multi-select/multi-select-header.js rename to app/assets/javascripts/select-kit/addon/components/multi-select/multi-select-header.js diff --git a/app/assets/javascripts/select-kit/app/components/multi-select/selected-category.js b/app/assets/javascripts/select-kit/addon/components/multi-select/selected-category.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/multi-select/selected-category.js rename to app/assets/javascripts/select-kit/addon/components/multi-select/selected-category.js diff --git a/app/assets/javascripts/select-kit/app/components/multi-select/selected-color.js b/app/assets/javascripts/select-kit/addon/components/multi-select/selected-color.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/multi-select/selected-color.js rename to app/assets/javascripts/select-kit/addon/components/multi-select/selected-color.js diff --git a/app/assets/javascripts/select-kit/app/components/none-category-row.js b/app/assets/javascripts/select-kit/addon/components/none-category-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/none-category-row.js rename to app/assets/javascripts/select-kit/addon/components/none-category-row.js diff --git a/app/assets/javascripts/select-kit/app/components/notifications-button.js b/app/assets/javascripts/select-kit/addon/components/notifications-button.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/notifications-button.js rename to app/assets/javascripts/select-kit/addon/components/notifications-button.js diff --git a/app/assets/javascripts/select-kit/app/components/notifications-button/notifications-button-row.js b/app/assets/javascripts/select-kit/addon/components/notifications-button/notifications-button-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/notifications-button/notifications-button-row.js rename to app/assets/javascripts/select-kit/addon/components/notifications-button/notifications-button-row.js diff --git a/app/assets/javascripts/select-kit/app/components/notifications-filter.js b/app/assets/javascripts/select-kit/addon/components/notifications-filter.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/notifications-filter.js rename to app/assets/javascripts/select-kit/addon/components/notifications-filter.js diff --git a/app/assets/javascripts/select-kit/app/components/notifications-filter/notifications-filter-header.js b/app/assets/javascripts/select-kit/addon/components/notifications-filter/notifications-filter-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/notifications-filter/notifications-filter-header.js rename to app/assets/javascripts/select-kit/addon/components/notifications-filter/notifications-filter-header.js diff --git a/app/assets/javascripts/select-kit/app/components/period-chooser.js b/app/assets/javascripts/select-kit/addon/components/period-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/period-chooser.js rename to app/assets/javascripts/select-kit/addon/components/period-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/period-chooser/period-chooser-header.js b/app/assets/javascripts/select-kit/addon/components/period-chooser/period-chooser-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/period-chooser/period-chooser-header.js rename to app/assets/javascripts/select-kit/addon/components/period-chooser/period-chooser-header.js diff --git a/app/assets/javascripts/select-kit/app/components/period-chooser/period-chooser-row.js b/app/assets/javascripts/select-kit/addon/components/period-chooser/period-chooser-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/period-chooser/period-chooser-row.js rename to app/assets/javascripts/select-kit/addon/components/period-chooser/period-chooser-row.js diff --git a/app/assets/javascripts/select-kit/app/components/pinned-button.js b/app/assets/javascripts/select-kit/addon/components/pinned-button.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/pinned-button.js rename to app/assets/javascripts/select-kit/addon/components/pinned-button.js diff --git a/app/assets/javascripts/select-kit/app/components/pinned-options.js b/app/assets/javascripts/select-kit/addon/components/pinned-options.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/pinned-options.js rename to app/assets/javascripts/select-kit/addon/components/pinned-options.js diff --git a/app/assets/javascripts/select-kit/app/components/search-advanced-category-chooser.js b/app/assets/javascripts/select-kit/addon/components/search-advanced-category-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/search-advanced-category-chooser.js rename to app/assets/javascripts/select-kit/addon/components/search-advanced-category-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit.js b/app/assets/javascripts/select-kit/addon/components/select-kit.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit.js rename to app/assets/javascripts/select-kit/addon/components/select-kit.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/errors-collection.js b/app/assets/javascripts/select-kit/addon/components/select-kit/errors-collection.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/errors-collection.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/errors-collection.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-body.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-body.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-body.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-body.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-collection.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-collection.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-collection.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-collection.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-create-row.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-create-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-create-row.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-create-row.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-filter.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-filter.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-filter.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-filter.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-header.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-header.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-header.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-none-row.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-none-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-none-row.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-none-row.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/select-kit-row.js b/app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/select-kit-row.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/select-kit-row.js diff --git a/app/assets/javascripts/select-kit/app/components/select-kit/single-select-header.js b/app/assets/javascripts/select-kit/addon/components/select-kit/single-select-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/select-kit/single-select-header.js rename to app/assets/javascripts/select-kit/addon/components/select-kit/single-select-header.js diff --git a/app/assets/javascripts/select-kit/app/components/selected-color.js b/app/assets/javascripts/select-kit/addon/components/selected-color.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/selected-color.js rename to app/assets/javascripts/select-kit/addon/components/selected-color.js diff --git a/app/assets/javascripts/select-kit/app/components/selected-name.js b/app/assets/javascripts/select-kit/addon/components/selected-name.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/selected-name.js rename to app/assets/javascripts/select-kit/addon/components/selected-name.js diff --git a/app/assets/javascripts/select-kit/app/components/single-select.js b/app/assets/javascripts/select-kit/addon/components/single-select.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/single-select.js rename to app/assets/javascripts/select-kit/addon/components/single-select.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-chooser-row.js b/app/assets/javascripts/select-kit/addon/components/tag-chooser-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-chooser-row.js rename to app/assets/javascripts/select-kit/addon/components/tag-chooser-row.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-chooser.js b/app/assets/javascripts/select-kit/addon/components/tag-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-chooser.js rename to app/assets/javascripts/select-kit/addon/components/tag-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-drop.js b/app/assets/javascripts/select-kit/addon/components/tag-drop.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-drop.js rename to app/assets/javascripts/select-kit/addon/components/tag-drop.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-drop/tag-drop-header.js b/app/assets/javascripts/select-kit/addon/components/tag-drop/tag-drop-header.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-drop/tag-drop-header.js rename to app/assets/javascripts/select-kit/addon/components/tag-drop/tag-drop-header.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-group-chooser.js b/app/assets/javascripts/select-kit/addon/components/tag-group-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-group-chooser.js rename to app/assets/javascripts/select-kit/addon/components/tag-group-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-notifications-button.js b/app/assets/javascripts/select-kit/addon/components/tag-notifications-button.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-notifications-button.js rename to app/assets/javascripts/select-kit/addon/components/tag-notifications-button.js diff --git a/app/assets/javascripts/select-kit/app/components/tag-row.js b/app/assets/javascripts/select-kit/addon/components/tag-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/tag-row.js rename to app/assets/javascripts/select-kit/addon/components/tag-row.js diff --git a/app/assets/javascripts/select-kit/app/components/timezone-input.js b/app/assets/javascripts/select-kit/addon/components/timezone-input.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/timezone-input.js rename to app/assets/javascripts/select-kit/addon/components/timezone-input.js diff --git a/app/assets/javascripts/select-kit/app/components/toolbar-popup-menu-options.js b/app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/toolbar-popup-menu-options.js rename to app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options.js diff --git a/app/assets/javascripts/select-kit/app/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.js b/app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.js rename to app/assets/javascripts/select-kit/addon/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.js diff --git a/app/assets/javascripts/select-kit/app/components/topic-footer-mobile-dropdown.js b/app/assets/javascripts/select-kit/addon/components/topic-footer-mobile-dropdown.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/topic-footer-mobile-dropdown.js rename to app/assets/javascripts/select-kit/addon/components/topic-footer-mobile-dropdown.js diff --git a/app/assets/javascripts/select-kit/app/components/topic-notifications-button.js b/app/assets/javascripts/select-kit/addon/components/topic-notifications-button.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/topic-notifications-button.js rename to app/assets/javascripts/select-kit/addon/components/topic-notifications-button.js diff --git a/app/assets/javascripts/select-kit/app/components/topic-notifications-options.js b/app/assets/javascripts/select-kit/addon/components/topic-notifications-options.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/topic-notifications-options.js rename to app/assets/javascripts/select-kit/addon/components/topic-notifications-options.js diff --git a/app/assets/javascripts/select-kit/app/components/user-chooser.js b/app/assets/javascripts/select-kit/addon/components/user-chooser.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/user-chooser.js rename to app/assets/javascripts/select-kit/addon/components/user-chooser.js diff --git a/app/assets/javascripts/select-kit/app/components/user-chooser/user-row.js b/app/assets/javascripts/select-kit/addon/components/user-chooser/user-row.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/user-chooser/user-row.js rename to app/assets/javascripts/select-kit/addon/components/user-chooser/user-row.js diff --git a/app/assets/javascripts/select-kit/app/components/user-notifications-dropdown.js b/app/assets/javascripts/select-kit/addon/components/user-notifications-dropdown.js similarity index 100% rename from app/assets/javascripts/select-kit/app/components/user-notifications-dropdown.js rename to app/assets/javascripts/select-kit/addon/components/user-notifications-dropdown.js diff --git a/app/assets/javascripts/select-kit/app/mixins/plugin-api.js b/app/assets/javascripts/select-kit/addon/mixins/plugin-api.js similarity index 100% rename from app/assets/javascripts/select-kit/app/mixins/plugin-api.js rename to app/assets/javascripts/select-kit/addon/mixins/plugin-api.js diff --git a/app/assets/javascripts/select-kit/app/mixins/tags.js b/app/assets/javascripts/select-kit/addon/mixins/tags.js similarity index 100% rename from app/assets/javascripts/select-kit/app/mixins/tags.js rename to app/assets/javascripts/select-kit/addon/mixins/tags.js diff --git a/app/assets/javascripts/select-kit/app/mixins/utils.js b/app/assets/javascripts/select-kit/addon/mixins/utils.js similarity index 100% rename from app/assets/javascripts/select-kit/app/mixins/utils.js rename to app/assets/javascripts/select-kit/addon/mixins/utils.js diff --git a/app/assets/javascripts/select-kit/app/templates/components/category-drop/category-drop-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/category-drop/category-drop-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/category-drop/category-drop-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/category-drop/category-drop-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/category-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/category-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/category-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/category-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/color-palettes/color-palettes-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/color-palettes/color-palettes-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/color-palettes/color-palettes-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/color-palettes/color-palettes-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/combo-box/combo-box-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/combo-box/combo-box-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/combo-box/combo-box-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/combo-box/combo-box-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/create-color-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/create-color-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/create-color-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/create-color-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/dropdown-select-box/dropdown-select-box-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/dropdown-select-box/dropdown-select-box-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/dropdown-select-box/dropdown-select-box-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/dropdown-select-box/dropdown-select-box-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/dropdown-select-box/dropdown-select-box-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/dropdown-select-box/dropdown-select-box-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/dropdown-select-box/dropdown-select-box-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/dropdown-select-box/dropdown-select-box-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/future-date-input-selector/future-date-input-selector-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/future-date-input-selector/future-date-input-selector-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/future-date-input-selector/future-date-input-selector-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/future-date-input-selector/future-date-input-selector-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/future-date-input-selector/future-date-input-selector-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/future-date-input-selector/future-date-input-selector-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/future-date-input-selector/future-date-input-selector-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/future-date-input-selector/future-date-input-selector-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/mini-tag-chooser/mini-tag-chooser-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/mini-tag-chooser/mini-tag-chooser-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/mini-tag-chooser/mini-tag-chooser-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/mini-tag-chooser/mini-tag-chooser-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/mini-tag-chooser/selected-collection.hbs b/app/assets/javascripts/select-kit/addon/templates/components/mini-tag-chooser/selected-collection.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/mini-tag-chooser/selected-collection.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/mini-tag-chooser/selected-collection.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/multi-select.hbs b/app/assets/javascripts/select-kit/addon/templates/components/multi-select.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/multi-select.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/multi-select.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/multi-select/multi-select-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/multi-select/multi-select-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/multi-select/multi-select-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/multi-select/multi-select-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/multi-select/selected-category.hbs b/app/assets/javascripts/select-kit/addon/templates/components/multi-select/selected-category.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/multi-select/selected-category.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/multi-select/selected-category.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/notifications-filter/notifications-filter-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/notifications-filter/notifications-filter-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/notifications-filter/notifications-filter-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/notifications-filter/notifications-filter-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/period-chooser/period-chooser-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/period-chooser/period-chooser-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/period-chooser/period-chooser-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/period-chooser/period-chooser-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/period-chooser/period-chooser-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/period-chooser/period-chooser-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/period-chooser/period-chooser-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/period-chooser/period-chooser-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/pinned-button.hbs b/app/assets/javascripts/select-kit/addon/templates/components/pinned-button.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/pinned-button.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/pinned-button.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/select-kit/errors-collection.hbs b/app/assets/javascripts/select-kit/addon/templates/components/select-kit/errors-collection.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/select-kit/errors-collection.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/select-kit/errors-collection.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-body.hbs b/app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-body.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-body.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-body.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-collection.hbs b/app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-collection.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-collection.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-collection.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-filter.hbs b/app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-filter.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-filter.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-filter.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/select-kit/select-kit-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/select-kit/select-kit-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/select-kit/single-select-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/select-kit/single-select-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/select-kit/single-select-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/select-kit/single-select-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/selected-name.hbs b/app/assets/javascripts/select-kit/addon/templates/components/selected-name.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/selected-name.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/selected-name.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/single-select.hbs b/app/assets/javascripts/select-kit/addon/templates/components/single-select.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/single-select.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/single-select.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/tag-chooser-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/tag-chooser-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/tag-chooser-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/tag-chooser-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/tag-drop/tag-drop-header.hbs b/app/assets/javascripts/select-kit/addon/templates/components/tag-drop/tag-drop-header.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/tag-drop/tag-drop-header.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/tag-drop/tag-drop-header.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/tag-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/tag-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/tag-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/tag-row.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.hbs b/app/assets/javascripts/select-kit/addon/templates/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/toolbar-popup-menu-options/toolbar-popup-menu-options-heading.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs b/app/assets/javascripts/select-kit/addon/templates/components/topic-notifications-button.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/topic-notifications-button.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/topic-notifications-button.hbs diff --git a/app/assets/javascripts/select-kit/app/templates/components/user-chooser/user-row.hbs b/app/assets/javascripts/select-kit/addon/templates/components/user-chooser/user-row.hbs similarity index 100% rename from app/assets/javascripts/select-kit/app/templates/components/user-chooser/user-row.hbs rename to app/assets/javascripts/select-kit/addon/templates/components/user-chooser/user-row.hbs From 8851b79472faf1d0f53fa2e7c4d07c91ca96a9a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 20 May 2020 18:00:25 +0200 Subject: [PATCH 48/80] DEV: less code for Category#url --- app/models/category.rb | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/app/models/category.rb b/app/models/category.rb index 63db814752e..6ecfe9d3afe 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -709,37 +709,29 @@ class Category < ActiveRecord::Base ].include? id end - @@url_cache = DistributedCache.new('category_url') + def full_slug(separator = "-") + start_idx = "#{Discourse.base_uri}/c/".size + url[start_idx..-1].gsub("/", separator) + end + + @@url_cache = DistributedCache.new("category_url") def clear_url_cache @@url_cache.clear end - def full_slug(separator = "-") - start_idx = "#{Discourse.base_uri}/c/".length - url[start_idx..-1].gsub("/", separator) - end - def url - url = @@url_cache[self.id] - unless url - url = "#{Discourse.base_uri}/c/#{slug_path.join('/')}" - - @@url_cache[self.id] = url - end - - url + @@url_cache[self.id] ||= "#{Discourse.base_uri}/c/#{slug_path.join('/')}" end def url_with_id self.parent_category ? "#{url}/#{self.id}" : "#{Discourse.base_uri}/c/#{self.slug}/#{self.id}" end - # If the name changes, try and update the category definition topic too if it's - # an exact match + # If the name changes, try and update the category definition topic too if it's an exact match def rename_category_definition - old_name = saved_changes.transform_values(&:first)["name"] return unless topic.present? + old_name = saved_changes.transform_values(&:first)["name"] if topic.title == I18n.t("category.topic_prefix", category: old_name) topic.update_attribute(:title, I18n.t("category.topic_prefix", category: name)) end From 3062036f2ffee70fa6d72a9a95eadd120fe78980 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 20 May 2020 12:05:41 -0400 Subject: [PATCH 49/80] FIX: Allow deprecation to work with Ember CLI --- .../discourse/app/models/nav-item.js | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/discourse/app/models/nav-item.js b/app/assets/javascripts/discourse/app/models/nav-item.js index 412cd8ec2e4..955e536e1eb 100644 --- a/app/assets/javascripts/discourse/app/models/nav-item.js +++ b/app/assets/javascripts/discourse/app/models/nav-item.js @@ -273,12 +273,17 @@ export function addNavItem(item) { NavItem.extraNavItemDescriptors.push(item); } -Object.defineProperty(Discourse, "NavItem", { - get() { - deprecated("Import the NavItem class instead of using Discourse.NavItem", { - since: "2.4.0", - dropFrom: "2.5.0" - }); - return NavItem; - } -}); +if (typeof Discourse !== "undefined") { + Object.defineProperty(Discourse, "NavItem", { + get() { + deprecated( + "Import the NavItem class instead of using Discourse.NavItem", + { + since: "2.4.0", + dropFrom: "2.5.0" + } + ); + return NavItem; + } + }); +} From ba04bb755232bef01347b2b24638f2874e04c61f Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 20 May 2020 12:13:15 -0400 Subject: [PATCH 50/80] FIX: Path should be `addon` not `app` --- app/assets/javascripts/wizard-application.js | 2 +- config/application.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/wizard-application.js b/app/assets/javascripts/wizard-application.js index b8e8797f0c6..4e2a7adc072 100644 --- a/app/assets/javascripts/wizard-application.js +++ b/app/assets/javascripts/wizard-application.js @@ -1,6 +1,6 @@ //= require_tree ./discourse-common/addon //= require i18n-patches -//= require_tree ./select-kit/app +//= require_tree ./select-kit/addon //= require wizard/router //= require wizard/wizard //= require_tree ./wizard/templates diff --git a/config/application.rb b/config/application.rb index ba4486320c4..0157dc82895 100644 --- a/config/application.rb +++ b/config/application.rb @@ -254,7 +254,7 @@ module Discourse # Our templates shouldn't start with 'discourse/app/templates' config.handlebars.templates_root = { 'discourse/app/templates' => '', - 'select-kit/app/templates' => 'select-kit/templates/' + 'select-kit/addon/templates' => 'select-kit/templates/' } config.handlebars.raw_template_namespace = "__DISCOURSE_RAW_TEMPLATES" From e1bd57007be821a7efa0becb7b812449ac53b67f Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Wed, 20 May 2020 11:30:27 -0500 Subject: [PATCH 51/80] DEV: Specs for AboutController can_see_about_stats? impact (#9843) --- spec/requests/about_controller_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/requests/about_controller_spec.rb b/spec/requests/about_controller_spec.rb index 6c58284979f..a10b7663043 100644 --- a/spec/requests/about_controller_spec.rb +++ b/spec/requests/about_controller_spec.rb @@ -36,5 +36,21 @@ describe AboutController do expect(response.body).to include("About - Discourse") end end + + it "serializes stats when 'Guardian#can_see_about_stats?' is true" do + Guardian.any_instance.stubs(:can_see_about_stats?).returns(true) + get "/about.json" + + expect(response.status).to eq(200) + expect(response.parsed_body["about"].keys).to include("stats") + end + + it "does not serialize stats when 'Guardian#can_see_about_stats?' is false" do + Guardian.any_instance.stubs(:can_see_about_stats?).returns(false) + get "/about.json" + + expect(response.status).to eq(200) + expect(response.parsed_body["about"].keys).not_to include("stats") + end end end From 096eca0ee813fa5ba79d76e6012f251e5f85a8e4 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Wed, 20 May 2020 15:09:17 -0400 Subject: [PATCH 52/80] FIX: Requests were not being logged correctly `enable` was defaulting to `nil` which is not what we wanted. --- app/models/application_request.rb | 7 ++++--- spec/rails_helper.rb | 3 +++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/models/application_request.rb b/app/models/application_request.rb index 52a6a8a87e0..3d0d8ae905f 100644 --- a/app/models/application_request.rb +++ b/app/models/application_request.rb @@ -16,15 +16,16 @@ class ApplicationRequest < ActiveRecord::Base include CachedCounting def self.disable - @enabled = false + @disabled = true end def self.enable - @enabled = true + @disabled = false end def self.increment!(type, opts = nil) - perform_increment!(redis_key(type), opts) if @enabled + return if @disabled + perform_increment!(redis_key(type), opts) end def self.write_cache!(date = nil) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index a0ce4b71b7d..cd235fedc92 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -128,6 +128,9 @@ module TestSetup # code that runs inside jobs. run_later! means they are put on the redis # queue and never processed. Jobs.run_later! + + # Don't track ApplicationRequests in test mode unless opted in + ApplicationRequest.disable end end From eef47a26d9ea6db10a646771b094a9f534511c85 Mon Sep 17 00:00:00 2001 From: Kris Date: Wed, 20 May 2020 17:17:47 -0400 Subject: [PATCH 53/80] UX: More consistent mobile banner/alert styles, css cleanup --- app/assets/stylesheets/common/base/alert.scss | 1 + app/assets/stylesheets/desktop.scss | 1 - app/assets/stylesheets/desktop/alert.scss | 3 --- app/assets/stylesheets/mobile/alert.scss | 5 +++-- app/assets/stylesheets/mobile/banner.scss | 7 +------ 5 files changed, 5 insertions(+), 12 deletions(-) delete mode 100644 app/assets/stylesheets/desktop/alert.scss diff --git a/app/assets/stylesheets/common/base/alert.scss b/app/assets/stylesheets/common/base/alert.scss index d729cdc7423..05a29029059 100644 --- a/app/assets/stylesheets/common/base/alert.scss +++ b/app/assets/stylesheets/common/base/alert.scss @@ -3,6 +3,7 @@ background-color: $danger-low; color: $primary; position: relative; + margin-bottom: 1em; .close { font-size: $font-up-3; diff --git a/app/assets/stylesheets/desktop.scss b/app/assets/stylesheets/desktop.scss index 70229afbbc1..064cd7174a7 100644 --- a/app/assets/stylesheets/desktop.scss +++ b/app/assets/stylesheets/desktop.scss @@ -2,7 +2,6 @@ /* @import "desktop/*"; TODO: get this working again */ -@import "desktop/alert"; @import "desktop/banner"; @import "desktop/compose"; @import "desktop/discourse"; diff --git a/app/assets/stylesheets/desktop/alert.scss b/app/assets/stylesheets/desktop/alert.scss deleted file mode 100644 index f3f57eac668..00000000000 --- a/app/assets/stylesheets/desktop/alert.scss +++ /dev/null @@ -1,3 +0,0 @@ -.alert { - margin-bottom: 1em; -} diff --git a/app/assets/stylesheets/mobile/alert.scss b/app/assets/stylesheets/mobile/alert.scss index 0ee9b44ee0e..12e60245e57 100644 --- a/app/assets/stylesheets/mobile/alert.scss +++ b/app/assets/stylesheets/mobile/alert.scss @@ -1,7 +1,8 @@ -// there are (n) new or updated topics, click to show .alert.alert-info { - margin: 0; + margin-bottom: 0.5em; &.clickable { + // there are (n) new or updated topics, click to show + margin-bottom: 0; padding: 1em; } } diff --git a/app/assets/stylesheets/mobile/banner.scss b/app/assets/stylesheets/mobile/banner.scss index 852b2847364..fc308f05880 100644 --- a/app/assets/stylesheets/mobile/banner.scss +++ b/app/assets/stylesheets/mobile/banner.scss @@ -3,11 +3,6 @@ // -------------------------------------------------- #banner { - // go full width on mobile, by extending into the 10px wrap - // borders on left and right - margin: 0 -10px; max-height: 180px; - @media all and (max-height: 499px) { - max-height: 100px; - } + height: 20vh; } From 234933c781c0a0e6705b38abb2da9ec0c62af839 Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Wed, 20 May 2020 19:00:35 -0300 Subject: [PATCH 54/80] FIX: Show staff counters if the rejected posts count is the only value to show (#9845) --- app/assets/javascripts/discourse/app/controllers/user.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/app/controllers/user.js b/app/assets/javascripts/discourse/app/controllers/user.js index cc2db042fbf..b466f084ed5 100644 --- a/app/assets/javascripts/discourse/app/controllers/user.js +++ b/app/assets/javascripts/discourse/app/controllers/user.js @@ -51,13 +51,15 @@ export default Controller.extend(CanCheckEmails, { hasDeletedPosts: gt("model.number_of_deleted_posts", 0), hasBeenSuspended: gt("model.number_of_suspensions", 0), hasReceivedWarnings: gt("model.warnings_received_count", 0), + hasRejectedPosts: gt("model.number_of_rejected_posts", 0), showStaffCounters: or( "hasGivenFlags", "hasFlaggedPosts", "hasDeletedPosts", "hasBeenSuspended", - "hasReceivedWarnings" + "hasReceivedWarnings", + "hasRejectedPosts" ), showFeaturedTopic: and( From 62ecb2885fed1fee95b8879811c7978eb509a910 Mon Sep 17 00:00:00 2001 From: Kris Date: Wed, 20 May 2020 18:05:27 -0400 Subject: [PATCH 55/80] glob @import desktop and mobile scss --- app/assets/stylesheets/desktop.scss | 19 +---------------- app/assets/stylesheets/mobile.scss | 33 +---------------------------- 2 files changed, 2 insertions(+), 50 deletions(-) diff --git a/app/assets/stylesheets/desktop.scss b/app/assets/stylesheets/desktop.scss index 064cd7174a7..e9213e897b3 100644 --- a/app/assets/stylesheets/desktop.scss +++ b/app/assets/stylesheets/desktop.scss @@ -1,23 +1,6 @@ @import "common"; -/* @import "desktop/*"; TODO: get this working again */ - -@import "desktop/banner"; -@import "desktop/compose"; -@import "desktop/discourse"; -@import "desktop/header"; -@import "desktop/login"; -@import "desktop/modal"; -@import "desktop/category-list"; -@import "desktop/latest-topic-list"; -@import "desktop/topic-list"; -@import "desktop/topic-post"; -@import "desktop/topic"; -@import "desktop/upload"; -@import "desktop/user"; -@import "desktop/history"; -@import "desktop/group"; -@import "desktop/admin_customize"; +@import "desktop/*"; // Import all component-specific files @import "desktop/components/*"; diff --git a/app/assets/stylesheets/mobile.scss b/app/assets/stylesheets/mobile.scss index ee9c3ed92df..a3202ca43c1 100644 --- a/app/assets/stylesheets/mobile.scss +++ b/app/assets/stylesheets/mobile.scss @@ -1,37 +1,6 @@ @import "common"; -/* @import "mobile/*"; TODO: get this working again */ - -@import "mobile/buttons"; -@import "mobile/alert"; -@import "mobile/banner"; -@import "mobile/compose"; -@import "mobile/discourse"; -@import "mobile/header"; -@import "mobile/login"; -@import "mobile/modal"; -@import "mobile/topic-list"; -@import "mobile/topic-post"; -@import "mobile/topic"; -@import "mobile/upload"; -@import "mobile/user"; -@import "mobile/history"; -@import "mobile/lightbox"; -@import "mobile/directory"; -@import "mobile/search"; -@import "mobile/emoji"; -@import "mobile/ring"; -@import "mobile/group"; -@import "mobile/dashboard"; -@import "mobile/admin_badges"; -@import "mobile/admin_customize"; -@import "mobile/admin_reports"; -@import "mobile/admin_report"; -@import "mobile/admin_report_table"; -@import "mobile/admin_report_counters"; -@import "mobile/admin_emojis"; -@import "mobile/menu-panel"; -@import "mobile/reviewables"; +@import "mobile/*"; // Import all component-specific files @import "mobile/components/*"; From bf7103343afc3c1ff39cef1af3ba07cfac49ef5d Mon Sep 17 00:00:00 2001 From: Krzysztof Kotlarek Date: Thu, 21 May 2020 08:19:21 +1000 Subject: [PATCH 56/80] FIX: sidekiq is using _forim_session (#9825) Configure Sidekiq to use _forum_session instead of a rack.session --- config/routes.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/routes.rb b/config/routes.rb index a881b260d19..e3e7731bb2c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,6 +23,7 @@ Discourse::Application.routes.draw do post "webhooks/sparkpost" => "webhooks#sparkpost" scope path: nil, constraints: { format: /.*/ } do + Sidekiq::Web.set :sessions, Rails.application.config.session_options if Rails.env.development? mount Sidekiq::Web => "/sidekiq" mount Logster::Web => "/logs" From 68db5deaeca9e3b89501581abaf6e69a9f7ae760 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 21 May 2020 06:55:22 +0800 Subject: [PATCH 57/80] FIX: Badge granter was disabled by default. --- app/services/badge_granter.rb | 6 +++--- spec/rails_helper.rb | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index e402fb880cc..a5027c53030 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -3,11 +3,11 @@ class BadgeGranter def self.disable_queue - @queue_enabled = false + @queue_disabled = true end def self.enable_queue - @queue_enabled = true + @queue_disabled = false end def initialize(badge, user, opts = {}) @@ -124,7 +124,7 @@ class BadgeGranter end def self.queue_badge_grant(type, opt) - return if !SiteSetting.enable_badges || !@queue_enabled + return if !SiteSetting.enable_badges || @queue_disabled payload = nil case type diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index cd235fedc92..256de296583 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -131,6 +131,9 @@ module TestSetup # Don't track ApplicationRequests in test mode unless opted in ApplicationRequest.disable + + # Don't queue badge grant in test mode + BadgeGranter.disable_queue end end From df68d11c388e405b21c285c17ba633b1f731e512 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Thu, 21 May 2020 13:19:48 +1000 Subject: [PATCH 58/80] FEATURE: Add topic excerpt max length site setting (#9847) Adds a new topic_excerpt_maxlength site setting. * When topic excerpt is requested for a post, use the new topic_excerpt_maxlength site setting to limit the size of the excerpt * Remove code for getting/setting Post.excerpt_size as it is not used anywhere --- app/models/post.rb | 10 +--------- config/locales/server.en.yml | 1 + config/site_settings.yml | 6 ++++++ spec/components/search_spec.rb | 2 +- spec/fabricators/post_fabricator.rb | 2 +- spec/models/post_spec.rb | 19 +++++++++++++++++++ 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 89dbbcfebba..30ebaf01630 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -159,14 +159,6 @@ class Post < ActiveRecord::Base includes(:post_details).find_by(post_details: { key: key, value: value }) end - def self.excerpt_size=(sz) - @excerpt_size = sz - end - - def self.excerpt_size - @excerpt_size || 220 - end - def whisper? post_type == Post.types[:whisper] end @@ -482,7 +474,7 @@ class Post < ActiveRecord::Base end def excerpt_for_topic - Post.excerpt(cooked, Post.excerpt_size, strip_links: true, strip_images: true, post: self) + Post.excerpt(cooked, SiteSetting.topic_excerpt_maxlength, strip_links: true, strip_images: true, post: self) end def is_first_post? diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 996fd4040b4..d44d4678ed4 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1467,6 +1467,7 @@ en: exclude_rel_nofollow_domains: "A list of domains where nofollow should not be added to links. example.com will automatically allow sub.example.com as well. As a minimum, you should add the domain of this site to help web crawlers find all content. If other parts of your website are at other domains, add those too." post_excerpt_maxlength: "Maximum length of a post excerpt / summary." + topic_excerpt_maxlength: "Maximum length of a topic excerpt / summary, generated from the first post in a topic." show_pinned_excerpt_mobile: "Show excerpt on pinned topics in mobile view." show_pinned_excerpt_desktop: "Show excerpt on pinned topics in desktop view." post_onebox_maxlength: "Maximum length of a oneboxed Discourse post in characters." diff --git a/config/site_settings.yml b/config/site_settings.yml index ea4bbd4b665..88387952d73 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -819,6 +819,12 @@ posting: ja: 120 zh_CN: 120 zh_TW: 120 + topic_excerpt_maxlength: + default: 220 + locale_default: + ja: 120 + zh_CN: 120 + zh_TW: 120 show_pinned_excerpt_mobile: client: true default: true diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb index a455d81ec13..599ea3c5aa5 100644 --- a/spec/components/search_spec.rb +++ b/spec/components/search_spec.rb @@ -444,7 +444,7 @@ describe Search do end let(:expected_blurb) do - "...to satisfy any test conditions that require content longer than the typical test post raw content. elephant" + "...quire content longer than the typical test post raw content. It really is some long content, folks. elephant" end it 'returns the post' do diff --git a/spec/fabricators/post_fabricator.rb b/spec/fabricators/post_fabricator.rb index 42235cb94fc..77a234d9814 100644 --- a/spec/fabricators/post_fabricator.rb +++ b/spec/fabricators/post_fabricator.rb @@ -10,7 +10,7 @@ end Fabricator(:post_with_long_raw_content, from: :post) do raw 'This is a sample post with semi-long raw content. The raw content is also more than two hundred characters to satisfy any test conditions that require content longer - than the typical test post raw content.' + than the typical test post raw content. It really is some long content, folks.' end Fabricator(:post_with_youtube, from: :post) do diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index 4cc716d6916..d0e2aba6319 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -1158,6 +1158,25 @@ describe Post do expect(post.custom_fields).to eq("Tommy" => "Hanks", "Vincent" => "Vega") end + describe "#excerpt_for_topic" do + it "returns a topic excerpt, defaulting to 220 chars" do + expected_excerpt = "This is a sample post with semi-long raw content. The raw content is also more than \ntwo hundred characters to satisfy any test conditions that require content longer \nthan the typical test post raw content. It really is…" + post = Fabricate(:post_with_long_raw_content) + post.rebake! + excerpt = post.excerpt_for_topic + expect(excerpt).to eq(expected_excerpt) + end + + it "respects the site setting for topic excerpt" do + SiteSetting.topic_excerpt_maxlength = 10 + expected_excerpt = "This is a …" + post = Fabricate(:post_with_long_raw_content) + post.rebake! + excerpt = post.excerpt_for_topic + expect(excerpt).to eq(expected_excerpt) + end + end + describe "#rebake!" do it "will rebake a post correctly" do post = create_post From f4b82f1dc05081b5745a49a3b0dfa7f2bc852e3f Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 21 May 2020 07:19:25 +0800 Subject: [PATCH 59/80] DEV: Fix randomly failing spec. If a user is created with an id of 999, a `upload.user_id == user_avatar.user_id` will return true. This fix increases the id of the upload to something that we will not hit in the foreseeable future. --- spec/components/guardian/user_guardian_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/components/guardian/user_guardian_spec.rb b/spec/components/guardian/user_guardian_spec.rb index b812fa9526d..10b6afc9413 100644 --- a/spec/components/guardian/user_guardian_spec.rb +++ b/spec/components/guardian/user_guardian_spec.rb @@ -25,13 +25,13 @@ describe UserGuardian do end let :already_uploaded do - u = Upload.new(user_id: 999, id: 2) + u = Upload.new(user_id: 9999, id: 2) user_avatar.custom_upload_id = u.id u end let :not_my_upload do - Upload.new(user_id: 999, id: 3) + Upload.new(user_id: 9999, id: 3) end let(:moderator_upload) do From a2d939608d5b3adc7f037dc0ca38e7d1f6b895f6 Mon Sep 17 00:00:00 2001 From: Guo Xiang Tan Date: Thu, 21 May 2020 11:41:58 +0800 Subject: [PATCH 60/80] Bump rails_failover to 0.2.0. --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9709a203c63..6d65777f2c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -277,7 +277,7 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) - rails_failover (0.1.0) + rails_failover (0.2.0) redis (~> 4) rails_multisite (2.1.2) activerecord (> 5.0, < 7) From 3c9212fd88c6663061d9e5dd2ddc38e1e5d317bd Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 21 May 2020 13:00:05 +0530 Subject: [PATCH 61/80] UX: add title for user profile link --- app/assets/javascripts/discourse/app/widgets/header.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/discourse/app/widgets/header.js b/app/assets/javascripts/discourse/app/widgets/header.js index ca4d73c9256..c38e48a9791 100644 --- a/app/assets/javascripts/discourse/app/widgets/header.js +++ b/app/assets/javascripts/discourse/app/widgets/header.js @@ -125,6 +125,7 @@ createWidget( { attributes: { href: attrs.user.get("path"), + title: attrs.user.get("username"), "data-auto-route": true } }, From 18959ff9da96b78cbb2fb0d0583022d7d0d329d0 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 21 May 2020 14:02:12 +0530 Subject: [PATCH 62/80] UX: user name instead username for profile link title --- app/assets/javascripts/discourse/app/widgets/header.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/app/widgets/header.js b/app/assets/javascripts/discourse/app/widgets/header.js index c38e48a9791..8e27a15a036 100644 --- a/app/assets/javascripts/discourse/app/widgets/header.js +++ b/app/assets/javascripts/discourse/app/widgets/header.js @@ -125,7 +125,7 @@ createWidget( { attributes: { href: attrs.user.get("path"), - title: attrs.user.get("username"), + title: attrs.user.get("name"), "data-auto-route": true } }, From 7b6fbe9af2a4c7ac46d723af7079705e4b2de01d Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 21 May 2020 11:04:23 +0200 Subject: [PATCH 63/80] FIX: adds missing tags to published page header (#9835) --- app/views/layouts/publish.html.erb | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/views/layouts/publish.html.erb b/app/views/layouts/publish.html.erb index 5bb0f957c58..4a249e8f32d 100644 --- a/app/views/layouts/publish.html.erb +++ b/app/views/layouts/publish.html.erb @@ -2,13 +2,8 @@ - - + <%= render partial: "layouts/head" %> <%= render partial: "common/discourse_publish_stylesheet" %> - - <%- if @canonical_url -%> - - <%- end -%> <%= yield %> From 66960563ea9a34175018a7b742ee1149143fc830 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Thu, 21 May 2020 11:16:44 +0200 Subject: [PATCH 64/80] FIX: ensures category chooser is case insensitive (#9850) --- .../addon/components/category-chooser.js | 1 + .../acceptance/category-chooser-test.js | 16 ++++++++++++++++ test/javascripts/helpers/select-kit-helper.js | 9 +++++++++ 3 files changed, 26 insertions(+) diff --git a/app/assets/javascripts/select-kit/addon/components/category-chooser.js b/app/assets/javascripts/select-kit/addon/components/category-chooser.js index f36e8be2d32..72d0167ac09 100644 --- a/app/assets/javascripts/select-kit/addon/components/category-chooser.js +++ b/app/assets/javascripts/select-kit/addon/components/category-chooser.js @@ -67,6 +67,7 @@ export default ComboBoxComponent.extend({ search(filter) { if (filter) { + filter = filter.toLowerCase(); return this.content.filter(item => { const category = Category.findById(this.getValue(item)); const categoryName = this.getName(item); diff --git a/test/javascripts/acceptance/category-chooser-test.js b/test/javascripts/acceptance/category-chooser-test.js index b6772ab7710..2247c8cbee7 100644 --- a/test/javascripts/acceptance/category-chooser-test.js +++ b/test/javascripts/acceptance/category-chooser-test.js @@ -29,3 +29,19 @@ QUnit.test("prefill category when category_id is set", async assert => { 1 ); }); + +QUnit.test("filter is case insensitive", async assert => { + const categoryChooser = selectKit(".category-chooser"); + + await visit("/"); + await click("#create-topic"); + await categoryChooser.expand(); + await categoryChooser.fillInFilter("bug"); + + assert.ok(categoryChooser.rows().length, 1); + + await categoryChooser.emptyFilter(); + await categoryChooser.fillInFilter("Bug"); + + assert.ok(categoryChooser.rows().length, 1); +}); diff --git a/test/javascripts/helpers/select-kit-helper.js b/test/javascripts/helpers/select-kit-helper.js index 5d80b8f0b37..f7959913263 100644 --- a/test/javascripts/helpers/select-kit-helper.js +++ b/test/javascripts/helpers/select-kit-helper.js @@ -32,6 +32,11 @@ async function selectKitFillInFilter(filter, selector) { ); } +async function selectKitEmptyFilter(selector) { + checkSelectKitIsNotCollapsed(selector); + await fillIn(`${selector} .filter-input`, ""); +} + async function selectKitSelectRowByValue(value, selector) { checkSelectKitIsNotCollapsed(selector); await click(`${selector} .select-kit-row[data-value='${value}']`); @@ -180,6 +185,10 @@ export default function selectKit(selector) { await selectKitFillInFilter(filter, selector); }, + async emptyFilter() { + await selectKitEmptyFilter(selector); + }, + async keyboard(value, target) { await keyboardHelper(value, target, selector); }, From bde8862f0fba59edaf8fd9159caf4d56a51dbf79 Mon Sep 17 00:00:00 2001 From: David Taylor Date: Thu, 21 May 2020 10:44:25 +0100 Subject: [PATCH 65/80] FIX: Allow GitHub app client_id to be used for OAuth configuration --- config/site_settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index 88387952d73..6209cc621aa 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -394,7 +394,7 @@ login: default: false github_client_id: default: "" - regex: "^[a-f0-9]+$" + regex: "^[a-zA-Z0-9\\.]+$" github_client_secret: default: "" regex: "^[a-f0-9]+$" From 11304ba27c2ab40f7b25bccfd74dcb4ca81f3ca5 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 21 May 2020 09:23:34 -0400 Subject: [PATCH 66/80] Build(deps): Bump rubocop from 0.83.0 to 0.84.0 (#9849) Bumps [rubocop](https://github.com/rubocop-hq/rubocop) from 0.83.0 to 0.84.0. - [Release notes](https://github.com/rubocop-hq/rubocop/releases) - [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md) - [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.83.0...v0.84.0) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- Gemfile.lock | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 6d65777f2c7..db4b88d8631 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -343,13 +343,16 @@ GEM json-schema (~> 2.2) railties (>= 3.1, < 7.0) rtlit (0.0.5) - rubocop (0.83.0) + rubocop (0.84.0) parallel (~> 1.10) parser (>= 2.7.0.1) rainbow (>= 2.2.2, < 4.0) rexml + rubocop-ast (>= 0.0.3) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 2.0) + rubocop-ast (0.0.3) + parser (>= 2.7.0.1) rubocop-discourse (2.1.2) rubocop (>= 0.69.0) rubocop-rspec (>= 1.39.0) From 1a5bcf2a648caf3d277ae2b0856a566789c55e3f Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Thu, 21 May 2020 08:32:50 -0500 Subject: [PATCH 67/80] UX: Remove live theme previewing in favor of refresh (#9798) --- .../app/controllers/preferences/interface.js | 30 +++++---- .../discourse/app/helpers/page-reloader.js | 10 +++ .../discourse/app/lib/theme-selector.js | 61 ------------------- .../app/templates/preferences/interface.hbs | 4 +- app/assets/stylesheets/common/base/user.scss | 3 + app/controllers/themes_controller.rb | 31 ---------- config/locales/client.en.yml | 1 + config/routes.rb | 2 - .../acceptance/preferences-test.js | 1 - 9 files changed, 35 insertions(+), 108 deletions(-) create mode 100644 app/assets/javascripts/discourse/app/helpers/page-reloader.js delete mode 100644 app/controllers/themes_controller.rb diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/interface.js b/app/assets/javascripts/discourse/app/controllers/preferences/interface.js index 1ad85b7d7b1..2fcc5781c30 100644 --- a/app/assets/javascripts/discourse/app/controllers/preferences/interface.js +++ b/app/assets/javascripts/discourse/app/controllers/preferences/interface.js @@ -2,13 +2,10 @@ import I18n from "I18n"; import { inject } from "@ember/controller"; import Controller from "@ember/controller"; import { setDefaultHomepage } from "discourse/lib/utilities"; -import discourseComputed, { observes } from "discourse-common/utils/decorators"; -import { - listThemes, - previewTheme, - setLocalTheme -} from "discourse/lib/theme-selector"; +import discourseComputed from "discourse-common/utils/decorators"; +import { listThemes, setLocalTheme } from "discourse/lib/theme-selector"; import { popupAjaxError } from "discourse/lib/ajax-error"; +import pageReloader from "discourse/helpers/page-reloader"; import { safariHacksDisabled, isiPad, @@ -28,6 +25,9 @@ const TEXT_SIZES = ["smaller", "normal", "larger", "largest"]; const TITLE_COUNT_MODES = ["notifications", "contextual"]; export default Controller.extend({ + currentThemeId: -1, + preferencesController: inject("preferences"), + @discourseComputed("makeThemeDefault") saveAttrNames(makeDefault) { let attrs = [ @@ -51,8 +51,6 @@ export default Controller.extend({ return attrs; }, - preferencesController: inject("preferences"), - @discourseComputed() isiPad() { // TODO: remove this preference checkbox when iOS adoption > 90% @@ -105,10 +103,14 @@ export default Controller.extend({ return themes && themes.length > 1; }, - @observes("themeId") - themeIdChanged() { - const id = this.themeId; - previewTheme([id]); + @discourseComputed("themeId") + themeIdChanged(themeId) { + if (this.currentThemeId === -1) { + this.set("currentThemeId", themeId); + return false; + } else { + return this.currentThemeId !== themeId; + } }, @discourseComputed("model.user_option.theme_ids", "themeId") @@ -189,6 +191,10 @@ export default Controller.extend({ this.disableSafariHacks.toString() ); } + + if (this.themeId !== this.currentThemeId) { + pageReloader.reload(); + } }) .catch(popupAjaxError); }, diff --git a/app/assets/javascripts/discourse/app/helpers/page-reloader.js b/app/assets/javascripts/discourse/app/helpers/page-reloader.js new file mode 100644 index 00000000000..6429be3a3cc --- /dev/null +++ b/app/assets/javascripts/discourse/app/helpers/page-reloader.js @@ -0,0 +1,10 @@ +import EmberObject from "@ember/object"; +import Ember from "ember"; + +export default EmberObject.create({ + reload: function() { + if (!Ember.testing) { + location.reload(); + } + } +}); diff --git a/app/assets/javascripts/discourse/app/lib/theme-selector.js b/app/assets/javascripts/discourse/app/lib/theme-selector.js index 9d293fe312c..2eb4912c9c1 100644 --- a/app/assets/javascripts/discourse/app/lib/theme-selector.js +++ b/app/assets/javascripts/discourse/app/lib/theme-selector.js @@ -1,5 +1,4 @@ import I18n from "I18n"; -import { ajax } from "discourse/lib/ajax"; import deprecated from "discourse-common/lib/deprecated"; const keySelector = "meta[name=discourse_theme_ids]"; @@ -44,66 +43,6 @@ export function setLocalTheme(ids, themeSeq) { } } -export function refreshCSS(node, hash, newHref) { - let $orig = $(node); - - if ($orig.data("reloading")) { - clearTimeout($orig.data("timeout")); - $orig.data("copy").remove(); - } - - if (!$orig.data("orig")) { - $orig.data("orig", node.href); - } - - $orig.data("reloading", true); - - const orig = $(node).data("orig"); - - let reloaded = $orig.clone(true); - if (hash) { - reloaded[0].href = - orig + (orig.indexOf("?") >= 0 ? "&hash=" : "?hash=") + hash; - } else { - reloaded[0].href = newHref; - } - - $orig.after(reloaded); - - let timeout = setTimeout(() => { - $orig.remove(); - reloaded.data("reloading", false); - }, 2000); - - $orig.data("timeout", timeout); - $orig.data("copy", reloaded); -} - -export function previewTheme(ids = []) { - ids = ids.reject(id => !id); - if (!ids.includes(currentThemeId())) { - Discourse.set("assetVersion", "forceRefresh"); - - ajax(`/themes/assets/${ids.length > 0 ? ids.join("-") : "default"}`).then( - results => { - const elem = _.first($(keySelector)); - if (elem) { - elem.content = ids.join(","); - } - - results.themes.forEach(theme => { - const node = $( - `link[rel=stylesheet][data-target=${theme.target}]` - )[0]; - if (node) { - refreshCSS(node, null, theme.new_href); - } - }); - } - ); - } -} - export function listThemes(site) { let themes = site.get("user_themes"); diff --git a/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs b/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs index 45607c8cb75..4f1f13c6147 100644 --- a/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs +++ b/app/assets/javascripts/discourse/app/templates/preferences/interface.hbs @@ -5,9 +5,11 @@ {{combo-box content=userSelectableThemes value=themeId - onChange=(action (mut themeId)) }} + {{#if themeIdChanged}} +

{{i18n "user.save_to_change_theme" save_text=(i18n "save") }}

+ {{/if}} {{#if showThemeSetDefault}}
{{preference-checkbox labelKey="user.theme_default_on_all_devices" checked=makeThemeDefault}} diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index 587af3c3539..4d5e9f42886 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -653,6 +653,9 @@ padding: 5px 0; font-weight: bold; } + .save-theme-alert { + font-size: $font-down-1; + } } .paginated-topics-list { diff --git a/app/controllers/themes_controller.rb b/app/controllers/themes_controller.rb deleted file mode 100644 index 6520ec70975..00000000000 --- a/app/controllers/themes_controller.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -class ThemesController < ::ApplicationController - def assets - theme_ids = params[:ids].to_s.split("-").map(&:to_i) - - if params[:ids] == "default" - theme_ids = nil - else - raise Discourse::NotFound unless guardian.allow_themes?(theme_ids) - end - - targets = view_context.mobile_view? ? [:mobile, :mobile_theme] : [:desktop, :desktop_theme] - targets << :admin if guardian.is_staff? - targets.append(*Discourse.find_plugin_css_assets(mobile_view: true, desktop_view: true)) - - object = targets.map do |target| - Stylesheet::Manager.stylesheet_data(target, theme_ids).map do |hash| - next hash unless Rails.env.development? - - dup_hash = hash.dup - dup_hash[:new_href] = dup_hash[:new_href].dup - dup_hash[:new_href] << (dup_hash[:new_href].include?("?") ? "&" : "?") - dup_hash[:new_href] << SecureRandom.hex - dup_hash - end - end.flatten - - render json: object.as_json - end -end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 0da7d673427..3c3618ef96e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -963,6 +963,7 @@ en: api_approved: "Approved:" api_last_used_at: "Last used at:" theme: "Theme" + save_to_change_theme: 'Theme will be updated after you click "%{save_text}"' home: "Default Home Page" staged: "Staged" diff --git a/config/routes.rb b/config/routes.rb index e3e7731bb2c..69ade71938a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -950,8 +950,6 @@ Discourse::Application.routes.draw do get "/safe-mode" => "safe_mode#index" post "/safe-mode" => "safe_mode#enter", as: "safe_mode_enter" - get "/themes/assets/:ids" => "themes#assets" - unless Rails.env.production? get "/qunit" => "qunit#index" get "/wizard/qunit" => "wizard#qunit" diff --git a/test/javascripts/acceptance/preferences-test.js b/test/javascripts/acceptance/preferences-test.js index a9db1f08e50..20afdcd1677 100644 --- a/test/javascripts/acceptance/preferences-test.js +++ b/test/javascripts/acceptance/preferences-test.js @@ -1,7 +1,6 @@ import I18n from "I18n"; import { acceptance, updateCurrentUser } from "helpers/qunit-helpers"; import selectKit from "helpers/select-kit-helper"; - import User from "discourse/models/user"; acceptance("User Preferences", { From 5a71c51ddd50512aa83283b8b820c7cbe7592ef7 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 21 May 2020 12:40:33 -0400 Subject: [PATCH 68/80] FIX: tag input says tags are optional when they're required --- app/assets/javascripts/discourse/app/controllers/topic.js | 7 +++++++ app/assets/javascripts/discourse/app/templates/topic.hbs | 1 + 2 files changed, 8 insertions(+) diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js index 2c2ebdc7fe6..ba7caf554d1 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic.js +++ b/app/assets/javascripts/discourse/app/controllers/topic.js @@ -185,6 +185,13 @@ export default Controller.extend(bufferedProperty("model"), { ); }, + @discourseComputed("model.category") + minimumRequiredTags(category) { + return category && category.minimum_required_tags > 0 + ? category.minimum_required_tags + : null; + }, + _forceRefreshPostStream() { this.appEvents.trigger("post-stream:refresh", { force: true }); }, diff --git a/app/assets/javascripts/discourse/app/templates/topic.hbs b/app/assets/javascripts/discourse/app/templates/topic.hbs index 488970c10e8..d5e22f54379 100644 --- a/app/assets/javascripts/discourse/app/templates/topic.hbs +++ b/app/assets/javascripts/discourse/app/templates/topic.hbs @@ -36,6 +36,7 @@ options=(hash filterable=true categoryId=buffered.category_id + minimum=minimumRequiredTags ) }} {{/if}} From d11c462104e704e3ccd512a9b5d558c7d13555b2 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 21 May 2020 14:26:03 -0400 Subject: [PATCH 69/80] SECURITY: ERB execution in custom Email Style --- app/helpers/email_helper.rb | 8 +- app/views/layouts/email_template.html.erb | 5 +- spec/integration/email_style_spec.rb | 203 ++++++++++++---------- 3 files changed, 113 insertions(+), 103 deletions(-) diff --git a/app/helpers/email_helper.rb b/app/helpers/email_helper.rb index c579473a4d2..14364d45c32 100644 --- a/app/helpers/email_helper.rb +++ b/app/helpers/email_helper.rb @@ -25,12 +25,8 @@ module EmailHelper raw "#{title}" end - def email_html_template(binding_arg) - template = EmailStyle.new.html.sub( - '%{email_content}', - '<%= yield %><% if defined?(html_body) %><%= html_body %><% end %>' - ) - ERB.new(template).result(binding_arg) + def email_html_template + EmailStyle.new.html.sub('%{email_content}', yield).html_safe end protected diff --git a/app/views/layouts/email_template.html.erb b/app/views/layouts/email_template.html.erb index 80da92efc20..611eba0df49 100644 --- a/app/views/layouts/email_template.html.erb +++ b/app/views/layouts/email_template.html.erb @@ -2,5 +2,8 @@ <%= yield %> <% if defined?(html_body) %><%= html_body %><% end %> <% else %> - <%= email_html_template(binding).html_safe %> + <%= email_html_template do %> + <%= yield %> + <% if defined?(html_body) %><%= html_body %><% end %> + <% end %> <% end %> diff --git a/spec/integration/email_style_spec.rb b/spec/integration/email_style_spec.rb index ef69850891d..395dd19df15 100644 --- a/spec/integration/email_style_spec.rb +++ b/spec/integration/email_style_spec.rb @@ -3,128 +3,139 @@ require "rails_helper" describe EmailStyle do - before do - SiteSetting.email_custom_template = "

FOR YOU

%{email_content}
" - SiteSetting.email_custom_css = 'h1 { color: red; } div.body { color: #FAB; }' - SiteSetting.email_custom_css_compiled = SiteSetting.email_custom_css - end - after do - SiteSetting.remove_override!(:email_custom_template) - SiteSetting.remove_override!(:email_custom_css) - end - - context 'invite' do - fab!(:invite) { Fabricate(:invite) } - let(:invite_mail) { InviteMailer.send_invite(invite) } - - subject(:mail_html) { Email::Renderer.new(invite_mail).html } - - it 'applies customizations' do - expect(mail_html.scan('

FOR YOU

').count).to eq(1) - expect(mail_html).to match("#{Discourse.base_url}/invites/#{invite.invite_key}") - end - - it 'applies customizations if compiled is missing' do - SiteSetting.remove_override!(:email_custom_css_compiled) - expect(mail_html.scan('

FOR YOU

').count).to eq(1) - expect(mail_html).to match("#{Discourse.base_url}/invites/#{invite.invite_key}") - end - - it 'can apply RTL attrs' do - SiteSetting.default_locale = 'he' - body_attrs = mail_html.match(/])+/) - expect(body_attrs[0]&.downcase).to match(/text-align:\s*right/) - expect(body_attrs[0]&.downcase).to include('dir="rtl"') + context "ERB evaluation" do + it "does not evaluate ERB outside of the email itself" do + SiteSetting.email_custom_template = "
%{email_content}
<%= (111 * 333) %>" + html = Email::Renderer.new(UserNotifications.signup(Fabricate(:user))).html + expect(html).not_to match("36963") end end - context 'user_replied' do - let(:response_by_user) { Fabricate(:user, name: "John Doe") } - let(:category) { Fabricate(:category, name: 'India') } - let(:topic) { Fabricate(:topic, category: category, title: "Super cool topic") } - let(:post) { Fabricate(:post, topic: topic, raw: 'This is My super duper cool topic') } - let(:response) { Fabricate(:basic_reply, topic: post.topic, user: response_by_user) } - let(:user) { Fabricate(:user) } - let(:notification) { Fabricate(:replied_notification, user: user, post: response) } - - let(:mail) do - UserNotifications.user_replied( - user, - post: response, - notification_type: notification.notification_type, - notification_data_hash: notification.data_hash - ) + context "with a custom template" do + before do + SiteSetting.email_custom_template = "

FOR YOU

%{email_content}
" + SiteSetting.email_custom_css = 'h1 { color: red; } div.body { color: #FAB; }' + SiteSetting.email_custom_css_compiled = SiteSetting.email_custom_css end - subject(:mail_html) { Email::Renderer.new(mail).html } - - it "customizations are applied to html part of emails" do - expect(mail_html.scan('

FOR YOU

').count).to eq(1) - matches = mail_html.match(/
#{post.raw}/) - expect(matches[1]).to include('color: #FAB;') # custom - expect(matches[1]).to include('padding-top:5px;') # div.body + after do + SiteSetting.remove_override!(:email_custom_template) + SiteSetting.remove_override!(:email_custom_css) end - # TODO: translation override - end + context 'invite' do + fab!(:invite) { Fabricate(:invite) } + let(:invite_mail) { InviteMailer.send_invite(invite) } - context 'signup' do - let(:signup_mail) { UserNotifications.signup(Fabricate(:user)) } - subject(:mail_html) { Email::Renderer.new(signup_mail).html } + subject(:mail_html) { Email::Renderer.new(invite_mail).html } - it "customizations are applied to html part of emails" do - expect(mail_html.scan('

FOR YOU

').count).to eq(1) - expect(mail_html).to include('activate-account') + it 'applies customizations' do + expect(mail_html.scan('

FOR YOU

').count).to eq(1) + expect(mail_html).to match("#{Discourse.base_url}/invites/#{invite.invite_key}") + end + + it 'applies customizations if compiled is missing' do + SiteSetting.remove_override!(:email_custom_css_compiled) + expect(mail_html.scan('

FOR YOU

').count).to eq(1) + expect(mail_html).to match("#{Discourse.base_url}/invites/#{invite.invite_key}") + end + + it 'can apply RTL attrs' do + SiteSetting.default_locale = 'he' + body_attrs = mail_html.match(/])+/) + expect(body_attrs[0]&.downcase).to match(/text-align:\s*right/) + expect(body_attrs[0]&.downcase).to include('dir="rtl"') + end end - context 'translation override' do - before do - TranslationOverride.upsert!( - 'en', - 'user_notifications.signup.text_body_template', - "CLICK THAT LINK: %{base_url}/u/activate-account/%{email_token}" + context 'user_replied' do + let(:response_by_user) { Fabricate(:user, name: "John Doe") } + let(:category) { Fabricate(:category, name: 'India') } + let(:topic) { Fabricate(:topic, category: category, title: "Super cool topic") } + let(:post) { Fabricate(:post, topic: topic, raw: 'This is My super duper cool topic') } + let(:response) { Fabricate(:basic_reply, topic: post.topic, user: response_by_user) } + let(:user) { Fabricate(:user) } + let(:notification) { Fabricate(:replied_notification, user: user, post: response) } + + let(:mail) do + UserNotifications.user_replied( + user, + post: response, + notification_type: notification.notification_type, + notification_data_hash: notification.data_hash ) end - after do - TranslationOverride.revert!('en', ['user_notifications.signup.text_body_template']) + subject(:mail_html) { Email::Renderer.new(mail).html } + + it "customizations are applied to html part of emails" do + expect(mail_html.scan('

FOR YOU

').count).to eq(1) + matches = mail_html.match(/
#{post.raw}/) + expect(matches[1]).to include('color: #FAB;') # custom + expect(matches[1]).to include('padding-top:5px;') # div.body end - it "applies customizations when translation override exists" do - expect(mail_html.scan('

FOR YOU

').count).to eq(1) - expect(mail_html.scan('CLICK THAT LINK').count).to eq(1) - end + # TODO: translation override end - context 'with some bad css' do - before do - SiteSetting.email_custom_css = '@import "nope.css"; h1 {{{ size: really big; ' - SiteSetting.email_custom_css_compiled = SiteSetting.email_custom_css - end + context 'signup' do + let(:signup_mail) { UserNotifications.signup(Fabricate(:user)) } + subject(:mail_html) { Email::Renderer.new(signup_mail).html } - it "can render the html" do - expect(mail_html.scan(/FOR YOU<\/h1>/).count).to eq(1) + it "customizations are applied to html part of emails" do + expect(mail_html.scan('

FOR YOU

').count).to eq(1) expect(mail_html).to include('activate-account') end - end - end - context 'digest' do - fab!(:popular_topic) { Fabricate(:topic, user: Fabricate(:coding_horror), created_at: 1.hour.ago) } - let(:summary_email) { UserNotifications.digest(Fabricate(:user)) } - subject(:mail_html) { Email::Renderer.new(summary_email).html } + context 'translation override' do + before do + TranslationOverride.upsert!( + 'en', + 'user_notifications.signup.text_body_template', + "CLICK THAT LINK: %{base_url}/u/activate-account/%{email_token}" + ) + end - it "customizations are applied to html part of emails" do - expect(mail_html.scan('

FOR YOU

').count).to eq(1) - expect(mail_html).to include(popular_topic.title) + after do + TranslationOverride.revert!('en', ['user_notifications.signup.text_body_template']) + end + + it "applies customizations when translation override exists" do + expect(mail_html.scan('

FOR YOU

').count).to eq(1) + expect(mail_html.scan('CLICK THAT LINK').count).to eq(1) + end + end + + context 'with some bad css' do + before do + SiteSetting.email_custom_css = '@import "nope.css"; h1 {{{ size: really big; ' + SiteSetting.email_custom_css_compiled = SiteSetting.email_custom_css + end + + it "can render the html" do + expect(mail_html.scan(/FOR YOU<\/h1>/).count).to eq(1) + expect(mail_html).to include('activate-account') + end + end end - it "doesn't apply customizations if apply_custom_styles_to_digest is disabled" do - SiteSetting.apply_custom_styles_to_digest = false - expect(mail_html).to_not include('

FOR YOU

') - expect(mail_html).to_not include('FOR YOU') - expect(mail_html).to include(popular_topic.title) + context 'digest' do + fab!(:popular_topic) { Fabricate(:topic, user: Fabricate(:coding_horror), created_at: 1.hour.ago) } + let(:summary_email) { UserNotifications.digest(Fabricate(:user)) } + subject(:mail_html) { Email::Renderer.new(summary_email).html } + + it "customizations are applied to html part of emails" do + expect(mail_html.scan('

FOR YOU

').count).to eq(1) + expect(mail_html).to include(popular_topic.title) + end + + it "doesn't apply customizations if apply_custom_styles_to_digest is disabled" do + SiteSetting.apply_custom_styles_to_digest = false + expect(mail_html).to_not include('

FOR YOU

') + expect(mail_html).to_not include('FOR YOU') + expect(mail_html).to include(popular_topic.title) + end end end end From c0779df99d6e8cbd9b3216d967ae89cdd226ad40 Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Fri, 22 May 2020 11:20:25 +1000 Subject: [PATCH 70/80] FIX: Remove access control post FK from uploads (#9853) --- app/models/upload.rb | 4 ---- .../20200522004855_remove_access_control_post_fk.rb | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 db/post_migrate/20200522004855_remove_access_control_post_fk.rb diff --git a/app/models/upload.rb b/app/models/upload.rb index bb4e7976f5e..31c931c172b 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -448,7 +448,3 @@ end # index_uploads_on_url (url) # index_uploads_on_user_id (user_id) # -# Foreign Keys -# -# fk_rails_... (access_control_post_id => posts.id) -# diff --git a/db/post_migrate/20200522004855_remove_access_control_post_fk.rb b/db/post_migrate/20200522004855_remove_access_control_post_fk.rb new file mode 100644 index 00000000000..36c8d0fbb72 --- /dev/null +++ b/db/post_migrate/20200522004855_remove_access_control_post_fk.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class RemoveAccessControlPostFk < ActiveRecord::Migration[6.0] + def change + remove_foreign_key :uploads, column: :access_control_post_id + end +end From f9d55b49416971023fce2b457d3d5384c2c52cac Mon Sep 17 00:00:00 2001 From: Martin Brennan Date: Fri, 22 May 2020 13:04:15 +1000 Subject: [PATCH 71/80] FEATURE: Update the topic excerpt when the OP is rebaked (#9852) * We now have a site setting "topic_excerpt_maxlength" that is used when the OP is created or revised to generate a topic excerpt. * However, posts created before this setting was introduced cannot benefit from this change unless they are revised, and if the topic excerpt length setting is changed that situation is also not covererd. * This PR makes a change to rebake! to update the topic excerpt IF the post is the OP. --- app/models/post.rb | 4 ++++ app/models/topic.rb | 7 +++++++ lib/post_revisor.rb | 6 +----- spec/models/post_spec.rb | 19 +++++++++++++++++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/models/post.rb b/app/models/post.rb index 30ebaf01630..e1a3a1f391e 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -650,6 +650,10 @@ class Post < ActiveRecord::Base baked_version: BAKED_VERSION ) + if is_first_post? + topic.update_excerpt(excerpt_for_topic) + end + if invalidate_broken_images custom_fields.delete(BROKEN_IMAGES) save_custom_fields diff --git a/app/models/topic.rb b/app/models/topic.rb index f02b4fc030f..38affdb327b 100644 --- a/app/models/topic.rb +++ b/app/models/topic.rb @@ -1476,6 +1476,13 @@ class Topic < ActiveRecord::Base private_topic end + def update_excerpt(excerpt) + update_column(:excerpt, excerpt) + if archetype == "banner" + ApplicationController.banner_json_cache.clear + end + end + def pm_with_non_human_user? sql = <<~SQL SELECT 1 FROM topics diff --git a/lib/post_revisor.rb b/lib/post_revisor.rb index 3c9ec277cdb..d610fccf375 100644 --- a/lib/post_revisor.rb +++ b/lib/post_revisor.rb @@ -567,11 +567,7 @@ class PostRevisor end def update_topic_excerpt - excerpt = @post.excerpt_for_topic - @topic.update_column(:excerpt, excerpt) - if @topic.archetype == "banner" - ApplicationController.banner_json_cache.clear - end + @topic.update_excerpt(@post.excerpt_for_topic) end def update_category_description diff --git a/spec/models/post_spec.rb b/spec/models/post_spec.rb index d0e2aba6319..5bc5206bced 100644 --- a/spec/models/post_spec.rb +++ b/spec/models/post_spec.rb @@ -1195,6 +1195,25 @@ describe Post do expect(post.cooked).to eq(first_cooked) expect(result).to eq(true) end + + it "updates the topic excerpt at the same time if it is the OP" do + post = create_post + post.topic.update(excerpt: "test") + DB.exec("UPDATE posts SET cooked = 'frogs' WHERE id = ?", [ post.id ]) + post.reload + result = post.rebake! + post.topic.reload + expect(post.topic.excerpt).not_to eq("test") + end + + it "does not update the topic excerpt if the post is not the OP" do + post = create_post + post2 = create_post + post.topic.update(excerpt: "test") + result = post2.rebake! + post.topic.reload + expect(post.topic.excerpt).to eq("test") + end end describe "#set_owner" do From 61d8955fcb165d2a55760279928306b47fb98898 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Fri, 22 May 2020 14:42:22 +0530 Subject: [PATCH 72/80] DEV: add spec for tag with unicode name --- spec/requests/list_controller_spec.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/requests/list_controller_spec.rb b/spec/requests/list_controller_spec.rb index d1238c1f00f..bc913c58a04 100644 --- a/spec/requests/list_controller_spec.rb +++ b/spec/requests/list_controller_spec.rb @@ -128,7 +128,7 @@ RSpec.describe ListController do let(:moderator) { Fabricate(:moderator) } let(:admin) { Fabricate(:admin) } let(:tag) { Fabricate(:tag) } - let(:private_message) { Fabricate(:private_message_topic) } + let(:private_message) { Fabricate(:private_message_topic, user: admin) } before do SiteSetting.tagging_enabled = true @@ -149,6 +149,17 @@ RSpec.describe ListController do expect(response.status).to eq(200) end end + + it 'should work for tag with unicode name' do + unicode_tag = Fabricate(:tag, name: 'hello-🇺🇸') + Fabricate(:topic_tag, tag: unicode_tag, topic: private_message) + + sign_in(admin) + get "/topics/private-messages-tags/#{admin.username}/#{UrlHelper.encode_component(unicode_tag.name)}.json" + expect(response.status).to eq(200) + expect(response.parsed_body["topic_list"]["topics"].first["id"]) + .to eq(private_message.id) + end end describe '#private_messages_group' do From e71f5e8951bcffdaac3476d96efaa2232b809a4c Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 22 May 2020 15:19:55 +0200 Subject: [PATCH 73/80] UI: apply margin only if the menu has content (#9857) --- app/assets/stylesheets/common/base/topic-post.scss | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 54aa976c0c0..55b9063ea79 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1012,13 +1012,15 @@ a.mention-group { display: flex; flex-wrap: wrap; - > .btn, - .topic-admin-menu-button-container { + > .btn { + display: inline-flex; margin: 0 0.5em 0.5em 0; } - .topic-admin-menu-button-container { + .topic-admin-menu-button-container > span:not(:empty) { display: inline-flex; + margin: 0 0 0.5em 0; + margin-right: 0.5em; } } From 793085c703608b345f12e94e3b53b7df07e5521e Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 22 May 2020 15:23:17 +0200 Subject: [PATCH 74/80] REFACTOR: slightly cleaner topic admin button css (#9858) --- app/assets/stylesheets/common/base/topic-post.scss | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index 55b9063ea79..b55bb190487 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1017,10 +1017,12 @@ a.mention-group { margin: 0 0.5em 0.5em 0; } - .topic-admin-menu-button-container > span:not(:empty) { + .topic-admin-menu-button-container { display: inline-flex; - margin: 0 0 0.5em 0; - margin-right: 0.5em; + } + + .topic-admin-menu-button-container > span:not(:empty) { + margin: 0 0.5em 0.5em 0; } } From f9649c92b5c9c2c850c993d47196a5a656d64547 Mon Sep 17 00:00:00 2001 From: Mark VanLandingham Date: Fri, 22 May 2020 09:37:35 -0500 Subject: [PATCH 75/80] FIX: Live reloading of css in development (#9859) --- .../discourse/app/lib/theme-selector.js | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app/assets/javascripts/discourse/app/lib/theme-selector.js b/app/assets/javascripts/discourse/app/lib/theme-selector.js index 2eb4912c9c1..48f63c31fbf 100644 --- a/app/assets/javascripts/discourse/app/lib/theme-selector.js +++ b/app/assets/javascripts/discourse/app/lib/theme-selector.js @@ -43,6 +43,41 @@ export function setLocalTheme(ids, themeSeq) { } } +export function refreshCSS(node, hash, newHref) { + let $orig = $(node); + + if ($orig.data("reloading")) { + clearTimeout($orig.data("timeout")); + $orig.data("copy").remove(); + } + + if (!$orig.data("orig")) { + $orig.data("orig", node.href); + } + + $orig.data("reloading", true); + + const orig = $(node).data("orig"); + + let reloaded = $orig.clone(true); + if (hash) { + reloaded[0].href = + orig + (orig.indexOf("?") >= 0 ? "&hash=" : "?hash=") + hash; + } else { + reloaded[0].href = newHref; + } + + $orig.after(reloaded); + + let timeout = setTimeout(() => { + $orig.remove(); + reloaded.data("reloading", false); + }, 2000); + + $orig.data("timeout", timeout); + $orig.data("copy", reloaded); +} + export function listThemes(site) { let themes = site.get("user_themes"); From 671f882fa34e4d4fcf68dfac1af3244244aa860f Mon Sep 17 00:00:00 2001 From: Roman Rizzi Date: Fri, 22 May 2020 11:50:28 -0300 Subject: [PATCH 76/80] FIX: We don't create a Post object if the queued post gets rejected. We need to count review items directly. (#9856) --- app/models/user.rb | 7 +++---- spec/models/user_spec.rb | 9 ++------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 5d162848ebb..d9678d1a1c7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1115,10 +1115,9 @@ class User < ActiveRecord::Base end def number_of_rejected_posts - Post.with_deleted - .where(user_id: self.id) - .joins('INNER JOIN reviewables r ON posts.id = r.target_id') - .where(r: { status: Reviewable.statuses[:rejected], type: ReviewableQueuedPost.name }) + ReviewableQueuedPost + .where(status: Reviewable.statuses[:rejected]) + .where(created_by_id: self.id) .count end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 89d5f627041..4d2592c788f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1578,20 +1578,15 @@ describe User do describe '#number_of_rejected_posts' do it 'counts rejected posts' do - post = Fabricate(:post, user: user) - - Fabricate(:reviewable_queued_post, target: post, status: Reviewable.statuses[:rejected]) + Fabricate(:reviewable_queued_post, created_by: user, status: Reviewable.statuses[:rejected]) expect(user.number_of_rejected_posts).to eq(1) end it 'ignore non-rejected posts' do - post = Fabricate(:post, user: user) - - Fabricate(:reviewable_queued_post, target: post, status: Reviewable.statuses[:approved]) + Fabricate(:reviewable_queued_post, created_by: user, status: Reviewable.statuses[:approved]) expect(user.number_of_rejected_posts).to eq(0) - end end end From 06e1d430c1aa84ca5c55ac60cc712f63416e3a44 Mon Sep 17 00:00:00 2001 From: Joffrey JAFFEUX Date: Fri, 22 May 2020 17:03:22 +0200 Subject: [PATCH 77/80] FIX: better cross browser topic footer buttons alignment (#9860) --- app/assets/stylesheets/common/base/topic-post.scss | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/common/base/topic-post.scss b/app/assets/stylesheets/common/base/topic-post.scss index b55bb190487..48c361c1647 100644 --- a/app/assets/stylesheets/common/base/topic-post.scss +++ b/app/assets/stylesheets/common/base/topic-post.scss @@ -1013,8 +1013,15 @@ a.mention-group { flex-wrap: wrap; > .btn { - display: inline-flex; margin: 0 0.5em 0.5em 0; + display: inline-flex; + align-items: center; + + .d-button-label { + display: flex; + flex: 1 0 auto; + align-items: center; + } } .topic-admin-menu-button-container { From 37128d71c7b9c5cd5f3d67989c7cbf5ddf126772 Mon Sep 17 00:00:00 2001 From: Ankur Dahiya Date: Fri, 22 May 2020 09:27:52 -0700 Subject: [PATCH 78/80] Add rails_helper to spec (#9861) --- .../spec/jobs/send_advanced_tutorial_message_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/discourse-narrative-bot/spec/jobs/send_advanced_tutorial_message_spec.rb b/plugins/discourse-narrative-bot/spec/jobs/send_advanced_tutorial_message_spec.rb index 5d3674cae08..874e40cfe81 100644 --- a/plugins/discourse-narrative-bot/spec/jobs/send_advanced_tutorial_message_spec.rb +++ b/plugins/discourse-narrative-bot/spec/jobs/send_advanced_tutorial_message_spec.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'rails_helper' + RSpec.describe Jobs::SendAdvancedTutorialMessage do before do Jobs.run_immediately! From bf8085e436f379ffabc5b217ea0cefdbb7430677 Mon Sep 17 00:00:00 2001 From: Jordan Vidrine <30537603+jordanvidrine@users.noreply.github.com> Date: Fri, 22 May 2020 13:33:29 -0500 Subject: [PATCH 79/80] FIX: Double Button Alignment Mobile (#9862) --- app/assets/stylesheets/mobile/topic-post.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/mobile/topic-post.scss b/app/assets/stylesheets/mobile/topic-post.scss index db68682303d..d84b4a727cf 100644 --- a/app/assets/stylesheets/mobile/topic-post.scss +++ b/app/assets/stylesheets/mobile/topic-post.scss @@ -36,6 +36,7 @@ span.badge-posts { .double-button { display: flex; flex: 0 1 auto; + align-items: center; button { &.like, &.read-indicator, From 03d26cd6f0f81794505eedf05e5416fddb3e578f Mon Sep 17 00:00:00 2001 From: Blake Erickson Date: Fri, 22 May 2020 14:54:37 -0600 Subject: [PATCH 80/80] SECURITY: ensure embed_url contains valid http(s) uri --- app/models/topic_embed.rb | 2 ++ lib/post_creator.rb | 4 ++++ spec/models/topic_embed_spec.rb | 8 ++++++++ spec/requests/posts_controller_spec.rb | 11 +++++++++++ 4 files changed, 25 insertions(+) diff --git a/app/models/topic_embed.rb b/app/models/topic_embed.rb index a18e5b85dea..362ee79f4ac 100644 --- a/app/models/topic_embed.rb +++ b/app/models/topic_embed.rb @@ -109,6 +109,8 @@ class TopicEmbed < ActiveRecord::Base url = UrlHelper.escape_uri(url) original_uri = URI.parse(url) + raise URI::InvalidURIError unless original_uri.is_a?(URI::HTTP) + opts = { tags: %w[div p code pre h1 h2 h3 b em i strong a img ul li ol blockquote], attributes: %w[href src class], diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 8a37e4c9c64..c3b9556df21 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -374,6 +374,10 @@ class PostCreator # discourse post. def create_embedded_topic return unless @opts[:embed_url].present? + + original_uri = URI.parse(@opts[:embed_url]) + raise Discourse::InvalidParameters.new(:embed_url) unless original_uri.is_a?(URI::HTTP) + embed = TopicEmbed.new(topic_id: @post.topic_id, post_id: @post.id, embed_url: @opts[:embed_url]) rollback_from_errors!(embed) unless embed.save end diff --git a/spec/models/topic_embed_spec.rb b/spec/models/topic_embed_spec.rb index ddfbe115ecf..c91781e6dd7 100644 --- a/spec/models/topic_embed_spec.rb +++ b/spec/models/topic_embed_spec.rb @@ -308,6 +308,14 @@ describe TopicEmbed do end end + context "non-http URL" do + let(:url) { '/test.txt' } + + it "throws an error" do + expect { TopicEmbed.find_remote(url) }.to raise_error(URI::InvalidURIError) + end + end + context "emails" do let(:url) { 'http://example.com/foo' } let(:contents) { '

URL encoded @ symbol

normal mailto link

' } diff --git a/spec/requests/posts_controller_spec.rb b/spec/requests/posts_controller_spec.rb index 909db8c509b..ff355ada967 100644 --- a/spec/requests/posts_controller_spec.rb +++ b/spec/requests/posts_controller_spec.rb @@ -675,6 +675,17 @@ describe PostsController do I18n.t("invalid_params", message: "category") ) end + + it 'will raise an error if specified embed_url is invalid' do + user = Fabricate(:admin) + master_key = Fabricate(:api_key).key + + post "/posts.json", + params: { title: 'this is a test title', raw: 'this is test body', embed_url: '/test.txt' }, + headers: { HTTP_API_USERNAME: user.username, HTTP_API_KEY: master_key } + + expect(response.status).to eq(422) + end end describe "when logged in" do