Browse Source

Fixes #4403 - Can not use RSS feed in Microsoft Teams (invalid url).

Mantas Masalskis 2 years ago
parent
commit
33fff229f8

+ 28 - 5
app/controllers/knowledge_base/feeds_controller.rb

@@ -1,6 +1,8 @@
 # Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
 
 class KnowledgeBase::FeedsController < KnowledgeBase::BaseController
+  ITEMS_IN_FEED = 10
+
   prepend_before_action { authorize! }
   skip_before_action :authentication_check
   prepend_before_action -> { authentication_check_only }, only: %i[root category]
@@ -20,7 +22,7 @@ class KnowledgeBase::FeedsController < KnowledgeBase::BaseController
     @answers = scope
       .localed(@locale)
       .sorted_by_internally_published
-      .limit(10)
+      .limit(ITEMS_IN_FEED)
 
     render :feed
   end
@@ -37,7 +39,7 @@ class KnowledgeBase::FeedsController < KnowledgeBase::BaseController
     @answers = scope
       .localed(@locale)
       .sorted_by_internally_published
-      .limit(10)
+      .limit(ITEMS_IN_FEED)
 
     render :feed
   end
@@ -48,15 +50,36 @@ class KnowledgeBase::FeedsController < KnowledgeBase::BaseController
     categories = KnowledgeBase::InternalAssets
       .new(effective_user, categories_filter: category_filter)
       .accessible_categories
-      .all
 
-    @knowledge_base.answers.where(category_id: categories)
+    if categories.public_reader.none?
+      return @knowledge_base.answers.where(category_id: categories.all)
+    end
+
+    answer_ids = granular_public_answers_ids(categories) + granular_internal_answers_ids(categories)
+
+    @knowledge_base.answers.where(id: answer_ids)
+  end
+
+  def granular_public_answers_ids(categories)
+    @knowledge_base.answers
+      .where(category_id: categories.public_reader)
+      .sorted_by_published
+      .limit(ITEMS_IN_FEED)
+      .pluck(:id)
+  end
+
+  def granular_internal_answers_ids(categories)
+    @knowledge_base.answers
+      .where(category_id: categories.internally_visible)
+      .sorted_by_internally_published
+      .limit(ITEMS_IN_FEED)
+      .pluck(:id)
   end
 
   def effective_user
     return current_user if current_user.present?
 
-    Token.check(action: 'KnowledgeBaseFeed', name: given_token)
+    Token.check(action: 'KnowledgeBaseFeed', name: params[:token])
   end
 
   def ensure_response_format

+ 4 - 0
lib/knowledge_base/internal_assets.rb

@@ -6,6 +6,10 @@ class KnowledgeBase
       def all
         editor + reader + public_reader
       end
+
+      def internally_visible
+        editor + reader
+      end
     end
 
     attr_reader :assets

+ 100 - 0
spec/requests/knowledge_base/feed_spec.rb

@@ -69,4 +69,104 @@ RSpec.describe 'KnowledgeBase feed', authenticated_as: :user, type: :request do
       expect(response).to have_http_status :ok
     end
   end
+
+  context 'with granular permissions', :aggregate_failures do
+    before do
+      admin = create(:admin)
+      internal_answer
+      published_answer
+      KnowledgeBase::PermissionsUpdate.new(category, admin).update_using_params!(granular_permissions)
+    end
+
+    let(:role_admin)   { Role.find_by(name: 'Admin') }
+    let(:role_agent)   { Role.find_by(name: 'Agent') }
+
+    let(:granular_permissions) do
+      {
+        permissions: {
+          role_admin.id => 'editor',
+          role_agent.id => 'none'
+        }
+      }
+    end
+
+    context 'with admin user' do
+      let(:user) { create(:admin) }
+
+      it 'shows answer in root' do
+        get feed_knowledge_base_path(knowledge_base, locale_name)
+
+        expect(response).to have_http_status :ok
+        expect(response.body).to include internal_answer.translations.first.title
+        expect(response.body).to include published_answer.translations.first.title
+      end
+
+      it 'shows answer in category' do
+        get feed_knowledge_base_category_path(knowledge_base, category, locale_name)
+
+        expect(response).to have_http_status :ok
+        expect(response.body).to include internal_answer.translations.first.title
+        expect(response.body).to include published_answer.translations.first.title
+      end
+
+      context 'with a token', authenticated_as: false do
+        let(:token) { Token.ensure_token! 'KnowledgeBaseFeed', user.id }
+
+        it 'shows answer in root' do
+          get feed_knowledge_base_path(knowledge_base, locale_name, token: token)
+
+          expect(response).to have_http_status :ok
+          expect(response.body).to include internal_answer.translations.first.title
+          expect(response.body).to include published_answer.translations.first.title
+        end
+
+        it 'shows answer in category' do
+          get feed_knowledge_base_category_path(knowledge_base, category, locale_name, token: token)
+
+          expect(response).to have_http_status :ok
+          expect(response.body).to include internal_answer.translations.first.title
+          expect(response.body).to include published_answer.translations.first.title
+        end
+      end
+    end
+
+    context 'with agent user' do
+      let(:user) { create(:agent) }
+      let(:token) { Token.ensure_token! 'KnowledgeBaseFeed', user.id }
+
+      it 'does not show answer in root' do
+        get feed_knowledge_base_path(knowledge_base, locale_name)
+
+        expect(response).to have_http_status :ok
+        expect(response.body).not_to include internal_answer.translations.first.title
+        expect(response.body).to include published_answer.translations.first.title
+      end
+
+      it 'shows answer in category' do
+        get feed_knowledge_base_category_path(knowledge_base, category, locale_name)
+
+        expect(response).to have_http_status :ok
+        expect(response.body).not_to include internal_answer.translations.first.title
+        expect(response.body).to include published_answer.translations.first.title
+      end
+
+      context 'with a token', authenticated_as: false do
+        it 'does not show answer in root' do
+          get feed_knowledge_base_path(knowledge_base, locale_name, token: token)
+
+          expect(response).to have_http_status :ok
+          expect(response.body).not_to include internal_answer.translations.first.title
+          expect(response.body).to include published_answer.translations.first.title
+        end
+
+        it 'shows answer in category' do
+          get feed_knowledge_base_category_path(knowledge_base, category, locale_name, token: token)
+
+          expect(response).to have_http_status :ok
+          expect(response.body).not_to include internal_answer.translations.first.title
+          expect(response.body).to include published_answer.translations.first.title
+        end
+      end
+    end
+  end
 end