lockify 0.1.0 → 0.1.1

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: 76ccb3952ec8db598291189dd3eeb1829d30a70bc898875c80f6fbf0ab92df29
4
- data.tar.gz: fff2724bd616d40bbc4c80401abd247e552ffd27aa0a6c474781a6182b07ca88
3
+ metadata.gz: 3774209347893e94e2c24afa116a1a68571a4b6b4d95cdc687fd5fae1fefcaf2
4
+ data.tar.gz: 6de1f0b5996ceff3e4d92208fb07c10701e7249e9f540eb6fada0716d2990c14
5
5
  SHA512:
6
- metadata.gz: 8d3d08d984ea634f0518a9f79a207a68aa3a66c9d8c0e71f8bdf27e7d56dcaec7011c28a1745335c119821b45d54628331b0810cc6c786f444e3695abf9b3744
7
- data.tar.gz: 3be69e2b3e0a9ae0e04b9399ac6e31332c1010418e6f04f26c4519ac28224fe3bddce761cdba1799f7a4f2c2c702c3e5c74d8e973890d67ba4ff529c5ae10a29
6
+ metadata.gz: 5ecb7a57ef9f67730ca3f773b40cd06720f1e507a6c88b3de9d5922f2e816db402be40044a3b8db84e505a094a858e3640050905e041e719d032250bb63279d7
7
+ data.tar.gz: 6159f071d115a51a99f999305747feb070bbcc7e45bfdb4c9b70ceb04e0b1575d4acfae46674ade259a9632d5c1a7b7e7275c32dfa91b6a5ee448e8765e266a4
@@ -23,17 +23,20 @@ class Users::ConfirmationsController < ApplicationController
23
23
  def show
24
24
  self.resource = User.find_by(confirmation_token: params[:confirmation_token])
25
25
 
26
- if resource&.confirmation_period_expired?
26
+ if resource.nil?
27
+ set_flash_message!(:alert, :invalid_token)
28
+ redirect_to new_user_confirmation_path
29
+ elsif resource.confirmed?
30
+ set_flash_message!(:notice, :already_confirmed)
31
+ redirect_to new_user_session_path
32
+ elsif resource.confirmation_period_expired?
27
33
  set_flash_message!(:alert, :expired)
28
34
  redirect_to new_user_confirmation_path
29
- elsif resource
35
+ else
30
36
  resource.confirm!
31
37
  sign_in(resource)
32
38
  set_flash_message!(:notice, :confirmed)
33
- redirect_to after_confirmation_path_for(:user, resource)
34
- else
35
- set_flash_message!(:alert, :invalid_token)
36
- redirect_to new_user_confirmation_path
39
+ redirect_to root_path
37
40
  end
38
41
  end
39
42
 
@@ -7,14 +7,14 @@ class Users::SessionsController < ApplicationController
7
7
  end
8
8
 
9
9
  def create
10
- self.resource = User.find_by(email: sign_in_params[:email]&.downcase)
10
+ self.resource = User.find_by(email: params[:email]&.downcase)
11
11
 
12
- if resource&.authenticate(sign_in_params[:password])
12
+ if resource&.authenticate(params[:password])
13
13
  if resource.valid_for_authentication?
14
14
  resource.failed_attempts = 0 if resource.respond_to?(:failed_attempts=)
15
15
  resource.save(validate: false) if resource.respond_to?(:failed_attempts)
16
16
 
17
- sign_in(resource, remember_me: sign_in_params[:remember_me] == '1')
17
+ sign_in(resource, remember_me: params[:remember_me] == '1')
18
18
  respond_with resource, location: after_sign_in_path_for(resource)
19
19
  else
20
20
  set_flash_message!(:alert, :unconfirmed) unless resource.confirmed?
@@ -37,10 +37,6 @@ class Users::SessionsController < ApplicationController
37
37
 
38
38
  protected
39
39
 
40
- def sign_in_params
41
- params.require(:user).permit(:email, :password, :remember_me)
42
- end
43
-
44
40
  def configure_sign_in_params
45
41
  # Override in application if needed
46
42
  end
@@ -22,7 +22,8 @@ module LockifyUser
22
22
  def confirmation_period_expired?
23
23
  return false unless respond_to?(:confirmation_sent_at)
24
24
  return false unless Lockify.confirm_within
25
- confirmation_sent_at && confirmation_sent_at.utc <= Lockify.confirm_within.ago
25
+ return false unless confirmation_sent_at
26
+ confirmation_sent_at.utc <= Lockify.confirm_within.ago
26
27
  end
27
28
 
28
29
  def confirm!
@@ -0,0 +1,36 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <style>
6
+ body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
7
+ .container { max-width: 600px; margin: 0 auto; padding: 20px; }
8
+ .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; text-align: center; border-radius: 8px 8px 0 0; }
9
+ .content { background: #f8f9fa; padding: 30px; border-radius: 0 0 8px 8px; }
10
+ .btn { display: inline-block; background: #667eea; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; margin: 20px 0; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div class="container">
15
+ <div class="header">
16
+ <h1>¡Bienvenido!</h1>
17
+ </div>
18
+ <div class="content">
19
+ <h2>Confirma tu cuenta</h2>
20
+ <p>Hola <strong><%= @user.email %></strong>,</p>
21
+ <p>Gracias por registrarte. Para completar tu registro, confirma tu cuenta haciendo clic en el siguiente enlace:</p>
22
+
23
+ <p style="text-align: center;">
24
+ <%= link_to "Confirmar mi cuenta", @confirmation_url, class: "btn" %>
25
+ </p>
26
+
27
+ <p>Si no puedes hacer clic en el botón, copia y pega este enlace en tu navegador:</p>
28
+ <p style="word-break: break-all; background: #e9ecef; padding: 10px; border-radius: 4px;">
29
+ <%= @confirmation_url %>
30
+ </p>
31
+
32
+ <p>Si no te registraste en nuestro sitio, puedes ignorar este email.</p>
33
+ </div>
34
+ </div>
35
+ </body>
36
+ </html>
@@ -0,0 +1,37 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <style>
6
+ body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
7
+ .container { max-width: 600px; margin: 0 auto; padding: 20px; }
8
+ .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; text-align: center; border-radius: 8px 8px 0 0; }
9
+ .content { background: #f8f9fa; padding: 30px; border-radius: 0 0 8px 8px; }
10
+ .btn { display: inline-block; background: #667eea; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; margin: 20px 0; }
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <div class="container">
15
+ <div class="header">
16
+ <h1>Restablecer Contraseña</h1>
17
+ </div>
18
+ <div class="content">
19
+ <h2>Solicitud de cambio de contraseña</h2>
20
+ <p>Hola <strong><%= @user.email %></strong>,</p>
21
+ <p>Recibimos una solicitud para restablecer tu contraseña. Haz clic en el siguiente enlace para crear una nueva:</p>
22
+
23
+ <p style="text-align: center;">
24
+ <%= link_to "Cambiar mi contraseña", @reset_password_url, class: "btn" %>
25
+ </p>
26
+
27
+ <p>Si no puedes hacer clic en el botón, copia y pega este enlace en tu navegador:</p>
28
+ <p style="word-break: break-all; background: #e9ecef; padding: 10px; border-radius: 4px;">
29
+ <%= @reset_password_url %>
30
+ </p>
31
+
32
+ <p><strong>Importante:</strong> Este enlace expirará en 6 horas por seguridad.</p>
33
+ <p>Si no solicitaste este cambio, puedes ignorar este email. Tu contraseña no será modificada.</p>
34
+ </div>
35
+ </div>
36
+ </body>
37
+ </html>
@@ -0,0 +1,142 @@
1
+ <div class="auth-container">
2
+ <div class="auth-card">
3
+ <div class="auth-header">
4
+ <h2>Reenviar Confirmación</h2>
5
+ <p class="auth-subtitle">¿No recibiste el email de confirmación?</p>
6
+ </div>
7
+
8
+ <%= form_with(model: User.new, as: :user, url: user_confirmation_path, local: true, class: "auth-form") do |f| %>
9
+ <div class="form-group">
10
+ <%= f.label :email, "Email", class: "form-label" %>
11
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-input" %>
12
+ </div>
13
+
14
+ <div class="form-actions">
15
+ <%= f.submit "Reenviar confirmación", class: "btn btn-primary" %>
16
+ </div>
17
+ <% end %>
18
+
19
+ <div class="auth-links">
20
+ <%= link_to "← Volver al inicio de sesión", new_user_session_path, class: "auth-link" %>
21
+ <%= link_to "¿No tienes cuenta? Regístrate", new_user_registration_path, class: "auth-link" %>
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ <style>
27
+ .auth-container {
28
+ min-height: 100vh;
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: center;
32
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
33
+ padding: 20px;
34
+ }
35
+
36
+ .auth-card {
37
+ background: white;
38
+ border-radius: 12px;
39
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
40
+ padding: 40px;
41
+ width: 100%;
42
+ max-width: 400px;
43
+ }
44
+
45
+ .auth-header {
46
+ text-align: center;
47
+ margin-bottom: 30px;
48
+ }
49
+
50
+ .auth-header h2 {
51
+ color: #2c3e50;
52
+ font-size: 28px;
53
+ font-weight: 600;
54
+ margin: 0 0 8px 0;
55
+ }
56
+
57
+ .auth-subtitle {
58
+ color: #64748b;
59
+ font-size: 14px;
60
+ margin: 0;
61
+ }
62
+
63
+ .auth-form {
64
+ width: 100%;
65
+ }
66
+
67
+ .form-group {
68
+ margin-bottom: 20px;
69
+ }
70
+
71
+ .form-label {
72
+ display: block;
73
+ color: #34495e;
74
+ font-weight: 500;
75
+ margin-bottom: 8px;
76
+ font-size: 14px;
77
+ }
78
+
79
+ .form-input {
80
+ width: 100%;
81
+ padding: 12px 16px;
82
+ border: 2px solid #e2e8f0;
83
+ border-radius: 8px;
84
+ font-size: 16px;
85
+ transition: border-color 0.3s ease;
86
+ box-sizing: border-box;
87
+ }
88
+
89
+ .form-input:focus {
90
+ outline: none;
91
+ border-color: #667eea;
92
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
93
+ }
94
+
95
+ .form-actions {
96
+ margin-top: 30px;
97
+ }
98
+
99
+ .btn {
100
+ display: inline-block;
101
+ padding: 12px 24px;
102
+ border: none;
103
+ border-radius: 8px;
104
+ font-size: 16px;
105
+ font-weight: 500;
106
+ text-decoration: none;
107
+ cursor: pointer;
108
+ transition: all 0.3s ease;
109
+ width: 100%;
110
+ text-align: center;
111
+ }
112
+
113
+ .btn-primary {
114
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
115
+ color: white;
116
+ }
117
+
118
+ .btn-primary:hover {
119
+ transform: translateY(-2px);
120
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
121
+ }
122
+
123
+ .auth-links {
124
+ text-align: center;
125
+ margin-top: 30px;
126
+ padding-top: 20px;
127
+ border-top: 1px solid #e2e8f0;
128
+ }
129
+
130
+ .auth-link {
131
+ display: block;
132
+ color: #667eea;
133
+ text-decoration: none;
134
+ font-size: 14px;
135
+ margin-bottom: 8px;
136
+ transition: color 0.3s ease;
137
+ }
138
+
139
+ .auth-link:hover {
140
+ color: #764ba2;
141
+ }
142
+ </style>
@@ -0,0 +1,191 @@
1
+ <div class="auth-container">
2
+ <div class="auth-card">
3
+ <div class="auth-header">
4
+ <h2>Cambiar Contraseña</h2>
5
+ <p class="auth-subtitle">Ingresa tu nueva contraseña</p>
6
+ </div>
7
+
8
+ <%= form_with(model: @user || User.new, as: :user, url: user_password_path, method: :patch, local: true, class: "auth-form") do |f| %>
9
+ <%= f.hidden_field :reset_password_token, value: params[:reset_password_token] %>
10
+
11
+ <% if @user&.errors&.any? %>
12
+ <div class="error-messages">
13
+ <h4><%= pluralize(@user.errors.count, "error") %> impidieron guardar:</h4>
14
+ <ul>
15
+ <% @user.errors.full_messages.each do |message| %>
16
+ <li><%= message %></li>
17
+ <% end %>
18
+ </ul>
19
+ </div>
20
+ <% end %>
21
+
22
+ <div class="form-group">
23
+ <%= f.label :password, "Nueva Contraseña", class: "form-label" %>
24
+ <small class="form-hint">(mínimo 6 caracteres)</small>
25
+ <%= f.password_field :password, autofocus: true, autocomplete: "new-password", class: "form-input" %>
26
+ </div>
27
+
28
+ <div class="form-group">
29
+ <%= f.label :password_confirmation, "Confirmar Nueva Contraseña", class: "form-label" %>
30
+ <%= f.password_field :password_confirmation, autocomplete: "new-password", class: "form-input" %>
31
+ </div>
32
+
33
+ <div class="form-actions">
34
+ <%= f.submit "Cambiar Contraseña", class: "btn btn-primary" %>
35
+ </div>
36
+ <% end %>
37
+
38
+ <div class="auth-links">
39
+ <%= link_to "← Volver al inicio de sesión", new_user_session_path, class: "auth-link" %>
40
+ </div>
41
+ </div>
42
+ </div>
43
+
44
+ <style>
45
+ .auth-container {
46
+ min-height: 100vh;
47
+ display: flex;
48
+ align-items: center;
49
+ justify-content: center;
50
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
51
+ padding: 20px;
52
+ }
53
+
54
+ .auth-card {
55
+ background: white;
56
+ border-radius: 12px;
57
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
58
+ padding: 40px;
59
+ width: 100%;
60
+ max-width: 400px;
61
+ }
62
+
63
+ .auth-header {
64
+ text-align: center;
65
+ margin-bottom: 30px;
66
+ }
67
+
68
+ .auth-header h2 {
69
+ color: #2c3e50;
70
+ font-size: 28px;
71
+ font-weight: 600;
72
+ margin: 0 0 8px 0;
73
+ }
74
+
75
+ .auth-subtitle {
76
+ color: #64748b;
77
+ font-size: 14px;
78
+ margin: 0;
79
+ }
80
+
81
+ .auth-form {
82
+ width: 100%;
83
+ }
84
+
85
+ .form-group {
86
+ margin-bottom: 20px;
87
+ }
88
+
89
+ .form-label {
90
+ display: block;
91
+ color: #34495e;
92
+ font-weight: 500;
93
+ margin-bottom: 8px;
94
+ font-size: 14px;
95
+ }
96
+
97
+ .form-hint {
98
+ display: block;
99
+ color: #64748b;
100
+ font-size: 12px;
101
+ margin-bottom: 4px;
102
+ }
103
+
104
+ .form-input {
105
+ width: 100%;
106
+ padding: 12px 16px;
107
+ border: 2px solid #e2e8f0;
108
+ border-radius: 8px;
109
+ font-size: 16px;
110
+ transition: border-color 0.3s ease;
111
+ box-sizing: border-box;
112
+ }
113
+
114
+ .form-input:focus {
115
+ outline: none;
116
+ border-color: #667eea;
117
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
118
+ }
119
+
120
+ .form-actions {
121
+ margin-top: 30px;
122
+ }
123
+
124
+ .btn {
125
+ display: inline-block;
126
+ padding: 12px 24px;
127
+ border: none;
128
+ border-radius: 8px;
129
+ font-size: 16px;
130
+ font-weight: 500;
131
+ text-decoration: none;
132
+ cursor: pointer;
133
+ transition: all 0.3s ease;
134
+ width: 100%;
135
+ text-align: center;
136
+ }
137
+
138
+ .btn-primary {
139
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
140
+ color: white;
141
+ }
142
+
143
+ .btn-primary:hover {
144
+ transform: translateY(-2px);
145
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
146
+ }
147
+
148
+ .auth-links {
149
+ text-align: center;
150
+ margin-top: 30px;
151
+ padding-top: 20px;
152
+ border-top: 1px solid #e2e8f0;
153
+ }
154
+
155
+ .auth-link {
156
+ display: block;
157
+ color: #667eea;
158
+ text-decoration: none;
159
+ font-size: 14px;
160
+ margin-bottom: 8px;
161
+ transition: color 0.3s ease;
162
+ }
163
+
164
+ .auth-link:hover {
165
+ color: #764ba2;
166
+ }
167
+
168
+ .error-messages {
169
+ background: #fee2e2;
170
+ border: 1px solid #fecaca;
171
+ border-radius: 8px;
172
+ padding: 16px;
173
+ margin-bottom: 20px;
174
+ }
175
+
176
+ .error-messages h4 {
177
+ color: #dc2626;
178
+ margin: 0 0 8px 0;
179
+ font-size: 14px;
180
+ }
181
+
182
+ .error-messages ul {
183
+ margin: 0;
184
+ padding-left: 20px;
185
+ }
186
+
187
+ .error-messages li {
188
+ color: #dc2626;
189
+ font-size: 14px;
190
+ }
191
+ </style>
@@ -0,0 +1,142 @@
1
+ <div class="auth-container">
2
+ <div class="auth-card">
3
+ <div class="auth-header">
4
+ <h2>¿Olvidaste tu contraseña?</h2>
5
+ <p class="auth-subtitle">Te enviaremos instrucciones para restablecerla</p>
6
+ </div>
7
+
8
+ <%= form_with(model: User.new, as: :user, url: user_password_path, local: true, class: "auth-form") do |f| %>
9
+ <div class="form-group">
10
+ <%= f.label :email, "Email", class: "form-label" %>
11
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-input" %>
12
+ </div>
13
+
14
+ <div class="form-actions">
15
+ <%= f.submit "Enviar instrucciones", class: "btn btn-primary" %>
16
+ </div>
17
+ <% end %>
18
+
19
+ <div class="auth-links">
20
+ <%= link_to "← Volver al inicio de sesión", new_user_session_path, class: "auth-link" %>
21
+ <%= link_to "¿No tienes cuenta? Regístrate", new_user_registration_path, class: "auth-link" %>
22
+ </div>
23
+ </div>
24
+ </div>
25
+
26
+ <style>
27
+ .auth-container {
28
+ min-height: 100vh;
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: center;
32
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
33
+ padding: 20px;
34
+ }
35
+
36
+ .auth-card {
37
+ background: white;
38
+ border-radius: 12px;
39
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
40
+ padding: 40px;
41
+ width: 100%;
42
+ max-width: 400px;
43
+ }
44
+
45
+ .auth-header {
46
+ text-align: center;
47
+ margin-bottom: 30px;
48
+ }
49
+
50
+ .auth-header h2 {
51
+ color: #2c3e50;
52
+ font-size: 28px;
53
+ font-weight: 600;
54
+ margin: 0 0 8px 0;
55
+ }
56
+
57
+ .auth-subtitle {
58
+ color: #64748b;
59
+ font-size: 14px;
60
+ margin: 0;
61
+ }
62
+
63
+ .auth-form {
64
+ width: 100%;
65
+ }
66
+
67
+ .form-group {
68
+ margin-bottom: 20px;
69
+ }
70
+
71
+ .form-label {
72
+ display: block;
73
+ color: #34495e;
74
+ font-weight: 500;
75
+ margin-bottom: 8px;
76
+ font-size: 14px;
77
+ }
78
+
79
+ .form-input {
80
+ width: 100%;
81
+ padding: 12px 16px;
82
+ border: 2px solid #e2e8f0;
83
+ border-radius: 8px;
84
+ font-size: 16px;
85
+ transition: border-color 0.3s ease;
86
+ box-sizing: border-box;
87
+ }
88
+
89
+ .form-input:focus {
90
+ outline: none;
91
+ border-color: #667eea;
92
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
93
+ }
94
+
95
+ .form-actions {
96
+ margin-top: 30px;
97
+ }
98
+
99
+ .btn {
100
+ display: inline-block;
101
+ padding: 12px 24px;
102
+ border: none;
103
+ border-radius: 8px;
104
+ font-size: 16px;
105
+ font-weight: 500;
106
+ text-decoration: none;
107
+ cursor: pointer;
108
+ transition: all 0.3s ease;
109
+ width: 100%;
110
+ text-align: center;
111
+ }
112
+
113
+ .btn-primary {
114
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
115
+ color: white;
116
+ }
117
+
118
+ .btn-primary:hover {
119
+ transform: translateY(-2px);
120
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
121
+ }
122
+
123
+ .auth-links {
124
+ text-align: center;
125
+ margin-top: 30px;
126
+ padding-top: 20px;
127
+ border-top: 1px solid #e2e8f0;
128
+ }
129
+
130
+ .auth-link {
131
+ display: block;
132
+ color: #667eea;
133
+ text-decoration: none;
134
+ font-size: 14px;
135
+ margin-bottom: 8px;
136
+ transition: color 0.3s ease;
137
+ }
138
+
139
+ .auth-link:hover {
140
+ color: #764ba2;
141
+ }
142
+ </style>
@@ -0,0 +1,193 @@
1
+ <div class="auth-container">
2
+ <div class="auth-card">
3
+ <div class="auth-header">
4
+ <h2>Editar Perfil</h2>
5
+ </div>
6
+
7
+ <%= form_with(model: current_user, as: :user, url: user_registration_path, method: :patch, local: true, class: "auth-form") do |f| %>
8
+ <% if current_user.errors.any? %>
9
+ <div class="error-messages">
10
+ <h4><%= pluralize(current_user.errors.count, "error") %> impidieron guardar:</h4>
11
+ <ul>
12
+ <% current_user.errors.full_messages.each do |message| %>
13
+ <li><%= message %></li>
14
+ <% end %>
15
+ </ul>
16
+ </div>
17
+ <% end %>
18
+
19
+ <div class="form-group">
20
+ <%= f.label :email, "Email", class: "form-label" %>
21
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-input" %>
22
+ </div>
23
+
24
+ <div class="form-group">
25
+ <%= f.label :password, "Nueva Contraseña", class: "form-label" %>
26
+ <small class="form-hint">(déjalo en blanco si no quieres cambiarlo)</small>
27
+ <%= f.password_field :password, autocomplete: "new-password", class: "form-input" %>
28
+ </div>
29
+
30
+ <div class="form-group">
31
+ <%= f.label :password_confirmation, "Confirmar Nueva Contraseña", class: "form-label" %>
32
+ <%= f.password_field :password_confirmation, autocomplete: "new-password", class: "form-input" %>
33
+ </div>
34
+
35
+ <div class="form-group">
36
+ <%= f.label :current_password, "Contraseña Actual", class: "form-label" %>
37
+ <small class="form-hint">(necesaria para confirmar cambios)</small>
38
+ <%= f.password_field :current_password, autocomplete: "current-password", class: "form-input" %>
39
+ </div>
40
+
41
+ <div class="form-actions">
42
+ <%= f.submit "Actualizar", class: "btn btn-primary" %>
43
+ </div>
44
+ <% end %>
45
+
46
+ <div class="auth-links">
47
+ <%= link_to "← Volver", root_path, class: "auth-link" %>
48
+ </div>
49
+ </div>
50
+ </div>
51
+
52
+ <style>
53
+ .auth-container {
54
+ min-height: 100vh;
55
+ display: flex;
56
+ align-items: center;
57
+ justify-content: center;
58
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
59
+ padding: 20px;
60
+ }
61
+
62
+ .auth-card {
63
+ background: white;
64
+ border-radius: 12px;
65
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
66
+ padding: 40px;
67
+ width: 100%;
68
+ max-width: 400px;
69
+ }
70
+
71
+ .auth-header {
72
+ text-align: center;
73
+ margin-bottom: 30px;
74
+ }
75
+
76
+ .auth-header h2 {
77
+ color: #2c3e50;
78
+ font-size: 28px;
79
+ font-weight: 600;
80
+ margin: 0;
81
+ }
82
+
83
+ .auth-form {
84
+ width: 100%;
85
+ }
86
+
87
+ .form-group {
88
+ margin-bottom: 20px;
89
+ }
90
+
91
+ .form-label {
92
+ display: block;
93
+ color: #34495e;
94
+ font-weight: 500;
95
+ margin-bottom: 8px;
96
+ font-size: 14px;
97
+ }
98
+
99
+ .form-hint {
100
+ display: block;
101
+ color: #64748b;
102
+ font-size: 12px;
103
+ margin-bottom: 4px;
104
+ }
105
+
106
+ .form-input {
107
+ width: 100%;
108
+ padding: 12px 16px;
109
+ border: 2px solid #e2e8f0;
110
+ border-radius: 8px;
111
+ font-size: 16px;
112
+ transition: border-color 0.3s ease;
113
+ box-sizing: border-box;
114
+ }
115
+
116
+ .form-input:focus {
117
+ outline: none;
118
+ border-color: #667eea;
119
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
120
+ }
121
+
122
+ .form-actions {
123
+ margin-top: 30px;
124
+ }
125
+
126
+ .btn {
127
+ display: inline-block;
128
+ padding: 12px 24px;
129
+ border: none;
130
+ border-radius: 8px;
131
+ font-size: 16px;
132
+ font-weight: 500;
133
+ text-decoration: none;
134
+ cursor: pointer;
135
+ transition: all 0.3s ease;
136
+ width: 100%;
137
+ text-align: center;
138
+ }
139
+
140
+ .btn-primary {
141
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
142
+ color: white;
143
+ }
144
+
145
+ .btn-primary:hover {
146
+ transform: translateY(-2px);
147
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
148
+ }
149
+
150
+ .auth-links {
151
+ text-align: center;
152
+ margin-top: 30px;
153
+ padding-top: 20px;
154
+ border-top: 1px solid #e2e8f0;
155
+ }
156
+
157
+ .auth-link {
158
+ display: block;
159
+ color: #667eea;
160
+ text-decoration: none;
161
+ font-size: 14px;
162
+ margin-bottom: 8px;
163
+ transition: color 0.3s ease;
164
+ }
165
+
166
+ .auth-link:hover {
167
+ color: #764ba2;
168
+ }
169
+
170
+ .error-messages {
171
+ background: #fee2e2;
172
+ border: 1px solid #fecaca;
173
+ border-radius: 8px;
174
+ padding: 16px;
175
+ margin-bottom: 20px;
176
+ }
177
+
178
+ .error-messages h4 {
179
+ color: #dc2626;
180
+ margin: 0 0 8px 0;
181
+ font-size: 14px;
182
+ }
183
+
184
+ .error-messages ul {
185
+ margin: 0;
186
+ padding-left: 20px;
187
+ }
188
+
189
+ .error-messages li {
190
+ color: #dc2626;
191
+ font-size: 14px;
192
+ }
193
+ </style>
@@ -0,0 +1,187 @@
1
+ <div class="auth-container">
2
+ <div class="auth-card">
3
+ <div class="auth-header">
4
+ <h2>Crear Cuenta</h2>
5
+ </div>
6
+
7
+ <%= form_with(model: User.new, as: :user, url: user_registration_path, local: true, class: "auth-form") do |f| %>
8
+ <% if @user&.errors&.any? %>
9
+ <div class="error-messages">
10
+ <h4><%= pluralize(@user.errors.count, "error") %> impidieron guardar:</h4>
11
+ <ul>
12
+ <% @user.errors.full_messages.each do |message| %>
13
+ <li><%= message %></li>
14
+ <% end %>
15
+ </ul>
16
+ </div>
17
+ <% end %>
18
+
19
+ <div class="form-group">
20
+ <%= f.label :email, "Email", class: "form-label" %>
21
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-input" %>
22
+ </div>
23
+
24
+ <div class="form-group">
25
+ <%= f.label :password, "Contraseña", class: "form-label" %>
26
+ <small class="form-hint">(mínimo 6 caracteres)</small>
27
+ <%= f.password_field :password, autocomplete: "new-password", class: "form-input" %>
28
+ </div>
29
+
30
+ <div class="form-group">
31
+ <%= f.label :password_confirmation, "Confirmar Contraseña", class: "form-label" %>
32
+ <%= f.password_field :password_confirmation, autocomplete: "new-password", class: "form-input" %>
33
+ </div>
34
+
35
+ <div class="form-actions">
36
+ <%= f.submit "Crear Cuenta", class: "btn btn-primary" %>
37
+ </div>
38
+ <% end %>
39
+
40
+ <div class="auth-links">
41
+ <%= link_to "¿Ya tienes cuenta? Inicia sesión", new_user_session_path, class: "auth-link" %>
42
+ </div>
43
+ </div>
44
+ </div>
45
+
46
+ <style>
47
+ .auth-container {
48
+ min-height: 100vh;
49
+ display: flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
53
+ padding: 20px;
54
+ }
55
+
56
+ .auth-card {
57
+ background: white;
58
+ border-radius: 12px;
59
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
60
+ padding: 40px;
61
+ width: 100%;
62
+ max-width: 400px;
63
+ }
64
+
65
+ .auth-header {
66
+ text-align: center;
67
+ margin-bottom: 30px;
68
+ }
69
+
70
+ .auth-header h2 {
71
+ color: #2c3e50;
72
+ font-size: 28px;
73
+ font-weight: 600;
74
+ margin: 0;
75
+ }
76
+
77
+ .auth-form {
78
+ width: 100%;
79
+ }
80
+
81
+ .form-group {
82
+ margin-bottom: 20px;
83
+ }
84
+
85
+ .form-label {
86
+ display: block;
87
+ color: #34495e;
88
+ font-weight: 500;
89
+ margin-bottom: 8px;
90
+ font-size: 14px;
91
+ }
92
+
93
+ .form-hint {
94
+ display: block;
95
+ color: #64748b;
96
+ font-size: 12px;
97
+ margin-bottom: 4px;
98
+ }
99
+
100
+ .form-input {
101
+ width: 100%;
102
+ padding: 12px 16px;
103
+ border: 2px solid #e2e8f0;
104
+ border-radius: 8px;
105
+ font-size: 16px;
106
+ transition: border-color 0.3s ease;
107
+ box-sizing: border-box;
108
+ }
109
+
110
+ .form-input:focus {
111
+ outline: none;
112
+ border-color: #667eea;
113
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
114
+ }
115
+
116
+ .form-actions {
117
+ margin-top: 30px;
118
+ }
119
+
120
+ .btn {
121
+ display: inline-block;
122
+ padding: 12px 24px;
123
+ border: none;
124
+ border-radius: 8px;
125
+ font-size: 16px;
126
+ font-weight: 500;
127
+ text-decoration: none;
128
+ cursor: pointer;
129
+ transition: all 0.3s ease;
130
+ width: 100%;
131
+ text-align: center;
132
+ }
133
+
134
+ .btn-primary {
135
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
136
+ color: white;
137
+ }
138
+
139
+ .btn-primary:hover {
140
+ transform: translateY(-2px);
141
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
142
+ }
143
+
144
+ .auth-links {
145
+ text-align: center;
146
+ margin-top: 30px;
147
+ padding-top: 20px;
148
+ border-top: 1px solid #e2e8f0;
149
+ }
150
+
151
+ .auth-link {
152
+ display: block;
153
+ color: #667eea;
154
+ text-decoration: none;
155
+ font-size: 14px;
156
+ margin-bottom: 8px;
157
+ transition: color 0.3s ease;
158
+ }
159
+
160
+ .auth-link:hover {
161
+ color: #764ba2;
162
+ }
163
+
164
+ .error-messages {
165
+ background: #fee2e2;
166
+ border: 1px solid #fecaca;
167
+ border-radius: 8px;
168
+ padding: 16px;
169
+ margin-bottom: 20px;
170
+ }
171
+
172
+ .error-messages h4 {
173
+ color: #dc2626;
174
+ margin: 0 0 8px 0;
175
+ font-size: 14px;
176
+ }
177
+
178
+ .error-messages ul {
179
+ margin: 0;
180
+ padding-left: 20px;
181
+ }
182
+
183
+ .error-messages li {
184
+ color: #dc2626;
185
+ font-size: 14px;
186
+ }
187
+ </style>
@@ -0,0 +1,162 @@
1
+ <div class="auth-container">
2
+ <div class="auth-card">
3
+ <div class="auth-header">
4
+ <h2>Iniciar Sesión</h2>
5
+ </div>
6
+
7
+ <%= form_with(url: user_session_path, local: true, class: "auth-form") do |f| %>
8
+ <div class="form-group">
9
+ <%= f.label :email, "Email", class: "form-label" %>
10
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", class: "form-input" %>
11
+ </div>
12
+
13
+ <div class="form-group">
14
+ <%= f.label :password, "Contraseña", class: "form-label" %>
15
+ <%= f.password_field :password, autocomplete: "current-password", class: "form-input" %>
16
+ </div>
17
+
18
+ <div class="form-group checkbox-group">
19
+ <%= f.check_box :remember_me, class: "form-checkbox" %>
20
+ <%= f.label :remember_me, "Recordarme", class: "checkbox-label" %>
21
+ </div>
22
+
23
+ <div class="form-actions">
24
+ <%= f.submit "Iniciar Sesión", class: "btn btn-primary" %>
25
+ </div>
26
+ <% end %>
27
+
28
+ <div class="auth-links">
29
+ <%= link_to "¿No tienes cuenta? Regístrate", new_user_registration_path, class: "auth-link" %>
30
+ <%= link_to "¿Olvidaste tu contraseña?", new_user_password_path, class: "auth-link" %>
31
+ </div>
32
+ </div>
33
+ </div>
34
+
35
+ <style>
36
+ .auth-container {
37
+ min-height: 100vh;
38
+ display: flex;
39
+ align-items: center;
40
+ justify-content: center;
41
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
42
+ padding: 20px;
43
+ }
44
+
45
+ .auth-card {
46
+ background: white;
47
+ border-radius: 12px;
48
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
49
+ padding: 40px;
50
+ width: 100%;
51
+ max-width: 400px;
52
+ }
53
+
54
+ .auth-header {
55
+ text-align: center;
56
+ margin-bottom: 30px;
57
+ }
58
+
59
+ .auth-header h2 {
60
+ color: #2c3e50;
61
+ font-size: 28px;
62
+ font-weight: 600;
63
+ margin: 0;
64
+ }
65
+
66
+ .auth-form {
67
+ width: 100%;
68
+ }
69
+
70
+ .form-group {
71
+ margin-bottom: 20px;
72
+ }
73
+
74
+ .form-label {
75
+ display: block;
76
+ color: #34495e;
77
+ font-weight: 500;
78
+ margin-bottom: 8px;
79
+ font-size: 14px;
80
+ }
81
+
82
+ .form-input {
83
+ width: 100%;
84
+ padding: 12px 16px;
85
+ border: 2px solid #e2e8f0;
86
+ border-radius: 8px;
87
+ font-size: 16px;
88
+ transition: border-color 0.3s ease;
89
+ box-sizing: border-box;
90
+ }
91
+
92
+ .form-input:focus {
93
+ outline: none;
94
+ border-color: #667eea;
95
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
96
+ }
97
+
98
+ .checkbox-group {
99
+ display: flex;
100
+ align-items: center;
101
+ gap: 8px;
102
+ }
103
+
104
+ .form-checkbox {
105
+ width: auto;
106
+ margin: 0;
107
+ }
108
+
109
+ .checkbox-label {
110
+ margin: 0;
111
+ color: #64748b;
112
+ font-size: 14px;
113
+ }
114
+
115
+ .form-actions {
116
+ margin-top: 30px;
117
+ }
118
+
119
+ .btn {
120
+ display: inline-block;
121
+ padding: 12px 24px;
122
+ border: none;
123
+ border-radius: 8px;
124
+ font-size: 16px;
125
+ font-weight: 500;
126
+ text-decoration: none;
127
+ cursor: pointer;
128
+ transition: all 0.3s ease;
129
+ width: 100%;
130
+ text-align: center;
131
+ }
132
+
133
+ .btn-primary {
134
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
135
+ color: white;
136
+ }
137
+
138
+ .btn-primary:hover {
139
+ transform: translateY(-2px);
140
+ box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
141
+ }
142
+
143
+ .auth-links {
144
+ text-align: center;
145
+ margin-top: 30px;
146
+ padding-top: 20px;
147
+ border-top: 1px solid #e2e8f0;
148
+ }
149
+
150
+ .auth-link {
151
+ display: block;
152
+ color: #667eea;
153
+ text-decoration: none;
154
+ font-size: 14px;
155
+ margin-bottom: 8px;
156
+ transition: color 0.3s ease;
157
+ }
158
+
159
+ .auth-link:hover {
160
+ color: #764ba2;
161
+ }
162
+ </style>
data/config/routes.rb CHANGED
@@ -1,28 +1,2 @@
1
- Rails.application.routes.draw do
2
- devise_scope :user do
3
- # Sessions
4
- get '/users/sign_in', to: 'users/sessions#new', as: :new_user_session
5
- post '/users/sign_in', to: 'users/sessions#create', as: :user_session
6
- delete '/users/sign_out', to: 'users/sessions#destroy', as: :destroy_user_session
7
-
8
- # Registrations
9
- get '/users/sign_up', to: 'users/registrations#new', as: :new_user_registration
10
- post '/users', to: 'users/registrations#create', as: :user_registration
11
- get '/users/edit', to: 'users/registrations#edit', as: :edit_user_registration
12
- patch '/users', to: 'users/registrations#update'
13
- put '/users', to: 'users/registrations#update'
14
- delete '/users', to: 'users/registrations#destroy'
15
-
16
- # Passwords
17
- get '/users/password/new', to: 'users/passwords#new', as: :new_user_password
18
- post '/users/password', to: 'users/passwords#create', as: :user_password
19
- get '/users/password/edit', to: 'users/passwords#edit', as: :edit_user_password
20
- patch '/users/password', to: 'users/passwords#update'
21
- put '/users/password', to: 'users/passwords#update'
22
-
23
- # Confirmations
24
- get '/users/confirmation/new', to: 'users/confirmations#new', as: :new_user_confirmation
25
- post '/users/confirmation', to: 'users/confirmations#create', as: :user_confirmation
26
- get '/users/confirmation', to: 'users/confirmations#show'
27
- end
28
- end
1
+ # Rutas agregadas automáticamente por Lockify engine
2
+ # No necesitas agregar nada aquí
@@ -1,15 +1,13 @@
1
1
  require 'rails/generators'
2
- require 'rails/generators/active_record'
3
2
 
4
3
  module Lockify
5
4
  module Generators
6
5
  class InstallGenerator < Rails::Generators::Base
7
- include ActiveRecord::Generators::Migration
8
-
9
6
  source_root File.expand_path('templates', __dir__)
10
7
 
11
8
  def create_migration
12
- migration_template "migration.rb", "db/migrate/add_lockify_to_users.rb"
9
+ timestamp = Time.current.strftime("%Y%m%d%H%M%S")
10
+ create_file "db/migrate/#{timestamp}_add_lockify_to_users.rb", migration_content
13
11
  end
14
12
 
15
13
  def add_lockify_to_user_model
@@ -90,6 +88,10 @@ module Lockify
90
88
  def readme(path)
91
89
  say File.read(File.join(File.dirname(__FILE__), "templates", path))
92
90
  end
91
+
92
+ def migration_content
93
+ File.read(File.join(File.dirname(__FILE__), "templates", "migration.rb"))
94
+ end
93
95
  end
94
96
  end
95
97
  end
@@ -1,4 +1,4 @@
1
- class AddLockifyToUsers < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
1
+ class AddLockifyToUsers < ActiveRecord::Migration[8.0]
2
2
  def change
3
3
  # Rename encrypted_password to password_digest if it exists
4
4
  if column_exists?(:users, :encrypted_password)
@@ -23,6 +23,7 @@ module Lockify
23
23
  get '/users/sign_up', to: 'users/registrations#new', as: :new_user_registration
24
24
  post '/users', to: 'users/registrations#create', as: :user_registration
25
25
  get '/users/edit', to: 'users/registrations#edit', as: :edit_user_registration
26
+ get '/users', to: 'users/registrations#show'
26
27
  patch '/users', to: 'users/registrations#update'
27
28
  put '/users', to: 'users/registrations#update'
28
29
  delete '/users', to: 'users/registrations#destroy'
@@ -1,3 +1,3 @@
1
1
  module Lockify
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
- - Liz
7
+ - Govani G. Sanchez Orduña
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
@@ -74,6 +74,14 @@ files:
74
74
  - app/views/lockify/sessions/new.html.erb
75
75
  - app/views/lockify/shared/_error_messages.html.erb
76
76
  - app/views/lockify/shared/_links.html.erb
77
+ - app/views/user_mailer/confirmation_instructions.html.erb
78
+ - app/views/user_mailer/reset_password_instructions.html.erb
79
+ - app/views/users/confirmations/new.html.erb
80
+ - app/views/users/passwords/edit.html.erb
81
+ - app/views/users/passwords/new.html.erb
82
+ - app/views/users/registrations/edit.html.erb
83
+ - app/views/users/registrations/new.html.erb
84
+ - app/views/users/sessions/new.html.erb
77
85
  - config/locales/en.yml
78
86
  - config/locales/es.yml
79
87
  - config/routes.rb