lato 0.1.26 → 0.1.28

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6efff0dabd7587626cdb6a08a71312793654ddfed11b2a60fea58e58475eb8ac
4
- data.tar.gz: ff65ff6ad27a5b14c02742de7bb692a24e87e9305136d0bcfb0e9c9406377c26
3
+ metadata.gz: 5bcb5a6f47f56626a7fd68c8ab3872971d88291b568c8ede302e2307648babd3
4
+ data.tar.gz: d250a7b34e0dcee6cadbd41a4f93b2fccaaa6f78dd0b56b4f96d2a5cd5b3c097
5
5
  SHA512:
6
- metadata.gz: 9acbbfba492ee88a0f8acf41265966e7904de8e1cf060331b115e12d06ac41f58782935a4ab7b60c20b18bf1a62aa9e7850e69ea66160530e98c7927c2c6d914
7
- data.tar.gz: 532de791068976f1a0b4b693e14e0a10dd5ce88ebf7043065dd0c409fa2a7b1f3195799a00c74f64b36273260458a91e72394f27ee1b5eb83ebf307fba3e5270
6
+ metadata.gz: 61591a5033d2c16ca7bfbda32416d41060156298a4f2272daa210bf1203be2ccf4ec16e4f59034e05196a9f23dfc1621fa0b3e15db82421a930386c29b144d12
7
+ data.tar.gz: 73f3a4fdf44043aca72b8276c53a9d73d6285b59a49db1308d2c10e358f715d2c58b77f6c755763124b49072b5c11861f7d1b03f4dc0cbc1511fad4fd51a6d9a
@@ -1,12 +1,19 @@
1
1
  module Lato
2
2
  class AuthenticationController < ApplicationController
3
- before_action :not_authenticate_session, only: %i[signin signin_action signup signup_action]
3
+ before_action :not_authenticate_session, only: %i[signin signin_action signup signup_action accept_invitation accept_invitation_action]
4
4
  before_action :authenticate_session, only: %i[signout signout_action]
5
+
5
6
  before_action :find_user, only: %i[verify_email verify_email_action update_password update_password_action]
6
- before_action :hide_sidebar
7
+ before_action :find_invitation, only: %i[accept_invitation accept_invitation_action]
8
+
7
9
  before_action :lock_signup_if_disabled, only: %i[signup signup_action]
8
10
  before_action :lock_recover_password_if_disabled, only: %i[recover_password recover_password_action update_password update_password_action]
9
11
 
12
+ before_action :hide_sidebar
13
+
14
+ # Signin
15
+ ##
16
+
10
17
  def signin
11
18
  @user = Lato::User.new
12
19
  end
@@ -15,7 +22,10 @@ module Lato
15
22
  @user = Lato::User.new
16
23
 
17
24
  respond_to do |format|
18
- if @user.signin(params.require(:user).permit(:email, :password))
25
+ if @user.signin(params.require(:user).permit(:email, :password).merge(
26
+ ip_address: request.remote_ip,
27
+ user_agent: request.user_agent
28
+ ))
19
29
  session_create(@user.id)
20
30
 
21
31
  format.html { redirect_to lato.root_path }
@@ -27,12 +37,15 @@ module Lato
27
37
  end
28
38
  end
29
39
 
40
+ # Signup
41
+ ##
42
+
30
43
  def signup
31
44
  @user = Lato::User.new
32
45
  end
33
46
 
34
47
  def signup_action
35
- @user = Lato::User.new(params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :accepted_privacy_policy_version, :accepted_terms_and_conditions_version))
48
+ @user = Lato::User.new(registration_params)
36
49
 
37
50
  respond_to do |format|
38
51
  if @user.save
@@ -47,6 +60,9 @@ module Lato
47
60
  end
48
61
  end
49
62
 
63
+ # Signout
64
+ ##
65
+
50
66
  def signout; end
51
67
 
52
68
  def signout_action
@@ -58,6 +74,9 @@ module Lato
58
74
  end
59
75
  end
60
76
 
77
+ # Verify email
78
+ ##
79
+
61
80
  def verify_email
62
81
  @code = params[:code]
63
82
  end
@@ -74,6 +93,9 @@ module Lato
74
93
  end
75
94
  end
76
95
 
96
+ # Recover password
97
+ ##
98
+
77
99
  def recover_password
78
100
  @user = Lato::User.new
79
101
  end
@@ -92,6 +114,9 @@ module Lato
92
114
  end
93
115
  end
94
116
 
117
+ # Update password
118
+ ##
119
+
95
120
  def update_password; end
96
121
 
97
122
  def update_password_action
@@ -106,23 +131,55 @@ module Lato
106
131
  end
107
132
  end
108
133
 
134
+ # Accept invitation
135
+ ##
136
+
137
+ def accept_invitation
138
+ @user = Lato::User.new(email: @invitation.email)
139
+ end
140
+
141
+ def accept_invitation_action
142
+ @user = Lato::User.new(registration_params)
143
+
144
+ respond_to do |format|
145
+ if @user.accept_invitation(params.permit(:id, :accepted_code))
146
+ session_create(@user.id)
147
+
148
+ format.html { redirect_to lato.root_path }
149
+ format.json { render json: @user }
150
+ else
151
+ format.html { render :accept_invitation, status: :unprocessable_entity }
152
+ format.json { render json: @user.errors, status: :unprocessable_entity }
153
+ end
154
+ end
155
+ end
156
+
109
157
  private
110
158
 
159
+ def registration_params
160
+ params.require(:user).permit(:first_name, :last_name, :email, :password, :password_confirmation, :accepted_privacy_policy_version, :accepted_terms_and_conditions_version)
161
+ end
162
+
111
163
  def find_user
112
164
  @user = User.find_by(id: params[:id])
113
165
  respond_to_with_not_found unless @user
114
166
  end
115
167
 
168
+ def find_invitation
169
+ @invitation = Lato::Invitation.find_by(id: params[:id], accepted_code: params[:accepted_code])
170
+ respond_to_with_not_found unless @invitation
171
+ end
172
+
116
173
  def lock_signup_if_disabled
117
174
  return unless Lato.config.auth_disable_signup
118
175
 
119
- respond_to_with_not_found
176
+ respond_to_with_not_found
120
177
  end
121
178
 
122
179
  def lock_recover_password_if_disabled
123
180
  return unless Lato.config.auth_disable_recover_password
124
181
 
125
- respond_to_with_not_found
182
+ respond_to_with_not_found
126
183
  end
127
184
  end
128
185
  end
@@ -50,7 +50,8 @@ module Lato
50
50
  columns = options[:columns] || @_lato_index[key][:columns] || collection.column_names || []
51
51
  sortable_columns = @_lato_index[key][:sortable_columns] || []
52
52
  searchable_columns = @_lato_index[key][:searchable_columns] || []
53
- model_name_underscore = options[:model_name] || collection.model.name.gsub('/', '_').underscore
53
+ model_name = options[:model_name] || collection.model.name
54
+ model_name_underscore = options[:model_name] || model_name.underscore.gsub('/', '_')
54
55
 
55
56
  render(
56
57
  'lato/components/index',
@@ -59,11 +60,20 @@ module Lato
59
60
  columns: columns,
60
61
  sortable_columns: sortable_columns,
61
62
  searchable_columns: searchable_columns,
63
+ model_name: model_name,
62
64
  model_name_underscore: model_name_underscore,
63
65
  custom_actions: options[:custom_actions] || {}
64
66
  )
65
67
  end
66
68
 
69
+ def lato_index_dynamic_label(params = {})
70
+ 'Please override the method lato_index_dynamic_label in your application_helper.rb'
71
+ end
72
+
73
+ def lato_index_dynamic_value(params = {})
74
+ 'Please override the method lato_index_dynamic_value in your application_helper.rb'
75
+ end
76
+
67
77
  # Operation
68
78
  ##
69
79
 
@@ -56,7 +56,9 @@ module Lato
56
56
  yield
57
57
  @operation&.completed
58
58
  rescue StandardError => e
59
- @operation&.failed(e.message)
59
+ return @operation.failed(e.message) if @operation
60
+
61
+ raise e
60
62
  end
61
63
  end
62
64
  end
@@ -0,0 +1,21 @@
1
+ module Lato
2
+ class InvitationMailer < ApplicationMailer
3
+ def invite_mail(invitation_id)
4
+ @invitation = Lato::Invitation.find(invitation_id)
5
+
6
+ set_invitation_locale
7
+
8
+ mail(
9
+ to: @invitation.email,
10
+ subject: 'Hai ricevuto un invito',
11
+ template_path: 'lato/mailer/invitation'
12
+ )
13
+ end
14
+
15
+ private
16
+
17
+ def set_invitation_locale
18
+ I18n.locale = @invitation.lato_user&.locale || I18n.default_locale
19
+ end
20
+ end
21
+ end
@@ -3,6 +3,9 @@ module Lato
3
3
  def email_verification_mail(user_id, code)
4
4
  @user = Lato::User.find(user_id)
5
5
  @code = code
6
+
7
+ set_user_locale
8
+
6
9
  mail(
7
10
  to: @user.email,
8
11
  subject: 'Conferma il tuo indirizzo email',
@@ -13,11 +16,20 @@ module Lato
13
16
  def password_update_mail(user_id, code)
14
17
  @user = Lato::User.find(user_id)
15
18
  @code = code
19
+
20
+ set_user_locale
21
+
16
22
  mail(
17
23
  to: @user.email,
18
24
  subject: 'Imposta una nuova password',
19
25
  template_path: 'lato/mailer/user'
20
26
  )
21
27
  end
28
+
29
+ private
30
+
31
+ def set_user_locale
32
+ I18n.locale = @user.locale || I18n.default_locale
33
+ end
22
34
  end
23
35
  end
@@ -0,0 +1,82 @@
1
+ module Lato
2
+ class Invitation < ApplicationRecord
3
+ attr_accessor :actions
4
+
5
+ # Kredis
6
+ ##
7
+
8
+ kredis_boolean :email_invite_semaphore, expires_in: 2.minutes
9
+
10
+ # Validations
11
+ ##
12
+
13
+ validates :email, presence: true, uniqueness: true
14
+
15
+ # Relations
16
+ ##
17
+
18
+ belongs_to :lato_user, class_name: 'Lato::User', foreign_key: :lato_user_id, optional: true
19
+
20
+ # Hooks
21
+ ##
22
+
23
+ before_validation do
24
+ self.email = email&.downcase&.strip
25
+ end
26
+
27
+ # be sure that email is not already used by another user
28
+ before_create do
29
+ if Lato::User.find_by(email: email)
30
+ errors.add(:email, 'is already used by another user')
31
+ throw :abort
32
+ end
33
+ end
34
+
35
+ # generate a random code for the invitation
36
+ before_create do
37
+ self.accepted_code = SecureRandom.hex(16)
38
+ end
39
+
40
+ # send an email to the invited user
41
+ after_create do
42
+ send_invite
43
+ end
44
+
45
+ # be sure accepted invitations can not be deleted
46
+ before_destroy do
47
+ throw :abort if accepted?
48
+ end
49
+
50
+ # Helpers
51
+ ##
52
+
53
+ def accepted?
54
+ !!accepted_at
55
+ end
56
+
57
+ # Operations
58
+ ##
59
+
60
+ def send_invite
61
+ if accepted?
62
+ errors.add(:base, :already_accepted)
63
+ return false
64
+ end
65
+
66
+ if email_invite_semaphore.value
67
+ errors.add(:base, :email_sending_limit)
68
+ return false
69
+ end
70
+
71
+ delivery = Lato::InvitationMailer.invite_mail(id).deliver_now
72
+ unless delivery
73
+ errors.add(:base, :email_sending_error)
74
+ return false
75
+ end
76
+
77
+ email_invite_semaphore.value = true
78
+
79
+ true
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,8 @@
1
+ module Lato
2
+ class Log::UserSignin < ApplicationRecord
3
+ # Relations
4
+ ##
5
+
6
+ belongs_to :lato_user, class_name: 'Lato::User', foreign_key: :lato_user_id, optional: true
7
+ end
8
+ end
@@ -0,0 +1,14 @@
1
+ module Lato
2
+ module Log
3
+ # This module is used to add log to the application.
4
+ # Log are used to track user actions without sensitive data.
5
+ # Log should not be destroyed.
6
+ before_destroy do
7
+ throw :abort
8
+ end
9
+
10
+ def self.table_name_prefix
11
+ 'lato_log_'
12
+ end
13
+ end
14
+ end
@@ -10,6 +10,11 @@ module Lato
10
10
  has_one_attached :input_file
11
11
  has_one_attached :output_file
12
12
 
13
+ # Relations
14
+ ##
15
+
16
+ belongs_to :lato_user, class_name: 'Lato::User', foreign_key: :lato_user_id, optional: true
17
+
13
18
  # Hooks
14
19
  ##
15
20
 
@@ -50,6 +55,7 @@ module Lato
50
55
  end
51
56
 
52
57
  # Operations
58
+ ##
53
59
 
54
60
  def start
55
61
  begin
@@ -93,7 +99,7 @@ module Lato
93
99
  }
94
100
  operation_params[:input_file] = file unless file.nil?
95
101
 
96
- Operation.create(operation_params)
102
+ Lato::Operation.create(operation_params)
97
103
  end
98
104
  end
99
105
  end
@@ -24,6 +24,9 @@ module Lato
24
24
  ##
25
25
 
26
26
  has_many :lato_operations, class_name: 'Lato::Operation', foreign_key: :lato_user_id, dependent: :nullify
27
+ has_many :lato_invitations, class_name: 'Lato::Invitation', foreign_key: :lato_user_id, dependent: :nullify
28
+
29
+ has_many :lato_log_user_signins, class_name: 'Lato::Log::UserSignin', foreign_key: :lato_user_id, dependent: :nullify
27
30
 
28
31
  # Hooks
29
32
  ##
@@ -80,6 +83,15 @@ module Lato
80
83
  self.id = user.id
81
84
  reload
82
85
 
86
+ begin
87
+ lato_log_user_signins.create(
88
+ ip_address: params[:ip_address],
89
+ user_agent: params[:user_agent]
90
+ )
91
+ rescue StandardError => e
92
+ Rails.logger.error(e)
93
+ end
94
+
83
95
  true
84
96
  end
85
97
 
@@ -120,15 +132,6 @@ module Lato
120
132
  true
121
133
  end
122
134
 
123
- def destroy_with_confirmation(params)
124
- unless params[:email_confirmation] == email
125
- errors.add(:email, :not_correct)
126
- return
127
- end
128
-
129
- destroy
130
- end
131
-
132
135
  def request_recover_password(params)
133
136
  user = Lato::User.find_by(email: params[:email])
134
137
  unless user
@@ -184,5 +187,31 @@ module Lato
184
187
 
185
188
  update(accepted_terms_and_conditions_version: Lato.config.legal_terms_and_conditions_version)
186
189
  end
190
+
191
+ def destroy_with_confirmation(params)
192
+ unless params[:email_confirmation] == email
193
+ errors.add(:email, :not_correct)
194
+ return
195
+ end
196
+
197
+ destroy
198
+ end
199
+
200
+ def accept_invitation(params)
201
+ invitation = Lato::Invitation.find_by(id: params[:id], accepted_code: params[:accepted_code])
202
+ if !invitation || invitation.accepted? || invitation.email != email
203
+ errors.add(:base, :invitation_invalid)
204
+ return
205
+ end
206
+
207
+ ActiveRecord::Base.transaction do
208
+ raise ActiveRecord::Rollback unless save && invitation.update(
209
+ accepted_at: Time.now,
210
+ lato_user_id: id
211
+ )
212
+
213
+ true
214
+ end
215
+ end
187
216
  end
188
217
  end
@@ -0,0 +1,37 @@
1
+ <%
2
+
3
+ email_readonly ||= false
4
+
5
+ %>
6
+
7
+ <div class="row">
8
+ <div class="col col-12 col-md-6 mb-3">
9
+ <%= lato_form_item_label form, :first_name %>
10
+ <%= lato_form_item_input_text form, :first_name, required: true %>
11
+ </div>
12
+
13
+ <div class="col col-12 col-md-6 mb-3">
14
+ <%= lato_form_item_label form, :last_name %>
15
+ <%= lato_form_item_input_text form, :last_name, required: true %>
16
+ </div>
17
+
18
+ <div class="col col-12 mb-3">
19
+ <%= lato_form_item_label form, :email %>
20
+ <%= lato_form_item_input_email form, :email, required: true, readonly: email_readonly %>
21
+ </div>
22
+
23
+ <div class="col col-12 col-md-6 mb-3">
24
+ <%= lato_form_item_label form, :password %>
25
+ <%= lato_form_item_input_password form, :password, required: true %>
26
+ </div>
27
+
28
+ <div class="col col-12 col-md-6 mb-3">
29
+ <%= lato_form_item_label form, :password_confirmation %>
30
+ <%= lato_form_item_input_password form, :password_confirmation, required: true %>
31
+ </div>
32
+ </div>
33
+
34
+ <div class="mb-3 text-muted" style="font-size: 14px;">
35
+ <%= lato_form_item_input_check form, :accepted_privacy_policy_version, I18n.t('lato.privacy_policy_checkbox', link: link_to(I18n.t('lato.privacy_policy'), Lato.config.legal_privacy_policy_url)), required: true %>
36
+ <%= lato_form_item_input_check form, :accepted_terms_and_conditions_version, I18n.t('lato.terms_and_conditions_checkbox', link: link_to(I18n.t('lato.terms_and_conditions'), Lato.config.legal_terms_and_conditions_url)), required: true %>
37
+ </div>
@@ -0,0 +1,18 @@
1
+ <%
2
+
3
+ user ||= Lato::User.new
4
+ invitation ||= Lato::Invitation.new
5
+
6
+ %>
7
+
8
+ <%= turbo_frame_tag 'authentication_form-signup' do %>
9
+ <%= form_with model: user, url: lato.authentication_accept_invitation_action_path(id: invitation.id, accepted_code: invitation.accepted_code), data: { turbo_frame: '_self', controller: 'lato-form' } do |form| %>
10
+ <%= lato_form_errors user, class: %w[mb-3] %>
11
+
12
+ <%= render 'lato/authentication/fields-registration', form: form, email_readonly: true %>
13
+
14
+ <div class="d-flex justify-content-end">
15
+ <%= lato_form_submit form, I18n.t('lato.confirm') %>
16
+ </div>
17
+ <% end %>
18
+ <% end %>
@@ -8,37 +8,7 @@ user ||= Lato::User.new
8
8
  <%= form_with model: user, url: lato.authentication_signup_action_path, data: { turbo_frame: '_self', controller: 'lato-form' } do |form| %>
9
9
  <%= lato_form_errors user, class: %w[mb-3] %>
10
10
 
11
- <div class="row">
12
- <div class="col col-12 col-md-6 mb-3">
13
- <%= lato_form_item_label form, :first_name %>
14
- <%= lato_form_item_input_text form, :first_name, required: true %>
15
- </div>
16
-
17
- <div class="col col-12 col-md-6 mb-3">
18
- <%= lato_form_item_label form, :last_name %>
19
- <%= lato_form_item_input_text form, :last_name, required: true %>
20
- </div>
21
-
22
- <div class="col col-12 mb-3">
23
- <%= lato_form_item_label form, :email %>
24
- <%= lato_form_item_input_email form, :email, required: true %>
25
- </div>
26
-
27
- <div class="col col-12 col-md-6 mb-3">
28
- <%= lato_form_item_label form, :password %>
29
- <%= lato_form_item_input_password form, :password, required: true %>
30
- </div>
31
-
32
- <div class="col col-12 col-md-6 mb-3">
33
- <%= lato_form_item_label form, :password_confirmation %>
34
- <%= lato_form_item_input_password form, :password_confirmation, required: true %>
35
- </div>
36
- </div>
37
-
38
- <div class="mb-3 text-muted" style="font-size: 14px;">
39
- <%= lato_form_item_input_check form, :accepted_privacy_policy_version, I18n.t('lato.privacy_policy_checkbox', link: link_to(I18n.t('lato.privacy_policy'), Lato.config.legal_privacy_policy_url)), required: true %>
40
- <%= lato_form_item_input_check form, :accepted_terms_and_conditions_version, I18n.t('lato.terms_and_conditions_checkbox', link: link_to(I18n.t('lato.terms_and_conditions'), Lato.config.legal_terms_and_conditions_url)), required: true %>
41
- </div>
11
+ <%= render 'lato/authentication/fields-registration', form: form %>
42
12
 
43
13
  <div class="d-flex justify-content-end">
44
14
  <%= lato_form_submit form, I18n.t('lato.signup') %>
@@ -0,0 +1,10 @@
1
+ <div class="w-100 h-100 d-flex justify-content-center align-items-center" style="min-height: calc(100vh - 54px - 2rem)">
2
+ <div class="card w-100" style="max-width: 550px">
3
+ <div class="card-header">
4
+ <h1 class="fs-3 mb-0 text-center"><%= I18n.t('lato.accept_invitation') %></h1>
5
+ </div>
6
+ <div class="card-body">
7
+ <%= render 'lato/authentication/form-accept-invitation', user: @user, invitation: @invitation %>
8
+ </div>
9
+ </div>
10
+ </div>
@@ -1,3 +1,9 @@
1
+ <%
2
+
3
+ collection_test_istance = collection.model.new
4
+
5
+ %>
6
+
1
7
  <%= turbo_frame_tag "lato_index_#{key}_#{model_name_underscore}", class: 'lato-index' do %>
2
8
 
3
9
  <%= form_tag request.path, method: :get, data: { turbo_frame: '_self' } do %>
@@ -38,10 +44,19 @@
38
44
  <tbody>
39
45
  <% columns.each do |column| %>
40
46
  <tr>
41
- <th><%= collection.model.human_attribute_name column %></th>
47
+ <th><%= collection_test_istance.respond_to?(column) ? collection.model.human_attribute_name(column) : lato_index_dynamic_label({
48
+ key: key,
49
+ model_name: model_name,
50
+ column: column
51
+ }) %></th>
42
52
  <td class="lato-index-col-<%= column %>">
43
53
  <% viewer_function_name = "#{model_name_underscore}_#{column}" %>
44
- <%= respond_to?(viewer_function_name) ? send(viewer_function_name, member) : member.send(column) %>
54
+ <%= respond_to?(viewer_function_name) ? send(viewer_function_name, member) : (collection_test_istance.respond_to?(column) ? member.send(column) : lato_index_dynamic_value({
55
+ key: key,
56
+ model_name: model_name,
57
+ column: column,
58
+ member: member
59
+ })) %>
45
60
  </td>
46
61
  </tr>
47
62
  <% end %>
@@ -67,7 +82,11 @@
67
82
  <% columns.each do |column| %>
68
83
  <th scope="col" class="lato-index-col-<%= column %>">
69
84
  <div class="d-flex align-items-center">
70
- <span><%= collection.model.human_attribute_name column %></span>
85
+ <span><%= collection_test_istance.respond_to?(column) ? collection.model.human_attribute_name(column) : lato_index_dynamic_label({
86
+ key: key,
87
+ model_name: model_name,
88
+ column: column
89
+ }) %></span>
71
90
  <% if sortable_columns.include?(column) %>
72
91
  <div class="btn-group ms-3">
73
92
  <div class="position-relative btn btn-sm <%= params[:sort_by] == "#{column}|ASC" ? 'btn-primary' : 'btn-outline-primary' %>">
@@ -92,7 +111,12 @@
92
111
  <% columns.each do |column| %>
93
112
  <td class="lato-index-col-<%= column %>">
94
113
  <% viewer_function_name = "#{model_name_underscore}_#{column}" %>
95
- <%= respond_to?(viewer_function_name) ? send(viewer_function_name, member) : member.send(column) %>
114
+ <%= respond_to?(viewer_function_name) ? send(viewer_function_name, member) : (collection_test_istance.respond_to?(column) ? member.send(column) : lato_index_dynamic_value({
115
+ key: key,
116
+ model_name: model_name,
117
+ column: column,
118
+ member: member
119
+ })) %>
96
120
  </td>
97
121
  <% end %>
98
122
  </tr>
@@ -0,0 +1,17 @@
1
+ <% if I18n.locale == 'en' %>
2
+
3
+ You have received an invitation to use <%= Lato.config.application_title %>.
4
+ <br><br>
5
+ Click the following link to accept the invitation and complete the registration:
6
+ <br><br>
7
+ <%= link_to lato.authentication_accept_invitation_url(id: @invitation.id, accepted_code: @invitation.accepted_code), lato.authentication_accept_invitation_url(id: @invitation.id, accepted_code: @invitation.accepted_code) %>
8
+
9
+ <% else %>
10
+
11
+ Hai ricevuto un invito per utilizzare <%= Lato.config.application_title %>.
12
+ <br><br>
13
+ Clicca il seguente link per accettare l'invito e completare la registrazione:
14
+ <br><br>
15
+ <%= link_to lato.authentication_accept_invitation_url(id: @invitation.id, accepted_code: @invitation.accepted_code), lato.authentication_accept_invitation_url(id: @invitation.id, accepted_code: @invitation.accepted_code) %>
16
+
17
+ <% end %>
@@ -1,4 +1,4 @@
1
- <% if @user.locale == 'en' %>
1
+ <% if I18n.locale == 'en' %>
2
2
 
3
3
  To have access to all the features of <%= Lato.config.application_title %> you must confirm your email address.
4
4
  <br><br>
@@ -1,4 +1,4 @@
1
- <% if @user.locale == 'en' %>
1
+ <% if I18n.locale == 'en' %>
2
2
 
3
3
  An update to your <%= Lato.config.application_title %> account password has been requested.
4
4
  <br><br>
@@ -13,4 +13,19 @@
13
13
  </div>
14
14
  </div>
15
15
  <% end %>
16
+
17
+ <% if alert %>
18
+ <div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
19
+ <div data-controller="lato-feedback" id="feedbackAlert" class="toast hide" role="alert" aria-live="assertive" aria-atomic="true">
20
+ <div class="toast-header">
21
+ <i class="bi bi-check-circle-fill text-danger me-2"></i>
22
+ <strong class="me-auto"><%= I18n.t('lato.operation_failed') %></strong>
23
+ <button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
24
+ </div>
25
+ <div class="toast-body">
26
+ <%= alert %>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ <% end %>
16
31
  </div>
@@ -1,7 +1,7 @@
1
- <% if @user.locale == 'en' %>
2
- Hello <%= @user.first_name %>,
1
+ <% if I18n.locale == 'en' %>
2
+ Hello,
3
3
  <br><br>
4
4
  <% else %>
5
- Salve <%= @user.first_name %>,
5
+ Salve,
6
6
  <br><br>
7
- <%end %>
7
+ <% end %>
@@ -36,8 +36,10 @@ en:
36
36
  signout_confirmation_request: "%{user}, Are you sure to leave?"
37
37
  recover_password_code: Code received by email
38
38
  operation_completed: Operation completed
39
+ operation_failed: Operation failed
39
40
  privacy_policy_update_title: Privacy policy update
40
41
  terms_and_conditions_update_title: Terms and conditions update
42
+ accept_invitation: Accept invitation
41
43
 
42
44
  account_controller:
43
45
  update_user_action_notice: Account information properly updated
@@ -79,3 +81,9 @@ en:
79
81
  inclusion: not accepted
80
82
  accepted_terms_and_conditions_version:
81
83
  inclusion: not accepted
84
+ lato/invitation:
85
+ attributes:
86
+ base:
87
+ already_accepted: Invitation already accepted
88
+ email_sending_error: Unable to send mail
89
+ email_sending_limit: Wait at least 2 minutes to try a new invite attempt
@@ -38,8 +38,10 @@ it:
38
38
  signout_confirmation_request: "%{user}, Sei sicuro di voler uscire dal tuo account?"
39
39
  recover_password_code: Codice ricevuto via email
40
40
  operation_completed: Operazione completata
41
+ operation_failed: Operazione fallita
41
42
  privacy_policy_update_title: Aggiornamento privacy policy
42
43
  terms_and_conditions_update_title: Aggiornamento termini e condizioni
44
+ accept_invitation: Accetta invito
43
45
 
44
46
  account_controller:
45
47
  update_user_action_notice: Informazioni account aggiornate correttamente
@@ -76,6 +78,7 @@ it:
76
78
  password_update_code_invalid: Il codice di verifica non risulta valido
77
79
  privacy_policy_invalid: Per accettare la privacy policy devi selezionare la checkbox di conferma
78
80
  terms_and_conditions_invalid: Per accettare i termini e condizioni devi selezionare la checkbox di conferma
81
+ invitation_invalid: Invito non valido
79
82
  password:
80
83
  not_correct: non corretta
81
84
  password_confirmation:
@@ -88,6 +91,14 @@ it:
88
91
  inclusion: non accettata
89
92
  accepted_terms_and_conditions_version:
90
93
  inclusion: non accettati
94
+ lato/invitation:
95
+ attributes:
96
+ base:
97
+ already_accepted: Invito già accettato dall'utente
98
+ email_sending_error: Impossibile inviare mail
99
+ email_sending_limit: Attendi almeno 2 minuti per provare un nuovo tentativo di invito email
100
+
101
+
91
102
  date:
92
103
  abbr_day_names:
93
104
  - dom
data/config/routes.rb CHANGED
@@ -19,6 +19,8 @@ Lato::Engine.routes.draw do
19
19
  post 'recover_password_action', to: 'authentication#recover_password_action', as: :authentication_recover_password_action
20
20
  get 'update_password', to: 'authentication#update_password', as: :authentication_update_password
21
21
  patch 'update_password_action', to: 'authentication#update_password_action', as: :authentication_update_password_action
22
+ get 'accept_invitation', to: 'authentication#accept_invitation', as: :authentication_accept_invitation
23
+ post 'accept_invitation_action', to: 'authentication#accept_invitation_action', as: :authentication_accept_invitation_action
22
24
  end
23
25
 
24
26
  scope :account do
@@ -0,0 +1,10 @@
1
+ class CreateLatoLogUserSignins < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :lato_log_user_signins do |t|
4
+ t.string :ip_address
5
+ t.string :user_agent
6
+ t.references :lato_user, index: true, foreign_key: true
7
+ t.timestamps
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ class CreateLatoInvitations < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :lato_invitations do |t|
4
+ t.string :email
5
+ t.datetime :accepted_at
6
+ t.string :accepted_code
7
+ t.references :lato_user, index: true, foreign_key: true
8
+ t.timestamps
9
+ end
10
+ end
11
+ end
data/lib/lato/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Lato
2
- VERSION = "0.1.26"
2
+ VERSION = "0.1.28"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lato
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.26
4
+ version: 0.1.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregorio Galante
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-30 00:00:00.000000000 Z
11
+ date: 2023-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -130,9 +130,13 @@ files:
130
130
  - app/helpers/lato/components_helper.rb
131
131
  - app/jobs/lato/application_job.rb
132
132
  - app/mailers/lato/application_mailer.rb
133
+ - app/mailers/lato/invitation_mailer.rb
133
134
  - app/mailers/lato/user_mailer.rb
134
135
  - app/models/concerns/lato_user_application.rb
135
136
  - app/models/lato/application_record.rb
137
+ - app/models/lato/invitation.rb
138
+ - app/models/lato/log.rb
139
+ - app/models/lato/log/user_signin.rb
136
140
  - app/models/lato/operation.rb
137
141
  - app/models/lato/session.rb
138
142
  - app/models/lato/user.rb
@@ -142,11 +146,14 @@ files:
142
146
  - app/views/lato/account/_form-password.html.erb
143
147
  - app/views/lato/account/_form-user.html.erb
144
148
  - app/views/lato/account/index.html.erb
149
+ - app/views/lato/authentication/_fields-registration.html.erb
150
+ - app/views/lato/authentication/_form-accept-invitation.html.erb
145
151
  - app/views/lato/authentication/_form-recover-password.html.erb
146
152
  - app/views/lato/authentication/_form-signin.html.erb
147
153
  - app/views/lato/authentication/_form-signup.html.erb
148
154
  - app/views/lato/authentication/_form-update-password.html.erb
149
155
  - app/views/lato/authentication/_form-verify-email.html.erb
156
+ - app/views/lato/authentication/accept_invitation.html.erb
150
157
  - app/views/lato/authentication/recover_password.html.erb
151
158
  - app/views/lato/authentication/signin.html.erb
152
159
  - app/views/lato/authentication/signout.html.erb
@@ -159,6 +166,7 @@ files:
159
166
  - app/views/lato/components/_operation.html.erb
160
167
  - app/views/lato/components/_page_head.html.erb
161
168
  - app/views/lato/components/_sidebar_nav_item.html.erb
169
+ - app/views/lato/mailer/invitation/invite_mail.html.erb
162
170
  - app/views/lato/mailer/user/email_verification_mail.html.erb
163
171
  - app/views/lato/mailer/user/password_update_mail.html.erb
164
172
  - app/views/lato/operations/show.html.erb
@@ -183,6 +191,8 @@ files:
183
191
  - db/migrate/20221022205744_create_lato_users.rb
184
192
  - db/migrate/20221118072130_create_lato_operations.rb
185
193
  - db/migrate/20221229233844_add_locale_to_lato_user.rb
194
+ - db/migrate/20230109054412_create_lato_log_user_signins.rb
195
+ - db/migrate/20230109061533_create_lato_invitations.rb
186
196
  - lib/lato.rb
187
197
  - lib/lato/btstrap.rb
188
198
  - lib/lato/config.rb