diff --git a/app/assets/javascripts/alchemy/templates/page.hbs b/app/assets/javascripts/alchemy/templates/page.hbs index 81748efe20..8eb772da82 100644 --- a/app/assets/javascripts/alchemy/templates/page.hbs +++ b/app/assets/javascripts/alchemy/templates/page.hbs @@ -1,9 +1,19 @@
- - - {{ page.name }} - - - {{ page.url_path }} - +
+ + + {{ page.name }} + + + {{ page.url_path }} + +
+
+ + {{ page.site.name }} + + + {{ page.language.name }} + +
diff --git a/app/assets/stylesheets/alchemy/page-select.scss b/app/assets/stylesheets/alchemy/page-select.scss index c6fe0760be..c944cd3c72 100644 --- a/app/assets/stylesheets/alchemy/page-select.scss +++ b/app/assets/stylesheets/alchemy/page-select.scss @@ -8,24 +8,49 @@ .page-select--page { display: flex; - align-items: center; + flex-direction: column; .icon { margin: 0 8px 0 4px; .select2-highlighted & { - color: $white + color: $white; } } } +.page-select--top, +.page-select--bottom { + display: flex; + flex-direction: row; + align-items: center; +} + +.page-select--bottom { + font-size: $small-font-size; + padding-left: 6 * $default-padding; +} + +.page-select--language-code { + display: inline-block; + background-color: $medium-gray; + margin-left: auto; + border-radius: $default-border-radius; + padding: $default-padding / 2 $default-padding; + + .select2-highlighted & { + color: $select-hover-bg-color; + background-color: white; + } +} + .page-select--page-urlname { margin-left: auto; - padding: $default-padding 2*$default-padding; + padding: $default-padding 2 * $default-padding; color: $dark-gray; font-size: $small-font-size; .select2-highlighted & { - color: $white + color: $white; } } diff --git a/app/controllers/alchemy/api/pages_controller.rb b/app/controllers/alchemy/api/pages_controller.rb index 48af2ee2ad..7a914fc41c 100644 --- a/app/controllers/alchemy/api/pages_controller.rb +++ b/app/controllers/alchemy/api/pages_controller.rb @@ -2,19 +2,19 @@ module Alchemy class Api::PagesController < Api::BaseController + serialization_scope :current_ability before_action :load_page, only: [:show] # Returns all pages as json object # def index - language = Alchemy::Language.find_by(id: params[:language_id]) || Alchemy::Language.current - # Fix for cancancan not able to merge multiple AR scopes for logged in users - if cannot? :edit_content, Alchemy::Page + if can? :edit_content, Alchemy::Page + @pages = Alchemy::Page.all + else + language = Alchemy::Language.find_by(id: params[:language_id]) || Alchemy::Language.current @pages = Alchemy::Page.accessible_by(current_ability, :index) @pages = @pages.where(language: language) - else - @pages = language&.pages.presence || Alchemy::Page.none end @pages = @pages.includes(*page_includes) @pages = @pages.ransack(params[:q]).result diff --git a/app/serializers/alchemy/page_serializer.rb b/app/serializers/alchemy/page_serializer.rb index 34d68bd500..59c16a773a 100644 --- a/app/serializers/alchemy/page_serializer.rb +++ b/app/serializers/alchemy/page_serializer.rb @@ -18,5 +18,10 @@ class PageSerializer < ActiveModel::Serializer :parent_id has_many :elements + + with_options if: -> { scope.can?(:edit_content, object) } do + belongs_to :site + belongs_to :language + end end end diff --git a/spec/controllers/alchemy/api/pages_controller_spec.rb b/spec/controllers/alchemy/api/pages_controller_spec.rb index 4db2105b10..45502e2722 100644 --- a/spec/controllers/alchemy/api/pages_controller_spec.rb +++ b/spec/controllers/alchemy/api/pages_controller_spec.rb @@ -10,7 +10,6 @@ module Alchemy let(:result) { JSON.parse(response.body) } context "without a default language present" do - it "returns JSON" do get :index, params: { format: :json } expect(result["pages"]).to eq([]) @@ -87,10 +86,27 @@ module Alchemy let(:language_2) { create(:alchemy_language, site: site_2) } let!(:site_2_page) { create(:alchemy_page, :public, language: language_2) } - it "only returns pages for current site" do - get :index, format: :json + context "as guest user" do + it "only returns pages for current site" do + get :index, format: :json + expect(result["pages"].map { |r| r["id"] }).to eq([page.parent_id, page.id]) + end + end + + context "as author user" do + before do + authorize_user(build(:alchemy_dummy_user, :as_author)) + end - expect(result["pages"].map { |r| r["id"] }).to_not include(site_2_page.id) + it "returns all pages" do + get :index, format: :json + expect(result["pages"].map { |r| r["id"] }).to eq([ + page.parent_id, + page.id, + site_2_page.parent_id, + site_2_page.id, + ]) + end end end diff --git a/spec/serializers/alchemy/page_serializer_spec.rb b/spec/serializers/alchemy/page_serializer_spec.rb new file mode 100644 index 0000000000..2345f21091 --- /dev/null +++ b/spec/serializers/alchemy/page_serializer_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe Alchemy::PageSerializer do + subject do + described_class.new(page, scope: Alchemy::Permissions.new(user)).to_json + end + + let(:page) { build_stubbed(:alchemy_page) } + + context "for guest user" do + let(:user) { nil } + + it "includes public attributes" do + json = JSON.parse(subject) + expect(json).to match( + "id" => page.id, + "name" => page.name, + "urlname" => page.urlname, + "page_layout" => page.page_layout, + "title" => page.title, + "language_code" => page.language_code, + "meta_keywords" => page.meta_keywords, + "meta_description" => page.meta_description, + "tag_list" => page.tag_list, + "created_at" => an_instance_of(String), + "updated_at" => an_instance_of(String), + "status" => page.status.transform_keys(&:to_s), + "url_path" => page.url_path, + "parent_id" => page.parent_id, + "elements" => [], + ) + end + end + + context "for admin user" do + let(:user) { build_stubbed(:alchemy_dummy_user, :as_author) } + + it "includes all attributes" do + json = JSON.parse(subject) + expect(json).to match( + "id" => page.id, + "name" => page.name, + "urlname" => page.urlname, + "page_layout" => page.page_layout, + "title" => page.title, + "language_code" => page.language_code, + "meta_keywords" => page.meta_keywords, + "meta_description" => page.meta_description, + "tag_list" => page.tag_list, + "created_at" => an_instance_of(String), + "updated_at" => an_instance_of(String), + "status" => page.status.transform_keys(&:to_s), + "url_path" => page.url_path, + "parent_id" => page.parent_id, + "elements" => [], + "site" => { + "id" => page.site.id, + "aliases" => nil, + "created_at" => an_instance_of(String), + "host" => "*", + "name" => "Default Site", + "public" => true, + "redirect_to_primary_host" => false, + "updated_at" => an_instance_of(String), + }, + "language" => { + "country_code" => "", + "created_at" => an_instance_of(String), + "creator_id" => nil, + "default" => true, + "frontpage_name" => "Intro", + "id" => page.language_id, + "language_code" => "en", + "locale" => "en", + "name" => "Your Language", + "page_layout" => "index", + "public" => true, + "site_id" => page.site.id, + "updated_at" => an_instance_of(String), + "updater_id" => nil, + }, + ) + end + end +end