Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customize etiquette and validation rules #191

Merged
merged 7 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
CHANGELOG
=========

v0.8.4
------

Compatibility:
- Decidim v0.26.x
- Decidim v0.25.x

Features:
- Feature: Override validation rules for title and body in proposals, with constrains available
- Improve loading process to facilitate development

v0.8.3
------

Expand Down
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
decidim-decidim_awesome (0.8.3)
decidim-decidim_awesome (0.8.4)
decidim-admin (>= 0.25.0, < 0.27)
decidim-core (>= 0.25.0, < 0.27)
sassc (~> 2.3)
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,19 @@ Using a link with a query string (ie: `/take-me-somewhere?locale=es`) that will

![Custom redirections screenshot](examples/custom-redirections.png)

#### 14. Custom validation rules for title and body in proposals

Configure as you wish how the fields "title" and "body" are validated in proposals creation.

Rules available:

* Minimum title and body length (defaults to 15 chars).
* Maximum percentage of capital letters for title and body (defaults to 25%).
* Maximum number of "marks" (aka: exclamation and interrogation signs) that can be consective in the title or the body (defaults to 1).
* Enable/disable forcing to start the title or the body with a capital letter (defaults to "enabled").

![Custom validations](examples/custom_validations.png)

#### To be continued...

We're not done! Please check the [issues](/Platoniq/decidim-module-decidim_awesome/issues) (and participate) to see what's on our mind
Expand Down
14 changes: 14 additions & 0 deletions app/forms/decidim/decidim_awesome/admin/config_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,26 @@ class ConfigForm < Decidim::Form
attribute :intergram_for_admins_settings, IntergramForm
attribute :intergram_for_public, Boolean
attribute :intergram_for_public_settings, IntergramForm
attribute :validate_title_min_length, Integer, default: 15
attribute :validate_title_max_caps_percent, Integer, default: 25
attribute :validate_title_max_marks_together, Integer, default: 1
attribute :validate_title_start_with_caps, Boolean, default: true
attribute :validate_body_min_length, Integer, default: 15
attribute :validate_body_max_caps_percent, Integer, default: 25
attribute :validate_body_max_marks_together, Integer, default: 1
attribute :validate_body_start_with_caps, Boolean, default: true

# collect all keys anything not specified in the params (UpdateConfig command ignores it)
attr_accessor :valid_keys

validate :css_syntax, if: ->(form) { form.scoped_styles.present? }
validate :json_syntax, if: ->(form) { form.proposal_custom_fields.present? }
validates :validate_title_min_length, presence: true, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 100 }
validates :validate_title_max_caps_percent, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
validates :validate_title_max_marks_together, presence: true, numericality: { greater_than_or_equal_to: 1 }
validates :validate_body_min_length, presence: true, numericality: { greater_than_or_equal_to: 0 }
validates :validate_body_max_caps_percent, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
validates :validate_body_max_marks_together, presence: true, numericality: { greater_than_or_equal_to: 1 }

# TODO: validate non general admins are here

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ module ProposalWizardCreateStepFormOverride
clear_validators!

validates :title, presence: true, etiquette: true
validates :title, length: { in: 15..150 }
validates :body, presence: true, etiquette: true, unless: ->(form) { form.override_validations? }
validates :title, proposal_length: {
minimum: ->(form) { form.minimum_title_length },
maximum: 150
}
validates :body, presence: true, unless: ->(form) { form.override_validations? || form.minimum_body_length.zero? }
validates :body, etiquette: true, unless: ->(form) { form.override_validations? }
validates :body, proposal_length: {
minimum: 15,
maximum: ->(record) { record.override_validations? ? 0 : record.component.settings.proposal_length }
minimum: ->(form) { form.minimum_body_length },
maximum: ->(form) { form.override_validations? ? 0 : form.component.settings.proposal_length }
}

validate :body_is_not_bare_template, unless: ->(form) { form.override_validations? }
Expand All @@ -26,10 +30,24 @@ def override_validations?
custom_fields.present?
end

def minimum_title_length
awesome_config.config[:validate_title_min_length].to_i
end

def minimum_body_length
awesome_config.config[:validate_body_min_length].to_i
end

def custom_fields
awesome_config = Decidim::DecidimAwesome::Config.new(context.current_organization)
awesome_config.context_from_component(context.current_component)
awesome_config.collect_sub_configs_values("proposal_custom_field")
@custom_fields ||= awesome_config.collect_sub_configs_values("proposal_custom_field")
end

def awesome_config
@awesome_config ||= begin
conf = Decidim::DecidimAwesome::Config.new(context.current_organization)
conf.context_from_component(context.current_component)
conf
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ def check(status)
def menus
@menus ||= {
editors: config_enabled?([:allow_images_in_full_editor, :allow_images_in_small_editor, :use_markdown_editor, :allow_images_in_markdown_editor]),
proposals: config_enabled?(:allow_images_in_proposals),
proposals: config_enabled?([:allow_images_in_proposals,
:validate_title_min_length, :validate_title_max_caps_percent,
:validate_title_max_marks_together, :validate_title_start_with_caps,
:validate_body_min_length, :validate_body_max_caps_percent,
:validate_body_max_marks_together, :validate_body_start_with_caps]),
surveys: config_enabled?(:auto_save_forms),
styles: config_enabled?(:scoped_styles),
proposal_custom_fields: config_enabled?(:proposal_custom_fields),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true

module Decidim
module DecidimAwesome
module EtiquetteValidatorOverride
extend ActiveSupport::Concern

included do
private

def validate_caps(record, attribute, value)
percent = awesome_config(record, "validate_#{attribute}_max_caps_percent").to_f
return if value.scan(/[[:upper:]]/).length < value.length * percent / 100

record.errors.add(attribute, options[:message] || I18n.t("too_much_caps", scope: "decidim.decidim_awesome.validators", percent: percent.round))
end

def validate_marks(record, attribute, value)
marks = awesome_config(record, "validate_#{attribute}_max_marks_together").to_i + 1
return if value.scan(/[!?¡¿]{#{marks},}/).empty?

record.errors.add(attribute, options[:message] || :too_many_marks)
end

def validate_caps_first(record, attribute, value)
return unless awesome_config(record, "validate_#{attribute}_start_with_caps")
return if value.scan(/\A[[:lower:]]{1}/).empty?

record.errors.add(attribute, options[:message] || :must_start_with_caps)
end

def awesome_config(record, var)
config = record.try(:awesome_config)&.config
return unless config.is_a?(Hash)

config[var.to_sym]
end
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,89 @@
<% if config_enabled? :allow_images_in_proposals %>
<p class="text-info"><%= t("rich_text_editor_in_public_views", scope: "decidim.decidim_awesome.admin.config") if current_organization.rich_text_editor_in_public_views %></p>

<%= form.check_box :allow_images_in_proposals %>
<%= form.check_box :allow_images_in_proposals, disabled: current_organization.rich_text_editor_in_public_views %>
<p class="help-text"><%= t("help.allow_images_in_proposals", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :allow_images_in_proposals, constraints: constraints_for(:allow_images_in_proposals) }) %>
<% unless current_organization.rich_text_editor_in_public_views %>
<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :allow_images_in_proposals, constraints: constraints_for(:allow_images_in_proposals) }) %>
<% end %>
<% end %>
</div>

<% if config_enabled? %i(validate_title_min_length validate_title_max_caps_percent validate_title_max_marks_together validate_title_start_with_caps) %>
</div> <!-- .card-section -->
</div><!-- .card -->

<div class="card">
<div class="card-divider">
<h2 class="card-title"><%= t("validators.title", scope: "decidim.decidim_awesome.admin.config.form") %></h2>
</div>
<div class="card-section">

<div class="row column decidim_awesome-form">
<% if config_enabled? :validate_title_start_with_caps %>
<%= form.check_box :validate_title_start_with_caps %>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_title_start_with_caps, constraints: constraints_for(:validate_title_start_with_caps) }) %>
<% end %>

<% if config_enabled? :validate_title_min_length %>
<%= form.number_field :validate_title_min_length %>
<p class="help-text"><%= t("help.validate_title_min_length", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_title_min_length, constraints: constraints_for(:validate_title_min_length) }) %>
<% end %>

<% if config_enabled? :validate_title_max_caps_percent %>
<%= form.number_field :validate_title_max_caps_percent %>
<p class="help-text"><%= t("help.validate_title_max_caps_percent", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_title_max_caps_percent, constraints: constraints_for(:validate_title_max_caps_percent) }) %>
<% end %>

<% if config_enabled? :validate_title_max_marks_together %>
<%= form.number_field :validate_title_max_marks_together %>
<p class="help-text"><%= t("help.validate_title_max_marks_together", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_title_max_marks_together, constraints: constraints_for(:validate_title_max_marks_together) }) %>
<% end %>
</div>
<% end %>

<% if config_enabled? %i(validate_body_min_length validate_body_max_caps_percent validate_body_max_marks_together validate_body_start_with_caps) %>
</div> <!-- .card-section -->
</div><!-- .card -->

<div class="card">
<div class="card-divider">
<h2 class="card-title"><%= t("validators.body", scope: "decidim.decidim_awesome.admin.config.form") %></h2>
</div>
<div class="card-section">
<% if config_enabled? :validate_body_start_with_caps %>
<%= form.check_box :validate_body_start_with_caps %>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_body_start_with_caps, constraints: constraints_for(:validate_body_start_with_caps) }) %>
<% end %>

<% if config_enabled? :validate_body_min_length %>
<%= form.number_field :validate_body_min_length %>
<p class="help-text"><%= t("help.validate_body_min_length", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_body_min_length, constraints: constraints_for(:validate_body_min_length) }) %>
<% end %>

<% if config_enabled? :validate_body_max_caps_percent %>
<%= form.number_field :validate_body_max_caps_percent %>
<p class="help-text"><%= t("help.validate_body_max_caps_percent", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_body_max_caps_percent, constraints: constraints_for(:validate_body_max_caps_percent) }) %>
<% end %>

<% if config_enabled? :validate_body_max_marks_together %>
<%= form.number_field :validate_body_max_marks_together %>
<p class="help-text"><%= t("help.validate_body_max_marks_together", scope: "decidim.decidim_awesome.admin.config.form") %></p>

<%= render(partial: "decidim/decidim_awesome/admin/config/constraints", locals: { key: :validate_body_max_marks_together, constraints: constraints_for(:validate_body_max_marks_together) }) %>
<% end %>
</div>
<% end %>
32 changes: 32 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ en:
scoped_admins: Scoped admins group %{id}
scoped_styles: Custom styles %{id}
use_markdown_editor: Use a Markdown editor instead of the HTML editor
validate_body_max_caps_percent: Maximum allowed percentage of capital letters
for the body
validate_body_max_marks_together: Maximum consecutive marks symbols allowed
in the body
validate_body_min_length: Minimum required characters for the body
validate_body_start_with_caps: Force the body to start with a capital letter
validate_title_max_caps_percent: Maximum allowed percentage of capital letters
for the title
validate_title_max_marks_together: Maximum consecutive marks symbols allowed
in the title
validate_title_min_length: Minimum required characters for the title
validate_title_start_with_caps: Force the title to start with a capital letter
constraint:
component_id: or specifically in
component_manifest: Only in components of type
Expand Down Expand Up @@ -199,6 +211,23 @@ en:
use_markdown_editor: This will substitute the Quill WYSIWYG editor,
to use a Markdown editor instead. Text will be converted and saved
as HTML in the database.
validate_body_max_caps_percent: Zero won't allow any capital letter,
100 will force to write everything in capital letters
validate_body_max_marks_together: 'Limit the number of question and
exclamation marks that can be written together. Ie: if it is 2, then
''!!!'' won''t be allowed in the text'
validate_body_min_length: This number can be zero, this will effectively
make this field non-mandatory
validate_title_max_caps_percent: Zero won't allow any capital letter,
100 will force to write everything in capital letters
validate_title_max_marks_together: 'Limit the number of question and
exclamation marks that can be written together. Ie: if it is 2, then
''!!!'' won''t be allowed in the text'
validate_title_min_length: Title is always mandatory and this number
cannot be zero
validators:
body: User input validations for the "body" field
title: User input validations for the "title" field
form_proposal_custom_fields:
new: Add a new "custom fields" box
remove: Remove this "custom fields" box
Expand Down Expand Up @@ -388,6 +417,9 @@ en:
show:
view_meeting: View meeting
view_proposal: View proposal
validators:
too_much_caps: Is using too many capital letters (over %{percent}% of the
text)
layouts:
decidim:
admin:
Expand Down
Binary file added examples/custom_validations.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions lib/decidim/decidim_awesome/awesome.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,41 @@ module DecidimAwesome
false
end

# Configuration options to handle different validations in proposals
# (maybe in the future will apply to other places)
# Set it to :disabled if you don't want to use this feature
config_accessor :validate_title_min_length do
15
end

config_accessor :validate_title_max_caps_percent do
25
end

config_accessor :validate_title_max_marks_together do
1
end

config_accessor :validate_title_start_with_caps do
true
end

config_accessor :validate_body_min_length do
15
end

config_accessor :validate_body_max_caps_percent do
25
end

config_accessor :validate_body_max_marks_together do
1
end

config_accessor :validate_body_start_with_caps do
true
end

config_accessor :intergram_for_public do
false
end
Expand Down
2 changes: 2 additions & 0 deletions lib/decidim/decidim_awesome/checksums.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ decidim-admin:
/app/views/layouts/decidim/admin/_header.html.erb:
decidim-0.25: 1aff077428830b12306d6c42e6b37216
decidim-core:
/app/validators/etiquette_validator.rb:
decidim-0.25: f7a4a652005385a994208f1ab41c4f08
/app/views/layouts/decidim/_head.html.erb:
decidim-0.25: eb490aa482477ff70f541d20cddec773
decidim-0.26: 0927fc81123addec70853c2e7986c538
Expand Down
Loading