summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/users.js16
-rw-r--r--app/views/account/new.html.haml15
-rw-r--r--config/initializers/client_side_validations.rb3
-rw-r--r--config/initializers/simple_form.rb71
-rw-r--r--config/initializers/simple_form_bootstrap.rb160
-rw-r--r--engines/support/app/views/tickets/_new_comment_form.html.haml2
-rw-r--r--test/integration/browser/account_livecycle_test.rb2
-rw-r--r--test/integration/browser/password_validation_test.rb33
-rw-r--r--test/support/browser_integration_test.rb2
9 files changed, 226 insertions, 78 deletions
diff --git a/app/assets/javascripts/users.js b/app/assets/javascripts/users.js
index 59478a6..9a10532 100644
--- a/app/assets/javascripts/users.js
+++ b/app/assets/javascripts/users.js
@@ -10,6 +10,7 @@
poll_identities,
prevent_default,
clear_errors,
+ validate_password_confirmation,
signup,
update_user;
@@ -57,6 +58,20 @@
});
};
+ validate_password_confirmation = function(submitEvent) {
+ var form = submitEvent.target;
+ var password = $(form).find('input#srp_password').val();
+ var confirmation = $(form).find('input#srp_password_confirmation').val();
+ if (password === confirmation) {
+ return true;
+ }
+ else {
+ displayFieldError("password_confirmation", "does not match.");
+ submitEvent.stopImmediatePropagation()
+ return false;
+ }
+ };
+
var account = {
// Returns the user's identity
@@ -163,6 +178,7 @@
$('.hidden.js-show').removeClass('hidden');
$('.js-show').show();
$('#new_user').submit(prevent_default);
+ $('#new_user').submit(validate_password_confirmation);
$('#new_user').submit(signup);
$('#new_session').submit(prevent_default);
$('#new_session').submit(srp.login);
diff --git a/app/views/account/new.html.haml b/app/views/account/new.html.haml
index d40259e..4766945 100644
--- a/app/views/account/new.html.haml
+++ b/app/views/account/new.html.haml
@@ -6,7 +6,12 @@
-# to prevent submission in the clear.
-#
-- form_options = {url: '/not-used', html: {id: 'new_user', class: user_form_class('form-horizontal'), style: 'display:none'}, validate: true}
+- form_options = { url: '/not-used',
+ html: { id: 'new_user',
+ class: user_form_class('form-horizontal'),
+ style: 'display:none' },
+ validate: true,
+ wrapper: :horizontal_form }
.col-md-1
.col-md-9
@@ -14,14 +19,14 @@
.lead=t :signup_info
= render "sessions/warnings"
= simple_form_for(@user, form_options) do |f|
- = f.input :login, :label => t(:username), :required => false, :input_html => { :id => :srp_username }
- = f.input :password, :label => t(:password), :required => false, :validate => true, :input_html => { :id => :srp_password }
- = f.input :password_confirmation, :label => t(:password_confirmation), :required => false, :validate => true, :input_html => { :id => :srp_password_confirmation }
+ = f.input :login, :label => t(:username), :validate => true, :input_html => { :id => :srp_username}
+ = f.input :password, :label => t(:password), :validate => true, :input_html => { :id => :srp_password }
+ = f.input :password_confirmation, :label => t(:password_confirmation), :validate => true, :input_html => { :id => :srp_password_confirmation }
- if APP_CONFIG[:invite_required]
= f.input :invite_code, :label => t(:invite_code), :input_html => { :id => :srp_invite_code }
- else
= f.input :invite_code, :as => "hidden", :input_html => { :value => " ", :id => :srp_invite_code }
- = f.button :wrapped, cancel: home_path
+ = f.button :submit # :wrapped, cancel: home_path
-#
diff --git a/config/initializers/client_side_validations.rb b/config/initializers/client_side_validations.rb
index f7a658a..9f3b17d 100644
--- a/config/initializers/client_side_validations.rb
+++ b/config/initializers/client_side_validations.rb
@@ -1,7 +1,8 @@
# ClientSideValidations Initializer
# Disabled validators. The uniqueness validator is disabled by default for security issues. Enable it on your own responsibility!
-# ClientSideValidations::Config.disabled_validators = [:uniqueness]
+
+ClientSideValidations::Config.disabled_validators = [:uniqueness, :confirmation]
# Uncomment to validate number format with current I18n locale
# ClientSideValidations::Config.number_format_with_locale = true
diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb
index 710dacc..cdd2afc 100644
--- a/config/initializers/simple_form.rb
+++ b/config/initializers/simple_form.rb
@@ -7,8 +7,8 @@ SimpleForm.setup do |config|
# wrapper, change the order or even add your own to the
# stack. The options given below are used to wrap the
# whole input.
- config.wrappers :default, :class => :input,
- :hint_class => :field_with_hint, :error_class => :field_with_errors do |b|
+ config.wrappers :default, class: :input,
+ hint_class: :field_with_hint, error_class: :field_with_errors do |b|
## Extensions enabled by default
# Any of these extensions can be disabled for a
# given input by passing: `f.input EXTENSION_NAME => false`.
@@ -20,18 +20,22 @@ SimpleForm.setup do |config|
b.use :html5
# Calculates placeholders automatically from I18n
- # You can also pass a string as f.input :placeholder => "Placeholder"
+ # You can also pass a string as f.input placeholder: "Placeholder"
b.use :placeholder
## Optional extensions
- # They are disabled unless you pass `f.input EXTENSION_NAME => :lookup`
+ # They are disabled unless you pass `f.input EXTENSION_NAME => true`
# to the input. If so, they will retrieve the values from the model
- # if any exists. If you want to enable the lookup for any of those
+ # if any exists. If you want to enable any of those
# extensions by default, you can change `b.optional` to `b.use`.
# Calculates maxlength from length validations for string inputs
+ # and/or database column lengths
b.optional :maxlength
+ # Calculate minlength from length validations for string inputs
+ b.optional :minlength
+
# Calculates pattern from format validations for string inputs
b.optional :pattern
@@ -43,8 +47,14 @@ SimpleForm.setup do |config|
## Inputs
b.use :label_input
- b.use :hint, :wrap_with => { :tag => :span, :class => :hint }
- b.use :error, :wrap_with => { :tag => :span, :class => :error }
+ b.use :hint, wrap_with: { tag: :span, class: :hint }
+ b.use :error, wrap_with: { tag: :span, class: :error }
+
+ ## full_messages_for
+ # If you want to display the full error message for the attribute, you can
+ # use the component :full_error, like:
+ #
+ # b.use :full_error, wrap_with: { tag: :span, class: :error }
end
# The default wrapper to be used by the FormBuilder.
@@ -52,8 +62,8 @@ SimpleForm.setup do |config|
# Define the way to render check boxes / radio buttons with labels.
# Defaults to :nested for bootstrap config.
- # :inline => input + label
- # :nested => label > input
+ # inline: input + label
+ # nested: label > input
config.boolean_style = :nested
# Default class for buttons
@@ -68,7 +78,7 @@ SimpleForm.setup do |config|
config.error_notification_tag = :div
# CSS class to add for error notification helper.
- config.error_notification_class = 'alert alert-error'
+ config.error_notification_class = 'error_notification'
# ID to add for error notification helper.
# config.error_notification_id = nil
@@ -86,21 +96,21 @@ SimpleForm.setup do |config|
# config.collection_wrapper_class = nil
# You can wrap each item in a collection of radio/check boxes with a tag,
- # defaulting to :span. Please note that when using :boolean_style = :nested,
- # SimpleForm will force this option to be a label.
+ # defaulting to :span.
# config.item_wrapper_tag = :span
# You can define a class to use in all item wrappers. Defaulting to none.
# config.item_wrapper_class = nil
# How the label text should be generated altogether with the required text.
- # config.label_text = lambda { |label, required| "#{required} #{label}" }
+ # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
# You can define the class to use on all labels. Default is nil.
- config.label_class = 'control-label'
+ # config.label_class = nil
- # You can define the class to use on all forms. Default is simple_form.
- # config.form_class = :simple_form
+ # You can define the default class to be used on forms. Can be overriden
+ # with `html: { :class }`. Defaulting to none.
+ # config.default_form_class = nil
# You can define which elements should obtain additional classes
# config.generate_additional_classes_for = [:wrapper, :label, :input]
@@ -108,8 +118,11 @@ SimpleForm.setup do |config|
# Whether attributes are required by default (or not). Default is true.
# config.required_by_default = true
- # Tell browsers whether to use default HTML5 validations (novalidate option).
- # Default is enabled.
+ # Tell browsers whether to use the native HTML5 validations (novalidate form option).
+ # These validations are enabled in SimpleForm's internal config but disabled by default
+ # in this configuration, which is recommended due to some quirks from different browsers.
+ # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations,
+ # change this configuration to true.
config.browser_validations = false
# Collection of methods to detect if a file type was given.
@@ -122,7 +135,11 @@ SimpleForm.setup do |config|
# Custom wrappers for input types. This should be a hash containing an input
# type as key and the wrapper that will be used for all inputs with specified type.
- # config.wrapper_mappings = { :string => :prepend }
+ # config.wrapper_mappings = { string: :prepend }
+
+ # Namespaces where SimpleForm should look for custom input classes that
+ # override default inputs.
+ # config.custom_inputs_namespaces << "CustomInputs"
# Default priority for time_zone inputs.
# config.time_zone_priority = nil
@@ -130,9 +147,6 @@ SimpleForm.setup do |config|
# Default priority for country inputs.
# config.country_priority = nil
- # Default size for text inputs.
- # config.default_input_size = 50
-
# When false, do not use translations for labels.
# config.translate_labels = true
@@ -141,4 +155,17 @@ SimpleForm.setup do |config|
# Cache SimpleForm inputs discovery
# config.cache_discovery = !Rails.env.development?
+
+ # Default class for inputs
+ # config.input_class = nil
+
+ # Define the default class of the input wrapper of the boolean input.
+ config.boolean_label_class = 'checkbox'
+
+ # Defines if the default input wrapper class should be included in radio
+ # collection wrappers.
+ # config.include_default_input_wrapper_class = true
+
+ # Defines which i18n scope will be used in Simple Form.
+ # config.i18n_scope = 'simple_form'
end
diff --git a/config/initializers/simple_form_bootstrap.rb b/config/initializers/simple_form_bootstrap.rb
index 720174f..d2f3926 100644
--- a/config/initializers/simple_form_bootstrap.rb
+++ b/config/initializers/simple_form_bootstrap.rb
@@ -1,57 +1,153 @@
# Use this setup block to configure all options available in SimpleForm.
SimpleForm.setup do |config|
- config.wrappers :bootstrap, :tag => 'div', :class => 'form-group', :error_class => 'error' do |b|
+ config.error_notification_class = 'alert alert-danger'
+ config.button_class = 'btn btn-default'
+ config.boolean_label_class = nil
+
+ config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.use :placeholder
- b.use :label, :class => 'col-sm-2'
- b.wrapper :tag => 'div', :class => 'col-sm-10' do |ba|
- ba.use :input
- ba.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
- ba.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
+ b.optional :maxlength
+ b.optional :minlength
+ b.optional :pattern
+ b.optional :min_max
+ b.optional :readonly
+ b.use :label, class: 'control-label'
+
+ b.use :input, class: 'form-control'
+ b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
+ end
+
+ config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
+ b.use :html5
+ b.use :placeholder
+ b.optional :maxlength
+ b.optional :minlength
+ b.optional :readonly
+ b.use :label, class: 'control-label'
+
+ b.use :input
+ b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
+ end
+
+ config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
+ b.use :html5
+ b.optional :readonly
+
+ b.wrapper tag: 'div', class: 'checkbox' do |ba|
+ ba.use :label_input
end
+
+ b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
+ end
+
+ config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
+ b.use :html5
+ b.optional :readonly
+ b.use :label, class: 'control-label'
+ b.use :input
+ b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- config.wrappers :prepend, :tag => 'div', :class => "form-group", :error_class => 'error' do |b|
+ config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.use :placeholder
- b.use :label
- b.wrapper :tag => 'div', :class => 'controls' do |input|
- input.wrapper :tag => 'div', :class => 'input-prepend' do |prepend|
- prepend.use :input
- end
- input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
- input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
+ b.optional :maxlength
+ b.optional :minlength
+ b.optional :pattern
+ b.optional :min_max
+ b.optional :readonly
+ b.use :label, class: 'col-sm-3 control-label'
+ b.wrapper tag: 'div', class: 'col-sm-6' do |ba|
+ ba.use :input, class: 'form-control'
end
+ b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- config.wrappers :append, :tag => 'div', :class => "form-group", :error_class => 'error' do |b|
+ config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.use :placeholder
- b.use :label
- b.wrapper :tag => 'div', :class => 'controls' do |input|
- input.wrapper :tag => 'div', :class => 'input-append' do |append|
- append.use :input
+ b.optional :maxlength
+ b.optional :minlength
+ b.optional :readonly
+ b.use :label, class: 'col-sm-3 control-label'
+
+ b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
+ ba.use :input
+ ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
+ end
+ end
+
+ config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
+ b.use :html5
+ b.optional :readonly
+
+ b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr|
+ wr.wrapper tag: 'div', class: 'checkbox' do |ba|
+ ba.use :label_input
end
- input.use :hint, :wrap_with => { :tag => 'span', :class => 'help-block' }
- input.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
+
+ wr.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
end
- #
- # when you don't want any bootstrap "form-group" or "controls" wrappers.
- #
- config.wrappers :none, :tag => 'div', :error_class => 'error' do |b|
+ config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
+ b.use :html5
+ b.optional :readonly
+
+ b.use :label, class: 'col-sm-3 control-label'
+
+ b.wrapper tag: 'div', class: 'col-sm-9' do |ba|
+ ba.use :input
+ ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
+ end
+ end
+
+ config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
b.use :html5
b.use :placeholder
- b.use :label
- b.use :input
- b.use :error, :wrap_with => { :tag => 'span', :class => 'help-inline' }
- b.use :hint, :wrap_with => { :tag => 'p', :class => 'help-block' }
+ b.optional :maxlength
+ b.optional :minlength
+ b.optional :pattern
+ b.optional :min_max
+ b.optional :readonly
+ b.use :label, class: 'sr-only'
+
+ b.use :input, class: 'form-control'
+ b.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ b.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
end
- # Wrappers for forms and inputs using the Twitter Bootstrap toolkit.
- # Check the Bootstrap docs (http://twitter.github.com/bootstrap)
+ config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b|
+ b.use :html5
+ b.optional :readonly
+ b.use :label, class: 'control-label'
+ b.wrapper tag: 'div', class: 'form-inline' do |ba|
+ ba.use :input, class: 'form-control'
+ ba.use :error, wrap_with: { tag: 'span', class: 'help-block' }
+ ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' }
+ end
+ end
+ # Wrappers for forms and inputs using the Bootstrap toolkit.
+ # Check the Bootstrap docs (http://getbootstrap.com)
# to learn about the different styles for forms and inputs,
# buttons and other elements.
- config.default_wrapper = :bootstrap
+ config.default_wrapper = :vertical_form
+ config.wrapper_mappings = {
+ check_boxes: :vertical_radio_and_checkboxes,
+ radio_buttons: :vertical_radio_and_checkboxes,
+ file: :vertical_file_input,
+ boolean: :vertical_boolean,
+ datetime: :multi_select,
+ date: :multi_select,
+ time: :multi_select
+ }
end
diff --git a/engines/support/app/views/tickets/_new_comment_form.html.haml b/engines/support/app/views/tickets/_new_comment_form.html.haml
index f285b8b..05a0d4c 100644
--- a/engines/support/app/views/tickets/_new_comment_form.html.haml
+++ b/engines/support/app/views/tickets/_new_comment_form.html.haml
@@ -3,7 +3,7 @@
-#
= simple_form_for @ticket, :html => {:class => 'slim'} do |f|
= hidden_ticket_fields
- = f.simple_fields_for :comments, @comment, :wrapper => :none, :html => {:class => 'slim'} do |c|
+ = f.simple_fields_for :comments, @comment, :wrapper => false, :html => {:class => 'slim'} do |c|
= c.input :body, :label => false, :as => :text,
:input_html => {:class => "full-width", :rows=> 5}
- if admin?
diff --git a/test/integration/browser/account_livecycle_test.rb b/test/integration/browser/account_livecycle_test.rb
index 85dbf13..835dfdc 100644
--- a/test/integration/browser/account_livecycle_test.rb
+++ b/test/integration/browser/account_livecycle_test.rb
@@ -24,7 +24,7 @@ class AccountLivecycleTest < BrowserIntegrationTest
visit '/signup'
fill_in 'Username', with: username
- fill_in 'Password', with: password
+ fill_in 'Password', with: password, match: :prefer_exact
fill_in 'Password confirmation', with: password
click_on 'Sign Up'
diff --git a/test/integration/browser/password_validation_test.rb b/test/integration/browser/password_validation_test.rb
index 51fcc5d..c5f0676 100644
--- a/test/integration/browser/password_validation_test.rb
+++ b/test/integration/browser/password_validation_test.rb
@@ -3,29 +3,32 @@ require 'test_helper'
class PasswordValidationTest < BrowserIntegrationTest
test "password confirmation is validated" do
- username ||= "test_#{SecureRandom.urlsafe_base64}".downcase
- password ||= SecureRandom.base64
- visit '/signup'
- fill_in 'Username', with: username
- fill_in 'Password', with: password
- fill_in 'Password confirmation', with: password + "-typo"
- click_on 'Sign Up'
+ password = SecureRandom.base64
+ submit_signup_form password: password, confirmation: password + 'a'
assert page.has_content? "does not match."
assert_equal '/signup', current_path
- assert page.has_selector? ".error #srp_password_confirmation"
+ assert_error_for 'srp_password_confirmation'
end
test "password needs to be at least 8 chars long" do
+ submit_signup_form password: SecureRandom.base64[0,7]
+ assert page.has_content? "needs to be at least 8 characters long"
+ assert_equal '/signup', current_path
+ assert_error_for 'srp_password'
+ end
+
+ def submit_signup_form(username: nil, password: nil, confirmation: nil)
username ||= "test_#{SecureRandom.urlsafe_base64}".downcase
- password ||= SecureRandom.base64[0,7]
+ password ||= SecureRandom.base64
+ confirmation ||= password
visit '/signup'
fill_in 'Username', with: username
- fill_in 'Password', with: password
- fill_in 'Password confirmation', with: password
+ fill_in 'Password', with: password, match: :prefer_exact
+ fill_in 'Password confirmation', with: confirmation
click_on 'Sign Up'
- assert page.has_content? "needs to be at least 8 characters long"
- assert_equal '/signup', current_path
- assert page.has_selector? ".error #srp_password"
end
-end
+ def assert_error_for(id)
+ assert page.has_selector? ".has-error ##{id}"
+ end
+end
diff --git a/test/support/browser_integration_test.rb b/test/support/browser_integration_test.rb
index c0fef0a..d00e606 100644
--- a/test/support/browser_integration_test.rb
+++ b/test/support/browser_integration_test.rb
@@ -36,7 +36,7 @@ class BrowserIntegrationTest < RackStackTest
password ||= SecureRandom.base64
visit '/signup'
fill_in 'Username', with: username
- fill_in 'Password', with: password
+ fill_in 'Password', with: password, match: :prefer_exact
if APP_CONFIG[:invite_required]
fill_in 'Invite code', with: @testcode.invite_code
end