solidus_content 0.1.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.
Files changed (89) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +72 -0
  3. data/.gem_release.yml +5 -0
  4. data/.github/stale.yml +17 -0
  5. data/.gitignore +20 -0
  6. data/.rspec +2 -0
  7. data/.rubocop.yml +38 -0
  8. data/Gemfile +38 -0
  9. data/LICENSE +26 -0
  10. data/README.md +439 -0
  11. data/Rakefile +6 -0
  12. data/app/assets/javascripts/spree/backend/solidus_content.js +2 -0
  13. data/app/assets/javascripts/spree/frontend/solidus_content.js +2 -0
  14. data/app/assets/stylesheets/spree/backend/solidus_content.css +4 -0
  15. data/app/assets/stylesheets/spree/frontend/solidus_content.css +4 -0
  16. data/app/controllers/solidus_content/resource_controller.rb +35 -0
  17. data/app/controllers/spree/admin/entries_controller.rb +25 -0
  18. data/app/controllers/spree/admin/entry_types_controller.rb +25 -0
  19. data/app/controllers/spree/solidus_content_controller.rb +13 -0
  20. data/app/models/solidus_content/application_record.rb +5 -0
  21. data/app/models/solidus_content/entry.rb +44 -0
  22. data/app/models/solidus_content/entry_type.rb +55 -0
  23. data/app/models/solidus_content/provider/fields.rb +20 -0
  24. data/app/views/spree/admin/entries/_form.html.erb +31 -0
  25. data/app/views/spree/admin/entries/_options_form.html.erb +18 -0
  26. data/app/views/spree/admin/entries/edit.html.erb +16 -0
  27. data/app/views/spree/admin/entries/index.html.erb +54 -0
  28. data/app/views/spree/admin/entries/new.html.erb +21 -0
  29. data/app/views/spree/admin/entry_types/_form.html.erb +30 -0
  30. data/app/views/spree/admin/entry_types/_options_form.html.erb +16 -0
  31. data/app/views/spree/admin/entry_types/edit.html.erb +16 -0
  32. data/app/views/spree/admin/entry_types/index.html.erb +54 -0
  33. data/app/views/spree/admin/entry_types/new.html.erb +21 -0
  34. data/app/views/spree/admin/shared/_solidus_content_sub_menu.html.erb +9 -0
  35. data/bin/console +17 -0
  36. data/bin/rails +7 -0
  37. data/bin/rails-engine +13 -0
  38. data/bin/rails-sandbox +16 -0
  39. data/bin/rake +7 -0
  40. data/bin/rspec +7 -0
  41. data/bin/sandbox +84 -0
  42. data/bin/setup +8 -0
  43. data/config/initializers/spree.rb +12 -0
  44. data/config/locales/en.yml +51 -0
  45. data/config/routes.rb +14 -0
  46. data/db/migrate/20200207135842_create_solidus_content_entries.rb +11 -0
  47. data/db/migrate/20200306110114_create_solidus_content_entry_types.rb +12 -0
  48. data/lib/generators/solidus_content/install/install_generator.rb +36 -0
  49. data/lib/generators/solidus_content/install/templates/initializer.rb +20 -0
  50. data/lib/solidus_content.rb +10 -0
  51. data/lib/solidus_content/active_record.rb +7 -0
  52. data/lib/solidus_content/configuration.rb +38 -0
  53. data/lib/solidus_content/engine.rb +19 -0
  54. data/lib/solidus_content/factories.rb +13 -0
  55. data/lib/solidus_content/providers.rb +23 -0
  56. data/lib/solidus_content/providers/contentful.rb +36 -0
  57. data/lib/solidus_content/providers/json.rb +27 -0
  58. data/lib/solidus_content/providers/prismic.rb +36 -0
  59. data/lib/solidus_content/providers/raw.rb +22 -0
  60. data/lib/solidus_content/providers/solidus_static_content.rb +23 -0
  61. data/lib/solidus_content/providers/yaml.rb +33 -0
  62. data/lib/solidus_content/version.rb +5 -0
  63. data/solidus_content.gemspec +36 -0
  64. data/spec/features/admin/content/create_entry_spec.rb +36 -0
  65. data/spec/features/admin/content/create_entry_type_spec.rb +36 -0
  66. data/spec/features/admin/content/delete_entry_spec.rb +20 -0
  67. data/spec/features/admin/content/delete_entry_type_spec.rb +20 -0
  68. data/spec/features/admin/content/edit_entry_spec.rb +45 -0
  69. data/spec/features/admin/content/edit_entry_type_spec.rb +44 -0
  70. data/spec/features/admin/content/list_entries_spec.rb +33 -0
  71. data/spec/features/admin/content/list_entry_types_spec.rb +33 -0
  72. data/spec/features/admin/sidebar_spec.rb +19 -0
  73. data/spec/features/render_content_with_views_spec.rb +41 -0
  74. data/spec/fixtures/content/example.json +1 -0
  75. data/spec/fixtures/content/example.yaml +1 -0
  76. data/spec/fixtures/content/example.yml +1 -0
  77. data/spec/fixtures/content/example_2.yaml +1 -0
  78. data/spec/models/solidus_content/entry_spec.rb +100 -0
  79. data/spec/models/solidus_content/entry_type_spec.rb +106 -0
  80. data/spec/solidus_content/configuration_spec.rb +37 -0
  81. data/spec/solidus_content/providers/contentful_spec.rb +56 -0
  82. data/spec/solidus_content/providers/json_spec.rb +33 -0
  83. data/spec/solidus_content/providers/prismic_spec.rb +82 -0
  84. data/spec/solidus_content/providers/solidus_static_content_spec.rb +34 -0
  85. data/spec/solidus_content/providers/yaml_spec.rb +51 -0
  86. data/spec/solidus_content_spec.rb +23 -0
  87. data/spec/spec_helper.rb +32 -0
  88. data/spec/support/warden.rb +5 -0
  89. metadata +206 -0
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'solidus_dev_support/rake_tasks'
4
+ SolidusDevSupport::RakeTasks.install
5
+
6
+ task default: 'extension:specs'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/backend/all.js'
@@ -0,0 +1,2 @@
1
+ // Placeholder manifest file.
2
+ // the installer will append this file to the app vendored assets here: vendor/assets/javascripts/spree/frontend/all.js'
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/backend/all.css'
4
+ */
@@ -0,0 +1,4 @@
1
+ /*
2
+ Placeholder manifest file.
3
+ the installer will append this file to the app vendored assets here: 'vendor/assets/stylesheets/spree/frontend/all.css'
4
+ */
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusContent
4
+ class ResourceController < Spree::Admin::ResourceController
5
+ private
6
+
7
+ def location_after_save
8
+ edit_object_url(@object)
9
+ end
10
+
11
+ def collection
12
+ super.page(params[:page] || 0)
13
+ end
14
+
15
+ def model_class
16
+ "SolidusContent::#{controller_name.classify}".constantize
17
+ end
18
+
19
+ def new_object_url(options = {})
20
+ send(:"new_admin_#{controller_name.singularize}_path", options)
21
+ end
22
+
23
+ def edit_object_url(object, options = {})
24
+ send(:"edit_admin_#{controller_name.singularize}_path", object, options)
25
+ end
26
+
27
+ def object_url(object = nil, options = {})
28
+ send(:"admin_#{controller_name.singularize}_path", object, options)
29
+ end
30
+
31
+ def collection_url(options = {})
32
+ send(:"admin_#{controller_name}_path", options)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Admin
5
+ class EntriesController < SolidusContent::ResourceController
6
+ helper_method :model_class
7
+
8
+ def show
9
+ redirect_to action: :edit
10
+ end
11
+
12
+ private
13
+
14
+ def permitted_resource_params
15
+ params
16
+ .require(:solidus_content_entry)
17
+ .permit(:slug, :entry_type_id, *provider_params)
18
+ end
19
+
20
+ def provider_params
21
+ @object.entry_fields || []
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Admin
5
+ class EntryTypesController < SolidusContent::ResourceController
6
+ helper_method :model_class
7
+
8
+ def show
9
+ redirect_to action: :edit
10
+ end
11
+
12
+ private
13
+
14
+ def permitted_resource_params
15
+ params
16
+ .require(:solidus_content_entry_type)
17
+ .permit(:name, :provider_name, *provider_params)
18
+ end
19
+
20
+ def provider_params
21
+ @object.entry_type_fields || []
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_dependency 'solidus_content/entry_type'
4
+
5
+ class Spree::SolidusContentController < Spree::StoreController
6
+ def show
7
+ slug = params[:id] || :default
8
+ type = params[:type]
9
+
10
+ @entry = ::SolidusContent::Entry.by_type(type).by_slug(slug)
11
+ render action: type
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusContent::ApplicationRecord < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusContent::Entry < SolidusContent::ApplicationRecord
4
+ include SolidusContent::Provider::Fields
5
+
6
+ belongs_to :entry_type
7
+
8
+ after_initialize { self.options ||= {} }
9
+ after_initialize :inject_entry_fields, if: :entry_type_id?
10
+
11
+ validates :slug, presence: true, uniqueness: { scope: :entry_type_id }
12
+
13
+ scope :by_slug, ->(slug) { find_by!(slug: slug) }
14
+ scope :by_type, ->(type) {
15
+ unless type.is_a? SolidusContent::EntryType
16
+ type = SolidusContent::EntryType.by_name(type)
17
+ end
18
+ where(entry_type: type)
19
+ }
20
+
21
+ def self.data_for(type, slug)
22
+ by_type(type).by_slug(slug).data
23
+ end
24
+
25
+ def data
26
+ content[:data]
27
+ end
28
+
29
+ def content
30
+ @content ||= entry_type.content_for(self)
31
+ end
32
+
33
+ def entry_fields
34
+ return unless entry_type_id?
35
+
36
+ entry_type.provider_class.entry_fields
37
+ end
38
+
39
+ private
40
+
41
+ def inject_entry_fields
42
+ provider_based_attr_reader(entry_fields)
43
+ end
44
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusContent::EntryType < SolidusContent::ApplicationRecord
4
+ include SolidusContent::Provider::Fields
5
+
6
+ has_many :entries, dependent: :destroy
7
+
8
+ scope :by_name, ->(name) { find_by!(name: name) }
9
+
10
+ validates :name, presence: true
11
+ validates :provider_name, presence: true
12
+ validates :name, :provider_name, presence: true
13
+ validate :ensure_provider_name_is_not_changed
14
+
15
+ after_initialize { self.options ||= {} }
16
+ after_initialize :inject_provider_fields, if: :provider_name?
17
+
18
+ scope :by_name, ->(name) { find_by!(name: name) }
19
+
20
+ def content_for(entry)
21
+ provider_class.call(
22
+ slug: entry.slug,
23
+ type: name,
24
+ provider: provider_name,
25
+ options: entry.options.symbolize_keys,
26
+ type_options: options.symbolize_keys,
27
+ )
28
+ end
29
+
30
+ def provider_class
31
+ SolidusContent.config.providers[provider_name.to_sym]
32
+ end
33
+
34
+ def provider_name_readonly?
35
+ persisted?
36
+ end
37
+
38
+ def entry_type_fields
39
+ return unless provider_name
40
+
41
+ provider_class.entry_type_fields
42
+ end
43
+
44
+ private
45
+
46
+ def inject_provider_fields
47
+ provider_based_attr_reader(entry_type_fields)
48
+ end
49
+
50
+ def ensure_provider_name_is_not_changed
51
+ return unless provider_name_changed? && persisted?
52
+
53
+ errors.add :provider_name, :readonly
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusContent
4
+ module Provider
5
+ module Fields
6
+ def provider_based_attr_reader(attrs)
7
+ attrs.each do |attr|
8
+ define_singleton_method(attr) do
9
+ options[attr.to_s] || ''
10
+ end
11
+
12
+ define_singleton_method("#{attr}=") do |value|
13
+ attribute_will_change!(:options)
14
+ options[attr.to_s] = value
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ <% entry_type_options = SolidusContent::EntryType.pluck(:name, :id) %>
2
+
3
+ <div data-hook="admin_entry_form_fields">
4
+ <div class="row">
5
+ <div class="left col-12" data-hook="admin_entry_form">
6
+ <div class="row">
7
+ <div class="col-6" data-hook="admin_entry_form_name">
8
+ <%= form.field_container :slug do %>
9
+ <%= form.field_hint :slug %>
10
+ <%= form.label :slug, class: 'required' %><br />
11
+ <%= form.text_field :slug, class: 'fullwidth' %>
12
+ <% end %>
13
+ </div>
14
+
15
+ <div class="col-6" data-hook="admin_entry_form_provider">
16
+ <%= form.field_container :entry_type_id do %>
17
+ <%= form.field_hint :entry_type_id %>
18
+ <%= form.label :entry_type_id, class: 'required' %><br />
19
+ <%= form.select :entry_type_id, entry_type_options, { include_blank: false }, { disabled: form.object.persisted?, class: 'custom-select fullwidth' } %>
20
+ <% end %>
21
+ </div>
22
+
23
+ <%= form.hidden_field :options, value: '{}' %>
24
+ </div>
25
+ </div>
26
+ </div>
27
+
28
+ <% if form.object.persisted? && @object.entry_fields.count > 0 %>
29
+ <%= render "options_form", form: form %>
30
+ <% end %>
31
+ </div>
@@ -0,0 +1,18 @@
1
+ <fieldset class="no-border-bottom">
2
+ <legend>
3
+ <%= @entry.entry_type.name %>
4
+ <%= model_class.human_attribute_name(:options) %>
5
+ (<%= SolidusContent.human_provider_name(@entry.entry_type.provider_name) %>)
6
+ </legend>
7
+
8
+ <div class="row">
9
+ <% @entry.entry_fields.each do |field| %>
10
+ <div class="col-12" data-hook="admin_entry_<%= field %>">
11
+ <div class="field" id="solidus_content_entry_<%= field %>_field">
12
+ <%= form.label field %>
13
+ <%= form.text_field field, class: 'fullwidth' %>
14
+ </div>
15
+ </div>
16
+ <% end %>
17
+ </div>
18
+ </fieldset>
@@ -0,0 +1,16 @@
1
+ <% admin_breadcrumb link_to(plural_resource_name(model_class), spree.admin_entries_path) %>
2
+ <% admin_breadcrumb @object.slug %>
3
+
4
+ <%= render 'spree/shared/error_messages', target: @object %>
5
+
6
+ <%= form_for @entry, url: spree.admin_entry_path(@entry) do |form| %>
7
+ <fieldset data-hook="edit_entry">
8
+ <%= content_tag :legend, model_class.model_name.human %>
9
+ <%= render 'form', form: form %>
10
+
11
+ <div class="form-buttons filter-actions actions" data-hook="buttons">
12
+ <%= submit_tag t('spree.actions.update'), class: 'btn btn-primary' %>
13
+ <%= link_to t('spree.actions.cancel'), collection_url, class: 'button' %>
14
+ </div>
15
+ </fieldset>
16
+ <% end %>
@@ -0,0 +1,54 @@
1
+ <% admin_layout "full-width" %>
2
+
3
+ <% admin_breadcrumb plural_resource_name(model_class) %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <li>
7
+ <%= link_to t('spree.admin.entry.new'), new_object_url, class: 'btn btn-primary' %>
8
+ </li>
9
+ <% end if can?(:create, model_class) %>
10
+
11
+ <%= paginate @collection, theme: "solidus_admin" %>
12
+
13
+ <% if @collection.any? %>
14
+ <table class="index" id="listing_entries">
15
+ <colgroup>
16
+ <col style="width: 40%;">
17
+ <col style="width: 40%;">
18
+ <col style="width: 20%;">
19
+ </colgroup>
20
+ <thead>
21
+ <tr data-hook="admin_products_index_headers">
22
+ <th><%= model_class.human_attribute_name(:slug) %></th>
23
+ <th><%= model_class.human_attribute_name(:entry_type) %></th>
24
+ <th></th>
25
+ </tr>
26
+ </thead>
27
+ <tbody>
28
+ <% @collection.each do |entry| %>
29
+ <tr id="<%= spree_dom_id entry %>" data-hook="admin_entries_index_rows">
30
+ <td>
31
+ <%= link_to entry.slug, object_url(entry) %>
32
+ </td>
33
+ <td>
34
+ <%= link_to entry.entry_type.name, admin_entry_type_path(entry.entry_type) %>
35
+ </td>
36
+ <td class="actions" data-hook="admin_entries_index_row_actions">
37
+ <%= link_to_edit entry, url: edit_object_url(entry),
38
+ class: 'edit edit-entry' if can?(:update, entry) %>
39
+ <%= link_to_delete entry, url: object_url(entry),
40
+ class: 'trash delete-entry' if can?(:destroy, entry) %>
41
+ </td>
42
+ </tr>
43
+ <% end %>
44
+ </tbody>
45
+ </table>
46
+ <% else %>
47
+ <div class="no-objects-found">
48
+ <%= render 'spree/admin/shared/no_objects_found',
49
+ resource: model_class,
50
+ new_resource_url: new_object_url %>
51
+ </div>
52
+ <% end %>
53
+
54
+ <%= paginate @collection, theme: "solidus_admin" %>
@@ -0,0 +1,21 @@
1
+ <% admin_breadcrumb link_to(plural_resource_name(model_class), collection_url) %>
2
+ <% admin_breadcrumb "#{t('spree.actions.new')} #{model_class.model_name.human}" %>
3
+
4
+
5
+ <%= render 'spree/shared/error_messages', target: @object %>
6
+
7
+ <%= form_for @object, url: collection_url do |form| %>
8
+ <fieldset data-hook="new_entry">
9
+ <legend align="center">
10
+ <%= admin_hint nil, t('solidus_content.hints.new_entry') %>
11
+ <%= t('new', scope: %w[spree admin entry]) %>
12
+ </legend>
13
+
14
+ <%= render 'form', form: form %>
15
+
16
+ <div class="form-buttons filter-actions actions" data-hook="buttons">
17
+ <%= submit_tag t('spree.actions.create'), class: 'btn btn-primary' %>
18
+ <%= link_to t('spree.actions.cancel'), collection_url, class: 'button' %>
19
+ </div>
20
+ </fieldset>
21
+ <% end %>
@@ -0,0 +1,30 @@
1
+ <% provider_options = SolidusContent.provider_names.map do |name|
2
+ [SolidusContent.human_provider_name(name), name]
3
+ end %>
4
+
5
+ <div data-hook="admin_entry_type_form_fields">
6
+ <div class="row">
7
+ <div class="left col-12" data-hook="admin_entry_type_form">
8
+ <div class="row">
9
+ <div class="col-6" data-hook="admin_entry_type_form_name">
10
+ <%= form.field_container :user do %>
11
+ <%= form.label :name, class: 'required' %><br />
12
+ <%= form.text_field :name, class: 'fullwidth' %>
13
+ <% end %>
14
+ </div>
15
+
16
+ <div class="col-6" data-hook="admin_entry_type_form_provider">
17
+ <%= form.field_container :provider_name do %>
18
+ <%= form.field_hint :provider_name %>
19
+ <%= form.label :provider_name, class: 'required' %><br />
20
+ <%= form.select :provider_name, provider_options, { include_blank: false }, { disabled: form.object.provider_name_readonly?, class: 'custom-select fullwidth' } %>
21
+ <% end %>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ </div>
26
+
27
+ <% if form.object.provider_name_readonly? && @object.entry_type_fields.count > 0 %>
28
+ <%= render "options_form", form: form %>
29
+ <% end %>
30
+ </div>
@@ -0,0 +1,16 @@
1
+ <fieldset class="options-form no-border-bottom">
2
+ <legend>
3
+ <%= SolidusContent.human_provider_name(@entry_type.provider_name) %>
4
+ <%= model_class.human_attribute_name(:options) %>
5
+ </legend>
6
+ <div class="row">
7
+ <% @entry_type.entry_type_fields.each do |field| %>
8
+ <div class="col-12" data-hook="admin_entry_type_<%= field %>">
9
+ <div class="field" id="solidus_content_entry_type_<%= field %>_field">
10
+ <%= form.label field %>
11
+ <%= form.text_field field, class: 'fullwidth' %>
12
+ </div>
13
+ </div>
14
+ <% end %>
15
+ </div>
16
+ </fieldset>