decidim-friendly_signup 0.3 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +52 -1
- data/app/controllers/concerns/decidim/friendly_signup/registrations_redirect.rb +37 -0
- data/app/controllers/decidim/friendly_signup/confirmation_codes_controller.rb +50 -0
- data/app/forms/decidim/friendly_signup/confirmation_code_form.rb +33 -0
- data/app/mailers/decidim/friendly_signup/confirmation_codes_mailer.rb +22 -0
- data/app/models/concerns/decidim/friendly_signup/needs_registration_codes.rb +24 -0
- data/app/packs/entrypoints/decidim_friendly_signup.js +1 -0
- data/app/packs/entrypoints/decidim_friendly_signup.scss +1 -0
- data/app/packs/src/decidim/friendly_signup/lib/instant_validator.js +10 -1
- data/app/packs/src/decidim/friendly_signup/setup_confirmations.js +57 -0
- data/app/packs/stylesheets/decidim/friendly_signup/_confirmation-codes.scss +23 -0
- data/app/views/decidim/devise/invitations/edit.html.erb +8 -6
- data/app/views/decidim/devise/passwords/edit.html.erb +2 -2
- data/app/views/decidim/devise/registrations/new.html.erb +5 -5
- data/app/views/decidim/devise/sessions/new.html.erb +58 -0
- data/app/views/decidim/friendly_signup/confirmation_codes/index.html.erb +38 -0
- data/app/views/decidim/friendly_signup/confirmation_codes_mailer/confirmation_instructions.html.erb +13 -0
- data/app/views/decidim/friendly_signup/shared/_password_fields.html.erb +13 -7
- data/config/locales/en.yml +103 -0
- data/lib/decidim/friendly_signup/engine.rb +19 -2
- data/lib/decidim/friendly_signup/user_attribute_validator.rb +34 -5
- data/lib/decidim/friendly_signup/version.rb +1 -1
- data/lib/decidim/friendly_signup.rb +12 -0
- metadata +12 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 156a94366f47dc7f364338feca03ba824d6e9d38a16b9c8f8a6fbac4774ccbd1
|
|
4
|
+
data.tar.gz: 131f4becfb5b981f0f026a970b0b38cf98fdb2d5970bc43873ad942d360df76d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0a384da56675c80fc63b1d3c8f1a197e5ac46658395caa5926dbedc6d3a20a37648dc7f50183ebe69d601940fa50b87f8ee124109a4dd44e12fdf137f79d2ec1
|
|
7
|
+
data.tar.gz: a5622ee4f5bbc17f42abbb24922007332df97361a7f00ca39702b4965e3117483170aafd15da5c68e38053606e9736bfae20b0f1414377eb1c522060a7f1e9da
|
data/README.md
CHANGED
|
@@ -20,7 +20,7 @@ This module simply substitutes some pages to ease up the registration process in
|
|
|
20
20
|
|
|
21
21
|
- [x] Remove the nickname field from the registration process and automatically create one on registering. 
|
|
22
22
|
- [x] Instant validate parameters when registering without having to send it for backend validation. 
|
|
23
|
-
- [
|
|
23
|
+
- [x] Use numeric, confirmation codes to validate the email instead of a link. 
|
|
24
24
|
|
|
25
25
|
## Installation
|
|
26
26
|
|
|
@@ -42,6 +42,18 @@ And then execute:
|
|
|
42
42
|
bundle
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
For security reasons, it is also recomended to set a expiration time on confirmation tokens, to do that, make sure your Devise initializer has the variable `confirm_within` to certain amount of time.
|
|
46
|
+
|
|
47
|
+
For instance, you can do that by creating an initializer such as:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
# config/initializers/devise.rb
|
|
51
|
+
|
|
52
|
+
Devise.setup do |config|
|
|
53
|
+
config.confirm_within = 12.hours
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
45
57
|
**Note:**
|
|
46
58
|
|
|
47
59
|
The correct version of FriendlySignup should resolved automatically by the Bundler.
|
|
@@ -51,6 +63,7 @@ Depending on your Decidim version, choose the corresponding FriendlySignup versi
|
|
|
51
63
|
|
|
52
64
|
| FriendlySignup version | Compatible Decidim versions |
|
|
53
65
|
|---|---|
|
|
66
|
+
| 0.4.x | 0.26.x |
|
|
54
67
|
| 0.3.x | 0.26.x |
|
|
55
68
|
| 0.2.x | 0.26.x |
|
|
56
69
|
| 0.1.x | 0.26.x |
|
|
@@ -71,9 +84,47 @@ Decidim::FriendlySignup.configure do |config|
|
|
|
71
84
|
|
|
72
85
|
# Hide nickname field and create one automatically from user's name or email (default is true)
|
|
73
86
|
config.hide_nickname = false
|
|
87
|
+
|
|
88
|
+
# Send the users a 4-digit number that needs to be entered in a confirmation page instead of a confirmation link (default is true)
|
|
89
|
+
config.use_confirmation_codes = false
|
|
74
90
|
end
|
|
75
91
|
```
|
|
76
92
|
|
|
93
|
+
### Customize error messages in instant validation
|
|
94
|
+
|
|
95
|
+
You can customize any message either overriding in your application the files in `config/locales/*.yml` or by using a module like Term Customizer.
|
|
96
|
+
|
|
97
|
+
This plugin uses a cascade-style fallback looking for a series of I18n keys and returns the first available. For instance, for the attribute `email` and the validation key `blank` it will look for these 3 possibilities, returning the first matching one:
|
|
98
|
+
|
|
99
|
+
Specific attribute error:
|
|
100
|
+
```yaml
|
|
101
|
+
en:
|
|
102
|
+
decidim:
|
|
103
|
+
friendly_signup:
|
|
104
|
+
errors:
|
|
105
|
+
messages:
|
|
106
|
+
email:
|
|
107
|
+
blank: Please enter an email address
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Generic error:
|
|
111
|
+
```yaml
|
|
112
|
+
en:
|
|
113
|
+
decidim:
|
|
114
|
+
friendly_signup:
|
|
115
|
+
errors:
|
|
116
|
+
messages:
|
|
117
|
+
blank: Looks like you haven’t entered anything in this field
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Rails' default error:
|
|
121
|
+
```yaml
|
|
122
|
+
en:
|
|
123
|
+
errors:
|
|
124
|
+
messages:
|
|
125
|
+
blank: can't be blank
|
|
126
|
+
```
|
|
127
|
+
|
|
77
128
|
## Contributing
|
|
78
129
|
|
|
79
130
|
Bug reports and pull requests are welcome on GitHub at https://github.com/OpenSourcePolitics/decidim-module-friendly_signup.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module FriendlySignup
|
|
7
|
+
module RegistrationsRedirect
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
def after_sign_up_path_for(user)
|
|
12
|
+
codes_confirmation_path(user) || super(user)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def after_inactive_sign_up_path_for(user)
|
|
16
|
+
codes_confirmation_path(user) || super(user)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def after_resending_confirmation_instructions_path_for(resource_name)
|
|
20
|
+
user = Decidim::User.find_by email: params.dig(:user, :email)
|
|
21
|
+
codes_confirmation_path(user) || super(resource_name)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def codes_confirmation_path(user)
|
|
28
|
+
return if Decidim::FriendlySignup.use_confirmation_codes.blank?
|
|
29
|
+
return if user.blank?
|
|
30
|
+
return unless user.inactive_message.to_s == "unconfirmed"
|
|
31
|
+
|
|
32
|
+
set_flash_message! :notice, :signed_up_but_code_required
|
|
33
|
+
decidim_friendly_signup.confirmation_codes_path(confirmation_token: user.confirmation_token)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module FriendlySignup
|
|
5
|
+
class ConfirmationCodesController < Decidim::Devise::ConfirmationsController
|
|
6
|
+
include Decidim::FormFactory
|
|
7
|
+
include NeedsHeaderSnippets
|
|
8
|
+
|
|
9
|
+
before_action :require_unconfirmed_user
|
|
10
|
+
helper_method :user, :confirmation_form
|
|
11
|
+
|
|
12
|
+
def index; end
|
|
13
|
+
|
|
14
|
+
def create
|
|
15
|
+
if confirmation_form.valid?
|
|
16
|
+
user.confirm
|
|
17
|
+
flash[:success] = I18n.t("confirmation_codes.create.user_confirmed", name: user.name, scope: "decidim.friendly_signup")
|
|
18
|
+
return sign_in_and_redirect user, event: :authentication
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
flash.now[:alert] = confirmation_form.errors.messages.values.flatten.join(" ")
|
|
22
|
+
render :index
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def confirmation_form
|
|
28
|
+
@confirmation_form ||= form(ConfirmationCodeForm).from_params(params)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def user
|
|
32
|
+
@user ||= User.find_by(confirmation_token: params[:confirmation_token], organization: current_organization)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def require_unconfirmed_user
|
|
36
|
+
return redirect_to decidim.user_confirmation_path unless FriendlySignup.use_confirmation_codes
|
|
37
|
+
|
|
38
|
+
unless user.present? && !user.confirmed?
|
|
39
|
+
flash[:alert] = I18n.t("confirmation_code_form.invalid_token", scope: "decidim.friendly_signup")
|
|
40
|
+
return redirect_to decidim.new_user_session_path
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if user.send(:confirmation_period_expired?)
|
|
44
|
+
flash[:alert] = I18n.t("confirmation_code_form.expired", scope: "decidim.friendly_signup")
|
|
45
|
+
redirect_to decidim.user_confirmation_path
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module FriendlySignup
|
|
5
|
+
class ConfirmationCodeForm < Decidim::Form
|
|
6
|
+
attribute :confirmation_token, String
|
|
7
|
+
attribute :code, Integer
|
|
8
|
+
attribute :confirmation_numbers, Array[Integer]
|
|
9
|
+
|
|
10
|
+
validates :confirmation_token, presence: true
|
|
11
|
+
validate :code_matches_confirmation_token
|
|
12
|
+
validate :user_exists
|
|
13
|
+
|
|
14
|
+
def user_code
|
|
15
|
+
code || confirmation_numbers.map(&:to_s).join("").to_i
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def code_matches_confirmation_token
|
|
21
|
+
return if FriendlySignup.confirmation_code(confirmation_token) == user_code
|
|
22
|
+
|
|
23
|
+
errors.add(:code, I18n.t("confirmation_code_form.invalid", scope: "decidim.friendly_signup"))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def user_exists
|
|
27
|
+
return if User.exists?(confirmation_token: confirmation_token, organization: current_organization)
|
|
28
|
+
|
|
29
|
+
errors.add(:code, I18n.t("confirmation_code_form.invalid_token", scope: "decidim.friendly_signup"))
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Decidim
|
|
4
|
+
module FriendlySignup
|
|
5
|
+
class ConfirmationCodesMailer < ApplicationMailer
|
|
6
|
+
include Decidim::LocalisedMailer
|
|
7
|
+
|
|
8
|
+
def confirmation_instructions(user, opts)
|
|
9
|
+
@user = user
|
|
10
|
+
@email = opts[:to] || user.email
|
|
11
|
+
@token = opts[:token]
|
|
12
|
+
@organization = user.organization
|
|
13
|
+
@code = FriendlySignup.confirmation_code(@token)
|
|
14
|
+
@expires_at = @user.confirmation_sent_at + @user.class.confirm_within if @user.class.confirm_within
|
|
15
|
+
|
|
16
|
+
with_user(user) do
|
|
17
|
+
mail(to: "#{user.name} <#{@email}>", subject: I18n.t("decidim.friendly_signup.confirmation_codes.mailer.subject", organization: @organization.name, code: @code))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/concern"
|
|
4
|
+
|
|
5
|
+
module Decidim
|
|
6
|
+
module FriendlySignup
|
|
7
|
+
module NeedsRegistrationCodes
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
included do
|
|
11
|
+
def send_confirmation_instructions
|
|
12
|
+
return super if Decidim::FriendlySignup.use_confirmation_codes.blank?
|
|
13
|
+
return super unless inactive_message.to_s == "unconfirmed"
|
|
14
|
+
|
|
15
|
+
generate_confirmation_token! unless @raw_confirmation_token
|
|
16
|
+
|
|
17
|
+
opts = pending_reconfirmation? ? { to: unconfirmed_email } : {}
|
|
18
|
+
opts[:token] = @raw_confirmation_token
|
|
19
|
+
ConfirmationCodesMailer.confirmation_instructions(self, opts).deliver_now
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -15,6 +15,9 @@ export default class InstantValidator {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
init() {
|
|
18
|
+
if (!this.url || !this.$form.length) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
18
21
|
this.$form.foundation("disableValidation");
|
|
19
22
|
// this final validation prevents abide from resetting the field when user loses focus
|
|
20
23
|
this.$inputs.on("blur", (evt) => {
|
|
@@ -50,10 +53,15 @@ export default class InstantValidator {
|
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
validate($input) {
|
|
56
|
+
let $recheck = $($input.data("instantRecheck"));
|
|
53
57
|
this.tamper($input);
|
|
54
58
|
this.post($input).done((response) => {
|
|
55
59
|
this.setFeedback(response, $input);
|
|
56
60
|
});
|
|
61
|
+
|
|
62
|
+
if ($recheck.length && this.isTampered($recheck)) {
|
|
63
|
+
this.validate($recheck)
|
|
64
|
+
}
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
setFeedback(data, $input) {
|
|
@@ -73,13 +81,14 @@ export default class InstantValidator {
|
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
addErrors($dest, msg) {
|
|
84
|
+
console.log("$dest", $dest, "%form", this.$form)
|
|
76
85
|
if ($dest.closest("label").find(".form-error").length > 1) {
|
|
77
86
|
// Decidim may add and additional error class that does not play well with abide
|
|
78
87
|
$dest.closest("label").find(".form-error:last").remove();
|
|
79
88
|
}
|
|
80
89
|
this.$form.foundation("addErrorClasses", $dest);
|
|
81
90
|
if (msg) {
|
|
82
|
-
$dest.closest("label").find(".form-error").
|
|
91
|
+
$dest.closest("label").find(".form-error").html(msg);
|
|
83
92
|
}
|
|
84
93
|
}
|
|
85
94
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
$(() => {
|
|
2
|
+
const $inputs = $('.confirmation-code-inputs input[type="number"]');
|
|
3
|
+
const $form = $inputs.closest("form");
|
|
4
|
+
const intRegex = /^\d+$/;
|
|
5
|
+
let disableManual = false;
|
|
6
|
+
|
|
7
|
+
// Parses the individual digits into the individual boxes.
|
|
8
|
+
const pasteValues = (element, $first) => {
|
|
9
|
+
const values = element.split("");
|
|
10
|
+
let $inputBox = $first;
|
|
11
|
+
|
|
12
|
+
$(values).each((index) => {
|
|
13
|
+
$inputBox.val(values[index]);
|
|
14
|
+
$inputBox = $inputBox.next('input[type="number"]');
|
|
15
|
+
if ($inputBox.length === 0) {
|
|
16
|
+
$form.submit();
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
$inputs.on("focus", (e) => {
|
|
22
|
+
$(e.target).select();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Prevents user from manually entering non-digits.
|
|
26
|
+
$inputs.on("input.fromManual", (e) => {
|
|
27
|
+
if (disableManual) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const $this = $(e.target);
|
|
31
|
+
if (intRegex.test($this.val())) {
|
|
32
|
+
pasteValues($this.val(), $this);
|
|
33
|
+
$this.next('input[type="number"]').focus();
|
|
34
|
+
} else {
|
|
35
|
+
$this.val("");
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
$inputs.on("paste", (evt) => {
|
|
40
|
+
const $this = $(evt.target);
|
|
41
|
+
const originalValue = $this.val();
|
|
42
|
+
$this.val("");
|
|
43
|
+
disableManual = true;
|
|
44
|
+
$this.one("input.fromPaste", (e) => {
|
|
45
|
+
const $currentInputBox = $(e.target);
|
|
46
|
+
|
|
47
|
+
const pastedValue = $currentInputBox.val();
|
|
48
|
+
if (intRegex.test(pastedValue)) {
|
|
49
|
+
pasteValues(pastedValue, $inputs.eq(0));
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
$this.val(originalValue);
|
|
53
|
+
}
|
|
54
|
+
disableManual = false;
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
.confirmation-code-inputs {
|
|
2
|
+
display: flex;
|
|
3
|
+
justify-content: center;
|
|
4
|
+
margin: 2rem;
|
|
5
|
+
|
|
6
|
+
input[type="number"] {
|
|
7
|
+
width: 15%;
|
|
8
|
+
font-size: 5em;
|
|
9
|
+
height: 1.2em;
|
|
10
|
+
line-height: 1;
|
|
11
|
+
padding: 0;
|
|
12
|
+
margin: 0 2%;
|
|
13
|
+
text-align: center;
|
|
14
|
+
box-shadow: 1px 3px 3px #bbb;
|
|
15
|
+
-moz-appearance: textfield;
|
|
16
|
+
|
|
17
|
+
&::-webkit-inner-spin-button,
|
|
18
|
+
&::-webkit-outer-spin-button {
|
|
19
|
+
-webkit-appearance: none;
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
<div class="row">
|
|
12
12
|
<div class="columns large-6 medium-10 medium-centered">
|
|
13
|
-
<%= decidim_form_for
|
|
13
|
+
<%= decidim_form_for(resource, namespace: "invitation", as: resource_name, url: invitation_path(resource_name, invite_redirect: params[:invite_redirect]), html: { method: :put, class: "register-form new_user#{friendly_override_activated?(:use_instant_validation) ? ' instant-validation' : ''}" } , data: { "validation-url" => decidim_friendly_signup.validate_path }) do |f| %>
|
|
14
14
|
<div class="card">
|
|
15
15
|
<div class="card__content">
|
|
16
16
|
<legend><%= t("sign_up_as.legend", scope: "decidim.devise.registrations.new") %></legend>
|
|
@@ -19,14 +19,16 @@
|
|
|
19
19
|
|
|
20
20
|
<%= f.hidden_field :invitation_token %>
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
<div class="
|
|
24
|
-
|
|
22
|
+
<% unless friendly_override_activated?(:hide_nickname) %>
|
|
23
|
+
<div class="user-nickname">
|
|
24
|
+
<div class="field">
|
|
25
|
+
<%= f.text_field :nickname, help_text: t("devise.invitations.edit.nickname_help", organization: current_organization.name), required: "required", prefix: { value: "@", small: 1, large: 1 }, data: { "instant-attribute" => "nickname", "instant-recheck" => "password" } %>
|
|
26
|
+
</div>
|
|
25
27
|
</div>
|
|
26
|
-
|
|
28
|
+
<% end %>
|
|
27
29
|
|
|
28
30
|
<% if f.object.class.require_password_on_accepting %>
|
|
29
|
-
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { required: "
|
|
31
|
+
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { required: true, autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH), minlength: ::PasswordValidator::MINIMUM_LENGTH, maxlength: ::PasswordValidator::MAX_LENGTH, data: { "instant-attribute" => "password" } }) %>
|
|
30
32
|
<% end %>
|
|
31
33
|
</div>
|
|
32
34
|
</div>
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
<div class="columns medium-7 large-5 medium-centered">
|
|
11
11
|
<div class="card">
|
|
12
12
|
<div class="card__content">
|
|
13
|
-
<%= decidim_form_for(resource, namespace: "password", as: resource_name, url: password_path(resource_name), html: { method: :put, class: "register-form new_user" }) do |f| %>
|
|
13
|
+
<%= decidim_form_for(resource, namespace: "password", as: resource_name, url: password_path(resource_name), html: { method: :put, class: "register-form new_user#{friendly_override_activated?(:use_instant_validation) ? ' instant-validation' : ''}" } , data: { "validation-url" => decidim_friendly_signup.validate_path }) do |f| %>
|
|
14
14
|
<%= form_required_explanation %>
|
|
15
15
|
|
|
16
16
|
<%= f.hidden_field :reset_password_token %>
|
|
17
17
|
|
|
18
|
-
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH) }) %>
|
|
18
|
+
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { required: true, autocomplete: "off", help_text: t("devise.passwords.edit.password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH), minlength: ::PasswordValidator::MINIMUM_LENGTH, maxlength: ::PasswordValidator::MAX_LENGTH, data: { "instant-attribute" => "password" } }) %>
|
|
19
19
|
|
|
20
20
|
<div class="actions">
|
|
21
21
|
<%= f.submit t("devise.passwords.edit.change_my_password"), class: "button expanded" %>
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<div class="row">
|
|
27
27
|
<div class="columns large-6 medium-10 medium-centered">
|
|
28
28
|
|
|
29
|
-
<%= decidim_form_for(@form, namespace: "registration", as: resource_name, url: registration_path(resource_name), html: { class: "register-form new_user#{friendly_override_activated?(:use_instant_validation)
|
|
29
|
+
<%= decidim_form_for(@form, namespace: "registration", as: resource_name, url: registration_path(resource_name), html: { class: "register-form new_user#{friendly_override_activated?(:use_instant_validation) ? ' instant-validation' : ''}", id: "register-form" }, data: { "validation-url" => decidim_friendly_signup.validate_path }) do |f| %>
|
|
30
30
|
<%= invisible_captcha %>
|
|
31
31
|
<div class="card">
|
|
32
32
|
<div class="card__content">
|
|
@@ -34,23 +34,23 @@
|
|
|
34
34
|
|
|
35
35
|
<div class="user-person">
|
|
36
36
|
<div class="field">
|
|
37
|
-
<%= f.text_field :name, help_text: t(".username_help"), autocomplete: "off", data: { "instant-attribute"
|
|
37
|
+
<%= f.text_field :name, help_text: t(".username_help"), autocomplete: "off", data: { "instant-attribute" => "name", "instant-recheck" => "#registration_user_password" } %>
|
|
38
38
|
</div>
|
|
39
39
|
</div>
|
|
40
40
|
|
|
41
41
|
<% unless friendly_override_activated?(:hide_nickname) %>
|
|
42
42
|
<div class="user-nickname">
|
|
43
43
|
<div class="field">
|
|
44
|
-
<%= f.text_field :nickname, help_text: t(".nickname_help", organization: current_organization.name), prefix: { value: "@", small: 1, large: 1 }, autocomplete: "off", data: { "instant-attribute"
|
|
44
|
+
<%= f.text_field :nickname, help_text: t(".nickname_help", organization: current_organization.name), prefix: { value: "@", small: 1, large: 1 }, autocomplete: "off", data: { "instant-attribute" => "nickname", "instant-recheck" => "#registration_user_password" } %>
|
|
45
45
|
</div>
|
|
46
46
|
</div>
|
|
47
47
|
<% end %>
|
|
48
48
|
|
|
49
49
|
<div class="field">
|
|
50
|
-
<%= f.email_field :email, autocomplete: "email", data: { "instant-attribute"
|
|
50
|
+
<%= f.email_field :email, autocomplete: "email", data: { "instant-attribute" => "email", "instant-recheck" => "#registration_user_password" } %>
|
|
51
51
|
</div>
|
|
52
52
|
|
|
53
|
-
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { required: true, help_text: t(".password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH), autocomplete: "off", data: { "instant-attribute"
|
|
53
|
+
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { required: true, help_text: t(".password_help", minimun_characters: ::PasswordValidator::MINIMUM_LENGTH), autocomplete: "off", data: { "instant-attribute" => "password" } }) %>
|
|
54
54
|
</div>
|
|
55
55
|
</div>
|
|
56
56
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<% add_decidim_page_title(t("devise.sessions.new.sign_in")) %>
|
|
2
|
+
|
|
3
|
+
<div class="wrapper">
|
|
4
|
+
<div class="row collapse">
|
|
5
|
+
<div class="row collapse">
|
|
6
|
+
<div class="columns large-8 large-centered text-center page-title">
|
|
7
|
+
<h1><%= t("devise.sessions.new.sign_in") %></h1>
|
|
8
|
+
<% if current_organization.sign_up_enabled? %>
|
|
9
|
+
<p>
|
|
10
|
+
<%= t(".are_you_new?") %>
|
|
11
|
+
<%= link_to t(".register"), new_user_registration_path %>
|
|
12
|
+
</p>
|
|
13
|
+
<% elsif current_organization.sign_in_enabled? %>
|
|
14
|
+
<p>
|
|
15
|
+
<%= t(".sign_up_disabled") %>
|
|
16
|
+
</p>
|
|
17
|
+
<% else %>
|
|
18
|
+
<p>
|
|
19
|
+
<%= t(".sign_in_disabled") %>
|
|
20
|
+
</p>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
<% cache current_organization do %>
|
|
25
|
+
<%= render "decidim/devise/shared/omniauth_buttons" %>
|
|
26
|
+
<% end %>
|
|
27
|
+
|
|
28
|
+
<% if current_organization.sign_in_enabled? %>
|
|
29
|
+
<div class="row">
|
|
30
|
+
<div class="columns large-6 medium-centered">
|
|
31
|
+
<div class="card">
|
|
32
|
+
<div class="card__content">
|
|
33
|
+
<%= decidim_form_for(resource, namespace: "session", as: resource_name, url: session_path(resource_name), html: { class: "register-form new_user" }) do |f| %>
|
|
34
|
+
<div>
|
|
35
|
+
<div class="field">
|
|
36
|
+
<%= f.email_field :email, required: true, pattern: "email" %>
|
|
37
|
+
</div>
|
|
38
|
+
<div class="field">
|
|
39
|
+
<%= render("decidim/friendly_signup/shared/password_fields", form: f, options: { autocomplete: "off" }, skip_confirmation: true) %>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<% if devise_mapping.rememberable? %>
|
|
43
|
+
<div class="field">
|
|
44
|
+
<%= f.check_box :remember_me %>
|
|
45
|
+
</div>
|
|
46
|
+
<% end %>
|
|
47
|
+
<div class="actions">
|
|
48
|
+
<%= f.submit t("devise.sessions.new.sign_in"), class: "button expanded" %>
|
|
49
|
+
</div>
|
|
50
|
+
<% end %>
|
|
51
|
+
<%= render "decidim/devise/shared/links" %>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
<% end %>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<% add_decidim_page_title(t(".enter_code")) %>
|
|
2
|
+
|
|
3
|
+
<div class="wrapper">
|
|
4
|
+
<div class="row collapse">
|
|
5
|
+
<div class="row collapse">
|
|
6
|
+
<div class="columns large-8 large-centered text-center page-title">
|
|
7
|
+
<h1><%= t(".title") %></h1>
|
|
8
|
+
<h6><%= t(".subtitle") %></h6>
|
|
9
|
+
</div>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="row">
|
|
13
|
+
<div class="columns medium-10 large-8 medium-centered">
|
|
14
|
+
<div class="card">
|
|
15
|
+
<div class="card__content">
|
|
16
|
+
<p class="text-center"><%= t(".description", email: "<strong>#{user.email}</strong>").html_safe %></p>
|
|
17
|
+
<%= decidim_form_for(confirmation_form, url: decidim_friendly_signup.confirmation_codes_path(confirmation_token: confirmation_form.confirmation_token)) do |f| %>
|
|
18
|
+
<div class="field confirmation-code-inputs">
|
|
19
|
+
<%= number_field_tag "confirmation_numbers[0]", "", autofocus: true, autocomplete: :off %>
|
|
20
|
+
<%= number_field_tag "confirmation_numbers[1]", "", autocomplete: :off %>
|
|
21
|
+
<%= number_field_tag "confirmation_numbers[2]", "", autocomplete: :off %>
|
|
22
|
+
<%= number_field_tag "confirmation_numbers[3]", "", autocomplete: :off %>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<div class="actions text-center">
|
|
26
|
+
<%= f.submit t(".verify"), class: "button text-uppercase" %>
|
|
27
|
+
</div>
|
|
28
|
+
<% end %>
|
|
29
|
+
|
|
30
|
+
<p class="text-center">
|
|
31
|
+
<%= link_to t(".code_not_received"), decidim.user_confirmation_path(confirmation_token: confirmation_form.confirmation_token, "user[email]" => user.email), method: :post, data: { confirm: t(".confirm_send_code", email: user.email) } %>
|
|
32
|
+
</p>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
data/app/views/decidim/friendly_signup/confirmation_codes_mailer/confirmation_instructions.html.erb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<h1 class="text-center"><%= t(".title") %></h1>
|
|
2
|
+
|
|
3
|
+
<p class="email-instructions text-center"><%= t(".subtitle", organization: link_to(@organization.name, decidim_friendly_signup.confirmation_codes_path(confirmation_token: @token))).html_safe %></p>
|
|
4
|
+
|
|
5
|
+
<h3 class="email-instruction text-center" style="margin:1em 0 0.2em 0;"><%= t(".copy") %></h3>
|
|
6
|
+
|
|
7
|
+
<p class="stat text-center" style="margin:1em 0 0.5em 0;"><b style="font-size: 2em"><%= @code %></b></p>
|
|
8
|
+
|
|
9
|
+
<% if @expires_at %>
|
|
10
|
+
<p class="email-small text-center" style="margin-bottom: 2em;"><%= t(".expires_in", time: distance_of_time_in_words(Time.now, @expires_at, scope: "decidim.friendly_signup.datetime.distance_in_words")) %></p>
|
|
11
|
+
<% end %>
|
|
12
|
+
|
|
13
|
+
<p class="email-small email-closing text-center"><%= t(".ignore").html_safe %></p>
|
|
@@ -9,17 +9,23 @@
|
|
|
9
9
|
</div>
|
|
10
10
|
</div>
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
<div class="
|
|
14
|
-
|
|
12
|
+
<% unless defined?(skip_confirmation) && skip_confirmation %>
|
|
13
|
+
<div class="user-password-confirmation">
|
|
14
|
+
<div class="field">
|
|
15
|
+
<%= form.password_field :password_confirmation %>
|
|
16
|
+
</div>
|
|
15
17
|
</div>
|
|
16
|
-
|
|
18
|
+
<% end %>
|
|
19
|
+
|
|
17
20
|
<% else %>
|
|
18
21
|
<div class="field">
|
|
19
22
|
<%= form.password_field :password, options %>
|
|
20
23
|
</div>
|
|
21
24
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
<% unless defined?(skip_confirmation) && skip_confirmation %>
|
|
26
|
+
<div class="field">
|
|
27
|
+
<%= form.password_field :password_confirmation %>
|
|
28
|
+
</div>
|
|
29
|
+
<% end %>
|
|
30
|
+
|
|
25
31
|
<% end %>
|
data/config/locales/en.yml
CHANGED
|
@@ -1,10 +1,113 @@
|
|
|
1
1
|
---
|
|
2
2
|
en:
|
|
3
|
+
activemodel:
|
|
4
|
+
attributes:
|
|
5
|
+
confirmation_code:
|
|
6
|
+
code: Confirmation code
|
|
3
7
|
decidim:
|
|
8
|
+
forms:
|
|
9
|
+
errors:
|
|
10
|
+
decidim/user:
|
|
11
|
+
email: Please enter a valid email address
|
|
4
12
|
friendly_signup:
|
|
13
|
+
confirmation_code_form:
|
|
14
|
+
expired: Sorry, this code has expired, please generate a new one.
|
|
15
|
+
invalid: Code is invalid, please make sure to copy the code emailed to you.
|
|
16
|
+
invalid_token: Invalid token.
|
|
17
|
+
confirmation_codes:
|
|
18
|
+
create:
|
|
19
|
+
user_confirmed: Welcome %{name}! Your account has been succesfully confirmed!
|
|
20
|
+
index:
|
|
21
|
+
code_not_received: Didn't receive the code?
|
|
22
|
+
confirm_send_code: Do you want to resend the confirmation code to %{email}?<br>Be
|
|
23
|
+
sure to check the spam folder just in case!
|
|
24
|
+
description: You should receive a 4 digit code at %{email}.<br>If you can't
|
|
25
|
+
find it, please check your spam folder or wait up to 10 minutes.
|
|
26
|
+
enter_code: Enter code
|
|
27
|
+
subtitle: You need to confirm your email address to be able to submit proposals,
|
|
28
|
+
comment and vote.
|
|
29
|
+
title: One last step...
|
|
30
|
+
verify: Verify
|
|
31
|
+
mailer:
|
|
32
|
+
subject: "%{code} is your confirmation code for %{organization}"
|
|
33
|
+
resend_code:
|
|
34
|
+
sent: The confirmation code has been sent to %{email}.
|
|
35
|
+
confirmation_codes_mailer:
|
|
36
|
+
confirmation_instructions:
|
|
37
|
+
copy: 'Copy this code:'
|
|
38
|
+
expires_in: It will expire in %{time}.
|
|
39
|
+
ignore: |-
|
|
40
|
+
If you didn't request this comunication, please ignore this email.<br />
|
|
41
|
+
Your account won't be active until your account is fully confirmed.
|
|
42
|
+
subtitle: To finalize the registration you just need to copy the 4 digit
|
|
43
|
+
code below, go back to the %{organization} signup page and paste it!
|
|
44
|
+
title: You're almost there!
|
|
45
|
+
datetime:
|
|
46
|
+
distance_in_words:
|
|
47
|
+
about_x_hours:
|
|
48
|
+
one: about 1 hour
|
|
49
|
+
other: about %{count} hours
|
|
50
|
+
about_x_months:
|
|
51
|
+
one: about 1 month
|
|
52
|
+
other: about %{count} months
|
|
53
|
+
about_x_years:
|
|
54
|
+
one: about 1 year
|
|
55
|
+
other: about %{count} years
|
|
56
|
+
almost_x_years:
|
|
57
|
+
one: almost 1 year
|
|
58
|
+
other: almost %{count} years
|
|
59
|
+
half_a_minute: half a minute
|
|
60
|
+
less_than_x_minutes:
|
|
61
|
+
one: less than a minute
|
|
62
|
+
other: less than %{count} minutes
|
|
63
|
+
less_than_x_seconds:
|
|
64
|
+
one: less than 1 second
|
|
65
|
+
other: less than %{count} seconds
|
|
66
|
+
over_x_years:
|
|
67
|
+
one: over 1 year
|
|
68
|
+
other: over %{count} years
|
|
69
|
+
x_days:
|
|
70
|
+
one: 1 day
|
|
71
|
+
other: "%{count} days"
|
|
72
|
+
x_minutes:
|
|
73
|
+
one: 1 minute
|
|
74
|
+
other: "%{count} minutes"
|
|
75
|
+
x_months:
|
|
76
|
+
one: 1 month
|
|
77
|
+
other: "%{count} months"
|
|
78
|
+
x_seconds:
|
|
79
|
+
one: 1 second
|
|
80
|
+
other: "%{count} seconds"
|
|
81
|
+
errors:
|
|
82
|
+
messages:
|
|
83
|
+
blank: Looks like you haven’t entered anything in this field
|
|
84
|
+
email:
|
|
85
|
+
blank: Please enter an email address
|
|
86
|
+
invalid: The email address looks incomplete
|
|
87
|
+
taken: This email is already in use for another account. Try signing in
|
|
88
|
+
or use another email
|
|
89
|
+
password:
|
|
90
|
+
email_included_in_password: The password you have entered is too similar
|
|
91
|
+
to your email
|
|
92
|
+
name_included_in_password: The password you have entered is too similar
|
|
93
|
+
to your name
|
|
94
|
+
nickname_included_in_password: The password you have entered is too similar
|
|
95
|
+
to your nickname
|
|
96
|
+
not_enough_unique_characters: The password you have entered does not have
|
|
97
|
+
enough different characters
|
|
98
|
+
password_too_common: The password you have entered is very common - we
|
|
99
|
+
suggest using a different password
|
|
100
|
+
password_too_short: The password you have entered is too short
|
|
5
101
|
shared:
|
|
6
102
|
password_fields:
|
|
7
103
|
hidden_password: Your password is hidden
|
|
8
104
|
hide_password: Hide password
|
|
9
105
|
show_password: Show password
|
|
10
106
|
shown_password: Your password is shown
|
|
107
|
+
devise:
|
|
108
|
+
confirmations:
|
|
109
|
+
signed_up_but_code_required: A message with a code has been sent to your email
|
|
110
|
+
address. Please copy and paste the received code in this page.
|
|
111
|
+
registrations:
|
|
112
|
+
signed_up_but_code_required: A message with a code has been sent to your email
|
|
113
|
+
address. Please copy and paste the received code in this page.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require "rails"
|
|
4
4
|
require "decidim/core"
|
|
5
|
+
require "rack/attack"
|
|
5
6
|
|
|
6
7
|
module Decidim
|
|
7
8
|
module FriendlySignup
|
|
@@ -10,21 +11,37 @@ module Decidim
|
|
|
10
11
|
isolate_namespace Decidim::FriendlySignup
|
|
11
12
|
|
|
12
13
|
routes do
|
|
14
|
+
devise_scope :user do
|
|
15
|
+
resources :confirmation_codes, only: [:index, :create]
|
|
16
|
+
end
|
|
13
17
|
post :validate, to: "validator#validate"
|
|
18
|
+
put :validate, to: "validator#validate"
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
# Prepare a zone to create overrides
|
|
17
22
|
# https://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers
|
|
18
23
|
# overrides
|
|
19
24
|
config.after_initialize do
|
|
25
|
+
Decidim::Devise::SessionsController.include(Decidim::FriendlySignup::NeedsHeaderSnippets)
|
|
20
26
|
Decidim::Devise::RegistrationsController.include(Decidim::FriendlySignup::NeedsHeaderSnippets)
|
|
21
|
-
Decidim::Devise::InvitationsController.include(Decidim::FriendlySignup::NeedsHeaderSnippets)
|
|
22
27
|
Decidim::Devise::PasswordsController.include(Decidim::FriendlySignup::NeedsHeaderSnippets)
|
|
28
|
+
Decidim::Devise::InvitationsController.include(Decidim::FriendlySignup::NeedsHeaderSnippets)
|
|
29
|
+
Decidim::Devise::RegistrationsController.include(Decidim::FriendlySignup::RegistrationsRedirect)
|
|
30
|
+
Decidim::Devise::ConfirmationsController.include(Decidim::FriendlySignup::RegistrationsRedirect)
|
|
23
31
|
Decidim::AccountController.include(Decidim::FriendlySignup::NeedsHeaderSnippets)
|
|
24
32
|
Decidim::RegistrationForm.include(Decidim::FriendlySignup::AutoNickname)
|
|
33
|
+
Decidim::User.include(Decidim::FriendlySignup::NeedsRegistrationCodes)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
initializer "friendly_signup.confirmation_throttling" do
|
|
37
|
+
# Throttle confirmation attempts for a given code parameter to 6 reqs/minute
|
|
38
|
+
# Return the confirmation_token as a discriminator on POST /users/sign_in requests
|
|
39
|
+
Rack::Attack.throttle("limit confirmations attempts per code", limit: 5, period: 60.seconds) do |request|
|
|
40
|
+
request.params["confirmation_token"] if request.path == "/friendly_signup/confirmation_codes" && request.post?
|
|
41
|
+
end
|
|
25
42
|
end
|
|
26
43
|
|
|
27
|
-
initializer "
|
|
44
|
+
initializer "friendly_signup.webpacker.assets_path" do
|
|
28
45
|
Decidim.register_assets_path File.expand_path("app/packs", root)
|
|
29
46
|
end
|
|
30
47
|
end
|
|
@@ -28,11 +28,44 @@ module Decidim
|
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def error
|
|
31
|
-
|
|
31
|
+
return if valid?
|
|
32
|
+
|
|
33
|
+
errors.map do |msg|
|
|
34
|
+
key = find_key(msg)
|
|
35
|
+
next if key == :nickname_included_in_password && FriendlySignup.hide_nickname.present?
|
|
36
|
+
|
|
37
|
+
custom_error(key).presence || msg.upcase_first
|
|
38
|
+
end.join(".<br>")
|
|
32
39
|
end
|
|
33
40
|
|
|
34
41
|
private
|
|
35
42
|
|
|
43
|
+
def custom_error(key)
|
|
44
|
+
return if key.blank?
|
|
45
|
+
|
|
46
|
+
generic = I18n.t(key, scope: "decidim.friendly_signup.errors.messages", default: "")
|
|
47
|
+
I18n.t("#{attribute}.#{key}", scope: "decidim.friendly_signup.errors.messages", default: generic)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def find_key(msg)
|
|
51
|
+
case attribute
|
|
52
|
+
when "password"
|
|
53
|
+
[:blacklisted,
|
|
54
|
+
:domain_included_in_password,
|
|
55
|
+
:email_included_in_password,
|
|
56
|
+
:fallback,
|
|
57
|
+
:name_included_in_password,
|
|
58
|
+
:nickname_included_in_password,
|
|
59
|
+
:not_enough_unique_characters,
|
|
60
|
+
:password_not_allowed,
|
|
61
|
+
:password_too_common,
|
|
62
|
+
:password_too_long,
|
|
63
|
+
:password_too_short].find { |key| msg == I18n.t(key, scope: "password_validator") }
|
|
64
|
+
else
|
|
65
|
+
[:blank, :invalid, :taken].find { |key| msg == I18n.t(key, scope: "errors.messages") }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
36
69
|
def valid_attribute?
|
|
37
70
|
%w(nickname email name password).include? attribute.to_s
|
|
38
71
|
end
|
|
@@ -40,10 +73,6 @@ module Decidim
|
|
|
40
73
|
def valid_suggestor?
|
|
41
74
|
["nickname"].include? attribute.to_s
|
|
42
75
|
end
|
|
43
|
-
|
|
44
|
-
def valid_users
|
|
45
|
-
Decidim::UserBaseEntity.where(invitation_token: nil, organization: current_organization)
|
|
46
|
-
end
|
|
47
76
|
end
|
|
48
77
|
end
|
|
49
78
|
end
|
|
@@ -23,6 +23,18 @@ module Decidim
|
|
|
23
23
|
config_accessor :hide_nickname do
|
|
24
24
|
true
|
|
25
25
|
end
|
|
26
|
+
|
|
27
|
+
# Use confirmation codes instead of confirmation links
|
|
28
|
+
config_accessor :use_confirmation_codes do
|
|
29
|
+
true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Generates a secure code from a string
|
|
33
|
+
def self.confirmation_code(hash)
|
|
34
|
+
num = Decidim::Tokenizer.new(salt: Rails.application.secret_key_base).int_digest(hash).to_s[0..3]
|
|
35
|
+
num += "0" while num.size < 4
|
|
36
|
+
num.to_i
|
|
37
|
+
end
|
|
26
38
|
end
|
|
27
39
|
end
|
|
28
40
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: decidim-friendly_signup
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 0.4.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ivan Vergés
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-07-
|
|
11
|
+
date: 2022-07-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: decidim-core
|
|
@@ -49,21 +49,31 @@ files:
|
|
|
49
49
|
- README.md
|
|
50
50
|
- Rakefile
|
|
51
51
|
- app/controllers/concerns/decidim/friendly_signup/needs_header_snippets.rb
|
|
52
|
+
- app/controllers/concerns/decidim/friendly_signup/registrations_redirect.rb
|
|
52
53
|
- app/controllers/decidim/friendly_signup/application_controller.rb
|
|
54
|
+
- app/controllers/decidim/friendly_signup/confirmation_codes_controller.rb
|
|
53
55
|
- app/controllers/decidim/friendly_signup/validator_controller.rb
|
|
54
56
|
- app/forms/concerns/decidim/friendly_signup/auto_nickname.rb
|
|
57
|
+
- app/forms/decidim/friendly_signup/confirmation_code_form.rb
|
|
58
|
+
- app/mailers/decidim/friendly_signup/confirmation_codes_mailer.rb
|
|
59
|
+
- app/models/concerns/decidim/friendly_signup/needs_registration_codes.rb
|
|
55
60
|
- app/packs/entrypoints/decidim_friendly_signup.js
|
|
56
61
|
- app/packs/entrypoints/decidim_friendly_signup.scss
|
|
57
62
|
- app/packs/images/decidim/friendly_signup/icon.svg
|
|
58
63
|
- app/packs/src/decidim/friendly_signup/lib/instant_validator.js
|
|
59
64
|
- app/packs/src/decidim/friendly_signup/lib/password_toggler.js
|
|
65
|
+
- app/packs/src/decidim/friendly_signup/setup_confirmations.js
|
|
60
66
|
- app/packs/src/decidim/friendly_signup/setup_password.js
|
|
61
67
|
- app/packs/src/decidim/friendly_signup/setup_validations.js
|
|
68
|
+
- app/packs/stylesheets/decidim/friendly_signup/_confirmation-codes.scss
|
|
62
69
|
- app/packs/stylesheets/decidim/friendly_signup/_input-groups.scss
|
|
63
70
|
- app/views/decidim/account/_password_fields.html.erb
|
|
64
71
|
- app/views/decidim/devise/invitations/edit.html.erb
|
|
65
72
|
- app/views/decidim/devise/passwords/edit.html.erb
|
|
66
73
|
- app/views/decidim/devise/registrations/new.html.erb
|
|
74
|
+
- app/views/decidim/devise/sessions/new.html.erb
|
|
75
|
+
- app/views/decidim/friendly_signup/confirmation_codes/index.html.erb
|
|
76
|
+
- app/views/decidim/friendly_signup/confirmation_codes_mailer/confirmation_instructions.html.erb
|
|
67
77
|
- app/views/decidim/friendly_signup/shared/_password_fields.html.erb
|
|
68
78
|
- config/assets.rb
|
|
69
79
|
- config/i18n-tasks.yml
|