dynamican 0.1.7 → 1.0.1
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 +58 -50
- data/dynamican.gemspec +2 -2
- data/lib/dynamican.rb +5 -3
- data/lib/dynamican/authorization.rb +25 -0
- data/lib/dynamican/evaluator.rb +16 -17
- data/lib/dynamican/model.rb +5 -6
- data/lib/generators/dynamican_migration_generator.rb +53 -0
- data/lib/models/dynamican/action.rb +9 -0
- data/lib/models/dynamican/condition.rb +3 -1
- data/lib/models/dynamican/item.rb +15 -0
- data/lib/models/dynamican/permission.rb +9 -5
- metadata +11 -10
- data/lib/dynamican/configuration.rb +0 -17
- data/lib/models/dynamican/permission_connector.rb +0 -14
- data/migrations/0.1.2/dynamican_create_database_structure.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee2ebd9f3470a7ad1002ee3344a357fc1549e8065dffc09986f9c466577de8a9
|
4
|
+
data.tar.gz: e1cac4d8aa2b6f209dc6885cebe31d9ec5548af8578514aa9bf44fe1836fb697
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63e6761a9fed8385830c6f10697a0448ec08a8e2a781612ac54544ed810635bbfec6006c26e5054b653131a495815c6da5ed1842e11262736f9b1a274c9b0882
|
7
|
+
data.tar.gz: be88310e037fb8cb2e71af8f8616f1441a2963b4b65a6599762e92b6800e30cec6ede2216c5558d2ff8c8ffc7407c94e866c5894a3f8e15c31517dcb213ac5a6
|
data/README.md
CHANGED
@@ -1,30 +1,26 @@
|
|
1
1
|
# Dynamican
|
2
|
-
Dynamican is a flexible gem
|
2
|
+
Dynamican is a flexible gem which introduces permissions on rails applications. It is very customizable because it stores all the rules inside the database and can be added to multiple models: for example you can add permissions to your Role and User models. With a couple of overrides you can also add permissions to both Role and User and allow user to use its roles permissions.
|
3
3
|
|
4
4
|
## Installation
|
5
5
|
Inside your Gemfile put
|
6
6
|
|
7
7
|
gem 'dynamican'
|
8
8
|
|
9
|
-
|
9
|
+
and run `bundle install`, then you can launch the following command.
|
10
10
|
|
11
|
-
|
11
|
+
rails g dynamican_migration
|
12
12
|
|
13
|
-
|
13
|
+
This command will generate a migration file in your project, which you can run with
|
14
14
|
|
15
|
-
|
15
|
+
rails db:migrate
|
16
16
|
|
17
|
-
|
17
|
+
In each model you want to have the feature, just put the following.
|
18
18
|
|
19
|
-
|
20
|
-
role:
|
21
|
-
class_name: 'Role'
|
22
|
-
user:
|
23
|
-
class_name: 'User'
|
19
|
+
include Dynamican::Model
|
24
20
|
|
25
|
-
### Using permissions on
|
21
|
+
### Using a model permissions on another model
|
26
22
|
|
27
|
-
I wanted to have the possibility to assign permissions both directly to my User model and my Role model, so that if the User had one permission and one of its
|
23
|
+
I wanted to have the possibility to assign permissions both directly to my User model and my Role model, so that if the User had one permission and one of its Roles had another, the User could benefit from both. So i included the feature into both models and then decorated my User model like following.
|
28
24
|
|
29
25
|
module Decorators
|
30
26
|
module Models
|
@@ -32,16 +28,11 @@ I wanted to have the possibility to assign permissions both directly to my User
|
|
32
28
|
module DynamicanOverrides
|
33
29
|
def self.prepended(base)
|
34
30
|
base.class_eval do
|
35
|
-
has_many :
|
36
|
-
has_many :user_permissions, class_name: 'Dynamican::Permission', through: :user_permission_connectors, source: :permission
|
31
|
+
has_many :user_permissions, class_name: 'Dynamican::Permission', as: :permittable, inverse_of: :permittable, foreign_key: :permittable_id
|
37
32
|
has_many :role_permissions, through: :roles, class_name: 'Dynamican::Permission', source: :permissions
|
38
33
|
end
|
39
34
|
end
|
40
35
|
|
41
|
-
def permission_connectors
|
42
|
-
Dynamican::PermissionConnector.where(id: user_permission_connectors.ids + roles.map(&:permission_connectors).flatten.map(&:id))
|
43
|
-
end
|
44
|
-
|
45
36
|
def permissions
|
46
37
|
Dynamican::Permission.where(id: user_permissions.ids + role_permissions.ids)
|
47
38
|
end
|
@@ -52,67 +43,84 @@ I wanted to have the possibility to assign permissions both directly to my User
|
|
52
43
|
end
|
53
44
|
end
|
54
45
|
|
55
|
-
I personally have put this in `app/decorators/models/user/dynamican_overrides.rb` (
|
46
|
+
I personally have put this in `app/decorators/models/user/dynamican_overrides.rb` (rails needs to load the folder of course); you can make it work as you please but i recommend to keep it separate from the original User model.
|
56
47
|
|
57
48
|
## Usage
|
58
49
|
|
59
50
|
Now the hard part: the real configuration.
|
60
51
|
|
61
|
-
Create one `Dynamican::
|
52
|
+
Create one `Dynamican::Action` for each action you need. For example i created CRUD permissions.
|
53
|
+
|
54
|
+
a1 = Dynamican::Action.create(name: 'create')
|
55
|
+
a2 = Dynamican::Action.create(name: 'read')
|
56
|
+
a3 = Dynamican::Action.create(name: 'update')
|
57
|
+
a4 = Dynamican::Action.create(name: 'delete')
|
62
58
|
|
63
|
-
|
64
|
-
p2 = Dynamican::Permission.create(action: 'read', object_name: 'order')
|
65
|
-
p3 = Dynamican::Permission.create(action: 'update', object_name: 'order')
|
66
|
-
p4 = Dynamican::Permission.create(action: 'delete', object_name: 'order')
|
59
|
+
Then create one `Dynamican::Item` for each resource you want your permittables to have permissions to act on. This is not mandatory for every permission though: you can also set a permission to do a general action, like `login`. Right now i'm trying to setup permissions for my permittable (Role model) to act on Order model.
|
67
60
|
|
68
|
-
|
61
|
+
i1 = Dynamican::Item.create(name: 'Order')
|
69
62
|
|
70
|
-
|
63
|
+
NOTE: conventionally, the name should be PascalCase, so there is a `before_validation` hook that classifies the name you are setting.
|
71
64
|
|
72
|
-
|
65
|
+
Create one `Dynamican::Permission` for each action you want your `role` instance to have permissions for.
|
73
66
|
|
74
|
-
|
67
|
+
p1 = Dynamican::Permission.create(action: a1, items: [i1], permittable: role)
|
68
|
+
p2 = Dynamican::Permission.create(action: a2, items: [i1], permittable: role)
|
69
|
+
p3 = Dynamican::Permission.create(action: a3, items: [i1], permittable: role)
|
70
|
+
p4 = Dynamican::Permission.create(action: a4, items: [i1], permittable: role)
|
75
71
|
|
76
|
-
Now your
|
72
|
+
Now your Role is considered able to create, read, update and destroy orders; you can evaluate permissions with `can?` method.
|
77
73
|
|
78
|
-
|
79
|
-
# Returns true
|
74
|
+
role.can? :create, :order
|
80
75
|
|
81
|
-
|
82
|
-
# Returns false
|
76
|
+
# true
|
83
77
|
|
84
|
-
|
85
|
-
You can also pass an array of these elements and permissions for all elements will be evaluated. The `can?` method will return true only if all permissions are evaluated positively.
|
86
|
-
You can also create custom permissions which don't need an object, simply leaving the `object_name` empty. Let's say you want to give permission to a certain user to dance
|
78
|
+
role.can? :else, :order
|
87
79
|
|
88
|
-
|
80
|
+
# false
|
89
81
|
|
90
|
-
|
82
|
+
You can pass as second argument (the item) a symbol, a string, the class itself and also the instance (instances are required for condition evaluations).
|
83
|
+
If you pass an array of these elements, permissions for all single element will be evaluated. The `can?` method will return true only if permissions to all items are evaluated positively.
|
84
|
+
You can also create custom permissions which don't need an item, (item is not required for permission creation). Let's say you want to give permission to a certain `user` to dance.
|
85
|
+
|
86
|
+
action_dance = Dynamican::Action.create(name: 'dance')
|
87
|
+
p5 = Dynamican::Permission.create(action: action_dance, permittable: user)
|
91
88
|
|
92
89
|
Call the `can?` method without any second argument
|
93
90
|
|
94
91
|
user.can? :dance
|
95
92
|
|
96
|
-
#
|
93
|
+
# true
|
97
94
|
|
98
95
|
|
99
|
-
|
96
|
+
### Conditions
|
100
97
|
|
101
|
-
You can link a `Dynamican::
|
98
|
+
You can link a `Dynamican::Permission` to as many conditions as you want. A permission having at least one condition linked to is considered conditional (Permission class have `conditional` and `unconditional` scopes)
|
102
99
|
|
103
|
-
Conditions are created like this
|
100
|
+
Conditions are created like this.
|
104
101
|
|
105
|
-
|
106
|
-
|
102
|
+
permission.conditions.create(statement: '@user.orders.count < 5')
|
103
|
+
permission.conditions.create(statement: '@item.field.present?')
|
107
104
|
|
108
|
-
You can store in conditions statements whatever conditions you like in plain ruby and the string will be evaulated. Inside the statements, object have to be called as instance variables. These instance variables need to be present and can be declared
|
105
|
+
You can store in conditions statements whatever conditions you like in plain ruby and the string will be evaulated. Inside the statements, object have to be called as instance variables. These instance variables indeed need to be present and can be declared in a few ways.
|
109
106
|
|
110
|
-
1. The model name of the instance you called `can?` from, like the user, will be defined automatically based on model name so if you call `user.can?` you will have `@user` variable defined.
|
111
|
-
2. The
|
107
|
+
1. The model name of the instance you called `can?` from, like the user, will be defined automatically based both on a fixed name and on model name, so if you call `user.can?` you will have `@subject` variable (this is fixed) and `@user` variable defined because user is of class `User` (namespaces get cut out, so `Something::User` still turne into `@user`).
|
108
|
+
2. The same thing happens with the item: it will be defined both as `@item` and as the name of its class, so if you call `user.can? :read, @order` you will have `@item` and `@order` variable defined containing your `@order` object.
|
112
109
|
3. You can pass as third argument an hash of objects like this `user.can? :read, @order, time: Time.zone.now, whatever: @you_want` and you will have `@time` and `@whatever` variables defined.
|
113
110
|
|
114
|
-
WARNING: since the condition statement gets evaluated, i recommend not to allow anyone except project developers to create conditions to prevent malicious code from being executed.
|
111
|
+
WARNING: since the condition statement gets evaluated, i recommend not to allow anyone except project developers to create conditions, in order to prevent malicious code from being executed.
|
115
112
|
|
116
|
-
If one `Dynamican::
|
113
|
+
If one `Dynamican::Permission` is linked to many conditions, the model will be allowed to make that action only if all conditions are true. If you want to set alternative conditions, you should store the `or` conditions inside the same condition statement, like this:
|
117
114
|
|
118
115
|
condition.statement = '@user.nice? || @user.polite?'
|
116
|
+
|
117
|
+
### Permission scopes
|
118
|
+
|
119
|
+
You can apply the scope `for_action(action_name)` to Permission to find permissions bound to a specific action.
|
120
|
+
There is a `for_item(item_name)` scope, which turns to string and then classifies automatically the argument to match it with the classified item name. The scope filters all Permission records that have an item with the specified name in its items list.
|
121
|
+
There is also a `without_item` scope to filter records that are not linked to any item.
|
122
|
+
As mentioned before, you can also use `conditional` and `unconditional` scopes to find objects with or without any condition attached.
|
123
|
+
|
124
|
+
### Controller usage
|
125
|
+
|
126
|
+
Your controllers now all have the `authorize!` method, which accepts one or two arguments: the first is the action, and the second (optional) is the item (or list of items) you want to check permissions for. As you can see, the usage is similar to the `can?` method. The reason is that is actually calls that method on the instance of `@current_user` and, whether permissions are evaluated as false, it raises an exception which is rescued by an `unauthorized` response rendered.
|
data/dynamican.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'dynamican'
|
3
|
-
s.version = '0.1
|
4
|
-
s.date = '2020-
|
3
|
+
s.version = '1.0.1'
|
4
|
+
s.date = '2020-09-10'
|
5
5
|
s.summary = "Dynamic permissions"
|
6
6
|
s.description = "Dynamic and flexible database configurable permissions for your application"
|
7
7
|
s.authors = ["Valerio Bellaveglia"]
|
data/lib/dynamican.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require 'dynamican/
|
1
|
+
require 'dynamican/authorization'
|
2
2
|
require 'dynamican/evaluator'
|
3
3
|
require 'dynamican/model'
|
4
|
-
require 'models/dynamican/condition'
|
5
|
-
require 'models/dynamican/permission_connector'
|
6
4
|
require 'models/dynamican/permission'
|
5
|
+
require 'models/dynamican/action'
|
6
|
+
require 'models/dynamican/item'
|
7
|
+
require 'models/dynamican/condition'
|
8
|
+
require 'generators/dynamican_migration_generator'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Dynamican
|
2
|
+
module Authorization
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class UnauthorizedResource < StandardError; end
|
6
|
+
|
7
|
+
included do
|
8
|
+
rescue_from UnauthorizedResource, with: :unauthorized
|
9
|
+
end
|
10
|
+
|
11
|
+
def authorize!(action, item = nil)
|
12
|
+
raise UnauthorizedResource unless @current_user.can? action, item
|
13
|
+
end
|
14
|
+
|
15
|
+
def unauthorized
|
16
|
+
render status: :unauthorized
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
if defined? ActiveSupport
|
22
|
+
ActiveSupport.on_load(:action_controller) do
|
23
|
+
include Dynamican::Authorization
|
24
|
+
end
|
25
|
+
end
|
data/lib/dynamican/evaluator.rb
CHANGED
@@ -1,42 +1,41 @@
|
|
1
1
|
module Dynamican
|
2
2
|
class Evaluator
|
3
|
-
attr_reader :subject, :action, :
|
3
|
+
attr_reader :subject, :action, :item, :item_name, :conditions_instances
|
4
4
|
|
5
|
-
def initialize(subject, action,
|
5
|
+
def initialize(subject, action, item, conditions_instances = {})
|
6
6
|
@subject = subject
|
7
7
|
@action = action
|
8
|
-
@
|
9
|
-
@
|
8
|
+
@item = item
|
9
|
+
@item_name = calculate_item_name
|
10
10
|
@conditions_instances = conditions_instances
|
11
11
|
end
|
12
12
|
|
13
13
|
def evaluate
|
14
14
|
set_instance_variables
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
matching_permissions = item.present? ? subject.permissions.for_action(action).for_item(item_name) : subject.permissions.for_action(action).without_item
|
17
|
+
matching_permissions_statements = matching_permissions.conditional.map(&:conditions).flatten.map(&:statement)
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
matching_permissions.unconditional.any? ||
|
20
|
+
matching_permissions_statements.any? && matching_permissions_statements.map { |statement| eval statement }.all?
|
21
21
|
end
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
25
|
def set_instance_variables
|
26
|
-
instance_variable_set("@#{subject.
|
26
|
+
instance_variable_set("@#{subject.class.name.demodulize.underscore}", subject)
|
27
|
+
instance_variable_set("@#{item.class.name.demodulize.underscore}", item)
|
27
28
|
|
28
|
-
conditions_instances.each do |instance_name,
|
29
|
-
instance_variable_set("@#{instance_name}",
|
29
|
+
conditions_instances.each do |instance_name, instance_item|
|
30
|
+
instance_variable_set("@#{instance_name}", instance_item)
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
def
|
34
|
-
if
|
35
|
-
|
36
|
-
elsif object.is_a?(NilClass)
|
37
|
-
nil
|
34
|
+
def calculate_item_name
|
35
|
+
if item.class.in? [Symbol, String, Class]
|
36
|
+
item.to_s.classify
|
38
37
|
else
|
39
|
-
|
38
|
+
item.class.name.demodulize
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end
|
data/lib/dynamican/model.rb
CHANGED
@@ -3,15 +3,14 @@ module Dynamican
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
has_many :
|
7
|
-
has_many :permissions, class_name: 'Dynamican::Permission', through: :permission_connectors, source: :permission
|
6
|
+
has_many :permissions, class_name: 'Dynamican::Permission', as: :permittable, dependent: :destroy
|
8
7
|
end
|
9
8
|
|
10
|
-
def can?(action,
|
11
|
-
if
|
12
|
-
|
9
|
+
def can?(action, item = nil, conditions_instances = {})
|
10
|
+
if item.respond_to? :each
|
11
|
+
item.all? { |single_item| can? action, single_item }
|
13
12
|
else
|
14
|
-
Dynamican::Evaluator.new(self, action,
|
13
|
+
Dynamican::Evaluator.new(self, action, item, conditions_instances).evaluate
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
class DynamicanMigrationGenerator < Rails::Generators::Base
|
4
|
+
|
5
|
+
def create_migration_file
|
6
|
+
create_file "db/migrate/#{Time.zone.now.strftime("%Y%m%d%H%M%S")}_dynamican_migration.rb", migration_data
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def migration_data
|
12
|
+
<<MIGRATION
|
13
|
+
class DynamicanMigration < ActiveRecord::Migration[5.2]
|
14
|
+
def change
|
15
|
+
unless table_exists? :permissions
|
16
|
+
create_table :permissions do |t|
|
17
|
+
t.bigint :permittable_id
|
18
|
+
t.string :permittable_type
|
19
|
+
t.bigint :action_id
|
20
|
+
|
21
|
+
t.timestamps
|
22
|
+
end
|
23
|
+
|
24
|
+
create_table :actions do |t|
|
25
|
+
t.string :name
|
26
|
+
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
create_table :items do |t|
|
31
|
+
t.string :name
|
32
|
+
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
|
36
|
+
create_table :conditions do |t|
|
37
|
+
t.bigint :permission_id
|
38
|
+
t.string :statement
|
39
|
+
t.string :description
|
40
|
+
|
41
|
+
t.timestamps
|
42
|
+
end
|
43
|
+
|
44
|
+
create_table :items_permissions do |t|
|
45
|
+
t.bigint :item_id
|
46
|
+
t.bigint :permission_id
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
MIGRATION
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Dynamican
|
2
|
+
class Action < ActiveRecord::Base
|
3
|
+
has_many :permissions, class_name: 'Dynamican::Permission', inverse_of: :action, foreign_key: :action_id, dependent: :destroy
|
4
|
+
|
5
|
+
validates :name, presence: true, uniqueness: true
|
6
|
+
|
7
|
+
attr_readonly :name
|
8
|
+
end
|
9
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module Dynamican
|
2
2
|
class Condition < ActiveRecord::Base
|
3
|
-
|
3
|
+
belongs_to :permission, class_name: 'Dynamican::Permission', inverse_of: :conditions, foreign_key: :permission_id
|
4
|
+
|
5
|
+
validates_presence_of :statement
|
4
6
|
end
|
5
7
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Dynamican
|
2
|
+
class Item < ActiveRecord::Base
|
3
|
+
has_and_belongs_to_many :permissions, class_name: 'Dynamican::Permission', inverse_of: :items, foreign_key: :item_id, dependent: :destroy
|
4
|
+
|
5
|
+
validates :name, presence: true, uniqueness: true
|
6
|
+
|
7
|
+
attr_readonly :name
|
8
|
+
|
9
|
+
before_validation :classify_name
|
10
|
+
|
11
|
+
def classify_name
|
12
|
+
self.name = self.name.classify
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Dynamican
|
2
2
|
class Permission < ActiveRecord::Base
|
3
|
-
|
3
|
+
belongs_to :permittable, polymorphic: true
|
4
|
+
belongs_to :action, class_name: 'Dynamican::Action', inverse_of: :permissions, foreign_key: :action_id
|
5
|
+
has_and_belongs_to_many :items, class_name: 'Dynamican::Item', inverse_of: :permissions, foreign_key: :permission_id
|
6
|
+
has_many :conditions, class_name: 'Dynamican::Condition', inverse_of: :permission, foreign_key: :permission_id
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
scope :
|
8
|
-
scope :
|
8
|
+
scope :for_action, -> (action_name) { joins(:action).where(actions: { name: action_name }) }
|
9
|
+
scope :for_item, -> (item_name) { joins(:items).where(items: { name: item_name.to_s.classify }) }
|
10
|
+
scope :without_item, -> { left_outer_joins(:items).where(items: { id: nil }) }
|
11
|
+
scope :conditional, -> { joins(:conditions) }
|
12
|
+
scope :unconditional, -> { left_outer_joins(:conditions).where(conditions: { id: nil }) }
|
9
13
|
end
|
10
14
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamican
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valerio Bellaveglia
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-10 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Dynamic and flexible database configurable permissions for your application
|
14
|
-
email:
|
14
|
+
email:
|
15
15
|
executables: []
|
16
16
|
extensions: []
|
17
17
|
extra_rdoc_files: []
|
@@ -20,18 +20,19 @@ files:
|
|
20
20
|
- README.md
|
21
21
|
- dynamican.gemspec
|
22
22
|
- lib/dynamican.rb
|
23
|
-
- lib/dynamican/
|
23
|
+
- lib/dynamican/authorization.rb
|
24
24
|
- lib/dynamican/evaluator.rb
|
25
25
|
- lib/dynamican/model.rb
|
26
|
+
- lib/generators/dynamican_migration_generator.rb
|
27
|
+
- lib/models/dynamican/action.rb
|
26
28
|
- lib/models/dynamican/condition.rb
|
29
|
+
- lib/models/dynamican/item.rb
|
27
30
|
- lib/models/dynamican/permission.rb
|
28
|
-
- lib/models/dynamican/permission_connector.rb
|
29
|
-
- migrations/0.1.2/dynamican_create_database_structure.rb
|
30
31
|
homepage: https://github.com/ValerioBellaveglia/Dynamican
|
31
32
|
licenses:
|
32
33
|
- MIT
|
33
34
|
metadata: {}
|
34
|
-
post_install_message:
|
35
|
+
post_install_message:
|
35
36
|
rdoc_options: []
|
36
37
|
require_paths:
|
37
38
|
- lib
|
@@ -46,8 +47,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
46
47
|
- !ruby/object:Gem::Version
|
47
48
|
version: '0'
|
48
49
|
requirements: []
|
49
|
-
rubygems_version: 3.
|
50
|
-
signing_key:
|
50
|
+
rubygems_version: 3.1.2
|
51
|
+
signing_key:
|
51
52
|
specification_version: 4
|
52
53
|
summary: Dynamic permissions
|
53
54
|
test_files: []
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module Dynamican
|
2
|
-
def self.configuration
|
3
|
-
@configuration ||= Configuration.new(configuration_hash)
|
4
|
-
end
|
5
|
-
|
6
|
-
def self.configuration_hash
|
7
|
-
@configuration_hash ||= HashWithIndifferentAccess.new(YAML.load_file('config/dynamican.yml'))
|
8
|
-
end
|
9
|
-
|
10
|
-
class Configuration
|
11
|
-
attr_accessor :associations
|
12
|
-
|
13
|
-
def initialize(configuration_hash)
|
14
|
-
@associations = configuration_hash[:associations]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
module Dynamican
|
2
|
-
class PermissionConnector < ActiveRecord::Base
|
3
|
-
Dynamican.configuration.associations.each do |association_name, association_options|
|
4
|
-
belongs_to association_name.to_sym, class_name: association_options[:class_name], inverse_of: association_options[:inverse_of], foreign_key: "#{association_name}_id".to_sym, optional: true
|
5
|
-
end
|
6
|
-
has_and_belongs_to_many :conditions, class_name: 'Dynamican::Condition', inverse_of: :permission_connectors, foreign_key: :permission_connector_id
|
7
|
-
belongs_to :permission, class_name: 'Dynamican::Permission', inverse_of: :permission_connectors, foreign_key: :permission_id
|
8
|
-
|
9
|
-
scope :conditional, -> { where(conditional: true) }
|
10
|
-
scope :unconditional, -> { where(conditional: false) }
|
11
|
-
scope :for_action, -> (action) { joins(:permission).where(permissions: { action: action }) }
|
12
|
-
scope :for_object, -> (object_name) { joins(:permission).where(permissions: { object_name: object_name }) }
|
13
|
-
end
|
14
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
class DynamicanCreateDatabaseStructure < ActiveRecord::Migration[5.2]
|
2
|
-
def change
|
3
|
-
create_table :conditions do |t|
|
4
|
-
t.string :description
|
5
|
-
t.string :statement
|
6
|
-
|
7
|
-
t.timestamps
|
8
|
-
end
|
9
|
-
|
10
|
-
create_table :permissions do |t|
|
11
|
-
t.string :action
|
12
|
-
t.string :object_name
|
13
|
-
|
14
|
-
t.timestamps
|
15
|
-
end
|
16
|
-
|
17
|
-
create_table :permission_connectors do |t|
|
18
|
-
t.references :user
|
19
|
-
t.references :role
|
20
|
-
t.references :permission
|
21
|
-
t.boolean :conditional, default: false
|
22
|
-
|
23
|
-
t.timestamps
|
24
|
-
end
|
25
|
-
|
26
|
-
create_table :conditions_permission_connectors do |t|
|
27
|
-
t.bigint :condition_id
|
28
|
-
t.bigint :permission_connector_id
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|