alchemy-json_api 0.12.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec8c154e4f6ac5ba72d6d96b39a60475acf9b0d411d3a4e2d34c81fc271d1489
4
- data.tar.gz: c0cc273e02b2038e5462428fa1f7d0960be37ccf8225abd76af7343ca4f76ec0
3
+ metadata.gz: 369f587874aab63134861d26c9b1babfc0d0ba7d25a981bd2a977bf00d847b48
4
+ data.tar.gz: 3e3e10d5862df03767a538fe785b17d67d88a1e02151fa0a6b67b45370876960
5
5
  SHA512:
6
- metadata.gz: 2f0ebd08816a2d97347555eaf114735b429ec7c1e2592f9c1ff0b652be9f0799c782489987eac5d3142d5f5246ac6f02375460d62931ef4cfcca4f8a3e9ad809
7
- data.tar.gz: '08c7a5e5570c995b3495844bcceb9a145173cb3e224fce0051a5b672eae408aee58850e1b612fb25051c0896c571365481daabe28d7e4766b62742e1b0363e34'
6
+ metadata.gz: 7f7b3074e7c9e446e22c12f8f8fffe64a2548ede87af8a22515efe53edc9060e2446d8cf9e2bd4511941158920e55e9cce5478b876fe4e9438d2d63d60df8cb6
7
+ data.tar.gz: c68a930b025975095291d0cf53d8f7cbba2a65e309ac4a0d24ef2db5966b4bc157cc35f199c2f69c3c2e8503de20517f19594a6ef3afac12f82eb124373ee170
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+ module Alchemy
3
+ module JsonApi
4
+ module Admin
5
+ class LayoutPagesController < JsonApi::Admin::PagesController
6
+ private
7
+
8
+ def page_scope
9
+ page_scope_with_includes.layoutpages
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+ module Alchemy
3
+ module JsonApi
4
+ module Admin
5
+ class PagesController < JsonApi::PagesController
6
+ prepend_before_action { authorize! :edit_content, Alchemy::Page }
7
+
8
+ private
9
+
10
+ def page_version_type
11
+ :draft_version
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -9,6 +9,11 @@ module Alchemy
9
9
  include JSONAPI::Filtering
10
10
  include JSONAPI::Pagination
11
11
 
12
+ rescue_from(
13
+ CanCan::AccessDenied,
14
+ with: :render_jsonapi_unauthorized,
15
+ )
16
+
12
17
  private
13
18
 
14
19
  def render_jsonapi_internal_server_error(exception)
@@ -25,6 +30,11 @@ module Alchemy
25
30
  message << " " << exception.backtrace.join("\n ")
26
31
  logger.fatal("#{message}\n\n")
27
32
  end
33
+
34
+ def render_jsonapi_unauthorized(exception)
35
+ error = { status: "401", title: Rack::Utils::HTTP_STATUS_CODES[401] }
36
+ render jsonapi_errors: [error], status: :unauthorized
37
+ end
28
38
  end
29
39
  end
30
40
  end
@@ -4,10 +4,6 @@ module Alchemy
4
4
  class LayoutPagesController < JsonApi::PagesController
5
5
  private
6
6
 
7
- def base_page_scope
8
- ::Alchemy::JsonApi::Page.all
9
- end
10
-
11
7
  def page_scope
12
8
  page_scope_with_includes.layoutpages
13
9
  end
@@ -9,14 +9,16 @@ module Alchemy
9
9
  allowed = [:page_layout]
10
10
 
11
11
  jsonapi_filter(page_scope, allowed) do |filtered|
12
- jsonapi_paginate(filtered.result) do |paginated|
12
+ # decorate with our page model that has a eager loaded elements collection
13
+ pages = filtered.result.map { |page| api_page(page) }
14
+ jsonapi_paginate(pages) do |paginated|
13
15
  render jsonapi: paginated
14
16
  end
15
17
  end
16
18
  end
17
19
 
18
20
  def show
19
- render jsonapi: @page
21
+ render jsonapi: api_page(@page)
20
22
  end
21
23
 
22
24
  private
@@ -26,7 +28,7 @@ module Alchemy
26
28
 
27
29
  {
28
30
  pagination: pagination.presence,
29
- total: page_scope.count
31
+ total: page_scope.count,
30
32
  }.compact
31
33
  end
32
34
 
@@ -49,16 +51,37 @@ module Alchemy
49
51
 
50
52
  def page_scope_with_includes
51
53
  base_page_scope.
52
- with_language(Language.current).
53
- preload(language: { nodes: [:parent, :page, :children] }, all_elements: { contents: { essence: :ingredient_association } })
54
+ where(language: Language.current).
55
+ includes(
56
+ [
57
+ :legacy_urls,
58
+ { language: { nodes: [:parent, :children, { page: { language: { site: :languages } } }] } },
59
+ {
60
+ page_version_type => {
61
+ elements: [
62
+ :nested_elements,
63
+ { contents: { essence: :ingredient_association } },
64
+ ],
65
+ },
66
+ },
67
+ ]
68
+ )
69
+ end
70
+
71
+ def page_version_type
72
+ :public_version
73
+ end
74
+
75
+ def api_page(page)
76
+ Alchemy::JsonApi::Page.new(page, page_version_type: page_version_type)
54
77
  end
55
78
 
56
79
  def base_page_scope
57
80
  # cancancan is not able to merge our complex AR scopes for logged in users
58
81
  if can?(:edit_content, ::Alchemy::Page)
59
- ::Alchemy::JsonApi::Page.all
82
+ Alchemy::Page.all.joins(page_version_type)
60
83
  else
61
- ::Alchemy::JsonApi::Page.published
84
+ Alchemy::Page.published.joins(page_version_type)
62
85
  end
63
86
  end
64
87
 
@@ -1,35 +1,31 @@
1
1
  module Alchemy
2
2
  module JsonApi
3
- class Page < BaseRecord
4
- self.table_name = "alchemy_pages"
3
+ class Page < SimpleDelegator
4
+ attr_reader :page_version_type, :page_version
5
5
 
6
- belongs_to :language, class_name: "Alchemy::Language"
7
-
8
- has_many :all_elements,
9
- -> { available.order(:position) },
10
- class_name: "Alchemy::JsonApi::Element",
11
- inverse_of: :page
12
-
13
- scope :published, -> {
14
- where("#{table_name}.public_on <= :time AND " \
15
- "(#{table_name}.public_until IS NULL " \
16
- "OR #{table_name}.public_until >= :time)", time: Time.current)
17
- }
6
+ def initialize(page, page_version_type: :public_version)
7
+ @page_version_type = page_version_type
8
+ @page_version = page.public_send(page_version_type)
9
+ super(page)
10
+ end
18
11
 
19
- scope :contentpages, -> { where(layoutpage: false) }
20
- scope :layoutpages, -> { where(layoutpage: true) }
21
- scope :with_language, ->(language_id) { where(language_id: language_id) }
12
+ # All elements including nested and fixed elements
13
+ def all_elements
14
+ @_all_elements ||= element_repository
15
+ end
22
16
 
23
- # The top level public, non-fixed elements of this page that - if present -
24
- # contains their nested_elements.
17
+ # Not nested unfixed top level elements
25
18
  def elements
26
- @_elements ||= first_level_elements.reject(&:fixed?)
19
+ @_elements ||= element_repository.not_nested.unfixed
27
20
  end
28
21
 
29
- # The top level public, fixed elements of this page that - if present -
30
- # contains their nested_elements.
22
+ # Not nested fixed top level elements
31
23
  def fixed_elements
32
- @_fixed_elements ||= first_level_elements.select(&:fixed?)
24
+ @_fixed_elements ||= element_repository.not_nested.fixed
25
+ end
26
+
27
+ def all_element_ids
28
+ @_all_element_ids ||= all_elements.map(&:id)
33
29
  end
34
30
 
35
31
  def element_ids
@@ -40,10 +36,17 @@ module Alchemy
40
36
  @_fixed_element_ids ||= fixed_elements.map(&:id)
41
37
  end
42
38
 
39
+ def ancestor_ids
40
+ @_ancestor_ids ||= ancestors.map(&:id)
41
+ end
42
+
43
43
  private
44
44
 
45
- def first_level_elements
46
- @_first_level_elements ||= all_elements.reject(&:parent_element_id)
45
+ def element_repository
46
+ return Alchemy::ElementsRepository.none unless page_version
47
+
48
+ # Need to use select here, otherwise rails would not eager load the elements correctly
49
+ Alchemy::ElementsRepository.new(page_version.elements.select(&:public))
47
50
  end
48
51
  end
49
52
  end
@@ -16,10 +16,6 @@ module Alchemy
16
16
  !!element.definition[:deprecated]
17
17
  end
18
18
 
19
- belongs_to :parent_element, record_type: :element, serializer: self
20
-
21
- belongs_to :page, record_type: :page, serializer: ::Alchemy::JsonApi::PageSerializer
22
-
23
19
  has_many :essences, polymorphic: true do |element|
24
20
  element.contents.map(&:essence)
25
21
  end
@@ -18,7 +18,19 @@ module Alchemy
18
18
 
19
19
  with_options if: proc { |essence| essence.picture.present? } do
20
20
  attribute :image_dimensions do |essence|
21
- essence.sizes_from_string(essence.render_size)
21
+ sizes = essence.content.settings[:size]&.split("x", 2)&.map(&:to_i) || [
22
+ essence.image_file_width,
23
+ essence.image_file_height,
24
+ ]
25
+
26
+ ratio = essence.image_file_width.to_f / essence.image_file_height
27
+ width = sizes[0].zero? ? sizes[1] * ratio : sizes[0]
28
+ height = sizes[1].zero? ? sizes[0] / ratio : sizes[1]
29
+
30
+ {
31
+ width: width,
32
+ height: height,
33
+ }
22
34
  end
23
35
 
24
36
  attribute :image_name do |essence|
@@ -7,6 +7,7 @@ module Alchemy
7
7
  include EssenceSerializer
8
8
  attributes(
9
9
  :body,
10
+ :sanitized_body,
10
11
  :stripped_body,
11
12
  )
12
13
  end
@@ -18,8 +18,18 @@ module Alchemy
18
18
  :updated_at,
19
19
  )
20
20
 
21
+ attribute :legacy_urls do |page|
22
+ page.legacy_urls.map(&:urlname)
23
+ end
24
+
21
25
  belongs_to :language, record_type: :language, serializer: ::Alchemy::JsonApi::LanguageSerializer
22
26
 
27
+ has_many :ancestors, record_type: :page, serializer: self do |page|
28
+ page.ancestors.map do |ancestor|
29
+ Alchemy::JsonApi::Page.new(ancestor, page_version_type: page.page_version_type)
30
+ end
31
+ end
32
+
23
33
  # All public elements of this page regardless of if they are fixed or nested.
24
34
  # Used for eager loading and should be used as the +include+ parameter of your query
25
35
  has_many :all_elements, record_type: :element, serializer: ELEMENT_SERIALIZER
data/config/routes.rb CHANGED
@@ -4,4 +4,10 @@ Alchemy::JsonApi::Engine.routes.draw do
4
4
  get "pages/*path" => "pages#show", as: :page
5
5
  resources :layout_pages, only: [:index]
6
6
  get "layout_pages/*path" => "layout_pages#show", as: :layout_page
7
+
8
+ namespace :admin do
9
+ get "pages/*path" => "pages#show", as: :page
10
+ resources :layout_pages, only: [:index]
11
+ get "layout_pages/*path" => "layout_pages#show", as: :layout_page
12
+ end
7
13
  end
@@ -11,6 +11,15 @@ RSpec.shared_examples "an essence serializer" do
11
11
  context "a deprecated content" do
12
12
  let(:content) { FactoryBot.create(:alchemy_content, name: "intro", element: element) }
13
13
 
14
+ before do
15
+ expect(content).to receive(:definition).at_least(:once) do
16
+ {
17
+ name: "intro",
18
+ deprecated: true,
19
+ }
20
+ end
21
+ end
22
+
14
23
  it "has deprecated attribute set to true" do
15
24
  expect(subject[:deprecated]).to eq(true)
16
25
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Alchemy
3
3
  module JsonApi
4
- VERSION = "0.12.0"
4
+ VERSION = "0.15.0"
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alchemy-json_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Meyerhoff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-25 00:00:00.000000000 Z
11
+ date: 2021-05-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: alchemy_cms
@@ -16,7 +16,7 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '5.0'
19
+ version: 6.0.a
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
22
  version: '6.1'
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '5.0'
29
+ version: 6.0.a
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6.1'
@@ -124,10 +124,11 @@ files:
124
124
  - MIT-LICENSE
125
125
  - README.md
126
126
  - Rakefile
127
+ - app/controllers/alchemy/json_api/admin/layout_pages_controller.rb
128
+ - app/controllers/alchemy/json_api/admin/pages_controller.rb
127
129
  - app/controllers/alchemy/json_api/base_controller.rb
128
130
  - app/controllers/alchemy/json_api/layout_pages_controller.rb
129
131
  - app/controllers/alchemy/json_api/pages_controller.rb
130
- - app/models/alchemy/json_api/element.rb
131
132
  - app/models/alchemy/json_api/page.rb
132
133
  - app/serializers/alchemy/json_api/element_serializer.rb
133
134
  - app/serializers/alchemy/json_api/essence_boolean_serializer.rb
@@ -1,33 +0,0 @@
1
- module Alchemy
2
- module JsonApi
3
- class Element < BaseRecord
4
- include Alchemy::Element::Definitions
5
- include Alchemy::Element::ElementContents
6
-
7
- self.table_name = "alchemy_elements"
8
-
9
- belongs_to :page, class_name: "Alchemy::JsonApi::Page", inverse_of: :all_elements
10
- has_many :contents, class_name: "Alchemy::Content", inverse_of: :element
11
-
12
- scope :available, -> { where(public: true).where.not(position: nil) }
13
-
14
- def parent_element
15
- page.all_elements.detect do |element|
16
- element.id == parent_element_id
17
- end
18
- end
19
-
20
- def nested_elements
21
- @_nested_elements ||= begin
22
- page.all_elements.select do |element|
23
- element.parent_element_id == id
24
- end
25
- end
26
- end
27
-
28
- def nested_element_ids
29
- nested_elements.map(&:id)
30
- end
31
- end
32
- end
33
- end