ez-permissions 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 63fcfa633d299ba98948f0139ad49873bbdd3098f45a6e714d2fb5da27f28b18
4
+ data.tar.gz: c392ff7f90575129d0c7c7a99d873c7552acf88d59b82460e766a3c42dac4461
5
+ SHA512:
6
+ metadata.gz: e6bb7cfe77c7b5f3c51d38d5e4f9349d2e59c7d8e47de0f9c728c66190453013fef6ce348cfef4bfcba40cda3d58296d1b7a047a0001c1358a1274b01cbc152b
7
+ data.tar.gz: 37c0fe0b3dd8f727b20f8a4820cdd56c95e29dd413b0317c8f0cee204fe9e152129805a96f4a402e90255571b1b9ce9c0d8610af5057d07a31eb635d9806bd52
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2019 Volodymyr Sveredyuk
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,210 @@
1
+ # Ez::Permissions
2
+
3
+ [![Build Status](https://travis-ci.org/ez-engines/ez-permissions.svg?branch=master)](https://travis-ci.org/ez-engines/ez-permissions)
4
+
5
+ **Ez Permissions** (read as "easy permissions") - one of the [ez-engines](https://github.com/ez-engines) collection that helps easily add permissions interface to your [Rails](http://rubyonrails.org/) application.
6
+
7
+ - Most advanced RBAC model:
8
+ - Flexible tool with simple DSL and confguration
9
+ - All in one solution
10
+ - Convetion over configuration principles.
11
+ - Depends on [ez-core](https://github.com/ez-engines/ez-core)
12
+
13
+ ## Installation
14
+ Add this line to your application's Gemfile:
15
+ ```ruby
16
+ gem 'ez-permissions'
17
+ ```
18
+
19
+ ## Generators
20
+
21
+ Generate configuration file:
22
+ ```bash
23
+ rails generate ez:permissions:install
24
+ ```
25
+
26
+ ### Configuration
27
+
28
+ Configuration interface allows you to change default behavior
29
+ ```ruby
30
+ Ez::Permissions.configure do |config|
31
+ # If in generated migrations you changed table names, please configure them here:
32
+ config.permission_table_name = 'my_permissions'
33
+ config.roles_table_name = 'my_roles'
34
+ config.models_roles_table_name = 'my_model_roles'
35
+ config.permissions_roles_table_name = 'my_permissions_roles'
36
+
37
+ # Define your custom callbacks
38
+ config.handle_no_permission_model = lambda { |context|
39
+ raise 'User not exist'
40
+ }
41
+
42
+ config.handle_not_authorized = lambda { |context|
43
+ raise 'Not authorized'
44
+ }
45
+ end
46
+
47
+ ```
48
+ ### ActiveRecord migrations:
49
+
50
+ **If you need change table names, please change configuration first**
51
+
52
+ And run
53
+ ```bash
54
+ rails generate ez:permissions:migrations
55
+ ```
56
+
57
+ ## DSL
58
+
59
+ Simple DSL for difinition of permission relationships
60
+ ```ruby
61
+ Ez::Permissions::DSL.define do |setup|
62
+ # You need add all resources of your application and possible actions
63
+ setup.add :roles, actions: %i[create read]
64
+
65
+ # Use `crud` for adding default `create`, `read`, `update` and `delete` actions
66
+ # And any your custom action
67
+ setup.add :permissions, actions: %i[crud my_custom_action]
68
+
69
+ # Actions option are not required. In such case you add all crud actions by default
70
+ setup.add :users
71
+ setup.add :projects
72
+ end
73
+ ```
74
+
75
+ ## Permission model
76
+
77
+ In your application, you usually have `User` model.
78
+ ```ruby
79
+ class User < ActiveRecord::Base
80
+ include Ez::Permissions::Model
81
+ end
82
+
83
+ user = User.first
84
+
85
+ # User model become permission model
86
+ user.roles #=> [application level roles]
87
+ user.assigned_roles #=> [user owned roles, gloabal and scoped]
88
+ user.permissions #=> [user available permissions through assigned_roles]
89
+ ```
90
+
91
+ ## API
92
+
93
+ **Please, do not use direct rails code like:** `Ez::Permissions::Permission.create(name: 'admin')`
94
+
95
+ Instead you should use public api. You can extend you custom module with `API` mixin
96
+ ```ruby
97
+ # Use engine facade methods
98
+ Ez::Permissions::API
99
+
100
+ # or extend your own module and keep your code clean
101
+ module Permissions
102
+ extend Ez::Permissions::API::Roles
103
+ extend Ez::Permissions::API::Permissions
104
+ extend Ez::Permissions::API::Models
105
+ extend Ez::Permissions::API::Authorize
106
+ end
107
+ ```
108
+
109
+ ### Roles
110
+ ```ruby
111
+ # Create regular role
112
+ Permissions.create_role(:user)
113
+ Permissions.create_role(:admin)
114
+
115
+ # Get role object by name
116
+ Permissions.get_role(:user)
117
+
118
+ # Update role attributes
119
+ Permissions.update_role(:user, name: 'super_user')
120
+
121
+ # Delete role
122
+ Permissions.delete_role(:user)
123
+
124
+ # Assign role to the user
125
+ user = User.first
126
+ Permissions.assign_role(user, :admin)
127
+
128
+ # Assign role to the user in scope of any resource
129
+ project = Project.first
130
+ Permissions.assign_role(user, :admin, scoped: project)
131
+
132
+ # Reject user role in global scope, but project admin role will stay
133
+ Permissions.reject_role(user, :admin)
134
+ ```
135
+
136
+ ### Permissions
137
+ ```ruby
138
+ # Create a role
139
+ Permissions.create_role(:user)
140
+
141
+ # Grant role's possibility to have action per resource
142
+ Permissions.grant_permission(:user, :read, :projects)
143
+
144
+ # Grant all defined actions per resource
145
+ Permissions.grant_permission(:user, :all, :projects)
146
+
147
+ # Revoke particular permission
148
+ Permissions.revoke_permission(:user, :create, :projects)
149
+ ```
150
+
151
+ ### Authorize access
152
+ ```ruby
153
+ user = User.first
154
+ project = Project.first
155
+
156
+ Permissions.create_role(:admin)
157
+ Permissions.grant_permission(:admin, :all, :users)
158
+ Permissions.assign_role(user, :admin, scoped: project)
159
+
160
+ Permissions.authorize!(user, :create, :users, scoped: project) do
161
+ # code here would be executed if user has permissions
162
+ # for user creation in particular project
163
+ end
164
+
165
+ # otherwise catch exception
166
+ Ez::Permissions::API::Authrozation::NotAuthorized
167
+
168
+ # if you don't want raise exception, just use
169
+ Permissions.authorize(user, :create, :users) { puts 'Yeahh!' } #=> false
170
+ # Because user has scoped role in the project and don't has global role.
171
+ ```
172
+
173
+ ### Kepp it excplicit!
174
+ You can wonder, why we just not add authorization methods to user instance, like:
175
+ ```ruby
176
+ user.can?(:something)
177
+ ```
178
+ Because ez-permissions engine don't want pollute your application and keep implementation isolated in external modules.
179
+ Of course, you can use them as mixins, but it's up to you.
180
+
181
+ ## Understanding scoped roles
182
+ - System have many roles
183
+ - User has many assigned roles
184
+ - User can has role in scope of some resource (Project, Company, Business, etc.)
185
+ - User can has role in global scope (without scope)
186
+ - If user want access data in scope of resource - user must has assigned role scoped for this resource
187
+ - If user want access data in global scope - user must has assigned role wihtout any scoped resorce (global role)
188
+ - User with global role - can't access scoped resources.
189
+ - User with scoped role - can't access global resources.
190
+
191
+ ## TODO
192
+ - [x] Add README
193
+ - [x] Add Role model
194
+ - [x] Add Permissions model
195
+ - [x] Add PermissionsRole model
196
+ - [x] Add rails generators for migrations
197
+ - [x] Add rails generators for configuration
198
+ - [x] Add configuration DSL
199
+ - [x] Add Permissions API for managing relationships
200
+ - [x] User can has multiple roles
201
+ - [x] Better errors for non-existing records
202
+ - [x] Add permissions helpers `authorize` and `authorize!`
203
+ - [x] Move all erros under `Ez::Permissions::API` namespace and add `Error` suffix
204
+ - [ ] Add helper methods for seed grant permissions
205
+
206
+ ## Contributing
207
+ Contribution directions go here.
208
+
209
+ ## License
210
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rdoc/task'
10
+
11
+ RDoc::Task.new(:rdoc) do |rdoc|
12
+ rdoc.rdoc_dir = 'rdoc'
13
+ rdoc.title = 'Ez::Permissions'
14
+ rdoc.options << '--line-numbers'
15
+ rdoc.rdoc_files.include('README.md')
16
+ rdoc.rdoc_files.include('lib/**/*.rb')
17
+ end
18
+
19
+ APP_RAKEFILE = File.expand_path('spec/dummy/Rakefile', __dir__)
20
+ load 'rails/tasks/engine.rake'
21
+
22
+ load 'rails/tasks/statistics.rake'
23
+
24
+ require 'bundler/gem_tasks'
25
+
26
+ require 'rspec/core/rake_task'
27
+
28
+ RSpec::Core::RakeTask.new(:spec)
29
+
30
+ task default: :spec
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: Use this for potential UI or API features
4
+ # module Ez
5
+ # module Permissions
6
+ # class ApplicationController < ActionController::Base
7
+ # protect_from_forgery with: :exception
8
+ # end
9
+ # end
10
+ # end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ module Model
6
+ # rubocop:disable Metrics/MethodLength
7
+ def self.included(base)
8
+ base.has_many :assigned_roles,
9
+ class_name: 'Ez::Permissions::ModelRole',
10
+ as: :model
11
+
12
+ base.has_many :roles,
13
+ -> { distinct },
14
+ through: :assigned_roles,
15
+ class_name: 'Ez::Permissions::Role'
16
+
17
+ base.has_many :permissions,
18
+ -> { distinct },
19
+ through: :roles,
20
+ class_name: 'Ez::Permissions::Permission'
21
+ end
22
+ # rubocop:enable Metrics/MethodLength
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class ModelRole < ApplicationRecord
6
+ self.table_name = Ez::Permissions.config.models_roles_table_name
7
+
8
+ belongs_to :model, polymorphic: true
9
+ belongs_to :scoped, polymorphic: true, optional: true
10
+ belongs_to :role
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class Permission < ApplicationRecord
6
+ self.table_name = Ez::Permissions.config.permissions_table_name
7
+
8
+ validates :resource, presence: true
9
+ validates :action, presence: true
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class PermissionRole < ApplicationRecord
6
+ self.table_name = Ez::Permissions.config.permissions_roles_table_name
7
+
8
+ belongs_to :permission, class_name: 'Ez::Permissions::Permission'
9
+ belongs_to :role, class_name: 'Ez::Permissions::Role'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class Role < ApplicationRecord
6
+ self.table_name = Ez::Permissions.config.roles_table_name
7
+
8
+ has_and_belongs_to_many :permissions
9
+
10
+ validates :name, presence: true
11
+ validates :name, uniqueness: true
12
+ end
13
+ end
14
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: Use this for potential UI or API features
4
+ # Ez::Permissions::Engine.routes.draw do
5
+ # end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ module API
6
+ module Authorize
7
+ NotAuthorized = Class.new(StandardError)
8
+
9
+ def authorize!(model, *actions, resource, scoped: nil, &block)
10
+ authorize(model, *actions, resource, scoped: scoped, raise_exception: true, &block)
11
+ end
12
+
13
+ def authorize(model, *actions, resource, scoped: nil, raise_exception: false)
14
+ return handle_no_permission_model_callback.call(self) if handle_no_permission_model_callback && !model
15
+
16
+ return yield if permissions(model, *actions, resource, scoped: scoped).any?
17
+
18
+ return handle_not_authorized_callback.call(self) if handle_not_authorized_callback
19
+
20
+ raise NotAuthorized, not_authorized_msg(model, actions, resource, scoped) if raise_exception
21
+
22
+ false
23
+ end
24
+
25
+ private
26
+
27
+ def permissions(model, *actions, resource, scoped: nil)
28
+ # TODO: Refactor to 1 query with joins
29
+ roles_ids = model.assigned_roles.where(scoped: scoped).pluck(:role_id)
30
+ permission_ids = Ez::Permissions::PermissionRole.where(role_id: roles_ids).pluck(:permission_id)
31
+
32
+ Ez::Permissions::Permission.where(
33
+ id: permission_ids,
34
+ resource: resource,
35
+ action: actions.map(&:to_s)
36
+ )
37
+ end
38
+
39
+ def not_authorized_msg(model, actions, resource, scoped = nil)
40
+ msg = "#{model.class}##{model.id} is not authorized to [#{actions.join(', ')} -> #{resource}]"
41
+ msg = "#{msg} for #{scoped.class}##{scoped.id}" if scoped
42
+
43
+ msg
44
+ end
45
+
46
+ def handle_no_permission_model_callback
47
+ Ez::Permissions.config.handle_no_permission_model
48
+ end
49
+
50
+ def handle_not_authorized_callback
51
+ Ez::Permissions.config.handle_not_authorized
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ module API
6
+ module Models
7
+ def assign_role(model, role_name, scoped: nil)
8
+ role = Ez::Permissions::API.get_role!(role_name)
9
+
10
+ Ez::Permissions::ModelRole.find_or_create_by!(
11
+ role: role,
12
+ model: model,
13
+ scoped: scoped
14
+ )
15
+ end
16
+
17
+ def reject_role(model, role_name, scoped: nil)
18
+ role = Ez::Permissions::API.get_role!(role_name)
19
+
20
+ Ez::Permissions::ModelRole.find_by(
21
+ role: role,
22
+ model: model,
23
+ scoped: scoped
24
+ )&.delete
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ module API
6
+ module Permissions
7
+ PermissionNotFound = Class.new(StandardError)
8
+
9
+ def get_permission!(action, resource)
10
+ Ez::Permissions::Permission.find_by!(resource: resource, action: action)
11
+ rescue ActiveRecord::RecordNotFound
12
+ raise PermissionNotFound, "Permission [#{action} -> #{resource}] not found"
13
+ end
14
+
15
+ def grant_permission(role_name, action, resource)
16
+ role = Ez::Permissions::API.get_role!(role_name)
17
+
18
+ if action == :all
19
+ grant_all_permissions(role, resource)
20
+ else
21
+ permission = get_permission!(action, resource)
22
+ grant_single_permission(role, permission)
23
+ end
24
+ end
25
+
26
+ def revoke_permission(role_name, action, resource)
27
+ role = Ez::Permissions::API.get_role!(role_name)
28
+ permission = get_permission!(action, resource)
29
+
30
+ Ez::Permissions::PermissionRole.find_by(
31
+ role: role,
32
+ permission: permission
33
+ )&.delete
34
+ end
35
+
36
+ private
37
+
38
+ def grant_single_permission(role, permission)
39
+ Ez::Permissions::PermissionRole.find_or_create_by!(
40
+ role: role,
41
+ permission: permission
42
+ )
43
+ end
44
+
45
+ def grant_all_permissions(role, resource)
46
+ Ez::Permissions::DSL.resource(resource).actions.each do |action|
47
+ permission = get_permission!(action, resource)
48
+ grant_single_permission(role, permission)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ module API
6
+ module Roles
7
+ RoleNotFound = Class.new(StandardError)
8
+
9
+ def create_role(name)
10
+ Role.create(name: name)
11
+ end
12
+
13
+ def get_role(name)
14
+ Role.find_by(name: name)
15
+ end
16
+
17
+ def get_role!(name)
18
+ Role.find_by!(name: name)
19
+ rescue ActiveRecord::RecordNotFound
20
+ raise RoleNotFound, "Role #{name} not found"
21
+ end
22
+
23
+ def update_role(role_name, name:)
24
+ role = get_role!(role_name)
25
+
26
+ role.update(name: name)
27
+ end
28
+
29
+ def delete_role(name)
30
+ role = get_role!(name)
31
+
32
+ role.delete
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'api/roles'
4
+ require_relative 'api/permissions'
5
+ require_relative 'api/models'
6
+ require_relative 'api/authorize'
7
+
8
+ module Ez
9
+ module Permissions
10
+ module API
11
+ extend Ez::Permissions::API::Roles
12
+ extend Ez::Permissions::API::Permissions
13
+ extend Ez::Permissions::API::Models
14
+ extend Ez::Permissions::API::Authorize
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'resource'
4
+
5
+ module Ez
6
+ module Permissions
7
+ class DSL
8
+ include Singleton
9
+
10
+ def self.define
11
+ yield DSL.instance
12
+ end
13
+
14
+ def self.resources
15
+ DSL.instance.resources
16
+ end
17
+
18
+ def self.resource(name)
19
+ DSL.instance.resources.find { |r| r.name.to_sym == name.to_sym }
20
+ end
21
+
22
+ attr_reader :resources
23
+
24
+ def initialize
25
+ @resources = []
26
+ end
27
+
28
+ def add(name, options = {})
29
+ if self.class.resource(name)
30
+ return message("[WARN] Ez::Permissions resource [#{name}] has been already defined!")
31
+ end
32
+
33
+ resource = Ez::Permissions::Resource.new(name, options)
34
+
35
+ message(
36
+ "[SUCCESS] Ez::Permissions resource [#{name}] has been successfully registred with actions: \
37
+ [#{resource.actions.join(', ')}]"
38
+ )
39
+
40
+ @resources << resource
41
+ seed_to_db resource
42
+ end
43
+
44
+ private
45
+
46
+ def message(txt)
47
+ STDOUT.puts(txt)
48
+ end
49
+
50
+ def seed_to_db(resource)
51
+ try_db_connection
52
+
53
+ return unless ActiveRecord::Base.connection.data_source_exists?(Ez::Permissions.config.permissions_table_name)
54
+
55
+ return unless resource.actions
56
+
57
+ resource.actions.each do |action|
58
+ Ez::Permissions::Permission.where(
59
+ resource: resource.name,
60
+ action: action
61
+ ).first_or_create!
62
+ end
63
+ end
64
+
65
+ def try_db_connection
66
+ ActiveRecord::Base.connection
67
+ rescue ActiveRecord::NoDatabaseError
68
+ STDOUT.puts 'Database does not exist'
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace Ez::Permissions
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # TODO: Use this for potential UI or API features
4
+ # module Ez
5
+ # module Permissions
6
+ # class Railtie < ::Rails::Railtie
7
+ # end
8
+ # end
9
+ # end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class Resource
6
+ ACTIONS = %i[create read update delete].freeze
7
+
8
+ attr_reader :name, :model, :actions
9
+
10
+ def initialize(name, options = {})
11
+ @name = name
12
+ @model = options.fetch(:model, nil)
13
+ @actions = process_actions(options.fetch(:actions, nil))
14
+ end
15
+
16
+ def <=>(other)
17
+ name <=> other.name
18
+ end
19
+
20
+ private
21
+
22
+ def process_actions(actions)
23
+ return ACTIONS unless actions
24
+
25
+ actions.map { |action| action == :crud ? ACTIONS : action }.flatten
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ez/permissions/engine'
4
+ require 'ez/permissions/dsl'
5
+ require 'ez/permissions/api'
6
+ require 'ez/configurator'
7
+
8
+ module Ez
9
+ module Permissions
10
+ include Ez::Configurator
11
+
12
+ configure do |config|
13
+ config.permissions_table_name = 'ez_permissions_permissions'
14
+ config.roles_table_name = 'ez_permissions_roles'
15
+ config.models_roles_table_name = 'ez_permissions_model_roles'
16
+ config.permissions_roles_table_name = 'ez_permissions_permissions_roles'
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ez
4
+ module Permissions
5
+ class InstallGenerator < Rails::Generators::Base
6
+ def create_migration
7
+ create_file 'config/initializers/ez_permissions.rb',
8
+ "# frozen_string_literal: true
9
+
10
+ Ez::Permissions.configure do |config|
11
+ # config.permission_table_name = 'ez_permissions_permissions'
12
+ # config.roles_table_name = 'ez_permissions_roles'
13
+ # config.models_roles_table_name = 'ez_permissions_model_roles'
14
+ # config.permissions_roles_table_name = 'ez_permissions_permissions_roles'
15
+
16
+ # config.handle_no_permission_model = lambda { |context|
17
+ # here you can define your custom callback
18
+ # in case when permission model (user) is nil
19
+ # }
20
+
21
+ # config.handle_not_authorized = lambda { |context|
22
+ # here you can define your custom callback
23
+ # in case when model (user) is not authorized
24
+ # }
25
+ end
26
+ "
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable all
4
+ module Ez
5
+ module Permissions
6
+ class MigrationsGenerator < Rails::Generators::Base
7
+ def config
8
+ Ez::Permissions.config
9
+ end
10
+
11
+ def create_migration
12
+ create_file "db/migrate/#{Time.current.strftime('%Y%m%d%H%M%S')}_create_ez_permissions_roles.rb",
13
+ "# frozen_string_literal: true
14
+
15
+ class CreateEzPermissionsRoles < ActiveRecord::Migration[5.0]
16
+ def change
17
+ create_table :#{config.roles_table_name} do |t|
18
+ t.string :name, null: false
19
+ t.timestamps null: false
20
+ end
21
+ end
22
+ end
23
+ "
24
+ create_file "db/migrate/#{(Time.current + 1).strftime('%Y%m%d%H%M%S')}_create_ez_permissions_permissions.rb",
25
+ "# frozen_string_literal: true
26
+
27
+ class CreateEzPermissionsPermissions < ActiveRecord::Migration[5.0]
28
+ def change
29
+ create_table :#{config.permissions_table_name} do |t|
30
+ t.string :resource, index: true, null: false
31
+ t.string :action, index: true, null: false
32
+ t.timestamps null: false
33
+ end
34
+ end
35
+ end
36
+ "
37
+ create_file "db/migrate/#{(Time.current + 2).strftime('%Y%m%d%H%M%S')}_create_ez_permissions_model_roles.rb",
38
+ "# frozen_string_literal: true
39
+
40
+ class CreateEzPermissionsModelRoles < ActiveRecord::Migration[5.0]
41
+ def change
42
+ create_table :#{config.models_roles_table_name} do |t|
43
+ t.integer :model_id, index: true, null: false
44
+ t.string :model_type, index: true, null: false
45
+
46
+ t.integer :scoped_id, index: true
47
+ t.string :scoped_type, index: true
48
+
49
+ t.integer :role_id, index: true, null: false
50
+
51
+ t.timestamps null: false
52
+ end
53
+ end
54
+ end
55
+ "
56
+
57
+ create_file "db/migrate/#{(Time.current + 3).strftime('%Y%m%d%H%M%S')}_create_ez_permissions_permissions_roles.rb",
58
+ "# frozen_string_literal: true
59
+
60
+ class CreateEzPermissionsPermissionsRoles < ActiveRecord::Migration[5.0]
61
+ def change
62
+ create_table :#{config.permissions_roles_table_name} do |t|
63
+ t.integer :permission_id, index: true, null: false
64
+ t.integer :role_id, index: true
65
+ end
66
+ end
67
+ end
68
+ "
69
+ end
70
+ end
71
+ end
72
+ end
73
+ # rubocop: enable all
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # desc "Explaining what the task does"
4
+ # task :ez_permissions do
5
+ # # Task goes here
6
+ # end
metadata ADDED
@@ -0,0 +1,210 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ez-permissions
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Volodya Sveredyuk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ez-core
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '5.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: faker
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec-rails
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 1.3.6
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 1.3.6
153
+ description: Easy permissions engine for Rails app.
154
+ email:
155
+ - sveredyuk@gmail.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - MIT-LICENSE
161
+ - README.md
162
+ - Rakefile
163
+ - app/controllers/ez/permissions/application_controller.rb
164
+ - app/models/ez/permissions/application_record.rb
165
+ - app/models/ez/permissions/model.rb
166
+ - app/models/ez/permissions/model_role.rb
167
+ - app/models/ez/permissions/permission.rb
168
+ - app/models/ez/permissions/permission_role.rb
169
+ - app/models/ez/permissions/role.rb
170
+ - config/routes.rb
171
+ - lib/ez/permissions.rb
172
+ - lib/ez/permissions/api.rb
173
+ - lib/ez/permissions/api/authorize.rb
174
+ - lib/ez/permissions/api/models.rb
175
+ - lib/ez/permissions/api/permissions.rb
176
+ - lib/ez/permissions/api/roles.rb
177
+ - lib/ez/permissions/dsl.rb
178
+ - lib/ez/permissions/engine.rb
179
+ - lib/ez/permissions/railtie.rb
180
+ - lib/ez/permissions/resource.rb
181
+ - lib/ez/permissions/version.rb
182
+ - lib/generators/ez/permissions/install_generator.rb
183
+ - lib/generators/ez/permissions/migrations_generator.rb
184
+ - lib/tasks/ez/permissions_tasks.rake
185
+ homepage: https://github.com/ez-permissions
186
+ licenses:
187
+ - MIT
188
+ metadata:
189
+ allowed_push_host: https://rubygems.org
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 2.7.6
207
+ signing_key:
208
+ specification_version: 4
209
+ summary: Easy permissions engine for Rails app.
210
+ test_files: []