effective_organizations 0.0.2 → 0.0.6
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/README.md +71 -2
- data/app/datatables/effective_representatives_datatable.rb +15 -2
- data/app/models/concerns/effective_organizations_organization.rb +19 -3
- data/app/models/concerns/effective_organizations_user.rb +9 -2
- data/app/models/effective/organization.rb +1 -0
- data/app/models/effective/representative.rb +9 -3
- data/app/views/admin/organizations/_fields.html.haml +6 -0
- data/app/views/admin/organizations/_form_organization.html.haml +2 -7
- data/app/views/admin/representatives/_form.html.haml +4 -3
- data/app/views/effective/organizations/_fields.html.haml +6 -0
- data/app/views/effective/organizations/_form_organization.html.haml +2 -7
- data/app/views/effective/representatives/_form.html.haml +4 -3
- data/db/migrate/01_create_effective_organizations.rb.erb +1 -2
- data/lib/effective_organizations/version.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2ee1cb9ffc7df883ea343966168245ab3d77ba59ef9753a20d825702ba46aaa
|
4
|
+
data.tar.gz: fcd8f65d9dbc66c5073077e6bd7fe9f48774c4444d965c7c4ce95d09c3d97935
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a34485e30e3d66f85cb4dff1ed2ccd6656134ac5171c2ceae64e8fc30336144c1ac6c9889dab98b018dbdad0c2b3bda96e583f70583a9907f09eaf1ed4ebe1a0
|
7
|
+
data.tar.gz: fb7e677000619da597b0b43f5ae827211d2d55fca0d51326559b27bb7fc7fbd7b3155260afa37f7768360a0f695d2d80667dabc680414f2479582c645c438dac
|
data/README.md
CHANGED
@@ -71,16 +71,85 @@ Add a link to the admin menu:
|
|
71
71
|
|
72
72
|
All authorization checks are handled via the effective_resources gem found in the `config/initializers/effective_resources.rb` file.
|
73
73
|
|
74
|
+
## Effective Roles
|
75
|
+
|
76
|
+
This gem works with effective roles for the representative roles.
|
77
|
+
|
78
|
+
Configure your `config/initializers/effective_roles.rb` something like this:
|
79
|
+
|
80
|
+
```
|
81
|
+
EffectiveRoles.setup(:caaa) do |config|
|
82
|
+
config.roles = [:admin, :reserved, :owner, :billing] # Only add to the end of this array. Never prepend roles.
|
83
|
+
|
84
|
+
# config.role_descriptions
|
85
|
+
# ========================
|
86
|
+
# This setting configures the text that is displayed by form helpers (see README.md)
|
87
|
+
|
88
|
+
config.role_descriptions = {
|
89
|
+
'User' => {
|
90
|
+
# User roles
|
91
|
+
admin: 'can log in to the /admin section of the website. full access to everything.',
|
92
|
+
},
|
93
|
+
'Effective::Representative' => {
|
94
|
+
owner: 'the owner. full access to everything.',
|
95
|
+
billing: 'the billing contact. full access to everything.'
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
99
|
+
# config.assignable_roles
|
100
|
+
# Which roles can be assigned by whom
|
101
|
+
# =======================
|
102
|
+
# When current_user is passed into a form helper function (see README.md)
|
103
|
+
# this setting determines which roles that current_user may assign
|
104
|
+
config.assignable_roles = {
|
105
|
+
'User' => { admin: [:admin] },
|
106
|
+
|
107
|
+
'Effective::Representative' => {
|
108
|
+
admin: [:owner, :billing],
|
109
|
+
owner: [:owner, :billing],
|
110
|
+
billing: [:billing]
|
111
|
+
}
|
112
|
+
}
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
116
|
+
|
74
117
|
## Permissions
|
75
118
|
|
76
119
|
The permissions you actually want to define are as follows (using CanCan):
|
77
120
|
|
78
121
|
```ruby
|
122
|
+
if user.persisted?
|
123
|
+
can :index, EffectiveOrganizations.Organization
|
124
|
+
can(:show, EffectiveOrganizations.Organization) { |organization| user.organizations.include?(organization) }
|
125
|
+
|
126
|
+
can([:edit, :update], EffectiveOrganizations.Organization) do |organization|
|
127
|
+
rep = user.representative(organization: organization)
|
128
|
+
rep && (rep.is?(:owner) || rep.is?(:billing))
|
129
|
+
end
|
130
|
+
|
131
|
+
can :index, Effective::Representative
|
132
|
+
can(:new, Effective::Representative)
|
133
|
+
|
134
|
+
can([:create, :edit, :update], Effective::Representative) do |representative|
|
135
|
+
rep = user.representative(organization: representative.organization)
|
136
|
+
rep && (rep.is?(:owner) || rep.is?(:billing))
|
137
|
+
end
|
138
|
+
|
139
|
+
can(:destroy, Effective::Representative) do |representative|
|
140
|
+
allowed = !(representative.is?(:owner) || representative.is?(:billing))
|
141
|
+
rep = user.representative(organization: representative.organization)
|
142
|
+
|
143
|
+
allowed && rep && (rep.is?(:owner) || rep.is?(:billing))
|
144
|
+
end
|
145
|
+
end
|
79
146
|
|
80
147
|
if user.admin?
|
81
148
|
can :admin, :effective_organizations
|
82
|
-
can
|
83
|
-
|
149
|
+
can(crud, EffectiveOrganizations.Organization)
|
150
|
+
|
151
|
+
can(crud - [:destroy], Effective::Representative)
|
152
|
+
can(:destroy, Effective::Representative) { |rep| !rep.is?(:owner) }
|
84
153
|
end
|
85
154
|
```
|
86
155
|
|
@@ -11,11 +11,24 @@ class EffectiveRepresentativesDatatable < Effective::Datatable
|
|
11
11
|
|
12
12
|
col :roles, search: roles_collection
|
13
13
|
|
14
|
-
|
14
|
+
unless attributes[:actions] == false
|
15
|
+
actions_col
|
16
|
+
end
|
17
|
+
|
15
18
|
end
|
16
19
|
|
17
20
|
collection do
|
18
|
-
Effective::Representative.deep.all.where(organization: current_user.organizations)
|
21
|
+
scope = Effective::Representative.deep.all.where(organization: current_user.organizations)
|
22
|
+
|
23
|
+
if attributes[:organization_id]
|
24
|
+
scope = scope.where(organization_id: attributes[:organization_id])
|
25
|
+
end
|
26
|
+
|
27
|
+
if attributes[:user_id]
|
28
|
+
scope = scope.where(user_id: attributes[:user_id])
|
29
|
+
end
|
30
|
+
|
31
|
+
scope
|
19
32
|
end
|
20
33
|
|
21
34
|
def roles_collection
|
@@ -6,7 +6,11 @@ module EffectiveOrganizationsOrganization
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
module Base
|
9
|
-
def effective_organizations_organization
|
9
|
+
def effective_organizations_organization(users_source_type: nil)
|
10
|
+
@effective_organizations_organization_opts = {
|
11
|
+
users_source_type: users_source_type
|
12
|
+
}
|
13
|
+
|
10
14
|
include ::EffectiveOrganizationsOrganization
|
11
15
|
end
|
12
16
|
end
|
@@ -20,7 +24,7 @@ module EffectiveOrganizationsOrganization
|
|
20
24
|
end
|
21
25
|
|
22
26
|
included do
|
23
|
-
log_changes(except: :representatives) if respond_to?(:log_changes)
|
27
|
+
log_changes(except: [:representatives, :users]) if respond_to?(:log_changes)
|
24
28
|
|
25
29
|
# rich_text_body
|
26
30
|
# has_many_rich_texts
|
@@ -28,7 +32,10 @@ module EffectiveOrganizationsOrganization
|
|
28
32
|
has_many :representatives, -> { Effective::Representative.sorted },
|
29
33
|
class_name: 'Effective::Representative', inverse_of: :organization, dependent: :delete_all
|
30
34
|
|
31
|
-
|
35
|
+
accepts_nested_attributes_for :representatives, allow_destroy: true
|
36
|
+
|
37
|
+
has_many :users, through: :representatives,
|
38
|
+
source_type: (@effective_organizations_organization_opts[:users_source_type] || (name.start_with?('Effective') ? '::User' : "#{name.split('::').first}::Organization"))
|
32
39
|
|
33
40
|
effective_resource do
|
34
41
|
title :string
|
@@ -53,4 +60,13 @@ module EffectiveOrganizationsOrganization
|
|
53
60
|
title.presence || 'New Organization'
|
54
61
|
end
|
55
62
|
|
63
|
+
def representative(user:)
|
64
|
+
representatives.find { |rep| rep.user_id == user.id }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Find or build
|
68
|
+
def build_representative(user:)
|
69
|
+
representative(user: user) || representatives.build(user: user)
|
70
|
+
end
|
71
|
+
|
56
72
|
end
|
@@ -6,7 +6,11 @@ module EffectiveOrganizationsUser
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
module Base
|
9
|
-
def effective_organizations_user
|
9
|
+
def effective_organizations_user(organizations_source_type: nil)
|
10
|
+
@effective_organizations_user_opts = {
|
11
|
+
organizations_source_type: organizations_source_type
|
12
|
+
}
|
13
|
+
|
10
14
|
include ::EffectiveOrganizationsUser
|
11
15
|
end
|
12
16
|
end
|
@@ -20,8 +24,11 @@ module EffectiveOrganizationsUser
|
|
20
24
|
has_many :representatives, -> { Effective::Representative.sorted },
|
21
25
|
class_name: 'Effective::Representative', inverse_of: :user, dependent: :delete_all
|
22
26
|
|
27
|
+
accepts_nested_attributes_for :representatives, allow_destroy: true
|
28
|
+
|
23
29
|
# App scoped
|
24
|
-
has_many :organizations, through: :representatives
|
30
|
+
has_many :organizations, through: :representatives,
|
31
|
+
source_type: @effective_organizations_user_opts[:organizations_source_type] || "#{name.split('::').first}::Organization"
|
25
32
|
end
|
26
33
|
|
27
34
|
def representative(organization:)
|
@@ -7,9 +7,10 @@ module Effective
|
|
7
7
|
|
8
8
|
log_changes(to: :organization) if respond_to?(:log_changes)
|
9
9
|
|
10
|
-
belongs_to :organization, counter_cache: true
|
10
|
+
belongs_to :organization, polymorphic: true, counter_cache: true
|
11
11
|
belongs_to :user, polymorphic: true
|
12
12
|
|
13
|
+
accepts_nested_attributes_for :organization
|
13
14
|
accepts_nested_attributes_for :user
|
14
15
|
|
15
16
|
effective_resource do
|
@@ -28,8 +29,8 @@ module Effective
|
|
28
29
|
validates :organization, presence: true
|
29
30
|
validates :user, presence: true
|
30
31
|
|
31
|
-
validates :user_id, if: -> { user_id && user_type && organization_id },
|
32
|
-
uniqueness: { scope: [:organization_id], message: 'already belongs to this organization' }
|
32
|
+
validates :user_id, if: -> { user_id && user_type && organization_id && organization_type },
|
33
|
+
uniqueness: { scope: [:organization_id, :organization_type], message: 'already belongs to this organization' }
|
33
34
|
|
34
35
|
def to_s
|
35
36
|
user.to_s
|
@@ -40,5 +41,10 @@ module Effective
|
|
40
41
|
self.user = user_type.constantize.new(attributes)
|
41
42
|
end
|
42
43
|
|
44
|
+
def build_organization(attributes = {})
|
45
|
+
raise('please assign organization_type first') if organization_type.blank?
|
46
|
+
self.organization = organization_type.constantize.new(attributes)
|
47
|
+
end
|
48
|
+
|
43
49
|
end
|
44
50
|
end
|
@@ -1,14 +1,9 @@
|
|
1
1
|
= effective_form_with(model: [:admin, organization], engine: true) do |f|
|
2
|
-
|
3
|
-
|
4
|
-
- if categories.present?
|
5
|
-
= f.select :category, categories, required: true
|
6
|
-
|
7
|
-
= f.text_field :title
|
2
|
+
= render 'admin/organizations/fields', f: f
|
8
3
|
|
9
4
|
= effective_submit(f)
|
10
5
|
|
11
6
|
- if organization.persisted?
|
12
7
|
%h2 Representatives
|
13
|
-
- datatable = Admin::EffectiveRepresentativesDatatable.new(organization_id: organization.id)
|
8
|
+
- datatable = Admin::EffectiveRepresentativesDatatable.new(organization_id: organization.id, organization_type: organization.class.name)
|
14
9
|
= render_inline_datatable(datatable)
|
@@ -4,12 +4,13 @@
|
|
4
4
|
= f.hidden_field :user_id
|
5
5
|
= f.hidden_field :user_type
|
6
6
|
= f.hidden_field :organization_id
|
7
|
+
= f.hidden_field :organization_type
|
7
8
|
|
8
9
|
- if f.object.new_record?
|
9
10
|
- unless inline_datatable? && inline_datatable.attributes[:organization_id].present?
|
10
|
-
= f.select :
|
11
|
+
= f.select :organization, { 'Organizations' => EffectiveOrganizations.Organization.sorted }, polymorphic: true
|
11
12
|
|
12
|
-
= f.checks :roles, EffectiveRoles.roles_collection(f.object)
|
13
|
+
= f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
|
13
14
|
|
14
15
|
- unless inline_datatable? && inline_datatable.attributes[:user_id].present?
|
15
16
|
= f.radios :new_representative_user_action, ['Invite new user', 'Add existing user'], inline: true, label: 'Representative'
|
@@ -28,7 +29,7 @@
|
|
28
29
|
- unless inline_datatable? && inline_datatable.attributes[:user_id].present?
|
29
30
|
= f.static_field :user
|
30
31
|
|
31
|
-
= f.checks :roles, EffectiveRoles.roles_collection(f.object)
|
32
|
+
= f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
|
32
33
|
|
33
34
|
- unless inline_datatable? && inline_datatable.attributes[:user_id].present?
|
34
35
|
= f.fields_for :user, f.object.user do |fu|
|
@@ -1,16 +1,11 @@
|
|
1
1
|
- url = (organization.persisted? ? effective_organizations.organization_path(organization) : effective_organizations.organizations_path)
|
2
2
|
|
3
3
|
= effective_form_with(model: organization, url: url) do |f|
|
4
|
-
|
5
|
-
|
6
|
-
- if categories.present?
|
7
|
-
= f.select :category, categories, required: true
|
8
|
-
|
9
|
-
= f.text_field :title
|
4
|
+
= render 'effective/organizations/fields', f: f
|
10
5
|
|
11
6
|
= f.submit
|
12
7
|
|
13
8
|
- if organization.persisted?
|
14
9
|
%h2 Representatives
|
15
|
-
- datatable = EffectiveRepresentativesDatatable.new(
|
10
|
+
- datatable = EffectiveRepresentativesDatatable.new(organization: organization)
|
16
11
|
= render_inline_datatable(datatable)
|
@@ -4,12 +4,13 @@
|
|
4
4
|
= f.hidden_field :user_id
|
5
5
|
= f.hidden_field :user_type
|
6
6
|
= f.hidden_field :organization_id
|
7
|
+
= f.hidden_field :organization_type
|
7
8
|
|
8
9
|
- if f.object.new_record?
|
9
10
|
- unless inline_datatable? && inline_datatable.attributes[:organization_id].present?
|
10
|
-
= f.select :
|
11
|
+
= f.select :organization, { 'Organizations' => EffectiveOrganizations.Organization.sorted }, polymorphic: true
|
11
12
|
|
12
|
-
= f.checks :roles, EffectiveRoles.roles_collection(f.object)
|
13
|
+
= f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
|
13
14
|
|
14
15
|
- unless inline_datatable? && inline_datatable.attributes[:user_id].present?
|
15
16
|
= f.hidden_field :new_representative_user_action, value: 'Invite new user'
|
@@ -24,7 +25,7 @@
|
|
24
25
|
- unless inline_datatable? && inline_datatable.attributes[:user_id].present?
|
25
26
|
= f.static_field :user
|
26
27
|
|
27
|
-
= f.checks :roles, EffectiveRoles.roles_collection(f.object)
|
28
|
+
= f.checks :roles, EffectiveRoles.roles_collection(f.object, skip_disabled: true)
|
28
29
|
|
29
30
|
= f.fields_for :user, f.object.user do |fu|
|
30
31
|
= render 'effective/representatives/user_fields', f: fu
|
@@ -18,7 +18,6 @@ class CreateEffectiveOrganizations < ActiveRecord::Migration[6.0]
|
|
18
18
|
# Representatives
|
19
19
|
create_table :representatives do |t|
|
20
20
|
t.integer :organization_id
|
21
|
-
t.string :organization_type
|
22
21
|
|
23
22
|
t.integer :user_id
|
24
23
|
t.string :user_type
|
@@ -29,7 +28,7 @@ class CreateEffectiveOrganizations < ActiveRecord::Migration[6.0]
|
|
29
28
|
t.datetime :created_at
|
30
29
|
end
|
31
30
|
|
32
|
-
add_index :representatives, [:organization_id
|
31
|
+
add_index :representatives, [:organization_id]
|
33
32
|
add_index :representatives, [:user_id, :user_type]
|
34
33
|
|
35
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_organizations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
11
|
+
date: 2021-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: effective_roles
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: sqlite3
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,11 +192,13 @@ files:
|
|
178
192
|
- app/models/concerns/effective_organizations_user.rb
|
179
193
|
- app/models/effective/organization.rb
|
180
194
|
- app/models/effective/representative.rb
|
195
|
+
- app/views/admin/organizations/_fields.html.haml
|
181
196
|
- app/views/admin/organizations/_form.html.haml
|
182
197
|
- app/views/admin/organizations/_form_organization.html.haml
|
183
198
|
- app/views/admin/representatives/_form.html.haml
|
184
199
|
- app/views/admin/representatives/_user_fields.html.haml
|
185
200
|
- app/views/effective/organizations/_dashboard.html.haml
|
201
|
+
- app/views/effective/organizations/_fields.html.haml
|
186
202
|
- app/views/effective/organizations/_form.html.haml
|
187
203
|
- app/views/effective/organizations/_form_organization.html.haml
|
188
204
|
- app/views/effective/representatives/_form.html.haml
|