From b9ac752e3bdeecc9e8e3b255dc9f60363d17bf63 Mon Sep 17 00:00:00 2001 From: Thomas von Deyen Date: Mon, 16 Nov 2020 17:15:47 +0100 Subject: [PATCH] Add authorization to pages controllers Authorized users can now access unpublished pages as well. --- .../alchemy/json_api/base_controller.rb | 1 + .../alchemy/json_api/pages_controller.rb | 9 ++- .../alchemy/json_api/layout_pages_spec.rb | 55 +++++++++++++++++-- spec/requests/alchemy/json_api/pages_spec.rb | 55 +++++++++++++++++-- 4 files changed, 106 insertions(+), 14 deletions(-) diff --git a/app/controllers/alchemy/json_api/base_controller.rb b/app/controllers/alchemy/json_api/base_controller.rb index 13d0535..c279c86 100644 --- a/app/controllers/alchemy/json_api/base_controller.rb +++ b/app/controllers/alchemy/json_api/base_controller.rb @@ -3,6 +3,7 @@ module Alchemy module JsonApi class BaseController < ::ApplicationController include Alchemy::ControllerActions + include Alchemy::AbilityHelper include JSONAPI::Fetching include JSONAPI::Errors include JSONAPI::Filtering diff --git a/app/controllers/alchemy/json_api/pages_controller.rb b/app/controllers/alchemy/json_api/pages_controller.rb index 9ac3d84..5b0a8ab 100644 --- a/app/controllers/alchemy/json_api/pages_controller.rb +++ b/app/controllers/alchemy/json_api/pages_controller.rb @@ -46,9 +46,14 @@ def page_scope end def base_page_scope - ::Alchemy::Page. + # cancancan is not able to merge our complex AR scopes for logged in users + if can?(:edit_content, Page) + pages = Page.all + else + pages = Page.accessible_by(current_ability, :index) + end + pages. with_language(Language.current). - published. preload(language: {nodes: [:parent, :page]}, all_elements: [:parent_element, :nested_elements, { contents: { essence: :ingredient_association } }]) end diff --git a/spec/requests/alchemy/json_api/layout_pages_spec.rb b/spec/requests/alchemy/json_api/layout_pages_spec.rb index 7687493..cec2364 100644 --- a/spec/requests/alchemy/json_api/layout_pages_spec.rb +++ b/spec/requests/alchemy/json_api/layout_pages_spec.rb @@ -2,6 +2,7 @@ require "rails_helper" require "alchemy/test_support/factories/page_factory" require "alchemy/test_support/factories/element_factory" +require "alchemy/devise/test_support/factories" RSpec.describe "Alchemy::JsonApi::LayoutPagesController", type: :request do let(:page) do @@ -53,6 +54,30 @@ expect(response).to have_http_status(404) end end + + context "when requesting an unpublished layout page" do + let(:page) { FactoryBot.create(:alchemy_page, :layoutpage) } + + context "as anonymous user" do + it "returns a 404" do + get alchemy_json_api.layout_page_path(page.urlname) + expect(response).to have_http_status(404) + end + end + + context "as admin" do + before do + allow_any_instance_of(ApplicationController).to receive(:current_user) do + FactoryBot.create(:alchemy_admin_user) + end + end + + it "finds the page" do + get alchemy_json_api.layout_page_path(page.urlname) + expect(response).to have_http_status(200) + end + end + end end describe "GET /alchemy/json_api/layout_pages" do @@ -61,12 +86,30 @@ let!(:non_public_layout_page) { FactoryBot.create(:alchemy_page, :layoutpage) } let!(:public_page) { FactoryBot.create(:alchemy_page, :public) } - it "returns only public layout pages" do - get alchemy_json_api.layout_pages_path - document = JSON.parse(response.body) - expect(document["data"]).to include(have_id(layoutpage.id.to_s)) - expect(document["data"]).not_to include(have_id(non_public_layout_page.id.to_s)) - expect(document["data"]).not_to include(have_id(public_page.id.to_s)) + context "as anonymous user" do + it "returns only public layout pages" do + get alchemy_json_api.layout_pages_path + document = JSON.parse(response.body) + expect(document["data"]).to include(have_id(layoutpage.id.to_s)) + expect(document["data"]).not_to include(have_id(non_public_layout_page.id.to_s)) + expect(document["data"]).not_to include(have_id(public_page.id.to_s)) + end + end + + context "as admin user" do + before do + allow_any_instance_of(ApplicationController).to receive(:current_user) do + FactoryBot.create(:alchemy_admin_user) + end + end + + it "returns all layout pages" do + get alchemy_json_api.layout_pages_path + document = JSON.parse(response.body) + expect(document["data"]).to include(have_id(layoutpage.id.to_s)) + expect(document["data"]).to include(have_id(non_public_layout_page.id.to_s)) + expect(document["data"]).not_to include(have_id(public_page.id.to_s)) + end end end diff --git a/spec/requests/alchemy/json_api/pages_spec.rb b/spec/requests/alchemy/json_api/pages_spec.rb index dbbf301..d6a1f95 100644 --- a/spec/requests/alchemy/json_api/pages_spec.rb +++ b/spec/requests/alchemy/json_api/pages_spec.rb @@ -2,6 +2,7 @@ require "rails_helper" require "alchemy/test_support/factories/page_factory" require "alchemy/test_support/factories/element_factory" +require "alchemy/devise/test_support/factories" RSpec.describe "Alchemy::JsonApi::Pages", type: :request do let(:page) do @@ -71,6 +72,30 @@ expect(response).to have_http_status(404) end end + + context "when requesting an unpublished page" do + let(:page) { FactoryBot.create(:alchemy_page) } + + context "as anonymous user" do + it "returns a 404" do + get alchemy_json_api.page_path(page.urlname) + expect(response).to have_http_status(404) + end + end + + context "as admin" do + before do + allow_any_instance_of(ApplicationController).to receive(:current_user) do + FactoryBot.create(:alchemy_admin_user) + end + end + + it "finds the page" do + get alchemy_json_api.page_path(page.urlname) + expect(response).to have_http_status(200) + end + end + end end describe "GET /alchemy/json_api/pages" do @@ -79,12 +104,30 @@ let!(:non_public_page) { FactoryBot.create(:alchemy_page) } let!(:public_page) { FactoryBot.create(:alchemy_page, :public) } - it "returns public content pages only" do - get alchemy_json_api.pages_path - document = JSON.parse(response.body) - expect(document["data"]).not_to include(have_id(layoutpage.id.to_s)) - expect(document["data"]).not_to include(have_id(non_public_page.id.to_s)) - expect(document["data"]).to include(have_id(public_page.id.to_s)) + context "as anonymous user" do + it "returns public content pages only" do + get alchemy_json_api.pages_path + document = JSON.parse(response.body) + expect(document["data"]).not_to include(have_id(layoutpage.id.to_s)) + expect(document["data"]).not_to include(have_id(non_public_page.id.to_s)) + expect(document["data"]).to include(have_id(public_page.id.to_s)) + end + end + + context "as admin user" do + before do + allow_any_instance_of(ApplicationController).to receive(:current_user) do + FactoryBot.create(:alchemy_admin_user) + end + end + + it "returns all content pages" do + get alchemy_json_api.pages_path + document = JSON.parse(response.body) + expect(document["data"]).not_to include(have_id(layoutpage.id.to_s)) + expect(document["data"]).to include(have_id(non_public_page.id.to_s)) + expect(document["data"]).to include(have_id(public_page.id.to_s)) + end end end