pundit_can 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: 6a70b76f365ad9d949e7db20d9fd1eebc689915d18c835801fb2078d98628b3b
4
+ data.tar.gz: b30f0f0ce6095d46818f7d47bbe3f95b8e7df58664929d0aa1e1e4a93122ab7e
5
+ SHA512:
6
+ metadata.gz: a96f83508916a9650fe4f14c24f0ff13d0d730cf14558e764070da4ec1eaf215c4ef1e06a91adaf09f0d013fb9e07193243a080b9bc737ea3e48dbcc866ed3c8
7
+ data.tar.gz: e755108ea59470ed01e17a81a8522657b787032c8a2c7fe50459f1353389f47ba9aa2700f6517ee094788a90771e0777fe630fa3f4d5a375edd7b37af8419758
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2023 candland
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,102 @@
1
+ # PunditCan
2
+
3
+ [Pundit](https://github.com/varvet/pundit) with [cancan](https://github.com/CanCanCommunity/cancancan)
4
+ style load_and_authorize functionality.
5
+
6
+ ## Usage
7
+
8
+ Include `PunditCan::LoadAndAuthorize` into `ApplicationController` or in each controller.
9
+
10
+ Call `load_resource` in the controller to load and authorize the resource.
11
+
12
+ ```ruby
13
+ class UsersController < ApplicationController
14
+ load_resource
15
+ end
16
+ ```
17
+
18
+ This will load `@user` from `User` using the `UserPolicy` to authorize and scope the loading.
19
+
20
+ ### Advanced usage
21
+
22
+ There is support for loading multiple models. However, there isn't a `:through` option, like cancan,
23
+ instead loading still goes through Pundit scopes.
24
+
25
+ There are options to customize the loaded instance_name, model, and policy classes.
26
+
27
+ #### Parent / nested
28
+
29
+ This is a example of loading User and Posts.
30
+ ```ruby
31
+ class PostsController < ApplicationController
32
+ load_resource model_class: User, parent: true
33
+ load_resource
34
+
35
+ ...
36
+ end
37
+ ```
38
+
39
+ That will load `@user` from the `UserPolicy` into a `User` class, using `:user_id` to find the user.
40
+ And it will lost `@post` or `@posts` using the `PostPolicy` with the `:id` param.
41
+
42
+ #### Customized loading
43
+
44
+ You can customize the loading for cases when the model, controller, and policies don't match up name-wise.
45
+ ```ruby
46
+ class MisMatchedController < ApplicationController
47
+ load_resource instance_name: :special_user,
48
+ model_class: User,
49
+ policy_class: SpecialUserPolicy,
50
+ policy_scope_class: SpecialUserPolicy::Scope
51
+
52
+ ...
53
+
54
+ # Pundit method to override the model param key
55
+ def pundit_params_for(record)
56
+ params.require(:special_user)
57
+ end
58
+ end
59
+ ```
60
+
61
+ This will set `@special_user` with the `User` class, using the `SpecialUserPolicy` and
62
+ `SpecialUserPolicy::Scope` classes to authorize and scope the loading.
63
+
64
+ #### Skiping checks
65
+
66
+ By default, `verify_authorized` and `verify_policy_scoped` after actions are setup. If
67
+ you need to skip those for an action, there are `skip_authorized_check` and `skip_scoped_check`
68
+ methods to skip the verify actions for the given actions.
69
+
70
+ ```ruby
71
+ class SkipsController < ApplicationController
72
+ skip_authorized_check :index, :show
73
+ skip_scoped_check :index, :show
74
+
75
+ ...
76
+ end
77
+ ```
78
+
79
+ ## Installation
80
+
81
+ Add this line to your application's Gemfile:
82
+ ```ruby
83
+ gem "pundit_can"
84
+ ```
85
+
86
+ And then execute:
87
+ ```bash
88
+ $ bundle
89
+ ```
90
+
91
+ Or install it yourself as:
92
+ ```bash
93
+ $ gem install pundit_can
94
+ ```
95
+
96
+ ## Contributing
97
+
98
+ Contribution directions go here.
99
+
100
+ ## License
101
+
102
+ 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,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,145 @@
1
+ require "pundit"
2
+
3
+ module PunditCan
4
+ module LoadAndAuthorize
5
+ extend ActiveSupport::Concern
6
+ include Pundit::Authorization
7
+
8
+ included do
9
+ after_action :verify_authorized, unless: -> { respond_to?(:devise_controller?) && devise_controller? }
10
+ after_action :verify_policy_scoped, except: [:new, :create], unless: -> { respond_to?(:devise_controller?) && devise_controller? }
11
+ end
12
+
13
+ class_methods do
14
+ # skip_authorized_check
15
+ #
16
+ # Skip the +verify_authorized+ after action for the provided actions
17
+ #
18
+ # @example
19
+ #
20
+ # skip_authorized_check :new, :edit
21
+ #
22
+ # @param [*Symbol] actions
23
+ #
24
+ def skip_authorized_check *actions
25
+ if actions.any?
26
+ skip_after_action :verify_authorized, only: actions
27
+ end
28
+ end
29
+
30
+ # skip_scoped_check
31
+ #
32
+ # Skip the +verify_policy_scoped+ after action for the provided actions
33
+ #
34
+ # @example
35
+ #
36
+ # skip_scoped_check :new, :edit
37
+ #
38
+ # @param [*Symbol] actions
39
+ #
40
+ def skip_scoped_check *actions
41
+ if actions.any?
42
+ skip_after_action :verify_policy_scoped, only: actions
43
+ end
44
+ end
45
+
46
+ # load_resource
47
+ #
48
+ # @example
49
+ #
50
+ # load_resource
51
+ #
52
+ # @example
53
+ #
54
+ # load_resource instance_name: :user, model_class: User, param_key: :user_id, parent: true
55
+ #
56
+ # @param [String] instance_name Optional. Defaults from the +model_class+ if
57
+ # provided, otherwise from the controller name.
58
+ #
59
+ # @param [Constant] model_class Optional. Tries to create model from the controller name when missing.
60
+ #
61
+ # @param [String] param_key Optional. The key for the Id in params. Defaults to +:id+, otherwise tries
62
+ # to guess from the +instance_name+ or +model_class+.
63
+ #
64
+ # @param [Boolean] parent Optional. Changes the loading for parent classes. Default +false+
65
+ #
66
+ # @param [Constant] policy_class Optional. The policy class to use. Defaults from controller name.
67
+ #
68
+ # @param [Constant] policy_scope_class Optional. The policy scope class to use. Defaults from controller name.
69
+ #
70
+ def load_resource **options
71
+ before_action(**options.extract!(:only, :except, :if, :unless)) do
72
+ load_scoped(**options)
73
+ end
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def resource_class_name
80
+ self.class.name[0..-11].singularize.demodulize
81
+ end
82
+
83
+ def load_scoped **options
84
+ model_class = options[:model_class] || resource_class_name.demodulize.constantize
85
+ instance_name = (options[:instance_name] || model_instance_name(options) || resource_class_name.underscore).to_s
86
+ param_key = get_param_key(options, instance_name, model_class)
87
+
88
+ loaded = if options[:parent]
89
+ load_parent_instance_var(model_class, param_key, options.extract!(:policy_class), options.extract!(:policy_scope_class))
90
+ else
91
+ load_instance_var(model_class, param_key, options.extract!(:policy_class), options.extract!(:policy_scope_class))
92
+ end
93
+
94
+ instance_name = instance_name.pluralize unless loaded.is_a?(model_class)
95
+ instance_variable_set("@#{instance_name}", loaded)
96
+ end
97
+
98
+ def get_param_key options, instance_name, model_class
99
+ if options[:parent]
100
+ options.fetch(:param_key, :"#{instance_name || model_class&.name&.underscore}_id")
101
+ else
102
+ options.fetch(:param_key, :id)
103
+ end
104
+ end
105
+
106
+ # if a model_name option is given use that otherwise nil
107
+ # and is parent
108
+ def model_instance_name options
109
+ options[:model_class].name.underscore if options[:model_class].present? && options[:parent]
110
+ end
111
+
112
+ def load_instance_var model_class, param_key, policy_kwopts, policy_scope_kwopts
113
+ case params[:action]
114
+ when "index"
115
+ load_scope(model_class, policy_kwopts, policy_scope_kwopts)
116
+ when "new"
117
+ authorize(model_class.new, **policy_kwopts)
118
+ when "create"
119
+ authorize(model_class.new(permitted_attributes(model_class)), **policy_kwopts)
120
+ when "edit", "update", "show", "destroy"
121
+ load_model(model_class, param_key, policy_kwopts, policy_scope_kwopts)
122
+ else
123
+ if params[param_key]
124
+ load_model(model_class, param_key, policy_kwopts, policy_scope_kwopts)
125
+ else
126
+ load_scope(model_class, policy_kwopts, policy_scope_kwopts)
127
+ end
128
+ end
129
+ end
130
+
131
+ def load_parent_instance_var model_class, param_key, policy_kwopts, policy_scope_kwopts
132
+ if params[param_key]
133
+ load_model(model_class, param_key, policy_kwopts, policy_scope_kwopts, :show?)
134
+ end
135
+ end
136
+
137
+ def load_model model_class, param_key, policy_kwopts, policy_scope_kwopts, query = nil
138
+ authorize(policy_scope(model_class, **policy_scope_kwopts).find(params[param_key]), query, **policy_kwopts)
139
+ end
140
+
141
+ def load_scope model_class, policy_kwopts, policy_scope_kwopts
142
+ authorize(policy_scope(model_class, **policy_scope_kwopts), **policy_kwopts)
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,4 @@
1
+ module PunditCan
2
+ class Railtie < ::Rails::Railtie
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module PunditCan
2
+ VERSION = "0.1.0"
3
+ end
data/lib/pundit_can.rb ADDED
@@ -0,0 +1,12 @@
1
+ require "pundit_can/version"
2
+ require "pundit_can/railtie"
3
+ require "pundit"
4
+ require "active_support/concern"
5
+ require "active_support/core_ext/string/inflections"
6
+ require "active_support/core_ext/object/blank"
7
+ require "active_support/core_ext/module/introspection"
8
+ require "active_support/dependencies/autoload"
9
+ require "pundit_can/load_and_authorize"
10
+
11
+ module PunditCan
12
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :pundit_can do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pundit_can
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - candland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.4.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.4.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: pundit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 2.0.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 2.0.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails-controller-testing
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Add cancan like load and authorize to controllers.
56
+ email:
57
+ - candland@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - MIT-LICENSE
63
+ - README.md
64
+ - Rakefile
65
+ - lib/pundit_can.rb
66
+ - lib/pundit_can/load_and_authorize.rb
67
+ - lib/pundit_can/railtie.rb
68
+ - lib/pundit_can/version.rb
69
+ - lib/tasks/pundit_can_tasks.rake
70
+ homepage: https://candland.net/pundit_can
71
+ licenses:
72
+ - MIT
73
+ metadata:
74
+ homepage_uri: https://candland.net/pundit_can
75
+ source_code_uri: https://github.com/candland/pundit_can
76
+ changelog_uri: https://github.com/candland/pundit_can/CHANGES.md
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubygems_version: 3.3.7
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Add cancan like load and authorize to controllers.
96
+ test_files: []