pg_rails 7.0.8.pre.alpha.51 → 7.0.8.pre.alpha.53
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/pg_engine/app/controllers/admin/users_controller.rb +7 -3
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +20 -14
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +3 -3
- data/pg_engine/app/controllers/public/mensaje_contactos_controller.rb +4 -0
- data/pg_engine/app/controllers/users/registrations_controller.rb +1 -3
- data/pg_engine/app/decorators/pg_engine/base_decorator.rb +8 -3
- data/pg_engine/app/helpers/pg_engine/index_helper.rb +2 -0
- data/pg_engine/app/models/pg_engine/base_record.rb +13 -0
- data/pg_engine/app/policies/user_policy.rb +15 -3
- data/pg_engine/app/policies/user_registration_policy.rb +26 -0
- data/pg_engine/app/views/admin/accounts/show.html.slim +1 -1
- data/pg_engine/app/views/admin/user_accounts/show.html.slim +1 -1
- data/pg_engine/app/views/admin/users/show.html.slim +5 -1
- data/pg_engine/app/views/public/mensaje_contactos/new.html.slim +21 -0
- data/pg_engine/config/initializers/active_admin.rb +7 -1
- data/pg_engine/config/initializers/devise.rb +2 -2
- data/pg_engine/config/locales/es.yml +4 -1
- data/pg_engine/config/simple_form/simple_form_bootstrap.rb +1 -1
- data/pg_engine/spec/controllers/admin/accounts_controller_spec.rb +14 -3
- data/pg_engine/spec/controllers/admin/user_accounts_controller_spec.rb +14 -3
- data/pg_engine/spec/controllers/admin/users_controller_spec.rb +14 -3
- data/pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb +31 -6
- data/pg_engine/spec/controllers/pg_engine/base_controller_spec.rb +2 -2
- data/pg_engine/spec/features/destroy_spec.rb +72 -0
- data/pg_engine/spec/features/login_spec.rb +41 -0
- data/pg_engine/spec/features/signup_spec.rb +78 -0
- data/pg_layout/app/javascript/controllers/navbar_controller.js +9 -0
- data/pg_layout/app/views/devise/registrations/new.html.erb +0 -6
- data/pg_layout/app/views/devise/sessions/new.html.erb +0 -7
- data/pg_layout/app/views/layouts/pg_layout/container_logo.html.slim +10 -0
- data/pg_layout/app/views/layouts/pg_layout/devise.html.slim +3 -3
- data/pg_layout/app/views/pg_layout/_navbar.html.erb +9 -3
- data/pg_layout/app/views/pg_layout/_sidebar.html.erb +4 -1
- data/pg_layout/app/views/pg_layout/_sidebar_mobile.html.erb +1 -1
- data/pg_rails/lib/version.rb +1 -1
- data/pg_scaffold/lib/generators/pg_rspec/scaffold/templates/controller_spec.rb +14 -7
- data/pg_scaffold/lib/generators/pg_slim/templates/show.html.slim +1 -1
- metadata +8 -3
- data/pg_engine/app/views/public/mensaje_contactos/_form.html.slim +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc65c537b0f07c6659a716cf31aca506a9da7d7ee43f6bbaa425a756864875ef
|
4
|
+
data.tar.gz: ba019b72eb7fac96fc364396da6890040a86b7743e2532e73c677a20809c546d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46fe858cbdfde69a00935a3e92aa2524729a030217629556a3f4a6717b7f873c80ccf72fee9698f0599b0b7768ddd27b392273b01685eb556c46c236a1eb1450
|
7
|
+
data.tar.gz: 3be35c7a9db5507e1c84f62e3b405772986ffb3fd63a09b5a93f5fd54128fca897da7f707437e66556a5aee9f6d26bfe639bdf51dceac99f210730cfd089134d
|
@@ -32,11 +32,15 @@ module Admin
|
|
32
32
|
|
33
33
|
# :nocov:
|
34
34
|
def login_as
|
35
|
-
|
36
|
-
|
35
|
+
return unless dev_user_or_env?
|
36
|
+
|
37
|
+
usuario = User.find(params[:id])
|
38
|
+
if usuario.confirmed_at.present?
|
37
39
|
sign_in(:user, usuario)
|
40
|
+
redirect_to after_sign_in_path_for(usuario)
|
41
|
+
else
|
42
|
+
go_back('No está confirmado')
|
38
43
|
end
|
39
|
-
redirect_to after_sign_in_path_for(usuario)
|
40
44
|
end
|
41
45
|
# :nocov:
|
42
46
|
|
@@ -49,8 +49,7 @@ module PgEngine
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def destroy
|
52
|
-
|
53
|
-
pg_respond_destroy(instancia_modelo, url)
|
52
|
+
pg_respond_destroy(instancia_modelo, params[:redirect_to])
|
54
53
|
end
|
55
54
|
# End public endpoints
|
56
55
|
|
@@ -150,15 +149,21 @@ module PgEngine
|
|
150
149
|
|
151
150
|
def pg_respond_destroy(model, redirect_url = nil)
|
152
151
|
if destroy_model(model)
|
152
|
+
msg = "#{model.model_name.human} #{model.gender == 'f' ? 'borrada' : 'borrado'}"
|
153
153
|
respond_to do |format|
|
154
|
-
|
155
|
-
|
156
|
-
redirect_to redirect_url, notice:
|
157
|
-
|
158
|
-
|
154
|
+
if redirect_url.present?
|
155
|
+
format.html do
|
156
|
+
redirect_to redirect_url, notice: msg, status: :see_other
|
157
|
+
end
|
158
|
+
else
|
159
|
+
format.turbo_stream do
|
160
|
+
render turbo_stream: turbo_stream.remove(model)
|
161
|
+
end
|
162
|
+
format.html do
|
163
|
+
redirect_back(fallback_location: root_path, notice: msg, status: 303)
|
159
164
|
end
|
165
|
+
format.json { head :no_content }
|
160
166
|
end
|
161
|
-
format.json { head :no_content }
|
162
167
|
end
|
163
168
|
else
|
164
169
|
respond_to do |format|
|
@@ -168,11 +173,7 @@ module PgEngine
|
|
168
173
|
render destroy_error_details_view
|
169
174
|
else
|
170
175
|
flash[:alert] = @error_message
|
171
|
-
# if redirect_url.present?
|
172
|
-
# redirect_to redirect_url
|
173
|
-
# else
|
174
176
|
redirect_back(fallback_location: root_path, status: 303)
|
175
|
-
# end
|
176
177
|
end
|
177
178
|
end
|
178
179
|
format.json { render json: { error: @error_message }, status: :unprocessable_entity }
|
@@ -273,7 +274,8 @@ module PgEngine
|
|
273
274
|
|
274
275
|
def do_sort(scope, field, direction)
|
275
276
|
# TODO: restringir ciertos campos?
|
276
|
-
unless scope.model.column_names.include?
|
277
|
+
unless scope.model.column_names.include?(field.to_s) ||
|
278
|
+
scope.model.respond_to?("order_by_#{field}")
|
277
279
|
PgLogger.warn("No existe el campo \"#{field}\"", :warn)
|
278
280
|
return scope
|
279
281
|
end
|
@@ -281,7 +283,11 @@ module PgEngine
|
|
281
283
|
PgLogger.warn("Direction not valid: \"#{direction}\"", :warn)
|
282
284
|
return scope
|
283
285
|
end
|
284
|
-
scope = scope.
|
286
|
+
scope = if scope.model.respond_to? "order_by_#{field}"
|
287
|
+
scope.send "order_by_#{field}", direction
|
288
|
+
else
|
289
|
+
scope.order(field => direction)
|
290
|
+
end
|
285
291
|
instance_variable_set(:@field, field)
|
286
292
|
instance_variable_set(:@direction, direction)
|
287
293
|
scope
|
@@ -99,16 +99,16 @@ module PgEngine
|
|
99
99
|
def not_authorized
|
100
100
|
respond_to do |format|
|
101
101
|
format.json do
|
102
|
-
render json: { error: '
|
102
|
+
render json: { error: 'Acceso no autorizado' },
|
103
103
|
status: :unprocessable_entity
|
104
104
|
end
|
105
105
|
format.html do
|
106
106
|
if request.path == root_path
|
107
107
|
# TODO!: renderear un 500.html y pg_err
|
108
108
|
sign_out(Current.user) if Current.user.present?
|
109
|
-
render plain: '
|
109
|
+
render plain: 'Acceso no autorizado'
|
110
110
|
else
|
111
|
-
go_back('
|
111
|
+
go_back('Acceso no autorizado')
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
@@ -12,6 +12,10 @@ module Public
|
|
12
12
|
|
13
13
|
before_action :set_instancia_modelo, only: %i[new create]
|
14
14
|
|
15
|
+
layout 'pg_layout/container_logo'
|
16
|
+
|
17
|
+
def new; end
|
18
|
+
|
15
19
|
def create
|
16
20
|
if @mensaje_contacto.save
|
17
21
|
render turbo_stream: turbo_stream.update('mensaje_contacto', partial: 'gracias')
|
@@ -31,12 +31,17 @@ module PgEngine
|
|
31
31
|
end
|
32
32
|
# rubocop:enable Style/MissingRespondToMissing
|
33
33
|
|
34
|
-
def
|
34
|
+
def destroy_link_redirect
|
35
|
+
destroy_link(redirect_to: helpers.url_for(target_index))
|
36
|
+
end
|
37
|
+
|
38
|
+
def destroy_link(confirm_text: '¿Estás seguro?', klass: 'btn-light', redirect_to: nil)
|
35
39
|
return unless Pundit.policy!(Current.user, object).destroy?
|
36
40
|
|
37
41
|
helpers.content_tag :span, rel: :tooltip, title: 'Eliminar' do
|
38
|
-
helpers.link_to object_url
|
39
|
-
|
42
|
+
helpers.link_to object_url + (redirect_to.present? ? "?redirect_to=#{redirect_to}" : ''),
|
43
|
+
data: { 'turbo-confirm': confirm_text, 'turbo-method': :delete },
|
44
|
+
class: "btn btn-sm #{klass}" do
|
40
45
|
helpers.content_tag :span, nil, class: clase_icono('trash-fill')
|
41
46
|
end
|
42
47
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module PgEngine
|
4
4
|
module IndexHelper
|
5
5
|
def encabezado(campo, options = {})
|
6
|
+
campo = campo.to_s.sub(/_f\z/, '')
|
7
|
+
campo = campo.to_s.sub(/_text\z/, '')
|
6
8
|
clase = options[:clase] || @clase_modelo
|
7
9
|
if options[:ordenable]
|
8
10
|
field = controller.instance_variable_get(:@field)
|
@@ -23,6 +23,10 @@ module PgEngine
|
|
23
23
|
authorizable_ransackable_attributes
|
24
24
|
end
|
25
25
|
|
26
|
+
def gender
|
27
|
+
self.class.model_name.human.downcase.ends_with?('a') ? 'f' : 'm'
|
28
|
+
end
|
29
|
+
|
26
30
|
def self.nombre_plural
|
27
31
|
model_name.human(count: 2)
|
28
32
|
end
|
@@ -43,6 +47,15 @@ module PgEngine
|
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
50
|
+
# Para el dom_id (index.html)
|
51
|
+
def to_key
|
52
|
+
if respond_to? :hashid
|
53
|
+
[hashid]
|
54
|
+
else
|
55
|
+
super
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
46
59
|
def to_s
|
47
60
|
%i[nombre name].each do |campo|
|
48
61
|
return "#{send(campo)} ##{to_param}" if try(campo).present?
|
@@ -13,7 +13,19 @@ class UserPolicy < ApplicationPolicy
|
|
13
13
|
# end
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
17
|
-
|
18
|
-
end
|
16
|
+
# def puede_editar?
|
17
|
+
# acceso_total? && !record.readonly?
|
18
|
+
# end
|
19
|
+
|
20
|
+
# def puede_crear?
|
21
|
+
# acceso_total? || user.asesor?
|
22
|
+
# end
|
23
|
+
|
24
|
+
# def puede_borrar?
|
25
|
+
# acceso_total? && !record.readonly?
|
26
|
+
# end
|
27
|
+
|
28
|
+
# def acceso_total?
|
29
|
+
# user.developer?
|
30
|
+
# end
|
19
31
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class UserRegistrationPolicy
|
4
|
+
attr_reader :user, :record
|
5
|
+
|
6
|
+
def initialize(user, record)
|
7
|
+
@user = user
|
8
|
+
@record = record
|
9
|
+
end
|
10
|
+
|
11
|
+
def new?
|
12
|
+
create?
|
13
|
+
end
|
14
|
+
|
15
|
+
def create?
|
16
|
+
user.blank?
|
17
|
+
end
|
18
|
+
|
19
|
+
def edit?
|
20
|
+
update?
|
21
|
+
end
|
22
|
+
|
23
|
+
def update?
|
24
|
+
user == record
|
25
|
+
end
|
26
|
+
end
|
@@ -1,9 +1,13 @@
|
|
1
1
|
- content_for :title do
|
2
2
|
= @user.to_s
|
3
3
|
- content_for :actions do
|
4
|
-
= @user.
|
4
|
+
= @user.destroy_link_redirect
|
5
5
|
.ms-1
|
6
6
|
= @user.edit_link
|
7
|
+
.ms-1
|
8
|
+
= link_to admin_login_as_path(id: @user.id), class: 'btn btn-light btn-sm' do
|
9
|
+
span.bi.bi-arrow-right
|
10
|
+
| Login as
|
7
11
|
|
8
12
|
table.table.table-borderless.table-sm.w-auto.mb-0.m-3
|
9
13
|
- atributos_para_mostrar.each do |att|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/ # locals: (object: nil, asociable: false)
|
2
|
+
.text-center
|
3
|
+
#mensaje_contacto
|
4
|
+
h2 Ponete en contacto
|
5
|
+
.d-inline-block style="width: 30em; max-width: 100%"
|
6
|
+
div data-controller="pg_form"
|
7
|
+
= pg_form_for(@mensaje_contacto || object, asociable:) do |f|
|
8
|
+
= f.mensajes_de_error
|
9
|
+
|
10
|
+
= hidden_field_tag :asociable, true if asociable
|
11
|
+
= f.input :nombre, input_html: { style: 'max-width: 22em' }
|
12
|
+
= f.input :email, input_html: { style: 'max-width: 23em' }
|
13
|
+
= f.input :telefono, hint: '(Opcional)', input_html: { style: 'max-width: 15em' }
|
14
|
+
= f.input :mensaje, as: :text, input_html: { rows: 5 }
|
15
|
+
.mt-2
|
16
|
+
= f.button :submit, value: 'Enviar'
|
17
|
+
|
18
|
+
css:
|
19
|
+
form input {
|
20
|
+
margin: auto;
|
21
|
+
}
|
@@ -1,3 +1,9 @@
|
|
1
|
+
class MyAdapter < ActiveAdmin::AuthorizationAdapter
|
2
|
+
def authorized?(action, subject = nil)
|
3
|
+
user.developer?
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
1
7
|
ActiveAdmin.setup do |config|
|
2
8
|
# == Site Title
|
3
9
|
#
|
@@ -79,7 +85,7 @@ ActiveAdmin.setup do |config|
|
|
79
85
|
# method in a before filter of all controller actions to
|
80
86
|
# ensure that there is a user with proper rights. You can use
|
81
87
|
# CanCanAdapter or make your own. Please refer to documentation.
|
82
|
-
|
88
|
+
config.authorization_adapter = MyAdapter
|
83
89
|
|
84
90
|
# In case you prefer Pundit over other solutions you can here pass
|
85
91
|
# the name of default policy class. This policy will be used in every
|
@@ -164,7 +164,7 @@ Devise.setup do |config|
|
|
164
164
|
|
165
165
|
# ==> Configuration for :rememberable
|
166
166
|
# The time the user will be remembered without asking for credentials again.
|
167
|
-
|
167
|
+
config.remember_for = 60.days
|
168
168
|
|
169
169
|
# Invalidates all the remember me tokens when the user signs out.
|
170
170
|
config.expire_all_remember_me_on_sign_out = true
|
@@ -188,7 +188,7 @@ Devise.setup do |config|
|
|
188
188
|
# ==> Configuration for :timeoutable
|
189
189
|
# The time you want to timeout the user session without activity. After this
|
190
190
|
# time the user will be asked for credentials again. Default is 30 minutes.
|
191
|
-
|
191
|
+
config.timeout_in = 14.days
|
192
192
|
|
193
193
|
# ==> Configuration for :lockable
|
194
194
|
# Defines which strategy will be used to lock an account.
|
@@ -77,7 +77,10 @@ es:
|
|
77
77
|
sign_up: Crear una cuenta
|
78
78
|
forgot_your_password: ¿Olvidaste tu contraseña?
|
79
79
|
didn_t_receive_confirmation_instructions: ¿No recibiste las instrucciones para confirmar tu cuenta?
|
80
|
-
|
80
|
+
activerecord:
|
81
|
+
attributes:
|
82
|
+
user:
|
83
|
+
remember_me: Mantener sesión abierta
|
81
84
|
|
82
85
|
|
83
86
|
|
@@ -92,7 +92,7 @@ SimpleForm.setup do |config|
|
|
92
92
|
config.wrappers :vertical_form, class: 'mb-3', &control_wrapper
|
93
93
|
|
94
94
|
# vertical input for boolean
|
95
|
-
config.wrappers :vertical_boolean, tag: 'fieldset', class: 'mb-3' do |b|
|
95
|
+
config.wrappers :vertical_boolean, tag: 'fieldset', class: 'mb-3 d-flex justify-content-center' do |b|
|
96
96
|
b.use :html5
|
97
97
|
b.optional :readonly
|
98
98
|
b.wrapper :form_check_wrapper, class: 'form-check' do |bb|
|
@@ -184,10 +184,12 @@ RSpec.describe Admin::AccountsController do
|
|
184
184
|
|
185
185
|
describe 'DELETE #destroy' do
|
186
186
|
subject do
|
187
|
-
|
187
|
+
request.headers['Accept'] = 'text/vnd.turbo-stream.html,text/html'
|
188
|
+
delete :destroy, params: { id: account.to_param, redirect_to: redirect_url }
|
188
189
|
end
|
189
190
|
|
190
191
|
let!(:account) { create :account }
|
192
|
+
let(:redirect_url) { nil }
|
191
193
|
|
192
194
|
it 'destroys the requested account' do
|
193
195
|
expect { subject }.to change(Account.kept, :count).by(-1)
|
@@ -198,9 +200,18 @@ RSpec.describe Admin::AccountsController do
|
|
198
200
|
expect(account.reload.discarded_at).to be_present
|
199
201
|
end
|
200
202
|
|
201
|
-
it '
|
203
|
+
it 'quita el elemento de la lista' do
|
202
204
|
subject
|
203
|
-
expect(response).to
|
205
|
+
expect(response.body).to include('turbo-stream action="remove"')
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'si hay redirect_to' do
|
209
|
+
let(:redirect_url) { admin_accounts_url }
|
210
|
+
|
211
|
+
it 'redirects to the accounts list' do
|
212
|
+
subject
|
213
|
+
expect(response).to redirect_to(admin_accounts_url)
|
214
|
+
end
|
204
215
|
end
|
205
216
|
end
|
206
217
|
end
|
@@ -172,18 +172,29 @@ RSpec.describe Admin::UserAccountsController do
|
|
172
172
|
|
173
173
|
describe 'DELETE #destroy' do
|
174
174
|
subject do
|
175
|
-
|
175
|
+
request.headers['Accept'] = 'text/vnd.turbo-stream.html,text/html'
|
176
|
+
delete :destroy, params: { id: user_account.to_param, redirect_to: redirect_url }
|
176
177
|
end
|
177
178
|
|
178
179
|
let!(:user_account) { create :user_account }
|
180
|
+
let(:redirect_url) { nil }
|
179
181
|
|
180
182
|
it 'destroys the requested user_account' do
|
181
183
|
expect { subject }.to change(UserAccount, :count).by(-1)
|
182
184
|
end
|
183
185
|
|
184
|
-
it '
|
186
|
+
it 'quita el elemento de la lista' do
|
185
187
|
subject
|
186
|
-
expect(response).to
|
188
|
+
expect(response.body).to include('turbo-stream action="remove"')
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'si hay redirect_to' do
|
192
|
+
let(:redirect_url) { admin_user_accounts_url }
|
193
|
+
|
194
|
+
it 'redirects to the user_accounts list' do
|
195
|
+
subject
|
196
|
+
expect(response).to redirect_to(admin_user_accounts_url)
|
197
|
+
end
|
187
198
|
end
|
188
199
|
end
|
189
200
|
end
|
@@ -158,10 +158,12 @@ RSpec.describe Admin::UsersController do
|
|
158
158
|
|
159
159
|
describe 'DELETE #destroy' do
|
160
160
|
subject do
|
161
|
-
|
161
|
+
request.headers['Accept'] = 'text/vnd.turbo-stream.html,text/html'
|
162
|
+
delete :destroy, params: { id: user.to_param, redirect_to: redirect_url }
|
162
163
|
end
|
163
164
|
|
164
165
|
let!(:user) { create :user }
|
166
|
+
let(:redirect_url) { nil }
|
165
167
|
|
166
168
|
it 'destroys the requested user' do
|
167
169
|
expect { subject }.to change(User.kept, :count).by(-1)
|
@@ -172,9 +174,18 @@ RSpec.describe Admin::UsersController do
|
|
172
174
|
expect(user.reload.discarded_at).to be_present
|
173
175
|
end
|
174
176
|
|
175
|
-
it '
|
177
|
+
it 'quita el elemento de la lista' do
|
176
178
|
subject
|
177
|
-
expect(response).to
|
179
|
+
expect(response.body).to include('turbo-stream action="remove"')
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'si hay redirect_to' do
|
183
|
+
let(:redirect_url) { admin_users_url }
|
184
|
+
|
185
|
+
it 'redirects to the users list' do
|
186
|
+
subject
|
187
|
+
expect(response).to redirect_to(admin_users_url)
|
188
|
+
end
|
178
189
|
end
|
179
190
|
end
|
180
191
|
end
|
@@ -34,9 +34,9 @@ describe PgEngine::Resource do
|
|
34
34
|
instancia.send(:do_sort, scope, param, direction)
|
35
35
|
end
|
36
36
|
|
37
|
-
let!(:
|
38
|
-
let!(:
|
39
|
-
let(:scope) {
|
37
|
+
let!(:cosa_ult) { create :cosa, nombre: 'Z' }
|
38
|
+
let!(:cosa_pri) { create :cosa, nombre: 'a' }
|
39
|
+
let(:scope) { Cosa.all }
|
40
40
|
let(:param) { :nombre }
|
41
41
|
let(:direction) { :desc }
|
42
42
|
|
@@ -44,7 +44,7 @@ describe PgEngine::Resource do
|
|
44
44
|
let(:direction) { :asc }
|
45
45
|
|
46
46
|
it do
|
47
|
-
expect(subject.to_a).to eq [
|
47
|
+
expect(subject.to_a).to eq [cosa_pri, cosa_ult]
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -52,7 +52,7 @@ describe PgEngine::Resource do
|
|
52
52
|
let(:direction) { :desc }
|
53
53
|
|
54
54
|
it do
|
55
|
-
expect(subject.to_a).to eq [
|
55
|
+
expect(subject.to_a).to eq [cosa_ult, cosa_pri]
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
@@ -60,7 +60,32 @@ describe PgEngine::Resource do
|
|
60
60
|
let(:param) { :inexistente }
|
61
61
|
|
62
62
|
it do
|
63
|
-
expect(subject.to_a).to eq [
|
63
|
+
expect(subject.to_a).to eq [cosa_ult, cosa_pri]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'cuando ordeno por categoria' do
|
68
|
+
let(:param) { :categoria_de_cosa }
|
69
|
+
|
70
|
+
before do
|
71
|
+
cosa_pri.categoria_de_cosa.update_column(:nombre, 'a') # rubocop:disable Rails/SkipsModelValidations
|
72
|
+
cosa_ult.categoria_de_cosa.update_column(:nombre, 'z') # rubocop:disable Rails/SkipsModelValidations
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'si es asc' do
|
76
|
+
let(:direction) { :asc }
|
77
|
+
|
78
|
+
it do
|
79
|
+
expect(subject.to_a).to eq [cosa_pri, cosa_ult]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'si es desc' do
|
84
|
+
let(:direction) { :desc }
|
85
|
+
|
86
|
+
it do
|
87
|
+
expect(subject.to_a).to eq [cosa_ult, cosa_pri]
|
88
|
+
end
|
64
89
|
end
|
65
90
|
end
|
66
91
|
end
|
@@ -42,7 +42,7 @@ describe DummyBaseController do
|
|
42
42
|
it do
|
43
43
|
subject
|
44
44
|
expect(response).to redirect_to root_path
|
45
|
-
expect(flash[:alert]).to eq '
|
45
|
+
expect(flash[:alert]).to eq 'Acceso no autorizado'
|
46
46
|
expect(controller).to be_user_signed_in
|
47
47
|
end
|
48
48
|
|
@@ -54,7 +54,7 @@ describe DummyBaseController do
|
|
54
54
|
it do
|
55
55
|
subject
|
56
56
|
expect(response).to have_http_status(:ok)
|
57
|
-
expect(response.body).to eq '
|
57
|
+
expect(response.body).to eq 'Acceso no autorizado'
|
58
58
|
expect(controller).not_to be_user_signed_in
|
59
59
|
end
|
60
60
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe 'Sign in', :js do
|
6
|
+
include ActionView::RecordIdentifier
|
7
|
+
|
8
|
+
shared_examples 'destroy from index' do
|
9
|
+
subject do
|
10
|
+
accept_confirm do
|
11
|
+
find("##{dom_id(cosa)} span[title=Eliminar] a").click
|
12
|
+
end
|
13
|
+
sleep 1
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:user) { create :user, :developer }
|
17
|
+
let!(:cosa) { create :cosa }
|
18
|
+
|
19
|
+
before do
|
20
|
+
create_list :cosa, 5
|
21
|
+
login_as user
|
22
|
+
visit '/frontend/cosas'
|
23
|
+
end
|
24
|
+
|
25
|
+
it do
|
26
|
+
expect { subject }.to change { page.find_all('tbody tr').length }.from(6).to(5)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
shared_examples 'destroy from show' do
|
31
|
+
subject do
|
32
|
+
accept_confirm do
|
33
|
+
find('.btn-toolbar span[title=Eliminar] a').click
|
34
|
+
end
|
35
|
+
sleep 1
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:user) { create :user, :developer }
|
39
|
+
let!(:cosa) { create :cosa }
|
40
|
+
|
41
|
+
before do
|
42
|
+
login_as user
|
43
|
+
visit "/frontend/cosas/#{cosa.to_param}"
|
44
|
+
end
|
45
|
+
|
46
|
+
it do # rubocop:disable RSpec/MultipleExpectations
|
47
|
+
subject
|
48
|
+
expect(page).to have_current_path('/frontend/cosas')
|
49
|
+
expect(page).to have_text('Coso borrado')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Capybara.drivers.keys
|
54
|
+
drivers = %i[
|
55
|
+
selenium_headless
|
56
|
+
selenium_chrome_headless
|
57
|
+
selenium_chrome_headless_notebook
|
58
|
+
selenium_chrome_headless_iphone
|
59
|
+
]
|
60
|
+
# drivers = %i[selenium_chrome_headless_notebook]
|
61
|
+
# drivers = %i[selenium_chrome_debugger]
|
62
|
+
# drivers = %i[selenium]
|
63
|
+
# drivers = %i[selenium_chrome]
|
64
|
+
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
65
|
+
|
66
|
+
drivers.each do |driver|
|
67
|
+
context("with driver '#{driver}'", driver:) do
|
68
|
+
it_behaves_like 'destroy from index'
|
69
|
+
it_behaves_like 'destroy from show'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe 'Sign in', :js do
|
6
|
+
shared_examples 'sign_in' do
|
7
|
+
subject do
|
8
|
+
visit '/users/sign_in'
|
9
|
+
fill_in 'user_email', with: user.email
|
10
|
+
fill_in 'user_password', with: password
|
11
|
+
find('input[type=submit]').click
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:password) { 'pass1234' }
|
15
|
+
let!(:user) { create :user, password: }
|
16
|
+
|
17
|
+
it do
|
18
|
+
subject
|
19
|
+
expect(page).to have_text :all, 'No hay categorías de cosas aún'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Capybara.drivers.keys
|
24
|
+
drivers = %i[
|
25
|
+
selenium_headless
|
26
|
+
selenium_chrome_headless
|
27
|
+
selenium_chrome_headless_notebook
|
28
|
+
selenium_chrome_headless_iphone
|
29
|
+
]
|
30
|
+
# drivers = %i[selenium_chrome_headless_notebook]
|
31
|
+
# drivers = %i[selenium_chrome_debugger]
|
32
|
+
# drivers = %i[selenium]
|
33
|
+
# drivers = %i[selenium_chrome]
|
34
|
+
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
35
|
+
|
36
|
+
drivers.each do |driver|
|
37
|
+
context("with driver '#{driver}'", driver:) do
|
38
|
+
include_examples 'sign_in'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails_helper'
|
4
|
+
|
5
|
+
describe 'Al Registrarse', :js do
|
6
|
+
include ActiveJob::TestHelper
|
7
|
+
|
8
|
+
find_scroll = proc do |selector, options = {}|
|
9
|
+
elem = find(selector, **options.merge(visible: :all))
|
10
|
+
script = 'arguments[0].scrollIntoView({ behavior: "instant", block: "start", inline: "nearest" });'
|
11
|
+
page.execute_script(script, elem)
|
12
|
+
sleep 0.5
|
13
|
+
elem
|
14
|
+
end
|
15
|
+
|
16
|
+
shared_examples 'sign_up' do
|
17
|
+
subject do
|
18
|
+
perform_enqueued_jobs do
|
19
|
+
visit '/users/sign_up'
|
20
|
+
fill_in 'user_email', with: Faker::Internet.email
|
21
|
+
fill_in 'user_nombre', with: Faker::Name.name
|
22
|
+
fill_in 'user_apellido', with: Faker::Name.name
|
23
|
+
fill_in 'user_password', with: 'admin123'
|
24
|
+
fill_in 'user_password_confirmation', with: 'admin123'
|
25
|
+
instance_exec('input[type=submit]', &find_scroll).click
|
26
|
+
expect(page).to have_text('Se ha enviado un mensaje con un enlace')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'guarda el user' do
|
31
|
+
expect { subject }.to change(User, :count).by(1)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
shared_examples 'edit user' do
|
36
|
+
subject do
|
37
|
+
fill_in 'user_nombre', with: 'despues'
|
38
|
+
fill_in 'user_current_password', with: password
|
39
|
+
instance_exec('input[type=submit]', &find_scroll).click
|
40
|
+
# find('').click
|
41
|
+
sleep 1
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:password) { 'pass1234' }
|
45
|
+
let(:nombre) { 'antes' }
|
46
|
+
let!(:user) { create :user, password:, nombre: }
|
47
|
+
|
48
|
+
before do
|
49
|
+
login_as user
|
50
|
+
visit '/users/edit'
|
51
|
+
end
|
52
|
+
|
53
|
+
it do # rubocop:disable RSpec/MultipleExpectations
|
54
|
+
expect { subject }.to change { user.reload.nombre }.to('despues')
|
55
|
+
expect(page).to have_text('Tu cuenta se ha actualizado')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Capybara.drivers.keys
|
60
|
+
drivers = %i[
|
61
|
+
selenium_headless
|
62
|
+
selenium_chrome_headless
|
63
|
+
selenium_chrome_headless_notebook
|
64
|
+
selenium_chrome_headless_iphone
|
65
|
+
]
|
66
|
+
# drivers = %i[selenium_chrome_headless_notebook]
|
67
|
+
# drivers = %i[selenium_chrome_debugger]
|
68
|
+
# drivers = %i[selenium]
|
69
|
+
# drivers = %i[selenium_chrome]
|
70
|
+
drivers = [ENV['DRIVER'].to_sym] if ENV['DRIVER'].present?
|
71
|
+
|
72
|
+
drivers.each do |driver|
|
73
|
+
context("with driver '#{driver}'", driver:) do
|
74
|
+
it_behaves_like 'sign_up'
|
75
|
+
it_behaves_like 'edit user'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -1,15 +1,24 @@
|
|
1
1
|
import { Controller } from '@hotwired/stimulus'
|
2
2
|
import Cookies from './../utils/cookies'
|
3
|
+
import { fadeOut, fadeIn } from './../utils/utils'
|
3
4
|
|
4
5
|
export default class extends Controller {
|
6
|
+
connect () {
|
7
|
+
if (document.getElementById('sidebar').classList.contains('opened')) {
|
8
|
+
document.querySelector('.navbar .navbar-brand').style.visibility = 'hidden'
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
5
12
|
expandNavbar (e) {
|
6
13
|
const icon = this.element.querySelector('i')
|
7
14
|
if (document.getElementById('sidebar').classList.toggle('opened')) {
|
8
15
|
icon.classList.add('bi-chevron-left')
|
9
16
|
icon.classList.remove('bi-chevron-right')
|
17
|
+
fadeOut(document.querySelector('.navbar .navbar-brand'))
|
10
18
|
} else {
|
11
19
|
icon.classList.remove('bi-chevron-left')
|
12
20
|
icon.classList.add('bi-chevron-right')
|
21
|
+
fadeIn(document.querySelector('.navbar .navbar-brand'))
|
13
22
|
}
|
14
23
|
const isOpened = document.getElementById('sidebar').classList.contains('opened')
|
15
24
|
new Cookies().setCookie('navbar_expand', isOpened, 30)
|
@@ -1,9 +1,3 @@
|
|
1
|
-
<% if @navbar.logo_xl_url.present? %>
|
2
|
-
<div class="mx-3 my-4 m-md-5">
|
3
|
-
<%= image_tag @navbar.logo_xl_url, class: 'img-fluid' %>
|
4
|
-
</div>
|
5
|
-
<% end %>
|
6
|
-
|
7
1
|
<h2><%= t(".sign_up") %></h2>
|
8
2
|
<div id="form-signup" data-controller="pg_form">
|
9
3
|
<%= pg_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
|
@@ -1,9 +1,3 @@
|
|
1
|
-
<% if @navbar.logo_xl_url.present? %>
|
2
|
-
<div class="mx-3 my-4 m-md-5">
|
3
|
-
<%= image_tag @navbar.logo_xl_url, class: 'img-fluid' %>
|
4
|
-
</div>
|
5
|
-
<% end %>
|
6
|
-
|
7
1
|
<h2><%= t(".sign_in") %></h2>
|
8
2
|
|
9
3
|
<%= render partial: 'pg_layout/flash_container' %>
|
@@ -16,7 +10,6 @@
|
|
16
10
|
<%= f.input :password,
|
17
11
|
required: false,
|
18
12
|
input_html: { autocomplete: "current-password" } %>
|
19
|
-
<%# TODO!: corregir style de checkbox %>
|
20
13
|
<%#= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %>
|
21
14
|
</div>
|
22
15
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
- content_for :content do
|
2
|
+
.container-fluid.pt-4
|
3
|
+
.text-center
|
4
|
+
- if @navbar.logo_xl_url.present?
|
5
|
+
.mb-4
|
6
|
+
= image_tag @navbar.logo_xl_url, class: 'img-fluid', style: 'max-height: 4em'
|
7
|
+
|
8
|
+
= content_for?(:container_logo_content) ? yield(:container_logo_content) : yield
|
9
|
+
|
10
|
+
= render template: 'layouts/pg_layout/base'
|
@@ -1,5 +1,5 @@
|
|
1
|
-
- content_for :
|
2
|
-
.
|
1
|
+
- content_for :container_logo_content do
|
2
|
+
.text-center
|
3
3
|
= yield
|
4
4
|
|
5
5
|
css:
|
@@ -8,4 +8,4 @@
|
|
8
8
|
margin: auto;
|
9
9
|
}
|
10
10
|
|
11
|
-
= render template: 'layouts/pg_layout/
|
11
|
+
= render template: 'layouts/pg_layout/container_logo'
|
@@ -5,13 +5,19 @@
|
|
5
5
|
<i class="bi <%= @navbar_chevron_class %>"></i>
|
6
6
|
</button>
|
7
7
|
|
8
|
-
<button class="btn btn-outline-light d-inline-block d-<%= @breakpoint_navbar_expand %>-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasExample" aria-controls="offcanvasExample">
|
9
|
-
<i class="bi bi-list"></i>
|
10
|
-
</button>
|
11
8
|
<% end %>
|
12
9
|
<% @navbar.extensiones.each do |extension| %>
|
13
10
|
<%= extension %>
|
14
11
|
<% end %>
|
15
12
|
<%= @navbar.logo if @navbar.logo.present? %>
|
13
|
+
<button class="btn btn-outline-light d-inline-block d-<%= @breakpoint_navbar_expand %>-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasExample" aria-controls="offcanvasExample">
|
14
|
+
<i class="bi bi-list"></i>
|
15
|
+
</button>
|
16
16
|
</div>
|
17
17
|
</nav>
|
18
|
+
|
19
|
+
<style type="text/css" media="(max-width: 767px)">
|
20
|
+
.navbar .navbar-brand {
|
21
|
+
visibility:visible!important;
|
22
|
+
}
|
23
|
+
</style>
|
@@ -1,5 +1,8 @@
|
|
1
1
|
<div id="sidebar" class="<%= @navbar_opened_class %> flex-shrink-0 d-none d-<%= @breakpoint_navbar_expand %>-block">
|
2
|
-
<div class="mt-
|
2
|
+
<div class="mt-1">
|
3
|
+
<div class="m-3">
|
4
|
+
<%= @navbar.logo if @navbar.logo.present? %>
|
5
|
+
</div>
|
3
6
|
<% if user_signed_in? %>
|
4
7
|
<span class="ms-3 text-light"><%= Current.user %></span>
|
5
8
|
<hr>
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<div class="offcanvas offcanvas-
|
1
|
+
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
|
2
2
|
<div class="offcanvas-header" data-bs-theme="dark">
|
3
3
|
<h5 class="offcanvas-title" id="offcanvasExampleLabel"></h5>
|
4
4
|
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
data/pg_rails/lib/version.rb
CHANGED
@@ -241,14 +241,12 @@ RSpec.describe <%= controller_class_name %>Controller do
|
|
241
241
|
|
242
242
|
describe 'DELETE #destroy' do
|
243
243
|
subject do
|
244
|
-
|
245
|
-
delete :destroy, { id: <%= file_name %>.to_param }
|
246
|
-
<% else -%>
|
247
|
-
delete :destroy, params: { id: <%= file_name %>.to_param }
|
248
|
-
<% end -%>
|
244
|
+
request.headers['Accept'] = "text/vnd.turbo-stream.html,text/html"
|
245
|
+
delete :destroy, params: { id: <%= file_name %>.to_param, redirect_to: redirect_url }
|
249
246
|
end
|
250
247
|
|
251
248
|
let!(:<%= nombre_tabla_completo_singular %>) { create :<%= nombre_tabla_completo_singular %> }
|
249
|
+
let(:redirect_url) { nil }
|
252
250
|
|
253
251
|
it 'destroys the requested <%= nombre_tabla_completo_singular %>' do
|
254
252
|
<% if options[:discard] -%>
|
@@ -267,9 +265,18 @@ RSpec.describe <%= controller_class_name %>Controller do
|
|
267
265
|
end
|
268
266
|
|
269
267
|
<% end -%>
|
270
|
-
it '
|
268
|
+
it 'quita el elemento de la lista' do
|
271
269
|
subject
|
272
|
-
expect(response).to
|
270
|
+
expect(response.body).to include('turbo-stream action="remove"')
|
271
|
+
end
|
272
|
+
|
273
|
+
context 'si hay redirect_to' do
|
274
|
+
let(:redirect_url) { <%= index_helper %>_url }
|
275
|
+
|
276
|
+
it 'redirects to the <%= table_name %> list' do
|
277
|
+
subject
|
278
|
+
expect(response).to redirect_to(<%= index_helper %>_url)
|
279
|
+
end
|
273
280
|
end
|
274
281
|
end
|
275
282
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.8.pre.alpha.
|
4
|
+
version: 7.0.8.pre.alpha.53
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martín Rosso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -890,6 +890,7 @@ files:
|
|
890
890
|
- pg_engine/app/policies/pg_engine/application_policy.rb
|
891
891
|
- pg_engine/app/policies/user_account_policy.rb
|
892
892
|
- pg_engine/app/policies/user_policy.rb
|
893
|
+
- pg_engine/app/policies/user_registration_policy.rb
|
893
894
|
- pg_engine/app/views/admin/accounts/_account.html.slim
|
894
895
|
- pg_engine/app/views/admin/accounts/_form.html.slim
|
895
896
|
- pg_engine/app/views/admin/accounts/edit.html.slim
|
@@ -909,8 +910,8 @@ files:
|
|
909
910
|
- pg_engine/app/views/pg_engine/base/edit.html.slim
|
910
911
|
- pg_engine/app/views/pg_engine/base/index.html.slim
|
911
912
|
- pg_engine/app/views/pg_engine/base/new.html.slim
|
912
|
-
- pg_engine/app/views/public/mensaje_contactos/_form.html.slim
|
913
913
|
- pg_engine/app/views/public/mensaje_contactos/_gracias.html.slim
|
914
|
+
- pg_engine/app/views/public/mensaje_contactos/new.html.slim
|
914
915
|
- pg_engine/config/initializers/action_mailer.rb
|
915
916
|
- pg_engine/config/initializers/active_admin.rb
|
916
917
|
- pg_engine/config/initializers/anycable.rb
|
@@ -956,6 +957,9 @@ files:
|
|
956
957
|
- pg_engine/spec/factories/mensaje_contactos.rb
|
957
958
|
- pg_engine/spec/factories/user_accounts.rb
|
958
959
|
- pg_engine/spec/factories/users.rb
|
960
|
+
- pg_engine/spec/features/destroy_spec.rb
|
961
|
+
- pg_engine/spec/features/login_spec.rb
|
962
|
+
- pg_engine/spec/features/signup_spec.rb
|
959
963
|
- pg_engine/spec/fixtures/test.pdf
|
960
964
|
- pg_engine/spec/helpers/pg_engine/pg_rails_helper_spec.rb
|
961
965
|
- pg_engine/spec/lib/pg_engine/error_helper_spec.rb
|
@@ -1005,6 +1009,7 @@ files:
|
|
1005
1009
|
- pg_layout/app/views/kaminari/_paginator.html.slim
|
1006
1010
|
- pg_layout/app/views/kaminari/_prev_page.html.slim
|
1007
1011
|
- pg_layout/app/views/layouts/pg_layout/base.html.slim
|
1012
|
+
- pg_layout/app/views/layouts/pg_layout/container_logo.html.slim
|
1008
1013
|
- pg_layout/app/views/layouts/pg_layout/containerized.html.slim
|
1009
1014
|
- pg_layout/app/views/layouts/pg_layout/devise.html.slim
|
1010
1015
|
- pg_layout/app/views/pg_layout/_flash.html.slim
|
@@ -1,14 +0,0 @@
|
|
1
|
-
/ # locals: (object: nil, asociable: false)
|
2
|
-
#mensaje_contacto.text-center
|
3
|
-
.d-inline-block style="width: 22em; max-width: 100%"
|
4
|
-
div data-controller="pg_form"
|
5
|
-
= pg_form_for(@mensaje_contacto || object, asociable:) do |f|
|
6
|
-
= f.mensajes_de_error
|
7
|
-
|
8
|
-
= hidden_field_tag :asociable, true if asociable
|
9
|
-
= f.input :nombre
|
10
|
-
= f.input :email
|
11
|
-
= f.input :telefono, hint: '(Opcional)'
|
12
|
-
= f.input :mensaje, as: :text
|
13
|
-
.mt-2
|
14
|
-
= f.button :submit, value: 'Enviar'
|