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,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'Delete entry type', :js do
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ before do
9
+ login_as admin_user
10
+
11
+ create(:entry_type)
12
+ visit spree.admin_entry_types_path
13
+ end
14
+
15
+ it 'deletes entry type' do
16
+ expect {
17
+ accept_confirm { find('.delete-entry-type').click }
18
+ }.to change(SolidusContent::EntryType, :count).from(1).to(0)
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'Edit entry', :js do
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ let(:entry_type) { create(:entry_type, provider_name: :raw) }
9
+ let(:entry) { create(:entry, entry_type: entry_type) }
10
+
11
+ before { login_as admin_user }
12
+
13
+ describe 'Edit entry type' do
14
+ context 'when the entry type provides has fields' do
15
+ let(:fields) { %i[date bar foo] }
16
+
17
+ before do
18
+ allow(SolidusContent::Providers::RAW)
19
+ .to receive(:entry_fields).and_return(fields)
20
+
21
+ visit spree.edit_admin_entry_path(entry)
22
+ end
23
+
24
+ it 'changes the option types fields' do
25
+ fields.each do |field|
26
+ fill_in "solidus_content_entry_#{field}", with: 'foo'
27
+ end
28
+
29
+ expect {
30
+ click_on 'Update'
31
+ }.to change { SolidusContent::Entry.last.options }.from({}).to(
32
+ 'date' => 'foo', 'bar' => 'foo', 'foo' => 'foo'
33
+ )
34
+ end
35
+ end
36
+
37
+ context 'when the entry type provides has not fields' do
38
+ before { visit spree.edit_admin_entry_path(entry) }
39
+
40
+ it 'does not show the option types fields' do
41
+ expect(page).not_to have_selector('.options-form')
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'Edit entry type', :js do
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ let(:entry_type) { create(:entry_type, provider_name: :raw) }
9
+
10
+ before { login_as admin_user }
11
+
12
+ describe 'Edit entry type' do
13
+ context 'when the entry type provides has fields' do
14
+ let(:fields) { %i[date bar foo] }
15
+
16
+ before do
17
+ allow(SolidusContent::Providers::RAW).to receive(:entry_type_fields)
18
+ .and_return(fields)
19
+
20
+ visit spree.edit_admin_entry_type_path(entry_type)
21
+ end
22
+
23
+ it 'changes the option types fields' do
24
+ fields.each do |field|
25
+ fill_in "solidus_content_entry_type_#{field}", with: 'foo'
26
+ end
27
+
28
+ expect {
29
+ click_on 'Update'
30
+ }.to change { SolidusContent::EntryType.last.options }.from({}).to(
31
+ 'date' => 'foo', 'bar' => 'foo', 'foo' => 'foo'
32
+ )
33
+ end
34
+ end
35
+
36
+ context 'when the entry type provides has not fields' do
37
+ before { visit spree.edit_admin_entry_type_path(entry_type) }
38
+
39
+ it 'does not show the option types fields' do
40
+ expect(page).not_to have_selector('.options-form')
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'List entries', :js do
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ before { login_as admin_user }
9
+
10
+ context 'when there are not entries' do
11
+ before { visit spree.admin_entries_path }
12
+
13
+ it 'shows empty message' do
14
+ expect(page).to have_selector('.no-objects-found')
15
+ end
16
+ end
17
+
18
+ context 'when there are entries' do
19
+ before do
20
+ create_list(:entry, 30)
21
+
22
+ visit spree.admin_entries_path
23
+ end
24
+
25
+ it 'shows pagination' do
26
+ expect(page).to have_selector('.pagination', count: 2)
27
+ end
28
+
29
+ it 'shows the list of entries' do
30
+ expect(page).to have_selector('[data-hook="admin_entries_index_rows"]', count: 25)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'List entry types', :js do
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ before { login_as admin_user }
9
+
10
+ context 'when there are not entries' do
11
+ before { visit spree.admin_entry_types_path }
12
+
13
+ it 'shows empty message' do
14
+ expect(page).to have_selector('.no-objects-found')
15
+ end
16
+ end
17
+
18
+ context 'when there are entries' do
19
+ before do
20
+ create_list(:entry_type, 30)
21
+
22
+ visit spree.admin_entry_types_path
23
+ end
24
+
25
+ it 'shows pagination' do
26
+ expect(page).to have_selector('.pagination', count: 2)
27
+ end
28
+
29
+ it 'shows the list of entries' do
30
+ expect(page).to have_selector('[data-hook="admin_entry_types_index_rows"]', count: 25)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe 'Sidebar', :js do
6
+ let(:admin_user) { create(:admin_user) }
7
+
8
+ before do
9
+ login_as admin_user
10
+
11
+ visit spree.admin_path
12
+ end
13
+
14
+ it 'shows Content menu item in the sidebar' do
15
+ within '[data-hook="admin_tabs"]' do
16
+ expect(page).to have_text(I18n.t(:content, scope: %i[spree admin tab]))
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'Render content with views' do
6
+ let(:post) { create(:entry_type, name: :post, provider_name: :raw) }
7
+ let(:view_path) { Rails.root.join('app/views/spree/solidus_content/post.html.erb') }
8
+
9
+ before do
10
+ view_path.dirname.mkpath
11
+
12
+ create(:entry, slug: 'one', options: { title: 'first post' }, entry_type: post)
13
+ create(:entry, slug: 'two', options: { title: 'second post' }, entry_type: post)
14
+
15
+ view_path.write(%{<main><h1><%= @entry.data[:title] %></h1></main>})
16
+ end
17
+
18
+ after { view_path.delete }
19
+
20
+ it 'rendering posts as views' do
21
+ visit '/c/post/one'
22
+ expect(page.find(:css, 'main h1')).to have_content 'first post'
23
+
24
+ visit '/c/post/two'
25
+ expect(page.find(:css, 'main h1')).to have_content 'second post'
26
+ end
27
+
28
+ context 'when the default route is disabled' do
29
+ it 'gives 404 when the default route is disabled' do
30
+ SolidusContent.config.skip_default_route = true
31
+ Rails.application.reload_routes!
32
+
33
+ expect { visit '/c/post/one' }.to raise_error(ActionController::RoutingError)
34
+
35
+ SolidusContent.config.skip_default_route = false
36
+ Rails.application.reload_routes!
37
+
38
+ expect { visit '/c/post/one' }.not_to raise_error
39
+ end
40
+ end
41
+ end
@@ -0,0 +1 @@
1
+ {"foo": "json_bar"}
@@ -0,0 +1 @@
1
+ foo: yaml_bar
@@ -0,0 +1 @@
1
+ foo: yml_bar
@@ -0,0 +1 @@
1
+ foo: yaml_bar
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe SolidusContent::Entry do
6
+ let(:entry) { build(:entry) }
7
+
8
+ let(:post) { create(:entry_type, name: :post, provider_name: :raw) }
9
+ let(:home) { create(:entry_type, name: :home, provider_name: :raw) }
10
+
11
+ let!(:post_one) do
12
+ create(
13
+ :entry,
14
+ slug: "one",
15
+ options: { title: "first post" },
16
+ entry_type: post
17
+ )
18
+ end
19
+
20
+ let!(:home_default) do
21
+ create(
22
+ :entry,
23
+ slug: :default,
24
+ options: { title: "Homepage" },
25
+ entry_type: home
26
+ )
27
+ end
28
+
29
+ it "has a valid factory" do
30
+ expect(entry).to be_valid
31
+ end
32
+
33
+ describe ".data_for" do
34
+ context "with using correct type and slug" do
35
+ it "returns the stored data" do
36
+ expect(
37
+ described_class.data_for(:post, "one")
38
+ ).to eq(title: "first post")
39
+ end
40
+ end
41
+
42
+ context "with using invalid type" do
43
+ it "will raise an ActiveRecord::RecordNotFound exception" do
44
+ expect{
45
+ described_class.data_for(:foo, "one")
46
+ }.to raise_error(ActiveRecord::RecordNotFound)
47
+ end
48
+ end
49
+
50
+ context "with using an invalid slug" do
51
+ it "will raise an ActiveRecord::RecordNotFound exception" do
52
+ expect{
53
+ described_class.data_for(:post, "foo")
54
+ }.to raise_error(ActiveRecord::RecordNotFound)
55
+ end
56
+ end
57
+ end
58
+
59
+ describe ".by_type" do
60
+ context "with entry_type present" do
61
+ context "with symbol passed in for type" do
62
+ it "returns the correct Entries" do
63
+ expect(described_class.by_type(:post)).to include post_one
64
+ expect(described_class.by_type(:post)).not_to include home_default
65
+ end
66
+ end
67
+
68
+ context "with EntryType instance passed in for type" do
69
+ it "returns the correct Entries" do
70
+ expect(described_class.by_type(post)).to include post_one
71
+ expect(described_class.by_type(post)).not_to include home_default
72
+ end
73
+ end
74
+ end
75
+
76
+ context "with using invalid type" do
77
+ it "will raise an ActiveRecord::RecordNotFound exception" do
78
+ expect{
79
+ described_class.by_type(:foo)
80
+ }.to raise_error(ActiveRecord::RecordNotFound)
81
+ end
82
+ end
83
+ end
84
+
85
+ specify "#data" do
86
+ expect(entry.entry_type)
87
+ .to receive(:content_for).with(entry).and_return(data: :foo)
88
+
89
+ expect(entry.data).to eq(:foo)
90
+ end
91
+
92
+ specify "#content" do
93
+ content = instance_double(Hash)
94
+
95
+ expect(entry.entry_type)
96
+ .to receive(:content_for).with(entry).and_return(content)
97
+
98
+ expect(entry.content).to eq(content)
99
+ end
100
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe SolidusContent::EntryType do
6
+ it 'has a valid factory' do
7
+ expect(build(:entry_type)).to be_valid
8
+ end
9
+
10
+ describe '#content_for' do
11
+ let(:entry_options) { {} }
12
+ let(:entry_type_options) { {} }
13
+ let(:entry_type) { create(:entry_type, provider_name: provider_name) }
14
+ let(:entry) { create(:entry, slug: :example, entry_type: entry_type, options: entry_options) }
15
+
16
+ shared_examples 'a content provider' do
17
+ it 'calls the content-provider call method' do
18
+ expect(
19
+ SolidusContent.config.providers[provider_name.to_sym]
20
+ ).to receive(:call).with(
21
+ slug: entry.slug,
22
+ type: entry_type.name,
23
+ provider: provider_name,
24
+ options: entry.options.symbolize_keys,
25
+ type_options: entry_type.options.symbolize_keys,
26
+ ).and_return(content)
27
+
28
+ entry_type.content_for(entry)
29
+ end
30
+ end
31
+
32
+ context 'with the JSON provider' do
33
+ let(:provider_name) { 'json' }
34
+ let(:entry_type_options) { { path: "#{FIXTURES_PATH}/content" } }
35
+ let(:content) { { foo: 'bar' } }
36
+
37
+ it_behaves_like 'a content provider'
38
+ end
39
+
40
+ context 'with the RAW provider' do
41
+ let(:provider_name) { 'raw' }
42
+ let(:entry_options) { { foo: 'bar' } }
43
+ let(:content) { { foo: 'bar' } }
44
+
45
+ it_behaves_like 'a content provider'
46
+ end
47
+
48
+ context 'with the solidus static content provider' do
49
+ let(:provider_name) { 'solidus_static_content' }
50
+ let(:content) { { foo: 'bar' } }
51
+
52
+ it_behaves_like 'a content provider'
53
+ end
54
+
55
+ context 'with the Prismic provider' do
56
+ let(:provider_name) { 'prismic' }
57
+ let(:content) { { foo: 'bar' } }
58
+
59
+ it_behaves_like 'a content provider'
60
+ end
61
+
62
+ context 'with an unknown provider' do
63
+ let(:provider_name) { 'unknown' }
64
+
65
+ it 'raises an unknow provider error' do
66
+ expect { entry_type.content_for(entry_options) }
67
+ .to raise_error(SolidusContent::Configuration::UnknownProvider)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe '.by_name' do
73
+ let!(:home) { create(:entry_type, name: :home, provider_name: :raw) }
74
+
75
+ context 'with existing name' do
76
+ it 'returns the entry_type' do
77
+ expect(described_class.by_name(:home)).to eql home
78
+ end
79
+ end
80
+
81
+ context 'with non-existing name' do
82
+ it 'will raise an ActiveRecord::RecordNotFound exception' do
83
+ expect{
84
+ described_class.by_name(:post)
85
+ }.to raise_error(ActiveRecord::RecordNotFound)
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#provider_name_readonly?' do
91
+ subject(:entry_type) { build(:entry_type) }
92
+
93
+ it 'ensures is not changed after creation' do
94
+ expect(subject.provider_name_readonly?).to eq(false)
95
+ expect(subject.valid?).to eq(true)
96
+
97
+ subject.save!
98
+ expect(subject.provider_name_readonly?).to eq(true)
99
+ expect(subject.valid?).to eq(true)
100
+
101
+ subject.provider_name = 'foo'
102
+ expect(subject.provider_name_readonly?).to eq(true)
103
+ expect(subject.valid?).to eq(false)
104
+ end
105
+ end
106
+ end