decidim-core 0.0.1.alpha2 → 0.0.1.alpha3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +11 -6
  3. data/app/assets/config/decidim_core_manifest.js +1 -0
  4. data/app/assets/images/decidim/badge-ajuntament-footer.png +0 -0
  5. data/app/assets/images/decidim/badge-ajuntament-header.svg +60 -0
  6. data/app/assets/images/decidim/cc-badge.png +0 -0
  7. data/app/assets/images/decidim/hero-home.jpg +0 -0
  8. data/app/assets/images/decidim/icons.svg +1 -0
  9. data/app/assets/javascripts/decidim.js +12 -1
  10. data/app/assets/stylesheets/{decidim.css → decidim.scss} +2 -1
  11. data/app/assets/stylesheets/decidim/application.sass +7 -0
  12. data/app/assets/stylesheets/decidim/layouts/_home.scss +244 -0
  13. data/app/assets/stylesheets/decidim/layouts/_user.scss +24 -0
  14. data/app/assets/stylesheets/decidim/layouts/_view.scss +22 -0
  15. data/app/assets/stylesheets/decidim/modules/_address.scss +26 -0
  16. data/app/assets/stylesheets/decidim/modules/_author-avatar.scss +119 -0
  17. data/app/assets/stylesheets/decidim/modules/_buttons.scss +120 -0
  18. data/app/assets/stylesheets/decidim/modules/_callout.scss +25 -0
  19. data/app/assets/stylesheets/decidim/modules/_card-grid.scss +22 -0
  20. data/app/assets/stylesheets/decidim/modules/_cards.scss +520 -0
  21. data/app/assets/stylesheets/decidim/modules/_comments.scss +119 -0
  22. data/app/assets/stylesheets/decidim/modules/_defintion-data.scss +54 -0
  23. data/app/assets/stylesheets/decidim/modules/_extra.scss +43 -0
  24. data/app/assets/stylesheets/decidim/modules/_filters.scss +96 -0
  25. data/app/assets/stylesheets/decidim/modules/_flag.scss +9 -0
  26. data/app/assets/stylesheets/decidim/modules/_footer.scss +90 -0
  27. data/app/assets/stylesheets/decidim/modules/_forms.scss +30 -0
  28. data/app/assets/stylesheets/decidim/modules/_help.scss +14 -0
  29. data/app/assets/stylesheets/decidim/modules/_icons.scss +32 -0
  30. data/app/assets/stylesheets/decidim/modules/_layout.scss +58 -0
  31. data/app/assets/stylesheets/decidim/modules/_list-docs.scss +30 -0
  32. data/app/assets/stylesheets/decidim/modules/_main-container.scss +70 -0
  33. data/app/assets/stylesheets/decidim/modules/_map.scss +72 -0
  34. data/app/assets/stylesheets/decidim/modules/_navbar.scss +258 -0
  35. data/app/assets/stylesheets/decidim/modules/_opinion-toggle.scss +30 -0
  36. data/app/assets/stylesheets/decidim/modules/_order-by.scss +66 -0
  37. data/app/assets/stylesheets/decidim/modules/_owl-carousel.scss +72 -0
  38. data/app/assets/stylesheets/decidim/modules/_phase-nav.scss +177 -0
  39. data/app/assets/stylesheets/decidim/modules/_popularity.scss +74 -0
  40. data/app/assets/stylesheets/decidim/modules/_process-header.scss +125 -0
  41. data/app/assets/stylesheets/decidim/modules/_process-info.scss +44 -0
  42. data/app/assets/stylesheets/decidim/modules/_process-nav.scss +99 -0
  43. data/app/assets/stylesheets/decidim/modules/_reference.scss +6 -0
  44. data/app/assets/stylesheets/decidim/modules/_reveal.scss +20 -0
  45. data/app/assets/stylesheets/decidim/modules/_share.scss +28 -0
  46. data/app/assets/stylesheets/decidim/modules/_signup.scss +39 -0
  47. data/app/assets/stylesheets/decidim/modules/_static-pages.scss +46 -0
  48. data/app/assets/stylesheets/decidim/modules/_status-labels.scss +14 -0
  49. data/app/assets/stylesheets/decidim/modules/_tags.scss +29 -0
  50. data/app/assets/stylesheets/decidim/modules/_timeline.scss +189 -0
  51. data/app/assets/stylesheets/decidim/modules/_title-action.scss +28 -0
  52. data/app/assets/stylesheets/decidim/modules/_typography.scss +116 -0
  53. data/app/assets/stylesheets/decidim/modules/_user-form.scss +14 -0
  54. data/app/assets/stylesheets/decidim/modules/_video.scss +18 -0
  55. data/app/assets/stylesheets/decidim/utils/_fontface.scss +1 -0
  56. data/app/assets/stylesheets/decidim/utils/_helpers.sass +21 -0
  57. data/app/assets/stylesheets/decidim/utils/_keyframes.sass +13 -0
  58. data/app/assets/stylesheets/decidim/utils/_mixins.sass +33 -0
  59. data/app/assets/stylesheets/decidim/utils/_settings.scss +570 -0
  60. data/app/assets/stylesheets/decidim/utils/_toggle-expand.scss +8 -0
  61. data/app/assets/stylesheets/decidim/utils/_variables.scss +25 -0
  62. data/app/controllers/concerns/decidim/needs_organization.rb +31 -0
  63. data/app/controllers/decidim/application_controller.rb +1 -0
  64. data/app/controllers/decidim/devise/confirmations_controller.rb +10 -0
  65. data/app/controllers/decidim/devise/invitations_controller.rb +20 -0
  66. data/app/controllers/decidim/devise/passwords_controller.rb +10 -0
  67. data/app/controllers/decidim/devise/registrations_controller.rb +19 -0
  68. data/app/controllers/decidim/devise/sessions_controller.rb +10 -0
  69. data/app/helpers/decidim/application_helper.rb +3 -0
  70. data/app/helpers/decidim/layout_helper.rb +27 -0
  71. data/app/helpers/decidim/translations_helper.rb +16 -0
  72. data/app/mailers/decidim/decidim_devise_mailer.rb +11 -0
  73. data/app/middleware/decidim/current_organization.rb +28 -0
  74. data/app/models/decidim/organization.rb +9 -0
  75. data/app/models/decidim/participatory_process.rb +14 -0
  76. data/app/models/decidim/user.rb +28 -4
  77. data/app/views/decidim/devise/confirmations/new.html.erb +15 -0
  78. data/app/views/decidim/devise/invitations/edit.html.erb +14 -0
  79. data/app/views/decidim/devise/passwords/edit.html.erb +20 -0
  80. data/app/views/decidim/devise/passwords/new.html.erb +15 -0
  81. data/app/views/decidim/devise/registrations/edit.html.erb +35 -0
  82. data/app/views/decidim/devise/registrations/new.html.erb +23 -0
  83. data/app/views/decidim/devise/sessions/new.html.erb +23 -0
  84. data/app/views/decidim/devise/shared/_links.html.erb +25 -0
  85. data/app/views/decidim/home/show.html.erb +16 -4
  86. data/app/views/devise/mailer/confirmation_instructions.html.erb +4 -0
  87. data/app/views/devise/mailer/organization_admin_invitation_instructions.html.erb +10 -0
  88. data/app/views/devise/mailer/organization_admin_invitation_instructions.text.erb +11 -0
  89. data/app/views/devise/mailer/password_change.html.erb +3 -0
  90. data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
  91. data/app/views/layouts/decidim/_footer.html.erb +28 -2
  92. data/app/views/layouts/decidim/_header.html.erb +59 -2
  93. data/config/i18n-tasks.yml +120 -0
  94. data/config/initializers/devise.rb +58 -8
  95. data/config/locales/en.yml +35 -0
  96. data/config/routes.rb +12 -1
  97. data/db/migrate/20160919104837_create_decidim_organizations.rb +13 -0
  98. data/db/migrate/20160920140207_devise_invitable_add_to_decidim_users.rb +23 -0
  99. data/db/migrate/20160920141039_user_belongs_to_organization.rb +5 -0
  100. data/db/migrate/20160920141151_user_has_roles.rb +5 -0
  101. data/db/migrate/20161005130108_add_participatory_processes.rb +17 -0
  102. data/db/migrate/20161005153007_add_description_to_organizations.rb +9 -0
  103. data/db/migrate/20161006085629_add_confirmable_to_devise.rb +14 -0
  104. data/db/seeds.rb +35 -0
  105. data/lib/decidim/core.rb +0 -1
  106. data/lib/decidim/core/engine.rb +30 -0
  107. data/lib/decidim/core/version.rb +1 -1
  108. data/lib/decidim/devise_failure_app.rb +36 -0
  109. data/lib/decidim/form_builder.rb +38 -0
  110. data/lib/decidim/translatable_attributes.rb +86 -0
  111. data/lib/devise/models/decidim_validatable.rb +67 -0
  112. data/lib/tasks/factory_girl.rake +16 -0
  113. metadata +254 -9
  114. data/config/locales/devise.en.yml +0 -62
  115. data/lib/decidim/testing_support/common_rake.rb +0 -13
  116. data/lib/generators/decidim/dummy_generator.rb +0 -58
  117. data/lib/generators/decidim/install_generator.rb +0 -76
  118. data/lib/generators/decidim/templates/initializer.rb +0 -4
data/config/routes.rb CHANGED
@@ -1,5 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  Decidim::Core::Engine.routes.draw do
3
- devise_for :users, class_name: "Decidim::User", module: :devise
4
+ devise_for :users,
5
+ class_name: "Decidim::User",
6
+ module: :devise,
7
+ router_name: :decidim,
8
+ controllers: {
9
+ invitations: "decidim/devise/invitations",
10
+ sessions: "decidim/devise/sessions",
11
+ confirmations: "decidim/devise/confirmations",
12
+ registrations: "decidim/devise/registrations",
13
+ passwords: "decidim/devise/passwords"
14
+ }
4
15
  root to: "home#show"
5
16
  end
@@ -0,0 +1,13 @@
1
+ class CreateDecidimOrganizations < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :decidim_organizations do |t|
4
+ t.string :name, null: false
5
+ t.string :host, null: false
6
+
7
+ t.timestamps
8
+ end
9
+
10
+ add_index :decidim_organizations, :name, unique: true
11
+ add_index :decidim_organizations, :host, unique: true
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ class DeviseInvitableAddToDecidimUsers < ActiveRecord::Migration[4.2]
2
+ def up
3
+ change_table :decidim_users do |t|
4
+ t.string :invitation_token
5
+ t.datetime :invitation_created_at
6
+ t.datetime :invitation_sent_at
7
+ t.datetime :invitation_accepted_at
8
+ t.integer :invitation_limit
9
+ t.references :invited_by, polymorphic: true
10
+ t.integer :invitations_count, default: 0
11
+ t.index :invitations_count
12
+ t.index :invitation_token, unique: true # for invitable
13
+ t.index :invited_by_id
14
+ end
15
+ end
16
+
17
+ def down
18
+ change_table :decidim_users do |t|
19
+ t.remove_references :invited_by, polymorphic: true
20
+ t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ class UserBelongsToOrganization < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_reference :decidim_users, :decidim_organization, index: true, foreign_key: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class UserHasRoles < ActiveRecord::Migration[5.0]
2
+ def change
3
+ add_column :decidim_users, :roles, :string, array: true, default: []
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ class AddParticipatoryProcesses < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :decidim_participatory_processes do |t|
4
+ t.string :title, null: false
5
+ t.string :slug, null: false, unique: true
6
+ t.string :hashtag, unique: true
7
+ t.string :subtitle, null: false
8
+ t.text :short_description, null: false
9
+ t.text :description, null: false
10
+ t.references :decidim_organization,
11
+ foreign_key: true,
12
+ index: { name: 'index_decidim_processes_on_decidim_organization_id' }
13
+
14
+ t.timestamps
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ class AddDescriptionToOrganizations < ActiveRecord::Migration[5.0]
2
+ def change
3
+ enable_extension :hstore
4
+
5
+ change_table :decidim_organizations do |t|
6
+ t.hstore :description
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ class AddConfirmableToDevise < ActiveRecord::Migration[5.0]
2
+ def up
3
+ add_column :decidim_users, :confirmation_token, :string
4
+ add_column :decidim_users, :confirmed_at, :datetime
5
+ add_column :decidim_users, :confirmation_sent_at, :datetime
6
+ add_column :decidim_users, :unconfirmed_email, :string
7
+ add_index :decidim_users, :confirmation_token, unique: true
8
+ execute("UPDATE decidim_users SET confirmed_at = NOW()")
9
+ end
10
+
11
+ def down
12
+ remove_columns :decidim_users, :confirmation_token, :confirmed_at, :confirmation_sent_at
13
+ end
14
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,35 @@
1
+ if !Rails.env.production? || ENV["SEED"]
2
+ puts "Creating Decidim::Core seeds..."
3
+
4
+ staging_organization = Decidim::Organization.create!(
5
+ name: "Decidim Staging",
6
+ host: ENV["DECIDIM_HOST"] || "localhost"
7
+ )
8
+
9
+ Decidim::User.create!(
10
+ email: "admin@decidim.org",
11
+ password: "decidim123456",
12
+ password_confirmation: "decidim123456",
13
+ organization: staging_organization,
14
+ roles: ["admin"]
15
+ )
16
+
17
+ Decidim::User.create!(
18
+ email: "user@decidim.org",
19
+ password: "decidim123456",
20
+ password_confirmation: "decidim123456",
21
+ organization: staging_organization
22
+ )
23
+
24
+ Decidim::ParticipatoryProcess.create!(
25
+ title: 'Urbanistic plan for Newtown neighbourhood',
26
+ slug: 'urbanistic-plan-for-newtown-neighbourhood',
27
+ subtitle: 'Go for it!',
28
+ hashtag: '#urbaNewtown',
29
+ short_description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed feugiat ex at neque vehicula, non facilisis mi laoreet. Duis id felis at libero cursus tincidunt vehicula posuere elit. Cras venenatis ultricies ligula, a eleifend sem viverra at. Cras quis venenatis diam. Etiam consectetur, nulla nec consequat sollicitudin, risus ipsum rutrum lacus, a ultrices risus mauris in metus. Aenean dignissim ullamcorper efficitur. Sed eget elit suscipit, efficitur dui vitae, placerat quam. Pellentesque sodales congue tortor ut maximus. Cras a nulla enim. Aliquam ac lacinia lorem, nec vehicula turpis.',
30
+ description: '<p>Mauris nec diam nibh. Quisque tincidunt aliquam malesuada. Aliquam eget velit pretium, placerat metus in, auctor dui. In mollis, ligula vel interdum hendrerit, eros sem bibendum justo, ac ornare orci nulla non mauris. Phasellus tincidunt urna est, sit amet condimentum est efficitur fringilla. Sed egestas tellus nec ligula vehicula, nec suscipit tellus consequat. Mauris interdum eu urna mollis volutpat. Maecenas condimentum pharetra lectus, quis egestas sem finibus et. Ut non est et metus ultrices convallis ut vel magna. Donec sagittis justo nec varius vestibulum.</p>
31
+
32
+ <p>Phasellus eget urna at nisl pellentesque tempus in at sem. Sed consectetur, lectus sit amet aliquam aliquet, augue justo iaculis eros, sodales mollis mauris odio vel elit. Nam ut tristique ipsum, in consectetur elit. Nullam tellus dui, placerat ut lobortis laoreet, cursus vestibulum nunc. Praesent consequat nisi non iaculis laoreet. Nullam sed molestie arcu. Vivamus ultricies dapibus neque tristique maximus. Cras quis pulvinar leo. Cras semper enim non justo lacinia cursus in eu enim. Pellentesque id erat pellentesque, semper nisi non, dignissim odio. In hac habitasse platea dictumst. Sed hendrerit purus elit, in condimentum ligula iaculis nec. Cras semper metus non lectus placerat, a auctor mauris feugiat. Sed euismod tempus egestas. Fusce porttitor vel enim non tincidunt. Duis non risus eu justo ultricies dignissim.</p>',
33
+ organization: staging_organization
34
+ )
35
+ end
data/lib/decidim/core.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require "decidim/core/engine"
3
3
  require "decidim/core/version"
4
- require "devise"
5
4
 
6
5
  # Decidim configuration.
7
6
  module Decidim
@@ -2,6 +2,22 @@
2
2
  require "rails"
3
3
  require "active_support/all"
4
4
 
5
+ require "devise"
6
+ require "devise-i18n"
7
+ require "devise_invitable"
8
+ require "jquery-rails"
9
+ require "sass-rails"
10
+ require "turbolinks"
11
+ require "jquery-turbolinks"
12
+ require "foundation-rails"
13
+ require "foundation_rails_helper"
14
+ require "jbuilder"
15
+ require "active_link_to"
16
+ require "rectify"
17
+
18
+ require "decidim/translatable_attributes"
19
+ require "decidim/form_builder"
20
+
5
21
  module Decidim
6
22
  module Core
7
23
  # Decidim's core Rails Engine.
@@ -14,6 +30,20 @@ module Decidim
14
30
  helper Decidim::LayoutHelper
15
31
  end
16
32
  end
33
+
34
+ initializer "decidim.middleware" do |app|
35
+ app.config.middleware.use Decidim::CurrentOrganization
36
+ end
37
+
38
+ initializer "decidim.default_form_builder" do |_app|
39
+ ActionView::Base.default_form_builder = Decidim::FormBuilder
40
+ end
41
+
42
+ config.to_prepare do
43
+ Rails.application.config.assets.precompile += %w(
44
+ decidim_core_manifest.js
45
+ )
46
+ end
17
47
  end
18
48
  end
19
49
  end
@@ -2,7 +2,7 @@
2
2
  # This holds Decidim's version and the Rails version on which it depends.
3
3
  module Decidim
4
4
  def self.version
5
- "0.0.1.alpha2"
5
+ "0.0.1.alpha3"
6
6
  end
7
7
 
8
8
  def self.rails_version
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Decidim
5
+ # We've provided a custom class in order to be able to deactivate the
6
+ # script_name hack that doesn't seem to be affecting us (it is actually
7
+ # introducing a bug).
8
+ class DeviseFailureApp < ::Devise::FailureApp
9
+ def scope_url
10
+ opts = {}
11
+
12
+ # Initialize script_name with nil to prevent infinite loops in
13
+ # authenticated mounted engines in rails 4.2 and 5.0
14
+
15
+ # The line below is what we commented LOL ^^
16
+ # opts[:script_name] = nil
17
+
18
+ route = route(scope)
19
+
20
+ opts[:format] = request_format unless skip_format?
21
+
22
+ opts[:script_name] = relative_url_root if relative_url_root?
23
+
24
+ router_name = ::Devise.mappings[scope].router_name || ::Devise.available_router_name
25
+ context = send(router_name)
26
+
27
+ if context.respond_to?(route)
28
+ context.send(route, opts)
29
+ elsif respond_to?(:root_url)
30
+ root_url(opts)
31
+ else
32
+ "/"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ require "foundation_rails_helper/form_builder"
3
+
4
+ module Decidim
5
+ # This custom FormBuilder adds fields needed to deal with translatable fields,
6
+ # following the conventions set on `Decidim::TranslatableAttributes`.
7
+ class FormBuilder < FoundationRailsHelper::FormBuilder
8
+ # Public: Generates an form field for each locale.
9
+ #
10
+ # type - The form field's type, like `text_area` or `text_input`
11
+ # name - The name of the field
12
+ # options - The set of options to send to the field
13
+ #
14
+ # Renders form fields for each locale.
15
+ def translated(type, name, options = {})
16
+ locales.map do |locale|
17
+ label = options[:label] || label_for(name)
18
+ language = locale
19
+
20
+ send(type, "#{name}_#{locale}", options.merge(label: "#{label} (#{language})"))
21
+ end.join.html_safe
22
+ end
23
+
24
+ private
25
+
26
+ def locales
27
+ I18n.available_locales
28
+ end
29
+
30
+ def label_for(attribute)
31
+ if object.class.respond_to?(:human_attribute_name)
32
+ object.class.human_attribute_name(attribute)
33
+ else
34
+ attribute.to_s.humanize
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+ require "active_support/concern"
3
+
4
+ module Decidim
5
+ # A set of convenience methods to deal with I18n attributes and validations
6
+ # in a way that's compatible with Virtus and ActiveModel, thus making it easy
7
+ # to integrate into Rails' forms and similar workflows.
8
+ module TranslatableAttributes
9
+ extend ActiveSupport::Concern
10
+
11
+ class_methods do
12
+ # Public: Mirrors Virtus' `attribute` interface to define attributes in
13
+ # multiple locales.
14
+ #
15
+ # name - The attribute's name
16
+ # type - The attribute's Type
17
+ #
18
+ # Example:
19
+ #
20
+ # translatable_attribute(:name, String)
21
+ # # This will generate: `name_ca`, `name_en`, `name_ca=`, `name_en=`
22
+ # # and will keep them synchronized with a hash in `name`:
23
+ # # name = { "ca" => "Hola", "en" => "Hello" }
24
+ #
25
+ # Returns nothing.
26
+ def translatable_attribute(name, type, *options)
27
+ attribute name, Hash, default: {}
28
+
29
+ locales.each do |locale|
30
+ attribute_name = "#{name}_#{locale}"
31
+
32
+ attribute attribute_name, type, *options
33
+
34
+ define_method attribute_name do
35
+ translatable_attribute_getter(name, locale)
36
+ end
37
+
38
+ alias_method "#{attribute_name}_virtus=", "#{attribute_name}="
39
+
40
+ define_method "#{attribute_name}=" do |value|
41
+ new_value = send("#{attribute_name}_virtus=", value)
42
+ translatable_attribute_setter(name, locale, new_value)
43
+ end
44
+ end
45
+ end
46
+
47
+ # Public: Mirrors ActiveModel's `validates` interface to define
48
+ # validations in multiple locales.
49
+ #
50
+ # *arguments - The exact same arguments `validates` would receive.
51
+ #
52
+ # Example:
53
+ #
54
+ # translatable_validates :name, :description, presence: true
55
+ # # This will validate the presence of `name_ca` and `name_en`
56
+ #
57
+ # Returns nothing.
58
+ def translatable_validates(*arguments)
59
+ options = arguments.last
60
+ fields = arguments[0..-2]
61
+
62
+ localized_fields = fields.flat_map do |f|
63
+ locales.map { |locale| "#{f}_#{locale}" }
64
+ end
65
+
66
+ validation_arguments = localized_fields + [options]
67
+ validates(*validation_arguments)
68
+ end
69
+
70
+ def locales
71
+ I18n.available_locales
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def translatable_attribute_setter(name, locale, value)
78
+ public_send("#{name}=", (public_send(name) || {}).merge(locale => value))
79
+ end
80
+
81
+ def translatable_attribute_getter(name, locale)
82
+ field = public_send(name) || {}
83
+ field[locale.to_s] || field[locale.to_sym]
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+ module Devise
3
+ module Models
4
+ # Validatable creates all needed validations for a user email and password.
5
+ # Automatically validate if the email is present, unique and its format is
6
+ # valid. Also tests presence of password, confirmation and length.
7
+ #
8
+ # == Options
9
+ #
10
+ # Validatable adds the following options to devise_for:
11
+ #
12
+ # * +email_regexp+: the regular expression used to validate e-mails;
13
+ # * +password_length+: a range expressing password length. Defaults to 8..72.
14
+ #
15
+ module DecidimValidatable
16
+ # All validations used by this module.
17
+ VALIDATIONS = [:validates_presence_of, :validates_uniqueness_of, :validates_format_of,
18
+ :validates_confirmation_of, :validates_length_of].freeze
19
+
20
+ def self.required_fields(_klass)
21
+ []
22
+ end
23
+
24
+ def self.included(base)
25
+ base.extend ClassMethods
26
+ assert_validations_api!(base)
27
+
28
+ base.class_eval do
29
+ validates_presence_of :email, if: :email_required?
30
+ validates_uniqueness_of :email, allow_blank: true, if: :email_changed?, scope: :organization
31
+ validates_format_of :email, with: email_regexp, allow_blank: true, if: :email_changed?
32
+
33
+ validates_presence_of :password, if: :password_required?
34
+ validates_confirmation_of :password, if: :password_required?
35
+ validates_length_of :password, within: password_length, allow_blank: true
36
+ end
37
+ end
38
+
39
+ def self.assert_validations_api!(base) #:nodoc:
40
+ unavailable_validations = VALIDATIONS.select { |v| !base.respond_to?(v) }
41
+
42
+ unless unavailable_validations.empty?
43
+ raise "Could not use :validatable module since #{base} does not respond " \
44
+ "to the following methods: #{unavailable_validations.to_sentence}."
45
+ end
46
+ end
47
+
48
+ protected
49
+
50
+ # Checks whether a password is needed or not. For validations only.
51
+ # Passwords are always required if it's a new record, or if the password
52
+ # or confirmation are being set somewhere.
53
+ def password_required?
54
+ !persisted? || !password.nil? || !password_confirmation.nil?
55
+ end
56
+
57
+ def email_required?
58
+ true
59
+ end
60
+
61
+ # Methods to be injected at class level.
62
+ module ClassMethods
63
+ Devise::Models.config(self, :email_regexp, :password_length)
64
+ end
65
+ end
66
+ end
67
+ end