archangel 0.0.5 → 0.0.6

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