alchemy-json_api 0.12.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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