diff --git a/config/routes/knowledge_base.rb b/config/routes/knowledge_base.rb
index 209b4b0e6..0b7ea76d0 100644
--- a/config/routes/knowledge_base.rb
+++ b/config/routes/knowledge_base.rb
@@ -68,6 +68,8 @@ Zammad::Application.routes.draw do
get '', to: 'knowledge_base/public/categories#forward_root', as: :help_no_locale
get ':locale', to: 'knowledge_base/public/categories#index', as: :help_root
+ get ':locale/tag/:tag', to: 'knowledge_base/public/tags#show', as: :help_tag
+
get ':locale/:category', to: 'knowledge_base/public/categories#show', as: :help_category
get ':locale/:category/:answer', to: 'knowledge_base/public/answers#show', as: :help_answer
end
diff --git a/lib/search_knowledge_base_backend.rb b/lib/search_knowledge_base_backend.rb
index b3e179768..61484ce42 100644
--- a/lib/search_knowledge_base_backend.rb
+++ b/lib/search_knowledge_base_backend.rb
@@ -173,7 +173,7 @@ class SearchKnowledgeBaseBackend
if @params.fetch(:highlight_enabled, true)
output[:highlight_fields_by_indexes] = {
- 'KnowledgeBase::Answer::Translation': %w[title content.body attachment.content],
+ 'KnowledgeBase::Answer::Translation': %w[title content.body attachment.content tags],
'KnowledgeBase::Category::Translation': %w[title],
'KnowledgeBase::Translation': %w[title]
}
diff --git a/public/assets/images/icons.svg b/public/assets/images/icons.svg
index 922167867..34d8e364f 100644
--- a/public/assets/images/icons.svg
+++ b/public/assets/images/icons.svg
@@ -350,6 +350,11 @@
group
+
+
+ hashtag
+
+
help
diff --git a/public/assets/images/icons/hashtag.svg b/public/assets/images/icons/hashtag.svg
new file mode 100644
index 000000000..b989c751c
--- /dev/null
+++ b/public/assets/images/icons/hashtag.svg
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/spec/factories/knowledge_base/answer.rb b/spec/factories/knowledge_base/answer.rb
index a0b589430..909362695 100644
--- a/spec/factories/knowledge_base/answer.rb
+++ b/spec/factories/knowledge_base/answer.rb
@@ -3,10 +3,10 @@
FactoryBot.define do
factory 'knowledge_base/answer', aliases: %i[knowledge_base_answer] do
transient do
- add_translation { true }
- translation_traits { [] }
+ add_translation { true }
+ translation_traits { [] }
translation_attributes { {} }
- knowledge_base { nil }
+ knowledge_base { nil }
end
category { create(:knowledge_base_category, { knowledge_base: knowledge_base }.compact) }
@@ -43,6 +43,16 @@ FactoryBot.define do
end
end
+ trait :with_tag do
+ transient do
+ tag_names { %w[example_kb_tag] }
+ end
+
+ after(:create) do |answer, context|
+ context.tag_names.each { |tag| answer.tag_add tag }
+ end
+ end
+
trait :with_attachment do
transient do
attachment { File.open('spec/fixtures/upload/hello_world.txt') }
diff --git a/spec/models/knowledge_base/answer_spec.rb b/spec/models/knowledge_base/answer_spec.rb
index bed059945..d17bf7a7d 100644
--- a/spec/models/knowledge_base/answer_spec.rb
+++ b/spec/models/knowledge_base/answer_spec.rb
@@ -2,11 +2,14 @@
require 'rails_helper'
require 'models/concerns/checks_kb_client_notification_examples'
+require 'models/concerns/has_tags_examples'
require 'models/contexts/factory_context'
RSpec.describe KnowledgeBase::Answer, type: :model, current_user_id: 1 do
subject!(:kb_answer) { create(:knowledge_base_answer) }
+ it_behaves_like 'HasTags'
+
include_context 'factory'
it_behaves_like 'ChecksKbClientNotification'
diff --git a/spec/models/tag_spec.rb b/spec/models/tag_spec.rb
index af040f720..cbc8c9f09 100644
--- a/spec/models/tag_spec.rb
+++ b/spec/models/tag_spec.rb
@@ -167,7 +167,7 @@ RSpec.describe Tag, type: :model do
let(:object_1) { create(:ticket) }
let(:object_2) { create(:knowledge_base_answer) }
- let(:tag) { 'foo' }
+ let(:tag) { 'foo' }
it 'returns references' do
expect(described_class.tag_references(tag: tag)).to match_array [
diff --git a/spec/support/knowledge_base_contexts.rb b/spec/support/knowledge_base_contexts.rb
index d1db022be..55c9e9e00 100644
--- a/spec/support/knowledge_base_contexts.rb
+++ b/spec/support/knowledge_base_contexts.rb
@@ -9,6 +9,10 @@ RSpec.shared_context 'basic Knowledge Base', current_user_id: 1 do # rubocop:dis
knowledge_base.translation_primary.kb_locale
end
+ let :locale_name do
+ primary_locale.system_locale.locale
+ end
+
let :alternative_locale do
create(:knowledge_base_locale, knowledge_base: knowledge_base, system_locale: Locale.find_by(locale: 'lt'))
end
@@ -29,6 +33,14 @@ RSpec.shared_context 'basic Knowledge Base', current_user_id: 1 do # rubocop:dis
create(:knowledge_base_answer, :published, :with_video, category: category)
end
+ let :published_answer_with_tag do
+ create(:knowledge_base_answer, :published, :with_tag, tag_names: [published_answer_tag_name], category: category)
+ end
+
+ let(:published_answer_tag_name) do
+ 'example_kb_tag'
+ end
+
let :internal_answer do
create(:knowledge_base_answer, :internal, category: category)
end
diff --git a/spec/system/knowledge_base/locale/answer/edit_spec.rb b/spec/system/knowledge_base/locale/answer/edit_spec.rb
index bc1f333e9..be7ca43b2 100644
--- a/spec/system/knowledge_base/locale/answer/edit_spec.rb
+++ b/spec/system/knowledge_base/locale/answer/edit_spec.rb
@@ -87,4 +87,64 @@ RSpec.describe 'Knowledge Base Locale Answer Edit', type: :system do
expect(iframe['src']).to start_with('https://www.youtube.com/embed/')
end
end
+
+ context 'tags' do
+ before do
+ visit "#knowledge_base/#{knowledge_base.id}/locale/#{locale_name}/answer/#{published_answer_with_tag.id}/edit"
+ end
+
+ let(:new_tag_name) { 'capybara_kb_tag' }
+
+ it 'adds a new tag' do
+ within :active_content do
+ click '.js-newTagLabel'
+
+ elem = find('.js-newTagInput')
+ elem.fill_in with: new_tag_name
+ elem.send_keys :return
+
+ expect(page).to have_css('a.js-tag', text: new_tag_name)
+ end
+ end
+
+ it 'saves new tag to the database' do
+ within :active_content do
+ click '.js-newTagLabel'
+
+ elem = find('.js-newTagInput')
+ elem.fill_in with: new_tag_name
+ elem.send_keys :return
+
+ wait.until_exists { published_answer_with_tag.reload.tag_list.include? new_tag_name }
+ end
+ end
+
+ it 'shows an existing tag' do
+ within :active_content do
+ expect(page).to have_css('a.js-tag', text: published_answer_tag_name)
+ end
+ end
+
+ it 'deletes a tag' do
+ within :active_content do
+ click '.js-newTagLabel'
+
+ find('.list-item', text: published_answer_tag_name)
+ .find('.js-delete').click
+
+ expect(page).to have_no_css('a.js-tag', text: published_answer_tag_name)
+ end
+ end
+
+ it 'deletes the tag from the database' do
+ within :active_content do
+ click '.js-newTagLabel'
+
+ find('.list-item', text: published_answer_tag_name)
+ .find('.js-delete').click
+
+ wait.until_exists { published_answer_with_tag.reload.tag_list.exclude? published_answer_tag_name }
+ end
+ end
+ end
end
diff --git a/spec/system/knowledge_base/locale/answer/read_spec.rb b/spec/system/knowledge_base/locale/answer/read_spec.rb
new file mode 100644
index 000000000..6a97318aa
--- /dev/null
+++ b/spec/system/knowledge_base/locale/answer/read_spec.rb
@@ -0,0 +1,51 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+require 'rails_helper'
+
+RSpec.describe 'Knowledge Base Locale Answer Read', type: :system, authenticated_as: true do
+ include_context 'basic Knowledge Base'
+
+ describe 'tags' do
+ context 'when answer has tags' do
+ before do
+ visit "#knowledge_base/#{knowledge_base.id}/locale/#{locale_name}/answer/#{published_answer_with_tag.id}"
+ end
+
+ it 'has tags container' do
+ within :active_content do
+ expect(page).to have_css('.knowledge-base-article-tags--container')
+ end
+ end
+
+ it 'shows tag' do
+ within :active_content do
+ within '.knowledge-base-article-tags--container' do
+ expect(page).to have_css('a', text: published_answer_tag_name)
+ end
+ end
+ end
+
+ it 'opens search on clicking' do
+ within :active_content do
+ find('.knowledge-base-article-tags--container a', text: published_answer_tag_name).click
+ end
+
+ search_bar = find '#global-search'
+
+ expect(search_bar.value).to eq "tags:#{published_answer_tag_name}"
+ end
+ end
+
+ context 'when answer has no tags' do
+ before do
+ visit "#knowledge_base/#{knowledge_base.id}/locale/#{locale_name}/answer/#{published_answer.id}"
+ end
+
+ it 'has no tags container' do
+ within :active_content do
+ expect(page).to have_no_css('.knowledge-base-article-tags--container')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/system/knowledge_base_public/answer_spec.rb b/spec/system/knowledge_base_public/answer_spec.rb
index 546f4dc52..a11fc9aa5 100644
--- a/spec/system/knowledge_base_public/answer_spec.rb
+++ b/spec/system/knowledge_base_public/answer_spec.rb
@@ -18,4 +18,20 @@ RSpec.describe 'Public Knowledge Base answer', type: :system, authenticated_as:
expect(iframe['src']).to start_with('https://www.youtube.com/embed/')
end
end
+
+ context 'tags' do
+ before do
+ visit help_answer_path(locale_name, category, published_answer_with_tag)
+ end
+
+ it 'shows an associated tag' do
+ expect(page).to have_css('.tags a', text: published_answer_tag_name)
+ end
+
+ it 'links to tag page' do
+ click '.tags a'
+
+ expect(current_url).to end_with help_tag_path(locale_name, published_answer_tag_name)
+ end
+ end
end
diff --git a/spec/system/knowledge_base_public/canonical_link_spec.rb b/spec/system/knowledge_base_public/canonical_link_spec.rb
index 8bbec6f26..f32ffd515 100644
--- a/spec/system/knowledge_base_public/canonical_link_spec.rb
+++ b/spec/system/knowledge_base_public/canonical_link_spec.rb
@@ -31,6 +31,11 @@ RSpec.describe 'Public Knowledge Base canonical link', type: :system, current_us
visit help_answer_path(locale, published_answer.category, published_answer)
expect(page).to have_canonical_url("#{prefix}/#{locale}/#{category_slug}/#{answer_slug}")
end
+
+ it 'includes canonical link on tag page' do
+ visit help_tag_path(locale, published_answer_tag_name)
+ expect(page).to have_canonical_url("#{prefix}/#{locale}/tag/#{published_answer_tag_name}")
+ end
end
shared_examples 'core locations' do
diff --git a/spec/system/knowledge_base_public/tag_spec.rb b/spec/system/knowledge_base_public/tag_spec.rb
new file mode 100644
index 000000000..d963ff89a
--- /dev/null
+++ b/spec/system/knowledge_base_public/tag_spec.rb
@@ -0,0 +1,51 @@
+# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
+
+require 'rails_helper'
+
+RSpec.describe 'Public Knowledge Base tag', type: :system, authenticated_as: false do
+ include_context 'basic Knowledge Base'
+
+ context 'when answer with the tag exists' do
+ before do
+ published_answer && published_answer_with_tag
+
+ visit help_tag_path(locale_name, published_answer_tag_name)
+ end
+
+ it 'displays tag name' do
+ expect(page).to have_css('h1', text: published_answer_tag_name)
+ end
+
+ it 'lists an answer with the tag' do
+ expect(page).to have_css('a', text: published_answer_with_tag.translations.first.title)
+ end
+
+ it 'does not list another answer' do
+ expect(page).to have_no_css('a', text: published_answer.translations.first.title)
+ end
+
+ it 'does not show empty placeholder' do
+ expect(page).to have_no_css('.sections-empty')
+ end
+ end
+
+ context 'when no answers with the tag exists' do
+ before do
+ published_answer
+
+ visit help_tag_path(locale_name, published_answer_tag_name)
+ end
+
+ it 'shows empty placeholder' do
+ expect(page).to have_css('.sections-empty')
+ end
+
+ it 'shows no links' do
+ expect(page).to have_no_css('.main a')
+ end
+
+ it 'displays tag name' do
+ expect(page).to have_css('h1', text: published_answer_tag_name)
+ end
+ end
+end