pg_rails 7.6.20 → 7.6.21.pre.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/pg_associable/app/javascript/modal_controller.js +8 -4
- data/pg_associable/spec/pg_associable/helpers_spec.rb +8 -13
- data/pg_engine/app/components/inline_edit/inline_edit_component.html.slim +1 -1
- data/pg_engine/app/components/inline_edit/inline_show_component.html.slim +2 -2
- data/pg_engine/app/components/notifications_bell_component.rb +1 -1
- data/pg_engine/app/controllers/admin/accounts_controller.rb +2 -2
- data/pg_engine/app/controllers/admin/user_accounts_controller.rb +3 -3
- data/pg_engine/app/controllers/admin/users_controller.rb +4 -1
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +12 -7
- data/pg_engine/app/controllers/concerns/pg_engine/tenant_helper.rb +33 -0
- data/pg_engine/app/controllers/pg_engine/base_admin_controller.rb +0 -1
- data/pg_engine/app/controllers/pg_engine/base_controller.rb +18 -21
- data/pg_engine/app/controllers/pg_engine/base_public_controller.rb +1 -1
- data/pg_engine/app/controllers/pg_engine/base_users_controller.rb +5 -3
- data/pg_engine/app/controllers/pg_engine/devise_controller.rb +4 -1
- data/pg_engine/app/controllers/pg_engine/tenant_controller.rb +22 -0
- data/pg_engine/app/controllers/{users → tenant}/dashboard_controller.rb +2 -2
- data/pg_engine/app/controllers/tenant/inline_edit_controller.rb +22 -0
- data/pg_engine/app/controllers/tenant/user_accounts_controller.rb +56 -0
- data/pg_engine/app/controllers/users/accounts_controller.rb +46 -15
- data/pg_engine/app/controllers/users/invitations_controller.rb +78 -0
- data/pg_engine/app/controllers/users/notifications_controller.rb +1 -0
- data/pg_engine/app/controllers/users/registrations_controller.rb +3 -2
- data/pg_engine/app/decorators/account_decorator.rb +18 -0
- data/pg_engine/app/decorators/pg_engine/base_record_decorator.rb +9 -1
- data/pg_engine/app/decorators/user_account_decorator.rb +76 -11
- data/pg_engine/app/helpers/pg_engine/accounts_helper.rb +9 -0
- data/pg_engine/app/helpers/pg_engine/frame_helper.rb +12 -0
- data/pg_engine/app/lib/pg_engine/default_url_options.rb +21 -0
- data/pg_engine/app/lib/pg_engine/filtros_builder.rb +2 -0
- data/pg_engine/app/models/account.rb +28 -1
- data/pg_engine/app/models/concerns/pg_engine/child_record.rb +55 -0
- data/pg_engine/app/models/current.rb +29 -3
- data/pg_engine/app/models/pg_engine/base_record.rb +5 -0
- data/pg_engine/app/models/user.rb +56 -14
- data/pg_engine/app/models/user_account.rb +74 -9
- data/pg_engine/app/policies/account_policy.rb +35 -16
- data/pg_engine/app/policies/email_log_policy.rb +0 -4
- data/pg_engine/app/policies/email_policy.rb +0 -4
- data/pg_engine/app/policies/pg_engine/base_policy.rb +31 -10
- data/pg_engine/app/policies/user_account_policy.rb +59 -25
- data/pg_engine/app/policies/user_policy.rb +14 -1
- data/pg_engine/app/views/admin/user_accounts/_form.html.slim +1 -1
- data/pg_engine/app/views/admin/user_accounts/show.html.slim +15 -0
- data/pg_engine/app/views/admin/users/show.html.slim +0 -3
- data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -2
- data/pg_engine/app/views/tenant/dashboard/dashboard.html.slim +2 -0
- data/pg_engine/app/views/tenant/user_accounts/_fields.html.slim +13 -0
- data/pg_engine/app/views/tenant/user_accounts/_form.html.slim +9 -0
- data/pg_engine/app/views/tenant/user_accounts/show.html.slim +20 -0
- data/pg_engine/app/views/users/accounts/_form.html.slim +7 -0
- data/pg_engine/app/views/users/accounts/show.html.slim +23 -15
- data/pg_engine/config/initializers/acts_as_tenant.rb +7 -2
- data/pg_engine/config/initializers/devise.rb +10 -0
- data/pg_engine/config/initializers/ransack.rb +2 -0
- data/pg_engine/config/locales/es.yml +60 -0
- data/pg_engine/config/routes.rb +21 -11
- data/pg_engine/config/simple_form/simple_form_bootstrap.rb +2 -2
- data/pg_engine/db/migrate/20241023203849_devise_invitable.rb +14 -0
- data/pg_engine/db/migrate/20241027225618_add_membership_status_to_user_accounts.rb +6 -0
- data/pg_engine/db/seeds.rb +6 -6
- data/pg_engine/lib/pg_engine/configuracion.rb +36 -1
- data/pg_engine/lib/pg_engine/navigator.rb +2 -25
- data/pg_engine/lib/pg_engine.rb +1 -0
- data/pg_engine/spec/controllers/admin/accounts_controller_spec.rb +3 -2
- data/pg_engine/spec/controllers/admin/user_accounts_controller_spec.rb +11 -9
- data/pg_engine/spec/factories/accounts.rb +8 -0
- data/pg_engine/spec/factories/user_accounts.rb +1 -1
- data/pg_engine/spec/factories/users.rb +6 -0
- data/pg_engine/spec/models/concerns/pg_engine/child_record_spec.rb +27 -0
- data/pg_engine/spec/models/user_account_spec.rb +5 -1
- data/pg_engine/spec/models/user_spec.rb +3 -25
- data/pg_engine/spec/policies/account_policy_spec.rb +19 -0
- data/pg_engine/spec/requests/devise/invitations_spec.rb +196 -0
- data/pg_engine/spec/requests/resource_spec.rb +14 -15
- data/pg_engine/spec/requests/users/accounts_spec.rb +117 -8
- data/pg_engine/spec/requests/users/base_controller_spec.rb +31 -0
- data/pg_engine/spec/requests/users/dashboard_spec.rb +4 -9
- data/pg_engine/spec/requests/users/date_jumper_spec.rb +2 -1
- data/pg_engine/spec/requests/users/inline_edit_spec.rb +6 -5
- data/pg_engine/spec/requests/users/registrations_spec.rb +2 -2
- data/pg_engine/spec/requests/users/user_accounts_spec.rb +54 -0
- data/pg_engine/spec/system/login_spec.rb +2 -2
- data/pg_engine/spec/system/noticed_spec.rb +0 -2
- data/pg_engine/spec/system/signup_spec.rb +4 -3
- data/pg_engine/spec/system/tenants_spec.rb +10 -9
- data/pg_layout/app/javascript/application.js +1 -1
- data/pg_layout/app/javascript/config/turbo_rails/index.js +1 -1
- data/pg_layout/app/lib/navbar.rb +15 -1
- data/pg_layout/app/views/devise/invitations/edit.html.erb +34 -0
- data/pg_layout/app/views/devise/invitations/new.html.erb +15 -0
- data/pg_layout/app/views/devise/mailer/invitation_instructions.html.erb +11 -0
- data/pg_layout/app/views/devise/mailer/invitation_instructions.text.erb +11 -0
- data/pg_layout/app/views/devise/registrations/edit.html.erb +1 -0
- data/pg_layout/app/views/layouts/pg_layout/base.html.slim +7 -5
- data/pg_layout/app/views/pg_layout/_navbar.html.erb +7 -6
- data/pg_layout/app/views/pg_layout/_sidebar.html.erb +2 -20
- data/pg_layout/app/views/pg_layout/_signed_in_links.html.slim +52 -0
- data/pg_layout/lib/pg_layout.rb +0 -5
- data/pg_rails/lib/pg_rails/pundit_matchers.rb +21 -0
- data/pg_rails/lib/pg_rails/tpath_support.rb +73 -0
- data/pg_rails/lib/pg_rails.rb +6 -0
- data/pg_rails/lib/version.rb +1 -1
- data/pg_rails/scss/pg_rails.scss +1 -1
- data/pg_scaffold/lib/generators/pg_rspec/scaffold/templates/controller_spec.rb +1 -1
- data/pg_scaffold/lib/generators/pg_slim/templates/index.html.slim +1 -1
- metadata +43 -9
- data/pg_engine/app/controllers/concerns/pg_engine/require_tenant_set.rb +0 -15
- data/pg_engine/app/controllers/users/account_switcher_controller.rb +0 -30
- data/pg_engine/app/controllers/users/inline_edit_controller.rb +0 -21
- data/pg_engine/app/views/users/account_switcher/list.html.slim +0 -24
- data/pg_engine/app/views/users/dashboard/dashboard.html.slim +0 -1
- data/pg_engine/spec/requests/users/switcher_spec.rb +0 -84
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Users
|
|
2
2
|
class RegistrationsController < Devise::RegistrationsController
|
|
3
3
|
before_action do
|
|
4
|
+
@sidebar = false
|
|
4
5
|
authorize resource, nil, policy_class: UserRegistrationPolicy
|
|
5
6
|
end
|
|
6
7
|
|
|
@@ -11,6 +12,7 @@ module Users
|
|
|
11
12
|
resource.save
|
|
12
13
|
yield resource if block_given?
|
|
13
14
|
if resource.persisted?
|
|
15
|
+
# FIXME: no va más
|
|
14
16
|
create_account_for(resource) if ActsAsTenant.current_tenant.blank?
|
|
15
17
|
|
|
16
18
|
expire_data_after_sign_in!
|
|
@@ -35,8 +37,7 @@ module Users
|
|
|
35
37
|
private
|
|
36
38
|
|
|
37
39
|
def create_account_for(user)
|
|
38
|
-
|
|
39
|
-
user.user_accounts.create!(account:)
|
|
40
|
+
Account.create!(nombre: user.email, creado_por: user)
|
|
40
41
|
end
|
|
41
42
|
end
|
|
42
43
|
end
|
|
@@ -13,4 +13,22 @@ class AccountDecorator < PgEngine::BaseRecordDecorator
|
|
|
13
13
|
# object.created_at.strftime("%a %m/%d/%y")
|
|
14
14
|
# end
|
|
15
15
|
# end
|
|
16
|
+
def extra_actions(*)
|
|
17
|
+
return if Current.namespace == :admin
|
|
18
|
+
|
|
19
|
+
ua = Current.user.user_account_for(object).decorate
|
|
20
|
+
[ua.ingresar_link,
|
|
21
|
+
ua.accept_invitation_link,
|
|
22
|
+
ua.reject_invitation_link].compact.join.html_safe
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# def show_link(text: '', klass: 'btn-light')
|
|
26
|
+
# return unless Pundit.policy!(Current.user, object).show?
|
|
27
|
+
|
|
28
|
+
# helpers.content_tag :span, 'data-controller': :tooltip, title: 'Más opciones' do
|
|
29
|
+
# helpers.link_to object_url, class: "btn btn-sm #{klass}" do
|
|
30
|
+
# helpers.content_tag(:span, nil, class: clase_icono('list')) + text
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
16
34
|
end
|
|
@@ -65,8 +65,16 @@ module PgEngine
|
|
|
65
65
|
return unless Pundit.policy!(Current.user, object).destroy?
|
|
66
66
|
|
|
67
67
|
helpers.content_tag :span, rel: :tooltip, title: 'Eliminar definitivamente' do
|
|
68
|
+
# :nocov:
|
|
69
|
+
confirm_key = if Rails.env.development?
|
|
70
|
+
'noconfirm'
|
|
71
|
+
else
|
|
72
|
+
'turbo-confirm'
|
|
73
|
+
end
|
|
74
|
+
# :nocov:
|
|
75
|
+
|
|
68
76
|
helpers.link_to object_url + (land_on.present? ? "?land_on=#{land_on}" : ''),
|
|
69
|
-
data: {
|
|
77
|
+
data: { "#{confirm_key}": confirm_text, 'turbo-method': :delete },
|
|
70
78
|
class: "btn btn-sm #{klass} text-danger" do
|
|
71
79
|
helpers.content_tag :span, nil, class: clase_icono('trash-fill')
|
|
72
80
|
end
|
|
@@ -5,15 +5,80 @@
|
|
|
5
5
|
class UserAccountDecorator < PgEngine::BaseRecordDecorator
|
|
6
6
|
delegate_all
|
|
7
7
|
|
|
8
|
-
def
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
def ingresar_link
|
|
9
|
+
return unless Pundit.policy!(Current.user, object).ingresar?
|
|
10
|
+
|
|
11
|
+
h.link_to h.tenant_root_path(tid: object.to_param),
|
|
12
|
+
'data-turbo-frame': :_top,
|
|
13
|
+
class: 'btn btn-sm btn-primary' do
|
|
14
|
+
'<i class="bi bi-box-arrow-in-right"></i> Ingresar'.html_safe
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def accept_invitation_link
|
|
19
|
+
return unless Pundit.policy!(Current.user, object).accept_invitation_link?
|
|
20
|
+
|
|
21
|
+
h.link_to [:update_invitation, :users, account, { accept: 1 }].flatten,
|
|
22
|
+
'data-turbo-method': :put,
|
|
23
|
+
class: 'btn btn-sm btn-success' do
|
|
24
|
+
'Aceptar invitación'
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def reject_invitation_link
|
|
29
|
+
return unless Pundit.policy!(Current.user, object).accept_invitation_link?
|
|
30
|
+
|
|
31
|
+
h.link_to [:update_invitation, :users, account, { reject: 1 }].flatten,
|
|
32
|
+
'data-turbo-method': :put,
|
|
33
|
+
class: 'btn btn-sm btn-danger' do
|
|
34
|
+
'Rechazar'
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def sign_off_link
|
|
39
|
+
return unless Pundit.policy!(Current.user, object).sign_off?
|
|
40
|
+
|
|
41
|
+
h.link_to [:update_invitation, :users, account, { sign_off: 1 }].flatten,
|
|
42
|
+
'data-turbo-method': :put,
|
|
43
|
+
class: 'btn btn-sm btn-outline-danger' do
|
|
44
|
+
'Dejar la cuenta'
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def estado_f
|
|
49
|
+
membership_status_f + ' - ' + invitation_status_f
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def membership_status_f
|
|
53
|
+
klass = {
|
|
54
|
+
'ms_active' => 'text-success',
|
|
55
|
+
'ms_disabled' => 'text-danger'
|
|
56
|
+
}[object.membership_status]
|
|
57
|
+
|
|
58
|
+
content_tag :span, object.membership_status_text, class: "#{klass} fw-bold"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def invitation_status_f
|
|
62
|
+
klass = {
|
|
63
|
+
'ist_accepted' => 'text-success',
|
|
64
|
+
'ist_invited' => 'text-warning-emphasis',
|
|
65
|
+
'ist_rejected' => 'text-danger',
|
|
66
|
+
'ist_signed_off' => 'text-danger'
|
|
67
|
+
}[object.invitation_status]
|
|
68
|
+
|
|
69
|
+
content_tag :span, object.invitation_status_text, class: "#{klass} fw-bold"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def profiles_f
|
|
73
|
+
return if object.profiles.account__owner?
|
|
74
|
+
|
|
75
|
+
# object.profiles.texts.join(', ')
|
|
76
|
+
PgEngine.config.profile_groups_options.map do |profile_group|
|
|
77
|
+
"<b>#{I18n.t(profile_group[:name], scope: 'profile_group')}: </b>" + h.show_profiles_for(object, profile_group)
|
|
78
|
+
end.join('. ').html_safe
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def user_email_f
|
|
82
|
+
user.email
|
|
83
|
+
end
|
|
19
84
|
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
module PgEngine
|
|
2
|
+
module AccountsHelper
|
|
3
|
+
def show_profiles_for(user_account, profile_group)
|
|
4
|
+
aux = profile_group[:options].select { |opt| user_account.profiles.include?(opt.first) }
|
|
5
|
+
aux = aux.map(&:last).map { |pr| t(pr, scope: 'profile_member') }.join(', ').html_safe
|
|
6
|
+
aux.presence || 'No'
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
@@ -32,6 +32,18 @@ module PgEngine
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def embed_index(object, key)
|
|
35
|
+
reflection = object.class.reflect_on_all_associations.find do |a|
|
|
36
|
+
a.name == key.to_sym
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if reflection.blank?
|
|
40
|
+
# :nocov:
|
|
41
|
+
raise PgEngine::Error, "#{key} not an association for #{object.class}"
|
|
42
|
+
# :nocov:
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
return unless policy(reflection.klass).index?
|
|
46
|
+
|
|
35
47
|
content_tag(:div, 'data-controller': 'embedded-frame') do
|
|
36
48
|
turbo_frame_tag "embedded--#{key}",
|
|
37
49
|
refresh: :morph, src: url_for([pg_namespace, object, key]) do
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module PgEngine
|
|
2
|
+
module DefaultUrlOptions
|
|
3
|
+
# Aunque parece intuitivo que se podría definir solamente url_options,
|
|
4
|
+
# es importante que default_url_options también esté definido
|
|
5
|
+
def url_options
|
|
6
|
+
if Current.active_user_account
|
|
7
|
+
super.merge(tid: Current.active_user_account.to_param)
|
|
8
|
+
else
|
|
9
|
+
super.merge(tid: nil)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def default_url_options
|
|
14
|
+
if Current.active_user_account
|
|
15
|
+
{ tid: Current.active_user_account.to_param }
|
|
16
|
+
else
|
|
17
|
+
{ tid: nil }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -24,7 +24,7 @@ class Account < ApplicationRecord
|
|
|
24
24
|
include Discard::Model
|
|
25
25
|
include Hashid::Rails
|
|
26
26
|
|
|
27
|
-
has_many :user_accounts
|
|
27
|
+
has_many :user_accounts, dependent: :destroy
|
|
28
28
|
has_many :users, through: :user_accounts
|
|
29
29
|
|
|
30
30
|
belongs_to :creado_por, optional: true, class_name: 'User'
|
|
@@ -36,15 +36,42 @@ class Account < ApplicationRecord
|
|
|
36
36
|
|
|
37
37
|
has_many :audits, dependent: :nullify, class_name: 'Audited::Audit'
|
|
38
38
|
|
|
39
|
+
has_one_attached :logo do |attachable|
|
|
40
|
+
attachable.variant :thumb, resize_and_pad: [80, 80]
|
|
41
|
+
end
|
|
42
|
+
|
|
39
43
|
ransacker :search do |parent|
|
|
40
44
|
parent.table[:nombre]
|
|
41
45
|
end
|
|
42
46
|
|
|
47
|
+
after_create do
|
|
48
|
+
if creado_por.present?
|
|
49
|
+
ActsAsTenant.without_tenant do
|
|
50
|
+
user_accounts.create!(account: self, user: creado_por, profiles: [:account__owner])
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
43
55
|
before_validation do
|
|
44
56
|
self.plan = 0 if plan.blank?
|
|
45
57
|
end
|
|
46
58
|
|
|
59
|
+
def self.gender
|
|
60
|
+
'm'
|
|
61
|
+
end
|
|
62
|
+
|
|
47
63
|
def to_s
|
|
48
64
|
nombre
|
|
49
65
|
end
|
|
66
|
+
|
|
67
|
+
# There can be only one
|
|
68
|
+
def owner
|
|
69
|
+
@owner ||= ActsAsTenant.without_tenant do
|
|
70
|
+
user_accounts.ua_active.owners.first&.user
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
raise PgEngine::Error, 'orphan account' if @owner.nil?
|
|
74
|
+
|
|
75
|
+
@owner
|
|
76
|
+
end
|
|
50
77
|
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module PgEngine
|
|
2
|
+
module ChildRecord
|
|
3
|
+
extend ActiveSupport::Concern
|
|
4
|
+
|
|
5
|
+
included do
|
|
6
|
+
scope :kept, -> { undiscarded.joins(klass.parent_accessor).merge(klass.parent_klass.kept) }
|
|
7
|
+
scope :unkept, -> { discarded.joins(klass.parent_accessor).or(klass.parent_klass.discarded) }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class_methods do
|
|
11
|
+
attr_accessor :parent_accessor
|
|
12
|
+
|
|
13
|
+
def parent_klass
|
|
14
|
+
if parent_accessor.blank?
|
|
15
|
+
# :nocov:
|
|
16
|
+
raise PgEngine::Error, 'parent_accessor must be present'
|
|
17
|
+
# :nocov:
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
reflection = reflect_on_all_associations.select { |r| r.name == parent_accessor.to_sym }.first
|
|
21
|
+
if reflection.blank?
|
|
22
|
+
# :nocov:
|
|
23
|
+
raise PgEngine::Error, "#{parent_accessor} not an association on #{self}"
|
|
24
|
+
# :nocov:
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
reflection.klass
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def parent?
|
|
32
|
+
if self.class.parent_accessor.blank?
|
|
33
|
+
# :nocov:
|
|
34
|
+
raise PgEngine::Error, 'parent_accessor must be present'
|
|
35
|
+
# :nocov:
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
true
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def parent
|
|
42
|
+
if self.class.parent_accessor.blank?
|
|
43
|
+
# :nocov:
|
|
44
|
+
raise PgEngine::Error, 'parent_accessor must be present'
|
|
45
|
+
# :nocov:
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
send(self.class.parent_accessor)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def kept?
|
|
52
|
+
undiscarded? && (parent.blank? || parent.kept?)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -1,14 +1,40 @@
|
|
|
1
1
|
class Current < ActiveSupport::CurrentAttributes
|
|
2
|
-
attribute :
|
|
2
|
+
attribute :user, :namespace, :controller, :active_user_account
|
|
3
3
|
# attribute :request_id, :user_agent, :ip_address
|
|
4
4
|
|
|
5
5
|
# resets { Time.zone = nil }
|
|
6
|
+
def active_user_account
|
|
7
|
+
# Para los jobs
|
|
8
|
+
if attributes[:active_user_account].nil? && user.present? && account.present?
|
|
9
|
+
attributes[:active_user_account] = user.active_user_account_for(account)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def tid
|
|
16
|
+
active_user_account.to_param
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def active_user_profiles
|
|
20
|
+
if active_user_account.present?
|
|
21
|
+
active_user_account.profiles
|
|
22
|
+
else
|
|
23
|
+
[]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def user_account_owner?
|
|
28
|
+
active_user_profiles.include?('account__owner')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def account
|
|
32
|
+
ActsAsTenant.current_tenant
|
|
33
|
+
end
|
|
6
34
|
|
|
7
35
|
# def user=(user)
|
|
8
36
|
# super
|
|
9
37
|
#
|
|
10
38
|
# Time.zone = user.time_zone
|
|
11
39
|
# end
|
|
12
|
-
|
|
13
|
-
deprecate :account, deprecator: PgEngine.deprecator
|
|
14
40
|
end
|
|
@@ -29,24 +29,49 @@
|
|
|
29
29
|
#
|
|
30
30
|
|
|
31
31
|
class User < ApplicationRecord
|
|
32
|
+
default_scope lambda {
|
|
33
|
+
if Current.namespace == :tenant
|
|
34
|
+
if ActsAsTenant.unscoped?
|
|
35
|
+
all
|
|
36
|
+
else
|
|
37
|
+
ids = Current.account.user_accounts.ua_active.pluck(:user_id)
|
|
38
|
+
# ids = ids.push(Current.user.id) ?
|
|
39
|
+
where(id: ids)
|
|
40
|
+
end
|
|
41
|
+
else
|
|
42
|
+
all
|
|
43
|
+
end
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
devise :database_authenticatable, :registerable,
|
|
33
47
|
:recoverable, :rememberable,
|
|
34
|
-
:lockable, :timeoutable, :trackable, :confirmable
|
|
48
|
+
:lockable, :timeoutable, :trackable, :confirmable, :invitable
|
|
35
49
|
|
|
36
50
|
audited
|
|
37
51
|
include Discard::Model
|
|
38
52
|
|
|
39
53
|
has_many :user_accounts, dependent: :destroy
|
|
54
|
+
accepts_nested_attributes_for :user_accounts
|
|
40
55
|
|
|
41
56
|
# Hace falta?
|
|
42
57
|
has_many :accounts, through: :user_accounts
|
|
43
58
|
|
|
44
|
-
|
|
59
|
+
# Crea automáticamente una user_account on create
|
|
60
|
+
# a menos que ya exista en los nested attributes una user
|
|
61
|
+
# account para la current tenant
|
|
62
|
+
#
|
|
63
|
+
# Es problemático porque interfiere en UserAccount.joins(:user)
|
|
64
|
+
# y hace un doble join
|
|
65
|
+
# acts_as_tenant :account, through: :user_accounts
|
|
45
66
|
|
|
46
67
|
has_many :notifications, as: :recipient, class_name: 'Noticed::Notification'
|
|
47
68
|
|
|
48
69
|
validates :nombre, :apellido, presence: true
|
|
49
70
|
|
|
71
|
+
has_one_attached :avatar do |attachable|
|
|
72
|
+
attachable.variant :thumb, resize_to_fill: [80, 80]
|
|
73
|
+
end
|
|
74
|
+
|
|
50
75
|
validates_presence_of :email
|
|
51
76
|
validates_uniqueness_of :email, message: 'ya pertenece a un usuario'
|
|
52
77
|
validates_format_of :email, with: /\A[^@\s]+@[^@\s]+\z/
|
|
@@ -59,6 +84,11 @@ class User < ApplicationRecord
|
|
|
59
84
|
message: 'Para crear una cuenta es necesario que aceptes los términos y condiciones'
|
|
60
85
|
}
|
|
61
86
|
|
|
87
|
+
# When the user is invited via Devise Invitable
|
|
88
|
+
before_invitation_created do
|
|
89
|
+
user_accounts.first.invitation_status = :ist_invited
|
|
90
|
+
end
|
|
91
|
+
|
|
62
92
|
attr_accessor :orphan
|
|
63
93
|
|
|
64
94
|
def active_for_authentication?
|
|
@@ -93,7 +123,7 @@ class User < ApplicationRecord
|
|
|
93
123
|
end
|
|
94
124
|
|
|
95
125
|
def to_s
|
|
96
|
-
nombre_completo
|
|
126
|
+
nombre_completo.strip.presence || email
|
|
97
127
|
end
|
|
98
128
|
|
|
99
129
|
def nombre_completo
|
|
@@ -102,22 +132,34 @@ class User < ApplicationRecord
|
|
|
102
132
|
|
|
103
133
|
class Error < PgEngine::Error; end
|
|
104
134
|
|
|
105
|
-
def
|
|
106
|
-
|
|
107
|
-
user_accounts.to_a
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def default_account
|
|
112
|
-
raise Error, 'El usuario debe tener cuenta' if accounts.empty?
|
|
135
|
+
# def default_account
|
|
136
|
+
# raise Error, 'El usuario debe tener cuenta' if accounts.empty?
|
|
113
137
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
end
|
|
138
|
+
# user_accounts.first.account
|
|
139
|
+
# # throw :warden, scope: :user, message: :user_not_belongs_to_account
|
|
140
|
+
# end
|
|
117
141
|
|
|
118
142
|
deprecate :current_account, deprecator: PgEngine.deprecator
|
|
119
143
|
|
|
120
144
|
def current_account
|
|
121
145
|
ActsAsTenant.current_tenant
|
|
122
146
|
end
|
|
147
|
+
|
|
148
|
+
def active_user_account_for(account)
|
|
149
|
+
user_account_for(account, active: true)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def user_account_for(account, active: false)
|
|
153
|
+
if account.nil?
|
|
154
|
+
# :nocov:
|
|
155
|
+
raise PgEngine::Error, 'account must be present'
|
|
156
|
+
# :nocov:
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
scope_name = active ? :ua_active : :kept
|
|
160
|
+
|
|
161
|
+
ActsAsTenant.without_tenant do
|
|
162
|
+
user_accounts.send(scope_name).where(account:).first
|
|
163
|
+
end
|
|
164
|
+
end
|
|
123
165
|
end
|
|
@@ -21,24 +21,89 @@
|
|
|
21
21
|
# fk_rails_... (user_id => users.id)
|
|
22
22
|
#
|
|
23
23
|
|
|
24
|
-
# FIXME: add column active?
|
|
25
24
|
class UserAccount < ApplicationRecord
|
|
26
25
|
audited
|
|
27
26
|
include Hashid::Rails
|
|
28
27
|
|
|
28
|
+
# self.inline_editable_fields = %i[profiles]
|
|
29
|
+
self.default_modal = true
|
|
30
|
+
|
|
29
31
|
belongs_to :user, inverse_of: :user_accounts
|
|
32
|
+
|
|
30
33
|
acts_as_tenant :account
|
|
31
34
|
|
|
35
|
+
def self.gender
|
|
36
|
+
'f'
|
|
37
|
+
end
|
|
38
|
+
|
|
32
39
|
belongs_to :creado_por, optional: true, class_name: 'User'
|
|
33
40
|
belongs_to :actualizado_por, optional: true, class_name: 'User'
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
validates :user_id, uniqueness: { scope: :account_id }
|
|
43
|
+
|
|
44
|
+
after_destroy :cleanup_invitation
|
|
45
|
+
def cleanup_invitation
|
|
46
|
+
usr = User.unscoped.find(user_id)
|
|
47
|
+
return unless usr.invited_to_sign_up? && !usr.confirmed?
|
|
48
|
+
return if usr.destroy
|
|
49
|
+
# :nocov:
|
|
50
|
+
|
|
51
|
+
pg_err 'User couldnt be deleted on invitation cleanup'
|
|
52
|
+
# :nocov:
|
|
53
|
+
end
|
|
54
|
+
# El problema está en el joins(:user), ya que la default scope de user está scopeada dentro
|
|
55
|
+
# del current_tenant entonces vuelve sobre la tabla user_accounts y bardea
|
|
56
|
+
#
|
|
57
|
+
# Tengo que escribir el user joins a mano porque de lo contrario sumaría la default_scope de
|
|
58
|
+
# User, que a su vez joinea con user_accounts
|
|
59
|
+
USER_JOINS = 'INNER JOIN users ON users.id = user_accounts.user_id'
|
|
60
|
+
scope :kept, -> { joins(USER_JOINS, :account).merge(Account.kept).merge(User.unscoped.kept) }
|
|
61
|
+
|
|
62
|
+
scope :ua_active, lambda {
|
|
63
|
+
kept.where(membership_status: :ms_active, invitation_status: :ist_accepted)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
OWNERS_PREDICATE = lambda do
|
|
67
|
+
UserAccount.arel_table[:profiles].contains([UserAccount.profiles.account__owner.value])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
scope :owners, lambda {
|
|
71
|
+
where(OWNERS_PREDICATE.call)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
scope :regulars, lambda {
|
|
75
|
+
where.not(OWNERS_PREDICATE.call)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Se usa en schema.rb, default: 1
|
|
79
|
+
enumerize :membership_status, in: {
|
|
80
|
+
ms_active: 1,
|
|
81
|
+
ms_disabled: 2
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Se usa en schema.rb, default: 1
|
|
85
|
+
enumerize :invitation_status, in: {
|
|
86
|
+
ist_accepted: 1,
|
|
87
|
+
ist_invited: 2,
|
|
88
|
+
ist_rejected: 3,
|
|
89
|
+
ist_signed_off: 4
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
scope :not_discarded_by_user, -> { where.not(invitation_status: %i[ist_rejected ist_signed_off]) }
|
|
93
|
+
|
|
94
|
+
def discarded_by_user?
|
|
95
|
+
invitation_status.ist_rejected? || invitation_status.ist_signed_off?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def ua_active?
|
|
99
|
+
invitation_status.ist_accepted? && membership_status.ms_active?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def ua_invite_pending?
|
|
103
|
+
invitation_status.ist_invited? && membership_status.ms_active?
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
enumerize :profiles, in: PgEngine.configuracion.user_profiles, multiple: true
|
|
38
107
|
|
|
39
|
-
|
|
40
|
-
administracion: 1,
|
|
41
|
-
operacion: 2,
|
|
42
|
-
lectura: 3
|
|
43
|
-
}, multiple: true
|
|
108
|
+
delegate :to_s, to: :user
|
|
44
109
|
end
|
|
@@ -4,37 +4,56 @@
|
|
|
4
4
|
|
|
5
5
|
class AccountPolicy < ApplicationPolicy
|
|
6
6
|
class Scope < ApplicationPolicy::Scope
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
def resolve
|
|
8
|
+
if Current.namespace == :admin
|
|
9
|
+
scope.all
|
|
10
|
+
else
|
|
11
|
+
ary = ActsAsTenant.without_tenant do
|
|
12
|
+
Current.user.user_accounts.kept.not_discarded_by_user.pluck(:account_id)
|
|
13
|
+
end
|
|
14
|
+
scope.where(id: ary)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def update_invitation?
|
|
20
|
+
user_belongs_to_account?
|
|
14
21
|
end
|
|
15
22
|
|
|
16
23
|
def puede_editar?
|
|
17
|
-
user
|
|
24
|
+
Current.namespace == :admin || record.owner == Current.user
|
|
18
25
|
end
|
|
19
26
|
|
|
20
27
|
def puede_crear?
|
|
21
|
-
user.
|
|
28
|
+
user.present?
|
|
22
29
|
end
|
|
23
30
|
|
|
24
31
|
def puede_borrar?
|
|
25
|
-
|
|
32
|
+
Current.namespace == :admin
|
|
26
33
|
end
|
|
27
34
|
|
|
28
|
-
# def acceso_total?
|
|
29
|
-
# user.developer?
|
|
30
|
-
# end
|
|
31
|
-
|
|
32
35
|
def new_from_associable?
|
|
33
36
|
false
|
|
34
37
|
end
|
|
35
38
|
|
|
39
|
+
def show?
|
|
40
|
+
base_access_to_record?
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def index?
|
|
44
|
+
base_access_to_collection?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def base_access_to_collection?
|
|
48
|
+
user.present?
|
|
49
|
+
end
|
|
50
|
+
|
|
36
51
|
def base_access_to_record?
|
|
37
|
-
|
|
38
|
-
|
|
52
|
+
ua = user.user_account_for(record)
|
|
53
|
+
Current.namespace == :admin || (ua.present? && !ua.ua_invite_pending?)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def user_belongs_to_account?
|
|
57
|
+
user.user_account_for(record).present?
|
|
39
58
|
end
|
|
40
59
|
end
|