archangel 0.0.5 → 0.0.6

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.jshintrc +3 -3
  3. data/.reek +9 -0
  4. data/Gemfile +1 -0
  5. data/app/assets/javascripts/archangel/object/flash.js +2 -2
  6. data/app/assets/javascripts/archangel/object/routes.js.erb +4 -0
  7. data/app/assets/javascripts/archangel/object/routes/backend.js +13 -2
  8. data/app/helpers/archangel/flash_helper.rb +1 -1
  9. data/app/models/archangel/asset.rb +1 -1
  10. data/app/models/archangel/collection.rb +3 -3
  11. data/app/models/archangel/page.rb +1 -1
  12. data/app/models/archangel/site.rb +3 -4
  13. data/app/models/archangel/user.rb +4 -2
  14. data/app/models/archangel/widget.rb +1 -1
  15. data/app/services/archangel/render_service.rb +1 -7
  16. data/app/services/archangel/template_render_service.rb +1 -3
  17. data/app/themes/default/assets/javascripts/default/backend.js +0 -2
  18. data/app/themes/default/assets/javascripts/default/backend/core.js +71 -2
  19. data/app/themes/default/assets/javascripts/default/common/flash.js +1 -1
  20. data/app/themes/default/views/layouts/auth.html.erb +2 -0
  21. data/app/themes/default/views/layouts/backend/_sidebar.html.erb +7 -5
  22. data/app/views/archangel/shared/_flash_messages.html.erb +3 -3
  23. data/app/views/devise/shared/_links.html.erb +7 -7
  24. data/db/migrate/20171003210347_create_archangel_users.rb +2 -2
  25. data/db/migrate/20171005224054_create_archangel_pages.rb +1 -1
  26. data/db/migrate/20171006175939_create_archangel_widgets.rb +1 -1
  27. data/db/migrate/20171006194044_create_archangel_collections.rb +1 -1
  28. data/db/seeds.rb +72 -7
  29. data/docs/Extension/Models.md +1 -1
  30. data/lib/archangel/command/templates/extension/config/routes.rb +1 -1
  31. data/lib/archangel/engine.rb +4 -0
  32. data/lib/archangel/version.rb +1 -1
  33. data/lib/generators/archangel/dummy/templates/config/database.yml +0 -12
  34. data/spec/lib/archangel/command/extension_spec.rb +1 -1
  35. data/spec/models/archangel/asset_spec.rb +11 -14
  36. data/spec/models/archangel/collection_spec.rb +37 -7
  37. data/spec/models/archangel/entry_spec.rb +8 -6
  38. data/spec/models/archangel/field_spec.rb +21 -10
  39. data/spec/models/archangel/page_spec.rb +65 -24
  40. data/spec/models/archangel/site_spec.rb +45 -2
  41. data/spec/models/archangel/template_spec.rb +16 -9
  42. data/spec/models/archangel/user_spec.rb +44 -15
  43. data/spec/models/archangel/widget_spec.rb +44 -10
  44. data/spec/policies/archangel/asset_policy_spec.rb +26 -9
  45. data/spec/policies/archangel/collection_policy_spec.rb +23 -8
  46. data/spec/policies/archangel/entries_policy_spec.rb +26 -9
  47. data/spec/policies/archangel/page_policy_spec.rb +23 -8
  48. data/spec/policies/archangel/site_policy_spec.rb +11 -9
  49. data/spec/policies/archangel/template_policy_spec.rb +23 -8
  50. data/spec/policies/archangel/user_policy_spec.rb +23 -8
  51. data/spec/policies/archangel/widget_policy_spec.rb +23 -8
  52. metadata +2 -4
  53. data/app/themes/default/assets/javascripts/default/common/navigation.js +0 -30
  54. data/app/themes/default/assets/javascripts/default/common/sidebar.js +0 -114
@@ -14,7 +14,7 @@ class CreateArchangelWidgets < ActiveRecord::Migration[5.1]
14
14
  add_index :archangel_widgets, :deleted_at
15
15
  add_index :archangel_widgets, :name
16
16
  add_index :archangel_widgets, :site_id
17
- add_index :archangel_widgets, :slug, unique: true
17
+ add_index :archangel_widgets, :slug
18
18
  add_index :archangel_widgets, :template_id
19
19
  end
20
20
  end
@@ -12,6 +12,6 @@ class CreateArchangelCollections < ActiveRecord::Migration[5.1]
12
12
  add_index :archangel_collections, :deleted_at
13
13
  add_index :archangel_collections, :name
14
14
  add_index :archangel_collections, :site_id
15
- add_index :archangel_collections, :slug, unique: true
15
+ add_index :archangel_collections, :slug
16
16
  end
17
17
  end
@@ -29,20 +29,19 @@ def prompt_for_admin_password
29
29
  end
30
30
 
31
31
  # Site
32
- site = Archangel::Site.first_or_create! do |item|
32
+ curent_site = Archangel::Site.first_or_create! do |item|
33
33
  item.name = "Archangel"
34
34
  item.locale = "en"
35
35
  end
36
36
 
37
37
  # User
38
- unless Archangel::User.first
38
+ unless curent_site.users.first
39
39
  email = prompt_for_admin_email
40
40
  name = prompt_for_admin_name
41
41
  username = prompt_for_admin_username
42
42
  password = prompt_for_admin_password
43
43
 
44
44
  attributes = {
45
- site: site,
46
45
  email: email,
47
46
  username: username,
48
47
  name: name,
@@ -52,14 +51,80 @@ unless Archangel::User.first
52
51
  confirmed_at: Time.current
53
52
  }
54
53
 
55
- Archangel::User.create!(attributes)
54
+ curent_site.users.create!(attributes)
56
55
  end
57
56
 
58
57
  # Homepage
59
- Archangel::Page.published
60
- .find_or_create_by!(site: site, homepage: true) do |item|
58
+ curent_site.pages.published.find_or_create_by(homepage: true) do |item|
61
59
  item.slug = "homepage-#{Time.now.to_i}"
62
60
  item.title = "Welcome to Archangel"
63
- item.content = "<p>Welcome to your new site.</p>"
61
+ item.content = %(
62
+ <p>Welcome to your new site.</p>
63
+ )
64
64
  item.published_at = Time.current
65
65
  end
66
+
67
+ # Page Template
68
+ page_template = curent_site.templates
69
+ .find_or_create_by!(partial: false) do |item|
70
+ item.name = "Example Page Template"
71
+ item.content = %(
72
+ <p>I think this is the beginning of a beautiful page template.</p>
73
+ {{ content_for_layout }}
74
+ <p>I think this is the end of a beautiful page template.</p>
75
+ )
76
+ end
77
+
78
+ # Page
79
+ curent_site.pages.find_or_create_by!(slug: "example-page",
80
+ template: page_template,
81
+ homepage: false) do |item|
82
+ item.title = "Example Page"
83
+ item.content = %(
84
+ <p>I think this is the content of the page.</p>
85
+ )
86
+ item.published_at = Time.now
87
+ end
88
+
89
+ # Template
90
+ widget_template = curent_site.templates
91
+ .find_or_create_by!(partial: true) do |item|
92
+ item.name = "Example Widget Template"
93
+ item.content = %(
94
+ <p>I think this is the beginning of a beautiful widget template.</p>
95
+ {{ content_for_layout }}
96
+ <p>I think this is the end of a beautiful widget template.</p>
97
+ )
98
+ end
99
+
100
+ # Widget
101
+ curent_site.widgets.find_or_create_by!(slug: "example-widget",
102
+ template: widget_template) do |item|
103
+ item.name = "Example Widget"
104
+ item.content = %(
105
+ <p>I think this is the content of the widget.</p>
106
+ )
107
+ end
108
+
109
+ # Collection
110
+ collection = curent_site.collections.find_or_create_by!(
111
+ slug: "example-collection"
112
+ ) do |item|
113
+ item.name = "Example Collection"
114
+ end
115
+
116
+ # Fields
117
+ collection.fields.find_or_create_by!(
118
+ collection: collection,
119
+ slug: "field1",
120
+ required: true
121
+ ) do |item|
122
+ item.label = "Field 1"
123
+ item.classification = "string"
124
+ end
125
+
126
+ # Entry
127
+ collection.entries.find_or_create_by(collection: collection) do |item|
128
+ item.value = { field1: "Value for field 1" }
129
+ item.available_at = Time.now
130
+ end
@@ -10,7 +10,7 @@ module Archangel
10
10
  before_validation :parameterize_slug
11
11
 
12
12
  validates :bar, presence: true
13
- validates :slug, presence: true, uniqueness: true
13
+ validates :slug, presence: true, uniqueness: { scope: :site_id }
14
14
 
15
15
  belongs_to :site
16
16
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Archangel::Engine.routes.draw do
3
+ Archangel::Engine.routes.prepend do
4
4
  # Add your routes here
5
5
  end
@@ -53,6 +53,10 @@ module Archangel
53
53
  end
54
54
  end
55
55
 
56
+ config.after_initialize do
57
+ Rails.application.routes_reloader.reload!
58
+ end
59
+
56
60
  config.action_controller.include_all_helpers = false
57
61
 
58
62
  config.generators do |gen|
@@ -4,7 +4,7 @@ module Archangel
4
4
  ##
5
5
  # Archangel gem version
6
6
  #
7
- VERSION = "0.0.5".freeze
7
+ VERSION = "0.0.6".freeze
8
8
 
9
9
  ##
10
10
  # Archangel version
@@ -10,10 +10,6 @@ development:
10
10
  test:
11
11
  <<: *default
12
12
  database: archangel_<%= options[:lib_name] %>_test
13
-
14
- production:
15
- <<: *default
16
- database: archangel_<%= options[:lib_name] %>_production
17
13
  <%- when "postgres" -%>
18
14
  default: &default
19
15
  adapter: postgresql
@@ -26,10 +22,6 @@ development:
26
22
  test:
27
23
  <<: *default
28
24
  database: archangel_<%= options[:lib_name] %>_test
29
-
30
- production:
31
- <<: *default
32
- database: archangel_<%= options[:lib_name] %>_production
33
25
  <%- else -%>
34
26
  default: &default
35
27
  adapter: sqlite3
@@ -41,8 +33,4 @@ development:
41
33
  test:
42
34
  <<: *default
43
35
  database: db/archangel_<%= options[:lib_name] %>_test.sqlite3
44
-
45
- production:
46
- <<: *default
47
- database: db/archangel_<%= options[:lib_name] %>_production.sqlite3
48
36
  <%- end -%>
@@ -57,7 +57,7 @@ module Archangel
57
57
  silence_output
58
58
 
59
59
  Dir.chdir("spec/dummy") do
60
- subject = Archangel::Command::Extension.new([extension_name])
60
+ subject = described_class.new([extension_name])
61
61
  subject.invoke_all
62
62
  end
63
63
  end
@@ -5,28 +5,25 @@ require "rails_helper"
5
5
  module Archangel
6
6
  RSpec.describe Asset, type: :model do
7
7
  context "callbacks" do
8
- it { expect(subject).to callback(:save_asset_attributes).before(:save) }
8
+ it { is_expected.to callback(:save_asset_attributes).before(:save) }
9
9
  end
10
10
 
11
11
  context "validations" do
12
- it { expect(subject).to validate_presence_of(:file) }
13
- it { expect(subject).to validate_presence_of(:file_name) }
12
+ it { is_expected.to validate_presence_of(:file) }
13
+ it { is_expected.to validate_presence_of(:file_name) }
14
14
 
15
- it { expect(subject).to allow_value("success.jpg").for(:file_name) }
15
+ it { is_expected.to allow_value("success.js").for(:file_name) }
16
+ it { is_expected.to allow_value("success.jpg").for(:file_name) }
17
+ it { is_expected.to allow_value("filename.extension").for(:file_name) }
16
18
 
17
- it do
18
- expect(subject).not_to allow_value("without-extension").for(:file_name)
19
- end
20
- it do
21
- expect(subject).not_to allow_value("with.dot.jpg").for(:file_name)
22
- end
23
- it do
24
- expect(subject).not_to allow_value("with space.jpg").for(:file_name)
25
- end
19
+ it { is_expected.to_not allow_value("error.c").for(:file_name) }
20
+ it { is_expected.to_not allow_value("without-extension").for(:file_name) }
21
+ it { is_expected.to_not allow_value("with.dot.jpg").for(:file_name) }
22
+ it { is_expected.to_not allow_value("with space.jpg").for(:file_name) }
26
23
  end
27
24
 
28
25
  context "associations" do
29
- it { expect(subject).to belong_to(:site) }
26
+ it { is_expected.to belong_to(:site) }
30
27
  end
31
28
  end
32
29
  end
@@ -5,21 +5,51 @@ require "rails_helper"
5
5
  module Archangel
6
6
  RSpec.describe Collection, type: :model do
7
7
  context "callbacks" do
8
- it { expect(subject).to callback(:parameterize_slug).before(:validation) }
8
+ it { is_expected.to callback(:parameterize_slug).before(:validation) }
9
9
 
10
- it { expect(subject).to callback(:column_reset).after(:destroy) }
10
+ it { is_expected.to callback(:column_reset).after(:destroy) }
11
11
  end
12
12
 
13
13
  context "validations" do
14
- it { expect(subject).to validate_presence_of(:name) }
15
- it { expect(subject).to validate_presence_of(:slug) }
14
+ it { is_expected.to validate_presence_of(:name) }
15
+ it { is_expected.to validate_presence_of(:slug) }
16
16
 
17
- it { expect(subject).to have_db_index(:slug).unique(true) }
17
+ it "has a unique slug scoped to Site" do
18
+ resource = build(:collection)
19
+
20
+ expect(resource)
21
+ .to validate_uniqueness_of(:slug).scoped_to(:site_id).case_insensitive
22
+ end
18
23
  end
19
24
 
20
25
  context "associations" do
21
- it { expect(subject).to have_many(:entries) }
22
- it { expect(subject).to have_many(:fields) }
26
+ it { is_expected.to belong_to(:site) }
27
+
28
+ it { is_expected.to have_many(:entries) }
29
+ it { is_expected.to have_many(:fields) }
30
+ end
31
+
32
+ context "#to_param" do
33
+ it "uses `slug` as the identifier for routes" do
34
+ resource = build(:collection, slug: "foo")
35
+
36
+ expect(resource.to_param).to eq("foo")
37
+ end
38
+ end
39
+
40
+ context "#column_reset" do
41
+ before { ::Timecop.freeze }
42
+ after { ::Timecop.return }
43
+
44
+ it "resets `slug` to `slug` + current time" do
45
+ resource = create(:collection)
46
+
47
+ slug = resource.slug
48
+
49
+ resource.destroy!
50
+
51
+ expect(resource.slug).to eq "#{Time.current.to_i}_#{slug}"
52
+ end
23
53
  end
24
54
  end
25
55
  end
@@ -5,16 +5,18 @@ require "rails_helper"
5
5
  module Archangel
6
6
  RSpec.describe Entry, type: :model do
7
7
  context "validations" do
8
- it { expect(subject).to validate_presence_of(:collection_id) }
9
- it { expect(subject).to validate_presence_of(:value) }
8
+ it { is_expected.to validate_presence_of(:collection_id) }
9
+ it { is_expected.to validate_presence_of(:value) }
10
10
 
11
- it { expect(subject).to allow_value(nil).for(:available_at) }
12
- it { expect(subject).to allow_value(Time.current).for(:available_at) }
13
- it { expect(subject).not_to allow_value("invalid").for(:available_at) }
11
+ it { is_expected.to allow_value(nil).for(:available_at) }
12
+ it { is_expected.to allow_value("").for(:available_at) }
13
+ it { is_expected.to allow_value(Time.current).for(:available_at) }
14
+
15
+ it { is_expected.to_not allow_value("invalid").for(:available_at) }
14
16
  end
15
17
 
16
18
  context "associations" do
17
- it { expect(subject).to belong_to(:collection) }
19
+ it { is_expected.to belong_to(:collection) }
18
20
  end
19
21
  end
20
22
  end
@@ -5,25 +5,36 @@ require "rails_helper"
5
5
  module Archangel
6
6
  RSpec.describe Field, type: :model do
7
7
  context "validations" do
8
- it { expect(subject).to validate_presence_of(:classification) }
9
- it { expect(subject).to validate_presence_of(:collection_id).on(:update) }
10
- it { expect(subject).to validate_presence_of(:label) }
11
- it { expect(subject).to validate_presence_of(:slug) }
8
+ it { is_expected.to validate_presence_of(:classification) }
9
+ it { is_expected.to validate_presence_of(:collection_id).on(:update) }
10
+ it { is_expected.to validate_presence_of(:label) }
11
+ it { is_expected.to validate_presence_of(:slug) }
12
12
 
13
- it { expect(subject).to allow_value(true).for(:required) }
14
- it { expect(subject).to allow_value(false).for(:required) }
15
- it { expect(subject).not_to allow_value(nil).for(:required) }
13
+ it { is_expected.to allow_value(true).for(:required) }
14
+ it { is_expected.to allow_value(1).for(:required) }
15
+ it { is_expected.to allow_value(false).for(:required) }
16
+ it { is_expected.to allow_value(0).for(:required) }
16
17
 
17
- it do
18
+ it { is_expected.to_not allow_value(nil).for(:required) }
19
+
20
+ it "allows certain classifications" do
18
21
  expect(subject).to(
19
22
  validate_inclusion_of(:classification)
20
- .in_array(%w[string text boolean])
23
+ .in_array(Archangel::Field::CLASSIFICATIONS)
24
+ )
25
+ end
26
+
27
+ it "has a unique slug scoped to Collection" do
28
+ resource = build(:field)
29
+
30
+ expect(resource).to(
31
+ validate_uniqueness_of(:slug).scoped_to(:collection_id)
21
32
  )
22
33
  end
23
34
  end
24
35
 
25
36
  context "associations" do
26
- it { expect(subject).to belong_to(:collection) }
37
+ it { is_expected.to belong_to(:collection) }
27
38
  end
28
39
  end
29
40
  end
@@ -5,38 +5,56 @@ require "rails_helper"
5
5
  module Archangel
6
6
  RSpec.describe Page, type: :model do
7
7
  context "callbacks" do
8
- it { expect(subject).to callback(:parameterize_slug).before(:validation) }
8
+ it { is_expected.to callback(:parameterize_slug).before(:validation) }
9
9
 
10
- it { expect(subject).to callback(:build_page_path).before(:save) }
10
+ it { is_expected.to callback(:build_page_path).before(:save) }
11
11
 
12
- it { expect(subject).to callback(:homepage_reset).after(:save) }
12
+ it { is_expected.to callback(:homepage_reset).after(:save) }
13
13
 
14
- it { expect(subject).to callback(:column_reset).after(:destroy) }
14
+ it { is_expected.to callback(:column_reset).after(:destroy) }
15
15
  end
16
16
 
17
17
  context "validations" do
18
- it { expect(subject).to validate_presence_of(:content) }
19
- it { expect(subject).to validate_presence_of(:slug) }
20
- it { expect(subject).to validate_presence_of(:title) }
18
+ it { is_expected.to validate_presence_of(:content) }
19
+ it { is_expected.to validate_presence_of(:slug) }
20
+ it { is_expected.to validate_presence_of(:title) }
21
21
 
22
- it { expect(subject).to allow_value(true).for(:homepage) }
23
- it { expect(subject).to allow_value(false).for(:homepage) }
24
- it { expect(subject).not_to allow_value(nil).for(:homepage) }
22
+ it { is_expected.to allow_value("{{ foo }}").for(:content) }
25
23
 
26
- it { expect(subject).to allow_value(nil).for(:published_at) }
27
- it { expect(subject).to allow_value(Time.current).for(:published_at) }
28
- it { expect(subject).not_to allow_value("invalid").for(:published_at) }
24
+ it { is_expected.to allow_value(true).for(:homepage) }
25
+ it { is_expected.to allow_value(1).for(:homepage) }
26
+ it { is_expected.to allow_value(false).for(:homepage) }
27
+ it { is_expected.to allow_value(0).for(:homepage) }
29
28
 
30
- it { expect(subject).to have_db_index(:path).unique(true) }
29
+ it { is_expected.to_not allow_value(nil).for(:homepage) }
31
30
 
32
- it { expect(subject).to allow_value("{{ foo }}").for(:content) }
33
- it { expect(subject).not_to allow_value("{{ foo }").for(:content) }
31
+ it { is_expected.to allow_value(nil).for(:published_at) }
32
+ it { is_expected.to allow_value(Time.current).for(:published_at) }
33
+
34
+ it { is_expected.to_not allow_value("invalid").for(:published_at) }
35
+
36
+ it "has a unique path scoped to Site" do
37
+ resource = build(:page)
38
+
39
+ expect(resource).to validate_uniqueness_of(:path).scoped_to(:site_id)
40
+ end
41
+
42
+ it "has a unique slug scoped to Page" do
43
+ resource = build(:page, :with_parent)
44
+
45
+ expect(resource).to(
46
+ validate_uniqueness_of(:slug).scoped_to(:parent_id).case_insensitive
47
+ )
48
+ end
49
+
50
+ it { is_expected.to allow_value("{{ foo }}").for(:content) }
51
+ it { is_expected.to_not allow_value("{{ foo }").for(:content) }
34
52
  end
35
53
 
36
54
  context "associations" do
37
- it { expect(subject).to belong_to(:parent) }
38
- it { expect(subject).to belong_to(:site) }
39
- it { expect(subject).to belong_to(:template) }
55
+ it { is_expected.to belong_to(:site) }
56
+ it { is_expected.to belong_to(:parent).class_name("Archangel::Page") }
57
+ it { is_expected.to belong_to(:template).conditions(partial: false) }
40
58
  end
41
59
 
42
60
  context "scopes" do
@@ -44,7 +62,7 @@ module Archangel
44
62
  it "returns all where published_at <= now" do
45
63
  page = create(:page)
46
64
 
47
- expect(Page.published.first).to eq(page)
65
+ expect(described_class.published.first).to eq(page)
48
66
  end
49
67
  end
50
68
 
@@ -52,13 +70,13 @@ module Archangel
52
70
  it "returns all where published_at is nil" do
53
71
  page = create(:page, :unpublished)
54
72
 
55
- expect(Page.unpublished.first).to eq(page)
73
+ expect(described_class.unpublished.first).to eq(page)
56
74
  end
57
75
 
58
76
  it "returns all where published_at is > now" do
59
77
  page = create(:page, :future)
60
78
 
61
- expect(Page.unpublished.first).to eq(page)
79
+ expect(described_class.unpublished.first).to eq(page)
62
80
  end
63
81
  end
64
82
 
@@ -66,12 +84,12 @@ module Archangel
66
84
  it "returns all where homepage is true" do
67
85
  page = create(:page, :homepage)
68
86
 
69
- expect(Page.homepage.first).to eq(page)
87
+ expect(described_class.homepage.first).to eq(page)
70
88
  end
71
89
  end
72
90
  end
73
91
 
74
- context "#published?" do
92
+ context ".published?" do
75
93
  it "is published" do
76
94
  page = build(:page)
77
95
 
@@ -90,5 +108,28 @@ module Archangel
90
108
  expect(page.published?).to be_falsey
91
109
  end
92
110
  end
111
+
112
+ context "#to_liquid" do
113
+ it "returns a Liquid object" do
114
+ resource = build(:page)
115
+
116
+ expect(resource.to_liquid).to be_a(Archangel::Liquid::Drops::PageDrop)
117
+ end
118
+ end
119
+
120
+ context "#column_reset" do
121
+ before { ::Timecop.freeze }
122
+ after { ::Timecop.return }
123
+
124
+ it "resets `slug` to `slug` + current time" do
125
+ resource = create(:page)
126
+
127
+ slug = resource.slug
128
+
129
+ resource.destroy!
130
+
131
+ expect(resource.slug).to eq "#{Time.current.to_i}_#{slug}"
132
+ end
133
+ end
93
134
  end
94
135
  end