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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d09b2b524c0d918a1098d8f77e7c4e41b3614bffe7703a28df6f26932dcf0d19
4
- data.tar.gz: d5d7a79459ce16ab1a8109b803cff19dce14b1f3b813ddf716edb71c2c2b638a
3
+ metadata.gz: ffb41416bed166dc7a839e962bd30c941dbc5a617a082bafd8b53c9dfce8dfb1
4
+ data.tar.gz: 21ee7b769a7678816b1668800714dac78292c07aa60d6abc3a86f807c5302c56
5
5
  SHA512:
6
- metadata.gz: baffd2cd0808981ad90eeb76a4925d3dd7a843da6f38a77894cca076d6a1a00f602e8a07741023c9882be15e7b1f2b633ef9e8470dbf4bb9d3a26f6017240587
7
- data.tar.gz: 1d81da1349524ed0ac92dedd88abd93620b78b7b09fb3057d4927b39cadb7c4f3a1da9a9b13820212ff804332eccbc95509793466d9ac9fcb6f8e1f9c85d5b3f
6
+ metadata.gz: 6b0381d552c49d82b3ee4bc5fe1501e06e7aa809e7ae9f1209e6761d2252c262b507ab18ede3136310b241d8b7eedbd459f7fa9ac5630c6922ec3f18a6bd9e10
7
+ data.tar.gz: 4156e91ffcf03d124aad5654b773d39d92a1e1733f817246eda137dcb964695fceedbbcee63a51c672168fa464cc4ae9da11fa3cf57eacaacd0bad39aafad92e
data/.jshintrc CHANGED
@@ -2,12 +2,12 @@
2
2
  "globals": {
3
3
  "$": true,
4
4
  "Archangel": true,
5
+ "Sortable": true,
6
+ "XMLHttpRequest": true,
5
7
  "document": true,
6
8
  "jQuery": true,
7
9
  "localStorage": true,
8
- "Sortable": true,
9
- "window": true,
10
- "XMLHttpRequest": true
10
+ "window": true
11
11
  },
12
12
  "boss": true,
13
13
  "curly": true,
data/.reek CHANGED
@@ -30,6 +30,15 @@ UtilityFunction:
30
30
  enabled: false
31
31
  UtilityFunction:
32
32
  enabled: false
33
+ "app/inputs":
34
+ InstanceVariableAssumption:
35
+ enabled: false
33
36
  "app/mailers":
34
37
  InstanceVariableAssumption:
35
38
  enabled: false
39
+ "app/policies":
40
+ InstanceVariableAssumption:
41
+ enabled: false
42
+ "app/uploaders":
43
+ UtilityFunction:
44
+ enabled: false
data/Gemfile CHANGED
@@ -33,4 +33,5 @@ group :test do
33
33
  gem "shoulda-callback-matchers", "~> 1.1"
34
34
  gem "shoulda-matchers", "~> 3.1"
35
35
  gem "simplecov", "~> 0.14"
36
+ gem "timecop", "~> 0.9"
36
37
  end
@@ -28,7 +28,7 @@
28
28
  },
29
29
 
30
30
  flashMessage: function(type, message) {
31
- if (message == '' || message == undefined) {
31
+ if (message === '' || message === undefined) {
32
32
  return false;
33
33
  }
34
34
 
@@ -37,7 +37,7 @@
37
37
  var messagesContainer = document.querySelector('#alert-messages'),
38
38
  msgContainer = document.createElement('div');
39
39
 
40
- msgContainer.setAttribute('class', 'alert alert-' + type + ' alert-link');
40
+ msgContainer.setAttribute('class', 'alert alert-' + type + ' alert-link alert-dismissable fade-in');
41
41
  msgContainer.setAttribute('role', 'alert');
42
42
  msgContainer.innerHTML = message;
43
43
 
@@ -75,6 +75,10 @@
75
75
  return '/' + finalPath;
76
76
  };
77
77
 
78
+ object.rootUrl = function() {
79
+ return window.location.origin + object.rootPath();
80
+ };
81
+
78
82
  object.route = {
79
83
  rootPath: object.rootPath()
80
84
  };
@@ -5,15 +5,26 @@
5
5
  return object.pathBuilder([object.mountScope(), object.backendScope()]);
6
6
  };
7
7
 
8
+ object.backendUrl = function () {
9
+ return [object.rootUrl(), object.backendPath()].join('/');
10
+ };
11
+
8
12
  object.backendPathFor = function (path, args) {
9
13
  return object.pathFor([object.backendScope(), path], args);
10
14
  };
11
15
 
16
+ object.backendUrlFor = function (path, args) {
17
+ return object.backendUrl() + object.backendPathFor(path, args);
18
+ };
19
+
12
20
  object.route.backend = {
13
- // Dashboard
21
+ // Dashboard (path)
14
22
  rootPath: object.backendPath(),
15
23
 
16
- // Assets
24
+ // Dashboard (url)
25
+ rootUrl: object.backendUrl(),
26
+
27
+ // Assets (path)
17
28
  assetsPath: object.backendPathFor('assets'),
18
29
  newAssetPath: object.backendPathFor('assets/new'),
19
30
  assetPath: function (id) {
@@ -16,7 +16,7 @@ module Archangel
16
16
 
17
17
  {
18
18
  success: "success", error: "danger", alert: "warning", notice: "info"
19
- }[flash_type.to_sym] || flash_type
19
+ }.fetch(flash_type.to_sym, flash_type)
20
20
  end
21
21
  end
22
22
  end
@@ -34,7 +34,7 @@ module Archangel
34
34
  end
35
35
 
36
36
  def valid_file_name
37
- return if /^[\w-]+\.[A-Za-z]{3}$/ =~ file_name
37
+ return if /^[\w-]+\.[A-Za-z]{2,}$/ =~ file_name
38
38
 
39
39
  errors.add(:file_name, Archangel.t(:file_name_invalid))
40
40
  end
@@ -12,10 +12,10 @@ module Archangel
12
12
  after_destroy :column_reset
13
13
 
14
14
  validates :name, presence: true
15
- validates :slug, presence: true, uniqueness: true
15
+ validates :slug, presence: true, uniqueness: { scope: :site_id }
16
16
 
17
- has_many :entries, inverse_of: :collection, dependent: :destroy
18
- has_many :fields, inverse_of: :collection, dependent: :destroy
17
+ has_many :entries, inverse_of: :collection
18
+ has_many :fields, inverse_of: :collection
19
19
 
20
20
  accepts_nested_attributes_for :fields, reject_if: :all_blank,
21
21
  allow_destroy: true
@@ -20,7 +20,7 @@ module Archangel
20
20
 
21
21
  validates :content, presence: true
22
22
  validates :homepage, inclusion: { in: [true, false] }
23
- validates :path, uniqueness: true
23
+ validates :path, uniqueness: { scope: :site_id }
24
24
  validates :published_at, allow_blank: true, date: true
25
25
  validates :slug, presence: true, uniqueness: { scope: :parent_id }
26
26
  validates :title, presence: true
@@ -18,18 +18,17 @@ module Archangel
18
18
  less_than_or_equal_to: Archangel.config.image_maximum_file_size
19
19
  }
20
20
  validates :name, presence: true
21
- validates :theme, presence: true,
22
- inclusion: { in: Archangel.themes },
23
- allow_blank: true
21
+ validates :theme, inclusion: { in: Archangel.themes }, allow_blank: true
24
22
 
25
23
  has_many :assets
26
- has_many :collections
27
24
  has_many :pages
28
25
  has_many :templates
29
26
  has_many :users
30
27
  has_many :widgets
31
28
 
29
+ has_many :collections
32
30
  has_many :entries, through: :collections
31
+ has_many :fields, through: :collections
33
32
 
34
33
  ##
35
34
  # Current site
@@ -22,12 +22,14 @@ module Archangel
22
22
  validates :avatar, file_size: {
23
23
  less_than_or_equal_to: Archangel.config.image_maximum_file_size
24
24
  }
25
- validates :email, presence: true, uniqueness: true, email: true
25
+ validates :email, presence: true,
26
+ email: true,
27
+ uniqueness: { scope: :site_id }
26
28
  validates :name, presence: true
27
29
  validates :password, presence: true, length: { minimum: 8 }, on: :create
28
30
  validates :password, allow_blank: true, length: { minimum: 8 }, on: :update
29
31
  validates :role, presence: true, inclusion: { in: Archangel::ROLES }
30
- validates :username, presence: true, uniqueness: true
32
+ validates :username, presence: true, uniqueness: { scope: :site_id }
31
33
 
32
34
  belongs_to :site
33
35
 
@@ -13,7 +13,7 @@ module Archangel
13
13
 
14
14
  validates :content, presence: true
15
15
  validates :name, presence: true
16
- validates :slug, presence: true, uniqueness: true
16
+ validates :slug, presence: true, uniqueness: { scope: :site_id }
17
17
 
18
18
  validate :valid_liquid_content
19
19
 
@@ -58,17 +58,11 @@ module Archangel
58
58
  #
59
59
  def call
60
60
  liquid = ::Liquid::Template.parse(template)
61
- liquid.send(liquid_renderer,
62
- stringify_assigns,
63
- liquid_options).html_safe
61
+ liquid.send(:render, stringify_assigns, liquid_options).html_safe
64
62
  end
65
63
 
66
64
  protected
67
65
 
68
- def liquid_renderer
69
- %w[development test].include?(Rails.env) ? :render! : :render
70
- end
71
-
72
66
  def stringify_assigns
73
67
  assigns.deep_stringify_keys
74
68
  end
@@ -14,9 +14,7 @@ module Archangel
14
14
  template_content = build_template(template)
15
15
 
16
16
  liquid = ::Liquid::Template.parse(template_content)
17
- liquid.send(liquid_renderer,
18
- stringify_assigns,
19
- liquid_options).html_safe
17
+ liquid.send(:render, stringify_assigns, liquid_options).html_safe
20
18
  end
21
19
 
22
20
  protected
@@ -44,7 +44,5 @@
44
44
  // Theme assets
45
45
  //= require default/common/cards
46
46
  //= require default/common/flash
47
- //= require default/common/navigation
48
- //= require default/common/sidebar
49
47
  //
50
48
  //= require default/backend/core
@@ -1,7 +1,76 @@
1
1
  (function () {
2
2
  'use strict';
3
3
 
4
- document.addEventListener('DOMContentLoaded', function() {
5
- // Nothing
4
+ jQuery(function() {
5
+
6
+ function resizeBroadcast() {
7
+ var timesRun = 0,
8
+ interval = setInterval(function() {
9
+ timesRun += 1;
10
+ if (timesRun === 5) {
11
+ clearInterval(interval);
12
+ }
13
+ window.dispatchEvent(new Event('resize'));
14
+ }, 62.5);
15
+ }
16
+
17
+ // Add class .active to current link
18
+ $('nav > ul.nav').find('a').each(function() {
19
+ var currentUrl = String(window.location).split('?')[0],
20
+ rootUrl = Archangel.route.backend.rootUrl,
21
+ itemHref = $($(this))[0].href;
22
+
23
+ if (currentUrl.substr(currentUrl.length - 1) === '#') {
24
+ currentUrl = currentUrl.slice(0, -1);
25
+ }
26
+
27
+ // Dashboard
28
+ if (itemHref === rootUrl && itemHref === currentUrl) {
29
+ $(this).addClass('active');
30
+
31
+ return;
32
+ }
33
+
34
+ // All other items
35
+ if (itemHref !== rootUrl && currentUrl.lastIndexOf(itemHref, 0) === 0) {
36
+ $(this).addClass('active');
37
+ }
38
+ });
39
+
40
+ // Dropdown Menu
41
+ $('nav > ul.nav').on('click', 'a', function(evt) {
42
+ if ($.ajaxLoad) {
43
+ evt.preventDefault();
44
+ }
45
+
46
+ if ($(this).hasClass('nav-dropdown-toggle')) {
47
+ $(this).parent().toggleClass('open');
48
+
49
+ resizeBroadcast();
50
+ }
51
+ });
52
+
53
+ $('.sidebar-toggler').click(function(){
54
+ $('body').toggleClass('sidebar-hidden');
55
+
56
+ resizeBroadcast();
57
+ });
58
+
59
+ $('.sidebar-minimizer').click(function(){
60
+ $('body').toggleClass('sidebar-minimized');
61
+
62
+ resizeBroadcast();
63
+ });
64
+
65
+ $('.brand-minimizer').click(function(){
66
+ $('body').toggleClass('brand-minimized');
67
+ });
68
+
69
+ $('.mobile-sidebar-toggler').click(function(){
70
+ $('body').toggleClass('sidebar-mobile-show');
71
+
72
+ resizeBroadcast();
73
+ });
74
+
6
75
  });
7
76
  }());
@@ -21,7 +21,7 @@
21
21
 
22
22
  clearInterval(fadeInternal);
23
23
 
24
- if (typeof callback == 'function') callback(true);
24
+ if (typeof callback === 'function') { callback(true); }
25
25
  }
26
26
 
27
27
  else {
@@ -22,6 +22,8 @@
22
22
  <div class="card-body">
23
23
  <%= render "archangel/shared/flash_messages" %>
24
24
 
25
+ <%= image_tag(current_site.logo.medium.url, alt: current_site.name, class: "mx-auto d-block") %>
26
+
25
27
  <%= yield %>
26
28
  </div>
27
29
  </div>
@@ -34,12 +34,14 @@
34
34
  </li>
35
35
 
36
36
  <% if current_site.collections.present? %>
37
- <li class="nav-title">
38
- <%= Archangel.t(:collections) %>
39
- </li>
40
-
41
- <% for item in current_site.collections %>
37
+ <% current_site.collections.each_with_index do |item, index| %>
42
38
  <% if item.persisted? %>
39
+ <% if index.zero? %>
40
+ <li class="nav-title">
41
+ <%= Archangel.t(:collections) %>
42
+ </li>
43
+ <% end %>
44
+
43
45
  <li class="nav-item">
44
46
  <a class="nav-link" href="<%= backend_collection_entries_path(item) %>"><%= fa_icon("circle") %> <%= item.name %></a>
45
47
  </li>
@@ -1,8 +1,8 @@
1
1
  <div id="alert-messages">
2
2
  <% unless flash.empty? %>
3
- <% flash.delete(:timedout).each do |key, value| %>
4
- <div class="alert alert-<%= flash_class_for(key) %> alert-link" role="alert">
5
- <%= value %>
3
+ <% flash.delete(:timedout).each do |type, message| %>
4
+ <div class="alert alert-<%= flash_class_for(type) %> alert-link alert-dismissable" role="alert">
5
+ <%= message %>
6
6
  </div>
7
7
  <% end %>
8
8
  <% end %>
@@ -1,30 +1,30 @@
1
- <ul class="nav justify-content-center">
1
+ <ul class="list-inline text-center">
2
2
  <%- if controller_name != "sessions" %>
3
- <li class="nav-item">
3
+ <li class="list-inline-item">
4
4
  <%= link_to("Log in", new_session_path(resource_name), class: "nav-link") %>
5
5
  </li>
6
6
  <% end -%>
7
7
 
8
8
  <%- if Archangel.config.allow_registration && devise_mapping.registerable? && controller_name != "registrations" %>
9
- <li class="nav-item">
9
+ <li class="list-inline-item">
10
10
  <%= link_to("Sign up", new_registration_path(resource_name), class: "nav-link") %>
11
11
  </li>
12
12
  <% end -%>
13
13
 
14
14
  <%- if devise_mapping.recoverable? && controller_name != "passwords" && controller_name != "registrations" %>
15
- <li class="nav-item">
15
+ <li class="list-inline-item">
16
16
  <%= link_to("Forgot your password?", new_password_path(resource_name), class: "nav-link") %>
17
17
  </li>
18
18
  <% end -%>
19
19
 
20
20
  <%- if devise_mapping.confirmable? && controller_name != "confirmations" %>
21
- <li class="nav-item">
21
+ <li class="list-inline-item">
22
22
  <%= link_to("Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "nav-link") %>
23
23
  </li>
24
24
  <% end -%>
25
25
 
26
26
  <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != "unlocks" %>
27
- <li class="nav-item">
27
+ <li class="list-inline-item">
28
28
  <%= link_to("Didn't receive unlock instructions?", new_unlock_path(resource_name), class: "nav-link") %>
29
29
  </li>
30
30
  <% end -%>
@@ -33,7 +33,7 @@
33
33
  <%- if devise_mapping.omniauthable? %>
34
34
  <ul class="nav justify-content-center">
35
35
  <%- resource_class.omniauth_providers.each do |provider| %>
36
- <li class="nav-item">
36
+ <li class="list-inline-item">
37
37
  <%= link_to("Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), class: "nav-link") %>
38
38
  </li>
39
39
  <% end -%>
@@ -52,7 +52,7 @@ class CreateArchangelUsers < ActiveRecord::Migration[5.1]
52
52
  t.timestamps null: false
53
53
  end
54
54
 
55
- add_index :archangel_users, :email, unique: true
55
+ add_index :archangel_users, :email
56
56
  add_index :archangel_users, :reset_password_token, unique: true
57
57
  add_index :archangel_users, :confirmation_token, unique: true
58
58
  add_index :archangel_users, :unlock_token, unique: true
@@ -60,7 +60,7 @@ class CreateArchangelUsers < ActiveRecord::Migration[5.1]
60
60
  add_index :archangel_users, :name
61
61
  add_index :archangel_users, :role
62
62
  add_index :archangel_users, :site_id
63
- add_index :archangel_users, :username, unique: true
63
+ add_index :archangel_users, :username
64
64
  add_index :archangel_users, :invitations_count
65
65
  add_index :archangel_users, :invitation_token, unique: true
66
66
  add_index :archangel_users, :invited_by_id
@@ -20,7 +20,7 @@ class CreateArchangelPages < ActiveRecord::Migration[5.1]
20
20
  add_index :archangel_pages, :deleted_at
21
21
  add_index :archangel_pages, :homepage
22
22
  add_index :archangel_pages, :parent_id
23
- add_index :archangel_pages, :path, unique: true
23
+ add_index :archangel_pages, :path
24
24
  add_index :archangel_pages, :published_at
25
25
  add_index :archangel_pages, :site_id
26
26
  add_index :archangel_pages, :slug