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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/pg_engine/app/controllers/admin/users_controller.rb +7 -3
  3. data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +20 -14
  4. data/pg_engine/app/controllers/pg_engine/base_controller.rb +3 -3
  5. data/pg_engine/app/controllers/public/mensaje_contactos_controller.rb +4 -0
  6. data/pg_engine/app/controllers/users/registrations_controller.rb +1 -3
  7. data/pg_engine/app/decorators/pg_engine/base_decorator.rb +8 -3
  8. data/pg_engine/app/helpers/pg_engine/index_helper.rb +2 -0
  9. data/pg_engine/app/models/pg_engine/base_record.rb +13 -0
  10. data/pg_engine/app/policies/user_policy.rb +15 -3
  11. data/pg_engine/app/policies/user_registration_policy.rb +26 -0
  12. data/pg_engine/app/views/admin/accounts/show.html.slim +1 -1
  13. data/pg_engine/app/views/admin/user_accounts/show.html.slim +1 -1
  14. data/pg_engine/app/views/admin/users/show.html.slim +5 -1
  15. data/pg_engine/app/views/public/mensaje_contactos/new.html.slim +21 -0
  16. data/pg_engine/config/initializers/active_admin.rb +7 -1
  17. data/pg_engine/config/initializers/devise.rb +2 -2
  18. data/pg_engine/config/locales/es.yml +4 -1
  19. data/pg_engine/config/simple_form/simple_form_bootstrap.rb +1 -1
  20. data/pg_engine/spec/controllers/admin/accounts_controller_spec.rb +14 -3
  21. data/pg_engine/spec/controllers/admin/user_accounts_controller_spec.rb +14 -3
  22. data/pg_engine/spec/controllers/admin/users_controller_spec.rb +14 -3
  23. data/pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb +31 -6
  24. data/pg_engine/spec/controllers/pg_engine/base_controller_spec.rb +2 -2
  25. data/pg_engine/spec/features/destroy_spec.rb +72 -0
  26. data/pg_engine/spec/features/login_spec.rb +41 -0
  27. data/pg_engine/spec/features/signup_spec.rb +78 -0
  28. data/pg_layout/app/javascript/controllers/navbar_controller.js +9 -0
  29. data/pg_layout/app/views/devise/registrations/new.html.erb +0 -6
  30. data/pg_layout/app/views/devise/sessions/new.html.erb +0 -7
  31. data/pg_layout/app/views/layouts/pg_layout/container_logo.html.slim +10 -0
  32. data/pg_layout/app/views/layouts/pg_layout/devise.html.slim +3 -3
  33. data/pg_layout/app/views/pg_layout/_navbar.html.erb +9 -3
  34. data/pg_layout/app/views/pg_layout/_sidebar.html.erb +4 -1
  35. data/pg_layout/app/views/pg_layout/_sidebar_mobile.html.erb +1 -1
  36. data/pg_rails/lib/version.rb +1 -1
  37. data/pg_scaffold/lib/generators/pg_rspec/scaffold/templates/controller_spec.rb +14 -7
  38. data/pg_scaffold/lib/generators/pg_slim/templates/show.html.slim +1 -1
  39. metadata +8 -3
  40. 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: 12e2f8570100688111978d151d42a814178f2382d18b373455535f7b5d625216
4
- data.tar.gz: e867b8911a1a67781515d30efbf3facf6ad31cb27c296444327016c3ad2fdbca
3
+ metadata.gz: bc65c537b0f07c6659a716cf31aca506a9da7d7ee43f6bbaa425a756864875ef
4
+ data.tar.gz: ba019b72eb7fac96fc364396da6890040a86b7743e2532e73c677a20809c546d
5
5
  SHA512:
6
- metadata.gz: e7bc0a0f4e182d2f0fc451278e779acb22c31de3e7939de6d9feeb5047590b972586a70c8f03823b648c1e298bfa9ca7cc9609748175f8de941bc03658e42476
7
- data.tar.gz: e5b2f79ca65227fdf85761af0a96629405c0904c6f0027b3f16e001648470c375920c8b5eb2d550ae0b697e4784b95f791ec4d073d4d22ebb37f6d8ea73e9dd9
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
- if dev_user_or_env?
36
- usuario = User.find(params[:id])
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
- url = namespaced_path(@clase_modelo)
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
- format.html do
155
- if redirect_url.present?
156
- redirect_to redirect_url, notice: 'Elemento borrado.', status: :see_other
157
- else
158
- redirect_back(fallback_location: root_path, notice: 'Elemento borrado.', status: 303)
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? field.to_s
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.order(field => direction)
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: 'Not authorized' },
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: 'Not authorized'
109
+ render plain: 'Acceso no autorizado'
110
110
  else
111
- go_back('Not authorized')
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')
@@ -1,9 +1,7 @@
1
1
  module Users
2
2
  class RegistrationsController < Devise::RegistrationsController
3
- # POST /resource
4
-
5
3
  before_action do
6
- authorize User
4
+ authorize resource, nil, policy_class: UserRegistrationPolicy
7
5
  end
8
6
 
9
7
  def create
@@ -31,12 +31,17 @@ module PgEngine
31
31
  end
32
32
  # rubocop:enable Style/MissingRespondToMissing
33
33
 
34
- def destroy_link(confirm_text: '¿Estás seguro?', klass: 'btn-light')
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, data: { 'turbo-confirm': confirm_text, 'turbo-method': :delete },
39
- class: "btn btn-sm #{klass}" do
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 acceso_total?
17
- true
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,7 +1,7 @@
1
1
  - content_for :title do
2
2
  = @account.to_s
3
3
  - content_for :actions do
4
- = @account.destroy_link
4
+ = @account.destroy_link_redirect
5
5
  .ms-1
6
6
  = @account.edit_link
7
7
 
@@ -1,7 +1,7 @@
1
1
  - content_for :title do
2
2
  = @user_account.to_s
3
3
  - content_for :actions do
4
- = @user_account.destroy_link
4
+ = @user_account.destroy_link_redirect
5
5
  .ms-1
6
6
  = @user_account.edit_link
7
7
 
@@ -1,9 +1,13 @@
1
1
  - content_for :title do
2
2
  = @user.to_s
3
3
  - content_for :actions do
4
- = @user.destroy_link
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
- # config.authorization_adapter = ActiveAdmin::CanCanAdapter
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
- # config.remember_for = 2.weeks
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
- # config.timeout_in = 30.minutes
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
- delete :destroy, params: { id: account.to_param }
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 'redirects to the accounts list' do
203
+ it 'quita el elemento de la lista' do
202
204
  subject
203
- expect(response).to redirect_to(admin_accounts_url)
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
- delete :destroy, params: { id: user_account.to_param }
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 'redirects to the user_accounts list' do
186
+ it 'quita el elemento de la lista' do
185
187
  subject
186
- expect(response).to redirect_to(admin_user_accounts_url)
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
- delete :destroy, params: { id: user.to_param }
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 'redirects to the users list' do
177
+ it 'quita el elemento de la lista' do
176
178
  subject
177
- expect(response).to redirect_to(admin_users_url)
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!(:categoria_de_cosa_ult) { create :categoria_de_cosa, nombre: 'Z' }
38
- let!(:categoria_de_cosa_pri) { create :categoria_de_cosa, nombre: 'a' }
39
- let(:scope) { CategoriaDeCosa.all }
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 [categoria_de_cosa_pri, categoria_de_cosa_ult]
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 [categoria_de_cosa_ult, categoria_de_cosa_pri]
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 [categoria_de_cosa_ult, categoria_de_cosa_pri]
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 'Not authorized'
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 'Not authorized'
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 :content do
2
- .container.text-center.pt-4
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/base'
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-4">
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-start" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
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>
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRails
4
- VERSION = '7.0.8-alpha.51'
4
+ VERSION = '7.0.8-alpha.53'
5
5
  end
@@ -241,14 +241,12 @@ RSpec.describe <%= controller_class_name %>Controller do
241
241
 
242
242
  describe 'DELETE #destroy' do
243
243
  subject do
244
- <% if Rails::VERSION::STRING < '5.0' -%>
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 'redirects to the <%= table_name %> list' do
268
+ it 'quita el elemento de la lista' do
271
269
  subject
272
- expect(response).to redirect_to(<%= index_helper %>_url)
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
@@ -1,7 +1,7 @@
1
1
  - content_for :title do
2
2
  = @<%= singular_name %>.to_s
3
3
  - content_for :actions do
4
- = @<%= singular_name %>.destroy_link
4
+ = @<%= singular_name %>.destroy_link_redirect
5
5
  .ms-1
6
6
  = @<%= singular_name %>.edit_link
7
7
 
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.51
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-04-28 00:00:00.000000000 Z
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'