pg_rails 7.6.20 → 7.6.21.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 +21 -3
- data/pg_engine/app/models/pg_engine/base_record.rb +5 -0
- data/pg_engine/app/models/user.rb +51 -9
- 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 +6 -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,32 @@
|
|
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
6
|
|
7
|
+
def tid
|
8
|
+
active_user_account.to_param
|
9
|
+
end
|
10
|
+
|
11
|
+
def active_user_profiles
|
12
|
+
if active_user_account.present?
|
13
|
+
active_user_account.profiles
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def user_account_owner?
|
20
|
+
active_user_profiles.include?('account__owner')
|
21
|
+
end
|
22
|
+
|
23
|
+
def account
|
24
|
+
ActsAsTenant.current_tenant
|
25
|
+
end
|
26
|
+
|
7
27
|
# def user=(user)
|
8
28
|
# super
|
9
29
|
#
|
10
30
|
# Time.zone = user.time_zone
|
11
31
|
# end
|
12
|
-
|
13
|
-
deprecate :account, deprecator: PgEngine.deprecator
|
14
32
|
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,12 +132,6 @@ class User < ApplicationRecord
|
|
102
132
|
|
103
133
|
class Error < PgEngine::Error; end
|
104
134
|
|
105
|
-
def user_accounts_without_tenant
|
106
|
-
ActsAsTenant.without_tenant do
|
107
|
-
user_accounts.to_a
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
135
|
def default_account
|
112
136
|
raise Error, 'El usuario debe tener cuenta' if accounts.empty?
|
113
137
|
|
@@ -120,4 +144,22 @@ class User < ApplicationRecord
|
|
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
|