udongo 2.0.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/backend/application.js +1 -0
  3. data/app/assets/javascripts/backend/bootstrap.js +3 -3569
  4. data/app/assets/javascripts/backend/tree.js +106 -65
  5. data/app/assets/stylesheets/backend/application.scss +2 -0
  6. data/app/assets/stylesheets/backend/bootstrap.scss +29 -51
  7. data/app/assets/stylesheets/backend/components/_page_tree.scss +9 -0
  8. data/app/assets/stylesheets/backend/custom.scss +0 -0
  9. data/app/assets/stylesheets/backend/font-awesome.scss +644 -1977
  10. data/app/assets/stylesheets/backend/udongo.scss +1 -0
  11. data/app/controllers/backend/admins_controller.rb +2 -2
  12. data/app/controllers/{backend_controller.rb → backend/base_controller.rb} +13 -5
  13. data/app/controllers/backend/content/rows/columns_controller.rb +1 -1
  14. data/app/controllers/backend/content/rows/images_controller.rb +1 -1
  15. data/app/controllers/backend/content/rows/texts_controller.rb +1 -1
  16. data/app/controllers/backend/content/rows_controller.rb +1 -1
  17. data/app/controllers/backend/dashboard_controller.rb +1 -1
  18. data/app/controllers/backend/email_templates_controller.rb +12 -12
  19. data/app/controllers/backend/emails_controller.rb +1 -1
  20. data/app/controllers/backend/navigation/items_controller.rb +9 -11
  21. data/app/controllers/backend/navigations_controller.rb +1 -1
  22. data/app/controllers/backend/pages_controller.rb +17 -39
  23. data/app/controllers/backend/redirects_controller.rb +1 -1
  24. data/app/controllers/backend/seo_controller.rb +1 -1
  25. data/app/controllers/backend/sessions_controller.rb +1 -1
  26. data/app/controllers/backend/snippets_controller.rb +14 -13
  27. data/app/controllers/backend/tagbox_controller.rb +1 -1
  28. data/app/controllers/catch_all_controller.rb +1 -1
  29. data/app/controllers/concerns/backend/content_type_controller.rb +3 -1
  30. data/app/controllers/redirects_controller.rb +1 -1
  31. data/app/decorators/page_decorator.rb +1 -4
  32. data/app/forms/backend/email_template_translation_form.rb +1 -23
  33. data/app/forms/backend/navigation_item_translation_form.rb +1 -23
  34. data/app/forms/backend/page_translation_form.rb +13 -18
  35. data/app/forms/backend/snippet_translation_form.rb +1 -23
  36. data/app/forms/backend/translation_form.rb +22 -0
  37. data/app/helpers/udongo_helper.rb +0 -4
  38. data/app/mailers/general_mailer.rb +14 -4
  39. data/app/models/admin.rb +2 -2
  40. data/app/models/comment.rb +1 -2
  41. data/app/models/concerns/addressable.rb +40 -0
  42. data/app/models/concerns/addressable/config.rb +33 -0
  43. data/app/models/concerns/cacheable.rb +1 -1
  44. data/app/models/email.rb +2 -2
  45. data/app/models/email_template.rb +2 -1
  46. data/app/views/backend/_general_form_error.html.erb +6 -0
  47. data/app/views/backend/admins/_form.html.erb +3 -0
  48. data/app/views/backend/content/rows/columns/_dimension_fields.html.erb +3 -0
  49. data/app/views/backend/content/rows/columns/edit.html.erb +3 -5
  50. data/app/views/backend/content/rows/columns/new.html.erb +3 -5
  51. data/app/views/backend/content/rows/images/edit.html.erb +2 -0
  52. data/app/views/backend/dashboard/show.html.erb +1 -1
  53. data/app/views/backend/email_templates/_form.html.erb +29 -7
  54. data/app/views/backend/email_templates/_tabs.html.erb +1 -1
  55. data/app/views/backend/email_templates/edit_translation.html.erb +1 -0
  56. data/app/views/backend/navigation/items/_form.html.erb +4 -2
  57. data/app/views/backend/navigation/items/_tabs.html.erb +1 -1
  58. data/app/views/backend/navigation/items/edit_translation.html.erb +1 -0
  59. data/app/views/backend/pages/_form.html.erb +4 -2
  60. data/app/views/backend/pages/_tabs.html.erb +1 -1
  61. data/app/views/backend/pages/edit_translation.html.erb +1 -0
  62. data/app/views/backend/redirects/_form.html.erb +2 -0
  63. data/app/views/backend/snippets/_form.html.erb +3 -1
  64. data/app/views/backend/snippets/_tabs.html.erb +1 -1
  65. data/app/views/backend/snippets/edit.html.erb +1 -1
  66. data/app/views/backend/snippets/edit_translation.html.erb +1 -0
  67. data/app/views/backend/snippets/new.html.erb +1 -1
  68. data/app/views/layouts/backend/_top_navigation.html.erb +1 -2
  69. data/changelog.md +38 -0
  70. data/config/initializers/simple_form_bootstrap.rb +13 -9
  71. data/config/locales/en_backend.yml +1 -4
  72. data/config/locales/en_forms.yml +3 -0
  73. data/config/locales/nl_backend.yml +3 -4
  74. data/config/locales/nl_forms.yml +3 -0
  75. data/config/routes.rb +5 -7
  76. data/db/migrate/20160815100903_remove_form_models.rb +9 -0
  77. data/db/migrate/20161014135637_add_category_to_admin.rb +5 -0
  78. data/db/migrate/20161029124558_add_locale_to_admin.rb +6 -0
  79. data/db/migrate/20161029130557_add_bcc_and_cc_to_email_templates.rb +6 -0
  80. data/db/migrate/20161029171056_add_ccc_and_bcc_to_email.rb +6 -0
  81. data/lib/udongo/configs/flexible_content.rb +7 -0
  82. data/lib/udongo/configs/i18n.rb +5 -3
  83. data/lib/udongo/configs/i18ns/app.rb +12 -0
  84. data/lib/udongo/configs/i18ns/cms.rb +12 -0
  85. data/lib/udongo/flexible_content/column_width_calculator.rb +4 -2
  86. data/lib/udongo/pages/tree.rb +15 -0
  87. data/lib/udongo/pages/tree_node.rb +43 -0
  88. data/lib/udongo/version.rb +1 -1
  89. data/readme.md +103 -43
  90. data/vendor/assets/javascripts/backend/select2.min.js +3 -0
  91. data/vendor/assets/stylesheets/backend/jstree/default/style.scss +3 -3
  92. data/vendor/assets/stylesheets/backend/select2.min.scss +1 -0
  93. metadata +22 -30
  94. data/app/controllers/backend/forms/base_controller.rb +0 -14
  95. data/app/controllers/backend/forms/submissions_controller.rb +0 -8
  96. data/app/controllers/backend/forms_controller.rb +0 -7
  97. data/app/controllers/backend/webserver_controller.rb +0 -6
  98. data/app/decorators/form_decorator.rb +0 -16
  99. data/app/decorators/form_submission_decorator.rb +0 -3
  100. data/app/forms/backend/email_template_form.rb +0 -38
  101. data/app/forms/backend/navigation_item_form.rb +0 -23
  102. data/app/forms/backend/page_form.rb +0 -26
  103. data/app/forms/backend/snippet_form.rb +0 -35
  104. data/app/models/form.rb +0 -10
  105. data/app/models/form_field.rb +0 -15
  106. data/app/models/form_field_validation.rb +0 -11
  107. data/app/models/form_submission.rb +0 -15
  108. data/app/models/form_submission_data.rb +0 -5
  109. data/app/views/backend/_form_errors.html.erb +0 -15
  110. data/app/views/backend/forms/index.html.erb +0 -27
  111. data/app/views/backend/forms/submissions/_filter.html.erb +0 -16
  112. data/app/views/backend/forms/submissions/index.html.erb +0 -34
  113. data/lib/generators/udongo/form/form_generator.rb +0 -62
  114. data/lib/generators/udongo/form/templates/form.rb +0 -18
  115. data/lib/udongo/configs/forms.rb +0 -18
  116. data/lib/udongo/configs/routes.rb +0 -13
  117. data/lib/udongo/email_vars/form_submission.rb +0 -18
  118. data/lib/udongo/forms/submission_datagrid.rb +0 -27
  119. data/lib/udongo/forms/submission_filter.rb +0 -31
@@ -1,33 +1,11 @@
1
- class Backend::EmailTemplateTranslationForm < Udongo::Form
2
- attr_reader :email_template, :translation
3
-
1
+ class Backend::EmailTemplateTranslationForm < Backend::TranslationForm
4
2
  attribute :subject, String
5
3
  attribute :plain_content, String
6
4
  attribute :html_content, String
7
5
 
8
6
  validates :subject, :plain_content, :html_content, presence: true
9
7
 
10
- delegate :id, to: :email_template
11
-
12
- def initialize(email_template, translation)
13
- @email_template = email_template
14
- @translation = translation
15
-
16
- init_attribute_values(@translation)
17
- end
18
-
19
8
  def self.model_name
20
9
  EmailTemplate.model_name
21
10
  end
22
-
23
- def persisted?
24
- true
25
- end
26
-
27
- private
28
-
29
- def save_object
30
- init_object_values(@translation)
31
- @translation.save
32
- end
33
11
  end
@@ -1,30 +1,8 @@
1
- class Backend::NavigationItemTranslationForm < Udongo::Form
2
- attr_reader :navigation_item, :translation
3
-
1
+ class Backend::NavigationItemTranslationForm < Backend::TranslationForm
4
2
  attribute :label, String
5
3
  attribute :path, String
6
4
 
7
- delegate :id, to: :navigation_item
8
-
9
- def initialize(navigation_item, translation)
10
- @navigation_item = navigation_item
11
- @translation = translation
12
-
13
- init_attribute_values(translation)
14
- end
15
-
16
5
  def self.model_name
17
6
  NavigationItem.model_name
18
7
  end
19
-
20
- def persisted?
21
- true
22
- end
23
-
24
- private
25
-
26
- def save_object
27
- init_object_values(@translation)
28
- @translation.save
29
- end
30
8
  end
@@ -22,11 +22,9 @@ class Backend::PageTranslationForm < Udongo::Form
22
22
  self.title = @translation.title
23
23
  self.subtitle = @translation.subtitle
24
24
 
25
- self.seo_title = @seo.title
26
- self.seo_keywords = @seo.keywords
27
- self.seo_description = @seo.description
28
- self.seo_custom = @seo.custom
29
- self.seo_slug = @seo.slug
25
+ %w(title keywords description custom slug).each do |f|
26
+ self.send("seo_#{f}=", @seo.send(f))
27
+ end
30
28
  end
31
29
 
32
30
  def self.model_name
@@ -41,11 +39,9 @@ class Backend::PageTranslationForm < Udongo::Form
41
39
  self.title = params[:title]
42
40
  self.subtitle = params[:subtitle]
43
41
 
44
- self.seo_title = params[:seo_title]
45
- self.seo_keywords = params[:seo_keywords]
46
- self.seo_description = params[:seo_description]
47
- self.seo_custom = params[:seo_custom]
48
- self.seo_slug = params[:seo_slug]
42
+ %w(title keywords description custom slug).each do |f|
43
+ self.send("seo_#{f}=", params["seo_#{f}".to_sym])
44
+ end
49
45
 
50
46
  if valid?
51
47
  save_object
@@ -60,13 +56,12 @@ class Backend::PageTranslationForm < Udongo::Form
60
56
  def save_object
61
57
  @translation.title = title
62
58
  @translation.subtitle = subtitle
63
- @translation.save
64
-
65
- @seo.title = seo_title
66
- @seo.keywords = seo_keywords
67
- @seo.description = seo_description
68
- @seo.custom = seo_custom
69
- @seo.slug = seo_slug
70
- @seo.save
59
+
60
+ %w(title keywords description custom slug).each do |f|
61
+ @seo.send("#{f}=", send("seo_#{f}"))
62
+ end
63
+
64
+ # Saves the page, translation and SEO info all at once.
65
+ @page.save
71
66
  end
72
67
  end
@@ -1,30 +1,8 @@
1
- class Backend::SnippetTranslationForm < Udongo::Form
2
- attr_reader :snippet, :translation
3
-
1
+ class Backend::SnippetTranslationForm < Backend::TranslationForm
4
2
  attribute :title, String
5
3
  attribute :content, String
6
4
 
7
- delegate :id, to: :snippet
8
-
9
- def initialize(snippet, translation)
10
- @snippet = snippet
11
- @translation = translation
12
-
13
- init_attribute_values(translation)
14
- end
15
-
16
5
  def self.model_name
17
6
  Snippet.model_name
18
7
  end
19
-
20
- def persisted?
21
- true
22
- end
23
-
24
- private
25
-
26
- def save_object
27
- init_object_values(@translation)
28
- @translation.save
29
- end
30
8
  end
@@ -0,0 +1,22 @@
1
+ class Backend::TranslationForm < Udongo::Form
2
+ attr_reader :model, :translation
3
+ delegate :id, to: :model
4
+
5
+ def initialize(model, translation)
6
+ @model = model
7
+ @translation = translation
8
+
9
+ init_attribute_values(@translation)
10
+ end
11
+
12
+ def persisted?
13
+ true
14
+ end
15
+
16
+ private
17
+
18
+ def save_object
19
+ init_object_values(@translation)
20
+ @model.save
21
+ end
22
+ end
@@ -5,10 +5,6 @@ module UdongoHelper
5
5
  js_asset_loader.load_js file, target
6
6
  end
7
7
 
8
- def restart_webserver_button
9
- link_to I18n.t('b.restart_webserver'), backend_restart_webserver_path, class: 'btn btn-info', method: 'post'
10
- end
11
-
12
8
  # Before using: Put <%= yield(:stylesheets) %> in the <head> of your app's frontend
13
9
  def stylesheet(file, media = :screen)
14
10
  css_asset_loader.view = self
@@ -1,13 +1,23 @@
1
1
  class GeneralMailer < ActionMailer::Base
2
2
  def email(email)
3
- from = "#{email.from_name} <#{email.from_email}>"
4
- to = "#{email.to_name} <#{email.to_email}>"
5
-
6
- mail(from: from, to: to, subject: email.subject) do |format|
3
+ mail(headers(email)) do |format|
7
4
  format.text { render text: email.plain_content }
8
5
  format.html { render html: email.html_content.html_safe }
9
6
  end
10
7
 
11
8
  email.mark_as_sent!
12
9
  end
10
+
11
+ private
12
+
13
+ def headers(email)
14
+ from = "#{email.from_name} <#{email.from_email}>"
15
+ to = "#{email.to_name} <#{email.to_email}>"
16
+
17
+ {
18
+ from: from,
19
+ to: to,
20
+ subject: email.subject
21
+ }
22
+ end
13
23
  end
data/app/models/admin.rb CHANGED
@@ -2,8 +2,8 @@ class Admin < ApplicationRecord
2
2
  include Concerns::Person
3
3
  has_secure_password
4
4
 
5
- validates :first_name, :last_name, presence: true
5
+ validates :locale, :first_name, :last_name, presence: true
6
6
  validates :email,
7
7
  uniqueness: { case_sensitive: false },
8
- format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
8
+ email: true
9
9
  end
@@ -11,8 +11,7 @@ class Comment < ApplicationRecord
11
11
 
12
12
  validates :author, :message, presence: true
13
13
  validates :status, inclusion: { in: STATUSES }
14
- validates :email, presence: true,
15
- format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
14
+ validates :email, presence: true, email: true
16
15
  validates :website, url: true, allow_blank: true
17
16
 
18
17
  def published?
@@ -0,0 +1,40 @@
1
+ module Concerns
2
+ module Addressable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :addresses, dependent: :destroy
7
+ end
8
+
9
+ module ClassMethods
10
+ def configure_adress(categories, default: nil)
11
+ address_config.update(categories, default: default)
12
+ end
13
+
14
+ def address_config
15
+ @address_config ||= Concerns::Addressable::Config.new
16
+ end
17
+ end
18
+
19
+ def address(category = nil)
20
+ category = self.class.address_config.default unless category.present?
21
+
22
+ unless self.class.address_config.allowed?(category)
23
+ raise "You can't select the '#{category}' address because it's not an allowed category"
24
+ end
25
+
26
+ @address_collections = {} unless @address_collections
27
+
28
+ unless @address_collections[category.to_sym]
29
+
30
+ @address_collections[category.to_sym] = Address.find_or_initialize_by(
31
+ category: category,
32
+ addressable_type: self.class.name,
33
+ addressable_id: id
34
+ )
35
+ end
36
+
37
+ @address_collections[category.to_sym]
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ module Concerns
2
+ module Addressable
3
+ class Config
4
+ attr_reader :fields, :default
5
+
6
+ def initialize
7
+ @fields = []
8
+ @default = nil
9
+ end
10
+
11
+ def update(categories, default: nil)
12
+ unless categories.respond_to?(:each) && categories.any?
13
+ raise 'Please provide an array with address categories'
14
+ end
15
+
16
+ @fields = categories.map(&:to_sym).uniq
17
+ @default = @fields.first
18
+
19
+ if default
20
+ unless @fields.include?(default.to_sym)
21
+ raise "You can't make '#{default.to_s}' the default address category because it's not in the list of categories"
22
+ end
23
+
24
+ @default = default.to_sym
25
+ end
26
+ end
27
+
28
+ def allowed?(field)
29
+ @fields.include?(field.to_sym)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -7,7 +7,7 @@ module Concerns
7
7
  after_touch :flush_cache
8
8
 
9
9
  scope :find_in_cache, ->(value) {
10
- Rails.cache.fetch [name, value] do
10
+ Rails.cache.fetch [name, value] do
11
11
  find_by!(@cache_field => value)
12
12
  end
13
13
  }
data/app/models/email.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  class Email < ApplicationRecord
2
2
  validates :from_name, :to_name, :subject, :plain_content, :html_content,
3
3
  presence: true
4
- validates :from_email, :to_email,
5
- format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
4
+ validates :from_email, :to_email, email: true
5
+ validates :cc, :bcc, email: true, allow_blank: true
6
6
 
7
7
  scope :sent, -> { where('sent_at IS NOT NULL') }
8
8
  scope :not_sent, -> { where('sent_at IS NULL') }
@@ -6,5 +6,6 @@ class EmailTemplate < ApplicationRecord
6
6
 
7
7
  validates :description, :from_name, presence: true
8
8
  validates :identifier, presence: true, uniqueness: { case_sensitive: false }
9
- validates :from_email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
9
+ validates :from_email, email: true
10
+ validates :cc, :bcc, email: true, allow_blank: true
10
11
  end
@@ -0,0 +1,6 @@
1
+ <% if object.errors.any? %>
2
+ <div class="alert alert-danger" role="alert">
3
+ <%= t('b.msg.general_form_error').html_safe %>
4
+ </div>
5
+ <% end %>
6
+
@@ -1,3 +1,5 @@
1
+ <%= render 'backend/general_form_error', object: @admin %>
2
+
1
3
  <%= simple_form_for [:backend, @admin] do |f| %>
2
4
  <div class="row">
3
5
  <div class="col-md-6">
@@ -7,6 +9,7 @@
7
9
  </div>
8
10
 
9
11
  <div class="card-block">
12
+ <%= f.input :locale, collection: Udongo.config.i18n.cms.interface_locales, include_blank: false %>
10
13
  <%= f.input :first_name %>
11
14
  <%= f.input :last_name %>
12
15
  <%= f.input :email, required: true %>
@@ -0,0 +1,3 @@
1
+ <% Udongo::Configs::FlexibleContent::BREAKPOINTS.each do |bp| %>
2
+ <%= form.input "width_#{bp}", as: :integer, wrapper_html: { hidden: !Udongo.config.flexible_content.allowed_breakpoint?(bp) } %>
3
+ <% end %>
@@ -1,3 +1,5 @@
1
+ <%= render 'backend/general_form_error', object: @column %>
2
+
1
3
  <%= simple_form_for(@column, url: backend_content_row_column_path(@row, @column)) do |f| %>
2
4
  <div class="card">
3
5
  <div class="card-header">
@@ -7,11 +9,7 @@
7
9
  <div class="card-block">
8
10
  <div class="row">
9
11
  <div class="col-md-6">
10
- <%= f.input :width_xs, as: :integer %>
11
- <%= f.input :width_sm, as: :integer %>
12
- <%= f.input :width_md, as: :integer %>
13
- <%= f.input :width_lg, as: :integer %>
14
- <%= f.input :width_xl, as: :integer %>
12
+ <%= render 'backend/content/rows/columns/dimension_fields', form: f %>
15
13
  </div>
16
14
 
17
15
  <div class="col-md-6">
@@ -1,3 +1,5 @@
1
+ <%= render 'backend/general_form_error', object: @column %>
2
+
1
3
  <%= simple_form_for(@column, url: backend_content_row_columns_path(@row)) do |f| %>
2
4
  <div class="card">
3
5
  <div class="card-header">
@@ -7,11 +9,7 @@
7
9
  <div class="card-block">
8
10
  <div class="row">
9
11
  <div class="col-md-6">
10
- <%= f.input :width_xs, as: :integer %>
11
- <%= f.input :width_sm, as: :integer %>
12
- <%= f.input :width_md, as: :integer %>
13
- <%= f.input :width_lg, as: :integer %>
14
- <%= f.input :width_xl, as: :integer %>
12
+ <%= render 'backend/content/rows/columns/dimension_fields', form: f %>
15
13
  </div>
16
14
 
17
15
  <div class="col-md-6">
@@ -1,3 +1,5 @@
1
+ <%= render 'backend/general_form_error', object: @model %>
2
+
1
3
  <div class="card">
2
4
  <div class="card-header">
3
5
  <%= t 'b.msg.flexible_content.edit_image' %>
@@ -1 +1 @@
1
- Dashboard#show
1
+ <!-- Fine me in app/views/backend/dashboard/show.html.erb -->
@@ -1,27 +1,49 @@
1
- <%= simple_form_for [:backend, @form] do |f| %>
1
+ <%= render 'backend/general_form_error', object: @model %>
2
+
3
+ <%= simple_form_for [:backend, @model] do |f| %>
2
4
  <div class="row">
3
- <div class="col-md-6">
5
+ <div class="col-md-12">
4
6
  <div class="card">
5
7
  <div class="card-header">
6
8
  <%= t 'b.general' %>
7
9
  </div>
8
10
 
9
11
  <div class="card-block">
10
- <%= f.input :identifier %>
11
- <%= f.input :description, as: :string %>
12
+ <div class="row">
13
+ <div class="col-md-6">
14
+ <%= f.input :identifier %>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="row">
19
+ <div class="col-md-12">
20
+ <%= f.input :description, as: :string %>
21
+ </div>
22
+ </div>
12
23
  </div>
13
24
  </div>
14
25
  </div>
26
+ </div>
15
27
 
16
- <div class="col-md-6">
28
+ <div class="row">
29
+ <div class="col-md-12">
17
30
  <div class="card">
18
31
  <div class="card-header">
19
32
  <%= t 'b.settings' %>
20
33
  </div>
21
34
 
22
35
  <div class="card-block">
23
- <%= f.input :from_name %>
24
- <%= f.input :from_email %>
36
+ <div class="row">
37
+ <div class="col-md-6">
38
+ <%= f.input :from_name %>
39
+ <%= f.input :from_email %>
40
+ </div>
41
+
42
+ <div class="col-md-6">
43
+ <%= f.input :cc %>
44
+ <%= f.input :bcc %>
45
+ </div>
46
+ </div>
25
47
  </div>
26
48
  </div>
27
49
  </div>