diff --git a/app/assets/javascripts/discourse/app/lib/hashtag-types/category.js b/app/assets/javascripts/discourse/app/lib/hashtag-types/category.js index ffb8f3001d4..e37a8e6617b 100644 --- a/app/assets/javascripts/discourse/app/lib/hashtag-types/category.js +++ b/app/assets/javascripts/discourse/app/lib/hashtag-types/category.js @@ -31,6 +31,10 @@ export default class CategoryHashtagType extends HashtagTypeBase { } generateIconHTML(hashtag) { - return ``; + const hashtagId = parseInt(hashtag.id, 10); + const colorCssClass = !this.preloadedData.mapBy("id").includes(hashtagId) + ? "hashtag-missing" + : `hashtag-color--${this.type}-${hashtag.id}`; + return ``; } } diff --git a/app/assets/stylesheets/common/components/hashtag.scss b/app/assets/stylesheets/common/components/hashtag.scss index ab328819ddb..9c9825d9d28 100644 --- a/app/assets/stylesheets/common/components/hashtag.scss +++ b/app/assets/stylesheets/common/components/hashtag.scss @@ -25,6 +25,10 @@ a.hashtag { .d-icon { font-size: var(--font-down-1); margin: 0 0.2em 0 0.1em; + + &.hashtag-missing { + color: var(--primary-medium); + } } img.emoji { @@ -43,6 +47,10 @@ a.hashtag { height: 9px; margin-right: 5px; display: inline-block; + + &.hashtag-missing { + background-color: var(--primary-medium); + } } } diff --git a/plugins/chat/assets/javascripts/discourse/lib/hashtag-types/channel.js b/plugins/chat/assets/javascripts/discourse/lib/hashtag-types/channel.js index 5e49cb37e31..f49216bbb38 100644 --- a/plugins/chat/assets/javascripts/discourse/lib/hashtag-types/channel.js +++ b/plugins/chat/assets/javascripts/discourse/lib/hashtag-types/channel.js @@ -25,8 +25,12 @@ export default class ChannelHashtagType extends HashtagTypeBase { } generateIconHTML(hashtag) { + const hashtagId = parseInt(hashtag.id, 10); + const colorCssClass = !this.preloadedData.mapBy("id").includes(hashtagId) + ? "hashtag-missing" + : `hashtag-color--${this.type}-${hashtag.id}`; return iconHTML(hashtag.icon, { - class: `hashtag-color--${this.type}-${hashtag.id}`, + class: colorCssClass, }); } } diff --git a/plugins/chat/spec/system/hashtag_autocomplete_spec.rb b/plugins/chat/spec/system/hashtag_autocomplete_spec.rb index 2973832dd67..d7d3c7d5ec4 100644 --- a/plugins/chat/spec/system/hashtag_autocomplete_spec.rb +++ b/plugins/chat/spec/system/hashtag_autocomplete_spec.rb @@ -80,4 +80,44 @@ describe "Using #hashtag autocompletion to search for and lookup channels", razed HTML end + + context "when a user cannot access the category for a cooked channel hashtag" do + fab!(:admin) { Fabricate(:admin) } + fab!(:manager_group) { Fabricate(:group, name: "Managers") } + fab!(:private_category) do + Fabricate(:private_category, name: "Management", slug: "management", group: manager_group) + end + fab!(:admin_group_user) { Fabricate(:group_user, user: admin, group: manager_group) } + fab!(:management_channel) do + Fabricate(:chat_channel, chatable: private_category, slug: "management") + end + fab!(:post_with_private_category) do + Fabricate( + :post, + topic: topic, + raw: "this is a secret #management::channel channel", + user: admin, + ) + end + fab!(:message_with_private_channel) do + Fabricate( + :chat_message, + chat_channel: channel1, + user: admin, + message: "this is a secret #management channel", + ) + end + + before { management_channel.add(admin) } + + it "shows a default color and css class for the channel icon in a post" do + topic_page.visit_topic(topic, post_number: post_with_private_category.post_number) + expect(page).to have_css(".hashtag-cooked .hashtag-missing") + end + + it "shows a default color and css class for the channel icon in a channel" do + chat_page.visit_channel(channel1) + expect(page).to have_css(".hashtag-cooked .hashtag-missing") + end + end end diff --git a/spec/system/hashtag_autocomplete_spec.rb b/spec/system/hashtag_autocomplete_spec.rb index cc7d40a94df..da22f0728fd 100644 --- a/spec/system/hashtag_autocomplete_spec.rb +++ b/spec/system/hashtag_autocomplete_spec.rb @@ -93,4 +93,21 @@ describe "Using #hashtag autocompletion to search for and lookup categories and cooltag HTML end + + context "when a user cannot access the category for a hashtag cooked in another post" do + fab!(:admin) { Fabricate(:admin) } + fab!(:manager_group) { Fabricate(:group, name: "Managers") } + fab!(:private_category) do + Fabricate(:private_category, name: "Management", slug: "management", group: manager_group) + end + fab!(:admin_group_user) { Fabricate(:group_user, user: admin, group: manager_group) } + fab!(:post_with_private_category) do + Fabricate(:post, topic: topic, raw: "this is a secret #management category", user: admin) + end + + it "shows a default color and css class for the category icon square" do + topic_page.visit_topic(topic, post_number: post_with_private_category.post_number) + expect(page).to have_css(".hashtag-cooked .hashtag-missing") + end + end end diff --git a/spec/system/page_objects/pages/topic.rb b/spec/system/page_objects/pages/topic.rb index dbc56fe3d40..15b7e23c926 100644 --- a/spec/system/page_objects/pages/topic.rb +++ b/spec/system/page_objects/pages/topic.rb @@ -8,8 +8,10 @@ module PageObjects @fast_edit_component = PageObjects::Components::FastEditor.new end - def visit_topic(topic) - page.visit "/t/#{topic.id}" + def visit_topic(topic, post_number: nil) + url = "/t/#{topic.id}" + url += "/#{post_number}" if post_number + page.visit url self end