solidus_content 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +72 -0
- data/.gem_release.yml +5 -0
- data/.github/stale.yml +17 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/.rubocop.yml +38 -0
- data/Gemfile +38 -0
- data/LICENSE +26 -0
- data/README.md +439 -0
- data/Rakefile +6 -0
- data/app/assets/javascripts/spree/backend/solidus_content.js +2 -0
- data/app/assets/javascripts/spree/frontend/solidus_content.js +2 -0
- data/app/assets/stylesheets/spree/backend/solidus_content.css +4 -0
- data/app/assets/stylesheets/spree/frontend/solidus_content.css +4 -0
- data/app/controllers/solidus_content/resource_controller.rb +35 -0
- data/app/controllers/spree/admin/entries_controller.rb +25 -0
- data/app/controllers/spree/admin/entry_types_controller.rb +25 -0
- data/app/controllers/spree/solidus_content_controller.rb +13 -0
- data/app/models/solidus_content/application_record.rb +5 -0
- data/app/models/solidus_content/entry.rb +44 -0
- data/app/models/solidus_content/entry_type.rb +55 -0
- data/app/models/solidus_content/provider/fields.rb +20 -0
- data/app/views/spree/admin/entries/_form.html.erb +31 -0
- data/app/views/spree/admin/entries/_options_form.html.erb +18 -0
- data/app/views/spree/admin/entries/edit.html.erb +16 -0
- data/app/views/spree/admin/entries/index.html.erb +54 -0
- data/app/views/spree/admin/entries/new.html.erb +21 -0
- data/app/views/spree/admin/entry_types/_form.html.erb +30 -0
- data/app/views/spree/admin/entry_types/_options_form.html.erb +16 -0
- data/app/views/spree/admin/entry_types/edit.html.erb +16 -0
- data/app/views/spree/admin/entry_types/index.html.erb +54 -0
- data/app/views/spree/admin/entry_types/new.html.erb +21 -0
- data/app/views/spree/admin/shared/_solidus_content_sub_menu.html.erb +9 -0
- data/bin/console +17 -0
- data/bin/rails +7 -0
- data/bin/rails-engine +13 -0
- data/bin/rails-sandbox +16 -0
- data/bin/rake +7 -0
- data/bin/rspec +7 -0
- data/bin/sandbox +84 -0
- data/bin/setup +8 -0
- data/config/initializers/spree.rb +12 -0
- data/config/locales/en.yml +51 -0
- data/config/routes.rb +14 -0
- data/db/migrate/20200207135842_create_solidus_content_entries.rb +11 -0
- data/db/migrate/20200306110114_create_solidus_content_entry_types.rb +12 -0
- data/lib/generators/solidus_content/install/install_generator.rb +36 -0
- data/lib/generators/solidus_content/install/templates/initializer.rb +20 -0
- data/lib/solidus_content.rb +10 -0
- data/lib/solidus_content/active_record.rb +7 -0
- data/lib/solidus_content/configuration.rb +38 -0
- data/lib/solidus_content/engine.rb +19 -0
- data/lib/solidus_content/factories.rb +13 -0
- data/lib/solidus_content/providers.rb +23 -0
- data/lib/solidus_content/providers/contentful.rb +36 -0
- data/lib/solidus_content/providers/json.rb +27 -0
- data/lib/solidus_content/providers/prismic.rb +36 -0
- data/lib/solidus_content/providers/raw.rb +22 -0
- data/lib/solidus_content/providers/solidus_static_content.rb +23 -0
- data/lib/solidus_content/providers/yaml.rb +33 -0
- data/lib/solidus_content/version.rb +5 -0
- data/solidus_content.gemspec +36 -0
- data/spec/features/admin/content/create_entry_spec.rb +36 -0
- data/spec/features/admin/content/create_entry_type_spec.rb +36 -0
- data/spec/features/admin/content/delete_entry_spec.rb +20 -0
- data/spec/features/admin/content/delete_entry_type_spec.rb +20 -0
- data/spec/features/admin/content/edit_entry_spec.rb +45 -0
- data/spec/features/admin/content/edit_entry_type_spec.rb +44 -0
- data/spec/features/admin/content/list_entries_spec.rb +33 -0
- data/spec/features/admin/content/list_entry_types_spec.rb +33 -0
- data/spec/features/admin/sidebar_spec.rb +19 -0
- data/spec/features/render_content_with_views_spec.rb +41 -0
- data/spec/fixtures/content/example.json +1 -0
- data/spec/fixtures/content/example.yaml +1 -0
- data/spec/fixtures/content/example.yml +1 -0
- data/spec/fixtures/content/example_2.yaml +1 -0
- data/spec/models/solidus_content/entry_spec.rb +100 -0
- data/spec/models/solidus_content/entry_type_spec.rb +106 -0
- data/spec/solidus_content/configuration_spec.rb +37 -0
- data/spec/solidus_content/providers/contentful_spec.rb +56 -0
- data/spec/solidus_content/providers/json_spec.rb +33 -0
- data/spec/solidus_content/providers/prismic_spec.rb +82 -0
- data/spec/solidus_content/providers/solidus_static_content_spec.rb +34 -0
- data/spec/solidus_content/providers/yaml_spec.rb +51 -0
- data/spec/solidus_content_spec.rb +23 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/warden.rb +5 -0
- metadata +206 -0
data/Rakefile
ADDED
@@ -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,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>
|