pg_rails 7.0.8.pre.alpha.51 → 7.0.8.pre.alpha.53

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.
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'