solidus_content 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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